学习《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设备模型浅析之设备篇》笔记(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: /sys目录下其他几个目录的生成
- 下一篇: 学习《Linux设备模型浅析之设备篇》笔