設備樹的查看與傳統驅動比較,簡單分析,初次編寫,環境搭建

設備樹在開發板上的查看

進入 sys/devices/platform
在這裏插入圖片描述
我們先用led 經行 查看
在這裏插入圖片描述
進入of_node (開放的固件) 裏面有 compatible(屬性) name pin(引腳) 進行查看 和設備樹上面的一致
最後一個用hexdump -C 進行查看 可以進行二進制的查看
在這裏插入圖片描述

寫設備樹時引用原有的代碼在哪查找

1 查看相關的文檔
假設我現在使用的3.5的內核那麼我就在--------->linux內核\linux-3.5-20160514\linux-3.5\Documentation\devicetree\bindings\arm
下面進行查看
![在這裏插入圖片描述](https://img-blog.csdnimg.cn/20200514144434508.png寄存器 x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80Mzg5ODA2Nw==,size_16,color_FFFFFF,t_70)
裏面會有寫設備樹的規範
比如 compatible 裏面必須填寫的信息是 atmel,<chip>-pit"
reg 是寄存器集合的地址偏移長度
在這裏插入圖片描述
2 查找同類型的單板設備樹文件 (在這個目錄下的文件就是參考上面的相關文檔寫出來的驅動)
在---->linux內核\linux-3.5-20160514\linux-3.5\drivers 有各種的硬件相關的設施
如果我們查看輸入子系統的設備 可以在裏面查看別人寫好的驅動程序
在這裏插入圖片描述
3 直接查看其他的設備樹來修改我們的設備樹
比如這兩個設備樹都是同一個單板的設備樹 但是多了mmc 我們要是給自己單板增加mmc 可以查看這兩個文件不同點
在這裏插入圖片描述

設備樹環境的構造

在jz2440 中要更換新的內核—>linux4.19,才能使用設備樹,由於需要編譯新的內核也需要新的交叉編譯鏈

  1. 編譯器的選擇:
    一個完整的Linux系統包含三部分: u-boot, kernel, root filesystem.
    a. 對於u-boot:
    我們仍然使用u-boot 1.1.6, 在這個版本上我們實現了很多功能: usb下載,菜單操作,網卡永遠使能等, 不忍丟棄.

b. 對於kernel:
我下載了目前(2018.09.19)最新的內核 (4.19)

c. 對於root filesystem
中文名爲"根文件系統", 它包含一些必須的APP, 一些動態庫。
一般來說這些動態庫是從工具鏈裏的lib目錄複製得到的,
當然也可以自己去編譯glibc等庫。

在編譯u-boot和kernel時, 我們可以使用新的工具鏈,
只要這個工具鏈支持ARM9的指令集(armv4)就可以(這通常可以通過編譯參數來指定使用特定的指令集).
工具鏈可以從某些網站上下載,並不需要自己去製作。
比如可以訪問這個網站: https://releases.linaro.org/components/toolchain/binaries/4.9-2017.01/arm-linux-gnueabi/
下載: gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi.tar.xz

但是在製作根文件系統時, 實際上我們是編譯各種APP,
這些APP要用到一些動態庫, 爲了方便一般直接使用工具鏈中lib目錄裏的庫。
新版工具鏈的lib庫一般是支持新的芯片,比如cortex A7,A8,A9,並不支持ARM9。
所以在製作根文件系統、編譯APP時我們還得使用比較老的工具鏈: arm-linux-gcc-4.3.2.tar.bz2

  1. 通過設置PATH環境變量來選擇使用某個工具鏈:
    2.1 安裝工具鏈:
    這非常簡單, 解壓即可:
    sudo tar xjf arm-linux-gcc-4.3.2.tar.bz2 -C / (解壓到根目錄, /usr/local/arm/4.3.2/bin/下就是工具鏈)
    tar xJf gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi.tar.xz (解壓到當前目錄, 假設/work/system/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi/bin下就是工具鏈)

    注意: “/work/system” 請自行替換爲你的實際目錄

2.2 設置環境變量使用某個工具鏈:
a. 要使用arm-linux-gcc 4.3.2, 執行如下命令:
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/arm/4.3.2/bin
然後就可以執行 arm-linux-gcc -v 觀看到版本號了

b. 要使用arm-linux-gnueabi-gcc 4.9.4, 執行如下命令:
export PATH=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/work/system/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi/bin
然後就可以執行 arm-linux-gnueabi-gcc -v 觀看到版本號了

  1. u-boot的編譯:
    a. 首先設置環境變量使用要使用arm-linux-gnueabi-gcc 4.3.2
    b.
    把源文件u-boot-1.1.6.tar.bz2、補丁文件u-boot-1.1.6_device_tree_for_jz2440.patch放在同一個目錄,
    執行如下命令:
    tar xjf u-boot-1.1.6.tar.bz2 // 解壓
    cd u-boot-1.1.6
    patch -p1 < …/u-boot-1.1.6_device_tree_for_jz2440.patch // 打補丁
    make 100ask24x0_config // 配置
    make // 編譯, 可以得到u-boot.bin

  2. kernel的編譯:
    a. 首先設置環境變量使用要使用arm-linux-gnueabi-gcc 4.3.2
    b.
    把源文件linux-4.19-rc3.tar.gz、補丁文件linux-4.19-rc3_device_tree_for_jz2440.patch放在同一個目錄,
    執行如下命令:
    tar xzf linux-4.19-rc3.tar.gz // 解壓
    cd linux-4.19-rc3
    patch -p1 < …/linux-4.19-rc3_device_tree_for_jz2440.patch // 打補丁
    cp config_ok .config // 配置
    make uImage // 編譯, 可以得到arch/arm/boot/uImage
    make dtbs // 編譯, 可以得到arch/arm/boot/dts/jz2440.dtb

注意:
a. 如果提示"mkimage not found", 先編譯u-boot, 把tools/mkimage複製到/bin目錄
b. 如果提示"openssl/bio.h: No such file or directory"
先確保你的ubuntu可以上網, 然後執行如下命令:
sudo apt-get update
sudo apt-get install libssl-dev

  1. 製作root filesystem :
    可以直接使用映象文件: fs_mini_mdev_new.yaffs2

    如果想自己製作,請參考視頻:
    從www.100ask.net下載頁面打開百度網盤,
    打開如下目錄:
    100ask分享的所有文件
    009_UBOOT移植_LINUX移植_驅動移植(免費)
    畢業班第3課_移植3.4.2內核
    畢業班第3課第2節_移植3.4.2內核之修改分區及製作根文件系統.WMV

  2. 燒寫
    a. 使用EOP燒寫u-boot.bin到JZ2440的nor flash或nand flash
    b. 啓動u-boot, 在串口工具中輸入相應菜單命令, 使用dnw_100ask.exe發送對應文件

    菜單                            要發送的文件
    

[k] Download Linux kernel uImage uImage
[t] Download device tree file(.dtb) jz2440.dtb
[y] Download root_yaffs image fs_mini_mdev_new.yaffs2

燒寫完畢即可重啓進入板上LINUX系統。

寫第一個簡單的設備樹驅動

驅動和dts進行匹配

在之前的led平臺總線驅動裏面 driver增加of_match_table(能匹配的dts數組) 再自己新增這個數組
數組裏面填寫能匹配的dts設備
在這裏插入圖片描述
寫好後可以和設備樹進行匹配了 這個寫法不規範 但是能用。 一般寫成 jz2440,led 表示廠家,設備
在這裏插入圖片描述
匹配成功後,和之前一樣,probe 函數就被調用

驅動和dts進行參數互傳
  1. 用自帶屬性reg 把引腳當做寄存器進行值的傳輸
    在這裏插入圖片描述
  2. 用我們自己創建的屬性 經行數值的傳輸
    在這裏插入圖片描述
    得到led的引腳之後就直接像之前一樣對它初始化,賦值,調整高低電頻

進行編譯測試

在編譯u-boot和kernel時, 我們可以使用新的工具鏈, 4.9.4 的arm-linux-gnueabi-
新版工具鏈的lib庫一般是支持新的芯片,比如cortex A7,A8,A9,並不支持ARM9。
所以在製作根文件系統、編譯APP時我們還得使用比較老的工具鏈: arm-linux-gcc-4.3.2.tar.bz2
使用4.9.4

export  PATH=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/work/system/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi/bin

使用4.3.2

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/arm/4.3.2/bin
設備樹的編譯和燒寫

把設備樹文件 jz2440.dts 拷貝到內核的 arch/arm/boot/dts/ 下
在根目錄進行make dtbs 再進入arch/arm/boot/dts/ 把編譯好的設備樹文件 jz2440.dtb取出
在這裏插入圖片描述
當uboot能夠ping通虛擬機 而且虛擬機上nfs能掛載後 進行設備樹的燒寫

nfs 32000000 192.168.2.51:/work/nfs_root/jz2440.dtb
nand erase device_tree
nand write.jffs2 32000000 device_tree
驅動編譯和上傳

更改編譯工具鏈爲4.9.4

export  PATH=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/work/system/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi/bin

用下面的makefile 和驅動和應用文件 編譯出驅動 led_drv.ko
在開發板上掛載nfs文件系統

ifconfig eth0 192.168.2.15
mount -t nfs -o nolock,vers=2 192.168.2.51:/work/nfs_root /mnt
進入nfs目錄
insmod led_drv.ko 
ls /dev/led

現在設備節點已經創建
在這裏插入圖片描述

應用編譯

要先把編譯器更換 換成4.3.2 才能編譯應用

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/arm/4.3.2/bin

源碼

led_drv.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>

#define S3C2440_GPA(n)  (0<<16 | n)
#define S3C2440_GPB(n)  (1<<16 | n)
#define S3C2440_GPC(n)  (2<<16 | n)
#define S3C2440_GPD(n)  (3<<16 | n)
#define S3C2440_GPE(n)  (4<<16 | n)
#define S3C2440_GPF(n)  (5<<16 | n)
#define S3C2440_GPG(n)  (6<<16 | n)
#define S3C2440_GPH(n)  (7<<16 | n)
#define S3C2440_GPI(n)  (8<<16 | n)
#define S3C2440_GPJ(n)  (9<<16 | n)

static int led_pin;
static volatile unsigned int *gpio_con;
static volatile unsigned int *gpio_dat;

/* 123. 分配/設置/註冊file_operations 
 * 4. 入口
 * 5. 出口
 */

static int major;
static struct class *led_class;

static unsigned int gpio_base[] = {
	0x56000000, /* GPACON */
	0x56000010, /* GPBCON */
	0x56000020, /* GPCCON */
	0x56000030, /* GPDCON */
	0x56000040, /* GPECON */
	0x56000050, /* GPFCON */
	0x56000060, /* GPGCON */
	0x56000070, /* GPHCON */
	0,          /* GPICON */
	0x560000D0, /* GPJCON */
};

static int led_open (struct inode *node, struct file *filp)
{
	/* 把LED引腳配置爲輸出引腳 */
	/* GPF5 - 0x56000050 */
	int bank = led_pin >> 16;
	int base = gpio_base[bank];

	int pin = led_pin & 0xffff;
	gpio_con = ioremap(base, 8);
	if (gpio_con) {
		printk("ioremap(0x%x) = 0x%x\n", base, gpio_con);
	}
	else {
		return -EINVAL;
	}
	
	gpio_dat = gpio_con + 1;

	*gpio_con &= ~(3<<(pin * 2));
	*gpio_con |= (1<<(pin * 2));  

	return 0;
}

static ssize_t led_write (struct file *filp, const char __user *buf, size_t size, loff_t *off)
{
	/* 根據APP傳入的值來設置LED引腳 */
	unsigned char val;
	int pin = led_pin & 0xffff;
	
	copy_from_user(&val, buf, 1);

	if (val)
	{
		/* 點燈 */
		*gpio_dat &= ~(1<<pin);
	}
	else
	{
		/* 滅燈 */
		*gpio_dat |= (1<<pin);
	}

	return 1; /* 已寫入1個數據 */
}

static int led_release (struct inode *node, struct file *filp)
{
	printk("iounmap(0x%x)\n", gpio_con);
	iounmap(gpio_con);
	return 0;
}


static struct file_operations myled_oprs = {
	.owner = THIS_MODULE,
	.open  = led_open,
	.write = led_write,
	.release = led_release,
};


static int led_probe(struct platform_device *pdev)
{
	struct resource		*res;

	/* 根據platform_device的資源進行ioremap */
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (res) {
		led_pin = res->start;
	}
	else {
		/* 獲得pin屬性 */
		of_property_read_s32(pdev->dev.of_node, "pin", &led_pin);
	}

	if (!led_pin) 
	{
		printk("can not get pin for led\n");
		return -EINVAL;
	}
		

	major = register_chrdev(0, "myled", &myled_oprs);

	led_class = class_create(THIS_MODULE, "myled");
	device_create(led_class, NULL, MKDEV(major, 0), NULL, "led"); /* /dev/led */
	
	return 0;
}

static int led_remove(struct platform_device *pdev)
{
	unregister_chrdev(major, "myled");
	device_destroy(led_class,  MKDEV(major, 0));
	class_destroy(led_class);
	
	return 0;
}


static const struct of_device_id of_match_leds[] = {
	{ .compatible = "jz2440_led", .data = NULL },
	{ /* sentinel */ }
};


struct platform_driver led_drv = {
	.probe		= led_probe,
	.remove		= led_remove,
	.driver		= {
		.name	= "myled",
		.of_match_table = of_match_leds, /* 能支持哪些來自於dts的platform_device */
	}
};


static int myled_init(void)
{
	platform_driver_register(&led_drv);
	return 0;
}

static void myled_exit(void)
{
	platform_driver_unregister(&led_drv);
}



module_init(myled_init);
module_exit(myled_exit);


MODULE_LICENSE("GPL");



jz2440.dts

// SPDX-License-Identifier: GPL-2.0
/*
 * SAMSUNG SMDK2440 board device tree source
 *
 * Copyright (c) 2018 [email protected]
 * dtc -I dtb -O dts -o jz2440.dts jz2440.dtb
 */
 
#define S3C2410_GPA(_nr)	((0<<16) + (_nr))
#define S3C2410_GPB(_nr)	((1<<16) + (_nr))
#define S3C2410_GPC(_nr)	((2<<16) + (_nr))
#define S3C2410_GPD(_nr)	((3<<16) + (_nr))
#define S3C2410_GPE(_nr)	((4<<16) + (_nr))
#define S3C2410_GPF(_nr)	((5<<16) + (_nr))
#define S3C2410_GPG(_nr)	((6<<16) + (_nr))
#define S3C2410_GPH(_nr)	((7<<16) + (_nr))
#define S3C2410_GPJ(_nr)	((8<<16) + (_nr))
#define S3C2410_GPK(_nr)	((9<<16) + (_nr))
#define S3C2410_GPL(_nr)	((10<<16) + (_nr))
#define S3C2410_GPM(_nr)	((11<<16) + (_nr))

/dts-v1/;

/ {
	model = "SMDK24440";
	compatible = "samsung,smdk2440";

	#address-cells = <1>;
	#size-cells = <1>;
		
	memory@30000000 {
		device_type = "memory";
		reg =  <0x30000000 0x4000000>;
	};
/*
	cpus {
		cpu {
			compatible = "arm,arm926ej-s";
		};
	};
*/	
	chosen {
		bootargs = "noinitrd root=/dev/mtdblock4 rw init=/linuxrc console=ttySAC0,115200";
	};

	
	led {
		compatible = "jz2440_led";
		pin = <S3C2410_GPF(5)>;
	};
};


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章