使用Linux越来越多,千头万绪,冥冥之中走上这条路.........................
程序暂时是在ubuntu系统中测试的.
首先写驱动程序:
#include<linux/module.h> #include<linux/init.h> #include<linux/kernel.h> #include<linux/fs.h> #include<linux/miscdevice.h> #include<linux/uaccess.h> #define DEVICE_NAME "m_driver03" /* static struct file_operations dev_fops={ .owner = THIS_MODULE }; static struct miscdevice misc={ .minor=MISC_DYNAMIC_MINOR, .name=DEVICE_NAME, .fops=&dev_fops }; */ static unsigned char mem[10000]; static int written_count=0; static char read_flag='y'; /* static int m_driver03_init(void){ int ret; ret=misc_register(&misc); printk("m_driver03_init;\n"); return 0; } */ static ssize_t m_driver03_read(struct file *file,char __user *buf,size_t count,loff_t *ppos){ printk("read function entrance !\n"); unsigned char temp[4]; temp[0]=written_count>>24; temp[1]=written_count>>16; temp[2]=written_count>>8; temp[3]=written_count; if(read_flag=='n'){ copy_to_user(buf,(void*)temp,4); printk("read count : %d\t\n",(int)written_count); read_flag='y'; return count; }else{ return 0; } } static ssize_t m_driver03_write(struct file *file,const char __user *buf,size_t count,loff_t *ppos){ copy_from_user(mem,buf,count); read_flag='n'; printk("write function entrance !\n"); written_count=count; printk("written count : %d\n",(int)count); return count; } static struct file_operations dev_fops={ .owner=THIS_MODULE, .read=m_driver03_read, .write=m_driver03_write }; static struct miscdevice misc={ .minor=MISC_DYNAMIC_MINOR, .name=DEVICE_NAME, .fops=&dev_fops }; static __init int m_driver03_init(void){ int ret; ret=misc_register(&misc); printk("m_driver03_init;\n"); return 0; } static __exit void m_driver03_exit(void){ misc_deregister(&misc); printk("m_driver03_exit;\n"); } module_init(m_driver03_init); module_exit(m_driver03_exit); MODULE_AUTHOR("stephen"); MODULE_DESCRIPTION("show how to develop linux module!"); MODULE_ALIAS("using linux module!"); MODULE_LICENSE("GPL");
下面肢解上面各个部分:
<1> : 初始化时和退出时必须要的单元:
static __init int m_driver03_init(void){ int ret; ret=misc_register(&misc); printk("m_driver03_init;\n"); return 0; }
这一段初始化代码,只要编译后,在终端输入insmod module_name装载模块就会进行初始,其中:
ret=misc_register(&misc);
是向系统注册一个设备,misc是一个结构体变量名.
static struct miscdevice misc={ .minor=MISC_DYNAMIC_MINOR, .name=DEVICE_NAME, .fops=&dev_fops };
其中minor是动态分配一个次设备ID,
name是设备名,包括路径,格式="/dev/device_name"
fops是指向操作入口.
static struct file_operations dev_fops={ .owner=THIS_MODULE, .read=m_driver03_read, .write=m_driver03_write };
其中read指向m_driver03_read是读取时使用的函数;
write指向m_driver03_write是写入设备时使用的函数;
下面是卸载设备操作时会调用的:
static __exit void m_driver03_exit(void){ misc_deregister(&misc); printk("m_driver03_exit;\n"); }
反注册设备.
<2> : 具体读写操作如下:
另外附加信息:
#include<linux/module.h> #include<linux/init.h> #include<linux/kernel.h> #include<linux/fs.h> #include<linux/miscdevice.h> #include<linux/uaccess.h> #define DEVICE_NAME "m_driver03" /* static struct file_operations dev_fops={ .owner = THIS_MODULE }; static struct miscdevice misc={ .minor=MISC_DYNAMIC_MINOR, .name=DEVICE_NAME, .fops=&dev_fops }; */ static unsigned char mem[10000]; static int written_count=0; static char read_flag='y';
读设备:
static ssize_t m_driver03_read(struct file *file,char __user *buf,size_t count,loff_t *ppos){ printk("read function entrance !\n"); unsigned char temp[4]; temp[0]=written_count>>24; temp[1]=written_count>>16; temp[2]=written_count>>8; temp[3]=written_count; if(read_flag=='n'){ copy_to_user(buf,(void*)temp,4); printk("read count : %d\t\n",(int)written_count); read_flag='y'; return count; }else{ return 0; } }
上面对应读取操作,下面对应写入操作:
static ssize_t m_driver03_write(struct file *file,const char __user *buf,size_t count,loff_t *ppos){ copy_from_user(mem,buf,count); read_flag='n'; printk("write function entrance !\n"); written_count=count; printk("written count : %d\n",(int)count); return count; }
<3> 装在卸载模块:
module_init(m_driver03_init);
module_exit(m_driver03_exit);
<4> 模块信息:
MODULE_AUTHOR("stephen"); MODULE_DESCRIPTION("show how to develop linux module!"); MODULE_ALIAS("using linux module!"); MODULE_LICENSE("GPL");
可以用下面命令行显示出来:上面模块名实际将会生成m_driver03.ko
$ sudo modinfo m_driver03.ko
<5> 为了编译上面的模块,我写了一个shell脚本:
#!/bin/bash make -C /usr/src/linux-headers-3.8.0-29-generic M=/home/user/linux-driver/driver03 sudo insmod m_driver03.ko #sudo lsmod | grep m_driver03 sudo dmesg | grep m_driver03 | tail -n 2 #sudo echo 'I love you' > /dev/m_driver03 #sudo dmesg | grep driver03 | tail -n 2 sudo rmmod m_driver03
修改属性:
sudo chmod u+x build.sh
另外我又写了一个启动和查看基本信息的shell脚本:
#!/bin/bash sudo insmod m_driver03.ko sudo lsmod | grep m_driver03 sudo dmesg | grep m_driver03 | tail -n 2 ls -a /dev ls -l /dev #cat /proc/devices sudo modinfo m_driver03.ko
修改build_s.sh属性同上.
上面的已经测试过了,可以生成ko模块.
<6> : 测试上面的Linux驱动有两种方法,先第一种:
在测试之前,先修改一个驱动的属性:
sudo chmod 777 /dev/m_driver03
这里只是做测试用.
测试如下:
echo 'I like' > /dev/m_driver03
dmesg
<7> 第二种就是写一个程序来操作:
#include<stdio.h> #include<fcntl.h> #include<unistd.h> #include<stdlib.h> #include<string.h> int main(int argc,char *argv[]){ int testdev; unsigned char buf[4]; printf("driver test programm !\n"); testdev=open("/dev/m_driver03",O_RDWR); if(testdev==-1){ printf("can not open device! \n"); return 0; } if(argc>1){ write(testdev,argv[1],strlen(argv[1])); printf("string:%s\n",argv[1]); } read(testdev,buf,4); int n=0; n=((int)buf[0])<<24|((int)buf[1])<<16 | ((int)buf[2])<<8 | ((int)buf[3]); printf("word byte display:%d,%d,%d,%d\n",buf[0],buf[1],buf[2],buf[3]); printf("word count : %d\n",n); close(testdev); return 0; }
<8> : 测试如下:
user@ubuntu:~/linux-driver/driver03$ ./driver_test "hello linux" driver test programm ! string:hello linux word byte display:0,0,0,11 word count : 11
要看驱动那边的打印信息:
dmesg
这样写出来以后,就可以迅速开始更深的东西...