]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Cheery picked:
authorFrank Li <Frank.li@freescale.com>
Wed, 28 Aug 2013 21:02:06 +0000 (16:02 -0500)
committerOliver Wendt <ow@karo-electronics.de>
Thu, 12 Mar 2015 13:09:30 +0000 (14:09 +0100)
commit 125203588824fd5cb13822cb0b1fed7da91d7512
git://git.freescale.com/imx/linux-2.6-imx.git

ENGR00280494-1 make the kernel image for mfgtool

uboot needs pass down below parameters
removable = 1
stall = 0
idVendor = 0x066F
idProduct = 0x37FF
iSerialNumber = ""

Signed-off-by: Lu Lin <b37454@freescale.com>
Signed-off-by: Frank Li<frank.li@freescale.com>
resolved
Conflicts:
drivers/usb/gadget/f_mass_storage.c

drivers/usb/gadget/Kconfig
drivers/usb/gadget/f_mass_storage.c
drivers/usb/gadget/fsl_updater.c [new file with mode: 0644]
drivers/usb/gadget/fsl_updater.h [new file with mode: 0644]
drivers/usb/gadget/mass_storage.c

index ba18e9c110cc90dbf6d60b598d44ac717e5678b3..24878f178404e09987f0dec2f050e88c80b7c3ea 100644 (file)
@@ -945,6 +945,12 @@ config USB_MASS_STORAGE
          Say "y" to link the driver statically, or "m" to build
          a dynamically linked module called "g_mass_storage".
 
          Say "y" to link the driver statically, or "m" to build
          a dynamically linked module called "g_mass_storage".
 
+config FSL_UTP
+        bool "UTP over Storage Gadget"
+        depends on USB_MASS_STORAGE
+        help
+          Freescale's extension to MSC protocol
+
 config USB_GADGET_TARGET
        tristate "USB Gadget Target Fabric Module"
        depends on TARGET_CORE
 config USB_GADGET_TARGET
        tristate "USB Gadget Target Fabric Module"
        depends on TARGET_CORE
index b963939088606e7e9252ec1f55d42ff9fdd1dcd3..858f7a34308ac828cb669ed8484ac373498b2277 100644 (file)
@@ -336,8 +336,15 @@ struct fsg_dev {
 
        struct usb_ep           *bulk_in;
        struct usb_ep           *bulk_out;
 
        struct usb_ep           *bulk_in;
        struct usb_ep           *bulk_out;
+#ifdef CONFIG_FSL_UTP
+       void                    *utp;
+#endif
 };
 
 };
 
+#ifdef CONFIG_FSL_UTP
+#include "fsl_updater.h"
+#endif
+
 static inline int __fsg_is_set(struct fsg_common *common,
                               const char *func, unsigned line)
 {
 static inline int __fsg_is_set(struct fsg_common *common,
                               const char *func, unsigned line)
 {
@@ -1131,6 +1138,13 @@ static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh)
        }
 #endif
 
        }
 #endif
 
+#ifdef CONFIG_FSL_UTP
+       if (utp_get_sense(common->fsg) == 0) {  /* got the sense from the UTP */
+               sd = UTP_CTX(common->fsg)->sd;
+               sdinfo = UTP_CTX(common->fsg)->sdinfo;
+               valid = 0;
+       } else
+#endif
        if (!curlun) {          /* Unsupported LUNs are okay */
                common->bad_lun_okay = 1;
                sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
        if (!curlun) {          /* Unsupported LUNs are okay */
                common->bad_lun_okay = 1;
                sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
@@ -1152,6 +1166,9 @@ static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh)
        buf[7] = 18 - 8;                        /* Additional sense length */
        buf[12] = ASC(sd);
        buf[13] = ASCQ(sd);
        buf[7] = 18 - 8;                        /* Additional sense length */
        buf[12] = ASC(sd);
        buf[13] = ASCQ(sd);
+#ifdef CONFIG_FSL_UTP
+       put_unaligned_be32(UTP_CTX(common->fsg)->sdinfo_h, &buf[8]);
+#endif
        return 18;
 }
 
        return 18;
 }
 
@@ -1645,7 +1662,18 @@ static int send_status(struct fsg_common *common)
                sd = SS_INVALID_COMMAND;
        } else if (sd != SS_NO_SENSE) {
                DBG(common, "sending command-failure status\n");
                sd = SS_INVALID_COMMAND;
        } else if (sd != SS_NO_SENSE) {
                DBG(common, "sending command-failure status\n");
+#ifdef CONFIG_FSL_UTP
+/*
+ * mfgtool host frequently reset bus during transfer
+ *  - the response in csw to request sense will be 1 due to UTP change
+ *    some storage information
+ *  - host will reset the bus if response to request sense is 1
+ *  - change the response to 0 if CONFIG_FSL_UTP is defined
+ */
+               status = US_BULK_STAT_OK;
+#else
                status = US_BULK_STAT_FAIL;
                status = US_BULK_STAT_FAIL;
+#endif
                VDBG(common, "  sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
                                "  info x%x\n",
                                SK(sd), ASC(sd), ASCQ(sd), sdinfo);
                VDBG(common, "  sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
                                "  info x%x\n",
                                SK(sd), ASC(sd), ASCQ(sd), sdinfo);
@@ -1836,6 +1864,13 @@ static int do_scsi_command(struct fsg_common *common)
        common->phase_error = 0;
        common->short_packet_received = 0;
 
        common->phase_error = 0;
        common->short_packet_received = 0;
 
+#ifdef CONFIG_FSL_UTP
+       reply = utp_handle_message(common->fsg, common->cmnd, reply);
+
+       if (reply != -EINVAL)
+               return reply;
+#endif
+
        down_read(&common->filesem);    /* We're using the backing file */
        switch (common->cmnd[0]) {
 
        down_read(&common->filesem);    /* We're using the backing file */
        switch (common->cmnd[0]) {
 
@@ -2502,12 +2537,14 @@ static int fsg_main_thread(void *common_)
        /* Allow the thread to be frozen */
        set_freezable();
 
        /* Allow the thread to be frozen */
        set_freezable();
 
+#ifndef CONFIG_FSL_UTP
        /*
         * Arrange for userspace references to be interpreted as kernel
         * pointers.  That way we can pass a kernel pointer to a routine
         * that expects a __user pointer and it will work okay.
         */
        set_fs(get_ds());
        /*
         * Arrange for userspace references to be interpreted as kernel
         * pointers.  That way we can pass a kernel pointer to a routine
         * that expects a __user pointer and it will work okay.
         */
        set_fs(get_ds());
+#endif
 
        /* The main loop */
        while (common->state != FSG_STATE_TERMINATED) {
 
        /* The main loop */
        while (common->state != FSG_STATE_TERMINATED) {
@@ -3096,6 +3133,10 @@ static void fsg_common_release(struct kref *ref)
 
 /*-------------------------------------------------------------------------*/
 
 
 /*-------------------------------------------------------------------------*/
 
+#ifdef CONFIG_FSL_UTP
+#include "fsl_updater.c"
+#endif
+
 static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
 {
        struct fsg_dev          *fsg = fsg_from_func(f);
 static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
 {
        struct fsg_dev          *fsg = fsg_from_func(f);
@@ -3127,6 +3168,10 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
        fsg_intf_desc.bInterfaceNumber = i;
        fsg->interface_number = i;
 
        fsg_intf_desc.bInterfaceNumber = i;
        fsg->interface_number = i;
 
+#ifdef CONFIG_FSL_UTP
+       utp_init(fsg);
+#endif
+
        /* Find all the endpoints we will use */
        ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
        if (!ep)
        /* Find all the endpoints we will use */
        ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
        if (!ep)
@@ -3184,7 +3229,12 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
                wait_event(common->fsg_wait, common->fsg != fsg);
        }
 
                wait_event(common->fsg_wait, common->fsg != fsg);
        }
 
+       fsg_common_put(common);
        usb_free_all_descriptors(&fsg->function);
        usb_free_all_descriptors(&fsg->function);
+       kfree(fsg);
+#ifdef CONFIG_FSL_UTP
+       utp_exit(fsg);
+#endif
 }
 
 static inline struct fsg_lun_opts *to_fsg_lun_opts(struct config_item *item)
 }
 
 static inline struct fsg_lun_opts *to_fsg_lun_opts(struct config_item *item)
diff --git a/drivers/usb/gadget/fsl_updater.c b/drivers/usb/gadget/fsl_updater.c
new file mode 100644 (file)
index 0000000..8b4af62
--- /dev/null
@@ -0,0 +1,568 @@
+/*
+ * Freescale UUT driver
+ *
+ * Copyright 2008-2013 Freescale Semiconductor, Inc.
+ * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+static u64 get_be64(u8 *buf)
+{
+       return ((u64)get_unaligned_be32(buf) << 32) |
+               get_unaligned_be32(buf + 4);
+}
+
+static int utp_init(struct fsg_dev *fsg)
+{
+       init_waitqueue_head(&utp_context.wq);
+       init_waitqueue_head(&utp_context.list_full_wq);
+
+       INIT_LIST_HEAD(&utp_context.read);
+       INIT_LIST_HEAD(&utp_context.write);
+       mutex_init(&utp_context.lock);
+
+       /* the max message is 64KB */
+       utp_context.buffer = vmalloc(0x10000);
+       if (!utp_context.buffer)
+               return -EIO;
+       utp_context.utp_version = 0x1ull;
+       fsg->utp = &utp_context;
+       return misc_register(&utp_dev);
+}
+
+static void utp_exit(struct fsg_dev *fsg)
+{
+       vfree(utp_context.buffer);
+       misc_deregister(&utp_dev);
+}
+
+static struct utp_user_data *utp_user_data_alloc(size_t size)
+{
+       struct utp_user_data *uud;
+
+       uud = kzalloc(size + sizeof(*uud), GFP_KERNEL);
+       if (!uud)
+               return uud;
+       uud->data.size = size + sizeof(uud->data);
+       INIT_LIST_HEAD(&uud->link);
+       return uud;
+}
+
+static void utp_user_data_free(struct utp_user_data *uud)
+{
+       mutex_lock(&utp_context.lock);
+       list_del(&uud->link);
+       mutex_unlock(&utp_context.lock);
+       kfree(uud);
+}
+
+/* Get the number of element for list */
+static u32 count_list(struct list_head *l)
+{
+       u32 count = 0;
+       struct list_head *tmp;
+
+       list_for_each(tmp, l) {
+               count++;
+       }
+
+       return count;
+}
+/* The routine will not go on if utp_context.queue is empty */
+#define WAIT_ACTIVITY(queue) \
+ wait_event_interruptible(utp_context.wq, !list_empty(&utp_context.queue))
+
+/* Called by userspace program (uuc) */
+static ssize_t utp_file_read(struct file *file,
+                            char __user *buf,
+                            size_t size,
+                            loff_t *off)
+{
+       struct utp_user_data *uud;
+       size_t size_to_put;
+       int free = 0;
+
+       WAIT_ACTIVITY(read);
+
+       mutex_lock(&utp_context.lock);
+       uud = list_first_entry(&utp_context.read, struct utp_user_data, link);
+       mutex_unlock(&utp_context.lock);
+       size_to_put = uud->data.size;
+
+       if (size >= size_to_put)
+               free = !0;
+       if (copy_to_user(buf, &uud->data, size_to_put))
+               return -EACCES;
+       if (free)
+               utp_user_data_free(uud);
+       else {
+               pr_info("sizeof = %d, size = %d\n",
+                       sizeof(uud->data),
+                       uud->data.size);
+
+               pr_err("Will not free utp_user_data, because buffer size = %d,"
+                       "need to put %d\n", size, size_to_put);
+       }
+
+       /*
+        * The user program has already finished data process,
+        * go on getting data from the host
+        */
+       wake_up(&utp_context.list_full_wq);
+
+       return size_to_put;
+}
+
+static ssize_t utp_file_write(struct file *file, const char __user *buf,
+                               size_t size, loff_t *off)
+{
+       struct utp_user_data *uud;
+
+       if (size < sizeof(uud->data))
+               return -EINVAL;
+       uud = utp_user_data_alloc(size);
+       if (copy_from_user(&uud->data, buf, size))
+               return -EACCES;
+       mutex_lock(&utp_context.lock);
+       list_add_tail(&uud->link, &utp_context.write);
+       /* Go on EXEC routine process */
+       wake_up(&utp_context.wq);
+       mutex_unlock(&utp_context.lock);
+       return size;
+}
+
+/*
+ * uuc should change to use soc bus infrastructure to soc information
+ * /sys/devices/soc0/soc_id
+ * this function can be removed.
+ */
+static long
+utp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int cpu_id = 0;
+
+       switch (cmd) {
+       case UTP_GET_CPU_ID:
+               return put_user(cpu_id, (int __user *)arg);
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+/* Will be called when the host wants to get the sense data */
+static int utp_get_sense(struct fsg_dev *fsg)
+{
+       if (UTP_CTX(fsg)->processed == 0)
+               return -1;
+
+       UTP_CTX(fsg)->processed = 0;
+       return 0;
+}
+
+static int utp_do_read(struct fsg_dev *fsg, void *data, size_t size)
+{
+       struct fsg_buffhd       *bh;
+       int                     rc;
+       u32                     amount_left;
+       unsigned int            amount;
+
+       /* Get the starting Logical Block Address and check that it's
+        * not too big */
+
+       amount_left = size;
+       if (unlikely(amount_left == 0))
+               return -EIO;            /* No default reply*/
+
+       pr_debug("%s: sending %d\n", __func__, size);
+       for (;;) {
+               /* Figure out how much we need to read:
+                * Try to read the remaining amount.
+                * But don't read more than the buffer size.
+                * And don't try to read past the end of the file.
+                * Finally, if we're not at a page boundary, don't read past
+                *      the next page.
+                * If this means reading 0 then we were asked to read past
+                *      the end of file. */
+               amount = min((unsigned int) amount_left, FSG_BUFLEN);
+
+               /* Wait for the next buffer to become available */
+               bh = fsg->common->next_buffhd_to_fill;
+               while (bh->state != BUF_STATE_EMPTY) {
+                       rc = sleep_thread(fsg->common);
+                       if (rc)
+                               return rc;
+               }
+
+               /* If we were asked to read past the end of file,
+                * end with an empty buffer. */
+               if (amount == 0) {
+                       bh->inreq->length = 0;
+                       bh->state = BUF_STATE_FULL;
+                       break;
+               }
+
+               /* Perform the read */
+               pr_info("Copied to %p, %d bytes started from %d\n",
+                               bh->buf, amount, size - amount_left);
+               /* from upt buffer to file_storeage buffer */
+               memcpy(bh->buf, data + size - amount_left, amount);
+               amount_left  -= amount;
+               fsg->common->residue -= amount;
+
+               bh->inreq->length = amount;
+               bh->state = BUF_STATE_FULL;
+
+               /* Send this buffer and go read some more */
+               bh->inreq->zero = 0;
+
+               /* USB Physical transfer: Data from device to host */
+               start_transfer(fsg, fsg->bulk_in, bh->inreq,
+                               &bh->inreq_busy, &bh->state);
+
+               fsg->common->next_buffhd_to_fill = bh->next;
+
+               if (amount_left <= 0)
+                       break;
+       }
+
+       return size - amount_left;
+}
+
+static int utp_do_write(struct fsg_dev *fsg, void *data, size_t size)
+{
+       struct fsg_buffhd       *bh;
+       int                     get_some_more;
+       u32                     amount_left_to_req, amount_left_to_write;
+       unsigned int            amount;
+       int                     rc;
+       loff_t                  offset;
+
+       /* Carry out the file writes */
+       get_some_more = 1;
+       amount_left_to_req = amount_left_to_write = size;
+
+       if (unlikely(amount_left_to_write == 0))
+               return -EIO;
+
+       offset = 0;
+       while (amount_left_to_write > 0) {
+
+               /* Queue a request for more data from the host */
+               bh = fsg->common->next_buffhd_to_fill;
+               if (bh->state == BUF_STATE_EMPTY && get_some_more) {
+
+                       /* Figure out how much we want to get:
+                        * Try to get the remaining amount.
+                        * But don't get more than the buffer size.
+                        * And don't try to go past the end of the file.
+                        * If we're not at a page boundary,
+                        *      don't go past the next page.
+                        * If this means getting 0, then we were asked
+                        *      to write past the end of file.
+                        * Finally, round down to a block boundary. */
+                       amount = min(amount_left_to_req, FSG_BUFLEN);
+
+                       if (amount == 0) {
+                               get_some_more = 0;
+                               /* cry now */
+                               continue;
+                       }
+
+                       /* Get the next buffer */
+                       amount_left_to_req -= amount;
+                       if (amount_left_to_req == 0)
+                               get_some_more = 0;
+
+                       /* amount is always divisible by 512, hence by
+                        * the bulk-out maxpacket size */
+                       bh->outreq->length = bh->bulk_out_intended_length =
+                                       amount;
+                       bh->outreq->short_not_ok = 1;
+                       start_transfer(fsg, fsg->bulk_out, bh->outreq,
+                                       &bh->outreq_busy, &bh->state);
+                       fsg->common->next_buffhd_to_fill = bh->next;
+                       continue;
+               }
+
+               /* Write the received data to the backing file */
+               bh = fsg->common->next_buffhd_to_drain;
+               if (bh->state == BUF_STATE_EMPTY && !get_some_more)
+                       break;                  /* We stopped early */
+               if (bh->state == BUF_STATE_FULL) {
+                       smp_rmb();
+                       fsg->common->next_buffhd_to_drain = bh->next;
+                       bh->state = BUF_STATE_EMPTY;
+
+                       /* Did something go wrong with the transfer? */
+                       if (bh->outreq->status != 0)
+                               /* cry again, COMMUNICATION_FAILURE */
+                               break;
+
+                       amount = bh->outreq->actual;
+
+                       /* Perform the write */
+                       memcpy(data + offset, bh->buf, amount);
+
+                       offset += amount;
+                       if (signal_pending(current))
+                               return -EINTR;          /* Interrupted!*/
+                       amount_left_to_write -= amount;
+                       fsg->common->residue -= amount;
+
+                       /* Did the host decide to stop early? */
+                       if (bh->outreq->actual != bh->outreq->length) {
+                               fsg->common->short_packet_received = 1;
+                               break;
+                       }
+                       continue;
+               }
+
+               /* Wait for something to happen */
+               rc = sleep_thread(fsg->common);
+               if (rc)
+                       return rc;
+       }
+
+       return -EIO;
+}
+
+static inline void utp_set_sense(struct fsg_dev *fsg, u16 code, u64 reply)
+{
+       UTP_CTX(fsg)->processed = true;
+       UTP_CTX(fsg)->sdinfo = reply & 0xFFFFFFFF;
+       UTP_CTX(fsg)->sdinfo_h = (reply >> 32) & 0xFFFFFFFF;
+       UTP_CTX(fsg)->sd = (UTP_SENSE_KEY << 16) | code;
+}
+
+static void utp_poll(struct fsg_dev *fsg)
+{
+       struct utp_context *ctx = UTP_CTX(fsg);
+       struct utp_user_data *uud = NULL;
+
+       mutex_lock(&ctx->lock);
+       if (!list_empty(&ctx->write))
+               uud = list_first_entry(&ctx->write, struct utp_user_data, link);
+       mutex_unlock(&ctx->lock);
+
+       if (uud) {
+               if (uud->data.flags & UTP_FLAG_STATUS) {
+                       printk(KERN_WARNING "%s: exit with status %d\n",
+                                       __func__, uud->data.status);
+                       UTP_SS_EXIT(fsg, uud->data.status);
+               } else {
+                       pr_debug("%s: pass\n", __func__);
+                       UTP_SS_PASS(fsg);
+               }
+               utp_user_data_free(uud);
+       } else {
+               pr_debug("%s: still busy...\n", __func__);
+               UTP_SS_BUSY(fsg, --ctx->counter);
+       }
+}
+
+static int utp_exec(struct fsg_dev *fsg,
+                   char *command,
+                   int cmdsize,
+                   unsigned long long payload)
+{
+       struct utp_user_data *uud = NULL, *uud2r;
+       struct utp_context *ctx = UTP_CTX(fsg);
+
+       uud2r = utp_user_data_alloc(cmdsize + 1);
+       uud2r->data.flags = UTP_FLAG_COMMAND;
+       uud2r->data.payload = payload;
+       strncpy(uud2r->data.command, command, cmdsize);
+
+       mutex_lock(&ctx->lock);
+       list_add_tail(&uud2r->link, &ctx->read);
+       mutex_unlock(&ctx->lock);
+       /* wake up the read routine */
+       wake_up(&ctx->wq);
+
+       if (command[0] == '!')  /* there will be no response */
+               return 0;
+
+       /*
+        * the user program (uuc) will return utp_message
+        * and add list to write list
+        */
+       WAIT_ACTIVITY(write);
+
+       mutex_lock(&ctx->lock);
+       if (!list_empty(&ctx->write)) {
+               uud = list_first_entry(&ctx->write, struct utp_user_data, link);
+#ifdef DEBUG
+               pr_info("UUD:\n\tFlags = %02X\n", uud->data.flags);
+               if (uud->data.flags & UTP_FLAG_DATA) {
+                       pr_info("\tbufsize = %d\n", uud->data.bufsize);
+                       print_hex_dump(KERN_DEBUG, "\t", DUMP_PREFIX_NONE,
+                               16, 2, uud->data.data, uud->data.bufsize, true);
+               }
+               if (uud->data.flags & UTP_FLAG_REPORT_BUSY)
+                       pr_info("\tBUSY\n");
+#endif
+       }
+       mutex_unlock(&ctx->lock);
+
+       if (uud->data.flags & UTP_FLAG_DATA) {
+               memcpy(ctx->buffer, uud->data.data, uud->data.bufsize);
+               UTP_SS_SIZE(fsg, uud->data.bufsize);
+       } else if (uud->data.flags & UTP_FLAG_REPORT_BUSY) {
+               ctx->counter = 0xFFFF;
+               UTP_SS_BUSY(fsg, ctx->counter);
+       } else if (uud->data.flags & UTP_FLAG_STATUS) {
+               printk(KERN_WARNING "%s: exit with status %d\n", __func__,
+                               uud->data.status);
+               UTP_SS_EXIT(fsg, uud->data.status);
+       } else {
+               pr_debug("%s: pass\n", __func__);
+               UTP_SS_PASS(fsg);
+       }
+       utp_user_data_free(uud);
+       return 0;
+}
+
+static int utp_send_status(struct fsg_dev *fsg)
+{
+       struct fsg_buffhd       *bh;
+       u8                      status = US_BULK_STAT_OK;
+       struct bulk_cs_wrap     *csw;
+       int                     rc;
+
+       /* Wait for the next buffer to become available */
+       bh = fsg->common->next_buffhd_to_fill;
+       while (bh->state != BUF_STATE_EMPTY) {
+               rc = sleep_thread(fsg->common);
+               if (rc)
+                       return rc;
+       }
+
+       if (fsg->common->phase_error) {
+               DBG(fsg, "sending phase-error status\n");
+               status = US_BULK_STAT_PHASE;
+
+       } else if ((UTP_CTX(fsg)->sd & 0xFFFF) != UTP_REPLY_PASS) {
+               status = US_BULK_STAT_FAIL;
+       }
+
+       csw = bh->buf;
+
+       /* Store and send the Bulk-only CSW */
+       csw->Signature = __constant_cpu_to_le32(US_BULK_CS_SIGN);
+       csw->Tag = fsg->common->tag;
+       csw->Residue = cpu_to_le32(fsg->common->residue);
+       csw->Status = status;
+
+       bh->inreq->length = US_BULK_CS_WRAP_LEN;
+       bh->inreq->zero = 0;
+       start_transfer(fsg, fsg->bulk_in, bh->inreq,
+                       &bh->inreq_busy, &bh->state);
+       fsg->common->next_buffhd_to_fill = bh->next;
+       return 0;
+}
+
+static int utp_handle_message(struct fsg_dev *fsg,
+                             char *cdb_data,
+                             int default_reply)
+{
+       struct utp_msg *m = (struct utp_msg *)cdb_data;
+       void *data = NULL;
+       int r;
+       struct utp_user_data *uud2r;
+       unsigned long long param;
+       unsigned long tag;
+
+       if (m->f0 != 0xF0)
+               return default_reply;
+
+       tag = get_unaligned_be32((void *)&m->utp_msg_tag);
+       param = get_be64((void *)&m->param);
+       pr_debug("Type 0x%x, tag 0x%08lx, param %llx\n",
+                       m->utp_msg_type, tag, param);
+
+       switch ((enum utp_msg_type)m->utp_msg_type) {
+
+       case UTP_POLL:
+               if (get_be64((void *)&m->param) == 1) {
+                       pr_debug("%s: version request\n", __func__);
+                       UTP_SS_EXIT(fsg, UTP_CTX(fsg)->utp_version);
+                       break;
+               }
+               utp_poll(fsg);
+               break;
+       case UTP_EXEC:
+               pr_debug("%s: EXEC\n", __func__);
+               data = kzalloc(fsg->common->data_size, GFP_KERNEL);
+               /* copy data from usb buffer to utp buffer */
+               utp_do_write(fsg, data, fsg->common->data_size);
+               utp_exec(fsg, data, fsg->common->data_size, param);
+               kfree(data);
+               break;
+       case UTP_GET: /* data from device to host */
+               pr_debug("%s: GET, %d bytes\n", __func__,
+                                       fsg->common->data_size);
+               r = utp_do_read(fsg, UTP_CTX(fsg)->buffer,
+                                       fsg->common->data_size);
+               UTP_SS_PASS(fsg);
+               break;
+       case UTP_PUT: /* data from host to device */
+               pr_debug("%s: PUT, %d bytes\n", __func__,
+                                       fsg->common->data_size);
+               uud2r = utp_user_data_alloc(fsg->common->data_size);
+               uud2r->data.bufsize = fsg->common->data_size;
+               uud2r->data.flags = UTP_FLAG_DATA;
+               utp_do_write(fsg, uud2r->data.data, fsg->common->data_size);
+               /* don't know what will be written */
+               mutex_lock(&UTP_CTX(fsg)->lock);
+               list_add_tail(&uud2r->link, &UTP_CTX(fsg)->read);
+               mutex_unlock(&UTP_CTX(fsg)->lock);
+               wake_up(&UTP_CTX(fsg)->wq);
+               /*
+                * Return PASS or FAIL according to uuc's status
+                * Please open it if need to check uuc's status
+                * and use another version uuc
+                */
+#if 0
+               struct utp_user_data *uud = NULL;
+               struct utp_context *ctx;
+               WAIT_ACTIVITY(write);
+               ctx = UTP_CTX(fsg);
+               mutex_lock(&ctx->lock);
+
+               if (!list_empty(&ctx->write))
+                       uud = list_first_entry(&ctx->write,
+                                       struct utp_user_data, link);
+
+               mutex_unlock(&ctx->lock);
+               if (uud) {
+                       if (uud->data.flags & UTP_FLAG_STATUS) {
+                               printk(KERN_WARNING "%s: exit with status %d\n",
+                                        __func__, uud->data.status);
+                               UTP_SS_EXIT(fsg, uud->data.status);
+                       } else {
+                               pr_debug("%s: pass\n", __func__);
+                               UTP_SS_PASS(fsg);
+                       }
+                       utp_user_data_free(uud);
+               } else{
+                       UTP_SS_PASS(fsg);
+               }
+#endif
+               UTP_SS_PASS(fsg);
+
+               wait_event_interruptible(UTP_CTX(fsg)->list_full_wq,
+                       count_list(&UTP_CTX(fsg)->read) < 7);
+               break;
+       }
+
+       utp_send_status(fsg);
+       return -1;
+}
diff --git a/drivers/usb/gadget/fsl_updater.h b/drivers/usb/gadget/fsl_updater.h
new file mode 100644 (file)
index 0000000..857e22e
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Freescale UUT driver
+ *
+ * Copyright 2008-2013 Freescale Semiconductor, Inc.
+ * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __FSL_UPDATER_H
+#define __FSL_UPDATER_H
+
+#include <linux/miscdevice.h>
+#include <linux/list.h>
+#include <linux/vmalloc.h>
+#include <linux/ioctl.h>
+/* #include <mach/hardware.h> */
+
+static int utp_init(struct fsg_dev *fsg);
+static void utp_exit(struct fsg_dev *fsg);
+static ssize_t utp_file_read(struct file *file,
+                            char __user *buf,
+                            size_t size,
+                            loff_t *off);
+
+static ssize_t utp_file_write(struct file *file,
+                             const char __user *buf,
+                             size_t size,
+                             loff_t *off);
+
+static long utp_ioctl(struct file *file,
+             unsigned int cmd, unsigned long arg);
+static struct utp_user_data *utp_user_data_alloc(size_t size);
+static void utp_user_data_free(struct utp_user_data *uud);
+static int utp_get_sense(struct fsg_dev *fsg);
+static int utp_do_read(struct fsg_dev *fsg, void *data, size_t size);
+static int utp_do_write(struct fsg_dev *fsg, void *data, size_t size);
+static inline void utp_set_sense(struct fsg_dev *fsg, u16 code, u64 reply);
+static int utp_handle_message(struct fsg_dev *fsg,
+                             char *cdb_data,
+                             int default_reply);
+
+#define UTP_REPLY_PASS         0
+#define UTP_REPLY_EXIT         0x8001
+#define UTP_REPLY_BUSY         0x8002
+#define UTP_REPLY_SIZE         0x8003
+#define UTP_SENSE_KEY          9
+
+#define UTP_MINOR              222
+/* MISC_DYNAMIC_MINOR would be better, but... */
+
+#define UTP_COMMAND_SIZE       80
+
+#define UTP_SS_EXIT(fsg, r)    utp_set_sense(fsg, UTP_REPLY_EXIT, (u64)r)
+#define UTP_SS_PASS(fsg)       utp_set_sense(fsg, UTP_REPLY_PASS, 0)
+#define UTP_SS_BUSY(fsg, r)    utp_set_sense(fsg, UTP_REPLY_BUSY, (u64)r)
+#define UTP_SS_SIZE(fsg, r)    utp_set_sense(fsg, UTP_REPLY_SIZE, (u64)r)
+
+#define        UTP_IOCTL_BASE  'U'
+#define        UTP_GET_CPU_ID  _IOR(UTP_IOCTL_BASE, 0, int)
+/* the structure of utp message which is mapped to 16-byte SCSI CBW's CDB */
+#pragma pack(1)
+struct utp_msg {
+       u8  f0;
+       u8  utp_msg_type;
+       u32 utp_msg_tag;
+       union {
+               struct {
+                       u32 param_lsb;
+                       u32 param_msb;
+               };
+               u64 param;
+       };
+};
+
+enum utp_msg_type {
+       UTP_POLL = 0,
+       UTP_EXEC,
+       UTP_GET,
+       UTP_PUT,
+};
+
+static struct utp_context {
+       wait_queue_head_t wq;
+       wait_queue_head_t list_full_wq;
+       struct mutex lock;
+       struct list_head read;
+       struct list_head write;
+       u32 sd, sdinfo, sdinfo_h;                       /* sense data */
+       int processed;
+       u8 *buffer;
+       u32 counter;
+       u64 utp_version;
+} utp_context;
+
+static const struct file_operations utp_fops = {
+       .open   = nonseekable_open,
+       .read   = utp_file_read,
+       .write  = utp_file_write,
+       /* .ioctl  = utp_ioctl, */
+       .unlocked_ioctl  = utp_ioctl,
+};
+
+static struct miscdevice utp_dev = {
+       .minor  = UTP_MINOR,
+       .name   = "utp",
+       .fops   = &utp_fops,
+};
+
+#define UTP_FLAG_COMMAND       0x00000001
+#define UTP_FLAG_DATA          0x00000002
+#define UTP_FLAG_STATUS                0x00000004
+#define UTP_FLAG_REPORT_BUSY   0x10000000
+struct utp_message {
+       u32     flags;
+       size_t  size;
+       union {
+               struct {
+                       u64 payload;
+                       char command[1];
+               };
+               struct {
+                       size_t bufsize;
+                       u8 data[1];
+               };
+               u32 status;
+       };
+};
+
+struct utp_user_data {
+       struct  list_head       link;
+       struct  utp_message     data;
+};
+#pragma pack()
+
+static inline struct utp_context *UTP_CTX(struct fsg_dev *fsg)
+{
+       return (struct utp_context *)fsg->utp;
+}
+
+#endif /* __FSL_UPDATER_H */
+
index 8e27a8c9644470bfa8d5b44fc95a198aeda7214f..1178aea9c5445d2a3a2b8384229cabb7cc2c3dc5 100644 (file)
@@ -266,7 +266,7 @@ static int __init msg_init(void)
 {
        return usb_composite_probe(&msg_driver);
 }
 {
        return usb_composite_probe(&msg_driver);
 }
-module_init(msg_init);
+late_initcall(msg_init);
 
 static void msg_cleanup(void)
 {
 
 static void msg_cleanup(void)
 {