]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
gadget: add stmp uut support to file storage
authorFrank Li <Frank.Li@freescale.com>
Wed, 23 Sep 2009 21:24:49 +0000 (18:24 -0300)
committerOliver Wendt <ow@karo-electronics.de>
Mon, 30 Sep 2013 12:08:44 +0000 (14:08 +0200)
This is gadget file storage changes needed for FSL universal updater
tool (manufacturing flashing tool).

ENGR00131456 mfg-tool: Add get cpu id ioctl at utp driver

The watchdog operation is differ with SoC's for rom code, so the utp app
needs to add or not add watchdog operation according to different SoCs.

Signed-off-by: Frank Li <Frank.Li@freescale.com>
Signed-off-by: Peter Chen <peter.chen@freescale.com>
drivers/usb/gadget/Kconfig
drivers/usb/gadget/file_storage.c
drivers/usb/gadget/fsl_updater.c [new file with mode: 0644]
drivers/usb/gadget/fsl_updater.h [new file with mode: 0644]

index 46f81aec63359a4ed92b1a9eb4df9edbacde565a..8c8ea43432384ce75b8822e0a76d68db055c9d75 100644 (file)
@@ -860,6 +860,12 @@ config USB_FILE_STORAGE
          Say "y" to link the driver statically, or "m" to build a
          dynamically linked module called "g_file_storage".
 
+config FSL_UTP
+       bool "UTP over Storage Gadget"
+       depends on USB_FILE_STORAGE
+       help
+         Freescale's extension to MSC protocol
+
 config USB_FILE_STORAGE_TEST
        bool "File-backed Storage Gadget testing version"
        depends on USB_FILE_STORAGE
index e358130a48572648f52942b7b3dd79d46fa36567..cd7c12d77d78eda60af78da7d6be275daeb3dc3a 100644 (file)
@@ -488,8 +488,16 @@ struct fsg_dev {
        unsigned int            nluns;
        struct fsg_lun          *luns;
        struct fsg_lun          *curlun;
+
+#ifdef CONFIG_FSL_UTP
+       void                    *utp;
+#endif
 };
 
+#ifdef CONFIG_FSL_UTP
+#include "fsl_updater.h"
+#endif
+
 typedef void (*fsg_routine_t)(struct fsg_dev *);
 
 static int exception_in_progress(struct fsg_dev *fsg)
@@ -557,7 +565,11 @@ device_desc = {
 
        .iManufacturer =        FSG_STRING_MANUFACTURER,
        .iProduct =             FSG_STRING_PRODUCT,
+#ifdef CONFIG_FSL_UTP
+       .iSerialNumber = 0,
+#else
        .iSerialNumber =        FSG_STRING_SERIAL,
+#endif
        .bNumConfigurations =   1,
 };
 
@@ -1622,6 +1634,13 @@ static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
        }
 #endif
 
+#ifdef CONFIG_FSL_UTP
+       if (utp_get_sense(fsg) == 0) {  /* got the sense from the UTP */
+               sd = UTP_CTX(fsg)->sd;
+               sdinfo = UTP_CTX(fsg)->sdinfo;
+               valid = 0;
+       } else
+#endif
        if (!curlun) {          // Unsupported LUNs are okay
                fsg->bad_lun_okay = 1;
                sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
@@ -1643,6 +1662,9 @@ static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
        buf[7] = 18 - 8;                        // Additional sense length
        buf[12] = ASC(sd);
        buf[13] = ASCQ(sd);
+#ifdef CONFIG_FSL_UTP
+       put_unaligned_be32(UTP_CTX(fsg)->sdinfo_h, &buf[8]);
+#endif
        return 18;
 }
 
@@ -2356,6 +2378,13 @@ static int do_scsi_command(struct fsg_dev *fsg)
        fsg->phase_error = 0;
        fsg->short_packet_received = 0;
 
+#ifdef CONFIG_FSL_UTP
+       reply = utp_handle_message(fsg, fsg->cmnd, reply);
+
+       if (reply != -EINVAL)
+               return reply;
+#endif
+
        down_read(&fsg->filesem);       // We're using the backing file
        switch (fsg->cmnd[0]) {
 
@@ -3048,10 +3077,12 @@ static int fsg_main_thread(void *fsg_)
        /* 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());
+#endif
 
        /* The main loop */
        while (fsg->state != FSG_STATE_TERMINATED) {
@@ -3175,6 +3206,9 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
        }
 
        set_gadget_data(gadget, NULL);
+#ifdef CONFIG_FSL_UTP
+       utp_exit(fsg);
+#endif
 }
 
 
@@ -3209,6 +3243,17 @@ static int __init check_parameters(struct fsg_dev *fsg)
 
        prot = simple_strtol(mod_data.protocol_parm, NULL, 0);
 
+#ifdef CONFIG_FSL_UTP
+       mod_data.can_stall = 0;
+       mod_data.removable = 1;
+       mod_data.nluns = 1;
+       mod_data.file[0] = NULL;
+       mod_data.vendor = 0x066F;
+       mod_data.product = 0x37FF;
+       pr_info("%s:UTP settings are in place now, overriding defaults\n",
+               __func__);
+#endif
+
 #ifdef CONFIG_USB_FILE_STORAGE_TEST
        if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) {
                ;               // Use default setting
@@ -3297,8 +3342,9 @@ static int __init check_parameters(struct fsg_dev *fsg)
 
        return 0;
 }
-
-
+#ifdef CONFIG_FSL_UTP
+#include "fsl_updater.c"
+#endif
 static int __init fsg_bind(struct usb_gadget *gadget)
 {
        struct fsg_dev          *fsg = the_fsg;
@@ -3329,6 +3375,9 @@ static int __init fsg_bind(struct usb_gadget *gadget)
        /* Only for removable media? */
        dev_attr_nofua.attr.mode = 0644;
        dev_attr_nofua.store = fsg_store_nofua;
+#ifdef CONFIG_FSL_UTP
+       utp_init(fsg);
+#endif
 
        /* Find out how many LUNs there should be */
        i = mod_data.nluns;
diff --git a/drivers/usb/gadget/fsl_updater.c b/drivers/usb/gadget/fsl_updater.c
new file mode 100644 (file)
index 0000000..cd8ba24
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+ * Freescale UUT driver
+ *
+ * Copyright 2008-2010 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;
+}
+
+static int
+utp_ioctl(struct inode *inode, struct file *file,
+             unsigned int cmd, unsigned long arg)
+{
+       int cpu_id = 0;
+       switch (cmd) {
+       case UTP_GET_CPU_ID:
+/* Currently, it only supports below SoC for manufacture tool
+ * The naming rule
+ * 1. The numberic for SoC string
+ * 2. If there is next SoC version, and the corresponding utp
+ * operation will be differ, then, need to add '1' next to SoC
+ * name. Such as the next 50 SoC version is: cpu_is = 501
+ */
+#ifdef CONFIG_ARCH_MXS
+               if (cpu_is_mx23())
+                       cpu_id = 23;
+               else if (cpu_is_mx28())
+                       cpu_id = 28;
+#endif
+#ifdef CONFIG_ARCH_MXC
+               if (cpu_is_mx25())
+                       cpu_id = 25;
+               else if (cpu_is_mx35())
+                       cpu_id = 35;
+               else if (cpu_is_mx51())
+                       cpu_id = 51;
+               else if (cpu_is_mx53())
+                       cpu_id = 53;
+               else if (cpu_is_mx50())
+                       cpu_id = 50;
+#endif
+               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, mod_data.buflen);
+
+               /* Wait for the next buffer to become available */
+               bh = fsg->next_buffhd_to_fill;
+               while (bh->state != BUF_STATE_EMPTY) {
+                       rc = sleep_thread(fsg);
+                       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->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->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->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, mod_data.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->next_buffhd_to_fill = bh->next;
+                       continue;
+               }
+
+               /* Write the received data to the backing file */
+               bh = fsg->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->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->residue -= amount;
+
+                       /* Did the host decide to stop early? */
+                       if (bh->outreq->actual != bh->outreq->length) {
+                               fsg->short_packet_received = 1;
+                               break;
+                       }
+                       continue;
+               }
+
+               /* Wait for something to happen */
+               rc = sleep_thread(fsg);
+               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 = USB_STATUS_PASS;
+       struct bulk_cs_wrap     *csw;
+       int                     rc;
+
+       /* Wait for the next buffer to become available */
+       bh = fsg->next_buffhd_to_fill;
+       while (bh->state != BUF_STATE_EMPTY) {
+               rc = sleep_thread(fsg);
+               if (rc)
+                       return rc;
+       }
+
+       if (fsg->phase_error) {
+               DBG(fsg, "sending phase-error status\n");
+               status = USB_STATUS_PHASE_ERROR;
+
+       } else if ((UTP_CTX(fsg)->sd & 0xFFFF) != UTP_REPLY_PASS) {
+               status = USB_STATUS_FAIL;
+       }
+
+       csw = bh->buf;
+
+       /* Store and send the Bulk-only CSW */
+       csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG);
+       csw->Tag = fsg->tag;
+       csw->Residue = cpu_to_le32(fsg->residue);
+       csw->Status = status;
+
+       bh->inreq->length = USB_BULK_CS_WRAP_LEN;
+       bh->inreq->zero = 0;
+       start_transfer(fsg, fsg->bulk_in, bh->inreq,
+                       &bh->inreq_busy, &bh->state);
+       fsg->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->data_size, GFP_KERNEL);
+               /* copy data from usb buffer to utp buffer */
+               utp_do_write(fsg, data, fsg->data_size);
+               utp_exec(fsg, data, fsg->data_size, param);
+               kfree(data);
+               break;
+       case UTP_GET: /* data from device to host */
+               pr_debug("%s: GET, %d bytes\n", __func__, fsg->data_size);
+               r = utp_do_read(fsg, UTP_CTX(fsg)->buffer, fsg->data_size);
+               UTP_SS_PASS(fsg);
+               break;
+       case UTP_PUT: /* data from host to device */
+               pr_debug("%s: PUT, %d bytes\n", __func__, fsg->data_size);
+               uud2r = utp_user_data_alloc(fsg->data_size);
+               uud2r->data.bufsize = fsg->data_size;
+               uud2r->data.flags = UTP_FLAG_DATA;
+               utp_do_write(fsg, uud2r->data.data, fsg->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..1662f9d
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Freescale UUT driver
+ *
+ * Copyright 2008-2010 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 int utp_ioctl(struct inode *inode, 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,
+};
+
+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 */
+