字符设备驱动:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 /* 驱动入口函数 */
2 static int __init xxx_init(void)
3 {
4 /* 入口函数具体内容 */
5 return 0;
6 }
7
8 /* 驱动出口函数 */
9 static void __exit xxx_exit(void)
10 {
11 /* 出口函数具体内容 */
12 }
13
14 /* 将上面两个函数指定为驱动的入口和出口函数 */
15 module_init(xxx_init);
16 module_exit(xxx_exit);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#define NEWCHRLED_CNT 1 /* 设备号个数 */
#define NEWCHRLED_NAME "newchrled" /* 名字 */
/* newchrled 设备结构体 */
struct newchrled_dev{
dev_t devid; /* 设备号 */
struct cdev cdev; /* cdev */
struct class *class; /* 类 */

struct device *device; /* 设备 */
int major; /* 主设备号 */
int minor; /* 次设备号 */
};
struct newchrled_dev newchrled; /* led 设备 */

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


static int __init xxx_init(void)
{
/* 注册字符设备驱动 */
/* 1、创建设备号 */
if (newchrled.major) { /* 定义了设备号 */
newchrled.devid = MKDEV(newchrled.major, 0);
register_chrdev_region(newchrled.devid, NEWCHRLED_CNT,
NEWCHRLED_NAME);
} else { /* 没有定义设备号 */
alloc_chrdev_region(&newchrled.devid, 0, NEWCHRLED_CNT,
NEWCHRLED_NAME); /* 申请设备号 */
newchrled.major = MAJOR(newchrled.devid); /* 获取主设备号 */
newchrled.minor = MINOR(newchrled.devid); /* 获取次设备号 */
}
printk("newcheled major=%d,minor=%d\r\n",newchrled.major,
newchrled.minor);

/* 2、初始化 cdev */
newchrled.cdev.owner = THIS_MODULE;
cdev_init(&newchrled.cdev, &newchrled_fops);

/* 3、添加一个 cdev */
cdev_add(&newchrled.cdev, newchrled.devid, NEWCHRLED_CNT);
/* 自动创建设备节点 */
/* 4、创建类 */
newchrled.class = class_create(THIS_MODULE, NEWCHRLED_NAME);
if (IS_ERR(newchrled.class)) {
return PTR_ERR(newchrled.class);
/* 5、创建设备 */
newchrled.device = device_create(newchrled.class, NULL,
newchrled.devid, NULL, NEWCHRLED_NAME);
if (IS_ERR(newchrled.device)) {
return PTR_ERR(newchrled.device);
}
return 0;
}

平台设备驱动:

平台设备:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/* 定义资源 */
#define CCM_CCGR1 0x020C406C //时钟控制寄存器
#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04 0x020E006C //GPIO1_04 复用功
能选择寄存器
...
/* 设备资源信息 */
static struct resource rled_resource[] = {
[0] = DEFINE_RES_MEM(GPIO1_DR, 4),
[1] = DEFINE_RES_MEM(GPIO1_GDIR, 4),
[2] = DEFINE_RES_MEM(IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04, 4),
[3] = DEFINE_RES_MEM(CCM_CCGR1, 4),
[4] = DEFINE_RES_MEM(IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04, 4),
};
/* platform 设备结构体 */
static struct platform_device rled_pdev = {
.name = "led_pdev",
.id = 0,
.num_resources = ARRAY_SIZE(rled_resource),
.resource = rled_resource,
.dev = {
.release = led_release,
.platform_data = rled_hwinfo,
},

};

static __init int led_pdev_init(void)
{
printk("pdev init\n");
platform_device_register(&rled_pdev);
return 0;

}

static __exit void led_pdev_exit(void)
{
printk("pdev exit\n");
platform_device_unregister(&rled_pdev);

}
module_init(led_pdev_exit);
module_exit(led_pdev_exit);


平台驱动:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
 #define LEDDEV_CNT 1 /* 设备号长度 */
#define LEDDEV_NAME "platled" /* 设备名字 */
static struct file_operations led_cdev_fops = {
.open = led_cdev_open,
.release = led_cdev_release,
.write = led_cdev_write,
};

static int led_pdrv_probe(struct platform_device *pdev)
{
struct led_data *cur_led;
unsigned int *led_hwinfo;
//第一步:提取平台设备提供的资源
cur_led = devm_kzalloc(&pdev->dev, sizeof(struct led_data), GFP_KERNEL);
if(!cur_led)
return -ENOMEM;
led_hwinfo = devm_kzalloc(&pdev->dev, sizeof(unsigned int)*2, GFP_KERNEL);
if(!led_hwinfo)
return -ENOMEM;
/* get platform resource */
mem_dr = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mem_gdir = platform_get_resource(pdev, IORESOURCE_MEM, 1);
mem_iomuxc_mux = platform_get_resource(pdev, IORESOURCE_MEM, 2);
mem_ccm_ccgrx = platform_get_resource(pdev, IORESOURCE_MEM, 3);
mem_iomux_pad = platform_get_resource(pdev, IORESOURCE_MEM, 4);
//第二步:注册字符设备
cur_dev = MKDEV(DEV_MAJOR, pdev->id);
register_chrdev_region(cur_dev, 1, "led_cdev");
cdev_init(&cur_led->led_cdev, &led_cdev_fops);
ret = cdev_add(&cur_led->led_cdev, cur_dev, 1);
if(ret < 0)
{
printk("fail to add cdev\n");
goto add_err;
}
device_create(my_led_class, NULL, cur_dev, NULL, DEV_NAME "%d", pdev->id);
/* save as drvdata */
platform_set_drvdata(pdev, cur_led);
return 0;
}

static struct platform_driver led_pdrv = {
.probe = led_pdrv_probe,
.remove = led_pdrv_remove,
.driver.name = "led_pdev",
.id_table = led_pdev_ids,
};

static __init int led_pdrv_init(void)
{

printk("led platform driver init\n");
my_led_class = class_create(THIS_MODULE, "my_leds");
platform_driver_register(&led_pdrv);
return 0;
}

static __exit void led_pdrv_exit(void)
{
printk("led platform driver exit\n");
platform_driver_unregister(&led_pdrv);
class_destroy(my_led_class);
}
module_init(led_pdrv_init);
module_exit(led_pdrv_exit);
MODULE_LICENSE("GPL");

设备树驱动:

在内核设备树文件中添加设备树节点,编译生成dtb文件移植到开发板上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#define DTSLED_CNT 1 /* 设备号个数 */
#define DTSLED_NAME "dtsled" /* 名字 */
/* dtsled 设备结构体 */
struct dtsled_dev{
dev_t devid; /* 设备号 */
struct cdev cdev; /* cdev */
struct class *class; /* 类 */
struct device *device; /* 设备 */
int major; /* 主设备号 */
int minor; /* 次设备号 */
struct device_node *nd; /* 设备节点 */
};

struct dtsled_dev dtsled; /* led 设备 */

/* 设备操作函数 */
static struct file_operations dtsled_fops = {
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write,
.release = led_release,
};

static int __init led_init(void)
{

/* 获取设备树中的属性数据 */
/* 1、获取设备节点:alphaled */
dtsled.nd = of_find_node_by_path("/alphaled");
if(dtsled.nd == NULL) {
printk("alphaled node can not found!\r\n");
return -EINVAL;
} else {
printk("alphaled node has been found!\r\n");
}
/* 2、获取 compatible 属性内容 */
proper = of_find_property(dtsled.nd, "compatible", NULL);
if(proper == NULL) {
printk("compatible property find failed\r\n");
} else {
printk("compatible = %s\r\n", (char*)proper->value);
}
/* 3、获取 status 属性内容 */
ret = of_property_read_string(dtsled.nd, "status", &str);
if(ret < 0){
printk("status read failed!\r\n");
} else {
printk("status = %s\r\n",str);
}
/* 4、获取 reg 属性内容 */
ret = of_property_read_u32_array(dtsled.nd, "reg", regdata, 10);
if(ret < 0) {
printk("reg property read failed!\r\n");
} else {
u8 i = 0;
printk("reg data:\r\n");
for(i = 0; i < 10; i++)
printk("%#X ", regdata[i]);
printk("\r\n");
}

/* 注册字符设备驱动 */
/* 1、创建设备号 */
if (dtsled.major) { /* 定义了设备号 */
dtsled.devid = MKDEV(dtsled.major, 0);
register_chrdev_region(dtsled.devid, DTSLED_CNT,
DTSLED_NAME);
} else { /* 没有定义设备号 */
alloc_chrdev_region(&dtsled.devid, 0, DTSLED_CNT,
DTSLED_NAME); /* 申请设备号 */
dtsled.major = MAJOR(dtsled.devid); /* 获取分配号的主设备号 */
dtsled.minor = MINOR(dtsled.devid); /* 获取分配号的次设备号 */
}
printk("dtsled major=%d,minor=%d\r\n",dtsled.major,
dtsled.minor);
/* 2、初始化 cdev */
dtsled.cdev.owner = THIS_MODULE;
cdev_init(&dtsled.cdev, &dtsled_fops);
/* 3、添加一个 cdev */
cdev_add(&dtsled.cdev, dtsled.devid, DTSLED_CNT);
/* 4、创建类 */
dtsled.class = class_create(THIS_MODULE, DTSLED_NAME);
if (IS_ERR(dtsled.class)) {
return PTR_ERR(dtsled.class);
}
/* 5、创建设备 */
dtsled.device = device_create(dtsled.class, NULL, dtsled.devid,
NULL, DTSLED_NAME);
if (IS_ERR(dtsled.device)) {
return PTR_ERR(dtsled.device);
}
return 0;
}

static void __exit led_exit(void)
{
/* 注销字符设备驱动 */
cdev_del(&dtsled.cdev);/* 删除 cdev */
unregister_chrdev_region(dtsled.devid, DTSLED_CNT);/*注销设备号*/

device_destroy(dtsled.class, dtsled.devid);
class_destroy(dtsled.class);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");