linux设备驱动之字符设备
来源:互联网 发布:vb中dim是什么意思 编辑:程序博客网 时间:2024/05/29 09:31
/*
1. 如何写字符设备驱动,添加字符设备
// 1 手动添加字符设备,cat/proc/divices ==> major 获得主设备号
已知主次设备号添加设备 cd /dev; mknod name c major minor
2 自动添加设备节点udev
class_create();
device_create();
2. 如何写设备fops
1 参考宋宝华《linux设备驱动开发详解》第6章p149 globalmem的设备驱动
本程序用到了内核封装api,可简化fops的操作,其实是一样的程序
simple_read_from_buffer();
simple_write_to_buffer ();
注意:注意返回值,cnt读写个数
如果是0的话,会重复读写(cat echo 命令下),如果是自己的写app,可以自己操作
当然,如果你想测试一下,只需要在fops中,打印一个log,就可以了
3. 了解procfs,sysfs文件系统,学会操作相关文件系统节点
1 可以参考宋宝华第5章文件系统5.4.2,21章21.5 使用/proc
/proc 和 文件fops 有点相似
/sys 写法比较简单
注意 /sys /proc 注意返回值count, 如果是0的话,会重复读写(cat echo 命令下),如果是自己的写app,可以自己操作
4. 写完驱动如何添加到内核里
1 Kconfig,注意source path/Kconfig,不能写完,一扔
2 Makefile
3 配置config文件
copyright(c)
author lxf
date 20160908
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/printk.h>
#include <linux/err.h>
#include <linux/miscdevice.h>
#include <linux/sysfs.h>
#include "freg.h"
//#define FREG_DEV_T
#ifdef FREG_DEV_T
#define FREG_MAJOR 243
#define FREG_MINOR 0
static int freg_major = 0;
static int freg_minor = 0;
// 设备类型和设备变量
//static struct class* freg_class = NULL;
static struct fake_reg_dev* freg_dev = NULL;
//
static struct proc_dir_entry* freg_dir, *freg;
// 传统的设备文件操作方法
static int freg_open(struct inode* inode, struct file* filp);
static int freg_release(struct inode* inode, struct file* filp);
static ssize_t freg_read(struct file * filp, char __user * buf, size_t size, loff_t * ppos);
static ssize_t freg_write(struct file * filp, const char __user * buf, size_t size, loff_t * ppos);
static int freg_open(struct inode* inode, struct file* filp)
{
filp->private_data = freg_dev;
pr_info("lxf %s\n",__func__);
return 0;
}
static int freg_release(struct inode* inode, struct file* filp)
{
pr_info("lxf %s\n",__func__);
return 0;
}
static ssize_t freg_read(struct file * filp, char __user * buf, size_t size, loff_t * ppos)
{
int cnt =0;
char val[4]={0};
pr_info("lxf %s bf lock\n",__func__);
mutex_lock(&freg_dev->freg_mutex);
cnt = sprintf(val,"%d\n",freg_dev->val);
cnt = simple_read_from_buffer(buf, size, ppos, val, cnt);
mutex_unlock(&freg_dev->freg_mutex);
pr_info("lxf %s af lock\n",__func__);
return cnt;
}
static ssize_t freg_write(struct file * filp, const char __user * buf, size_t size, loff_t * ppos)
{
char mem[10];
int cnt;
pr_info("lxf %s\n",__func__);
mutex_lock(&freg_dev->freg_mutex);
/*
simple_write_to_buffer(mem, size_t available, loff_t *ppos,
const void __user *from, size_t count)
*/
cnt = simple_write_to_buffer(mem, size, ppos, buf, sizeof(freg_dev->val));
freg_dev->val = (int)simple_strtoul(mem, NULL, 10);
mutex_unlock(&freg_dev->freg_mutex);
return cnt;
}
// 传统的设备文件操作方法表
static struct file_operations freg_fops =
{
.owner = THIS_MODULE,
.open = freg_open,
.release = freg_release,
.read = freg_read,
.write = freg_write,
};
/*
节点操作
*/
ssize_t freg_proc_read(struct file *file, char __user * buf, size_t size, loff_t * ppos)
{
/*
int cnt=0;
char *page = NULL;
page = kzalloc(128, GFP_KERNEL);
if((0 == strlen(module_name)) && (0 == tp_ver_show) && (0 == strlen(tp_ver_show_str)))
cnt = sprintf(page, "no tp\n");
else
{
// xuke @ 20140811
cnt = sprintf(page, "[Vendor]%s,%s\n", (strlen(module_name) ? module_name : "Unknown"),
(strlen(tp_ver_show_str) ? tp_ver_show_str : "Unknown product"));
}
cnt = simple_read_from_buffer(buf, size, ppos, page, cnt);
// printk("%s, page=%s, cnt=%d\n", __func__, page, cnt);
kfree(page);
return cnt;
*/
int cnt =0;
char* page ;
page = kzalloc(128,GFP_KERNEL);
cnt = sprintf(page,"%d\n",freg_dev->val);
pr_info("lxf %d\n", freg_dev->val);
cnt = simple_read_from_buffer(buf, size, ppos, page, cnt);
kfree(page);
return cnt;
}
ssize_t freg_proc_write(struct file *file, const char __user * buf, size_t count, loff_t * ppos)
{
pr_info("lxf %s\n",__func__);
freg_dev->val = (int)simple_strtoul(buf, NULL, 10);
pr_info("lxf %d\n", freg_dev->val);
return count;
}
static struct file_operations proc_fops =
{
.owner = THIS_MODULE,
.read = freg_proc_read,
.write = freg_proc_write,
};
int freg_creat_proc(void)
{
freg_dir = proc_mkdir("freg_dir", NULL);
freg = proc_create_data("freg", 0666, freg_dir, &proc_fops, freg_dev);
if (!freg)
{
return -1;
}
return 0;
}
static struct kobject* freg_device; //sysfs kobject
//static DEVICE_ATTR(tp_info, 0444, msm_tp_module_id_show, NULL);
static ssize_t freg_sys_show(struct device *dev,
struct device_attribute * attr, char *buf)
{
pr_info("lxf %s\n",__func__);
return sprintf(buf,"%d\n",freg_dev->val);
}
ssize_t freg_sys_store (struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
pr_info("lxf %s\n",__func__);
freg_dev->val = (int)simple_strtoul(buf, NULL, 10);
return count;
}
static DEVICE_ATTR(freg_info, 0666, freg_sys_show, freg_sys_store);
static int freg_creat_sysfs(void)
{
int ret = 0;
freg_device = kobject_create_and_add("freg_sys",NULL);
if (!freg_device)
{
pr_info("lxf subsystem_register failed\n");
ret = -ENOMEM;
return ret;
}
ret = sysfs_create_file(freg_device, &dev_attr_freg_info.attr);
if (ret)
{
pr_info("lxf sysfs_create_file fail\n");
kobject_del(freg_device);
}
return 0;
}
static int __init freg_init(void)
{
int ret;
dev_t devno;
struct class *myclass;
//创建字符设备
#ifdef FREG_DEV_T
freg_major = FREG_MAJOR;
freg_minor = FREG_MAJOR;
#endif
devno = MKDEV(freg_major, freg_minor);
if (freg_major)
{
ret = register_chrdev_region(devno, 1, "freg_cdev");
if (ret)
{
printk(KERN_INFO "lxf register_chrdev_region fail\n");
return ret;
}
}
else
{
ret = alloc_chrdev_region(&devno, 0, 1, "freg_cdev");
if (ret)
{
printk(KERN_INFO "lxf alloc_chrdev_region fail\n");
return ret;
}
freg_major = MAJOR(devno);
freg_minor = MINOR(devno);
}
freg_dev = kzalloc(sizeof(struct fake_reg_dev), GFP_KERNEL);
if (IS_ERR_OR_NULL(freg_dev))
{
printk(KERN_INFO "lxf kzalloc fail\n");
ret = -ENOMEM;
goto fail_malloc;
}
cdev_init(&freg_dev->dev,&freg_fops);
freg_dev->dev.owner = THIS_MODULE;
//freg_dev->val = 521;
mutex_init(&freg_dev->freg_mutex);
// 添加字符设备
ret = cdev_add(&freg_dev->dev, devno, 1);
if (ret)
{
printk(KERN_INFO "lxf register_chrdev_region fail\n");
goto cdev_del;
}
//创建相关节点
myclass = class_create(THIS_MODULE, "freg_cdev_driver");
/*
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt, ...)
*/
device_create(myclass, NULL, devno, NULL,"freg_cdev");
freg_creat_proc();
freg_creat_sysfs();
pr_info("lxf freg_init sucessfully\n");
return ret;
fail_malloc:
unregister_chrdev_region(devno, 1);
return ret;
}
static void __exit freg_exit(void)
{
//注销设备
cdev_del(&freg_dev->dev);
kfree(freg_dev);
unregister_chrdev_region(freg_dev->dev.dev, 1);
//删除节点
remove_proc_entry("freg", freg_dir);
remove_proc_entry("freg_dir", NULL);
sysfs_remove_file(freg_device, &dev_attr_freg_info.attr);
kobject_del(freg_device);
}
module_init(freg_init);
module_exit(freg_exit);
MODULE_AUTHOR("lxf");
MODULE_DESCRIPTION("this driver just for test");
MODULE_LICENSE("GPL v2");
1. 如何写字符设备驱动,添加字符设备
// 1 手动添加字符设备,cat/proc/divices ==> major 获得主设备号
已知主次设备号添加设备 cd /dev; mknod name c major minor
2 自动添加设备节点udev
class_create();
device_create();
2. 如何写设备fops
1 参考宋宝华《linux设备驱动开发详解》第6章p149 globalmem的设备驱动
本程序用到了内核封装api,可简化fops的操作,其实是一样的程序
simple_read_from_buffer();
simple_write_to_buffer ();
注意:注意返回值,cnt读写个数
如果是0的话,会重复读写(cat echo 命令下),如果是自己的写app,可以自己操作
当然,如果你想测试一下,只需要在fops中,打印一个log,就可以了
3. 了解procfs,sysfs文件系统,学会操作相关文件系统节点
1 可以参考宋宝华第5章文件系统5.4.2,21章21.5 使用/proc
/proc 和 文件fops 有点相似
/sys 写法比较简单
注意 /sys /proc 注意返回值count, 如果是0的话,会重复读写(cat echo 命令下),如果是自己的写app,可以自己操作
4. 写完驱动如何添加到内核里
1 Kconfig,注意source path/Kconfig,不能写完,一扔
2 Makefile
3 配置config文件
copyright(c)
author lxf
date 20160908
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/printk.h>
#include <linux/err.h>
#include <linux/miscdevice.h>
#include <linux/sysfs.h>
#include "freg.h"
//#define FREG_DEV_T
#ifdef FREG_DEV_T
#define FREG_MAJOR 243
#define FREG_MINOR 0
#endif
static int freg_major = 0;
static int freg_minor = 0;
// 设备类型和设备变量
//static struct class* freg_class = NULL;
static struct fake_reg_dev* freg_dev = NULL;
//
static struct proc_dir_entry* freg_dir, *freg;
// 传统的设备文件操作方法
static int freg_open(struct inode* inode, struct file* filp);
static int freg_release(struct inode* inode, struct file* filp);
static ssize_t freg_read(struct file * filp, char __user * buf, size_t size, loff_t * ppos);
static ssize_t freg_write(struct file * filp, const char __user * buf, size_t size, loff_t * ppos);
static int freg_open(struct inode* inode, struct file* filp)
{
filp->private_data = freg_dev;
pr_info("lxf %s\n",__func__);
return 0;
}
static int freg_release(struct inode* inode, struct file* filp)
{
pr_info("lxf %s\n",__func__);
return 0;
}
static ssize_t freg_read(struct file * filp, char __user * buf, size_t size, loff_t * ppos)
{
int cnt =0;
char val[4]={0};
pr_info("lxf %s bf lock\n",__func__);
mutex_lock(&freg_dev->freg_mutex);
cnt = sprintf(val,"%d\n",freg_dev->val);
cnt = simple_read_from_buffer(buf, size, ppos, val, cnt);
mutex_unlock(&freg_dev->freg_mutex);
pr_info("lxf %s af lock\n",__func__);
return cnt;
}
static ssize_t freg_write(struct file * filp, const char __user * buf, size_t size, loff_t * ppos)
{
char mem[10];
int cnt;
pr_info("lxf %s\n",__func__);
mutex_lock(&freg_dev->freg_mutex);
/*
simple_write_to_buffer(mem, size_t available, loff_t *ppos,
const void __user *from, size_t count)
*/
cnt = simple_write_to_buffer(mem, size, ppos, buf, sizeof(freg_dev->val));
freg_dev->val = (int)simple_strtoul(mem, NULL, 10);
mutex_unlock(&freg_dev->freg_mutex);
return cnt;
}
// 传统的设备文件操作方法表
static struct file_operations freg_fops =
{
.owner = THIS_MODULE,
.open = freg_open,
.release = freg_release,
.read = freg_read,
.write = freg_write,
};
/*
节点操作
*/
ssize_t freg_proc_read(struct file *file, char __user * buf, size_t size, loff_t * ppos)
{
/*
int cnt=0;
char *page = NULL;
page = kzalloc(128, GFP_KERNEL);
if((0 == strlen(module_name)) && (0 == tp_ver_show) && (0 == strlen(tp_ver_show_str)))
cnt = sprintf(page, "no tp\n");
else
{
// xuke @ 20140811
cnt = sprintf(page, "[Vendor]%s,%s\n", (strlen(module_name) ? module_name : "Unknown"),
(strlen(tp_ver_show_str) ? tp_ver_show_str : "Unknown product"));
}
cnt = simple_read_from_buffer(buf, size, ppos, page, cnt);
// printk("%s, page=%s, cnt=%d\n", __func__, page, cnt);
kfree(page);
return cnt;
*/
int cnt =0;
char* page ;
page = kzalloc(128,GFP_KERNEL);
cnt = sprintf(page,"%d\n",freg_dev->val);
pr_info("lxf %d\n", freg_dev->val);
cnt = simple_read_from_buffer(buf, size, ppos, page, cnt);
kfree(page);
return cnt;
}
ssize_t freg_proc_write(struct file *file, const char __user * buf, size_t count, loff_t * ppos)
{
pr_info("lxf %s\n",__func__);
freg_dev->val = (int)simple_strtoul(buf, NULL, 10);
pr_info("lxf %d\n", freg_dev->val);
return count;
}
static struct file_operations proc_fops =
{
.owner = THIS_MODULE,
.read = freg_proc_read,
.write = freg_proc_write,
};
int freg_creat_proc(void)
{
freg_dir = proc_mkdir("freg_dir", NULL);
freg = proc_create_data("freg", 0666, freg_dir, &proc_fops, freg_dev);
if (!freg)
{
return -1;
}
return 0;
}
static struct kobject* freg_device; //sysfs kobject
//static DEVICE_ATTR(tp_info, 0444, msm_tp_module_id_show, NULL);
static ssize_t freg_sys_show(struct device *dev,
struct device_attribute * attr, char *buf)
{
pr_info("lxf %s\n",__func__);
return sprintf(buf,"%d\n",freg_dev->val);
}
ssize_t freg_sys_store (struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
pr_info("lxf %s\n",__func__);
freg_dev->val = (int)simple_strtoul(buf, NULL, 10);
return count;
}
static DEVICE_ATTR(freg_info, 0666, freg_sys_show, freg_sys_store);
static int freg_creat_sysfs(void)
{
int ret = 0;
freg_device = kobject_create_and_add("freg_sys",NULL);
if (!freg_device)
{
pr_info("lxf subsystem_register failed\n");
ret = -ENOMEM;
return ret;
}
ret = sysfs_create_file(freg_device, &dev_attr_freg_info.attr);
if (ret)
{
pr_info("lxf sysfs_create_file fail\n");
kobject_del(freg_device);
}
return 0;
}
static int __init freg_init(void)
{
int ret;
dev_t devno;
struct class *myclass;
//创建字符设备
#ifdef FREG_DEV_T
freg_major = FREG_MAJOR;
freg_minor = FREG_MAJOR;
#endif
devno = MKDEV(freg_major, freg_minor);
if (freg_major)
{
ret = register_chrdev_region(devno, 1, "freg_cdev");
if (ret)
{
printk(KERN_INFO "lxf register_chrdev_region fail\n");
return ret;
}
}
else
{
ret = alloc_chrdev_region(&devno, 0, 1, "freg_cdev");
if (ret)
{
printk(KERN_INFO "lxf alloc_chrdev_region fail\n");
return ret;
}
freg_major = MAJOR(devno);
freg_minor = MINOR(devno);
}
freg_dev = kzalloc(sizeof(struct fake_reg_dev), GFP_KERNEL);
if (IS_ERR_OR_NULL(freg_dev))
{
printk(KERN_INFO "lxf kzalloc fail\n");
ret = -ENOMEM;
goto fail_malloc;
}
cdev_init(&freg_dev->dev,&freg_fops);
freg_dev->dev.owner = THIS_MODULE;
//freg_dev->val = 521;
mutex_init(&freg_dev->freg_mutex);
// 添加字符设备
ret = cdev_add(&freg_dev->dev, devno, 1);
if (ret)
{
printk(KERN_INFO "lxf register_chrdev_region fail\n");
goto cdev_del;
}
//创建相关节点
myclass = class_create(THIS_MODULE, "freg_cdev_driver");
/*
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt, ...)
*/
device_create(myclass, NULL, devno, NULL,"freg_cdev");
freg_creat_proc();
freg_creat_sysfs();
pr_info("lxf freg_init sucessfully\n");
return ret;
cdev_del:
cdev_del(&freg_dev->dev);fail_malloc:
unregister_chrdev_region(devno, 1);
return ret;
}
static void __exit freg_exit(void)
{
//注销设备
cdev_del(&freg_dev->dev);
kfree(freg_dev);
unregister_chrdev_region(freg_dev->dev.dev, 1);
//删除节点
remove_proc_entry("freg", freg_dir);
remove_proc_entry("freg_dir", NULL);
sysfs_remove_file(freg_device, &dev_attr_freg_info.attr);
kobject_del(freg_device);
}
module_init(freg_init);
module_exit(freg_exit);
MODULE_AUTHOR("lxf");
MODULE_DESCRIPTION("this driver just for test");
MODULE_LICENSE("GPL v2");
1 0
- Linux设备驱动之《字符设备驱动》
- Linux设备驱动之字符设备驱动
- Linux设备驱动之字符设备驱动
- Linux设备驱动之字符设备驱动
- Linux设备驱动之字符设备驱动
- Linux设备驱动之字符设备驱动
- linux设备驱动之字符设备驱动
- Linux 设备驱动之字符设备(一)
- 初识Linux设备驱动之字符设备
- Linux 设备驱动之字符设备(一)
- Linux 设备驱动之字符设备(二)
- Linux 设备驱动之字符设备(三)
- linux设备驱动之字符设备
- Linux 设备驱动之字符设备(一)
- Linux 设备驱动之字符设备(二)
- Linux 设备驱动之字符设备(三)
- linux 设备驱动之字符设备
- Linux设备驱动之字符设备
- mapreduce操作hbase多个输入表
- region的拆分策略
- Hbase的简单原理
- Hbase基本概念
- 两个大数(包括负数)相加
- linux设备驱动之字符设备
- codeforces665e Beautiful Subarrays(trie)
- Chrome浏览器快捷键大全
- 百度2017年暑假实习生编程题目(第三题)---3、进程调度算法 短作业优先(SJF, Shortest Job First)又称为“短进程优先
- Milking Cows(USACO)
- 如何系统学习数据分析?
- android开发环境安装-Eclipse篇
- 手机访问 电脑虚拟机的服务器
- notifyDataSetChanged