1 #include <linux/module.h> //MODULE_LICENSE("GPL");
2 #include <linux/init.h> //module_init module_exit
3 #include <linux/kernel.h> //printk
4 #include <linux/io.h> //ioremap iounremap
5 #include <linux/ioport.h> //request_mem_region
6 #include <mach/regs-gpio.h>
7
8 #include <linux/miscdevice.h>
9 #include <linux/fs.h> //file_operations 结构体的定义
10
11 /*
12 混杂字符设备驱动
13 linux/miscdevice.h
14
15 struct miscdevice
16
17 通过 cat /proc/devices 查看当前系统下所有的设备节点
18 misc 是字符设备中的一种, 所有的misc设备,主设备都是10,
19 struct miscdevice {
20 int minor; //字符设备 次设备,次设备号一般交给内核,让内核自行分配
21 minor = MISC_DYNAMIC_MINOR
22 const char *name; // 设备名称
23 const struct file_operations *fops; //文件操作相关,这个结构非常重要
24 //实现read open write close 等一些列文件操作,这些文件操作将和应用层交互
25
26 struct list_head list;
27 struct device *parent;
28 struct device *this_device;
29 const char *nodename;
30 umode_t mode;
31 };
32
33 linux/fs.h 头文件中
34 const struct file_operations *fops;
35
36 ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
37 ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
38 int (*open) (struct inode *, struct file *);
39 int (*release) (struct inode *, struct file *);
40
41
42 int fd = open("/dev/led");
43 当应用层调用对应的misc的设备节点时候,那么file_operations 会被自动调用
44
45 close-->release
46 read-->read
47 write-->write
48 */
49
50 /*
51 input 输入子系统
52 cdev 字符设备
53 misc 混杂字符设备 本质就是一个字符设备
54 /sysfs /proc
55
56
57
58 insmod test.ko之后
59 那么在 /dev/就会出现对应的节点
60
61
62 */
63
64 #define LED_REG_BASE 0x110002e0
65 #define DEVNAME "my_led"
66
67 //static u32 led_reg;
68
69 #define GPM4CON (*(volatile u32 *)(S5P_VA_GPIO2 + 0x02e0))
70 #define GPM4DAT (*(volatile u32 *)(S5P_VA_GPIO2 + 0x02e4))
71
72 struct ldm_info
73 {
74 struct miscdevice dev; //设备节点
75 struct file_operations ops; //文件操作
76 };
77
78 struct ldm_info ldm;
79
80 static int ldm_open(struct inode * inode, struct file * file)
81 {
82 printk("kernel: ldm_open\n");
83 return 0;
84 }
85
86
87 static void led_on(u8 stat)
88 {
89 GPM4DAT = (GPM4DAT & ~0xf) | (stat & 0xf);
90 }
91
92 //__user 标志 说明 地址是用户地址
93 /*
94 用户层
95 ssize_t write(int fildes, const void *buf, size_t nbyte);
96 调用用户层的write 之后, 会进入到内核中,调用file_operations中的write方法
97
98 */
99
100 //file_operations 中的read 和write都是站在 应用层的角度
101 static ssize_t ldm_write(struct file * file, const char __user * buf, size_t size, loff_t * offt)
102 {
103 printk("kernel:ldm_write\n");
104 led_on(*buf);
105 return 1;
106 }
107
108
109 //copy_to_user copy_from_user
110 //static ssize_t ldm_read(struct file * file, char __user * buf, size_t, loff_t *);
111
112
113 static int test_init(void)
114 {
115 int ret = 0;
116
117 printk("%s:%s:%d init\n", __FILE__, __FUNCTION__, __LINE__);
118 //向Linux内核中申请一段地址空间,如果之前已经有了其他的模块对该地址进行了申请,那么本次申请会失败.
119 //注册成功之后,那么可以在/proc/iomem 看到注册信息
120 //
121 if(!request_mem_region(LED_REG_BASE, 8 , DEVNAME)) {
122 printk("request_mem_region failed\n");
123 ret = -1;
124 goto err_request_mem_region;
125 }
126
127 //所谓的静态映射,是三星4412平台,已经做好的把物理地址,映射到的对应当的虚拟地址,所以此时没必要再调用ioremap函数
128 //led_reg = (u32)ioremap(LED_REG_BASE, 8);
129
130 //配置成输出模式
131 GPM4CON = (GPM4CON & ~0xffff) | 0x1111;
132
133 //填充info中的 miscdevice 结构体
134 //GPM4DAT = (GPM4DAT & ~0xf) | 0b1001;
135 ldm.dev.minor = MISC_DYNAMIC_MINOR; //系统自动分配次设备
136 ldm.dev.name = DEVNAME;//该名称将决定节点名称, 成功注册 linux 系统中
137 //在/dev 能够找一个和DEVNAME一样的节点
138 ldm.dev.fops = &ldm.ops; //关联文件操作
139
140 ldm.ops.open = ldm_open;
141 ldm.ops.write = ldm_write;
142
143 //把这个misc 注册到linux 内核中
144 ret = misc_register(&ldm.dev);
145 if(ret < 0) {
146 printk("misc_register failed\n");
147 goto err_misc_register;
148 }
149
150 return 0;
151 err_misc_register:
152 release_mem_region(LED_REG_BASE, 8);
153 err_request_mem_region:
154 return ret;
155
156 }
157
158 //卸载
159 static void test_exit(void)
160 {
161 printk("%s:%s:%d init\n", __FILE__, __FUNCTION__, __LINE__);
162
163 //注销misc
164 misc_deregister(&ldm.dev);
165 //释放映射的虚拟地址
166 // iounmap((void *)led_reg);
167
168 release_mem_region(LED_REG_BASE, 8);
169 }
170
171 module_init(test_init);
172 module_exit(test_exit);
173
174
175 MODULE_LICENSE("GPL"); //加入GPL许可