驱动实现过程(使用应用程序调用驱动 方便测试:
在用户空间的应用程序调用某一个函数实现操作驱动中的设备———用户空间调用的API函数属于C库的一部分。这个应用程序的函数在驱动中的表现为操作函数
驱动加载成功后在 /dev 下生成文件
----------------------------------------------------------------
/* 驱动入口函数 红色可改 */
static int __init chrdevbase_init(void)
{
/* 入口函数具体内容 */
int ret = 0;
/*注册字符设备*/
ret = register_chrdev(CHRDEVBASE_MAJOR,CHRDEVBASE_NAME, &chrdevbase_fops);
if(ret < 0)
{
printk("chrdevbase init failed!\r\n");
}
else
{
printk("chrdevbase init !\r\n");
}
return 0;
}
/* 驱动出口函数 */
static void __exit chrdevbase_exit(void)
{
printk("chrdevbase exit!\r\n");
/* 出口函数具体内容 */
/*注销字符设备*/
unregister_chrdev(CHRDEVBASE_MAJOR,CHRDEVBASE_NAME);
}
/*模块入口*/
module_init(chrdevbase_init);//用此函数声明上述两个函数为驱动入口函数
/*模块出口*/
module_exit(chrdevbase_exit);
MODULE_LICENSE("GPL");
-----------------------------------------------------------------------------此时编译make 有.ko(模块)文件生成
第一次得用 :depmod
加载此模块——》 modprobe xxx.ko
卸载:rmmod xxx.ko
________________________________________________________
字符设备驱动:加载后需要注册
每个设备都有个设备号:设备号(32位)=主设备号:次设备号(高12 低20)
#define CHRDEVBASE_MAJOR 200 /* 主设备号 */
//cat /proc/device 查看的当前使用的设备号 选择没有使用的
#define CHRDEVBASE_NAME "chrdevbase" /* 设备名 */ 自己取
static struct file_operations chrdevbase_fops={
.owner = THIS_MODULE,
.open = chrdevbase_open,
.release = chrdevbase_release,
.read = chrdevbase_read,
.write = chrdevbase_write,
//此部分就是实现与应用函数的函数调用的部分
};/*定义内核操作函数结构体*/
ret = register_chrdev(CHRDEVBASE_MAJOR,CHRDEVBASE_NAME, &chrdevbase_fops);
——————————————————————————————————————
操作函数的具体实现(套用框架)
static int chrdevbase_open(struct inode *inode, struct file *filp)
{
//printk("chrdevbase open!\r\n");
return 0;
}
static int chrdevbase_release(struct inode *inode, struct file *filp)
{
//printk("chrdevbase release!\r\n");
return 0;
}
//用户在应用程序中读取程序
static char readbuf[100];/*读缓冲*/
static char writebuf[100];/*写缓冲*/
static char kerneldate[] = {"kernel date!"};//在驱动中的字符数据 读到应用程序中
/dev/设备名
static ssize_t chrdevbase_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
// 打开的设备文件 传给应用程序(用户空间的)缓冲区 读文件的大小 相对文件首地址的偏移
int ret = 0 ;
//printk("chrdevbase read!\r\n");
memcpy(readbuf,kerneldate,sizeof(kerneldate));// kerneldate内存拷贝到readbuf
//将驱动中的数据放入缓冲区
//把中间的拷贝到第一个 读数据的大小由应用程序决定
ret = copy_to_user(buf ,readbuf,count);//目的,来源:数量 #include <linux/uaccess.h>
if (ret == 0)
{
/*拷贝成功*/
}
else
{
}
return 0;
}
//将应用程序写到驱动中
// 设备 应用程序中的数据 数据长度 偏移
static ssize_t chrdevbase_write(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
//printk("chrdevbase write!\r\n");
int ret = 0;
//接收应用程序中的数据
//把中间的拷贝到第一个 写数据的大小由应用程序决定
ret = copy_from_user(writebuf,buf,count);
if (ret == 0)
{
/* 写成功*/
printk("kernel date = %s \r\n",writebuf);
}
else
{
}
return 0;
}
————————————————————————————————————
在串口调试界面输入:
. /chrdevbaseAPP /dev/chrdevbase 2 表示从驱动里面写数据
./chrdevbaseAPP /dev/chrdevbase 1 表示从驱动里面读数据
int main(int argc,char *argv[])
{
argc:应用程序参数个数 argv[]具体发参数内容 字符串形式 字符串数组
argv[0]=./chrdevbaseAPP
argv[1]=/dev/chrdevbase
argv[2]=1/2
}
filename = argv[1]; //为操作的文件名
/*open*/ 要打开的设备名 文件打开方式
fd = open(filename,O_RDWR);
/*读命令 读驱动中的数据*/
char readbuf[100], writebuf[100];
static char usrdate[] = {"usr date!"};
if(atoi(argv[2]) == 1) //字符串的1 转换成数字1
ret = read(fd, readbuf,50);//50个字节
/*写命令 将应用程序中的数据写到驱动中*/
if(atoi(argv[2]) == 2)
memcpy(writebuf,usrdate,sizeof(usrdate));//头文件#include <string.h>
ret = write(fd, writebuf,50);//50个字节
/*close*/
ret = close(fd);
————————————————————————————
创建设备节点/dev/设备
应用程序通过设备节点实现与驱动的交互
Cat/proc/devices 查看设备名和设备号
mknod /dev/设备名 c 主设备号 次设备号