学习《Linux设备模型浅析之设备篇》笔记(一)

最近在学习Linux设备模型,前面几篇文章也是读这篇的时候遇到问题,然后为了搞清楚先转去摸索才写出来的。

当然了,刚开始是先读到《Linux那些事儿之我是Sysfs》,搞不清楚才去读的《Linux设备模型浅析之uevent》,结果那篇文章说要先读《Linux设备模型浅析之设备篇》。

而读《Linux那些事儿之我是Sysfs》之前是先读了《Linux那些事儿之我是U盘》,原因是当初在某培训机构培训后有一家公司去招聘,面试唯一的问题是,你搞过USB驱动吗?答:没搞过。然后面试就结束了。

另一个原因是自己买了一个USB无线网卡,用Linux内核带的驱动该网卡很不稳定,然后就跑到某国内操作系统论坛抱怨Linux下上网速度很慢,后来发现编译安装官方给的驱动就可以正常运行(发现自己的抱怨真的很笨)。为了搞懂这些都是为什么,于是决定学习USB驱动,并准备接下来学习网卡驱动。

USB的学习,这里必须推荐一下《圈圈教你玩USB》,我买了它的书和开发板之后,才能够快速的入门USB协议。看完了这本书之后才会有耐心开始看《Linux那些事儿之我是U盘》,然后才终于打开了Linux内核学习的大门。


好了,上面是闲扯,也是自己这一个月能够入门Linux内核的历程,结束了上面的闲扯之后,下面接着闲扯。

网上的这篇《Linux设备模型浅析之设备篇》我看2011年已经在网上传了,估计内核版本也比较老了,文章给出的 http://zhiqiang0071.cublog.cn 也打不开了。

我是升级控,把涉及到的代码用新版本的内核源码贴出来,也是为了保证自己学习的时候能够深入进去。

现在www.kernel.org最新稳定版本为3.14.5,这里源码就用这个内核版本


文件/arch/arm/plat-samsung/devs.c

static struct resource s3c_rtc_resource[] = {
        [0] = DEFINE_RES_MEM(S3C24XX_PA_RTC, SZ_256),
        [1] = DEFINE_RES_IRQ(IRQ_RTC),
        [2] = DEFINE_RES_IRQ(IRQ_TICK),
};


文件/include/linux/ioport.h

#define DEFINE_RES_MEM(_start, _size) \
        DEFINE_RES_MEM_NAMED((_start), (_size), NULL)


#define DEFINE_RES_MEM_NAMED(_start, _size, _name) \
        DEFINE_RES_NAMED((_start), (_size), (_name), IORESOURCE_MEM)


#define DEFINE_RES_NAMED(_start, _size, _name, _flags)\
        { \
                .start = (_start), \
                .end = (_start) + (_size) - 1, \
                .name = (_name), \
                .flags = (_flags), \
        }


#define DEFINE_RES_IRQ(_irq) \
        DEFINE_RES_IRQ_NAMED((_irq), NULL)


#define DEFINE_RES_IRQ_NAMED(_irq, _name) \
        DEFINE_RES_NAMED((_irq), 1, (_name), IORESOURCE_IRQ)


struct platform_device s3c_device_rtc = {
        .name = "s3c2410-rtc",
        .id = -1,
        .num_resources = ARRAY_SIZE(s3c_rtc_resource),
        .resource = s3c_rtc_resource,
};


文件/arch/arm/mach-s3c64xx/mach-smdk6410.c

static struct platform_device *smdk6410_devices[] __initdata = {
#ifdef CONFIG_SMDK6410_SD_CH0
        &s3c_device_hsmmc0,
#endif
#ifdef CONFIG_SMDK6410_SD_CH1
        &s3c_device_hsmmc1,
#endif
        &s3c_device_i2c0,
        &s3c_device_i2c1,
        &s3c_device_fb,
        &s3c_device_ohci,
        &samsung_device_pwm,
        &s3c_device_usb_hsotg,
        &s3c64xx_device_iisv4,
        &samsung_device_keypad,


#ifdef CONFIG_REGULATOR
        &smdk6410_b_pwr_5v,
#endif
        &smdk6410_lcd_powerdev,

        &smdk6410_smsc911x,
        &s3c_device_adc,
        &s3c_device_cfcon,
        &s3c_device_rtc,
        &s3c_device_ts,
        &s3c_device_wdt,
};


struct bus_type platform_bus_type = {
        .name = "platform",
        .dev_groups = platform_dev_groups,
        .match = platform_match,
        .uevent = platform_uevent,
        .pm = &platform_dev_pm_ops,
};


文件/drivers/base/core.c

/**
 * device_initialize - 初始化device结构
 * @dev: device.
 *
 * 这里初始化其区域来为其他层使用该设备准备。
 * 这里是device_register()的前一半, 如果是被那个方法调用的话,
 * 可是它也可以被单独调用, so one may use @dev's fields. In particular, 
 * 尤其在调用本方法后可以使用get_device()/put_device()修改引用次数。
 *
 * 除了一些被明确赋值为其他值的项外,@dev的所有区域必须被调用方
 * 初始化为0.  最简单的方法是使用kzalloc()来分配一个包含@dev的结构。
 *
 * 注意: 一旦你调用了该方法,就要使用put_device()来放弃你的引用,
 * 而不是直接释放@dev。
 */
void device_initialize(struct device *dev)
{
        dev->kobj.kset = devices_kset;
        kobject_init(&dev->kobj, &device_ktype);
        INIT_LIST_HEAD(&dev->dma_pools);
        mutex_init(&dev->mutex);
        lockdep_set_novalidate_class(&dev->mutex);
        spin_lock_init(&dev->devres_lock);
        INIT_LIST_HEAD(&dev->devres_head);
        device_pm_init(dev);
        set_dev_node(dev, -1);
}


文件/drivers/base/core.c

/**
 * platform_device_add - 添加platform设备到设备层
 * @pdev: 正在添加的platform设备
 *
 * 这是platform_device_register()的第二部分, though may be called
 * separately _iff_ pdev was allocated by platform_device_alloc().
 */
int platform_device_add(struct platform_device *pdev)
{
        int i, ret;

        if (!pdev)
                return -EINVAL;

        if (!pdev->dev.parent)
                pdev->dev.parent = &platform_bus;

        pdev->dev.bus = &platform_bus_type;

        switch (pdev->id) {
        default:
                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
                break;
        case PLATFORM_DEVID_NONE:
                dev_set_name(&pdev->dev, "%s", pdev->name);
                break;
        case PLATFORM_DEVID_AUTO:
                /*
                 * 自动分配设备ID。我们把他标记为这样,来保证我们可以记住它
                 * 必须被释放,而且我们追加一个后缀来避免命名空间显示ID冲突。
                 */
                ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL);
                if (ret < 0)
                        goto err_out;
                pdev->id = ret;
                pdev->id_auto = true;
                dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);
                break;
        }

        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)) {
                        dev_err(&pdev->dev, "failed to claim resource %d\n", 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:
        if (pdev->id_auto) {
                ida_simple_remove(&platform_devid_ida, pdev->id);
                pdev->id = PLATFORM_DEVID_AUTO;
        }

        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);
        }

        err_out:
        return ret;
}

你可能感兴趣的:(学习《Linux设备模型浅析之设备篇》笔记(一))