【原创】Linux应用程序完整调用自己写的字符设备驱动过程

Linux应用程序完整调用自己写的字符设备驱动过程
 
 
一、先写驱动程序hello.c
实现字符驱动的打开、关闭、读、写的函数框架,加载和卸载程序入口调用
 
通过dmesg来查看内核printk的打印
使用makefile来编写驱动,生成ko文件
 
lsmod查看驱动
insmod 加载驱动
rmmod卸载驱动
cat /proc/devices,查看主设备号使用情况,
在dev目录下创建hello设备节点
mknod /dev/hello c 200 0
 
//驱动hello.c代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

 

static struct file_operations chardev_fops;
#define CAHRDEV_MAJOR 200
#define CHARDEV_NAME "hello kernel!"
char writebuf[100];
char readbuf[100];

static struct file_operations chardev_fops;


static int chardev_open(struct inode *inode, struct file *file)
{
printk("chrdev_open!\r\n");
return 0;
}

static int chardev_close(struct inode *inode, struct file *filp)
{
printk("chrdev_release!\r\n");
return 0;
}

static ssize_t chardev_read(struct file *filp, __user char *buf,size_t
count,loff_t *ppos)
{
int ret = 0;
snprintf(readbuf,sizeof(readbuf),CHARDEV_NAME);
ret = copy_to_user(buf,readbuf,count);
if(ret == 0)
{
printk("chardev_read.\r\n");
}
return 0;
}

 

static ssize_t chardev_write(struct file *filp, const char __user *buf,size_t
count,loff_t *ppos)
{
int ret = 0;
ret = copy_from_user(writebuf,buf,count);
if(ret == 0)
{
printk("chrdev_write is : %s \r\n",&writebuf);
}

return 0;
}

static int hello_init(void)
{
int retvalue = 0;
/* 注册字符设备驱动 */
//cat /proc/devices,查看主设备号使用情况,
retvalue = register_chrdev(CAHRDEV_MAJOR, CHARDEV_NAME, &chardev_fops);
if(retvalue < 0)
{
/* 字符设备注册失败,自行处理 */
printk("hello_init fail.\r\n");

}
else
{
printk("hello world enter modules!!!\r\n");
}

return 0;
}

static void hello_exit(void)
{
/* 注销字符设备驱动 */
unregister_chrdev(CAHRDEV_MAJOR, CHARDEV_NAME);
printk("hello world exit modules!\r\n");
}

static struct file_operations chardev_fops={
.owner = THIS_MODULE,
.open = chardev_open,
.read = chardev_read,
.write = chardev_write,
.release= chardev_close,
};


module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("panda");

 
二、再写应用程序helloAPP.c
应用层调用打开、读、写、关闭字符底层驱动函数
查看创建的节点
ls /dev/hello -l
应用程序调用设备驱动节点
./helloAPP /dev/hello
 
//应用代码helloAPP.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

//argc:应用程序参数个数
//argv[]:具体参数内容,是字符串形式
int main(int argc,char *argv[])
{
int fd = 0;
int ret = 0;
char *filename;
char readbuf[100];
char writebuf[100] = "hello APP!!!";

filename = argv[1];

fd = open(filename,O_RDWR);
if(fd <0)
{
printf("can't open %s fail!\r\n",filename);
return -1;
}
else{
printf("open OK!\r\n");
}

ret = read(fd,readbuf,50);
if(ret <0)
{
printf("can't read %s fail!\r\n",filename);
}
else{
printf("read data is: %s \r\n",readbuf);
}

ret = write(fd,writebuf,50);
if(ret <0)
{
printf("can't write %s fail!\r\n",filename);
}
else{
printf("write OK!\r\n");
}

ret = close(fd);
if(ret <0)
{
printf("can't close %s fail!\r\n",filename);
}else
{
printf("close OK!\r\n");
}




printf("hello world!\n");

return 0;

}

 
三、最终打印内容
应用层调用打印:

 

 驱动层调用打印,输入dmesg打印printk内容

注意:
主设备号高12位,次设备号低20位,所以请注意Linux系统中主设备号范围为 0~4095,
 
man 1 命令查询
man 2 系统调用查询
man 3 库查询
man 2 open
 

posted @ 2020-11-18 01:13  _小百  阅读(441)  评论(0编辑  收藏  举报