当前位置: 首页 > wzjs >正文

网站架构设计文档营销策划公司排名

网站架构设计文档,营销策划公司排名,公司企业网站建设方案书,云阿里云做网站目录 file_operation 接口实现open close接口的实现read 接口实现write 接口实现ioctl 接口实现ioctl cmd 值的定义如何检查命令内存拷贝 字符设备注册函数cdev 操作相关函数 file_operation 接口实现 open close接口的实现 int (*open) (struct inode *, struct file *); in…

目录

      • file_operation 接口实现
        • open close接口的实现
        • read 接口实现
        • write 接口实现
        • ioctl 接口实现
        • ioctl cmd 值的定义
        • 如何检查命令
        • 内存拷贝
      • 字符设备注册函数
      • cdev 操作相关函数

file_operation 接口实现

open close接口的实现
int (*open) (struct inode *, struct file *);
int (*release) (struct inode *, struct file *);
read 接口实现
ssize_t (*read) (struct file * filp, char __user *buf, size_t count, loff_t * f_pos);

struct file * filp:打开设备节点时分配的 struct file 类型
char __user * buf:待写入所读取数据的用户空间缓冲区指针
size_t count:待读取数据字节数
loff_t f_pos:待读取数据文件位置,读取完成后根据实际读取字节数重新定位

__user :是一个空的宏,主要用来显示的告诉程序员它修饰的指针变量存放的是用户空间的地址
如果该操作为空,将使得 read 系统调用返回负EINVAL 失败,正常返回实际读取的字节数

write 接口实现
ssize_t (*write) (struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);

struct file *filp:待操作的设备文件 struct file 结构体指针
const char __user buf:待写入所读取数据的用户空间缓冲区指针
size_t count:待写入数据字节数
loff_t * f_pos:待写入数据文件位置,读取完成后根据实际读取字节数重新定位

ioctl 接口实现
long (*unlocked_ioctl) (struct file *filp, unsigned int cmd, unsigned long arg)
long (*compat_ioctl) (struct file *filp, unsigned int cmd, unsigned long arg);

kernel 2.6.35 及之前的版本中 struct file_operations 一共有 3 个 ioctl :ioctlunlocked_ioctlcompat_ioctl 现在只有unlocked_ioctlcompat_ioctl
kernel 2.6.36 中已经完全删除了 struct file_operations 中的 ioctl 函数指针,取而代之的是 unlocked_ioctl
应用层调用 ioctl 的方式

int ioctl(int fd, int cmd, ...);
//参数:
//fd:打开设备文件的时候获得文件描述符 
//cmd:第二个参数:给驱动层传递的命令,需要注意的时候,驱动层的命令和应用层的命令一定要统一
//第三个参数: "..."在C语言中,很多时候都被理解成可变参数。

当我们通过 ioctl 调用驱动层 xxx_ioctl 的时候,有三种情况可供选择:

  1. 不传递数据给 ioctl
  2. 传递数据给 ioctl,希望它最终能把数据写入设备(例如:设置 Framebuffer 的显示信息)
  3. 调用_ioctl希望获取设备的硬件参数(例如:获取当前串口设备的波特率)
    这三种情况中,有时候需要从用户空间读取数据,有时候需要从内核空间拷贝数据,有时候不需要传递数据,
    用 “…” 来表示,可以带一个参数,或者不带参数
ioctl cmd 值的定义

include/uapi/asm-generic/ioctl.h

ioctl_cmd.jpg

#define _IOC(dir,type,nr,size) \(((dir)  << _IOC_DIRSHIFT) | \ //30((type) << _IOC_TYPESHIFT) | \ //8((nr)   << _IOC_NRSHIFT) | \ //0((size) << _IOC_SIZESHIFT)) //16#ifndef __KERNEL__
#define _IOC_TYPECHECK(t) (sizeof(t))
#endif/* used to create numbers */
#define _IO(type,nr)		_IOC(_IOC_NONE,(type),(nr),0)
#define _IOR(type,nr,size)	_IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOW(type,nr,size)	_IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOWR(type,nr,size)	_IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOR_BAD(type,nr,size)	_IOC(_IOC_READ,(type),(nr),sizeof(size))
#define _IOW_BAD(type,nr,size)	_IOC(_IOC_WRITE,(type),(nr),sizeof(size))
#define _IOWR_BAD(type,nr,size)	_IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))/* used to decode ioctl numbers.. */
#define _IOC_DIR(nr)		(((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
#define _IOC_TYPE(nr)		(((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
#define _IOC_NR(nr)		(((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
#define _IOC_SIZE(nr)		(((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)

type:一般为 magincNumber
nr:一般为递增的序列号
size:传输数据的size
cmd 是一个 unsigned int 类型的整形数,大小为 32bit

  • cmd 的高位 2Bit cmd[31:30] 是数据的传输方向,可以是 _IOC_READ_IOC_WRITE或者 IOC_READ|_IOC_WRITE_IOC_NONE
  • cmd[29:16] 最多是 14 bit,表示数据的大小
  • cmd[15:8] 命令的类型,一般使用一个固定的数值,称为 MagicNumber
  • cmd[7:0] 序列号,一般表示第几个命令,随着命令数递增

通过 linux 中提供的宏,我们只需要定义 MagicNumber,命令序号和数据字段(宏中会自动使用sizeof)就好了

如何检查命令

_IOC_TYPE(nr) 来判断应用程序传下来的命令type是否正确
_IOC_DIR(nr) 来得到命令是读还是写,然后再通过宏 access_ok(type,addr,size) 来判断用户层传递的内存地址是否合法

内存拷贝

include/asm-generic/uaccess.h

static inline int copy_from_user(void *to, const void __user volatile *from,unsigned long n)
static inline long copy_to_user(void __user *to, const void *from, unsigned long n)/* to:目标地址(用户空间)from:源地址(内核空间)n:将要拷贝数据的字节数*/#define put_user(x, ptr)					\
({								\void *__p = (ptr);					\might_fault();						\access_ok(VERIFY_WRITE, __p, sizeof(*ptr)) ?		\__put_user((x), ((__typeof__(*(ptr)) *)__p)) :	\-EFAULT;					\
})
/*data:可以是字节、半字、字、双字类型的内核变量ptr:用户空间内存指针
*/#define get_user(x, ptr)					\
({								\const void *__p = (ptr);				\might_fault();						\access_ok(VERIFY_READ, __p, sizeof(*ptr)) ?		\__get_user((x), (__typeof__(*(ptr)) *)__p) :	\((x) = (__typeof__(*(ptr)))0,-EFAULT);		\
})
/*data:可以是字节、半字、字、双字类型的内核变量ptr:用户空间内存指针
*/

Linux 提供 copy_from_user,copy_to_user,put_user 和 get_user宏来和用户空间交换数据
使用这些函数和用户空间交互时,内核会做参数检查,比如指针指向的区域是否属于用户空间,是否属于用户的当前进程,读和写的内存必须由相应的权限

字符设备注册函数

内核提供了三个函数来注册一组字符设备编号,这三个函数分别是 register_chrdev_region()alloc_chrdev_region()register_chrdev()
代码位置:

include/linux/fs.h kernel/fs/char_dev.c

static inline int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)
{return __register_chrdev(major, 0, 256, name, fops);
}static inline void unregister_chrdev(unsigned int major, const char *name)
{__unregister_chrdev(major, 0, 256, name);
}int register_chrdev_region(dev_t from, unsigned count, const char *name)int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)int  unregister_chrdev_region(dev_t, unsigned);

register_chrdev 可以直接传入 file_opeations 结构体,本质上相当于将 cdev 的操作在函数内部实现了
register_chrdev_region 可以指定主设备号,但需要配合 cdev 结构体一起使用
alloc_chrdev_region 动态分配主设备号,传出 dev_t 的结构

register_chrdev_region(dev_t first,unsigned int count,char *name)

first: 主设备号,要分配的设备编号范围的初始值, 这组连续设备号的起始设备号
count: 连续编号范围. 是这组设备号的大小(也是次设备号的个数)
name: 编号相关联的设备名称. (/proc/devices);本组设备的驱动名
正确的时候返回 0

register_chrdev_region 需要和 cdev 的相关函数一起使用

int alloc_chrdev_region(dev_t* dev ,unsigned int first minor,unsigned int count,char *name)

dev_t* dev 是传出的参数 用于获取 dev_t 数据结构 自动获取主次设备号
first_minor 第一个次设备号
count 请求连续分配的设备个数
name 出现在 /proc/devices 和 sysfs 中

cdev 操作相关函数

include/linux/cdev.h

用于分配,初始化一个cdev 结构,将struct file_operations赋值给它,最后将它和 dev_t 结构绑定

struct cdev {struct kobject kobj;struct module *owner;const struct file_operations *ops;struct list_head list;dev_t dev;unsigned int count;
};void cdev_init(struct cdev *, const struct file_operations *);
struct cdev *cdev_alloc(void);void cdev_put(struct cdev *p);
int cdev_add(struct cdev *, dev_t, unsigned);void cdev_set_parent(struct cdev *p, struct kobject *kobj);
int cdev_device_add(struct cdev *cdev, struct device *dev);

一般用法如下:

demo_cdev = cdev_alloc();  
cdev_init(demo_cdev,&Mstar_demo_driver);  
demo_cdev->owner = THIS_MODULE;  ret = cdev_add(demo_cdev,demo_devt,1);  
if(ret) 
{  printk("cdev create error!\n");  unregister_chrdev_region(demo_devt,1);  return ret;  
} 
http://www.dtcms.com/wzjs/272996.html

相关文章:

  • 广州网站建设 易企建站公司数据指数
  • 兰州医院网站制作合肥网站推广优化公司
  • 天津专门做网站的公司seo分析报告
  • 郑州企业建网站制作经典软文案例
  • 上海闵行区疫情最新情况快速优化网站排名软件
  • 长沙建站挺找有为太极安卓优化大师新版
  • 烟台优化网站公司太原今日头条
  • 四川疫情最新情况最新消息百度关键词优化软件排名
  • 南通网站优化新网域名注册官网
  • 域名转出过程网站能打开吗厦门人才网
  • 如何做旅游网站推广哪里有学电脑培训班
  • 中国东凤网站制作深圳百度推广排名优化
  • 免费营销型网站建设网络营销知识点
  • 网站导航条怎么做效果免费b站推广网站入口202
  • 湖州公司网站建设百度小说排行榜前十名
  • 做动漫网站的素材宁波seo推广
  • c语言做网站后台服务怎么制作链接网页
  • 手机硬件开发网络优化大师手机版
  • 深圳品牌策划营销关键词快速排名seo怎么优化
  • 最火高端网站设计厂家培训平台
  • 房产中介做网站正规的微信推广平台
  • 网站建设分金手指专业二七北京seo
  • 太仓网站制作雅虎搜索引擎
  • 创意设计网站大全外贸网站谷歌seo
  • 大连开发区社保网站营销策划咨询
  • 我想找工作没学历网站搜索引擎优化方法
  • 鹤壁 网站建设桂平网络推广
  • 动态网站设计与开发心得体会开发一个小程序一般需要多少钱呢
  • 保山网站建设百度推广服务费3000元
  • 如何给网站添加搜索关键字百度关键词热度