字符设备 -----LDD3

水平有限,若有错误亦或者不当的地方,请大家不吝值出。谢谢~


字符设备创建流程

1、申请字符设备设备号

2、注册字符设备


一、字符设备主次设备号的申请

dev_t        --->linux/types.h

dev_t  设备号变量声明, 32 bit

bit31-20 主设备号

bit19- 0   次设备号


1、静态申请

         int register_chrdev_region(dev_tfirst, unsigned int count, char *name)

         first: 设备号的起始值(主设备号,起始次设备号)

         count:申请的次设备号个数

         name: 与设备号关联的设备名称,出现在/proc/devices

         返回值 : 0 : 成功   <0 :失败

 

2、动态申请

         int alloc_chrdev_region(dev_t*dev, unsigned intfirstminor, unsigned int count, char *neme)

         dev:输出值,起始设备号

         firstminor:起始次设备号

         count:次设备号个数

         name:与设备号关联的设备名称,出现在/proc/devices

         返回值 : 0 : 成功   <0 :失败

                           

3、释放设备号

         voidunregister_chrdev_region(dev_tfirst, unsigned int count)

         first: 起始设备号

         count:次设备号个数

 

二、字符设备注册

//字符设备结构体

struct cdev {                                          -----><linux/cdev.h>

structkobjectkobj;

struct module *owner;

conststructfile_operations *ops;             //文件操作

structlist_head list;

dev_tdev;

unsignedint count;

};


1、字符设备注册          

方法一:

//分配一个字符设备结构体

structcdev *my_cdev = cdev_alloc();      

 

//初始化字符设备结构体

my_cdev->ops = *my_fops;                        //关联file_operations             

my_cdev->ower = THIS_MODULE;

 

//添加设备及其关联设备号、到内核中

int cdev_add(structcdev *dev, dev_tnum;unsigned int count);

dev:字符设备结构体

num:字符设备起始设备号

count: 次设备号个数

返回值: 0 成功   <0:失败

 

方法二:

structcdevcdev;

 

cdev_init(&dev->cdev,&scull_fops); //关联字符设备及file_operation

dev->cdev.owner = THIS_MODULE;

 

int cdev_add(structcdev *dev, dev_tnum;unsigned int count);

 

2、移除字符设备

voidcdev_del(structcdev *dev)



三个重要结构体-----><linux/fs.h>

structfile_operations                ---->文件操作结构体

struct file                                      ---->每个打开的文件都有一个structfile

structinode                                  --->每个文件都对应着一个inode->structcdev

 

每个打开的文件都对应着一个struct file. 每个文件在文件系统中都对应着一个inode.

当多次打开同一文件时,内核中会存在多个struct file,但都对应一个inode.

 

struct inode

{       

         dev_ti_rdev;                       --->字符设备设备号

         structcdev* i_cdev;         --->字符设备结构体

......

}

 

打开一个字符设备结构体关联流程

Open(“/dev/xxx”, O_RDWR)–->struct file->inode->cdev->structfile_operations

 

//2.6版本前字符设备注册与释放

intregister_chrdev(unsigned int major,const char *name, structfile_operations *fops)

major : 主设备号

name : 驱动程序,出现在/proc/devices中

fops :文件操作相关, file_operations

返回值:> 0主设备号。次设备号会默认0-255中的某一个

                   <0, 调用失败

//释放

intunregister_chrdev(unsigned int major, constchar *name)

major:主设备号

name : 设备名称


Demo

/*
* cdev demo create by Yxl @20150406
*/


#include <linux/init.h>
#include <linux/module.h>


#include <linux/moduleparam.h>


#include <linux/errno.h>


#include <linux/types.h>
#include <linux/cdev.h> //char devices
#include <linux/fs.h> //struct file, struct inode, struct file_operation


#include <linux/proc_fs.h> //----> procfs
#include <linux/device.h> // class & device
#include <asm/uaccess.h>        //copy_to_user, copy_from_user


unsigned char* gPMem = NULL; 


/*模块参数*/
static int gData = 0;
static char *gStr = "this is my cdev.ko";
module_param(gData, int, S_IRUGO); 
module_param(gStr, charp, S_IRUGO);


/****************************字符设备*******************************/
/*设备号*/
dev_t gDev = 0;


/*字符设备设备*/
struct cdev *gCdev = NULL;


static int Mycdev_open(struct inode * inode, struct file * filp)
{
printk(KERN_INFO "%s", __FUNCTION__);
try_module_get(THIS_MODULE);
return 0;
}


static ssize_t Mycdev_read(struct file* filp, char __user *buffer, size_t count, loff_t *offp)
{
printk(KERN_INFO "%s", __FUNCTION__);
return 0;
}


static ssize_t Mycdev_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
{
printk(KERN_INFO "%s", __FUNCTION__);
return 0;
}
static int Mycdev_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
printk(KERN_INFO "%s", __FUNCTION__);
return 0;
}
static int Mycdev_release(struct inode *inode, struct file *filp)
{
printk(KERN_INFO "%s", __FUNCTION__);

module_put(THIS_MODULE);
return 0;
}

/*字符设备文件操作*/
struct file_operations Mycdev_fops = {
.owner = THIS_MODULE,
.open = Mycdev_open,
.read = Mycdev_read,
.write = Mycdev_write,
.unlocked_ioctl = Mycdev_ioctl,
.release = Mycdev_release,
};


/******************************class&device*******************************/
struct class *gcdev_class = NULL;
struct device *gcdev_device = NULL;


/*********************************proc操作*****************************/
/*Proc 调试信息*/
struct proc_dir_entry *gPentry = NULL;
struct proc_dir_entry *gentry = NULL;


/*proc_read/ proc_write*/
static int cdevDump_read_proc(char *page, char **start,  off_t offset, int count, int *eof, void *data)
{
int len = sprintf(page,"%s\n","hello world");      
return len;  
}

static int cdevDump_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
return 0;
}

//proc file_operations 操作
struct file_operations CdevProc_fpos={
};
/*********************************proc操作**************************/


static int __init Mycdev_init(void)
{
int ret = 0;

printk(KERN_INFO "%s", __FUNCTION__);
printk(KERN_INFO "gStr = %s, module_param gData = %d\n",gStr,  gData);

// 1
/*注册设备号, /proc/devices可以看到Mycdev名字*/
ret = alloc_chrdev_region(&gDev, 0, 1, "Mycdev");
if(ret < 0)
{
printk(KERN_ERR "alloc_chrdev_region failed, ret = %d\n", ret);
return ret;
}

/*注册字符设备*/
gCdev = cdev_alloc();

cdev_init(gCdev, &Mycdev_fops);
gCdev->owner = THIS_MODULE;
gCdev->ops = &Mycdev_fops;/*可以不做,cdev_init里已经做了*/


ret = cdev_add(gCdev, gDev, 1);
if(ret < 0)
{
printk(KERN_ERR "cdev_add failed, ret = %d\n", ret);
return ret;
}


// 2  /sys/class/cdev/DevCdev
/*自动创建/dev/设备节点,  cdev : /sys/class下类名文件夹*/
gcdev_class = class_create(THIS_MODULE, "cdev");
if(gcdev_class == NULL)
{
printk(KERN_ERR "class_create failed...\n");
return -1;
}


/*向sysfs注册class, 并关联设备号, DevCdev: /dev/下节点名字*/
gcdev_device = device_create(gcdev_class, NULL, gDev, NULL, "DevCdev");
if(gcdev_device == NULL)
{
printk(KERN_ERR "device_create failed...\n");
return -1;
}



// 3
/*创建/proc/media 调试信息*/
// 1 创建/proc/media目录
gPentry = proc_mkdir("media", NULL);
if(gPentry == NULL)
{
printk(KERN_ERR "proc_mkdir failed...\n");
}


// 创建/proc/media/cdevDump文件
#if 1
gentry = create_proc_entry("cdevDump", 0666, gPentry);
if(gentry)
{
gentry->proc_fops = &CdevProc_fpos;
gentry->read_proc = cdevDump_read_proc;
gentry->write_proc = cdevDump_write_proc;
}
else
{
printk(KERN_ERR "create_proc_entry failed...\n");
}
#else
/*在高版本中, create_proc替换了create_proc_entry*/
gentry = proc_create("cdevDump", 0666, gPentry, &CdevProc_fpos);
if(gentry == NULL)
{
printk(KERN_ERR "create_proc failed...\n");
}
#endif

return 0;
}


static void __exit Mycdev_exit(void)
{
printk(KERN_INFO "%s", __FUNCTION__);

// 1
/*销毁proc 文件*/
remove_proc_entry("cdevDump", gPentry);
remove_proc_entry("media", NULL);


// 2
/*销毁class & device*/
device_destroy(gcdev_class, gDev);
class_destroy(gcdev_class);

// 3
/*销毁字符设备(先销毁设备,再销毁设备号)*/
cdev_del(gCdev);
/*销毁设备号*/
unregister_chrdev_region(gDev, 1);
}


module_init(Mycdev_init);
module_exit(Mycdev_exit);


MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yxl");



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值