1
0
Fork 0

start work on utp support in uboot

utp
Martin T. H. Sandsmark 2017-01-21 18:06:05 +01:00
parent 71c1effdad
commit c3ea002c7b
7 changed files with 1099 additions and 299 deletions

View File

@ -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

View File

@ -258,6 +258,12 @@
#include <usb/lin_gadget_compat.h>
#include <g_dnl.h>
#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

View File

@ -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 <m.nazarewicz@samsung.com>
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
*/
#ifndef __F_MASS_STORAGE_H__
#define __F_MASS_STORAGE_H__
#include <linux/usb/composite.h>
/*-------------------------------------------------------------------------*/
/* 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

View File

@ -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 <asm/types.h>
#include <asm/unaligned.h>
#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;
}

View File

@ -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 <linux/miscdevice.h>*/
#include <linux/list.h>
/*#include <linux/vmalloc.h>*/
#include "f_mass_storage.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;
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 */

View File

@ -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 <usb_mass_storage.h>
/*-------------------------------------------------------------------------*/
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);

View File

@ -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