1 #include <linux/init.h>
2 #include <linux/module.h>
3 #include <linux/platform_device.h>
4 #include <linux/fs.h>
5 #include <linux/device.h>
6 #include <linux/miscdevice.h>
7
8 #include <asm/io.h>
9 #include <asm/uaccess.h>
10
11
12 static void *led_reg_base;
13 static struct miscdevice led_misc;
14
15 //实现设备操作接口
16 int led_plat_drv_open(struct inode *inode, struct file *filp)
17 {
18
19 printk("--------^_^ %s------------
",__FUNCTION__);
20 // 对寄存器进行初始化
21 unsigned long value = __raw_readl(led_reg_base);
22 value &= ~(0xff<<12);
23 value |= (0x11<<12); //配置成输出功能
24 __raw_writel(value, led_reg_base);
25
26 return 0;
27 }
28 ssize_t led_plat_drv_write(struct file *filp, const char __user *buf, size_t size, loff_t *flags)
29 {
30 int ret;
31 printk("--------^_^ %s------------
",__FUNCTION__);
32
33 unsigned int value;
34 //应用空间数据转换为内核空间数据
35 ret = copy_from_user(&value, buf, size);
36 if(ret != 0){
37 printk("copy_from_user error!
");
38 return -EFAULT;
39 }
40
41
42
43 if(value)
44 {
45 // 将led亮起来
46 __raw_writel(__raw_readl(led_reg_base + 4) | (0x3<<3), led_reg_base + 4);
47 }else
48 {
49 __raw_writel(__raw_readl(led_reg_base + 4) &~(0x3<<3), led_reg_base + 4);
50 }
51
52
53 return size;
54 }
55
56 int led_plat_drv_close(struct inode *inode, struct file *filp)
57 {
58 printk("--------^_^ %s------------
",__FUNCTION__);
59
60 __raw_writel(__raw_readl(led_reg_base + 4) &~(0x3<<3), led_reg_base + 4);
61
62 return 0;
63 }
64
65
66
67 const struct file_operations plat_led_fops = {
68 .open = led_plat_drv_open,
69 .write = led_plat_drv_write,
70 .release = led_plat_drv_close,
71
72 };
73
74 int led_pdrv_probe(struct platform_device *pdev)
75 {
76 printk("-----------%s-----------
", __FUNCTION__);
77
78
79 //任务1---与应用交互
80 // register_chrdev() , class_create, device_create, fops
81 // 或一种写法---用一个函数搞定上面所有函数
82 led_misc.name = "plat_led"; // /dev/plat_led
83 led_misc.minor = 120; // 主设备号默认为10, 次设备*定义--MISC_DYNAMIC_MINOR(255)由系统分配
84 led_misc.fops = &plat_led_fops;
85 misc_register(&led_misc);
86
87
88 //任务2---与硬件交互---先要获取资源, ioremap/request_irq()
89 //参数1--从哪个pdev中获取
90 //参数2--资源的类型
91 //参数3--同种资源的第几个
92 struct resource *mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
93
94 //获取地址资源就需要进行地址映射
95 led_reg_base = ioremap(mem_res->start, resource_size(mem_res));
96
97
98
99 return 0;
100 }
101 int led_pdrv_remove(struct platform_device *pdev)
102 {
103 printk("-----------%s-----------
", __FUNCTION__);
104
105 iounmap(led_reg_base);
106 misc_deregister(&led_misc);
107
108 return 0;
109 }
110
111
112 const struct platform_device_id led_id_table[] = {
113 {"s5pv210_led", 0x123}, //第二个值随便写
114 {"exynos4_led", 0x124},
115 {"s5p6818_led", 0x444},
116 };
117
118
119 struct platform_driver led_pdrv = {
120 .probe = led_pdrv_probe,
121 .remove = led_pdrv_remove,
122 .driver = { //父类一定要初始化
123 .name = "samsung_led_drv", // 一定要初始化--自定义
124 },
125 .id_table = led_id_table,
126
127 };
128
129 static int __init plat_led_drv_init(void)
130 {
131
132 //注册一个pdrv
133 return platform_driver_register(&led_pdrv);
134
135 }
136
137 static void __exit plat_led_drv_exit(void)
138 {
139
140 platform_driver_unregister(&led_pdrv);
141 }
142
143
144 module_init(plat_led_drv_init);
145 module_exit(plat_led_drv_exit);
146 MODULE_LICENSE("GPL");
1 #include <linux/init.h>
2 #include <linux/module.h>
3 #include <linux/platform_device.h>
4
5
6 #define GPC0_REG_BASE 0xE0200060
7 #define GPC0_SIZE 8
8
9 struct resource led_res[] = {
10 [0] = {
11 .start = GPC0_REG_BASE,
12 .end = GPC0_REG_BASE + GPC0_SIZE - 1,
13 .flags = IORESOURCE_MEM,
14 },
15 //以下代码为演示如何定义多个资源--led硬件实际没有
16 [1] = {
17 .start = 0x666,
18 .end = 0x666,
19 .name = "fake_irq",
20 .flags = IORESOURCE_IRQ,
21 },
22 [2] = {
23 .start = 0x12345678,
24 .end = 0x12345678 + 0x8 - 1,
25 .name = "fake_mem",
26 .flags = IORESOURCE_MEM,
27 },
28 };
29
30
31 //主要用于解决rmmod的有警告
32 void led_pdev_release(struct device *dev) //pdev从总线移除系统自动调用
33 {
34
35
36 }
37
38
39 struct platform_device led_pdev = {
40 .name = "s5pv210_led",
41 .id = -1,
42 .dev = {
43 .release = led_pdev_release,
44 },
45 .num_resources = ARRAY_SIZE(led_res),
46 .resource = led_res,
47 };
48
49
50 static int __init plat_led_dev_init(void)
51 {
52
53 //注册一个pdev
54 return platform_device_register(&led_pdev);
55
56 }
57
58 static void __exit plat_led_dev_exit(void)
59 {
60
61 platform_device_unregister(&led_pdev);
62 }
63
64
65 module_init(plat_led_dev_init);
66 module_exit(plat_led_dev_exit);
67 MODULE_LICENSE("GPL");
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <fcntl.h>
7
8 int main(void)
9 {
10
11 int fd;
12 int on;
13
14 fd = open("/dev/plat_led",O_RDWR);
15 if(fd < 0)
16 {
17 perror("open");
18 exit(1);
19 }
20
21
22 while(1)
23 {
24
25 on = 1;
26 write(fd,&on,sizeof(on));
27 sleep(1);
28
29
30 on = 0;
31 write(fd,&on,sizeof(on));
32 sleep(1);
33 }
34
35 close(fd);
36 return 0;
37 }
1 CROSS_COMPILE = arm-none-linux-gnueabi-
2 CC = $(CROSS_COMPILE)gcc
3
4 #指定内核源码路径
5 KERNEL_DIR = /home/farsight/s5pv210/kernel/driver/linux-3.0.8
6 CUR_DIR = $(shell pwd)
7
8 MYAPP = plat_led_app
9
10 MODULE = plat_led_dev
11 MODULE2 = plat_led_drv
12
13 all:
14 #让make进入内核源码编译,同时将当前目录中的c程序作为内核模块一起编译
15 make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
16 ifneq ($(MYAPP), )
17 $(CC) -o $(MYAPP) $(MYAPP).c
18 endif
19
20 clean:
21 #删除上面编译生成的文件
22 make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
23 rm -rf $(MYAPP)
24
25 install:
26 cp *.ko $(MYAPP) /opt/rootfs/drv_module
27
28 #指定当前目录下哪个文件作为内核模块编
29 obj-m += $(MODULE).o
30 obj-m += $(MODULE2).o