Android 4.0 USB挂载内核驱动层流程分析(2)

接《Android4.0 USB挂载内核驱动层流程分析(上)

1.supported_functions

static struct android_usb_function *supported_functions[] = {
 &rmnet_smd_function,
 &rmnet_sdio_function,
 &rmnet_smd_sdio_function,
 &rmnet_function,
 &diag_function,
 &serial_function,
 &adb_function,
 &ccid_function,
// &acm_function,
 &mtp_function,
 &ptp_function,
 &rndis_function,
 &mass_storage_function,
 &accessory_function,
 NULL
};

既然是分析USB挂载流程,那就不看别的功能函数,直接跳向mass_storage_function。

2.mass_storage_function

static struct android_usb_function mass_storage_function = {
 .name  = "mass_storage",
 .init  = mass_storage_function_init,
 .cleanup = mass_storage_function_cleanup,
 .bind_config = mass_storage_function_bind_config,
 .attributes = mass_storage_function_attributes,
};

包括功能名、初始化、清理、绑定配置、属性。

关于android_usb_function结构体:

struct android_usb_function {
 char *name;    //"mass_storage"
 void *config;

struct device *dev;
 char *dev_name;
 struct device_attribute **attributes;

/* for android_dev.enabled_functions */
 struct list_head enabled_list;

/* Optional: initialization during gadget bind */    //当设备驱动绑定时的初始化(可选)
 int (*init)(struct android_usb_function *, struct usb_composite_dev *);
 /* Optional: cleanup during gadget unbind */    //当设备解绑的时候清理工作(可选)
 void (*cleanup)(struct android_usb_function *);

int (*bind_config)(struct android_usb_function *, struct usb_configuration *);    //绑定时的配置

/* Optional: called when the configuration is removed */    //当配置被移除时(可选)
 void (*unbind_config)(struct android_usb_function *, struct usb_configuration *);
 /* Optional: handle ctrl requests before the device is configured */    //设备被配置前有什么请求的话会运行这个函数(可选)
 int (*ctrlrequest)(struct android_usb_function *,
     struct usb_composite_dev *,
     const struct usb_ctrlrequest *);
};

init函数:mass_storage_function_init

在分析mass_storage_function_init函数之前,先要了解一个很重要的结构体:

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;  /*  8 characters or less */
 const char *product_name;  /* 16 characters or less */
 u16 release;

char   can_stall;
};

上边这个结构体在f_mass_storage.c中,在C文件开头就对这个结构体有详细的介绍:

nluns    最大支持的LUN数量(LUN:Logical units)

luns      每个LUN的参数,如下

-->filename    此LUN的名字,如果不是可移除的(removable)则不需要

-->ro              FALSE(TRUE),设置read-only,如果是CD-ROM则不可能挂载成R/W

-->removable    TRUE(FALSE),说明此LUN可移除

-->cdrom      FALSE(TRUE),此LUN是否为CD-ROM

-->nofua      FALSE(TRUE),此LUN是否可忽略

还有lun_name_format  建议为lun%d形式,如果不只是一个LUN,可以用%d来引导,必须是整型数字,如果不符合,可能将出现不可预知的错误。

thread_name    默认名字是"file_storage",是应该叫内核线程名字吧

了解了这个结构体后,看mass_storage_function_init函数:

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;
        int i;
 config = kzalloc(sizeof(struct mass_storage_function_config),
        GFP_KERNEL);
 if (!config)
  return -ENOMEM;

/* support multi luns and ro of ench lun is set to 0 to allow
    * opening "filename" in R/W mode. If the file is read-only,
    * the ro will be set to 1 automatically.
    */
    config->fsg.nluns = USB_MAX_LUNS;    //USB_MAX_LUNS=3,说明支持三个存储设备。
 for (i = 0; i < USB_MAX_LUNS; i++) {    //三个设备都可以移除,可以忽略,可以挂载为R/W,没有一个是CD-ROM
        config->fsg.luns[i].removable = 1;
        config->fsg.luns[i].nofua = 1;   
 } 

common = fsg_common_init(NULL, cdev, &config->fsg);  //交给fsg_common_init去根据配置创建设备,具体实现在f_mass_storage.c中
 if (IS_ERR(common)) {
  kfree(config);
  return PTR_ERR(common);
 }

/* create a symlink for each lun */
 for (i = 0; i < USB_MAX_LUNS; i++)
    {
        err = sysfs_create_link(&f->dev->kobj,   
                    &common->luns[i].dev.kobj,
                    dev_name(&common->luns[i].dev));    //创建设备链接
        if (err)
        {
      fsg_common_release(&common->ref);
            kfree(config);
            return err;
        }
    }

config->common = common;
 f->config = config;
 return 0;
}

至此基本的结构也就初始化完成了。配置很重要,一定不能错。明天再分析android_bind。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/fb1aba3105ec1f84ff9e8b4ff051821d.html