驱动学习-日常笔记day3

【1】复习
1.内核模块
入口 出口 许可证
2.内核中打印函数
printk(打印级别 “想要打印的内容”);
printk(“想要打印的内容”);
3.模块传参
sudo insmod demo.ko a=100
/sys/module/驱动名/
module_param(变量名,类型,权限);
module_param_array(变量名,类型,长度,权限);
MODULE_PARM_DESC(变量,“字符串”);

4.模块导出符号表
	EXPORT_SYMBOL_GPL(变量名/函数名);
5.字符设备驱动
	major = register_chrdev(major,name,&fops);
	unregister_chrdev(major,name);
6.数据传输
	copy_from_user();
	copy_to_user();
	
7.地址映射
	虚拟地址 = ioremap(物理地址,长度)
	iounmap(虚拟地址);
	
练习:
	1.使用字符设备驱动点灯

【2】ioctl使用
man ioctl

#include <sys/ioctl.h>
int ioctl(int fd, int request, ...);
功能:input /output control device
参数:
	@fd     :打开设备得到的文件描述符
	@request:通过同宏_IO _IOR _IOW  _IOWR封装的请求码
	@...    :可变参数

fops:long (*unlocked_ioctl) (struct file *,
unsigned int cmd, unsigned long args);
参数:
cmd:就是用户空间传递过来的request
args:就是用户空间传递过来的…

应用层的ioctl被调用的时候驱动的fops中的
unlocked_ioctl就会被执行。

request这个32位请求码,每个部分的含义
 31-30  00 - no parameters: uses _IO macro
	10 - read: _IOR
	01 - write: _IOW
	11 - read/write: _IOWR

 29-16  size of arguments

 15-8   ascii character supposedly
	unique to each driver

 7-0    function #
                   
#define _IO(type,nr)		
	_IOC(_IOC_NONE,(type),(nr),0)
	
#define _IOR(type,nr,size)	
	_IOC(_IOC_READ,(type),(nr),(sizeof(size)))
#define _IOW(type,nr,size)	
	_IOC(_IOC_WRITE,(type),(nr),(sizeof(size)))
#define _IOWR(type,nr,size)	
	_IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(sizeof(size)))


#define _IOC(dir,type,nr,size) \
(((dir)  << _IOC_DIRSHIFT) | \
 ((type) << _IOC_TYPESHIFT) | \
 ((nr)   << _IOC_NRSHIFT) | \
 ((size) << _IOC_SIZESHIFT))


 2       14        8      8
 dir     size     type    nr
	
#define VFAT_IOCTL_READDIR_BOTH        
	_IOR('r', 1, struct dirent [2])


#define RED_ON   _IO('a',0)
#define RED_OFF  _IO('a',1)

PM:
练习:
1.从用户空间向内核空间传递char [50]字符串,在
内核中打印显示
2.将这份数据从内核空间传递到用户空间,打印显示

	#define ACCESS_DATA_R _IOR('a',0,int)
	#define ACCESS_DATA_W _IOW('a',0,int)
	case ACCESS_DATA_R:
		ret = copy_to_user((void *)args,&data,4);

		break;
	case ACCESS_DATA_W:
		ret = copy_from_user(&data,(void *)args,4);

【1】git下载代码
1.安装git
sudo apt-get install git
2.下载命令
git clone https://github.com/daizhansheng/Linux-driver-31.git

【2】自动创建设备节点的过程
user hotplug ---------------> udev/mdev
| |----->/dev/设备节点名
|/sys/class/目录/设备名
--------|-------------------------------------
kernel |
|
1.提交目录
class_create(owner, name)
2.提交设备名
struct device *device_create(struct class *class,
struct device *parent,dev_t devt, void *drvdata,
const char *fmt, …)

创建设备节点的函数接口讲解如下:
1.class_create(owner, name)
功能:提交目录
参数:
	@owner :THIS_MODULE
		(以后所有的驱动遇到owner就写THIS_MODULE,
		编译驱动之后会生成一个文件,这个文件通过this_module
		记录程序的入口和出口)
	@name :目录名
	
返回值:成功返回struct class *的结构体指针,
		失败返回错误码指针(void *)-5;


cls = class_create(owner, name);
思考如何判断这个函数返回的错误?

*((int *)ret) < 0  错误
sizeof(*ret) == 4; 错误

IS_ERR(cls)
如果返回值为真,表示他是一个错误,否则不是一个错误。

ERR_PTR(long error)
将错误码转化为错误码指针

PTR_ERR(const void *ptr)
将错误码指针转化为错误码

2.struct device *device_create(struct class *class,
struct device *parent,dev_t devt, void *drvdata, 
const char *fmt, ...)
功能:提交设备节点名
参数:
	@class :cls的结构体指针
	@parent:NULL
	@devt  : 设备号
	@drvdata:NULL
	@fmt   :设备节点的名字
返回值:成功返回struct device *的结构体指针,
		失败返回错误码指针


MKDEV(ma,mi) //根据主次设备号合成设备号
MAJOR(dev)   //根据设备号得到主设备号
MINOR(dev)   //根据设备号得到次设备号


void class_destroy(struct class *cls)
功能:注销class


void device_destroy(struct class *class, dev_t devt)
功能:注销device

猜你喜欢

转载自blog.csdn.net/weixin_48430195/article/details/108671789