SDIO驱动(3)sdio总线诞生记

xiaoxiao2021-02-28  131

Linux定义了形形色色的总线i2c,usb,pci还有我们这里要说的sdio等等等等,所谓总线,简单理解就是实现一个规范(specification),用来支持规范中定义的操作时序、读写方式、命令集合等,满足spec定义的设备或驱动就可以挂载上面由core(usb core,mmc core)进行管理。 对于sdio总线,它的定义如下: static struct bus_type sdio_bus_type = { .name = "sdio", .dev_attrs = sdio_dev_attrs, .match = sdio_bus_match, .uevent = sdio_bus_uevent, .probe = sdio_bus_probe, .remove = sdio_bus_remove, .pm = SDIO_PM_OPS_PTR, };"sdio"是我们给总线起的名字。 dev_attrs是一个struct device_attribute类型的指针,用来指定总线上设备的属性。如果用数组赋值,则最后一个元素必须为NULL,表示数组的结束,如这里的数组sdio_dev_attrs: static struct device_attribute sdio_dev_attrs[] = { __ATTR_RO(class), __ATTR_RO(vendor), __ATTR_RO(device), __ATTR_RO(modalias), __ATTR_NULL, };其中__ATTR_RO是一个宏,我们结合 struct device_attribute结构体来理解: #define __ATTR_NULL { .attr = { .name = NULL } } #define __ATTR_RO(_name) { \ .attr = { .name = __stringify(_name), .mode = 0444 }, \ .show = _name##_show, \ } struct device_attribute { struct attribute attr; ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf); ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); };显而易见,这里就是定义指定name的属性并设置属性读取函数(0444-只读属性)。各个属性文件对应只读函数函数实现: /* show configuration fields */ #define sdio_config_attr(field, format_string) \ static ssize_t field##_show(struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct sdio_func *func; \ \ func = dev_to_sdio_func (dev); \ return sprintf (buf, format_string, func->field); \ } sdio_config_attr(class, "0xx\n"); sdio_config_attr(vendor, "0xx\n"); sdio_config_attr(device, "0xx\n");一目了然。 sdio总线注册方式: int sdio_register_bus(void) { return bus_register(&sdio_bus_type); }由于mmc/sd/sdio之间的千丝万缕的关系,它们在mmc core 统一注册,sdio_register_bus()的调用: subsys_initcall(mmc_init); static int __init mmc_init(void) { int ret; ret = mmc_register_bus(); if (ret) return ret; ret = mmc_register_host_class(); if (ret) goto unregister_bus; ret = sdio_register_bus(); if (ret) goto unregister_host_class; return 0; unregister_host_class: mmc_unregister_host_class(); unregister_bus: mmc_unregister_bus(); return ret; } mmc_register_bus,注册"mmc"总线,成功后在sys文件系统就会出现/sys/bus/mmc/目录。 mmc_register_host_class,注册"mmc_host"类(class),成功后在sys文件系统就会出现/sys/class/mmc_host/目录;出错的话说明MMC子系统出现故障,然后调用mmc_unregister_bus卸掉上面注册的mmc总线。 sdio_register_bus,这个就是我们的"sdio"总线注册,如果出错卸掉前面的注册结果。注册成功后在sys文件系统就会出现/sys/bus/sdio/目录。
转载请注明原文地址: https://www.6miu.com/read-60149.html

最新回复(0)