linux 字符设备驱动
这是一个简单的字符驱动程序,有open, close, read, write 功能,还有 ioctl() 功能
0. 准备
新建 /opt/driver/char2文件夹,在里面创建4个文件: char2.c, test_char2.c, driver_ioctl.h, Makefile
1. char2.c
#include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/string.h> #include <asm/uaccess.h> #include "driver_ioctl.h" MODULE_LICENSE("GPL"); static char ker_buf[100]; static int a; static int dev_open(struct inode* inode, struct file* filep); static ssize_t dev_read(struct file *filep, char *buf, size_t len, loff_t *off); static ssize_t dev_write(struct file* filep, const char *buff, size_t len, loff_t *off); static int dev_release(struct inode* inode, struct file* filep); static long my_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); static struct file_operations fops = { .read = dev_read, .write = dev_write, .open = dev_open, .release = dev_release, .unlocked_ioctl = my_ioctl, }; static int char2_init(void) { int t = register_chrdev(91, "mydev2", &fops); if(t < 0) { printk(KERN_ALERT "2.=> DEVICE REGISTRATION FAILED.\n"); } else { printk(KERN_ALERT "2.=> DEVICE REGISTERED\n"); } return 0; } static void char2_exit(void) { unregister_chrdev(91, "mydev2"); printk(KERN_ALERT "2.=> EXITED.\n"); } static int dev_open(struct inode* inode, struct file* filep) { printk(KERN_ALERT "2.=> DEVICE OPENED\n"); return 0; } static ssize_t dev_read(struct file* filep, char *buf, size_t len, loff_t *off) { copy_to_user(buf, ker_buf, len); return len; } static ssize_t dev_write(struct file* filep, const char *buf, size_t len, loff_t *off) { copy_from_user(ker_buf, buf, len); ker_buf[len] = 0; return len; } static int dev_release(struct inode *inode, struct file *filep) { printk(KERN_ALERT "2.=> DEVICE CLOSED.\n"); return 0; } static long my_ioctl(struct file* filep, unsigned int cmd, unsigned long arg) { switch(cmd) { case QUERY_GET_VALUE: copy_to_user((int*)arg, &a, sizeof(int)); break; case QUERY_SET_VALUE: copy_from_user(&a, (int*)arg, sizeof(int)); break; case QUERY_CLEAR_VALUE: break; } return 0; } module_init(char2_init); module_exit(char2_exit);
2. driver_ioctl.h
#include <linux/ioctl.h> #define QUERY_GET_VALUE _IOR('q', 1, int *) #define QUERY_CLEAR_VALUE _IO('q', 2) #define QUERY_SET_VALUE _IOW('q', 3, int*)
3. Makefile
obj-m := char2.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules # make -C /usr/src/kernels/2.6.32-431.el6.i686 M=`pwd` modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
4. test_char2.c
#include <stdio.h> #include <fcntl.h> #include <assert.h> #include <string.h> #include <sys/ioctl.h> #include "driver_ioctl.h" // compile: gcc -o test_char2 test_char2.c int main() { char buf[100] = "hello"; char rbuf[7] = {0}; int a = 10; int fd; fd = open("/dev/mydev2", O_RDWR); // test read, write write(fd, buf, strlen(buf)); printf("writing into device\n"); read(fd, rbuf, 6); printf("read: %s\n", rbuf); // test ioctl ioctl(fd, QUERY_SET_VALUE, &a); printf("value written is: %d\n", a); a = 0; printf("let's read value from device\n"); ioctl(fd, QUERY_GET_VALUE, &a); printf("value of a is: %d\n", a); return 0; }
5. 编译
编译 .ko: # make 编译测试程序 test_char2.c : # gcc -o test_char2 test_char2.c
6. 创建字符设备文件
# mknod /dev/mydev2 c 91 1 # chmod a+w /dev/mydev2 mkdod创建设备文件, c 表示字符设备,91是主设备号, 1是次设备号 chmod为设备文件添加写权限, 否则不能向设备写数据。
7. 测试结果:
向内核插入模块: # insmod char2.ko # dmesg # cat /proc/devices ... 91 mydev2 ... 测试设备驱动: [root@centos6 char2]# ./test_char2 writing into device read: hello value written is: 10 let's read value from device value of a is: 10