1. based on init function clue;
struct mass_storage_function_config {
struct fsg_config fsg;
struct fsg_common *common;
};
struct fsg_config {
unsigned nluns;
struct fsg_lun_config {
const char *filename;
char ro;
char removable;
char cdrom;
char nofua;
} luns[FSG_MAX_LUNS];
const char *lun_name_format;
const char *thread_name;
//Callback functions.
const struct fsg_operations *ops;
//Gadget's private data.
void *private_data;
const char *vendor_name;
const char *product_name;
u16 release;
char can_stall;
};
/* Data shared by all the FSG instances. */
struct fsg_common {
struct usb_gadget *gadget;
struct usb_composite_dev *cdev;
struct fsg_dev *fsg, *new_fsg;
wait_queue_head_t fsg_wait;
/* filesem protects: backing files in use */
struct rw_semaphore filesem;
/* lock protects: state, all the req_busy's */
spinlock_t lock;
struct usb_ep *ep0; /* Copy of gadget->ep0 */
struct usb_request *ep0req; /* Copy of cdev->req */
unsigned int ep0_req_tag;
struct fsg_buffhd *next_buffhd_to_fill;
struct fsg_buffhd *next_buffhd_to_drain;
struct fsg_buffhd *buffhds;
int cmnd_size;
u8 cmnd[MAX_COMMAND_SIZE];
unsigned int nluns;
unsigned int lun;
struct fsg_lun *luns;
struct fsg_lun *curlun;
unsigned int bulk_out_maxpacket;
enum fsg_state state; /* For exception handling */
unsigned int exception_req_tag;
enum data_direction data_dir;
u32 data_size;
u32 data_size_from_cmnd;
u32 tag;
u32 residue;
u32 usb_amount_left;
unsigned int can_stall:1;
unsigned int free_storage_on_release:1;
unsigned int phase_error:1;
unsigned int short_packet_received:1;
unsigned int bad_lun_okay:1;
unsigned int running:1;
int thread_wakeup_needed;
struct completion thread_notifier;
struct task_struct *thread_task;
/* Callback functions. */
const struct fsg_operations *ops;
/* Gadget's private data. */
void *private_data;
/*
* Vendor (8 chars), product (16 chars), release (4
* hexadecimal digits) and NUL byte
*/
char inquiry_string[8 + 16 + 4 + 1];
struct kref ref;
};
struct fsg_dev {
struct usb_function function;
struct usb_gadget *gadget; /* Copy of cdev->gadget */
struct fsg_common *common;
u16 interface_number;
unsigned int bulk_in_enabled:1;
unsigned int bulk_out_enabled:1;
unsigned long atomic_bitflags;
#define IGNORE_BULK_OUT 0
struct usb_ep *bulk_in;
struct usb_ep *bulk_out;
};
struct fsg_lun {
struct file *filp;
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;
unsigned int blkbits; /* Bits of logical block size of bound block device */
unsigned int blksize; /* logical block size of bound block device */
struct device dev;
};
struct fsg_buffhd {
void *buf;
enum fsg_buffer_state state;
struct fsg_buffhd *next;
struct usb_request *inreq;
int inreq_busy;
struct usb_request *outreq;
int outreq_busy;
};
/*********************************************************************************************/
这么多数据结构,是个什么样的层次关系?这写数据结构都定义在什么地方?
1. 创建:
函数mass_storage_function_init: 变量mass_storage_function_config/ fsg_config;
函数fsg_common_init: 变量fsg_common
函数fsg_common_init: 变量fsg_buffhd /*fsg_buffhd[2]*/
common->buffhds = kcalloc(fsg_num_buffers,sizeof *(common->buffhds), GFP_KERNEL);
函数fsg_common_init: 变量fsg_lun /*fsg_lun[nluns]*/
common->luns = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL);
2. fsg_dev 是在函数fsg_bind_config中创建的
3. 在枚举过程的 set_interface处理函数中 fsg_common 和 fsg_dev 关联上
/*********************************************************************************************/
static int mass_storage_function_init(struct android_usb_function *f,
struct usb_composite_dev *cdev)
{
struct mass_storage_function_config *config;
struct fsg_common *common;
int err;
config = kzalloc(sizeof(struct mass_storage_function_config),GFP_KERNEL);
config->fsg.nluns = 2;
config->fsg.luns[0].removable = 1;
config->fsg.luns[0].nofua = 1;
config->fsg.luns[1].removable = 1;
config->fsg.luns[1].nofua = 1;
common = fsg_common_init(NULL, cdev, &config->fsg);
config->common = common;
f->config = config;
return 0;
}
/******************************************************/
2. based on init enable function clue;
static int mass_storage_function_bind_config(struct android_usb_function *f,
struct usb_configuration *c)
{
struct mass_storage_function_config *config = f->config;
return fsg_bind_config(c->cdev, c, config->common);
}
static int fsg_bind_config(struct usb_composite_dev *cdev,
struct usb_configuration *c,
struct fsg_common *common)
{
struct fsg_dev *fsg;
int rc;
fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
if (unlikely(!fsg))
return -ENOMEM;
fsg->function.name = FSG_DRIVER_DESC;
fsg->function.strings = fsg_strings_array;
fsg->function.bind = fsg_bind;
fsg->function.unbind = fsg_unbind;
fsg->function.setup = fsg_setup;
fsg->function.set_alt = fsg_set_alt;
fsg->function.disable = fsg_disable;
fsg->common = common;
/*
* Our caller holds a reference to common structure so we
* don't have to be worry about it being freed until we return
* from this function. So instead of incrementing counter now
* and decrement in error recovery we increment it only when
* call to usb_add_function() was successful.
*/
rc = usb_add_function(c, &fsg->function);
if (unlikely(rc))
kfree(fsg);
else
fsg_common_get(fsg->common);
return rc;
}
static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
{
struct fsg_dev *fsg = fsg_from_func(f);
struct usb_gadget *gadget = c->cdev->gadget;
int i;
struct usb_ep *ep;
fsg->gadget = gadget;
/* New interface */
i = usb_interface_id(c, f);
fsg_intf_desc.bInterfaceNumber = i;
fsg->interface_number = i;
/* Find all the endpoints we will use */
ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
ep->driver_data = fsg->common; /* claim the endpoint */
fsg->bulk_in = ep;
ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc);
ep->driver_data = fsg->common; /* claim the endpoint */
fsg->bulk_out = ep;
/* Copy descriptors */
f->descriptors = usb_copy_descriptors(fsg_fs_function);
}
3. based on set interface clue;
static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
struct fsg_dev *fsg = fsg_from_func(f);
fsg->common->new_fsg = fsg;
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
return USB_GADGET_DELAYED_STATUS;
}
static void raise_exception(struct fsg_common *common, enum fsg_state new_state)
{
unsigned long flags;
/*
* Do nothing if a higher-priority exception is already in progress.
* If a lower-or-equal priority exception is in progress, preempt it
* and notify the main thread by sending it a signal.
*/
spin_lock_irqsave(&common->lock, flags);
if (common->state <= new_state) {
common->exception_req_tag = common->ep0_req_tag;
common->state = new_state;
if (common->thread_task)
send_sig_info(SIGUSR1, SEND_SIG_FORCED,
common->thread_task);
}
spin_unlock_irqrestore(&common->lock, flags);
}
fsg_main_thread -> handle_exception:
static void handle_exception(struct fsg_common *common)
{
case FSG_STATE_CONFIG_CHANGE:
do_set_interface(common, common->new_fsg);
if (common->new_fsg)
usb_composite_setup_continue(common->cdev);
break;
}
/* Reset interface setting and re-init endpoint state (toggle etc).
* 端点的enalbe在这里处理/并且关联了
* fsg_common and fsg_dev
**/
static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg)
{
struct fsg_dev *fsg;
common->running = 0;
common->fsg = new_fsg;
fsg = common->fsg;
/* Enable the endpoints */
rc = config_ep_by_speed(common->gadget, &(fsg->function), fsg->bulk_in);
rc = usb_ep_enable(fsg->bulk_in);
fsg->bulk_in->driver_data = common;
fsg->bulk_in_enabled = 1;
rc = config_ep_by_speed(common->gadget, &(fsg->function),
fsg->bulk_out);
rc = usb_ep_enable(fsg->bulk_out);
fsg->bulk_out->driver_data = common;
fsg->bulk_out_enabled = 1;
common->bulk_out_maxpacket = usb_endpoint_maxp(fsg->bulk_out->desc);
clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
/* Allocate the requests */
for (i = 0; i < fsg_num_buffers; ++i) {
struct fsg_buffhd *bh = &common->buffhds[i];
rc = alloc_request(common, fsg->bulk_in, &bh->inreq);
rc = alloc_request(common, fsg->bulk_out, &bh->outreq);
bh->inreq->buf = bh->outreq->buf = bh->buf;
bh->inreq->context = bh->outreq->context = bh;
bh->inreq->complete = bulk_in_complete;
bh->outreq->complete = bulk_out_complete;
}
common->running = 1;
for (i = 0; i < common->nluns; ++i)
common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
return rc;
}
4.about filep;
static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{ /*device和 fsg_lun是何时关联的?*/
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
/* Load new medium */
if (count > 0 && buf[0]) {
rc = fsg_lun_open(curlun, buf);
if (rc == 0)
curlun->unit_attention_data =
SS_NOT_READY_TO_READY_TRANSITION;
}
}
fsg_common_init ->
{
/*这里关联了fsg_lun and device, 并且创建了属性文件 ro/file/nofua:
*这些属性文件的定义在storage_common.c中
**/
for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg){
curlun->cdrom = !!lcfg->cdrom;
curlun->ro = lcfg->cdrom || lcfg->ro;
curlun->initially_ro = curlun->ro;
curlun->removable = lcfg->removable;
curlun->dev.release = fsg_lun_release;
curlun->dev.parent = &gadget->dev;
/* curlun->dev.driver = &fsg_driver.driver; XXX */
dev_set_drvdata(&curlun->dev, &common->filesem);
dev_set_name(&curlun->dev,
cfg->lun_name_format
? cfg->lun_name_format
: "lun%d",
i);
rc = device_register(&curlun->dev);
if (rc) {
INFO(common, "failed to register LUN%d: %d\n", i, rc);
common->nluns = i;
put_device(&curlun->dev);
goto error_release;
}
rc = device_create_file(&curlun->dev, &dev_attr_ro);
if (rc)
goto error_luns;
rc = device_create_file(&curlun->dev, &dev_attr_file);
if (rc)
goto error_luns;
rc = device_create_file(&curlun->dev, &dev_attr_nofua);
if (rc)
goto error_luns;
if (lcfg->filename) {
rc = fsg_lun_open(curlun, lcfg->filename);
if (rc)
goto error_luns;
} else if (!curlun->removable) {
ERROR(common, "no file given for LUN%d\n", i);
rc = -EINVAL;
goto error_luns;
}
}
}
/
*fsg_lun的filp变量在这里赋值*/
static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
{
int ro;
struct file *filp = NULL;
/* R/W if we can, R/O if we must */
ro = curlun->initially_ro;
if (!ro) {
filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
if (PTR_ERR(filp) == -EROFS || PTR_ERR(filp) == -EACCES)
ro = 1;
}
curlun->ro = ro;
curlun->filp = filp;
curlun->file_length = size;
curlun->num_sectors = num_sectors;
}
/******************************************************/
5. 主thread:
int fsg_main_thread(void *common_)
{
/* The main loop */
while (common->state != FSG_STATE_TERMINATED) {
if (exception_in_progress(common) || signal_pending(current)) {
handle_exception(common);
continue;
}
if (!common->running) {
sleep_thread(common);
continue;
}
if (get_next_command(common))
continue;
spin_lock_irq(&common->lock);
if (!exception_in_progress(common))
common->state = FSG_STATE_DATA_PHASE;
spin_unlock_irq(&common->lock);
if (do_scsi_command(common) || finish_reply(common))
continue;
spin_lock_irq(&common->lock);
if (!exception_in_progress(common))
common->state = FSG_STATE_STATUS_PHASE;
spin_unlock_irq(&common->lock);
if (send_status(common))
continue;
spin_lock_irq(&common->lock);
if (!exception_in_progress(common))
common->state = FSG_STATE_IDLE;
spin_unlock_irq(&common->lock);
}
}
怎样控制枚举和传输过程的?使用 fsg_state
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
};
判断异常的方法
static int exception_in_progress(struct fsg_common *common)
{
return common->state > FSG_STATE_IDLE;
}
处理异常的方法:调用函数raise_exception -> send_sig_info;
raise_exception(fsg->common, FSG_STATE_RESET);
raise_exception(common,FSG_STATE_ABORT_BULK_OUT);
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
raise_exception(common, FSG_STATE_EXIT);
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
static void raise_exception(struct fsg_common *common, enum fsg_state new_state)
{
if (common->state <= new_state) {
common->exception_req_tag = common->ep0_req_tag;
common->state = new_state;
if (common->thread_task)
send_sig_info(SIGUSR1, SEND_SIG_FORCED,common->thread_task);
}
}
处理异常的方法: handle_exception
*分为两部分:1. common的; 2. 和 state相关的;
*/
void handle_exception(struct fsg_common *common)
{
/*
* Clear the existing signals. Anything but SIGUSR1 is converted
* into a high-priority EXIT exception.
*/
/* Cancel all the pending transfers */
/*
* Reset the I/O buffer states and pointers, the SCSI
* state, and the exception. Then invoke the handler.
*/
/* Carry out any extra actions required for the exception */
switch (old_state) {
case FSG_STATE_ABORT_BULK_OUT:
}
}
fsg_main_thread是怎样睡眠和唤醒的?
* try_to_freeze();set_current_state(TASK_INTERRUPTIBLE);
* schedule();这3步就可以把thread睡眠?不需要设置它在等待什么? waitqueue head?
* 最起码这样是可以的?
static int sleep_thread(struct fsg_common *common)
{
int rc = 0;
/* Wait until a signal arrives or we are woken up
*这里是说等到singal 或者 wakeup都可以把thread唤醒
**/
for (;;) {
try_to_freeze();
set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current)) {
rc = -EINTR;
break;
}
if (common->thread_wakeup_needed)
break;
schedule();
}
__set_current_state(TASK_RUNNING);
common->thread_wakeup_needed = 0;
return rc;
}
static void wakeup_thread(struct fsg_common *common)
{
/* Tell the main thread that something has happened */
common->thread_wakeup_needed = 1;
if (common->thread_task)
wake_up_process(common->thread_task);
}
何时唤醒thread?
bulk_in_complete -> wakeup_thread(common);
bulk_out_complete -> wakeup_thread(common);
以写数据为例看数据的传输过程
int get_next_command(fsg_common)
{
struct fsg_buffhd *bh;
int rc = 0;
/* Wait for the next buffer to become available */
bh = common->next_buffhd_to_fill;
/* Queue a request to read a Bulk-only CBW */
set_bulk_out_req_length(common, bh, US_BULK_CB_WRAP_LEN);
start_out_transfer(common, bh);
received_cbw(common->fsg, bh);
}
static bool start_out_transfer(struct fsg_common *common, struct fsg_buffhd *bh)
{
start_transfer(common->fsg, common->fsg->bulk_out,
bh->outreq, &bh->outreq_busy, &bh->state);
return true;
}
start_transfer -> usb_ep_queue(ep, req, GFP_KERNEL);
static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
{
struct usb_request *req = bh->outreq;
struct bulk_cb_wrap *cbw = req->buf;
/* Save the command for later */
common->cmnd_size = cbw->Length;
memcpy(common->cmnd, cbw->CDB, common->cmnd_size);
if (cbw->Flags & US_BULK_FLAG_IN)
common->data_dir = DATA_DIR_TO_HOST;
else
common->data_dir = DATA_DIR_FROM_HOST;
common->data_size = le32_to_cpu(cbw->DataTransferLength);
common->lun = cbw->Lun;
if (common->lun >= 0 && common->lun < common->nluns)
common->curlun = &common->luns[common->lun];
common->tag = cbw->Tag;
return 0;
}
/*得到的命令保存到fsg_common的cmnd变量中,do_scsi_command会使用
*common->state = FSG_STATE_DATA_PHASE;
**/
int do_scsi_command(struct fsg_common *common)
{
switch (common->cmnd[0]) {
case WRITE_10:
common->data_size_from_cmnd =
get_unaligned_be16(&common->cmnd[7]);
reply = check_command_size_in_blocks(common, 10,
DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"WRITE(10)");
if (reply == 0)
reply = do_write(common);
break;
}
}
/*
*
do_write分为两部分:get the data by USB/ write into file
**/
int do_write(struct fsg_common *common)
{
struct fsg_lun *curlun = common->curlun;
/* Carry out the file writes */
get_some_more = 1;
file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
amount_left_to_req = common->data_size_from_cmnd;
amount_left_to_write = common->data_size_from_cmnd;
while (amount_left_to_write > 0) {
/*
* Except at the end of the transfer, amount will be
* equal to the buffer size, which is divisible by
* the bulk-out maxpacket size.
*/
set_bulk_out_req_length(common, bh, amount);
start_out_transfer(common, bh);
/* Write the received data to the backing file */
vfs_write(curlun->filp,(char __user *)bh->buf,
amount, &file_offset_tmp);
}
}
/
*根据数据的方向判断数据是否发送接收完毕?*/
static int finish_reply(struct fsg_common *common)
{
struct fsg_buffhd *bh = common->next_buffhd_to_fill;
switch (common->data_dir) {
case DATA_DIR_NONE:
break;
case DATA_DIR_UNKNOWN:
/* All but the last buffer of data must have already been sent */
case DATA_DIR_TO_HOST:
/*
* We have processed all we want from the data the host has sent.
* There may still be outstanding bulk-out requests.
*/
case DATA_DIR_FROM_HOST:
if (common->residue == 0) {
/* Nothing to receive */
}
}
/*
最后发送status*/
static int send_status(struct fsg_common *common)
{
struct fsg_lun *curlun = common->curlun;
struct fsg_buffhd *bh;
struct bulk_cs_wrap *csw;
/* Store and send the Bulk-only CSW */
csw = (void *)bh->buf;
csw->Signature = cpu_to_le32(US_BULK_CS_SIGN);
csw->Tag = common->tag;
csw->Residue = cpu_to_le32(common->residue);
csw->Status = status;
bh->inreq->length = US_BULK_CS_WRAP_LEN;
bh->inreq->zero = 0;
start_in_transfer(common, bh)
有关存储介质:
*lun: Logical Unit Number,到底对应那个存储介质,是怎样决定的?
*
**/
fsg_common_init{
struct fsg_lun *curlun;
/* Find out how many LUNs there should be */
int nluns = cfg->nluns;
/*
* Create the LUNs, open their backing files, and register the
* LUN devices in sysfs.
*/
curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL);
common->luns = curlun;
for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) {
curlun->ro = lcfg->cdrom || lcfg->ro;
curlun->removable = lcfg->removable;
curlun->dev.parent = &gadget->dev;
/*在目录/sys/class/android_usb/f_mass-storage下创建了文件夹 lun 0,2..,
*lun下又创建了文件:file,nofua等。
**/
dev_set_name(&curlun->dev,
cfg->lun_name_format
? cfg->lun_name_format
: "lun%d",
i);
rc = device_register(&curlun->dev);
rc = device_create_file(&curlun->dev, &dev_attr_file);
}
}
/*当向属性文件/sys/class/android_usb/f_mass-storage/lun/file写入 /dev/mmcblk0p1等其他时:
*调用fsg_store_file
**/
static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
fsg_lun_open(curlun, buf[file name]);
}
/*从上可以看出问题的关键是:
*向那个lun,写入什么设备文件名:/sys/class/android_usb/f_mass-storage/lunX/file
*如: echo /dev/mmcblk0p1 > /sys/class/android_usb/f_mass-storage/lun1/file
*如果是 android,是上层某个应用程序自动设置的,如果是ubuntu等要手动设置
**/