天天看點

SDIO驅動(3)sdio總線誕生記

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, "0x%02x\n");
sdio_config_attr(vendor, "0x%04x\n");
sdio_config_attr(device, "0x%04x\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/目錄。

繼續閱讀