USB: g_mass_storage: fsg_config added & module params handlig changed
Removed all references to mod_data in f_mass_storage.c and instead created fsg_config structure fsg_common_init() takes as an argument -- it stores all configuration options that were previously taken from mod_data. Moreover, The fsg_config structure allows per-LUN configuration of removable and CD-ROM emulation. Module parameters are handled by defining an object of fsg_module_parameters structure and then declaring module parameters via FSG_MODULE_PARAMETERS() macro. It adds proper declarations to the code making specified object be populated from module parameters. To use values stored there one may use either fsg_config_from_params() which will will a fsg_config structure with values taken from fsg_module_parameters structure or fsg_common_from_params() which will initialise fsg_common structure directly. Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
d23b0f08d1
commit
481e49296a
@@ -253,51 +253,6 @@ static const char fsg_string_interface[] = "Mass Storage";
|
|||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
/* Encapsulate the module parameter settings */
|
|
||||||
|
|
||||||
static struct {
|
|
||||||
char *file[FSG_MAX_LUNS];
|
|
||||||
int ro[FSG_MAX_LUNS];
|
|
||||||
unsigned int num_filenames;
|
|
||||||
unsigned int num_ros;
|
|
||||||
unsigned int nluns;
|
|
||||||
|
|
||||||
int removable;
|
|
||||||
int can_stall;
|
|
||||||
int cdrom;
|
|
||||||
|
|
||||||
unsigned short release;
|
|
||||||
} mod_data = { // Default values
|
|
||||||
.removable = 0,
|
|
||||||
.can_stall = 1,
|
|
||||||
.cdrom = 0,
|
|
||||||
.release = 0xffff,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames,
|
|
||||||
S_IRUGO);
|
|
||||||
MODULE_PARM_DESC(file, "names of backing files or devices");
|
|
||||||
|
|
||||||
module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO);
|
|
||||||
MODULE_PARM_DESC(ro, "true to force read-only");
|
|
||||||
|
|
||||||
module_param_named(luns, mod_data.nluns, uint, S_IRUGO);
|
|
||||||
MODULE_PARM_DESC(luns, "number of LUNs");
|
|
||||||
|
|
||||||
module_param_named(removable, mod_data.removable, bool, S_IRUGO);
|
|
||||||
MODULE_PARM_DESC(removable, "true to simulate removable media");
|
|
||||||
|
|
||||||
module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
|
|
||||||
MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
|
|
||||||
|
|
||||||
module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO);
|
|
||||||
MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk");
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
|
|
||||||
/* Data shared by all the FSG instances. */
|
/* Data shared by all the FSG instances. */
|
||||||
struct fsg_common {
|
struct fsg_common {
|
||||||
struct usb_gadget *gadget;
|
struct usb_gadget *gadget;
|
||||||
@@ -317,12 +272,34 @@ struct fsg_common {
|
|||||||
struct fsg_lun *luns;
|
struct fsg_lun *luns;
|
||||||
struct fsg_lun *curlun;
|
struct fsg_lun *curlun;
|
||||||
|
|
||||||
|
unsigned int can_stall:1;
|
||||||
unsigned int free_storage_on_release:1;
|
unsigned int free_storage_on_release:1;
|
||||||
|
|
||||||
|
/* Vendor (8 chars), product (16 chars), release (4
|
||||||
|
* hexadecimal digits) and NUL byte */
|
||||||
|
char inquiry_string[8 + 16 + 4 + 1];
|
||||||
|
|
||||||
struct kref ref;
|
struct kref ref;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct fsg_config {
|
||||||
|
unsigned nluns;
|
||||||
|
struct fsg_lun_config {
|
||||||
|
const char *filename;
|
||||||
|
char ro;
|
||||||
|
char removable;
|
||||||
|
char cdrom;
|
||||||
|
} luns[FSG_MAX_LUNS];
|
||||||
|
|
||||||
|
const char *vendor_name; /* 8 characters or less */
|
||||||
|
const char *product_name; /* 16 characters or less */
|
||||||
|
u16 release;
|
||||||
|
|
||||||
|
char can_stall;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct fsg_dev {
|
struct fsg_dev {
|
||||||
struct usb_function function;
|
struct usb_function function;
|
||||||
struct usb_composite_dev*cdev;
|
struct usb_composite_dev*cdev;
|
||||||
@@ -351,6 +328,7 @@ struct fsg_dev {
|
|||||||
unsigned int phase_error : 1;
|
unsigned int phase_error : 1;
|
||||||
unsigned int short_packet_received : 1;
|
unsigned int short_packet_received : 1;
|
||||||
unsigned int bad_lun_okay : 1;
|
unsigned int bad_lun_okay : 1;
|
||||||
|
unsigned int can_stall : 1;
|
||||||
|
|
||||||
unsigned long atomic_bitflags;
|
unsigned long atomic_bitflags;
|
||||||
#define REGISTERED 0
|
#define REGISTERED 0
|
||||||
@@ -1065,13 +1043,10 @@ static int do_verify(struct fsg_dev *fsg)
|
|||||||
|
|
||||||
static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
||||||
{
|
{
|
||||||
|
struct fsg_lun *curlun = fsg->common->curlun;
|
||||||
u8 *buf = (u8 *) bh->buf;
|
u8 *buf = (u8 *) bh->buf;
|
||||||
|
|
||||||
static char vendor_id[] = "Linux ";
|
if (!curlun) { /* Unsupported LUNs are okay */
|
||||||
static char product_disk_id[] = "File-Stor Gadget";
|
|
||||||
static char product_cdrom_id[] = "File-CD Gadget ";
|
|
||||||
|
|
||||||
if (!fsg->common->curlun) { // Unsupported LUNs are okay
|
|
||||||
fsg->bad_lun_okay = 1;
|
fsg->bad_lun_okay = 1;
|
||||||
memset(buf, 0, 36);
|
memset(buf, 0, 36);
|
||||||
buf[0] = 0x7f; // Unsupported, no device-type
|
buf[0] = 0x7f; // Unsupported, no device-type
|
||||||
@@ -1079,18 +1054,16 @@ static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
|||||||
return 36;
|
return 36;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(buf, 0, 8);
|
buf[0] = curlun->cdrom ? TYPE_CDROM : TYPE_DISK;
|
||||||
buf[0] = (mod_data.cdrom ? TYPE_CDROM : TYPE_DISK);
|
buf[1] = curlun->removable ? 0x80 : 0;
|
||||||
if (mod_data.removable)
|
|
||||||
buf[1] = 0x80;
|
|
||||||
buf[2] = 2; // ANSI SCSI level 2
|
buf[2] = 2; // ANSI SCSI level 2
|
||||||
buf[3] = 2; // SCSI-2 INQUIRY data format
|
buf[3] = 2; // SCSI-2 INQUIRY data format
|
||||||
buf[4] = 31; // Additional length
|
buf[4] = 31; // Additional length
|
||||||
// No special options
|
buf[5] = 0; // No special options
|
||||||
sprintf(buf + 8, "%-8s%-16s%04x", vendor_id,
|
buf[6] = 0;
|
||||||
(mod_data.cdrom ? product_cdrom_id :
|
buf[7] = 0;
|
||||||
product_disk_id),
|
memcpy(buf + 8, fsg->common->inquiry_string,
|
||||||
mod_data.release);
|
sizeof fsg->common->inquiry_string);
|
||||||
return 36;
|
return 36;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1303,7 +1276,9 @@ static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
|||||||
|
|
||||||
static int do_start_stop(struct fsg_dev *fsg)
|
static int do_start_stop(struct fsg_dev *fsg)
|
||||||
{
|
{
|
||||||
if (!mod_data.removable) {
|
if (!fsg->common->curlun) {
|
||||||
|
return -EINVAL;
|
||||||
|
} else if (!fsg->common->curlun->removable) {
|
||||||
fsg->common->curlun->sense_data = SS_INVALID_COMMAND;
|
fsg->common->curlun->sense_data = SS_INVALID_COMMAND;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -1316,8 +1291,10 @@ static int do_prevent_allow(struct fsg_dev *fsg)
|
|||||||
struct fsg_lun *curlun = fsg->common->curlun;
|
struct fsg_lun *curlun = fsg->common->curlun;
|
||||||
int prevent;
|
int prevent;
|
||||||
|
|
||||||
if (!mod_data.removable) {
|
if (!fsg->common->curlun) {
|
||||||
curlun->sense_data = SS_INVALID_COMMAND;
|
return -EINVAL;
|
||||||
|
} else if (!fsg->common->curlun->removable) {
|
||||||
|
fsg->common->curlun->sense_data = SS_INVALID_COMMAND;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1505,7 +1482,7 @@ static int finish_reply(struct fsg_dev *fsg)
|
|||||||
* try to send or receive any data. So stall both bulk pipes
|
* try to send or receive any data. So stall both bulk pipes
|
||||||
* if we can and wait for a reset. */
|
* if we can and wait for a reset. */
|
||||||
case DATA_DIR_UNKNOWN:
|
case DATA_DIR_UNKNOWN:
|
||||||
if (mod_data.can_stall) {
|
if (fsg->can_stall) {
|
||||||
fsg_set_halt(fsg, fsg->bulk_out);
|
fsg_set_halt(fsg, fsg->bulk_out);
|
||||||
rc = halt_bulk_in_endpoint(fsg);
|
rc = halt_bulk_in_endpoint(fsg);
|
||||||
}
|
}
|
||||||
@@ -1526,7 +1503,7 @@ static int finish_reply(struct fsg_dev *fsg)
|
|||||||
/* For Bulk-only, if we're allowed to stall then send the
|
/* For Bulk-only, if we're allowed to stall then send the
|
||||||
* short packet and halt the bulk-in endpoint. If we can't
|
* short packet and halt the bulk-in endpoint. If we can't
|
||||||
* stall, pad out the remaining data with 0's. */
|
* stall, pad out the remaining data with 0's. */
|
||||||
} else if (mod_data.can_stall) {
|
} else if (fsg->can_stall) {
|
||||||
bh->inreq->zero = 1;
|
bh->inreq->zero = 1;
|
||||||
start_transfer(fsg, fsg->bulk_in, bh->inreq,
|
start_transfer(fsg, fsg->bulk_in, bh->inreq,
|
||||||
&bh->inreq_busy, &bh->state);
|
&bh->inreq_busy, &bh->state);
|
||||||
@@ -1556,7 +1533,7 @@ static int finish_reply(struct fsg_dev *fsg)
|
|||||||
* STALL. Not realizing the endpoint was halted, it wouldn't
|
* STALL. Not realizing the endpoint was halted, it wouldn't
|
||||||
* clear the halt -- leading to problems later on. */
|
* clear the halt -- leading to problems later on. */
|
||||||
#if 0
|
#if 0
|
||||||
else if (mod_data.can_stall) {
|
else if (fsg->can_stall) {
|
||||||
fsg_set_halt(fsg, fsg->bulk_out);
|
fsg_set_halt(fsg, fsg->bulk_out);
|
||||||
raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
|
raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
|
||||||
rc = -EINTR;
|
rc = -EINTR;
|
||||||
@@ -1866,7 +1843,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SC_READ_HEADER:
|
case SC_READ_HEADER:
|
||||||
if (!mod_data.cdrom)
|
if (!fsg->common->curlun || !fsg->common->curlun->cdrom)
|
||||||
goto unknown_cmnd;
|
goto unknown_cmnd;
|
||||||
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]);
|
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]);
|
||||||
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
|
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
|
||||||
@@ -1876,7 +1853,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SC_READ_TOC:
|
case SC_READ_TOC:
|
||||||
if (!mod_data.cdrom)
|
if (!fsg->common->curlun || !fsg->common->curlun->cdrom)
|
||||||
goto unknown_cmnd;
|
goto unknown_cmnd;
|
||||||
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]);
|
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->common->cmnd[7]);
|
||||||
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
|
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
|
||||||
@@ -2043,7 +2020,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
|||||||
|
|
||||||
/* We can do anything we want here, so let's stall the
|
/* We can do anything we want here, so let's stall the
|
||||||
* bulk pipes if we are allowed to. */
|
* bulk pipes if we are allowed to. */
|
||||||
if (mod_data.can_stall) {
|
if (fsg->can_stall) {
|
||||||
fsg_set_halt(fsg, fsg->bulk_out);
|
fsg_set_halt(fsg, fsg->bulk_out);
|
||||||
halt_bulk_in_endpoint(fsg);
|
halt_bulk_in_endpoint(fsg);
|
||||||
}
|
}
|
||||||
@@ -2499,18 +2476,18 @@ static inline void fsg_common_put(struct fsg_common *common)
|
|||||||
|
|
||||||
|
|
||||||
static struct fsg_common *fsg_common_init(struct fsg_common *common,
|
static struct fsg_common *fsg_common_init(struct fsg_common *common,
|
||||||
struct usb_composite_dev *cdev)
|
struct usb_composite_dev *cdev,
|
||||||
|
struct fsg_config *cfg)
|
||||||
{
|
{
|
||||||
struct usb_gadget *gadget = cdev->gadget;
|
struct usb_gadget *gadget = cdev->gadget;
|
||||||
struct fsg_buffhd *bh;
|
struct fsg_buffhd *bh;
|
||||||
struct fsg_lun *curlun;
|
struct fsg_lun *curlun;
|
||||||
|
struct fsg_lun_config *lcfg;
|
||||||
int nluns, i, rc;
|
int nluns, i, rc;
|
||||||
char *pathbuf;
|
char *pathbuf;
|
||||||
|
|
||||||
/* Find out how many LUNs there should be */
|
/* Find out how many LUNs there should be */
|
||||||
nluns = mod_data.nluns;
|
nluns = cfg->nluns;
|
||||||
if (nluns == 0)
|
|
||||||
nluns = max(mod_data.num_filenames, 1u);
|
|
||||||
if (nluns < 1 || nluns > FSG_MAX_LUNS) {
|
if (nluns < 1 || nluns > FSG_MAX_LUNS) {
|
||||||
dev_err(&gadget->dev, "invalid number of LUNs: %u\n", nluns);
|
dev_err(&gadget->dev, "invalid number of LUNs: %u\n", nluns);
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
@@ -2539,10 +2516,10 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
|
|||||||
|
|
||||||
init_rwsem(&common->filesem);
|
init_rwsem(&common->filesem);
|
||||||
|
|
||||||
for (i = 0; i < nluns; ++i, ++curlun) {
|
for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) {
|
||||||
curlun->cdrom = !!mod_data.cdrom;
|
curlun->cdrom = !!lcfg->cdrom;
|
||||||
curlun->ro = mod_data.cdrom || mod_data.ro[i];
|
curlun->ro = lcfg->cdrom || lcfg->ro;
|
||||||
curlun->removable = mod_data.removable;
|
curlun->removable = lcfg->removable;
|
||||||
curlun->dev.release = fsg_lun_release;
|
curlun->dev.release = fsg_lun_release;
|
||||||
curlun->dev.parent = &gadget->dev;
|
curlun->dev.parent = &gadget->dev;
|
||||||
/* curlun->dev.driver = &fsg_driver.driver; XXX */
|
/* curlun->dev.driver = &fsg_driver.driver; XXX */
|
||||||
@@ -2564,11 +2541,11 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
|
|||||||
if (rc)
|
if (rc)
|
||||||
goto error_luns;
|
goto error_luns;
|
||||||
|
|
||||||
if (mod_data.file[i] && *mod_data.file[i]) {
|
if (lcfg->filename) {
|
||||||
rc = fsg_lun_open(curlun, mod_data.file[i]);
|
rc = fsg_lun_open(curlun, lcfg->filename);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto error_luns;
|
goto error_luns;
|
||||||
} else if (!mod_data.removable) {
|
} else if (!curlun->removable) {
|
||||||
ERROR(common, "no file given for LUN%d\n", i);
|
ERROR(common, "no file given for LUN%d\n", i);
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
goto error_luns;
|
goto error_luns;
|
||||||
@@ -2588,33 +2565,40 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
|
|||||||
bh->next = common->buffhds;
|
bh->next = common->buffhds;
|
||||||
|
|
||||||
|
|
||||||
/* Release */
|
/* Prepare inquiryString */
|
||||||
if (mod_data.release == 0xffff) { // Parameter wasn't set
|
if (cfg->release != 0xffff) {
|
||||||
int gcnum;
|
i = cfg->release;
|
||||||
|
} else {
|
||||||
/* The sa1100 controller is not supported */
|
/* The sa1100 controller is not supported */
|
||||||
if (gadget_is_sa1100(gadget))
|
i = gadget_is_sa1100(gadget)
|
||||||
gcnum = -1;
|
? -1
|
||||||
else
|
: usb_gadget_controller_number(gadget);
|
||||||
gcnum = usb_gadget_controller_number(gadget);
|
if (i >= 0) {
|
||||||
if (gcnum >= 0)
|
i = 0x0300 + i;
|
||||||
mod_data.release = 0x0300 + gcnum;
|
} else {
|
||||||
else {
|
|
||||||
WARNING(common, "controller '%s' not recognized\n",
|
WARNING(common, "controller '%s' not recognized\n",
|
||||||
gadget->name);
|
gadget->name);
|
||||||
WARNING(common, "controller '%s' not recognized\n",
|
i = 0x0399;
|
||||||
gadget->name);
|
|
||||||
mod_data.release = 0x0399;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#define OR(x, y) ((x) ? (x) : (y))
|
||||||
|
snprintf(common->inquiry_string, sizeof common->inquiry_string,
|
||||||
|
"%-8s%-16s%04x",
|
||||||
|
OR(cfg->vendor_name, "Linux "),
|
||||||
|
/* Assume product name dependent on the first LUN */
|
||||||
|
OR(cfg->product_name, common->luns->cdrom
|
||||||
|
? "File-Stor Gadget"
|
||||||
|
: "File-CD Gadget "),
|
||||||
|
i);
|
||||||
|
#undef OR
|
||||||
|
|
||||||
|
|
||||||
/* Some peripheral controllers are known not to be able to
|
/* Some peripheral controllers are known not to be able to
|
||||||
* halt bulk endpoints correctly. If one of them is present,
|
* halt bulk endpoints correctly. If one of them is present,
|
||||||
* disable stalls.
|
* disable stalls.
|
||||||
*/
|
*/
|
||||||
if (gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget))
|
common->can_stall = cfg->can_stall &&
|
||||||
mod_data.can_stall = 0;
|
!(gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget));
|
||||||
|
|
||||||
|
|
||||||
kref_init(&common->ref);
|
kref_init(&common->ref);
|
||||||
@@ -2820,6 +2804,7 @@ static int fsg_add(struct usb_composite_dev *cdev,
|
|||||||
* from this function. So instead of incrementing counter now
|
* from this function. So instead of incrementing counter now
|
||||||
* and decrement in error recovery we increment it only when
|
* and decrement in error recovery we increment it only when
|
||||||
* call to usb_add_function() was successful. */
|
* call to usb_add_function() was successful. */
|
||||||
|
fsg->can_stall = common->can_stall;
|
||||||
|
|
||||||
rc = usb_add_function(c, &fsg->function);
|
rc = usb_add_function(c, &fsg->function);
|
||||||
|
|
||||||
@@ -2830,3 +2815,95 @@ static int fsg_add(struct usb_composite_dev *cdev,
|
|||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/************************* Module parameters *************************/
|
||||||
|
|
||||||
|
|
||||||
|
struct fsg_module_parameters {
|
||||||
|
char *file[FSG_MAX_LUNS];
|
||||||
|
int ro[FSG_MAX_LUNS];
|
||||||
|
int removable[FSG_MAX_LUNS];
|
||||||
|
int cdrom[FSG_MAX_LUNS];
|
||||||
|
|
||||||
|
unsigned int file_count, ro_count, removable_count, cdrom_count;
|
||||||
|
unsigned int luns; /* nluns */
|
||||||
|
int stall; /* can_stall */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc) \
|
||||||
|
module_param_array_named(prefix ## name, params.name, type, \
|
||||||
|
&prefix ## params.name ## _count, \
|
||||||
|
S_IRUGO); \
|
||||||
|
MODULE_PARM_DESC(prefix ## name, desc)
|
||||||
|
|
||||||
|
#define _FSG_MODULE_PARAM(prefix, params, name, type, desc) \
|
||||||
|
module_param_named(prefix ## name, params.name, type, \
|
||||||
|
S_IRUGO); \
|
||||||
|
MODULE_PARM_DESC(prefix ## name, desc)
|
||||||
|
|
||||||
|
#define FSG_MODULE_PARAMETERS(prefix, params) \
|
||||||
|
_FSG_MODULE_PARAM_ARRAY(prefix, params, file, charp, \
|
||||||
|
"names of backing files or devices"); \
|
||||||
|
_FSG_MODULE_PARAM_ARRAY(prefix, params, ro, bool, \
|
||||||
|
"true to force read-only"); \
|
||||||
|
_FSG_MODULE_PARAM_ARRAY(prefix, params, removable, bool, \
|
||||||
|
"true to simulate removable media"); \
|
||||||
|
_FSG_MODULE_PARAM_ARRAY(prefix, params, cdrom, bool, \
|
||||||
|
"true to simulate CD-ROM instead of disk"); \
|
||||||
|
_FSG_MODULE_PARAM(prefix, params, luns, uint, \
|
||||||
|
"number of LUNs"); \
|
||||||
|
_FSG_MODULE_PARAM(prefix, params, stall, bool, \
|
||||||
|
"false to prevent bulk stalls")
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsg_config_from_params(struct fsg_config *cfg,
|
||||||
|
const struct fsg_module_parameters *params)
|
||||||
|
{
|
||||||
|
struct fsg_lun_config *lun;
|
||||||
|
unsigned i, nluns;
|
||||||
|
|
||||||
|
/* Configure LUNs */
|
||||||
|
nluns = cfg->nluns = !params->luns
|
||||||
|
? params->file_count ? params->file_count : 1
|
||||||
|
: params->luns;
|
||||||
|
for (i = 0, lun = cfg->luns;
|
||||||
|
i < FSG_MAX_LUNS && i < nluns;
|
||||||
|
++i, ++lun) {
|
||||||
|
lun->ro = !!params->ro[i];
|
||||||
|
lun->cdrom = !!params->cdrom[i];
|
||||||
|
lun->removable =
|
||||||
|
params->removable_count <= i || params->removable[i];
|
||||||
|
lun->filename =
|
||||||
|
params->file_count > i && params->file[i][0]
|
||||||
|
? params->file[i]
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let FSG use defaults */
|
||||||
|
cfg->vendor_name = 0;
|
||||||
|
cfg->product_name = 0;
|
||||||
|
cfg->release = 0xffff;
|
||||||
|
|
||||||
|
/* Finalise */
|
||||||
|
cfg->can_stall = params->stall;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct fsg_common *
|
||||||
|
fsg_common_from_params(struct fsg_common *common,
|
||||||
|
struct usb_composite_dev *cdev,
|
||||||
|
const struct fsg_module_parameters *params)
|
||||||
|
__attribute__((unused));
|
||||||
|
static inline struct fsg_common *
|
||||||
|
fsg_common_from_params(struct fsg_common *common,
|
||||||
|
struct usb_composite_dev *cdev,
|
||||||
|
const struct fsg_module_parameters *params)
|
||||||
|
{
|
||||||
|
struct fsg_config cfg;
|
||||||
|
fsg_config_from_params(&cfg, params);
|
||||||
|
return fsg_common_init(common, cdev, &cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -127,6 +127,11 @@ static struct usb_gadget_strings *dev_strings[] = {
|
|||||||
|
|
||||||
/****************************** Configurations ******************************/
|
/****************************** Configurations ******************************/
|
||||||
|
|
||||||
|
static struct fsg_module_parameters mod_data = {
|
||||||
|
.stall = 1
|
||||||
|
};
|
||||||
|
FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
|
||||||
|
|
||||||
static int __init msg_do_config(struct usb_configuration *c)
|
static int __init msg_do_config(struct usb_configuration *c)
|
||||||
{
|
{
|
||||||
struct fsg_common *common;
|
struct fsg_common *common;
|
||||||
@@ -137,7 +142,7 @@ static int __init msg_do_config(struct usb_configuration *c)
|
|||||||
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
common = fsg_common_init(0, c->cdev);
|
common = fsg_common_from_params(0, c->cdev, &mod_data);
|
||||||
if (IS_ERR(common))
|
if (IS_ERR(common))
|
||||||
return PTR_ERR(common);
|
return PTR_ERR(common);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user