mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-20 22:21:41 +00:00
Merge branch 'master' of git://git.denx.de/u-boot-usb
This commit is contained in:
commit
3c47f2f487
23 changed files with 4203 additions and 49 deletions
|
@ -42,6 +42,7 @@
|
||||||
#include <power/max8997_muic.h>
|
#include <power/max8997_muic.h>
|
||||||
#include <power/battery.h>
|
#include <power/battery.h>
|
||||||
#include <power/max17042_fg.h>
|
#include <power/max17042_fg.h>
|
||||||
|
#include <usb_mass_storage.h>
|
||||||
|
|
||||||
#include "setup.h"
|
#include "setup.h"
|
||||||
|
|
||||||
|
@ -791,3 +792,65 @@ void init_panel_info(vidinfo_t *vid)
|
||||||
|
|
||||||
setenv("lcdinfo", "lcd=s6e8ax0");
|
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
|
||||||
|
|
|
@ -179,6 +179,7 @@ COBJS-y += cmd_usb.o
|
||||||
COBJS-y += usb.o usb_hub.o
|
COBJS-y += usb.o usb_hub.o
|
||||||
COBJS-$(CONFIG_USB_STORAGE) += usb_storage.o
|
COBJS-$(CONFIG_USB_STORAGE) += usb_storage.o
|
||||||
endif
|
endif
|
||||||
|
COBJS-$(CONFIG_CMD_USB_MASS_STORAGE) += cmd_usb_mass_storage.o
|
||||||
COBJS-$(CONFIG_CMD_XIMG) += cmd_ximg.o
|
COBJS-$(CONFIG_CMD_XIMG) += cmd_ximg.o
|
||||||
COBJS-$(CONFIG_YAFFS2) += cmd_yaffs2.o
|
COBJS-$(CONFIG_YAFFS2) += cmd_yaffs2.o
|
||||||
COBJS-$(CONFIG_CMD_SPL) += cmd_spl.o
|
COBJS-$(CONFIG_CMD_SPL) += cmd_spl.o
|
||||||
|
|
|
@ -50,12 +50,15 @@ static int do_dfu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||||
if (ret)
|
if (ret)
|
||||||
return CMD_RET_FAILURE;
|
return CMD_RET_FAILURE;
|
||||||
|
|
||||||
if (strcmp(argv[3], "list") == 0) {
|
if (argc > 3 && strcmp(argv[3], "list") == 0) {
|
||||||
dfu_show_entities();
|
dfu_show_entities();
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_TRATS
|
||||||
board_usb_init();
|
board_usb_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
g_dnl_register(s);
|
g_dnl_register(s);
|
||||||
while (1) {
|
while (1) {
|
||||||
if (ctrlc())
|
if (ctrlc())
|
||||||
|
|
86
common/cmd_usb_mass_storage.c
Normal file
86
common/cmd_usb_mass_storage.c
Normal 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"
|
||||||
|
);
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <dfu.h>
|
#include <dfu.h>
|
||||||
|
|
||||||
enum dfu_mmc_op {
|
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 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;
|
char *st;
|
||||||
|
|
||||||
dfu->dev_type = DFU_DEV_MMC;
|
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;
|
dfu->layout = DFU_FS_FAT;
|
||||||
} else if (!strcmp(st, "ext4")) {
|
} else if (!strcmp(st, "ext4")) {
|
||||||
dfu->layout = DFU_FS_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 {
|
} else {
|
||||||
printf("%s: Memory layout (%s) not supported!\n", __func__, st);
|
printf("%s: Memory layout (%s) not supported!\n", __func__, st);
|
||||||
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dfu->layout == DFU_FS_EXT4 || dfu->layout == DFU_FS_FAT) {
|
if (dfu->layout == DFU_FS_EXT4 || dfu->layout == DFU_FS_FAT) {
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
/*
|
/*
|
||||||
* Buffers to hold input and output data
|
* 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_input;
|
||||||
static circbuf_t usbtty_output;
|
static circbuf_t usbtty_output;
|
||||||
|
|
||||||
|
|
|
@ -265,10 +265,6 @@ static int smsc95xx_eeprom_confirm_not_busy(struct ueth_data *dev)
|
||||||
|
|
||||||
do {
|
do {
|
||||||
smsc95xx_read_reg(dev, E2P_CMD, &val);
|
smsc95xx_read_reg(dev, E2P_CMD, &val);
|
||||||
if (!(val & E2P_CMD_LOADED_)) {
|
|
||||||
debug("No EEPROM present\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!(val & E2P_CMD_BUSY_))
|
if (!(val & E2P_CMD_BUSY_))
|
||||||
return 0;
|
return 0;
|
||||||
udelay(40);
|
udelay(40);
|
||||||
|
|
|
@ -25,15 +25,21 @@ include $(TOPDIR)/config.mk
|
||||||
|
|
||||||
LIB := $(obj)libusb_gadget.o
|
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
|
# new USB gadget layer dependencies
|
||||||
ifdef CONFIG_USB_GADGET
|
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_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
|
||||||
COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
|
COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
|
||||||
COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o
|
COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o
|
||||||
endif
|
endif
|
||||||
ifdef CONFIG_USB_ETHER
|
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_USB_ETH_RNDIS) += rndis.o
|
||||||
COBJS-$(CONFIG_MV_UDC) += mv_udc.o
|
COBJS-$(CONFIG_MV_UDC) += mv_udc.o
|
||||||
COBJS-$(CONFIG_CPU_PXA25X) += pxa25x_udc.o
|
COBJS-$(CONFIG_CPU_PXA25X) += pxa25x_udc.o
|
||||||
|
|
|
@ -859,6 +859,25 @@ unknown:
|
||||||
if (&f->list == &cdev->config->functions)
|
if (&f->list == &cdev->config->functions)
|
||||||
f = NULL;
|
f = NULL;
|
||||||
break;
|
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)
|
if (f && f->setup)
|
||||||
|
|
|
@ -164,6 +164,9 @@ static void handle_getstatus(struct usb_request *req)
|
||||||
|
|
||||||
/* send status response */
|
/* send status response */
|
||||||
dstat->bStatus = f_dfu->dfu_status;
|
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->bState = f_dfu->dfu_state;
|
||||||
dstat->iString = 0;
|
dstat->iString = 0;
|
||||||
}
|
}
|
||||||
|
|
2793
drivers/usb/gadget/f_mass_storage.c
Normal file
2793
drivers/usb/gadget/f_mass_storage.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include "gadget_chips.h"
|
#include "gadget_chips.h"
|
||||||
#include "composite.c"
|
#include "composite.c"
|
||||||
|
#include "f_mass_storage.c"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* One needs to define the following:
|
* 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);
|
printf("GADGET DRIVER: %s\n", s);
|
||||||
if (!strcmp(s, "usb_dnl_dfu"))
|
if (!strcmp(s, "usb_dnl_dfu"))
|
||||||
ret = dfu_add(c);
|
ret = dfu_add(c);
|
||||||
|
else if (!strcmp(s, "usb_dnl_ums"))
|
||||||
|
ret = fsg_add(c);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -188,6 +191,9 @@ int g_dnl_register(const char *type)
|
||||||
if (!strcmp(type, "dfu")) {
|
if (!strcmp(type, "dfu")) {
|
||||||
strcpy(name, shortname);
|
strcpy(name, shortname);
|
||||||
strcat(name, type);
|
strcat(name, type);
|
||||||
|
} else if (!strcmp(type, "ums")) {
|
||||||
|
strcpy(name, shortname);
|
||||||
|
strcat(name, type);
|
||||||
} else {
|
} else {
|
||||||
printf("%s: unknown command: %s\n", __func__, type);
|
printf("%s: unknown command: %s\n", __func__, type);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
653
drivers/usb/gadget/storage_common.c
Normal file
653
drivers/usb/gadget/storage_common.c
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
|
@ -54,6 +54,7 @@ COBJS-$(CONFIG_USB_EHCI_PPC4XX) += ehci-ppc4xx.o
|
||||||
COBJS-$(CONFIG_USB_EHCI_IXP4XX) += ehci-ixp.o
|
COBJS-$(CONFIG_USB_EHCI_IXP4XX) += ehci-ixp.o
|
||||||
COBJS-$(CONFIG_USB_EHCI_MARVELL) += ehci-marvell.o
|
COBJS-$(CONFIG_USB_EHCI_MARVELL) += ehci-marvell.o
|
||||||
COBJS-$(CONFIG_USB_EHCI_PCI) += ehci-pci.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_TEGRA) += ehci-tegra.o
|
||||||
COBJS-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o
|
COBJS-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o
|
||||||
|
|
||||||
|
|
|
@ -42,11 +42,15 @@ DECLARE_GLOBAL_DATA_PTR;
|
||||||
*/
|
*/
|
||||||
struct exynos_ehci {
|
struct exynos_ehci {
|
||||||
struct exynos_usb_phy *usb;
|
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)
|
static int exynos_usb_parse_dt(const void *blob, struct exynos_ehci *exynos)
|
||||||
{
|
{
|
||||||
|
fdt_addr_t addr;
|
||||||
unsigned int node;
|
unsigned int node;
|
||||||
int depth;
|
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
|
* Get the base address for EHCI controller from the device node
|
||||||
*/
|
*/
|
||||||
exynos->hcd = (unsigned int *)fdtdec_get_addr(blob, node, "reg");
|
addr = fdtdec_get_addr(blob, node, "reg");
|
||||||
if (exynos->hcd == NULL) {
|
if (addr == FDT_ADDR_T_NONE) {
|
||||||
debug("Can't get the EHCI register address\n");
|
debug("Can't get the EHCI register address\n");
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exynos->hcd = (struct ehci_hccr *)addr;
|
||||||
|
|
||||||
depth = 0;
|
depth = 0;
|
||||||
node = fdtdec_next_compatible_subnode(blob, node,
|
node = fdtdec_next_compatible_subnode(blob, node,
|
||||||
COMPAT_SAMSUNG_EXYNOS_USB_PHY, &depth);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Setup the EHCI host controller. */
|
/* Setup the EHCI host controller. */
|
||||||
static void setup_usb_phy(struct exynos_usb_phy *usb)
|
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)
|
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 *)
|
#ifdef CONFIG_OF_CONTROL
|
||||||
kzalloc(sizeof(struct exynos_ehci), GFP_KERNEL);
|
if (exynos_usb_parse_dt(gd->fdt_blob, ctx)) {
|
||||||
if (!exynos) {
|
debug("Unable to parse device tree for ehci-exynos\n");
|
||||||
debug("failed to allocate exynos ehci context\n");
|
return -ENODEV;
|
||||||
return -ENOMEM;
|
|
||||||
}
|
}
|
||||||
|
#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 = ctx->hcd;
|
||||||
|
|
||||||
*hccr = (struct ehci_hccr *)(exynos->hcd);
|
|
||||||
*hcor = (struct ehci_hcor *)((uint32_t) *hccr
|
*hcor = (struct ehci_hcor *)((uint32_t) *hccr
|
||||||
+ HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
|
+ 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)*hccr, (uint32_t)*hcor,
|
||||||
(uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
|
(uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
|
||||||
|
|
||||||
kfree(exynos);
|
|
||||||
|
|
||||||
return 0;
|
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)
|
int ehci_hcd_stop(int index)
|
||||||
{
|
{
|
||||||
struct exynos_ehci *exynos = NULL;
|
struct exynos_ehci *ctx = &exynos;
|
||||||
|
|
||||||
exynos = (struct exynos_ehci *)
|
reset_usb_phy(ctx->usb);
|
||||||
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);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,12 +21,14 @@
|
||||||
* MA 02111-1307 USA
|
* MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <asm/byteorder.h>
|
#include <asm/byteorder.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
#include <usb.h>
|
#include <usb.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <watchdog.h>
|
#include <watchdog.h>
|
||||||
|
#include <linux/compiler.h>
|
||||||
|
|
||||||
#include "ehci.h"
|
#include "ehci.h"
|
||||||
|
|
||||||
|
@ -39,7 +41,10 @@ static struct ehci_ctrl {
|
||||||
struct ehci_hcor *hcor;
|
struct ehci_hcor *hcor;
|
||||||
int rootdev;
|
int rootdev;
|
||||||
uint16_t portreset;
|
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];
|
} ehcic[CONFIG_USB_MAX_CONTROLLER_COUNT];
|
||||||
|
|
||||||
#define ALIGN_END_ADDR(type, ptr, size) \
|
#define ALIGN_END_ADDR(type, ptr, size) \
|
||||||
|
@ -858,6 +863,8 @@ int usb_lowlevel_init(int index, void **controller)
|
||||||
uint32_t reg;
|
uint32_t reg;
|
||||||
uint32_t cmd;
|
uint32_t cmd;
|
||||||
struct QH *qh_list;
|
struct QH *qh_list;
|
||||||
|
struct QH *periodic;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (ehci_hcd_init(index, &ehcic[index].hccr, &ehcic[index].hcor))
|
if (ehci_hcd_init(index, &ehcic[index].hccr, &ehcic[index].hcor))
|
||||||
return -1;
|
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))
|
if (ehci_hcd_init(index, &ehcic[index].hccr, &ehcic[index].hcor))
|
||||||
return -1;
|
return -1;
|
||||||
#endif
|
#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;
|
qh_list = &ehcic[index].qh_list;
|
||||||
|
|
||||||
|
@ -884,6 +894,40 @@ int usb_lowlevel_init(int index, void **controller)
|
||||||
qh_list->qh_overlay.qt_token =
|
qh_list->qh_overlay.qt_token =
|
||||||
cpu_to_hc32(QT_TOKEN_STATUS(QT_TOKEN_STATUS_HALTED));
|
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);
|
reg = ehci_readl(&ehcic[index].hccr->cr_hcsparams);
|
||||||
descriptor.hub.bNbrPorts = HCS_N_PORTS(reg);
|
descriptor.hub.bNbrPorts = HCS_N_PORTS(reg);
|
||||||
debug("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts);
|
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);
|
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
|
int
|
||||||
submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
||||||
int length, int interval)
|
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",
|
debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d",
|
||||||
dev, pipe, buffer, length, interval);
|
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.
|
* not require more than a single qTD.
|
||||||
*/
|
*/
|
||||||
if (length > usb_maxpacket(dev, pipe)) {
|
if (length > usb_maxpacket(dev, pipe)) {
|
||||||
printf("%s: Interrupt transfers requiring several transactions "
|
printf("%s: Interrupt transfers requiring several "
|
||||||
"are not supported.\n", __func__);
|
"transactions are not supported.\n", __func__);
|
||||||
return -1;
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <pci.h>
|
#include <pci.h>
|
||||||
#include <usb.h>
|
#include <usb.h>
|
||||||
|
|
||||||
|
@ -32,31 +33,76 @@ static struct pci_device_id ehci_pci_ids[] = {
|
||||||
{0x12D8, 0x400F}, /* Pericom */
|
{0x12D8, 0x400F}, /* Pericom */
|
||||||
{0, 0}
|
{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
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the appropriate control structures to manage
|
* Create the appropriate control structures to manage
|
||||||
* a new EHCI host controller.
|
* 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;
|
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);
|
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");
|
printf("EHCI host controller not found\n");
|
||||||
return -1;
|
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);
|
PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
|
||||||
*hcor = (struct ehci_hcor *)((uint32_t) *hccr +
|
hcor = (struct ehci_hcor *)((uint32_t) hccr +
|
||||||
HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
|
HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
|
||||||
|
|
||||||
debug("EHCI-PCI init hccr 0x%x and hcor 0x%x hc_length %d\n",
|
debug("EHCI-PCI init hccr 0x%x and hcor 0x%x hc_length %d\n",
|
||||||
(uint32_t)*hccr, (uint32_t)*hcor,
|
(uint32_t)hccr, (uint32_t)hcor,
|
||||||
(uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
|
(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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
59
drivers/usb/host/ehci-spear.c
Normal file
59
drivers/usb/host/ehci-spear.c
Normal 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;
|
||||||
|
}
|
|
@ -69,6 +69,7 @@ struct ehci_hcor {
|
||||||
#define CMD_RUN (1 << 0) /* start/stop HC */
|
#define CMD_RUN (1 << 0) /* start/stop HC */
|
||||||
uint32_t or_usbsts;
|
uint32_t or_usbsts;
|
||||||
#define STS_ASS (1 << 15)
|
#define STS_ASS (1 << 15)
|
||||||
|
#define STS_PSS (1 << 14)
|
||||||
#define STS_HALT (1 << 12)
|
#define STS_HALT (1 << 12)
|
||||||
uint32_t or_usbintr;
|
uint32_t or_usbintr;
|
||||||
#define INTR_UE (1 << 0) /* USB interrupt enable */
|
#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
|
* Add dummy fill value to make the size of this struct
|
||||||
* aligned to 32 bytes
|
* aligned to 32 bytes
|
||||||
*/
|
*/
|
||||||
uint8_t fill[16];
|
union {
|
||||||
|
uint32_t fill[4];
|
||||||
|
void *buffer;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Low level init functions */
|
/* Low level init functions */
|
||||||
|
|
|
@ -273,6 +273,23 @@
|
||||||
*/
|
*/
|
||||||
#define CONFIG_PCI
|
#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 \
|
#define CONFIG_EXTRA_ENV_SETTINGS \
|
||||||
CONFIG_STD_DEVICES_SETTINGS
|
CONFIG_STD_DEVICES_SETTINGS
|
||||||
|
|
||||||
|
|
|
@ -316,4 +316,9 @@
|
||||||
#define CONFIG_VIDEO_BMP_GZIP
|
#define CONFIG_VIDEO_BMP_GZIP
|
||||||
#define CONFIG_SYS_VIDEO_LOGO_MAX_SIZE ((500 * 120 * 4) + (1 << 12))
|
#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 */
|
#endif /* __CONFIG_H */
|
||||||
|
|
55
include/usb_mass_storage.h
Normal file
55
include/usb_mass_storage.h
Normal 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__ */
|
|
@ -475,7 +475,9 @@ typedef struct urb_link {
|
||||||
* function driver to inform it that data has arrived.
|
* 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 urb {
|
||||||
|
|
||||||
struct usb_endpoint_instance *endpoint;
|
struct usb_endpoint_instance *endpoint;
|
||||||
|
|
Loading…
Add table
Reference in a new issue