开始初始化整个机器,启动内核
=========================================================
#ifdef CONFIG_MSM_DEBUG_UART
.phys_io = MSM_DEBUG_UART_PHYS,
.io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
.boot_params = PHYS_OFFSET + 0x1000,
.map_io = map_io,
.init_irq = init_irq,
//初始化整个机器设备
.init_machine =_init,
.timer = &msm_timer,
MACHINE_END
=======================================================
static void __init init(void)//board-es209ra.c
{
...........................
_init_usb();
_init_mmc();
bt_power_init();
audio_gpio_init();
msm_device_i2c_init();
msm_qsd_spi_init();
...........................
}
=======================================================
static void __init init_mmc(void)//board-es209ra.c
{
vreg_mmc = vreg_get(NULL, "gp6");
if (IS_ERR(vreg_mmc)) {
printk(KERN_ERR "%s: vreg get failed (%ld)\n",
__func__, PTR_ERR(vreg_mmc));
return;
}
sdcc_gpio_init();
msm_add_sdcc(1, &es209ra_sdcc_data1);
}
=======================================================
进入 init_mmc之后首先进行mmc与cpu相连接的gpio的初始化也即是
static void sdcc_gpio_init(void)
{
/* SD Card detection */
if (gpio_request(23, "sdc1_status_irq"))
pr_err("failed to request gpio sdc1_status_irq\n");
if (gpio_request(51, "sdc1_data_3"))
pr_err("failed to request gpio sdc1_data_3\n");
if (gpio_request(52, "sdc1_data_2"))
pr_err("failed to request gpio sdc1_data_2\n");
if (gpio_request(53, "sdc1_data_1"))
pr_err("failed to request gpio sdc1_data_1\n");
if (gpio_request(54, "sdc1_data_0"))
pr_err("failed to request gpio sdc1_data_0\n");
if (gpio_request(55, "sdc1_cmd"))
pr_err("failed to request gpio sdc1_cmd\n");
if (gpio_request(56, "sdc1_clk"))
pr_err("failed to request gpio sdc1_clk\n");
}
其次就是将mmc这种设备添加到系统中通过下面这个函数
int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat) //mach-msm/devices.c
{
struct platform_device *pdev;
if (controller < 1 || controller > 4)
return -EINVAL;
pdev = msm_sdcc_devices[controller-1];
pdev->dev.platform_data = plat;
return platform_device_register(pdev);
}
----------------------------------
这里要重点说一下平台设备的机制
平台设备大致需要以下四个步骤
分配platform_device,device_register,分配platform_driver
driver注册
----------------------------------
首先看这个msm_sdcc_devices[controller-1]
static struct platform_device *msm_sdcc_devices[] __initdata = {
&msm_device_sdc1,
&msm_device_sdc2,
&msm_device_sdc3,
&msm_device_sdc4,
};
controller 为1,那么就是取的是第一个参数 msm_device_sdc1
struct platform_device msm_device_sdc1 = {
.name = "msm_sdcc",
.id = 1,//id这个参数到底是干什么的?
.num_resources = ARRAY_SIZE(resources_sdc1),
.resource = resources_sdc1,
.dev = {
.coherent_dma_mask = 0xffffffff,
},
};
重点看这个结构题的第三个参数.resource = resources_sdc1,
static struct resource resources_sdc1[] = {
{
.start = MSM_SDC1_BASE,
.end = MSM_SDC1_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{
.start = INT_SDC1_0,
.end = INT_SDC1_1,
.flags = IORESOURCE_IRQ,
.name = "irq",
},
{
.start = 8,
.end =8,
.flags = IORESOURCE_DMA,
},
};
这个结构题数组包含了mmc这个设备连接cpu所需要的内存区域,还有
就是中断线,以及dma
--------------------------------------
其次看pdev->dev.platform_data = plat;
将mmc这种设备的的似有数据都放在plat这个结构里面,也即是es209ra_sdcc_data1
static struct mmc_platform_data es209ra_sdcc_data1 = {
.ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
.translate_vdd = msm_sdcc_setup_power,
.status = es209ra_sdcc_slot_status,
.status_irq = INT_ES209RA_GPIO_CARD_INS_N,
.irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
.mmc_bus_width = MMC_CAP_4_BIT_DATA,
#ifdef CONFIG_MMC_MSM_SDC1_DUMMY52_REQUIRED
.dummy52_required = 1,
#endif
};
NOTE:这是linux常用的似有结构题的形式,将这个指针放在pdev->dev.platform_data中,
一起注册到系统中去。
---------------------------------------
接下来就是platform_device_register(pdev)这条语句
这条语句干了什么事儿呢?
也就是上面所说的平台设备的第二步,将分配好的platform_device(有私有数据了,有中断,内存,dma,
还有driver name了,那么只要注册进去了,在driver边就可以直接使用)结构注册到系统中去。
进去看看发生了什么事儿:
int platform_device_register(struct platform_device *pdev)//drivers/base/platform.c
{
device_initialize(&pdev->dev);
return platform_device_add(pdev);
}
platform_device_add(pdev);
int platform_device_add(struct platform_device *pdev)//drivers/base/platform.c
{
int i, ret = 0;
if (!pdev)
return -EINVAL;
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus;
pdev->dev.bus = &platform_bus_type;
if (pdev->id != -1)
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
else
dev_set_name(&pdev->dev, pdev->name);
for (i = 0; i < pdev->num_resources; i++) {
struct resource *p, *r = &pdev->resource[i];
if (r->name == NULL)
r->name = dev_name(&pdev->dev);
p = r->parent;
if (!p) {
if (resource_type(r) == IORESOURCE_MEM)
p = &iomem_resource;
else if (resource_type(r) == IORESOURCE_IO)
p = &ioport_resource;
}
if (p && insert_resource(p, r)) {
printk(KERN_ERR
"%s: failed to claim resource %d\n",
dev_name(&pdev->dev), i);
ret = -EBUSY;
goto failed;
}
}
pr_debug("Registering platform device '%s'. Parent at %s\n",
dev_name(&pdev->dev), dev_name(pdev->dev.parent));
ret = device_add(&pdev->dev);
if (ret == 0)
return ret;
failed:
while (--i >= 0) {
struct resource *r = &pdev->resource[i];
unsigned long type = resource_type(r);
if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
release_resource(r);
}
return ret;
}
device_add(&pdev->dev);
int device_add(struct device *dev)
{
struct device *parent = NULL;
struct class_interface *class_intf;
int error = -EINVAL;
dev = get_device(dev);
if (!dev)
goto done;
/* Temporarily support init_name if it is set.
* It will override bus_id for now */
if (dev->init_name)
dev_set_name(dev, "%s", dev->init_name);
if (!strlen(dev->bus_id))
goto done;
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
parent = get_device(dev->parent);
setup_parent(dev, parent);
/* use parent numa_node */
if (parent)
set_dev_node(dev, dev_to_node(parent));
/* first, register with generic layer. */
error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev_name(dev));
if (error)
goto Error;
/* notify platform of device entry */
...................................
if (error)
goto ueventattrError;
error = device_create_sys_dev_entry(dev);
if (error)
goto devtattrError;
}
error = device_add_class_symlinks(dev);
if (error)
goto SymlinkError;
error = device_add_attrs(dev);
if (error)
goto AttrsError;
error = bus_add_device(dev);
if (error)
goto BusError;
error = dpm_sysfs_add(dev);
if (error)
goto DPMError;
device_pm_add(dev);
/* Notify clients of device addition. This call must come
* after dpm_sysf_add() and before kobject_uevent().
*/
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_ADD_DEVICE, dev);
kobject_uevent(&dev->kobj, KOBJ_ADD);
bus_attach_device(dev);
if (parent)
klist_add_tail(&dev->knode_parent, &parent->klist_children);
if (dev->class) {
mutex_lock(&dev->class->p->class_mutex);
/* tie the class to the device */
klist_add_tail(&dev->knode_class,
...............................
}
可以看到bus_attach_device(dev);
这个函数就可以想设备添加到相应的总线了,后面在driver那边取出其device就可以用了,包括私有信息
/**
* bus_attach_device - add device to bus
* @dev: device tried to attach to a driver
*
* - Add device to bus's list of devices.
* - Try to attach to driver.
*/
void bus_attach_device(struct device *dev)
{
struct bus_type *bus = dev->bus;
int ret = 0;
if (bus) {
if (bus->p->drivers_autoprobe)
ret = device_attach(dev);
WARN_ON(ret < 0);
if (ret >= 0)
klist_add_tail(&dev->knode_bus, &bus->p->klist_devices);
}
}
可以看到通过 klist_add_tail添加到总线的设备的链表,在driver边到时就可以
根据匹配规则去这个设备链表上面去拿东西了。
截至目前为止主要就是介绍了在设备端怎么添加设备到相应的总线上面去。
device_attach(dev);
/**
* device_attach - try to attach device to a driver.
* @dev: device.
*
* Walk the list of drivers that the bus has and call
* driver_probe_device() for each pair. If a compatible
* pair is found, break out and return.
*
* Returns 1 if the device was bound to a driver;
* 0 if no matching device was found;
* -ENODEV if the device is not registered.
*
* When called for a USB interface, @dev->parent->sem must be held.
*/
int device_attach(struct device *dev)
{
int ret = 0;
down(&dev->sem);
if (dev->driver) {
ret = device_bind_driver(dev);
if (ret == 0)
ret = 1;
else {
dev->driver = NULL;
ret = 0;
}
} else {
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
}
up(&dev->sem);
return ret;
}
阅读(1852) | 评论(1) | 转发(0) |