USB gadget driver: mass storage


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等要手动设置
 **/





  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值