编写好驱动,通过挂载的方法将驱动程序挂载到内核里面,大致步骤如下:
一: 1>建立以.c为后缀的c语言程序文件 (里面包含了设备名及设备号等)
2>建立Makefile文件(作用是通过make来产生设备文件*.ko文件,里面可以建立自己的平台所需的设备文件如:arm等).make 产生相应的设备文件
二: 要在/dev下建立相应的设备结点(设备名),用insomd *.ko命令将相应的驱动设备文件挂载到内核中.
三:编写测试文件(.c文件)用来测试内核是否已近成功挂载到内核.(编写好相应的测试文件后,用gcc –o Filename Filename.c(测试文件名) 来产生相应的可执行文件).
四:如果设备驱动挂载成功,当执行测试文件(./Filename)时会产生相应的结果.
五:可能用到的相关命令:
1. lsmod:列出内核已经载入模块的专题.
输出:
Module(模块名) size(大小) used by (被..使用)
2. demop:分析可加载模块的依赖性,生成modules.dep文件和映射文件
3. uname –r 显示内核版本(在编写Makefile时使用到)
4. modprobe : linux 内核添加和删除模块(相关参数请查看man帮助文档)
5. modinfo:显示内核模块的信息.
6. insmod: 向linux内核中加载一个模块,用法:insmod [filename] [module options…]
7. rmmod: 删除内核中的模块, 用法: rmmod [-f,w,s,v] [modulename]
8. dmesg: 显示内核缓冲区,内核的各种信息,内核启动时的信息会写入到/var/log/下.
六.例子
第一步:增加头文件和宏定义
1#include <linux/fs.h> 2#include <linux/types.h> 3#include <linux/cdev.h> 4#include <linux/uaccess.h> 5#include <linux/module> 6#include <linux/kernel>
第二步:添加与字符设备定义及注册有关的数据成员
1//定义设备名称 2#define DEVICE_NAME "test" //设备名 3#define BUF_SIZE 1024 4static char tmpbuf[BUF_SIZE]; 5 6//定义主次设备号 7static unsigned int TestMajor=0; //主 8static unsigned int TestMinor=0; //次 9 10 11static struct cdev *test_cdev; 12static dev_t dev;
第三步:增加open/release函数
1static int test_chardev_open(struct inode *inode,struct file *file) 2{ 3 printk("open major=%d, minor=%d\n", imajor(inode), 4 iminor(inode)); 5 return 0; 6} 7 8static int test_chardev_release(struct inode *inode,struct file *file) 9{ 10 printk("close major=%d,minor=%d\n",imajor(inode), 11 iminor(inode)); 12 return 0; 13}
第四步:增加read函数
1static ssize_t test_chardev_read(struct file *file,char __user *buf, 2 size_t const count,loff_t *offset) 3{ 4 if(count < BUF_SIZE) 5 { 6 if(copy_to_user(buf,tmpbuf,count)) 7 { 8 printk("copy to user fail \n"); 9 return -EFAULT; 10 } 11 }else{ 12 printk("read size must be less than %d\n", BUF_SIZE); 13 return -EINVAL; 14 } 15 *offset += count; 16 return count; 17} 18
第五步:增加write函数
1static ssize_t test_chardev_write(struct file *file, const char __user *buf,size_t const count,loff_t *offset) 2{ 3 if(count < BUF_SIZE) 4 { 5 if(copy_from_user(tmpbuf,buf,count)) 6 { 7 printk("copy from user fail \n"); 8 return -EFAULT; 9 } 10 }else{ 11 12 printk("size must be less than %d\n", BUF_SIZE); 13 return -EINVAL; 14 } 15 *offset += count; 16 return count; 17}
第六步:添加增加file_operations 成员
1static struct file_operations chardev_fops={ 2 .owner = THIS_MODULE, 3 .read = test_chardev_read, 4 .write = test_chardev_write, 5 .open = test_chardev_open, 6 .release = test_chardev_release, 7};
第七步:在模块的入口添加设备的设备号获取及设备注册
1static int __init chrdev_init(void) 2{ 3 int result; 4 5 if(TestMajor) 6 { 7 dev=MKDEV(TestMajor,TestMinor);//创建设备编号 8 result=register_chrdev_region(dev,1,DEVICE_NAME); 9 } else { 10 result=alloc_chrdev_region(&dev,TestMinor,1,DEVICE_NAME); 11 TestMajor=MAJOR(dev); 12 } 13 if(result<0) 14 { 15 printk(KERN_WARNING"LED: cannot get major %d \n",TestMajor); 16 return result; 17 } 18 19 test_cdev=cdev_alloc(); 20 cdev_init(test_cdev,&chardev_fops); 21 //test_cdev->ops=&chardev_fops; 22 test_cdev->owner=THIS_MODULE; 23 result=cdev_add(test_cdev,dev,1); 24 if(result) 25 printk("<1>Error %d while register led device!\n",result); 26 27 return 0; 28}
第八步:在模块的出口函数增加设备设备号释放及设备注销函数
1 unregister_chrdev_region(MKDEV(TestMajor,TestMinor),1); 2 cdev_del(test_cdev);
第九步:编译并加载该模块
第十步:根据设备号的设置,在文件系统中建立对应的设备节点
$mknod /dev/test c XXX(主设备号) XX(次设备号)
完整例子
驱动文件
1#include <linux/init.h> 2#include <linux/module.h> 3#include <linux/cdev.h> 4#include <linux/fs.h> 5#include <linux/kernel.h> 6#include <linux/uaccess.h> 7 8#define DEVICENAME "ccccc" 9 10unsigned int major=221; 11unsigned int minor=0; 12struct cdev *abc; 13dev_t dev; 14static char bufrh[1024]="read success!"; 15 16static int aaaaa_open(struct inode *inodep, struct file *filep) 17{ 18 printk("read success!\n"); 19 return 0; 20} 21 22int aaaaa_release(struct inode *inodep, struct file *filep) 23{ 24 return 0; 25} 26static ssize_t aaaaa_read (struct file *filep, char __user *buf, size_t count, loff_t *offset) 27{ 28 if(copy_to_user(buf, bufrh, 1)) 29 { 30 printk("copy_to_user fail!\n"); 31 } 32 return 0; 33} 34 35ssize_t aaaaa_write (struct file *filep, const char __user *buf, size_t count, loff_t *offse) 36{ 37 printk("write!\n"); 38 return 0; 39} 40 41 42static const struct file_operations fops = { 43 .owner = THIS_MODULE, 44 .open = aaaaa_open, 45 .release = aaaaa_release, 46 .read = aaaaa_read, 47 .write = aaaaa_write, 48 49 50}; 51 52 53 54 55static int __init aaaaa_init(void) 56{ 57 int a; 58 dev=MKDEV(major, minor); 59 a=register_chrdev_region(dev, 1, DEVICENAME); 60 61 abc=cdev_alloc(); 62 abc->owner=THIS_MODULE; 63 cdev_init(abc, &fops); 64 65 cdev_add(abc, dev, 1); 66 67 68 return 0; 69} 70 71static void __exit aaaaa_cleanup(void) 72{ 73 cdev_del(abc); 74 unregister_chrdev_region(dev, 1); 75} 76 77module_init(aaaaa_init); 78module_exit(aaaaa_cleanup); 79MODULE_LICENSE("GPL ");
Makefile文件
1obj-m += firstqd.o(相应设备文件名) 2 3KERDIR = /usr/src/linux-headers-2.6.32-24-generic #x86平台 4PWD=$(shell pwd) 5 6modules: 7 $(MAKE) -C $(KERDIR) M=$(PWD) modules 8 9pc: 10 gcc -o fristqd firstqd.c 11arm: 12 arm-linux-gcc -o fristqd firstqd.c 13 14clean: 15 rm -rf *.o *~core *.depend *.cmd *.ko *.mod.c *.tmp_versions
用户空间测试代码
1#include <stdio.h> 2#include <sys/types.h> 3#include <fcntl.h> 4 5char buf[1024]; 6char bufw[1024]="write success"; 7int main() 8{ 9 int fd,m,n; 10 fd=open("/dev/aaa",O_RDWR); 11 if (fd) 12 { 13 m=read(fd,buf,100); 14 printf("read kernel:%s\n",buf); 15 16 n=write(fd,bufw,10); 17 } 18 //printf("ni hao"); 19 return 0; 20}