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

This commit is contained in:
Tom Rini 2013-11-08 15:25:29 -05:00
commit 15c5cdf5aa
15 changed files with 205 additions and 158 deletions

7
README
View File

@ -1367,6 +1367,13 @@ The following options need to be configured:
for your device for your device
- CONFIG_USBD_PRODUCTID 0xFFFF - CONFIG_USBD_PRODUCTID 0xFFFF
Some USB device drivers may need to check USB cable attachment.
In this case you can enable following config in BoardName.h:
CONFIG_USB_CABLE_CHECK
This enables function definition:
- usb_cable_connected() in include/usb.h
Implementation of this function is board-specific.
- ULPI Layer Support: - ULPI Layer Support:
The ULPI (UTMI Low Pin (count) Interface) PHYs are supported via The ULPI (UTMI Low Pin (count) Interface) PHYs are supported via
the generic ULPI layer. The generic layer accesses the ULPI PHY the generic ULPI layer. The generic layer accesses the ULPI PHY

View File

@ -7,3 +7,4 @@
obj-$(CONFIG_SOFT_I2C_MULTI_BUS) += multi_i2c.o obj-$(CONFIG_SOFT_I2C_MULTI_BUS) += multi_i2c.o
obj-$(CONFIG_THOR_FUNCTION) += thor.o obj-$(CONFIG_THOR_FUNCTION) += thor.o
obj-$(CONFIG_CMD_USB_MASS_STORAGE) += ums.o

View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2013 Samsung Electronics
* Lukasz Majewski <l.majewski@samsung.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <usb_mass_storage.h>
#include <part.h>
static int ums_read_sector(struct ums *ums_dev,
ulong start, lbaint_t blkcnt, void *buf)
{
block_dev_desc_t *block_dev = &ums_dev->mmc->block_dev;
lbaint_t blkstart = start + ums_dev->start_sector;
int dev_num = block_dev->dev;
return block_dev->block_read(dev_num, blkstart, blkcnt, buf);
}
static int ums_write_sector(struct ums *ums_dev,
ulong start, lbaint_t blkcnt, const void *buf)
{
block_dev_desc_t *block_dev = &ums_dev->mmc->block_dev;
lbaint_t blkstart = start + ums_dev->start_sector;
int dev_num = block_dev->dev;
return block_dev->block_write(dev_num, blkstart, blkcnt, buf);
}
static struct ums ums_dev = {
.read_sector = ums_read_sector,
.write_sector = ums_write_sector,
.name = "UMS disk",
};
static struct ums *ums_disk_init(struct mmc *mmc)
{
uint64_t mmc_end_sector = mmc->capacity / SECTOR_SIZE;
uint64_t ums_end_sector = UMS_NUM_SECTORS + UMS_START_SECTOR;
if (!mmc_end_sector) {
error("MMC capacity is not valid");
return NULL;
}
ums_dev.mmc = mmc;
if (ums_end_sector <= mmc_end_sector) {
ums_dev.start_sector = UMS_START_SECTOR;
if (UMS_NUM_SECTORS)
ums_dev.num_sectors = UMS_NUM_SECTORS;
else
ums_dev.num_sectors = mmc_end_sector - UMS_START_SECTOR;
} else {
ums_dev.num_sectors = mmc_end_sector;
puts("UMS: defined bad disk parameters. Using default.\n");
}
printf("UMS: disk start sector: %#x, count: %#x\n",
ums_dev.start_sector, ums_dev.num_sectors);
return &ums_dev;
}
struct ums *ums_init(unsigned int dev_num)
{
struct mmc *mmc = NULL;
mmc = find_mmc_device(dev_num);
if (!mmc)
return NULL;
return ums_disk_init(mmc);
}

View File

@ -772,65 +772,3 @@ 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

View File

@ -5,6 +5,7 @@
* SPDX-License-Identifier: GPL-2.0+ * SPDX-License-Identifier: GPL-2.0+
*/ */
#include <errno.h>
#include <common.h> #include <common.h>
#include <command.h> #include <command.h>
#include <g_dnl.h> #include <g_dnl.h>
@ -20,55 +21,49 @@ int do_usb_mass_storage(cmd_tbl_t *cmdtp, int flag,
const char *usb_controller = argv[1]; const char *usb_controller = argv[1];
const char *mmc_devstring = argv[2]; const char *mmc_devstring = argv[2];
unsigned int dev_num = (unsigned int)(simple_strtoul(mmc_devstring, unsigned int dev_num = simple_strtoul(mmc_devstring, NULL, 0);
NULL, 0));
if (dev_num) { struct ums *ums = ums_init(dev_num);
error("Set eMMC device to 0! - e.g. ums 0"); if (!ums)
goto fail; return CMD_RET_FAILURE;
}
unsigned int controller_index = (unsigned int)(simple_strtoul( unsigned int controller_index = (unsigned int)(simple_strtoul(
usb_controller, NULL, 0)); usb_controller, NULL, 0));
if (board_usb_init(controller_index, USB_INIT_DEVICE)) { if (board_usb_init(controller_index, USB_INIT_DEVICE)) {
error("Couldn't init USB controller."); error("Couldn't init USB controller.");
goto fail; return CMD_RET_FAILURE;
} }
struct ums_board_info *ums_info = board_ums_init(dev_num, 0, 0); int rc = fsg_init(ums);
if (!ums_info) {
error("MMC: %d -> NOT available", dev_num);
goto fail;
}
int rc = fsg_init(ums_info);
if (rc) { if (rc) {
error("fsg_init failed"); error("fsg_init failed");
goto fail; return CMD_RET_FAILURE;
} }
g_dnl_register("ums"); g_dnl_register("ums");
while (1) { while (1) {
/* Handle control-c and timeouts */ usb_gadget_handle_interrupts();
if (ctrlc()) {
error("The remote end did not respond in time."); rc = fsg_main_thread(NULL);
if (rc) {
/* Check I/O error */
if (rc == -EIO)
printf("\rCheck USB cable connection\n");
/* Check CTRL+C */
if (rc == -EPIPE)
printf("\rCTRL+C - Operation aborted\n");
goto exit; goto exit;
} }
usb_gadget_handle_interrupts();
/* Check if USB cable has been detached */
if (fsg_main_thread(NULL) == EIO)
goto exit;
} }
exit: exit:
g_dnl_unregister(); g_dnl_unregister();
return 0; return CMD_RET_SUCCESS;
fail:
return -1;
} }
U_BOOT_CMD(ums, CONFIG_SYS_MAXARGS, 1, do_usb_mass_storage, U_BOOT_CMD(ums, CONFIG_SYS_MAXARGS, 1, do_usb_mass_storage,
"Use the UMS [User Mass Storage]", "Use the UMS [User Mass Storage]",
"<USB_controller> <mmc_dev>" "ums <USB_controller> <mmc_dev> e.g. ums 0 0"
); );

View File

@ -229,6 +229,7 @@ static int dfu_read_buffer_fill(struct dfu_entity *dfu, void *buf, int size)
dfu->crc = crc32(dfu->crc, buf, chunk); dfu->crc = crc32(dfu->crc, buf, chunk);
dfu->i_buf += chunk; dfu->i_buf += chunk;
dfu->b_left -= chunk; dfu->b_left -= chunk;
dfu->r_left -= chunk;
size -= chunk; size -= chunk;
buf += chunk; buf += chunk;
readn += chunk; readn += chunk;
@ -287,7 +288,7 @@ int dfu_read(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num)
dfu->offset = 0; dfu->offset = 0;
dfu->i_buf_end = dfu_get_buf() + dfu_buf_size; dfu->i_buf_end = dfu_get_buf() + dfu_buf_size;
dfu->i_buf = dfu->i_buf_start; dfu->i_buf = dfu->i_buf_start;
dfu->b_left = 0; dfu->b_left = min(dfu_buf_size, dfu->r_left);
dfu->bad_skip = 0; dfu->bad_skip = 0;

View File

@ -121,6 +121,7 @@ static int dfu_read_medium_nand(struct dfu_entity *dfu, u64 offset, void *buf,
switch (dfu->layout) { switch (dfu->layout) {
case DFU_RAW_ADDR: case DFU_RAW_ADDR:
*len = dfu->data.nand.size;
ret = nand_block_read(dfu, offset, buf, len); ret = nand_block_read(dfu, offset, buf, len);
break; break;
default: default:

View File

@ -243,6 +243,7 @@
#include <config.h> #include <config.h>
#include <malloc.h> #include <malloc.h>
#include <common.h> #include <common.h>
#include <usb.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/usb/ch9.h> #include <linux/usb/ch9.h>
@ -441,7 +442,7 @@ static void set_bulk_out_req_length(struct fsg_common *common,
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
struct ums_board_info *ums_info; struct ums *ums;
struct fsg_common *the_fsg_common; struct fsg_common *the_fsg_common;
static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
@ -675,6 +676,18 @@ static int sleep_thread(struct fsg_common *common)
k++; k++;
} }
if (k == 10) {
/* Handle CTRL+C */
if (ctrlc())
return -EPIPE;
#ifdef CONFIG_USB_CABLE_CHECK
/* Check cable connection */
if (!usb_cable_connected())
return -EIO;
#endif
k = 0;
}
usb_gadget_handle_interrupts(); usb_gadget_handle_interrupts();
} }
common->thread_wakeup_needed = 0; common->thread_wakeup_needed = 0;
@ -757,14 +770,14 @@ static int do_read(struct fsg_common *common)
} }
/* Perform the read */ /* Perform the read */
nread = 0; rc = ums->read_sector(ums,
rc = ums_info->read_sector(&(ums_info->ums_dev),
file_offset / SECTOR_SIZE, file_offset / SECTOR_SIZE,
amount / SECTOR_SIZE, amount / SECTOR_SIZE,
(char __user *)bh->buf); (char __user *)bh->buf);
if (rc) if (!rc)
return -EIO; return -EIO;
nread = amount;
nread = rc * SECTOR_SIZE;
VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
(unsigned long long) file_offset, (unsigned long long) file_offset,
@ -931,13 +944,13 @@ static int do_write(struct fsg_common *common)
amount = bh->outreq->actual; amount = bh->outreq->actual;
/* Perform the write */ /* Perform the write */
rc = ums_info->write_sector(&(ums_info->ums_dev), rc = ums->write_sector(ums,
file_offset / SECTOR_SIZE, file_offset / SECTOR_SIZE,
amount / SECTOR_SIZE, amount / SECTOR_SIZE,
(char __user *)bh->buf); (char __user *)bh->buf);
if (rc) if (!rc)
return -EIO; return -EIO;
nwritten = amount; nwritten = rc * SECTOR_SIZE;
VLDBG(curlun, "file write %u @ %llu -> %d\n", amount, VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
(unsigned long long) file_offset, (unsigned long long) file_offset,
@ -959,6 +972,8 @@ static int do_write(struct fsg_common *common)
/* If an error occurred, report it and its position */ /* If an error occurred, report it and its position */
if (nwritten < amount) { if (nwritten < amount) {
printf("nwritten:%d amount:%d\n", nwritten,
amount);
curlun->sense_data = SS_WRITE_ERROR; curlun->sense_data = SS_WRITE_ERROR;
curlun->info_valid = 1; curlun->info_valid = 1;
break; break;
@ -1045,14 +1060,13 @@ static int do_verify(struct fsg_common *common)
} }
/* Perform the read */ /* Perform the read */
nread = 0; rc = ums->read_sector(ums,
rc = ums_info->read_sector(&(ums_info->ums_dev),
file_offset / SECTOR_SIZE, file_offset / SECTOR_SIZE,
amount / SECTOR_SIZE, amount / SECTOR_SIZE,
(char __user *)bh->buf); (char __user *)bh->buf);
if (rc) if (!rc)
return -EIO; return -EIO;
nread = amount; nread = rc * SECTOR_SIZE;
VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
(unsigned long long) file_offset, (unsigned long long) file_offset,
@ -1100,7 +1114,7 @@ static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh)
buf[4] = 31; /* Additional length */ buf[4] = 31; /* Additional length */
/* No special options */ /* No special options */
sprintf((char *) (buf + 8), "%-8s%-16s%04x", (char*) vendor_id , sprintf((char *) (buf + 8), "%-8s%-16s%04x", (char*) vendor_id ,
ums_info->name, (u16) 0xffff); ums->name, (u16) 0xffff);
return 36; return 36;
} }
@ -2386,6 +2400,7 @@ static void handle_exception(struct fsg_common *common)
int fsg_main_thread(void *common_) int fsg_main_thread(void *common_)
{ {
int ret;
struct fsg_common *common = the_fsg_common; struct fsg_common *common = the_fsg_common;
/* The main loop */ /* The main loop */
do { do {
@ -2395,12 +2410,16 @@ int fsg_main_thread(void *common_)
} }
if (!common->running) { if (!common->running) {
sleep_thread(common); ret = sleep_thread(common);
if (ret)
return ret;
continue; continue;
} }
if (get_next_command(common)) ret = get_next_command(common);
continue; if (ret)
return ret;
if (!exception_in_progress(common)) if (!exception_in_progress(common))
common->state = FSG_STATE_DATA_PHASE; common->state = FSG_STATE_DATA_PHASE;
@ -2753,9 +2772,9 @@ int fsg_add(struct usb_configuration *c)
return fsg_bind_config(c->cdev, c, fsg_common); return fsg_bind_config(c->cdev, c, fsg_common);
} }
int fsg_init(struct ums_board_info *ums) int fsg_init(struct ums *ums_dev)
{ {
ums_info = ums; ums = ums_dev;
return 0; return 0;
} }

View File

@ -33,6 +33,9 @@
#define STRING_PRODUCT 2 #define STRING_PRODUCT 2
/* Index of String Descriptor describing this configuration */ /* Index of String Descriptor describing this configuration */
#define STRING_USBDOWN 2 #define STRING_USBDOWN 2
/* Index of String serial */
#define STRING_SERIAL 3
#define MAX_STRING_SERIAL 32
/* Number of supported configurations */ /* Number of supported configurations */
#define CONFIGURATION_NUMBER 1 #define CONFIGURATION_NUMBER 1
@ -40,8 +43,16 @@
static const char shortname[] = "usb_dnl_"; static const char shortname[] = "usb_dnl_";
static const char product[] = "USB download gadget"; static const char product[] = "USB download gadget";
static char g_dnl_serial[MAX_STRING_SERIAL];
static const char manufacturer[] = CONFIG_G_DNL_MANUFACTURER; static const char manufacturer[] = CONFIG_G_DNL_MANUFACTURER;
void g_dnl_set_serialnumber(char *s)
{
memset(g_dnl_serial, 0, MAX_STRING_SERIAL);
if (strlen(s) < MAX_STRING_SERIAL)
strncpy(g_dnl_serial, s, strlen(s));
}
static struct usb_device_descriptor device_desc = { static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc, .bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE, .bDescriptorType = USB_DT_DEVICE,
@ -53,6 +64,7 @@ static struct usb_device_descriptor device_desc = {
.idVendor = __constant_cpu_to_le16(CONFIG_G_DNL_VENDOR_NUM), .idVendor = __constant_cpu_to_le16(CONFIG_G_DNL_VENDOR_NUM),
.idProduct = __constant_cpu_to_le16(CONFIG_G_DNL_PRODUCT_NUM), .idProduct = __constant_cpu_to_le16(CONFIG_G_DNL_PRODUCT_NUM),
.iProduct = STRING_PRODUCT, .iProduct = STRING_PRODUCT,
.iSerialNumber = STRING_SERIAL,
.bNumConfigurations = 1, .bNumConfigurations = 1,
}; };
@ -63,6 +75,7 @@ static struct usb_device_descriptor device_desc = {
static struct usb_string g_dnl_string_defs[] = { static struct usb_string g_dnl_string_defs[] = {
{.s = manufacturer}, {.s = manufacturer},
{.s = product}, {.s = product},
{.s = g_dnl_serial},
{ } /* end of list */ { } /* end of list */
}; };
@ -156,6 +169,13 @@ static int g_dnl_bind(struct usb_composite_dev *cdev)
g_dnl_string_defs[1].id = id; g_dnl_string_defs[1].id = id;
device_desc.iProduct = id; device_desc.iProduct = id;
id = usb_string_id(cdev);
if (id < 0)
return id;
g_dnl_string_defs[2].id = id;
device_desc.iSerialNumber = id;
g_dnl_bind_fixup(&device_desc, cdev->driver->name); g_dnl_bind_fixup(&device_desc, cdev->driver->name);
ret = g_dnl_config_register(cdev); ret = g_dnl_config_register(cdev);
if (ret) if (ret)

View File

@ -275,7 +275,6 @@ struct rw_semaphore { int i; };
#define ETOOSMALL 525 #define ETOOSMALL 525
#include <usb_mass_storage.h> #include <usb_mass_storage.h>
extern struct ums_board_info *ums_info;
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
@ -573,36 +572,16 @@ static struct usb_gadget_strings fsg_stringtab = {
static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
{ {
int ro; 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 */ /* R/W if we can, R/O if we must */
ro = curlun->initially_ro; 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->ro = ro;
curlun->file_length = size; curlun->file_length = ums->num_sectors << 9;
curlun->num_sectors = num_sectors; curlun->num_sectors = ums->num_sectors;
debug("open backing file: %s\n", filename); debug("open backing file: %s\n", filename);
rc = 0;
out: return 0;
return rc;
} }
static void fsg_lun_close(struct fsg_lun *curlun) static void fsg_lun_close(struct fsg_lun *curlun)

View File

@ -1548,7 +1548,7 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
} }
dev->status = stat; dev->status = stat;
dev->act_len = transfer_len; dev->act_len = urb->actual_length;
#ifdef DEBUG #ifdef DEBUG
pkt_print(urb, dev, pipe, buffer, transfer_len, pkt_print(urb, dev, pipe, buffer, transfer_len,

View File

@ -321,9 +321,7 @@
#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 #define CONFIG_CMD_USB_MASS_STORAGE
#if defined(CONFIG_CMD_USB_MASS_STORAGE)
#define CONFIG_USB_GADGET_MASS_STORAGE #define CONFIG_USB_GADGET_MASS_STORAGE
#endif
/* Pass open firmware flat tree */ /* Pass open firmware flat tree */
#define CONFIG_OF_LIBFDT 1 #define CONFIG_OF_LIBFDT 1

View File

@ -13,5 +13,6 @@
int g_dnl_bind_fixup(struct usb_device_descriptor *, const char *); int g_dnl_bind_fixup(struct usb_device_descriptor *, const char *);
int g_dnl_register(const char *s); int g_dnl_register(const char *s);
void g_dnl_unregister(void); void g_dnl_unregister(void);
void g_dnl_set_serialnumber(char *);
#endif /* __G_DOWNLOAD_H_ */ #endif /* __G_DOWNLOAD_H_ */

View File

@ -197,6 +197,16 @@ int board_usb_init(int index, enum usb_init_type init);
*/ */
int board_usb_cleanup(int index, enum usb_init_type init); int board_usb_cleanup(int index, enum usb_init_type init);
/*
* If CONFIG_USB_CABLE_CHECK is set then this function
* should be defined in board file.
*
* @return 1 if cable is connected and 0 otherwise.
*/
#ifdef CONFIG_USB_CABLE_CHECK
int usb_cable_connected(void);
#endif
#ifdef CONFIG_USB_STORAGE #ifdef CONFIG_USB_STORAGE
#define USB_MAX_STOR_DEV 5 #define USB_MAX_STOR_DEV 5

View File

@ -9,32 +9,33 @@
#define __USB_MASS_STORAGE_H__ #define __USB_MASS_STORAGE_H__
#define SECTOR_SIZE 0x200 #define SECTOR_SIZE 0x200
#include <mmc.h> #include <mmc.h>
#include <linux/usb/composite.h> #include <linux/usb/composite.h>
struct ums_device { #ifndef UMS_START_SECTOR
struct mmc *mmc; #define UMS_START_SECTOR 0
int dev_num; #endif
int offset;
int part_size;
};
struct ums_board_info { #ifndef UMS_NUM_SECTORS
int (*read_sector)(struct ums_device *ums_dev, #define UMS_NUM_SECTORS 0
#endif
struct ums {
int (*read_sector)(struct ums *ums_dev,
ulong start, lbaint_t blkcnt, void *buf); ulong start, lbaint_t blkcnt, void *buf);
int (*write_sector)(struct ums_device *ums_dev, int (*write_sector)(struct ums *ums_dev,
ulong start, lbaint_t blkcnt, const void *buf); ulong start, lbaint_t blkcnt, const void *buf);
void (*get_capacity)(struct ums_device *ums_dev, unsigned int start_sector;
long long int *capacity); unsigned int num_sectors;
const char *name; const char *name;
struct ums_device ums_dev; struct mmc *mmc;
}; };
int fsg_init(struct ums_board_info *); extern struct ums *ums;
int fsg_init(struct ums *);
void fsg_cleanup(void); void fsg_cleanup(void);
struct ums_board_info *board_ums_init(unsigned int, unsigned int, struct ums *ums_init(unsigned int);
unsigned int);
int fsg_main_thread(void *); int fsg_main_thread(void *);
#ifdef CONFIG_USB_GADGET_MASS_STORAGE #ifdef CONFIG_USB_GADGET_MASS_STORAGE