闲话少说,理论不讲,直接拷贝源码即可运行。
首先是device文件:mycdev.c
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/fs.h>
- #include <asm/uaccess.h>
- #include <linux/cdev.h>
- MODULE_AUTHOR("Boatman Yang");
- MODULE_LICENSE("GPL");
- #define MYCDEV_MAJOR 231 /*the predefined mycdev's major devno*/
- #define MYCDEV_SIZE 100
- static int mycdev_open(struct inode *inode, struct file *fp)
- {
- return 0;
- }
- static int mycdev_release(struct inode *inode, struct file *fp)
- {
- return 0;
- }
- static ssize_t mycdev_read(struct file *fp, char __user *buf, size_t size, loff_t *pos)
- {
- unsigned long p = *pos;
- unsigned int count = size;
- int i;
- char kernel_buf[MYCDEV_SIZE] = "This is mycdev from Boatman!";
- if(p >= MYCDEV_SIZE)
- return -1;
- if(count > MYCDEV_SIZE)
- count = MYCDEV_SIZE - p;
- if (copy_to_user(buf, kernel_buf, count) != 0) {
- printk("read error!\n");
- return -1;
- }
- /*
- for (i = 0; i < count; i++) {
- __put_user(i, buf);//write 'i' from kernel space to user space's buf;
- buf++;
- }
- */
- printk("boatman's reader: %d bytes was read...\n", count);
- return count;
- }
- static ssize_t mycdev_write(struct file *fp, const char __user *buf, size_t size, loff_t *pos)
- {
- return size;
- }
- /*filling the mycdev's file operation interface in the struct file_operations*/
- static const struct file_operations mycdev_fops =
- {
- .owner = THIS_MODULE,
- .read = mycdev_read,
- .write = mycdev_write,
- .open = mycdev_open,
- .release = mycdev_release,
- };
- /*module loading function*/
- static int __init mycdev_init(void)
- {
- int ret;
- printk("mycdev module is staring..\n");
- ret=register_chrdev(MYCDEV_MAJOR,"boatman_cdev",&mycdev_fops);
- if(ret<0)
- {
- printk("register failed..\n");
- return 0;
- }
- else
- {
- printk("register success..\n");
- }
- return 0;
- }
- /*module unloading function*/
- static void __exit mycdev_exit(void)
- {
- printk("mycdev module is leaving..\n");
- unregister_chrdev(MYCDEV_MAJOR,"boatman_cdev");
- }
- module_init(mycdev_init);
- module_exit(mycdev_exit);
然后是它的Makefile文件,如下:
- obj-m:=mycdev.o
- PWD:=$(shell pwd)
- CUR_PATH:=$(shell uname -r)
- KERNEL_PATH:=/usr/src/linux-headers-$(CUR_PATH)
- all:
- make -C $(KERNEL_PATH) M=$(PWD) modules
- clean:
- make -C $(KERNEL_PATH) M=$(PWD) clean
第三个测试程序,mycdev_test.c
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <stdlib.h>
- int main()
- {
- int testdev;
- int i, ret;
- char buf[15];
- testdev = open("/dev/mycdev", O_RDWR);
- if (-1 == testdev) {
- printf("cannot open file.\n");
- exit(1);
- }
- if (ret = read(testdev, buf, 15) < 15) {
- printf("read error!\n");
- exit(1);
- }
- printf("%s\n", buf);
- close(testdev);
- return 0;
- }
测试步骤:
1. 运行“make”来编译mycdev.c,会生成mycdev.ko
2. 将生成的驱动文件插入到内核:sudo insmod mycdev.ko
3. 通过cat /proc/devices 查看系统中未使用的字符设备主设备号,比如当前231未使用;
4. 创建设备文件结点:sudo mknod /dev/mycdev c 231 0;具体使用方法通过man mknod命令查看;
5. 修改设备文件权限:sudo chmod 777 /dev/mycdev;
以上成功完成后,编译本用户态测试程序;运行该程序查看结果(如有必要可以通过dmesg查看日志信息);