Merge branch 'master' of git://git.denx.de/u-boot-usb

This commit is contained in:
Tom Rini 2013-03-18 15:33:47 -04:00
commit 3c47f2f487
23 changed files with 4203 additions and 49 deletions

View file

@ -42,6 +42,7 @@
#include <power/max8997_muic.h>
#include <power/battery.h>
#include <power/max17042_fg.h>
#include <usb_mass_storage.h>
#include "setup.h"
@ -791,3 +792,65 @@ void init_panel_info(vidinfo_t *vid)
setenv("lcdinfo", "lcd=s6e8ax0");
}
#ifdef CONFIG_USB_GADGET_MASS_STORAGE
static int ums_read_sector(struct ums_device *ums_dev,
ulong start, lbaint_t blkcnt, void *buf)
{
if (ums_dev->mmc->block_dev.block_read(ums_dev->dev_num,
start + ums_dev->offset, blkcnt, buf) != blkcnt)
return -1;
return 0;
}
static int ums_write_sector(struct ums_device *ums_dev,
ulong start, lbaint_t blkcnt, const void *buf)
{
if (ums_dev->mmc->block_dev.block_write(ums_dev->dev_num,
start + ums_dev->offset, blkcnt, buf) != blkcnt)
return -1;
return 0;
}
static void ums_get_capacity(struct ums_device *ums_dev,
long long int *capacity)
{
long long int tmp_capacity;
tmp_capacity = (long long int) ((ums_dev->offset + ums_dev->part_size)
* SECTOR_SIZE);
*capacity = ums_dev->mmc->capacity - tmp_capacity;
}
static struct ums_board_info ums_board = {
.read_sector = ums_read_sector,
.write_sector = ums_write_sector,
.get_capacity = ums_get_capacity,
.name = "TRATS UMS disk",
.ums_dev = {
.mmc = NULL,
.dev_num = 0,
.offset = 0,
.part_size = 0.
},
};
struct ums_board_info *board_ums_init(unsigned int dev_num, unsigned int offset,
unsigned int part_size)
{
struct mmc *mmc;
mmc = find_mmc_device(dev_num);
if (!mmc)
return NULL;
ums_board.ums_dev.mmc = mmc;
ums_board.ums_dev.dev_num = dev_num;
ums_board.ums_dev.offset = offset;
ums_board.ums_dev.part_size = part_size;
return &ums_board;
}
#endif

View file

@ -179,6 +179,7 @@ COBJS-y += cmd_usb.o
COBJS-y += usb.o usb_hub.o
COBJS-$(CONFIG_USB_STORAGE) += usb_storage.o
endif
COBJS-$(CONFIG_CMD_USB_MASS_STORAGE) += cmd_usb_mass_storage.o
COBJS-$(CONFIG_CMD_XIMG) += cmd_ximg.o
COBJS-$(CONFIG_YAFFS2) += cmd_yaffs2.o
COBJS-$(CONFIG_CMD_SPL) += cmd_spl.o

View file

@ -50,12 +50,15 @@ static int do_dfu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
if (ret)
return CMD_RET_FAILURE;
if (strcmp(argv[3], "list") == 0) {
if (argc > 3 && strcmp(argv[3], "list") == 0) {
dfu_show_entities();
goto done;
}
#ifdef CONFIG_TRATS
board_usb_init();
#endif
g_dnl_register(s);
while (1) {
if (ctrlc())

View file

@ -0,0 +1,86 @@
/*
* Copyright (C) 2011 Samsung Electronics
* Lukasz Majewski <l.majewski@samsung.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <errno.h>
#include <common.h>
#include <command.h>
#include <g_dnl.h>
#include <usb_mass_storage.h>
int do_usb_mass_storage(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
char *ep;
unsigned int dev_num = 0, offset = 0, part_size = 0;
int rc;
struct ums_board_info *ums_info;
static char *s = "ums";
if (argc < 2) {
printf("usage: ums <dev> - e.g. ums 0\n");
return 0;
}
dev_num = (int)simple_strtoul(argv[1], &ep, 16);
if (dev_num) {
puts("\nSet eMMC device to 0! - e.g. ums 0\n");
goto fail;
}
board_usb_init();
ums_info = board_ums_init(dev_num, offset, part_size);
if (!ums_info) {
printf("MMC: %d -> NOT available\n", dev_num);
goto fail;
}
rc = fsg_init(ums_info);
if (rc) {
printf("cmd ums: fsg_init failed\n");
goto fail;
}
g_dnl_register(s);
while (1) {
/* Handle control-c and timeouts */
if (ctrlc()) {
printf("The remote end did not respond in time.\n");
goto exit;
}
usb_gadget_handle_interrupts();
/* Check if USB cable has been detached */
if (fsg_main_thread(NULL) == EIO)
goto exit;
}
exit:
g_dnl_unregister();
return 0;
fail:
return -1;
}
U_BOOT_CMD(ums, CONFIG_SYS_MAXARGS, 1, do_usb_mass_storage,
"Use the UMS [User Mass Storage]",
"ums - User Mass Storage Gadget"
);

View file

@ -21,6 +21,7 @@
#include <common.h>
#include <malloc.h>
#include <errno.h>
#include <dfu.h>
enum dfu_mmc_op {
@ -153,6 +154,10 @@ int dfu_read_medium_mmc(struct dfu_entity *dfu, void *buf, long *len)
int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s)
{
int dev, part;
struct mmc *mmc;
block_dev_desc_t *blk_dev;
disk_partition_t partinfo;
char *st;
dfu->dev_type = DFU_DEV_MMC;
@ -166,8 +171,34 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s)
dfu->layout = DFU_FS_FAT;
} else if (!strcmp(st, "ext4")) {
dfu->layout = DFU_FS_EXT4;
} else if (!strcmp(st, "part")) {
dfu->layout = DFU_RAW_ADDR;
dev = simple_strtoul(s, &s, 10);
s++;
part = simple_strtoul(s, &s, 10);
mmc = find_mmc_device(dev);
if (mmc == NULL || mmc_init(mmc)) {
printf("%s: could not find mmc device #%d!\n", __func__, dev);
return -ENODEV;
}
blk_dev = &mmc->block_dev;
if (get_partition_info(blk_dev, part, &partinfo) != 0) {
printf("%s: could not find partition #%d on mmc device #%d!\n",
__func__, part, dev);
return -ENODEV;
}
dfu->data.mmc.lba_start = partinfo.start;
dfu->data.mmc.lba_size = partinfo.size;
dfu->data.mmc.lba_blk_size = partinfo.blksz;
} else {
printf("%s: Memory layout (%s) not supported!\n", __func__, st);
return -ENODEV;
}
if (dfu->layout == DFU_FS_EXT4 || dfu->layout == DFU_FS_FAT) {

View file

@ -63,7 +63,7 @@
/*
* Buffers to hold input and output data
*/
#define USBTTY_BUFFER_SIZE 256
#define USBTTY_BUFFER_SIZE 2048
static circbuf_t usbtty_input;
static circbuf_t usbtty_output;

View file

@ -265,10 +265,6 @@ static int smsc95xx_eeprom_confirm_not_busy(struct ueth_data *dev)
do {
smsc95xx_read_reg(dev, E2P_CMD, &val);
if (!(val & E2P_CMD_LOADED_)) {
debug("No EEPROM present\n");
return -1;
}
if (!(val & E2P_CMD_BUSY_))
return 0;
udelay(40);

View file

@ -25,15 +25,21 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libusb_gadget.o
# if defined(CONFIG_USB_GADGET) || defined(CONFIG_USB_ETHER)
# Everytime you forget how crufty makefiles can get things like
# this remind you...
ifneq (,$(CONFIG_USB_GADGET)$(CONFIG_USB_ETHER))
COBJS-y += epautoconf.o config.o usbstring.o
endif
# new USB gadget layer dependencies
ifdef CONFIG_USB_GADGET
COBJS-y += epautoconf.o config.o usbstring.o
COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o
endif
ifdef CONFIG_USB_ETHER
COBJS-y += ether.o epautoconf.o config.o usbstring.o
COBJS-y += ether.o
COBJS-$(CONFIG_USB_ETH_RNDIS) += rndis.o
COBJS-$(CONFIG_MV_UDC) += mv_udc.o
COBJS-$(CONFIG_CPU_PXA25X) += pxa25x_udc.o

View file

@ -859,6 +859,25 @@ unknown:
if (&f->list == &cdev->config->functions)
f = NULL;
break;
/*
* dfu-util (version 0.5) sets bmRequestType.Receipent = Device
* for non-standard request (w_value = 0x21,
* bRequest = GET_DESCRIPTOR in this case).
* When only one interface is registered (as it is done now),
* then this request shall be handled as it was requested for
* interface.
*
* In the below code it is checked if only one interface is
* present and proper function for it is extracted. Due to that
* function's setup (f->setup) is called to handle this
* special non-standard request.
*/
case USB_RECIP_DEVICE:
debug("cdev->config->next_interface_id: %d intf: %d\n",
cdev->config->next_interface_id, intf);
if (cdev->config->next_interface_id == 1)
f = cdev->config->interface[intf];
break;
}
if (f && f->setup)

View file

@ -164,6 +164,9 @@ static void handle_getstatus(struct usb_request *req)
/* send status response */
dstat->bStatus = f_dfu->dfu_status;
dstat->bwPollTimeout[0] = 0;
dstat->bwPollTimeout[1] = 0;
dstat->bwPollTimeout[2] = 0;
dstat->bState = f_dfu->dfu_state;
dstat->iString = 0;
}

File diff suppressed because it is too large Load diff

View file

@ -31,6 +31,7 @@
#include "gadget_chips.h"
#include "composite.c"
#include "f_mass_storage.c"
/*
* One needs to define the following:
@ -104,6 +105,8 @@ static int g_dnl_do_config(struct usb_configuration *c)
printf("GADGET DRIVER: %s\n", s);
if (!strcmp(s, "usb_dnl_dfu"))
ret = dfu_add(c);
else if (!strcmp(s, "usb_dnl_ums"))
ret = fsg_add(c);
return ret;
}
@ -188,6 +191,9 @@ int g_dnl_register(const char *type)
if (!strcmp(type, "dfu")) {
strcpy(name, shortname);
strcat(name, type);
} else if (!strcmp(type, "ums")) {
strcpy(name, shortname);
strcat(name, type);
} else {
printf("%s: unknown command: %s\n", __func__, type);
return -EINVAL;

View file

@ -0,0 +1,653 @@
/*
* storage_common.c -- Common definitions for mass storage functionality
*
* Copyright (C) 2003-2008 Alan Stern
* Copyeight (C) 2009 Samsung Electronics
* Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
*
* Ported to u-boot:
* Andrzej Pietrasiewicz <andrzej.p@samsung.com>
*
* Code refactoring & cleanup:
* Łukasz Majewski <l.majewski@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* This file requires the following identifiers used in USB strings to
* be defined (each of type pointer to char):
* - fsg_string_manufacturer -- name of the manufacturer
* - fsg_string_product -- name of the product
* - fsg_string_serial -- product's serial
* - fsg_string_config -- name of the configuration
* - fsg_string_interface -- name of the interface
* The first four are only needed when FSG_DESCRIPTORS_DEVICE_STRINGS
* macro is defined prior to including this file.
*/
/*
* When FSG_NO_INTR_EP is defined fsg_fs_intr_in_desc and
* fsg_hs_intr_in_desc objects as well as
* FSG_FS_FUNCTION_PRE_EP_ENTRIES and FSG_HS_FUNCTION_PRE_EP_ENTRIES
* macros are not defined.
*
* When FSG_NO_DEVICE_STRINGS is defined FSG_STRING_MANUFACTURER,
* FSG_STRING_PRODUCT, FSG_STRING_SERIAL and FSG_STRING_CONFIG are not
* defined (as well as corresponding entries in string tables are
* missing) and FSG_STRING_INTERFACE has value of zero.
*
* When FSG_NO_OTG is defined fsg_otg_desc won't be defined.
*/
/*
* When FSG_BUFFHD_STATIC_BUFFER is defined when this file is included
* the fsg_buffhd structure's buf field will be an array of FSG_BUFLEN
* characters rather then a pointer to void.
*/
/* #include <asm/unaligned.h> */
/*
* Thanks to NetChip Technologies for donating this product ID.
*
* DO NOT REUSE THESE IDs with any other driver!! Ever!!
* Instead: allocate your own, using normal USB-IF procedures.
*/
#define FSG_VENDOR_ID 0x0525 /* NetChip */
#define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */
/*-------------------------------------------------------------------------*/
#ifndef DEBUG
#undef VERBOSE_DEBUG
#undef DUMP_MSGS
#endif /* !DEBUG */
#ifdef VERBOSE_DEBUG
#define VLDBG LDBG
#else
#define VLDBG(lun, fmt, args...) do { } while (0)
#endif /* VERBOSE_DEBUG */
/*
#define LDBG(lun, fmt, args...) dev_dbg (&(lun)->dev, fmt, ## args)
#define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args)
#define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args)
#define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args)
*/
#define LDBG(lun, fmt, args...) do { } while (0)
#define LERROR(lun, fmt, args...) do { } while (0)
#define LWARN(lun, fmt, args...) do { } while (0)
#define LINFO(lun, fmt, args...) do { } while (0)
/*
* Keep those macros in sync with those in
* include/linux/usb/composite.h or else GCC will complain. If they
* are identical (the same names of arguments, white spaces in the
* same places) GCC will allow redefinition otherwise (even if some
* white space is removed or added) warning will be issued.
*
* Those macros are needed here because File Storage Gadget does not
* include the composite.h header. For composite gadgets those macros
* are redundant since composite.h is included any way.
*
* One could check whether those macros are already defined (which
* would indicate composite.h had been included) or not (which would
* indicate we were in FSG) but this is not done because a warning is
* desired if definitions here differ from the ones in composite.h.
*
* We want the definitions to match and be the same in File Storage
* Gadget as well as Mass Storage Function (and so composite gadgets
* using MSF). If someone changes them in composite.h it will produce
* a warning in this file when building MSF.
*/
#define DBG(d, fmt, args...) debug(fmt , ## args)
#define VDBG(d, fmt, args...) debug(fmt , ## args)
/* #define ERROR(d, fmt, args...) printf(fmt , ## args) */
/* #define WARNING(d, fmt, args...) printf(fmt , ## args) */
/* #define INFO(d, fmt, args...) printf(fmt , ## args) */
/* #define DBG(d, fmt, args...) do { } while (0) */
/* #define VDBG(d, fmt, args...) do { } while (0) */
#define ERROR(d, fmt, args...) do { } while (0)
#define WARNING(d, fmt, args...) do { } while (0)
#define INFO(d, fmt, args...) do { } while (0)
#ifdef DUMP_MSGS
/* dump_msg(fsg, const char * label, const u8 * buf, unsigned length); */
# define dump_msg(fsg, label, buf, length) do { \
if (length < 512) { \
DBG(fsg, "%s, length %u:\n", label, length); \
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, \
16, 1, buf, length, 0); \
} \
} while (0)
# define dump_cdb(fsg) do { } while (0)
#else
# define dump_msg(fsg, /* const char * */ label, \
/* const u8 * */ buf, /* unsigned */ length) do { } while (0)
# ifdef VERBOSE_DEBUG
# define dump_cdb(fsg) \
print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, \
16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0) \
# else
# define dump_cdb(fsg) do { } while (0)
# endif /* VERBOSE_DEBUG */
#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; };
struct rw_semaphore { int i; };
#define down_write(...) do { } while (0)
#define up_write(...) do { } while (0)
#define down_read(...) do { } while (0)
#define up_read(...) do { } while (0)
#define ETOOSMALL 525
#include <usb_mass_storage.h>
extern struct ums_board_info *ums_info;
/*-------------------------------------------------------------------------*/
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);
}
/*-------------------------------------------------------------------------*/
enum {
#ifndef FSG_NO_DEVICE_STRINGS
FSG_STRING_MANUFACTURER = 1,
FSG_STRING_PRODUCT,
FSG_STRING_SERIAL,
FSG_STRING_CONFIG,
#endif
FSG_STRING_INTERFACE
};
#ifndef FSG_NO_OTG
static struct usb_otg_descriptor
fsg_otg_desc = {
.bLength = sizeof fsg_otg_desc,
.bDescriptorType = USB_DT_OTG,
.bmAttributes = USB_OTG_SRP,
};
#endif
/* There is only one interface. */
static struct usb_interface_descriptor
fsg_intf_desc = {
.bLength = sizeof fsg_intf_desc,
.bDescriptorType = USB_DT_INTERFACE,
.bNumEndpoints = 2, /* Adjusted during fsg_bind() */
.bInterfaceClass = USB_CLASS_MASS_STORAGE,
.bInterfaceSubClass = USB_SC_SCSI, /* Adjusted during fsg_bind() */
.bInterfaceProtocol = USB_PR_BULK, /* Adjusted during fsg_bind() */
.iInterface = FSG_STRING_INTERFACE,
};
/*
* Three full-speed endpoint descriptors: bulk-in, bulk-out, and
* interrupt-in.
*/
static struct usb_endpoint_descriptor
fsg_fs_bulk_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
/* wMaxPacketSize set by autoconfiguration */
};
static struct usb_endpoint_descriptor
fsg_fs_bulk_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
/* wMaxPacketSize set by autoconfiguration */
};
#ifndef FSG_NO_INTR_EP
static struct usb_endpoint_descriptor
fsg_fs_intr_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize = cpu_to_le16(2),
.bInterval = 32, /* frames -> 32 ms */
};
#ifndef FSG_NO_OTG
# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 2
#else
# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 1
#endif
#endif
static struct usb_descriptor_header *fsg_fs_function[] = {
#ifndef FSG_NO_OTG
(struct usb_descriptor_header *) &fsg_otg_desc,
#endif
(struct usb_descriptor_header *) &fsg_intf_desc,
(struct usb_descriptor_header *) &fsg_fs_bulk_in_desc,
(struct usb_descriptor_header *) &fsg_fs_bulk_out_desc,
#ifndef FSG_NO_INTR_EP
(struct usb_descriptor_header *) &fsg_fs_intr_in_desc,
#endif
NULL,
};
/*
* USB 2.0 devices need to expose both high speed and full speed
* descriptors, unless they only run at full speed.
*
* That means alternate endpoint descriptors (bigger packets)
* and a "device qualifier" ... plus more construction options
* for the configuration descriptor.
*/
static struct usb_endpoint_descriptor
fsg_hs_bulk_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(512),
};
static struct usb_endpoint_descriptor
fsg_hs_bulk_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(512),
.bInterval = 1, /* NAK every 1 uframe */
};
#ifndef FSG_NO_INTR_EP
static struct usb_endpoint_descriptor
fsg_hs_intr_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
/* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
.bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize = cpu_to_le16(2),
.bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */
};
#ifndef FSG_NO_OTG
# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 2
#else
# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 1
#endif
#endif
static struct usb_descriptor_header *fsg_hs_function[] = {
#ifndef FSG_NO_OTG
(struct usb_descriptor_header *) &fsg_otg_desc,
#endif
(struct usb_descriptor_header *) &fsg_intf_desc,
(struct usb_descriptor_header *) &fsg_hs_bulk_in_desc,
(struct usb_descriptor_header *) &fsg_hs_bulk_out_desc,
#ifndef FSG_NO_INTR_EP
(struct usb_descriptor_header *) &fsg_hs_intr_in_desc,
#endif
NULL,
};
/* Maxpacket and other transfer characteristics vary by speed. */
static struct usb_endpoint_descriptor *
fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
struct usb_endpoint_descriptor *hs)
{
if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
return hs;
return fs;
}
/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */
static struct usb_string fsg_strings[] = {
#ifndef FSG_NO_DEVICE_STRINGS
{FSG_STRING_MANUFACTURER, fsg_string_manufacturer},
{FSG_STRING_PRODUCT, fsg_string_product},
{FSG_STRING_SERIAL, fsg_string_serial},
{FSG_STRING_CONFIG, fsg_string_config},
#endif
{FSG_STRING_INTERFACE, fsg_string_interface},
{}
};
static struct usb_gadget_strings fsg_stringtab = {
.language = 0x0409, /* en-us */
.strings = fsg_strings,
};
/*-------------------------------------------------------------------------*/
/*
* If the next two routines are called while the gadget is registered,
* the caller must own fsg->filesem for writing.
*/
static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
{
int ro;
int rc = -EINVAL;
loff_t size;
loff_t num_sectors;
loff_t min_sectors;
/* R/W if we can, R/O if we must */
ro = curlun->initially_ro;
ums_info->get_capacity(&(ums_info->ums_dev), &size);
if (size < 0) {
printf("unable to find file size: %s\n", filename);
rc = (int) size;
goto out;
}
num_sectors = size >> 9; /* File size in 512-byte blocks */
min_sectors = 1;
if (num_sectors < min_sectors) {
printf("file too small: %s\n", filename);
rc = -ETOOSMALL;
goto out;
}
curlun->ro = ro;
curlun->file_length = size;
curlun->num_sectors = num_sectors;
debug("open backing file: %s\n", filename);
rc = 0;
out:
return rc;
}
static void fsg_lun_close(struct fsg_lun *curlun)
{
}
/*-------------------------------------------------------------------------*/
/*
* Sync the file data, don't bother with the metadata.
* This code was copied from fs/buffer.c:sys_fdatasync().
*/
static int fsg_lun_fsync_sub(struct fsg_lun *curlun)
{
return 0;
}
static void store_cdrom_address(u8 *dest, int msf, u32 addr)
{
if (msf) {
/* Convert to Minutes-Seconds-Frames */
addr >>= 2; /* Convert to 2048-byte frames */
addr += 2*75; /* Lead-in occupies 2 seconds */
dest[3] = addr % 75; /* Frames */
addr /= 75;
dest[2] = addr % 60; /* Seconds */
addr /= 60;
dest[1] = addr; /* Minutes */
dest[0] = 0; /* Reserved */
} else {
/* Absolute sector */
put_unaligned_be32(addr, dest);
}
}
/*-------------------------------------------------------------------------*/

View file

@ -54,6 +54,7 @@ COBJS-$(CONFIG_USB_EHCI_PPC4XX) += ehci-ppc4xx.o
COBJS-$(CONFIG_USB_EHCI_IXP4XX) += ehci-ixp.o
COBJS-$(CONFIG_USB_EHCI_MARVELL) += ehci-marvell.o
COBJS-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
COBJS-$(CONFIG_USB_EHCI_SPEAR) += ehci-spear.o
COBJS-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o
COBJS-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o

View file

@ -42,11 +42,15 @@ DECLARE_GLOBAL_DATA_PTR;
*/
struct exynos_ehci {
struct exynos_usb_phy *usb;
unsigned int *hcd;
struct ehci_hccr *hcd;
};
static struct exynos_ehci exynos;
#ifdef CONFIG_OF_CONTROL
static int exynos_usb_parse_dt(const void *blob, struct exynos_ehci *exynos)
{
fdt_addr_t addr;
unsigned int node;
int depth;
@ -59,12 +63,14 @@ static int exynos_usb_parse_dt(const void *blob, struct exynos_ehci *exynos)
/*
* Get the base address for EHCI controller from the device node
*/
exynos->hcd = (unsigned int *)fdtdec_get_addr(blob, node, "reg");
if (exynos->hcd == NULL) {
addr = fdtdec_get_addr(blob, node, "reg");
if (addr == FDT_ADDR_T_NONE) {
debug("Can't get the EHCI register address\n");
return -ENXIO;
}
exynos->hcd = (struct ehci_hccr *)addr;
depth = 0;
node = fdtdec_next_compatible_subnode(blob, node,
COMPAT_SAMSUNG_EXYNOS_USB_PHY, &depth);
@ -85,6 +91,7 @@ static int exynos_usb_parse_dt(const void *blob, struct exynos_ehci *exynos)
return 0;
}
#endif
/* Setup the EHCI host controller. */
static void setup_usb_phy(struct exynos_usb_phy *usb)
@ -144,20 +151,21 @@ static void reset_usb_phy(struct exynos_usb_phy *usb)
*/
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
struct exynos_ehci *exynos = NULL;
struct exynos_ehci *ctx = &exynos;
exynos = (struct exynos_ehci *)
kzalloc(sizeof(struct exynos_ehci), GFP_KERNEL);
if (!exynos) {
debug("failed to allocate exynos ehci context\n");
return -ENOMEM;
#ifdef CONFIG_OF_CONTROL
if (exynos_usb_parse_dt(gd->fdt_blob, ctx)) {
debug("Unable to parse device tree for ehci-exynos\n");
return -ENODEV;
}
#else
ctx->usb = (struct exynos_usb_phy *)samsung_get_base_usb_phy();
ctx->hcd = (struct ehci_hccr *)samsung_get_base_usb_ehci();
#endif
exynos_usb_parse_dt(gd->fdt_blob, exynos);
setup_usb_phy(ctx->usb);
setup_usb_phy(exynos->usb);
*hccr = (struct ehci_hccr *)(exynos->hcd);
*hccr = ctx->hcd;
*hcor = (struct ehci_hcor *)((uint32_t) *hccr
+ HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
@ -165,8 +173,6 @@ int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
(uint32_t)*hccr, (uint32_t)*hcor,
(uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
kfree(exynos);
return 0;
}
@ -176,20 +182,9 @@ int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
*/
int ehci_hcd_stop(int index)
{
struct exynos_ehci *exynos = NULL;
struct exynos_ehci *ctx = &exynos;
exynos = (struct exynos_ehci *)
kzalloc(sizeof(struct exynos_ehci), GFP_KERNEL);
if (!exynos) {
debug("failed to allocate exynos ehci context\n");
return -ENOMEM;
}
exynos_usb_parse_dt(gd->fdt_blob, exynos);
reset_usb_phy(exynos->usb);
kfree(exynos);
reset_usb_phy(ctx->usb);
return 0;
}

View file

@ -21,12 +21,14 @@
* MA 02111-1307 USA
*/
#include <common.h>
#include <errno.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include <usb.h>
#include <asm/io.h>
#include <malloc.h>
#include <watchdog.h>
#include <linux/compiler.h>
#include "ehci.h"
@ -39,7 +41,10 @@ static struct ehci_ctrl {
struct ehci_hcor *hcor;
int rootdev;
uint16_t portreset;
struct QH qh_list __attribute__((aligned(USB_DMA_MINALIGN)));
struct QH qh_list __aligned(USB_DMA_MINALIGN);
struct QH periodic_queue __aligned(USB_DMA_MINALIGN);
uint32_t *periodic_list;
int ntds;
} ehcic[CONFIG_USB_MAX_CONTROLLER_COUNT];
#define ALIGN_END_ADDR(type, ptr, size) \
@ -858,6 +863,8 @@ int usb_lowlevel_init(int index, void **controller)
uint32_t reg;
uint32_t cmd;
struct QH *qh_list;
struct QH *periodic;
int i;
if (ehci_hcd_init(index, &ehcic[index].hccr, &ehcic[index].hcor))
return -1;
@ -870,6 +877,9 @@ int usb_lowlevel_init(int index, void **controller)
if (ehci_hcd_init(index, &ehcic[index].hccr, &ehcic[index].hcor))
return -1;
#endif
/* Set the high address word (aka segment) for 64-bit controller */
if (ehci_readl(&ehcic[index].hccr->cr_hccparams) & 1)
ehci_writel(ehcic[index].hcor->or_ctrldssegment, 0);
qh_list = &ehcic[index].qh_list;
@ -884,6 +894,40 @@ int usb_lowlevel_init(int index, void **controller)
qh_list->qh_overlay.qt_token =
cpu_to_hc32(QT_TOKEN_STATUS(QT_TOKEN_STATUS_HALTED));
/* Set async. queue head pointer. */
ehci_writel(&ehcic[index].hcor->or_asynclistaddr, (uint32_t)qh_list);
/*
* Set up periodic list
* Step 1: Parent QH for all periodic transfers.
*/
periodic = &ehcic[index].periodic_queue;
memset(periodic, 0, sizeof(*periodic));
periodic->qh_link = cpu_to_hc32(QH_LINK_TERMINATE);
periodic->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
periodic->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
/*
* Step 2: Setup frame-list: Every microframe, USB tries the same list.
* In particular, device specifications on polling frequency
* are disregarded. Keyboards seem to send NAK/NYet reliably
* when polled with an empty buffer.
*
* Split Transactions will be spread across microframes using
* S-mask and C-mask.
*/
ehcic[index].periodic_list = memalign(4096, 1024*4);
if (!ehcic[index].periodic_list)
return -ENOMEM;
for (i = 0; i < 1024; i++) {
ehcic[index].periodic_list[i] = (uint32_t)periodic
| QH_LINK_TYPE_QH;
}
/* Set periodic list base address */
ehci_writel(&ehcic[index].hcor->or_periodiclistbase,
(uint32_t)ehcic[index].periodic_list);
reg = ehci_readl(&ehcic[index].hccr->cr_hcsparams);
descriptor.hub.bNbrPorts = HCS_N_PORTS(reg);
debug("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts);
@ -953,10 +997,254 @@ submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
return ehci_submit_async(dev, pipe, buffer, length, setup);
}
struct int_queue {
struct QH *first;
struct QH *current;
struct QH *last;
struct qTD *tds;
};
#define NEXT_QH(qh) (struct QH *)((qh)->qh_link & ~0x1f)
static int
enable_periodic(struct ehci_ctrl *ctrl)
{
uint32_t cmd;
struct ehci_hcor *hcor = ctrl->hcor;
int ret;
cmd = ehci_readl(&hcor->or_usbcmd);
cmd |= CMD_PSE;
ehci_writel(&hcor->or_usbcmd, cmd);
ret = handshake((uint32_t *)&hcor->or_usbsts,
STS_PSS, STS_PSS, 100 * 1000);
if (ret < 0) {
printf("EHCI failed: timeout when enabling periodic list\n");
return -ETIMEDOUT;
}
udelay(1000);
return 0;
}
static int
disable_periodic(struct ehci_ctrl *ctrl)
{
uint32_t cmd;
struct ehci_hcor *hcor = ctrl->hcor;
int ret;
cmd = ehci_readl(&hcor->or_usbcmd);
cmd &= ~CMD_PSE;
ehci_writel(&hcor->or_usbcmd, cmd);
ret = handshake((uint32_t *)&hcor->or_usbsts,
STS_PSS, 0, 100 * 1000);
if (ret < 0) {
printf("EHCI failed: timeout when disabling periodic list\n");
return -ETIMEDOUT;
}
return 0;
}
static int periodic_schedules;
struct int_queue *
create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize,
int elementsize, void *buffer)
{
struct ehci_ctrl *ctrl = dev->controller;
struct int_queue *result = NULL;
int i;
debug("Enter create_int_queue\n");
if (usb_pipetype(pipe) != PIPE_INTERRUPT) {
debug("non-interrupt pipe (type=%lu)", usb_pipetype(pipe));
return NULL;
}
/* limit to 4 full pages worth of data -
* we can safely fit them in a single TD,
* no matter the alignment
*/
if (elementsize >= 16384) {
debug("too large elements for interrupt transfers\n");
return NULL;
}
result = malloc(sizeof(*result));
if (!result) {
debug("ehci intr queue: out of memory\n");
goto fail1;
}
result->first = memalign(32, sizeof(struct QH) * queuesize);
if (!result->first) {
debug("ehci intr queue: out of memory\n");
goto fail2;
}
result->current = result->first;
result->last = result->first + queuesize - 1;
result->tds = memalign(32, sizeof(struct qTD) * queuesize);
if (!result->tds) {
debug("ehci intr queue: out of memory\n");
goto fail3;
}
memset(result->first, 0, sizeof(struct QH) * queuesize);
memset(result->tds, 0, sizeof(struct qTD) * queuesize);
for (i = 0; i < queuesize; i++) {
struct QH *qh = result->first + i;
struct qTD *td = result->tds + i;
void **buf = &qh->buffer;
qh->qh_link = (uint32_t)(qh+1) | QH_LINK_TYPE_QH;
if (i == queuesize - 1)
qh->qh_link = QH_LINK_TERMINATE;
qh->qh_overlay.qt_next = (uint32_t)td;
qh->qh_endpt1 = (0 << 28) | /* No NAK reload (ehci 4.9) */
(usb_maxpacket(dev, pipe) << 16) | /* MPS */
(1 << 14) |
QH_ENDPT1_EPS(ehci_encode_speed(dev->speed)) |
(usb_pipeendpoint(pipe) << 8) | /* Endpoint Number */
(usb_pipedevice(pipe) << 0);
qh->qh_endpt2 = (1 << 30) | /* 1 Tx per mframe */
(1 << 0); /* S-mask: microframe 0 */
if (dev->speed == USB_SPEED_LOW ||
dev->speed == USB_SPEED_FULL) {
debug("TT: port: %d, hub address: %d\n",
dev->portnr, dev->parent->devnum);
qh->qh_endpt2 |= (dev->portnr << 23) |
(dev->parent->devnum << 16) |
(0x1c << 8); /* C-mask: microframes 2-4 */
}
td->qt_next = QT_NEXT_TERMINATE;
td->qt_altnext = QT_NEXT_TERMINATE;
debug("communication direction is '%s'\n",
usb_pipein(pipe) ? "in" : "out");
td->qt_token = (elementsize << 16) |
((usb_pipein(pipe) ? 1 : 0) << 8) | /* IN/OUT token */
0x80; /* active */
td->qt_buffer[0] = (uint32_t)buffer + i * elementsize;
td->qt_buffer[1] = (td->qt_buffer[0] + 0x1000) & ~0xfff;
td->qt_buffer[2] = (td->qt_buffer[0] + 0x2000) & ~0xfff;
td->qt_buffer[3] = (td->qt_buffer[0] + 0x3000) & ~0xfff;
td->qt_buffer[4] = (td->qt_buffer[0] + 0x4000) & ~0xfff;
*buf = buffer + i * elementsize;
}
if (disable_periodic(ctrl) < 0) {
debug("FATAL: periodic should never fail, but did");
goto fail3;
}
/* hook up to periodic list */
struct QH *list = &ctrl->periodic_queue;
result->last->qh_link = list->qh_link;
list->qh_link = (uint32_t)result->first | QH_LINK_TYPE_QH;
if (enable_periodic(ctrl) < 0) {
debug("FATAL: periodic should never fail, but did");
goto fail3;
}
periodic_schedules++;
debug("Exit create_int_queue\n");
return result;
fail3:
if (result->tds)
free(result->tds);
fail2:
if (result->first)
free(result->first);
if (result)
free(result);
fail1:
return NULL;
}
void *poll_int_queue(struct usb_device *dev, struct int_queue *queue)
{
struct QH *cur = queue->current;
/* depleted queue */
if (cur == NULL) {
debug("Exit poll_int_queue with completed queue\n");
return NULL;
}
/* still active */
if (cur->qh_overlay.qt_token & 0x80) {
debug("Exit poll_int_queue with no completed intr transfer. "
"token is %x\n", cur->qh_overlay.qt_token);
return NULL;
}
if (!(cur->qh_link & QH_LINK_TERMINATE))
queue->current++;
else
queue->current = NULL;
debug("Exit poll_int_queue with completed intr transfer. "
"token is %x at %p (first at %p)\n", cur->qh_overlay.qt_token,
&cur->qh_overlay.qt_token, queue->first);
return cur->buffer;
}
/* Do not free buffers associated with QHs, they're owned by someone else */
int
destroy_int_queue(struct usb_device *dev, struct int_queue *queue)
{
struct ehci_ctrl *ctrl = dev->controller;
int result = -1;
unsigned long timeout;
if (disable_periodic(ctrl) < 0) {
debug("FATAL: periodic should never fail, but did");
goto out;
}
periodic_schedules--;
struct QH *cur = &ctrl->periodic_queue;
timeout = get_timer(0) + 500; /* abort after 500ms */
while (!(cur->qh_link & QH_LINK_TERMINATE)) {
debug("considering %p, with qh_link %x\n", cur, cur->qh_link);
if (NEXT_QH(cur) == queue->first) {
debug("found candidate. removing from chain\n");
cur->qh_link = queue->last->qh_link;
result = 0;
break;
}
cur = NEXT_QH(cur);
if (get_timer(0) > timeout) {
printf("Timeout destroying interrupt endpoint queue\n");
result = -1;
goto out;
}
}
if (periodic_schedules > 0) {
result = enable_periodic(ctrl);
if (result < 0)
debug("FATAL: periodic should never fail, but did");
}
out:
free(queue->tds);
free(queue->first);
free(queue);
return result;
}
int
submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int length, int interval)
{
void *backbuffer;
struct int_queue *queue;
unsigned long timeout;
int result = 0, ret;
debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d",
dev, pipe, buffer, length, interval);
@ -972,9 +1260,31 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
* not require more than a single qTD.
*/
if (length > usb_maxpacket(dev, pipe)) {
printf("%s: Interrupt transfers requiring several transactions "
"are not supported.\n", __func__);
printf("%s: Interrupt transfers requiring several "
"transactions are not supported.\n", __func__);
return -1;
}
return ehci_submit_async(dev, pipe, buffer, length, NULL);
queue = create_int_queue(dev, pipe, 1, length, buffer);
timeout = get_timer(0) + USB_TIMEOUT_MS(pipe);
while ((backbuffer = poll_int_queue(dev, queue)) == NULL)
if (get_timer(0) > timeout) {
printf("Timeout poll on interrupt endpoint\n");
result = -ETIMEDOUT;
break;
}
if (backbuffer != buffer) {
debug("got wrong buffer back (%x instead of %x)\n",
(uint32_t)backbuffer, (uint32_t)buffer);
return -EINVAL;
}
ret = destroy_int_queue(dev, queue);
if (ret < 0)
return ret;
/* everything worked out fine */
return result;
}

View file

@ -19,6 +19,7 @@
*/
#include <common.h>
#include <errno.h>
#include <pci.h>
#include <usb.h>
@ -32,31 +33,76 @@ static struct pci_device_id ehci_pci_ids[] = {
{0x12D8, 0x400F}, /* Pericom */
{0, 0}
};
#else
static pci_dev_t ehci_find_class(int index)
{
int bus;
int devnum;
pci_dev_t bdf;
uint32_t class;
for (bus = 0; bus <= pci_last_busno(); bus++) {
for (devnum = 0; devnum < PCI_MAX_PCI_DEVICES-1; devnum++) {
pci_read_config_dword(PCI_BDF(bus, devnum, 0),
PCI_CLASS_REVISION, &class);
if (class >> 16 == 0xffff)
continue;
for (bdf = PCI_BDF(bus, devnum, 0);
bdf <= PCI_BDF(bus, devnum,
PCI_MAX_PCI_FUNCTIONS - 1);
bdf += PCI_BDF(0, 0, 1)) {
pci_read_config_dword(bdf, PCI_CLASS_REVISION,
&class);
if ((class >> 8 == PCI_CLASS_SERIAL_USB_EHCI)
&& !index--)
return bdf;
}
}
}
return -ENODEV;
}
#endif
/*
* Create the appropriate control structures to manage
* a new EHCI host controller.
*/
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
int ehci_hcd_init(int index, struct ehci_hccr **ret_hccr,
struct ehci_hcor **ret_hcor)
{
pci_dev_t pdev;
uint32_t cmd;
struct ehci_hccr *hccr;
struct ehci_hcor *hcor;
#ifdef CONFIG_PCI_EHCI_DEVICE
pdev = pci_find_devices(ehci_pci_ids, CONFIG_PCI_EHCI_DEVICE);
if (pdev == -1) {
#else
pdev = ehci_find_class(index);
#endif
if (pdev < 0) {
printf("EHCI host controller not found\n");
return -1;
}
*hccr = (struct ehci_hccr *)pci_map_bar(pdev,
hccr = (struct ehci_hccr *)pci_map_bar(pdev,
PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
*hcor = (struct ehci_hcor *)((uint32_t) *hccr +
HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
hcor = (struct ehci_hcor *)((uint32_t) hccr +
HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
debug("EHCI-PCI init hccr 0x%x and hcor 0x%x hc_length %d\n",
(uint32_t)*hccr, (uint32_t)*hcor,
(uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
(uint32_t)hccr, (uint32_t)hcor,
(uint32_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
*ret_hccr = hccr;
*ret_hcor = hcor;
/* enable busmaster */
pci_read_config_dword(pdev, PCI_COMMAND, &cmd);
cmd |= PCI_COMMAND_MASTER;
pci_write_config_dword(pdev, PCI_COMMAND, cmd);
return 0;
}

View file

@ -0,0 +1,59 @@
/*
* (C) Copyright 2010
* Armando Visconti, ST Micoelectronics, <armando.visconti@st.com>.
*
* (C) Copyright 2009
* Marvell Semiconductor <www.marvell.com>
* Written-by: Prafulla Wadaskar <prafulla@marvell.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <common.h>
#include <asm/io.h>
#include <usb.h>
#include "ehci.h"
#include <asm/arch/hardware.h>
/*
* Create the appropriate control structures to manage
* a new EHCI host controller.
*/
int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
*hccr = (struct ehci_hccr *)(CONFIG_SYS_UHC0_EHCI_BASE + 0x100);
*hcor = (struct ehci_hcor *)((uint32_t)*hccr
+ HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
debug("SPEAr-ehci: init hccr %x and hcor %x hc_length %d\n",
(uint32_t)*hccr, (uint32_t)*hcor,
(uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
return 0;
}
/*
* Destroy the appropriate control structures corresponding
* the the EHCI host controller.
*/
int ehci_hcd_stop(int index)
{
return 0;
}

View file

@ -69,6 +69,7 @@ struct ehci_hcor {
#define CMD_RUN (1 << 0) /* start/stop HC */
uint32_t or_usbsts;
#define STS_ASS (1 << 15)
#define STS_PSS (1 << 14)
#define STS_HALT (1 << 12)
uint32_t or_usbintr;
#define INTR_UE (1 << 0) /* USB interrupt enable */
@ -245,7 +246,10 @@ struct QH {
* Add dummy fill value to make the size of this struct
* aligned to 32 bytes
*/
uint8_t fill[16];
union {
uint32_t fill[4];
void *buffer;
};
};
/* Low level init functions */

View file

@ -273,6 +273,23 @@
*/
#define CONFIG_PCI
/*-----------------------------------------------------------------------
* USB configuration
*/
#define CONFIG_USB_EHCI
#define CONFIG_USB_EHCI_PCI
#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 12
#define CONFIG_USB_MAX_CONTROLLER_COUNT 2
#define CONFIG_USB_STORAGE
#define CONFIG_USB_KEYBOARD
#define CONFIG_SYS_USB_EVENT_POLL
#define CONFIG_USB_HOST_ETHER
#define CONFIG_USB_ETHER_ASIX
#define CONFIG_USB_ETHER_SMSC95XX
#define CONFIG_CMD_USB
#define CONFIG_EXTRA_ENV_SETTINGS \
CONFIG_STD_DEVICES_SETTINGS

View file

@ -316,4 +316,9 @@
#define CONFIG_VIDEO_BMP_GZIP
#define CONFIG_SYS_VIDEO_LOGO_MAX_SIZE ((500 * 120 * 4) + (1 << 12))
#define CONFIG_CMD_USB_MASS_STORAGE
#if defined(CONFIG_CMD_USB_MASS_STORAGE)
#define CONFIG_USB_GADGET_MASS_STORAGE
#endif
#endif /* __CONFIG_H */

View file

@ -0,0 +1,55 @@
/*
* Copyright (C) 2011 Samsung Electrnoics
* Lukasz Majewski <l.majewski@samsung.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* aloong with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#ifndef __USB_MASS_STORAGE_H__
#define __USB_MASS_STORAGE_H__
#define SECTOR_SIZE 0x200
#include <mmc.h>
struct ums_device {
struct mmc *mmc;
int dev_num;
int offset;
int part_size;
};
struct ums_board_info {
int (*read_sector)(struct ums_device *ums_dev,
ulong start, lbaint_t blkcnt, void *buf);
int (*write_sector)(struct ums_device *ums_dev,
ulong start, lbaint_t blkcnt, const void *buf);
void (*get_capacity)(struct ums_device *ums_dev,
long long int *capacity);
const char *name;
struct ums_device ums_dev;
};
extern void board_usb_init(void);
extern int fsg_init(struct ums_board_info *);
extern void fsg_cleanup(void);
extern struct ums_board_info *board_ums_init(unsigned int,
unsigned int, unsigned int);
extern int usb_gadget_handle_interrupts(void);
extern int fsg_main_thread(void *);
#endif /* __USB_MASS_STORAGE_H__ */

View file

@ -475,7 +475,9 @@ typedef struct urb_link {
* function driver to inform it that data has arrived.
*/
#define URB_BUF_SIZE 128 /* in linux we'd malloc this, but in u-boot we prefer static data */
/* in linux we'd malloc this, but in u-boot we prefer static data */
#define URB_BUF_SIZE 512
struct urb {
struct usb_endpoint_instance *endpoint;