diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index c915c79729..36e238a2d8 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_USB_GADGET_DOWNLOAD) += g_dnl.o obj-$(CONFIG_USB_FUNCTION_THOR) += f_thor.o obj-$(CONFIG_USB_FUNCTION_DFU) += f_dfu.o obj-$(CONFIG_USB_FUNCTION_MASS_STORAGE) += f_mass_storage.o +obj-$(CONFIG_USB_FUNCTION_FSL_UTP) += fsl_updater.o obj-$(CONFIG_USB_FUNCTION_FASTBOOT) += f_fastboot.o endif ifdef CONFIG_USB_ETHER diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 1ecb92ac6b..cf3ae89e5f 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -258,6 +258,12 @@ #include #include +#ifdef CONFIG_USB_FUNCTION_FSL_UTP +#include "fsl_updater.h" +#endif + +#include "f_mass_storage.h" + /*------------------------------------------------------------------------*/ #define FSG_DRIVER_DESC "Mass Storage Function" @@ -274,15 +280,6 @@ static const char fsg_string_interface[] = "Mass Storage"; /*-------------------------------------------------------------------------*/ -#define GFP_ATOMIC ((gfp_t) 0) -#define PAGE_CACHE_SHIFT 12 -#define PAGE_CACHE_SIZE (1 << PAGE_CACHE_SHIFT) -#define kthread_create(...) __builtin_return_address(0) -#define wait_for_completion(...) do {} while (0) - -struct kref {int x; }; -struct completion {int x; }; - inline void set_bit(int nr, volatile void *addr) { int mask; @@ -303,67 +300,6 @@ inline void clear_bit(int nr, volatile void *addr) *a &= ~mask; } -struct fsg_dev; -struct fsg_common; - -/* Data shared by all the FSG instances. */ -struct fsg_common { - struct usb_gadget *gadget; - struct fsg_dev *fsg, *new_fsg; - - struct usb_ep *ep0; /* Copy of gadget->ep0 */ - struct usb_request *ep0req; /* Copy of cdev->req */ - unsigned int ep0_req_tag; - - struct fsg_buffhd *next_buffhd_to_fill; - struct fsg_buffhd *next_buffhd_to_drain; - struct fsg_buffhd buffhds[FSG_NUM_BUFFERS]; - - int cmnd_size; - u8 cmnd[MAX_COMMAND_SIZE]; - - unsigned int nluns; - unsigned int lun; - struct fsg_lun luns[FSG_MAX_LUNS]; - - unsigned int bulk_out_maxpacket; - enum fsg_state state; /* For exception handling */ - unsigned int exception_req_tag; - - enum data_direction data_dir; - u32 data_size; - u32 data_size_from_cmnd; - u32 tag; - u32 residue; - u32 usb_amount_left; - - unsigned int can_stall:1; - unsigned int free_storage_on_release:1; - unsigned int phase_error:1; - unsigned int short_packet_received:1; - unsigned int bad_lun_okay:1; - unsigned int running:1; - - int thread_wakeup_needed; - struct completion thread_notifier; - struct task_struct *thread_task; - - /* Callback functions. */ - const struct fsg_operations *ops; - /* Gadget's private data. */ - void *private_data; - - const char *vendor_name; /* 8 characters or less */ - const char *product_name; /* 16 characters or less */ - u16 release; - - /* Vendor (8 chars), product (16 chars), release (4 - * hexadecimal digits) and NUL byte */ - char inquiry_string[8 + 16 + 4 + 1]; - - struct kref ref; -}; - struct fsg_config { unsigned nluns; struct fsg_lun_config { @@ -385,23 +321,6 @@ struct fsg_config { char can_stall; }; -struct fsg_dev { - struct usb_function function; - struct usb_gadget *gadget; /* Copy of cdev->gadget */ - struct fsg_common *common; - - u16 interface_number; - - unsigned int bulk_in_enabled:1; - unsigned int bulk_out_enabled:1; - - unsigned long atomic_bitflags; -#define IGNORE_BULK_OUT 0 - - struct usb_ep *bulk_in; - struct usb_ep *bulk_out; -}; - static inline int __fsg_is_set(struct fsg_common *common, const char *func, unsigned line) @@ -2016,6 +1935,12 @@ static int do_scsi_command(struct fsg_common *common) reply = do_write(common); break; +#ifdef CONFIG_USB_FUNCTION_FSL_UTP + case SC_FSL_UTP: + debug("got FSL UTP command\n"); + return utp_handle_message(common->fsg, common->cmnd, reply); +#endif + /* Some mandatory commands that we recognize but don't implement. * They don't mean much in this setting. It's left as an exercise * for anyone interested to implement RESERVE and RELEASE in terms diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h new file mode 100644 index 0000000000..ae85b6bb4f --- /dev/null +++ b/drivers/usb/gadget/f_mass_storage.h @@ -0,0 +1,329 @@ +/* + * f_mass_storage.c -- Mass Storage USB Composite Function + * + * Copyright (C) 2003-2008 Alan Stern + * Copyright (C) 2009 Samsung Electronics + * Author: Michal Nazarewicz + * All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause + */ + +#ifndef __F_MASS_STORAGE_H__ +#define __F_MASS_STORAGE_H__ + +#include + +/*-------------------------------------------------------------------------*/ + +/* SCSI device types */ +#define TYPE_DISK 0x00 +#define TYPE_CDROM 0x05 + +/* USB protocol value = the transport method */ +#define USB_PR_CBI 0x00 /* Control/Bulk/Interrupt */ +#define USB_PR_CB 0x01 /* Control/Bulk w/o interrupt */ +#define USB_PR_BULK 0x50 /* Bulk-only */ + +/* USB subclass value = the protocol encapsulation */ +#define USB_SC_RBC 0x01 /* Reduced Block Commands (flash) */ +#define USB_SC_8020 0x02 /* SFF-8020i, MMC-2, ATAPI (CD-ROM) */ +#define USB_SC_QIC 0x03 /* QIC-157 (tape) */ +#define USB_SC_UFI 0x04 /* UFI (floppy) */ +#define USB_SC_8070 0x05 /* SFF-8070i (removable) */ +#define USB_SC_SCSI 0x06 /* Transparent SCSI */ + +/* Bulk-only data structures */ + +/* Command Block Wrapper */ +struct fsg_bulk_cb_wrap { + __le32 Signature; /* Contains 'USBC' */ + u32 Tag; /* Unique per command id */ + __le32 DataTransferLength; /* Size of the data */ + u8 Flags; /* Direction in bit 7 */ + u8 Lun; /* LUN (normally 0) */ + u8 Length; /* Of the CDB, <= MAX_COMMAND_SIZE */ + u8 CDB[16]; /* Command Data Block */ +}; + +#define USB_BULK_CB_WRAP_LEN 31 +#define USB_BULK_CB_SIG 0x43425355 /* Spells out USBC */ +#define USB_BULK_IN_FLAG 0x80 + +/* Command Status Wrapper */ +struct bulk_cs_wrap { + __le32 Signature; /* Should = 'USBS' */ + u32 Tag; /* Same as original command */ + __le32 Residue; /* Amount not transferred */ + u8 Status; /* See below */ +}; + +#define USB_BULK_CS_WRAP_LEN 13 +#define USB_BULK_CS_SIG 0x53425355 /* Spells out 'USBS' */ +#define USB_STATUS_PASS 0 +#define USB_STATUS_FAIL 1 +#define USB_STATUS_PHASE_ERROR 2 + +/* Bulk-only class specific requests */ +#define USB_BULK_RESET_REQUEST 0xff +#define USB_BULK_GET_MAX_LUN_REQUEST 0xfe + +/* CBI Interrupt data structure */ +struct interrupt_data { + u8 bType; + u8 bValue; +}; + +#define CBI_INTERRUPT_DATA_LEN 2 + +/* CBI Accept Device-Specific Command request */ +#define USB_CBI_ADSC_REQUEST 0x00 + +/* Length of a SCSI Command Data Block */ +#define MAX_COMMAND_SIZE 16 + +/* SCSI commands that we recognize */ +#define SC_FORMAT_UNIT 0x04 +#define SC_INQUIRY 0x12 +#define SC_MODE_SELECT_6 0x15 +#define SC_MODE_SELECT_10 0x55 +#define SC_MODE_SENSE_6 0x1a +#define SC_MODE_SENSE_10 0x5a +#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e +#define SC_READ_6 0x08 +#define SC_READ_10 0x28 +#define SC_READ_12 0xa8 +#define SC_READ_CAPACITY 0x25 +#define SC_READ_FORMAT_CAPACITIES 0x23 +#define SC_READ_HEADER 0x44 +#define SC_READ_TOC 0x43 +#define SC_RELEASE 0x17 +#define SC_REQUEST_SENSE 0x03 +#define SC_RESERVE 0x16 +#define SC_SEND_DIAGNOSTIC 0x1d +#define SC_START_STOP_UNIT 0x1b +#define SC_SYNCHRONIZE_CACHE 0x35 +#define SC_TEST_UNIT_READY 0x00 +#define SC_VERIFY 0x2f +#define SC_WRITE_6 0x0a +#define SC_WRITE_10 0x2a +#define SC_WRITE_12 0xaa + +/* Vendor specific */ +#ifdef CONFIG_USB_FUNCTION_FSL_UTP +#define SC_FSL_UTP 0xf0 +#endif + + +/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ +#define SS_NO_SENSE 0 +#define SS_COMMUNICATION_FAILURE 0x040800 +#define SS_INVALID_COMMAND 0x052000 +#define SS_INVALID_FIELD_IN_CDB 0x052400 +#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100 +#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500 +#define SS_MEDIUM_NOT_PRESENT 0x023a00 +#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302 +#define SS_NOT_READY_TO_READY_TRANSITION 0x062800 +#define SS_RESET_OCCURRED 0x062900 +#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900 +#define SS_UNRECOVERED_READ_ERROR 0x031100 +#define SS_WRITE_ERROR 0x030c02 +#define SS_WRITE_PROTECTED 0x072700 + +#define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */ +#define ASC(x) ((u8) ((x) >> 8)) +#define ASCQ(x) ((u8) (x)) + +struct device_attribute { int i; }; +#define ETOOSMALL 525 + +/*-------------------------------------------------------------------------*/ + +struct fsg_lun { + loff_t file_length; + loff_t num_sectors; + + unsigned int initially_ro:1; + unsigned int ro:1; + unsigned int removable:1; + unsigned int cdrom:1; + unsigned int prevent_medium_removal:1; + unsigned int registered:1; + unsigned int info_valid:1; + unsigned int nofua:1; + + u32 sense_data; + u32 sense_data_info; + u32 unit_attention_data; + + struct device dev; +}; + +#define fsg_lun_is_open(curlun) ((curlun)->filp != NULL) +#if 0 +static struct fsg_lun *fsg_lun_from_dev(struct device *dev) +{ + return container_of(dev, struct fsg_lun, dev); +} +#endif + +/* Big enough to hold our biggest descriptor */ +#define EP0_BUFSIZE 256 +#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */ + +/* Number of buffers we will use. 2 is enough for double-buffering */ +#define FSG_NUM_BUFFERS 2 + +/* Default size of buffer length. */ +#define FSG_BUFLEN ((u32)16384) + +/* Maximal number of LUNs supported in mass storage function */ +#define FSG_MAX_LUNS 8 + +enum fsg_buffer_state { + BUF_STATE_EMPTY = 0, + BUF_STATE_FULL, + BUF_STATE_BUSY +}; + +struct fsg_buffhd { +#ifdef FSG_BUFFHD_STATIC_BUFFER + char buf[FSG_BUFLEN]; +#else + void *buf; +#endif + enum fsg_buffer_state state; + struct fsg_buffhd *next; + + /* + * The NetChip 2280 is faster, and handles some protocol faults + * better, if we don't submit any short bulk-out read requests. + * So we will record the intended request length here. + */ + unsigned int bulk_out_intended_length; + + struct usb_request *inreq; + int inreq_busy; + struct usb_request *outreq; + int outreq_busy; +}; + +enum fsg_state { + /* This one isn't used anywhere */ + FSG_STATE_COMMAND_PHASE = -10, + FSG_STATE_DATA_PHASE, + FSG_STATE_STATUS_PHASE, + + FSG_STATE_IDLE = 0, + FSG_STATE_ABORT_BULK_OUT, + FSG_STATE_RESET, + FSG_STATE_INTERFACE_CHANGE, + FSG_STATE_CONFIG_CHANGE, + FSG_STATE_DISCONNECT, + FSG_STATE_EXIT, + FSG_STATE_TERMINATED +}; + +enum data_direction { + DATA_DIR_UNKNOWN = 0, + DATA_DIR_FROM_HOST, + DATA_DIR_TO_HOST, + DATA_DIR_NONE +}; + +/*-------------------------------------------------------------------------*/ + +#define GFP_ATOMIC ((gfp_t) 0) +#define PAGE_CACHE_SHIFT 12 +#define PAGE_CACHE_SIZE (1 << PAGE_CACHE_SHIFT) +#define kthread_create(...) __builtin_return_address(0) +#define wait_for_completion(...) do {} while (0) + +struct kref {int x; }; +struct completion {int x; }; + +struct fsg_dev; + +/* Data shared by all the FSG instances. */ +struct fsg_common { + struct usb_gadget *gadget; + struct fsg_dev *fsg, *new_fsg; + + struct usb_ep *ep0; /* Copy of gadget->ep0 */ + struct usb_request *ep0req; /* Copy of cdev->req */ + unsigned int ep0_req_tag; + + struct fsg_buffhd *next_buffhd_to_fill; + struct fsg_buffhd *next_buffhd_to_drain; + struct fsg_buffhd buffhds[FSG_NUM_BUFFERS]; + + int cmnd_size; + u8 cmnd[MAX_COMMAND_SIZE]; + + unsigned int nluns; + unsigned int lun; + struct fsg_lun luns[FSG_MAX_LUNS]; + + unsigned int bulk_out_maxpacket; + enum fsg_state state; /* For exception handling */ + unsigned int exception_req_tag; + + enum data_direction data_dir; + u32 data_size; + u32 data_size_from_cmnd; + u32 tag; + u32 residue; + u32 usb_amount_left; + + unsigned int can_stall:1; + unsigned int free_storage_on_release:1; + unsigned int phase_error:1; + unsigned int short_packet_received:1; + unsigned int bad_lun_okay:1; + unsigned int running:1; + + int thread_wakeup_needed; + struct completion thread_notifier; + struct task_struct *thread_task; + + /* Callback functions. */ + const struct fsg_operations *ops; + /* Gadget's private data. */ + void *private_data; + + const char *vendor_name; /* 8 characters or less */ + const char *product_name; /* 16 characters or less */ + u16 release; + + /* Vendor (8 chars), product (16 chars), release (4 + * hexadecimal digits) and NUL byte */ + char inquiry_string[8 + 16 + 4 + 1]; + + struct kref ref; +}; + + +struct fsg_dev { + struct usb_function function; + struct usb_gadget *gadget; /* Copy of cdev->gadget */ + struct fsg_common *common; + + u16 interface_number; + + unsigned int bulk_in_enabled:1; + unsigned int bulk_out_enabled:1; + + unsigned long atomic_bitflags; +#define IGNORE_BULK_OUT 0 + + struct usb_ep *bulk_in; + struct usb_ep *bulk_out; + +#ifdef CONFIG_USB_FUNCTION_FSL_UTP + void *utp; +#endif +}; + +#endif + diff --git a/drivers/usb/gadget/fsl_updater.c b/drivers/usb/gadget/fsl_updater.c new file mode 100644 index 0000000000..34bef6f009 --- /dev/null +++ b/drivers/usb/gadget/fsl_updater.c @@ -0,0 +1,602 @@ +/* + * Freescale UUT driver + * + * Copyright 2008-2014 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 + */ + +#include +#include + +#include "fsl_updater.h" + +/*#include "storage_common.c"*/ + +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 = vmalloc(size + sizeof(*uud)); + if (!uud) + return uud; + memset(uud, 0, size + sizeof(*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); + vfree(uud); +} + +/* Get the number of element for list */ +static u32 count_list(struct list_head *l) +{ + u32 count = 0; + struct list_head *tmp; + + mutex_lock(&utp_context.lock); + list_for_each(tmp, l) { + count++; + } + mutex_unlock(&utp_context.lock); + + 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)) { + printk(KERN_INFO "[ %s ] copy error\n", __func__); + 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 (uud == NULL) + return -ENOMEM; + if (copy_from_user(&uud->data, buf, size)) { + printk(KERN_INFO "[ %s ] copy error!\n", __func__); + vfree(uud); + 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) +{ + return 0l; +/* 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, true); + 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, true); + 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 if (uud->data.flags & UTP_FLAG_REPORT_BUSY) { + UTP_SS_BUSY(fsg, --ctx->counter); + } else { + printk("%s: pass returned.\n", __func__); + UTP_SS_PASS(fsg); + } + utp_user_data_free(uud); + } else { + if (utp_context.cur_state & UTP_FLAG_DATA) { + if (count_list(&ctx->read) < 7) { + pr_debug("%s: pass returned in POLL stage. \n", __func__); + UTP_SS_PASS(fsg); + utp_context.cur_state = 0; + return; + } + } + 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); + + ctx->counter = 0xFFFF; + uud2r = utp_user_data_alloc(cmdsize + 1); + if (!uud2r) + return -ENOMEM; + 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) { + 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 returned in EXEC stage. \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->common->next_buffhd_to_fill; + while (bh->state != BUF_STATE_EMPTY) { + rc = sleep_thread(fsg->common, true); + if (rc) + return rc; + } + + if (fsg->common->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->common->tag; + csw->Residue = cpu_to_le32(fsg->common->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->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 = vmalloc(fsg->common->data_size); + memset(data, 0, fsg->common->data_size); + /* 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); + vfree(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: + utp_context.cur_state = UTP_FLAG_DATA; + pr_debug("%s: PUT, Received %d bytes\n", __func__, fsg->common->data_size);/* data from host to device */ + uud2r = utp_user_data_alloc(fsg->common->data_size); + if (!uud2r) + return -ENOMEM; + 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 + if (count_list(&UTP_CTX(fsg)->read) < 7) { + utp_context.cur_state = 0; + UTP_SS_PASS(fsg); + } else + UTP_SS_BUSY(fsg, UTP_CTX(fsg)->counter); + + 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 index 0000000000..cd17e89fa9 --- /dev/null +++ b/drivers/usb/gadget/fsl_updater.h @@ -0,0 +1,151 @@ +/* + * Freescale UUT driver + * + * Copyright 2008-2014 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 */ +#include +/*#include */ +#include "f_mass_storage.h" +/* #include */ + +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; + u32 cur_state; +} 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 */ + diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index b6df130a14..5b28b90126 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -151,222 +151,10 @@ #endif /* DUMP_MSGS */ -/*-------------------------------------------------------------------------*/ - -/* SCSI device types */ -#define TYPE_DISK 0x00 -#define TYPE_CDROM 0x05 - -/* USB protocol value = the transport method */ -#define USB_PR_CBI 0x00 /* Control/Bulk/Interrupt */ -#define USB_PR_CB 0x01 /* Control/Bulk w/o interrupt */ -#define USB_PR_BULK 0x50 /* Bulk-only */ - -/* USB subclass value = the protocol encapsulation */ -#define USB_SC_RBC 0x01 /* Reduced Block Commands (flash) */ -#define USB_SC_8020 0x02 /* SFF-8020i, MMC-2, ATAPI (CD-ROM) */ -#define USB_SC_QIC 0x03 /* QIC-157 (tape) */ -#define USB_SC_UFI 0x04 /* UFI (floppy) */ -#define USB_SC_8070 0x05 /* SFF-8070i (removable) */ -#define USB_SC_SCSI 0x06 /* Transparent SCSI */ - -/* Bulk-only data structures */ - -/* Command Block Wrapper */ -struct fsg_bulk_cb_wrap { - __le32 Signature; /* Contains 'USBC' */ - u32 Tag; /* Unique per command id */ - __le32 DataTransferLength; /* Size of the data */ - u8 Flags; /* Direction in bit 7 */ - u8 Lun; /* LUN (normally 0) */ - u8 Length; /* Of the CDB, <= MAX_COMMAND_SIZE */ - u8 CDB[16]; /* Command Data Block */ -}; - -#define USB_BULK_CB_WRAP_LEN 31 -#define USB_BULK_CB_SIG 0x43425355 /* Spells out USBC */ -#define USB_BULK_IN_FLAG 0x80 - -/* Command Status Wrapper */ -struct bulk_cs_wrap { - __le32 Signature; /* Should = 'USBS' */ - u32 Tag; /* Same as original command */ - __le32 Residue; /* Amount not transferred */ - u8 Status; /* See below */ -}; - -#define USB_BULK_CS_WRAP_LEN 13 -#define USB_BULK_CS_SIG 0x53425355 /* Spells out 'USBS' */ -#define USB_STATUS_PASS 0 -#define USB_STATUS_FAIL 1 -#define USB_STATUS_PHASE_ERROR 2 - -/* Bulk-only class specific requests */ -#define USB_BULK_RESET_REQUEST 0xff -#define USB_BULK_GET_MAX_LUN_REQUEST 0xfe - -/* CBI Interrupt data structure */ -struct interrupt_data { - u8 bType; - u8 bValue; -}; - -#define CBI_INTERRUPT_DATA_LEN 2 - -/* CBI Accept Device-Specific Command request */ -#define USB_CBI_ADSC_REQUEST 0x00 - -/* Length of a SCSI Command Data Block */ -#define MAX_COMMAND_SIZE 16 - -/* SCSI commands that we recognize */ -#define SC_FORMAT_UNIT 0x04 -#define SC_INQUIRY 0x12 -#define SC_MODE_SELECT_6 0x15 -#define SC_MODE_SELECT_10 0x55 -#define SC_MODE_SENSE_6 0x1a -#define SC_MODE_SENSE_10 0x5a -#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e -#define SC_READ_6 0x08 -#define SC_READ_10 0x28 -#define SC_READ_12 0xa8 -#define SC_READ_CAPACITY 0x25 -#define SC_READ_FORMAT_CAPACITIES 0x23 -#define SC_READ_HEADER 0x44 -#define SC_READ_TOC 0x43 -#define SC_RELEASE 0x17 -#define SC_REQUEST_SENSE 0x03 -#define SC_RESERVE 0x16 -#define SC_SEND_DIAGNOSTIC 0x1d -#define SC_START_STOP_UNIT 0x1b -#define SC_SYNCHRONIZE_CACHE 0x35 -#define SC_TEST_UNIT_READY 0x00 -#define SC_VERIFY 0x2f -#define SC_WRITE_6 0x0a -#define SC_WRITE_10 0x2a -#define SC_WRITE_12 0xaa - -/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ -#define SS_NO_SENSE 0 -#define SS_COMMUNICATION_FAILURE 0x040800 -#define SS_INVALID_COMMAND 0x052000 -#define SS_INVALID_FIELD_IN_CDB 0x052400 -#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100 -#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500 -#define SS_MEDIUM_NOT_PRESENT 0x023a00 -#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302 -#define SS_NOT_READY_TO_READY_TRANSITION 0x062800 -#define SS_RESET_OCCURRED 0x062900 -#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900 -#define SS_UNRECOVERED_READ_ERROR 0x031100 -#define SS_WRITE_ERROR 0x030c02 -#define SS_WRITE_PROTECTED 0x072700 - -#define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */ -#define ASC(x) ((u8) ((x) >> 8)) -#define ASCQ(x) ((u8) (x)) - -struct device_attribute { int i; }; -#define ETOOSMALL 525 - #include /*-------------------------------------------------------------------------*/ -struct fsg_lun { - loff_t file_length; - loff_t num_sectors; - - unsigned int initially_ro:1; - unsigned int ro:1; - unsigned int removable:1; - unsigned int cdrom:1; - unsigned int prevent_medium_removal:1; - unsigned int registered:1; - unsigned int info_valid:1; - unsigned int nofua:1; - - u32 sense_data; - u32 sense_data_info; - u32 unit_attention_data; - - struct device dev; -}; - -#define fsg_lun_is_open(curlun) ((curlun)->filp != NULL) -#if 0 -static struct fsg_lun *fsg_lun_from_dev(struct device *dev) -{ - return container_of(dev, struct fsg_lun, dev); -} -#endif - -/* Big enough to hold our biggest descriptor */ -#define EP0_BUFSIZE 256 -#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */ - -/* Number of buffers we will use. 2 is enough for double-buffering */ -#define FSG_NUM_BUFFERS 2 - -/* Default size of buffer length. */ -#define FSG_BUFLEN ((u32)16384) - -/* Maximal number of LUNs supported in mass storage function */ -#define FSG_MAX_LUNS 8 - -enum fsg_buffer_state { - BUF_STATE_EMPTY = 0, - BUF_STATE_FULL, - BUF_STATE_BUSY -}; - -struct fsg_buffhd { -#ifdef FSG_BUFFHD_STATIC_BUFFER - char buf[FSG_BUFLEN]; -#else - void *buf; -#endif - enum fsg_buffer_state state; - struct fsg_buffhd *next; - - /* - * The NetChip 2280 is faster, and handles some protocol faults - * better, if we don't submit any short bulk-out read requests. - * So we will record the intended request length here. - */ - unsigned int bulk_out_intended_length; - - struct usb_request *inreq; - int inreq_busy; - struct usb_request *outreq; - int outreq_busy; -}; - -enum fsg_state { - /* This one isn't used anywhere */ - FSG_STATE_COMMAND_PHASE = -10, - FSG_STATE_DATA_PHASE, - FSG_STATE_STATUS_PHASE, - - FSG_STATE_IDLE = 0, - FSG_STATE_ABORT_BULK_OUT, - FSG_STATE_RESET, - FSG_STATE_INTERFACE_CHANGE, - FSG_STATE_CONFIG_CHANGE, - FSG_STATE_DISCONNECT, - FSG_STATE_EXIT, - FSG_STATE_TERMINATED -}; - -enum data_direction { - DATA_DIR_UNKNOWN = 0, - DATA_DIR_FROM_HOST, - DATA_DIR_TO_HOST, - DATA_DIR_NONE -}; - -/*-------------------------------------------------------------------------*/ - static inline u32 get_unaligned_be24(u8 *buf) { return 0xffffff & (u32) get_unaligned_be32(buf - 1); diff --git a/include/configs/zero-gravitas.h b/include/configs/zero-gravitas.h index 3dce354d2b..64549787f8 100644 --- a/include/configs/zero-gravitas.h +++ b/include/configs/zero-gravitas.h @@ -18,6 +18,10 @@ #include "imx6_spl.h" #endif +#define CONFIG_USB_GADGET +#define CONFIG_USB_FUNCTION_MASS_STORAGE +#define CONFIG_USB_FUNCTION_FSL_UTP + #define CONFIG_SUPPORT_EMMC_BOOT /* eMMC specific */ #define CONFIG_MXC_EPDC