start work on utp support in uboot
parent
71c1effdad
commit
c3ea002c7b
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue