自动创建设备文件
来源:互联网 发布:mac 进入应用程序目录 编辑:程序博客网 时间:2024/04/28 02:26
- #define class_create(owner, name) \
- ({ \
- static struct lock_class_key __key; \
- __class_create(owner, name, &__key); \
- })
- static struct class *myclass;
- ...
- static int memdev_init(void)
- {
- ...
- /*如果定义了主设备号采用静态申请的方式*/
- if(mem_major)
- result = register_chrdev_region(devno,2,"mem_dev");
- else/*动态申请设备号*/
- {
- result = alloc_chrdev_region(&devno,0,2,"mem_dev");
- mem_major = MAJOR(result);
- }
- /*错误处理*/
- if(result < 0)
- return result;
- /*在设备号申请完成以后可以为设备创建一个设备类,用于设备文件的创建*/
- myclass = class_create(THIS_MODULE,"memdev_class");
- /*创建一个设备*/
- /*初始化cdev,并将相关的文件操作添加进来*/
- cdev_init(&cdev,&mem_fops);
- ...
- }
- struct device *device_create(struct class *class, struct device *parent,
- dev_t devt, void *drvdata, const char *fmt, ...)
- {
- va_list vargs;
- struct device *dev;
- va_start(vargs, fmt);
- dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
- va_end(vargs);
- return dev;
- }
- ...
- /*初始化cdev,并将相关的文件操作添加进来*/
- cdev_init(&cdev,&mem_fops);
- /*设备引用*/
- cdev.owner = THIS_MODULE;
- cdev.ops = &mem_fops;
- /*注册字符设备*/
- cdev_add(&cdev,MKDEV(mem_major,0),MEMDEV_NR_DEVS);
- /*以上设备添加完成*/
- /*分配两个内存空间,此处是在物理内存上实现分配,实质是创建两个设备的描述*/
- mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev),GFP_KERNEL);
- if(!mem_devp)/*出错的相应操作*/
- {
- result = -ENOMEM;
- /*错误处理,采用典型的goto语句*/
- goto fail_malloc;
- }
- /*清除空间*/
- memset(mem_devp,0,sizeof(struct mem_dev));
- for(i = 0; i < MEMDEV_NR_DEVS; ++i)
- {
- device_create(myclass,NULL,MKDEV(mem_major,i),NULL,"memdev%d",i);
- /*
- myclass为设备类
- NULL 表示父设备为空
- MKDEV(mem_major,i) 表示设备号
- NULL 表示设备数据为空
- 后面的参数是用来设置 设备文件的名字
- */
- mem_devp[i].size = MEMDEV_SIZE;
- /*对设备的数据空间分配空间*/
- mem_devp[i].data = kmalloc(MEMDEV_SIZE,GFP_KERNEL);
- /*问题,没有进行错误的控制*/
- memset(mem_devp[i].data,0,MEMDEV_SIZE);
- /*初始化定义的互信息量*/
- //mutex_init(&mem_devp[i].sem);
- //初始化定义的自旋锁ua
- spin_lock_init(&mem_devp[i].lock);
- }
- ...
- void device_destroy(struct class *class, dev_t devt)
- {
- struct device *dev;
- dev = class_find_device(class, NULL, &devt, __match_devt);
- if (dev) {
- put_device(dev);
- device_unregister(dev);
- }
- }
- void class_destroy(struct class *cls)
- {
- if ((cls == NULL) || (IS_ERR(cls)))
- return;
- class_unregister(cls);
- }
- /*模块清除函数*/
- static void memdev_exit(void)
- {
- cdev_del(&cdev);/*注销字符设备*/
- /*释放两个物理内存*/
- kfree(mem_devp[0].data);
- kfree(mem_devp[1].data);
- device_destroy(myclass,MKDEV(mem_major,0));
- device_destroy(myclass,MKDEV(mem_major,1));
- kfree(mem_devp);/*释放设备结构体内存*/
- class_destroy(myclass);
- unregister_chrdev_region(MKDEV(mem_major,0),2);
- }
下面以一个简单字符设备驱动来展示如何使用这几个函数
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/device.h>
#include "memdev.h"
static int mem_major = MEMDEV_MAJOR;
struct mem_dev *mem_devp; /*设备结构体指针*/
bool have_data = false; /*表明设备有足够数据可供读*/
struct cdev cdev;
struct class *myclass=NULL;
/*文件打开函数*/
int mem_open(struct inode *inode, struct file *filp)
{
struct mem_dev *dev;
/*获取次设备号*/
int num = MINOR(inode->i_rdev);
if (num >= MEMDEV_NR_DEVS)
return -ENODEV;
dev = &mem_devp[num];
/*将设备描述结构指针赋值给文件私有数据指针*/
filp->private_data = dev;
return 0;
}
/*文件释放函数*/
int mem_release(struct inode *inode, struct file *filp)
{
return 0;
}
/*读函数*/
static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/
/*判断读位置是否有效*/
if (p >= MEMDEV_SIZE)
return 0;
if (count > MEMDEV_SIZE - p)
count = MEMDEV_SIZE - p;
while (!have_data) /* 没有数据可读,考虑为什么不用if,而用while,中断信号唤醒 */
{
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
wait_event_interruptible(dev->inq,have_data);
}
/*读数据到用户空间*/
if (copy_to_user(buf, (void*)(dev->data + p), count))
{
ret = - EFAULT;
}
else
{
*ppos += count;
ret = count;
printk(KERN_INFO "read %d bytes(s) from %d\n", (int)count, (int)p);
}
have_data = false; /* 表明不再有数据可读 */
return ret;
}
/*写函数*/
static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/
/*分析和获取有效的写长度*/
if (p >= MEMDEV_SIZE)
return 0;
if (count > MEMDEV_SIZE - p)
count = MEMDEV_SIZE - p;
/*从用户空间写入数据*/
if (copy_from_user(dev->data + p, buf, count))
ret = - EFAULT;
else
{
*ppos += count;
ret = count;
printk(KERN_INFO "written %d bytes(s) from %d\n", (int)count, (int)p);
}
have_data = true; /* 有新的数据可读 */
/* 唤醒读进程 */
wake_up(&(dev->inq));
return ret;
}
/* seek文件定位函数 */
static loff_t mem_llseek(struct file *filp, loff_t offset, int whence)
{
loff_t newpos;
switch(whence) {
case 0: /* SEEK_SET */
newpos = offset;
break;
case 1: /* SEEK_CUR */
newpos = filp->f_pos + offset;
break;
case 2: /* SEEK_END */
newpos = MEMDEV_SIZE -1 + offset;
break;
default: /* can't happen */
return -EINVAL;
}
if ((newpos<0) || (newpos>MEMDEV_SIZE))
return -EINVAL;
filp->f_pos = newpos;
return newpos;
}
//static int mem_ioctl(struct inode * inode,struct file *flip,unsigned int cmd,
// unsigned long arg)
static int mem_ioctl(struct file *flip,unsigned int cmd,
unsigned long arg)
{
struct mem_dev *dev = flip->private_data; /*获得设备结构体指针*/
int err = 0;
int ret = 0;
int ioarg = 0;
/* 检测命令的有效性 */
if (_IOC_TYPE(cmd) != MEMDEV_IOC_MAGIC)
return -EINVAL;
if (_IOC_NR(cmd) > MEMDEV_IOC_MAXNR)
return -EINVAL;
/* 根据命令类型,检测参数空间是否可以访问 */
if (_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
else if (_IOC_DIR(cmd) & _IOC_WRITE)
err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
if (err)
return -EFAULT;
/* 根据命令,执行相应的操作 */
switch(cmd) {
/* 打印当前设备信息 */
case MEMDEV_IOCPRINT:
printk("<--- CMD MEMDEV_IOCPRINT Done--->\n\n");
break;
case MEMDEV_IOCMEMEST:
memset(dev->data, 0, MEMDEV_SIZE);
break;
/* 获取参数 */
case MEMDEV_IOCGETDATA:
ioarg = 1101;
ret = __put_user(ioarg, (int *)arg);
break;
/* 设置参数 */
case MEMDEV_IOCSETDATA:
ret = __get_user(ioarg, (int *)arg);
printk("<--- In Kernel MEMDEV_IOCSETDATA ioarg = %d --->\n\n",ioarg);
break;
default:
return -EINVAL;
}
return ret;
}
/*文件操作结构体*/
static const struct file_operations mem_fops =
{
.owner = THIS_MODULE,
.llseek = mem_llseek,
.read = mem_read,
.write = mem_write,
.open = mem_open,
.release = mem_release,
.unlocked_ioctl = mem_ioctl,
};
/*设备驱动模块加载函数*/
static int memdev_init(void)
{
int result;
int i;
dev_t devno = MKDEV(mem_major, 0);
if (mem_major)
result = register_chrdev_region(devno,2,"ZXJ");
else
{
result = alloc_chrdev_region(&devno,0,2,"ZXJ");
mem_major = MAJOR(devno);
}
if (result < 0)
return result;
/*
cdev_init(&cdev,&mem_fops);
cdev.owner = THIS_MODULE;
cdev.ops = &mem_fops;
cdev_add(&cdev,MKDEV(mem_major, 0),MEMDEV_NR_DEVS);
*/
/* 为设备描述结构分配内存*/
mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL);
if (!mem_devp) /*申请失败*/
{
result = - ENOMEM;
goto fail_malloc;
}
/* 清零存储器 */
memset(mem_devp, 0, sizeof(struct mem_dev) * MEMDEV_NR_DEVS);
/* 创建类/sys文件夹下面 */
myclass=class_create(THIS_MODULE,"test");
/*为设备分配内存*/
for (i=0; i < MEMDEV_NR_DEVS; i++)
{
mem_devp[i].size = MEMDEV_SIZE;
mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL);
if (!mem_devp[i].data)
printk("Bad Kmalloc\n");
memset(mem_devp[i].data, 0, MEMDEV_SIZE);
sprintf(mem_devp[i].name,"memdev%d",i);
cdev_init(&mem_devp[i].cdev,&mem_fops);
mem_devp[i].cdev.owner = THIS_MODULE;
result = cdev_add(&mem_devp[i].cdev,MKDEV(mem_major, i),1);
if (result)
{
printk("Bad cdev\n");
return result;
}
/* 初始化信号量 */
init_waitqueue_head(&(mem_devp[i].inq));
device_create(myclass,NULL,MKDEV(mem_major, i),NULL,"memdev%d",i);
}
return 0;
fail_malloc:
unregister_chrdev_region(devno, 1);
return result;
}
/*模块卸载函数*/
static void memdev_exit(void)
{
int i;
for (i=0; i < MEMDEV_NR_DEVS; i++)
{
device_destroy(myclass,MKDEV(mem_major, i));//删除设备文件
cdev_del(&mem_devp[i].cdev); /*注销设备*/
kfree(mem_devp[i].data); /*释放内存*/
}
class_destroy(myclass);
kfree(mem_devp); /*释放设备结构体内存*/
unregister_chrdev_region(MKDEV(mem_major, 0), 2); /*释放设备号*/
}
MODULE_AUTHOR("Smart.zhao");
MODULE_LICENSE("GPL");
module_init(memdev_init);
module_exit(memdev_exit);
当加载模块的时候,会在/dev/memdev0,/dev/memdev1两个设备文件,如图所示
- 自动创建设备文件
- 自动创建设备文件
- 自动创建设备文件
- 自动创建设备文件
- 自动创建设备文件
- 自动创建设备文件
- 自动创建设备文件
- 自动创建设备文件
- 自动创建设备文件节点
- 设备文件自动创建2
- linux设备驱动程序自动创建设备文件
- Linux 设备驱动--- 自动创建设备文件
- Linux 设备驱动--- 自动创建设备文件
- 自动在/dev/下创建设备文件
- class_create(),device_create自动创建设备文件结点
- class_create(),device_create自动创建设备文件结点
- class_create(),device_create自动创建设备文件结点
- class_create(),device_create自动创建设备文件结点
- 纳米线的新应用开发
- vimdiff折叠操作命令
- Android运行时异常“Binary XML file line # : Error inflating class”
- 别人博客
- 用C++和Windows的互斥对象(Mutex)来实现线程同步锁
- 自动创建设备文件
- 关于C#线程,线程池和并行运算的简单使用和对比
- ios 基础学习之零基础代码控制实现2
- Win32环境下两种用于C++的线程同步类
- 自己动手封装js工具类(JS中定义类的几种方式:混合的构造函数/原型方式,动态原型等)
- C#多线程:Interlocked类操作
- openssl安装说明
- 责任感和契约-你必须处理好面对的所有事
- C/C++ 多线程(MultiThread)编程及几种同步方式