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/目录。