2.6内核字符驱动程序
时间:2006-12-05 来源:kf701
目录
学习使用说明
1. 驱动程序源代码
2. Makefile
3. 加载脚本代码
4. 读测试
5. 写测试
首先你要有一份2.6内核的源码,然后编译并运行它。
在已运行了你编译的内核的系统里编译此驱动程序: $> make
编译成功后,以root身份运行加载脚本: $> ./chardev_load.sh
一切完成后,就可以测试你的驱动程序了。
此驱动程序的输出全部写到了 /var/log/debug 文件中,你可以如下查看:
$> tail -f /var/log/debug
我用的是 Linux debian 2.6.18.3,一切运行良好。
1 /*
2 * chardev.c kf701 2006/12/05
3 * /dev/kf701_chardev0 /proc/devices
4 */
5 #include <linux/init.h>
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <linux/fs.h>
9 #include <asm/uaccess.h>
10 #include <linux/cdev.h>
11
12 static int chardev_open(struct inode *, struct file *);
13 static int chardev_release(struct inode *, struct file *);
14 static ssize_t chardev_read(struct file *, char __user *, size_t, loff_t *);
15 static ssize_t chardev_write(struct file *, const char __user *, size_t, loff_t *);
16
17 #define SUCCESS 0
18 #define DEVICE "kf701_chardev"
19
20 int major = 233;
21 int minor = 0;
22
23 struct file_operations fops = {
24 .owner = THIS_MODULE,
25 .read = chardev_read,
26 .write = chardev_write,
27 .open = chardev_open,
28 .release = chardev_release,
29 };
30
31 struct my_dev{
32 uint8_t *buf;
33 uint32_t size;
34 uint32_t index;
35 struct semaphore sem;
36 struct cdev cdev;
37 } kf701_dev;
38
39 static int __init chardev_init(void)
40 {
41 // 1. 分配主设备号
42 dev_t devno = MKDEV( major, minor );
43 int ret = register_chrdev_region( devno, 1, DEVICE );
44 if( ret < 0 )
45 {
46 printk(KERN_DEBUG "register major number failed with %d\n", ret);
47 return ret;
48 }
49 printk(KERN_DEBUG "%s:register major number OK\n",DEVICE);
50
51 // 2. 注册设备
52 cdev_init( &kf701_dev.cdev, &fops );
53 kf701_dev.cdev.ops = &fops;
54 kf701_dev.cdev.owner = THIS_MODULE;
55 ret = cdev_add( &kf701_dev.cdev, devno, 1 );
56 if( ret < 0 )
57 {
58 printk(KERN_DEBUG "register device failed with %d\n", ret);
59 return ret;
60 }
61 printk(KERN_DEBUG "%s:register device OK\n",DEVICE);
62
63 // 3. 分配本驱动要使用的内存
64 kf701_dev.index = 0;
65 kf701_dev.size = 1024;
66 kf701_dev.buf = kmalloc( kf701_dev.size, GFP_KERNEL );
67 if( NULL == kf701_dev.buf )
68 {
69 printk(KERN_DEBUG "kmalloc failed\n");
70 return -ENOMEM;
71 }
72 printk(KERN_DEBUG "%s:kmalloc buffer OK\n",DEVICE);
73
74 // 初始化信号量
75 init_MUTEX( &(kf701_dev.sem) );
76 printk(KERN_DEBUG "%s:init semaphore OK\n",DEVICE);
77
78 return SUCCESS;
79 }
80
81 static void __exit chardev_exit(void)
82 {
83 dev_t devno = MKDEV( major, minor );
84 cdev_del( &kf701_dev.cdev );
85 unregister_chrdev_region( devno, 1 );
86
87 printk(KERN_DEBUG "%s:unregister device OK\n",DEVICE);
88 }
89
90 int chardev_open(struct inode *inode, struct file *file)
91 {
92 struct my_dev *dev = container_of(inode->i_cdev, struct my_dev, cdev);
93 file->private_data = dev;
94
95 printk(KERN_DEBUG "%s:open OK\n",DEVICE);
96 return SUCCESS;
97 }
98
99 int chardev_release(struct inode *inode, struct file *file)
100 {
101 printk(KERN_DEBUG "%s:release OK\n",DEVICE);
102 return SUCCESS;
103 }
104
105 ssize_t chardev_read(struct file *file, char __user *buf, size_t count,loff_t *offset)
106 {
107 struct my_dev *dev = file->private_data;
108 ssize_t retval = 0;
109
110 if( down_interruptible(&dev->sem) )
111 return -ERESTARTSYS;
112 printk(KERN_DEBUG "%s:read down sem OK\n",DEVICE);
113
114 if( 0 == dev->index )
115 goto out;
116 if( *offset >= dev->index )
117 goto out;
118 if( (*offset+count) > dev->index )
119 count = dev->index - *offset;
120 if( copy_to_user(buf, dev->buf + *offset, count) )
121 {
122 retval = -EFAULT;
123 goto out;
124 }
*offset += count;
125 retval = count;
126
127 out:
128 up(&dev->sem);
129 printk(KERN_DEBUG "%s:read up sem OK\n",DEVICE);
130 return retval;
131 }
132
133 // omit offset argument for write
134 ssize_t chardev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
135 {
136 struct my_dev *dev = file->private_data;
137 ssize_t retval = -ENOMEM;
138
139 if( down_interruptible(&dev->sem) )
140 return -ERESTARTSYS;
141 printk(KERN_DEBUG "%s:write down sem OK\n",DEVICE);
142
143 if( count > dev->size )
144 goto out;
145 if( copy_from_user(dev->buf, buf, count) )
146 {
147 retval = -EFAULT;
148 goto out;
149 }
150 dev->index = count;
151 retval = count;
152
153 out:
154 up(&dev->sem);
155 printk(KERN_DEBUG "%s:write up sem OK\n",DEVICE);
156 return retval;
157 }
158
159 module_init(chardev_init);
160 module_exit(chardev_exit);
161 MODULE_AUTHOR("kf701.ye at gmail.com");
162 MODULE_DESCRIPTION("Study for kf701");
163 MODULE_SUPPORTED_DEVICE(DEVICE);
164 MODULE_LICENSE("GPL");
下面是Makefile内容:
1
2 ###
3 # study
4 # kf_701
5 # 2006-12-4
6 ###
7
8 #obj-m += hello.o
9 obj-m += chardev.o
10
11 all:
12 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
13 clean:
14 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
加载脚本代码如下:
1 #!/bin/sh
2
3 module="chardev"
4 device="kf701_chardev"
5 mode=666
6
7 echo "insmod now"
8 /sbin/insmod ./$module.ko || exit 1
9
10 rm -f /dev/${device}0
11
12 major=$(awk "{ if(\$2 == \"${device}\") print \$1;}" /proc/devices)
13
14 echo "mknod now"
15 mknod /dev/${device}0 c $major 0
16
17 group="staff"
18 grep -q '^staff:' /etc/group || group="wheel"
19
20 echo "chgrp now"
21 chgrp $group /dev/${device}0
22 chmod $mode /dev/${device}0
23
下面是读测试方法:
$> cat /dev/kf701_chardev0
写测试如下命令:
$> echo "only for test" > /dev/kf701_chardev0
学习使用说明
1. 驱动程序源代码
2. Makefile
3. 加载脚本代码
4. 读测试
5. 写测试
首先你要有一份2.6内核的源码,然后编译并运行它。
在已运行了你编译的内核的系统里编译此驱动程序: $> make
编译成功后,以root身份运行加载脚本: $> ./chardev_load.sh
一切完成后,就可以测试你的驱动程序了。
此驱动程序的输出全部写到了 /var/log/debug 文件中,你可以如下查看:
$> tail -f /var/log/debug
我用的是 Linux debian 2.6.18.3,一切运行良好。
1 /*
2 * chardev.c kf701 2006/12/05
3 * /dev/kf701_chardev0 /proc/devices
4 */
5 #include <linux/init.h>
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <linux/fs.h>
9 #include <asm/uaccess.h>
10 #include <linux/cdev.h>
11
12 static int chardev_open(struct inode *, struct file *);
13 static int chardev_release(struct inode *, struct file *);
14 static ssize_t chardev_read(struct file *, char __user *, size_t, loff_t *);
15 static ssize_t chardev_write(struct file *, const char __user *, size_t, loff_t *);
16
17 #define SUCCESS 0
18 #define DEVICE "kf701_chardev"
19
20 int major = 233;
21 int minor = 0;
22
23 struct file_operations fops = {
24 .owner = THIS_MODULE,
25 .read = chardev_read,
26 .write = chardev_write,
27 .open = chardev_open,
28 .release = chardev_release,
29 };
30
31 struct my_dev{
32 uint8_t *buf;
33 uint32_t size;
34 uint32_t index;
35 struct semaphore sem;
36 struct cdev cdev;
37 } kf701_dev;
38
39 static int __init chardev_init(void)
40 {
41 // 1. 分配主设备号
42 dev_t devno = MKDEV( major, minor );
43 int ret = register_chrdev_region( devno, 1, DEVICE );
44 if( ret < 0 )
45 {
46 printk(KERN_DEBUG "register major number failed with %d\n", ret);
47 return ret;
48 }
49 printk(KERN_DEBUG "%s:register major number OK\n",DEVICE);
50
51 // 2. 注册设备
52 cdev_init( &kf701_dev.cdev, &fops );
53 kf701_dev.cdev.ops = &fops;
54 kf701_dev.cdev.owner = THIS_MODULE;
55 ret = cdev_add( &kf701_dev.cdev, devno, 1 );
56 if( ret < 0 )
57 {
58 printk(KERN_DEBUG "register device failed with %d\n", ret);
59 return ret;
60 }
61 printk(KERN_DEBUG "%s:register device OK\n",DEVICE);
62
63 // 3. 分配本驱动要使用的内存
64 kf701_dev.index = 0;
65 kf701_dev.size = 1024;
66 kf701_dev.buf = kmalloc( kf701_dev.size, GFP_KERNEL );
67 if( NULL == kf701_dev.buf )
68 {
69 printk(KERN_DEBUG "kmalloc failed\n");
70 return -ENOMEM;
71 }
72 printk(KERN_DEBUG "%s:kmalloc buffer OK\n",DEVICE);
73
74 // 初始化信号量
75 init_MUTEX( &(kf701_dev.sem) );
76 printk(KERN_DEBUG "%s:init semaphore OK\n",DEVICE);
77
78 return SUCCESS;
79 }
80
81 static void __exit chardev_exit(void)
82 {
83 dev_t devno = MKDEV( major, minor );
84 cdev_del( &kf701_dev.cdev );
85 unregister_chrdev_region( devno, 1 );
86
87 printk(KERN_DEBUG "%s:unregister device OK\n",DEVICE);
88 }
89
90 int chardev_open(struct inode *inode, struct file *file)
91 {
92 struct my_dev *dev = container_of(inode->i_cdev, struct my_dev, cdev);
93 file->private_data = dev;
94
95 printk(KERN_DEBUG "%s:open OK\n",DEVICE);
96 return SUCCESS;
97 }
98
99 int chardev_release(struct inode *inode, struct file *file)
100 {
101 printk(KERN_DEBUG "%s:release OK\n",DEVICE);
102 return SUCCESS;
103 }
104
105 ssize_t chardev_read(struct file *file, char __user *buf, size_t count,loff_t *offset)
106 {
107 struct my_dev *dev = file->private_data;
108 ssize_t retval = 0;
109
110 if( down_interruptible(&dev->sem) )
111 return -ERESTARTSYS;
112 printk(KERN_DEBUG "%s:read down sem OK\n",DEVICE);
113
114 if( 0 == dev->index )
115 goto out;
116 if( *offset >= dev->index )
117 goto out;
118 if( (*offset+count) > dev->index )
119 count = dev->index - *offset;
120 if( copy_to_user(buf, dev->buf + *offset, count) )
121 {
122 retval = -EFAULT;
123 goto out;
124 }
*offset += count;
125 retval = count;
126
127 out:
128 up(&dev->sem);
129 printk(KERN_DEBUG "%s:read up sem OK\n",DEVICE);
130 return retval;
131 }
132
133 // omit offset argument for write
134 ssize_t chardev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
135 {
136 struct my_dev *dev = file->private_data;
137 ssize_t retval = -ENOMEM;
138
139 if( down_interruptible(&dev->sem) )
140 return -ERESTARTSYS;
141 printk(KERN_DEBUG "%s:write down sem OK\n",DEVICE);
142
143 if( count > dev->size )
144 goto out;
145 if( copy_from_user(dev->buf, buf, count) )
146 {
147 retval = -EFAULT;
148 goto out;
149 }
150 dev->index = count;
151 retval = count;
152
153 out:
154 up(&dev->sem);
155 printk(KERN_DEBUG "%s:write up sem OK\n",DEVICE);
156 return retval;
157 }
158
159 module_init(chardev_init);
160 module_exit(chardev_exit);
161 MODULE_AUTHOR("kf701.ye at gmail.com");
162 MODULE_DESCRIPTION("Study for kf701");
163 MODULE_SUPPORTED_DEVICE(DEVICE);
164 MODULE_LICENSE("GPL");
下面是Makefile内容:
1
2 ###
3 # study
4 # kf_701
5 # 2006-12-4
6 ###
7
8 #obj-m += hello.o
9 obj-m += chardev.o
10
11 all:
12 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
13 clean:
14 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
加载脚本代码如下:
1 #!/bin/sh
2
3 module="chardev"
4 device="kf701_chardev"
5 mode=666
6
7 echo "insmod now"
8 /sbin/insmod ./$module.ko || exit 1
9
10 rm -f /dev/${device}0
11
12 major=$(awk "{ if(\$2 == \"${device}\") print \$1;}" /proc/devices)
13
14 echo "mknod now"
15 mknod /dev/${device}0 c $major 0
16
17 group="staff"
18 grep -q '^staff:' /etc/group || group="wheel"
19
20 echo "chgrp now"
21 chgrp $group /dev/${device}0
22 chmod $mode /dev/${device}0
23
下面是读测试方法:
$> cat /dev/kf701_chardev0
写测试如下命令:
$> echo "only for test" > /dev/kf701_chardev0
相关阅读 更多 +