我们都知道在linux里面存在块设备与字符设备。我们这里是设计的字符驱动,在不久,我会加入支持阻塞的功能。
我们可以通过查看cat /proc/device查看已注册的设备
[lzz@localhost device_character]$ cat /proc/devices Character devices: 1 mem 4 /dev/vc/0 4 tty 4 ttyS 5 /dev/tty 5 /dev/console 5 /dev/ptmx 7 vcs 10 misc 13 input 14 sound 21 sg 29 fb 99 ppdev 116 alsa 128 ptm 136 pts 162 raw 180 usb 188 ttyUSB 189 usb_device 202 cpu/msr 203 cpu/cpuid 226 drm 250 hidraw 251 usbmon 252 bsg 253 watchdog 254 rtc Block devices: 259 blkext 8 sd 9 md 11 sr 65 sd 66 sd 67 sd 68 sd 69 sd 70 sd 71 sd 128 sd 129 sd 130 sd 131 sd 132 sd 133 sd 134 sd 135 sd 253 device-mapper 254 mdp
我们选取一个231作为我们字符设备号,别的不废话,上代码.
字符设备驱动程序:
#include <linux/kernel.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/mm.h> #include <linux/vmalloc.h> #include <linux/slab.h> #include <asm/io.h> #include <linux/mman.h> #include <linux/uaccess.h> MODULE_AUTHOR("lzz"); MODULE_LICENSE("GPL"); #define MYCDEV_MAJOR 231 /*the predefined mycdev's major devno*/ #define MYCDEV_SIZE 100 static char kernel_buf[MYCDEV_SIZE]; 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; 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; } printk("lzz'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) { unsigned long p = *pos; unsigned int count = size; int ret =0; if(copy_from_user(kernel_buf+p,buf,count)) ret = -EFAULT; else { *pos+=count; ret = count; printk("lzz's write: %d bytes was wroten...\n", count); } return ret; } /*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,"lzz_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,"lzz_cdev"); } module_init(mycdev_init); module_exit(mycdev_exit);
Makefile文件:
obj-m:= map_driver.o CURRENT_PATH:=$(shell pwd) LINUX_KERNEL:=$(shell uname -r) LINUX_KERNEL_PATH:=/lib/modules/$(LINUX_KERNEL)/build all: make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules clean: make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
用户态测试程序:
#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[100]="test lzz's cdev ok!"; char buff[100]; testdev = open("/dev/mycdev", O_RDWR); if (-1 == testdev) { printf("cannot open file.\n"); exit(1); } write(testdev,buf,sizeof(buf)-1); if ((ret = read(testdev, buff, sizeof(buff)-1)) < 0) { printf("read error!\n"); exit(1); } printf("%s\n", buff); close(testdev); return 0; }