Drive learning-daily notes day3

[1] Review
1. Kernel module
entry and export license
2. Kernel print function
printk (print level "what you want to print");
printk ("what you want to print");
3. Module pass parameter
sudo insmod demo .ko a=100
/sys/module/driver name/
module_param (variable name, type, permission);
module_param_array (variable name, type, length, permission);
MODULE_PARM_DESC (variable, "string");

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 uses
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);
Parameters:
cmd: is the request
args passed from user space. args: is passed from user space...

应用层的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:
Exercise:
1. Transfer char [50] string from user space to kernel space
, print it in the kernel
2. Pass this data from kernel space to user space, print and display

	#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 download code
1. Install git
sudo apt-get install git
2. Download command
git clone https://github.com/daizhansheng/Linux-driver-31.git

[2] The process of automatically creating a device node
user hotplug ---------------> udev/mdev
| |----->/dev/device node name
|/sys/class/ Directory/device name
--------|-------------------------------------
kernel |
|
1. Submit directory
class_create(owner, name)
2. Submit device name
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

Guess you like

Origin blog.csdn.net/weixin_48430195/article/details/108671789