Linux驱动开发中常用的API

1.printk

打印等级

#define KERN_EMERG   "0"    /* system is unusable */
#define KERN_ALERT   "1"    /* action must be taken immediately */
#define KERN_CRIT    "2"    /* critical conditions */
#define KERN_ERR     "3"    /* error conditions */                               
#define KERN_WARNING     "4"    /* warning conditions */
#define KERN_NOTICE  "5"    /* normal but significant condition */
#define KERN_INFO    "6"    /* informational */
#define KERN_DEBUG   "7"    /* debug-level messages */

其它用法和printf一样,可以利用打印等级区分错误信息

2.module_param
module_param(name, type, perm)	
功能:接收命令行传递的参数
参数:
    @name:变量名
    @type:变量的类型
        /* Standard types are:
 		*	byte, hexint, short, ushort, int, uint, long, ulong
 		*	charp: a character pointer
 		*	bool: a bool, values 0/1, y/n, Y/N.
		*	invbool: the above, only sense-reversed (N = true). */
	@perm:权限   权限的最大值0664,用户与组全部归属于root用户
        
        在 /sys/module/驱动名字/parameters/目录下创建一个名字为 变量名 的文件,此文件的权限为 type
3.MODULE_PARM_DESC
MODULE_PARM_DESC(_parm, desc)
功能:对传递的参数进行描述,可以通过modinfo命令查看这个描述字段
参数:
     @_parm:变量名
     @desc:描述字段
4.EXPORT_SYMBOL_GPL
EXPORT_SYMBOL_GPL(x)
功能:导出符号表
参数:
    @x:函数名/变量名
5.register_chrdev
int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)
	#include <linux/fs.h>
功能:创建字符设备驱动  
参数:
    @major:主设备号 (一次创建256个设备号,主设备号+[0-255])
        major > 0 :静态指定主设备号
        major = 0 :动态申请主设备号 
	@name:驱动的名字
        linux@ubuntu:/dev/input$ cat /proc/devices 
        Character devices:
          1 			mem
          4 			/dev/vc/0
          4 			tty
          4 			ttyS
          5 			/dev/tty
    	  |              |
         主设备号      驱动的名字
	@fops:操作方法结构体
        struct file_operations {
            int (*open) (struct inode *, struct file *);
            ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
			ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    		int (*release) (struct inode *, struct file *);
        }
返回值:成功取决于第一个参数
    		major > 0 :成功返回0
        	major = 0 :成功返回的是主设备号
    	失败返回错误码
6.unregister_chrdev
#include <linux/fs.h>
void unregister_chrdev(unsigned int major, const char *name)
功能:销毁字符设备驱动
参数:
	@major:主设备号
    @name:驱动的名字
返回值:无
7.copy_to_user
#include <linux/uaccess.h>
unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)
功能:从内核空间向用户空间拷贝数据(驱动的read函数中)
参数:
    @to:用户空间的地址
	@from:内核空间的地址
	@n:拷贝的字节的个数
返回值:成功返回0,失败返回未拷贝的字节的个数
8.copy_from_user
#include <linux/uaccess.h>
unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)
功能:从用户空间向内核空间拷贝数据(驱动的write函数中)
参数:
    @to:内核空间的地址
	@from:用户空间的地址
	@n:拷贝的字节的个数
返回值:成功返回0,失败返回未拷贝的字节的个数
9.ioremap
#include <linux/io.h>
void  *ioremap(unsigned long phy_addr, unsigned long size)
功能:地址映射
参数:
    @phy_addr:虚拟地址
	@size:映射的大小,单位是字节
返回值:成功返回虚拟地址,失败返回NULL
10.iounmap
void iounmap(volatile void  *addr)
功能:取消地址映射
参数:
    @addr:虚拟地址
返回值:无
11.writel
writel(v,r)	
功能:向寄存器中写(32bit) 数据
参数:
    @v:写的值
	@r:寄存器地址
12.readl
readl(r)
功能:读取寄存器中的数据
参数:
    @r:寄存器地址
13.class_create
struct class * class_create(owner, name)
功能:向上层提交目录名
参数:
    @owner:THIS_MODULE (编译器相关的宏)
    @name:目录名  在/sys/class下
返回值:成功返回cls的结构体指针,失败返回错误码指针
eg:
	struct class *cls = class_create(THIS_MODULE,"hello");
	if(IS_ERR(cls)){ //进入if语句就是错误
       	printk("class create error\n");
        return PTR_ERR(cls); //将错误码指针转换为错误码
    }
14.device_create
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,...:可变参数,节点名
返回值:成功返回dev的指针,失败返回错误码指针
15.class_destroy
void class_destroy(struct class *cls)
功能:销毁目录
参数:
    @cls:目录的指针
返回值:无
16.device_destroy
void device_destroy(struct class *class, dev_t devt)
功能:销毁设备信息
参数:
    @class:目录的指针
	@devt:设备号
返回值:无
17.ioctl
#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...); --->应用层的ioctl函数
功能:设置的控制
参数:
    @fd:文件描述符
	@request:设备的请求码(命令码)
        //方向 第三个参数的大小
	@...:可变参数,可传递,也可以不传递 
返回值:成功返回0,失败返回-1置位错误码
----------------------------------------------------------------
fops://应用层的ioctl的第二个和第三个参数是和驱动的后两个参数对应的。
#include <linux/ioctl.h>
long (*unlocked_ioctl) (struct file *file, unsigned int cmd, unsigned long args);
{
	eg:
        switch(cmd){
            case 命令码:
                //用户的操作
                break;
        }

        return 0;
}
18.封装命令码的宏
#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)))

内部实现
type-->类型  nr--->功能  size--->类型
#define _IOC(dir,type,nr,size) 
	(((dir)  << 30) |((size) << 16))|((type) << 8)|(nr)  << 0)))
eg:
    #define LED1_ON  _IO('p',0)
    #define LED1_OFF _IO('p',1)

    #define LED_ON  _IOW('p',0,int)
    #define LED_OFF  _IOW('p',1,int)
19.字符设备驱动分布实现的API
#include <linux/cdev.h>
#include <linux/slab.h>  --->kfree头文件
1.分配对象
    struct cdev {
        struct module *owner;             //THIS_MODULE
        const struct file_operations *ops; //操作方法结构体
        struct list_head list;            //构成链表
        dev_t dev;                        //设备号
        unsigned int count;               //设备的个数
    } ;	
	
	struct cdev cdev;
	struct cdev *cdev;
	
	struct cdev *cdev_alloc(void)
    //void kfree(const void *addr)     
    功能:申请内存   //申请内存的大小(sizeof(struct cdev))
    参数:
        @无
	返回值:成功返回结构体指针,失败返回NULL
2.对象的初始化
	void cdev_init(struct cdev *cdev, const struct file_operations *fops)
    功能:初始化cdev结构体的成员
    参数:
        @cdev:cdev的结构体指针
		@fops:操作方法结构体指针
	返回值:无
3.申请设备号
     int register_chrdev_region(dev_t from, unsigned count, const char *name)
     //void unregister_chrdev_region(dev_t from, unsigned count)
     功能:静态指定设备号
     参数:
          @from:设备号的起始值 //major一样 填minor的起始值即可
          @count:设备的个数 
		  @name:设备的名字 //可以通过cat/proc/devices查看
	返回值:成功返回0,失败返回错误码
            
            
     int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)    
     //void unregister_chrdev_region(dev_t from, unsigned count)
     功能:动态申请设备号       
     参数:
          @dev:申请到的设备号
          @baseminor:起始的次设备号
          @count:设备的个数
          @name:设备的名字 //可以通过cat/proc/devices查看
	 返回值:成功返回0,失败返回错误码
4.注册
    int cdev_add(struct cdev *p, dev_t dev, unsigned count)    
    //void cdev_del(struct cdev *p)
    功能:注册
	参数:
         @p:cdev结构体指针
		 @dev:设备号
         @count:设备的个数
	返回值:成功返回0,失败返回错误码
20.中断屏蔽的API
local_irq_disable(); //关闭中断
//临界资源
local_irq_enable();  //开启中断
21.自旋锁的API
1.定义自旋锁
    spinlock_t lock;
2.初始化自旋锁
    void spin_lock_init(spinlock_t *lock)
3.上锁
    void spin_lock(spinlock_t *lock)  //上锁的时候中断可以打断锁
    void spin_lock_irq(spinlock_t *lock) //上锁的时候中断打断不了锁
4.解锁
    void spin_unlock(spinlock_t *lock)
    void spin_unlock_irq(spinlock_t *lock)
22.信号量的API
1.定义信号量
    struct semaphore sem;
2.初始化信号量
    void sema_init(struct semaphore *sem, int val)
	//初始化信号量,当val初始值设置为1的时候才有互斥的效果。当val设置为0的时候是同步的效果。
3.上锁
     void down(struct semaphore *sem); //上锁
	 int down_trylock(struct semaphore *sem) //尝试获取锁,成功返回0,失败返回1
4.解锁
    void up(struct semaphore *sem); //解锁
23.互斥体的API
1.定义互斥体
	struct mutex mutex;
2.初始化互斥体
    mutex_init(&mutex);
3.上锁
    void mutex_lock(struct mutex *lock);
	int  mutex_trylock(struct mutex *lock) //尝试获取锁,成功返回1,失败返回0
4.解锁
    void  mutex_unlock(struct mutex *lock) 
24.原子操作的API
1.定义原子变量并初始化
    atomic_t atm = ATOMIC_INIT(1);
	atomic_t atm = ATOMIC_INIT(-1);
2.上锁
    int atomic_dec_and_test(atomic_t *v)
    //让原子变量的值减去1,然后和0比较,如果结果为0代表获取锁成功了,这个函数返回真,否者返回假
    int atomic_inc_and_test(atomic_t *v)//让原子变量的值加1,然后和0比较,如果结果为0代表获取锁成功了,这个函数返回真,否者返回假
3.解锁
    atomic_inc(atomic_t *v)  //加1 必须保证原子变量为初始化时的值
    atomic_dec(atomic_t *v)  //减1 必须保证原子变量为初始化时的值
25.阻塞IO的API
1.定义等待队列头
    wait_queue_head_t wq;
2.初始化等待队列头
   init_waitqueue_head(&wq);
3.调用对应的函数完成阻塞(定义等待队列项,将等待队列项放到队列的队尾,进程休眠)
    wait_event(wq, condition)  
    //让进程进入到不可中断的等待态
	wait_event_interruptible(wq, condition)   
    //让进程进入到可中断的等待态
    //返回值:如果是数据准备好了它返回0,如果是信号唤醒的进程的休眠返回-ERESTARTSYS
    
    注:condition代表的是数据是否准备好的标志,如果condition为真代表数据准备好了
    进程不需要休眠,如果condition为假代表数据没有准备好进程需要进入休眠的状态。
4.唤醒休眠的进程
    condition=1wake_up(&wq);
    wake_up_interruptible(&wq);
	
	注:上述的两个函数唤醒的是等待队列,队列中的进程是否真的被唤醒取决于
        condition的真假,如果condition为真,进程就准备被唤醒了,如果condition
        为假进程没有被唤醒,进程继续休眠。
26.epoll
 #include <sys/epoll.h>
int epoll_create(int size);
功能:创建epoll
参数:
    @size:参数已经被忽略了,只需要填写大于0的值即可
返回值:成功返回epfd,失败返回-1置位错误码

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:关于epoll的控制操作
参数:
    @epfd:epoll的文件描述符
	@op:控制方式
        EPOLL_CTL_ADD:添加
        EPOLL_CTL_MOD:修改
        EPOLL_CTL_DEL:删除
	@fd:被操作的文件描述符
    @event:(事件)结构体指针
           typedef union epoll_data {
               void        *ptr;
               int          fd;  <====一般填写这个成员
               uint32_t     u32;
               uint64_t     u64;
           } epoll_data_t;

           struct epoll_event {
               uint32_t     events;      //EPOLLIN 读  EPOLLOUT 写
               epoll_data_t data;        //存放用户的数据
           };
返回值:成功返回0,失败返回-1置位错误码

int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
功能:阻塞等待文件描述符就绪
参数:
    @epfd:epoll的文件描述符
    @events:准备好的事件的结构体地址
	@maxevents:返回的最大的文件描述符的个数
    @timeout:超时
        >0 :毫秒级别的超时时间
        =0 :立即返回
        =-1:不关心超时时间
返回值:
     成功返回准备好的文件描述符的个数
     返回0代表超时时间到了
     失败返回-1置位错误码
27.设备树相关的结构体
struct device_node {  //在设备树中每个节点被解析后都会产生一个device_node的成员
	const char *name;      //节点名 "mynode"
	const char *full_name; //节点全名 "mynode@0x12345678"
	struct	property *properties; 
    //属性的指针,节点内核每个键值对都对应一个property结构体,所有的键值对构成单链表
	struct	device_node *parent; //节点的父节点
	struct	device_node *child;  //节点的子节点
	struct	device_node *sibling; //节点的兄弟节点
};

struct property {
	char	*name; //键的名字
	int	length;    //值的长度(字节)
	void	*value; //值
	struct property *next; //指向下一个键值对
};
28.获取device_node的函数
struct device_node *of_find_node_by_path(const char *path)
功能:通过节点的路径获取节点
参数:
    @path:节点的路径  "/mynode@0x12345678"
返回值:成功返回节点的指针,失败返回NULL

struct device_node *of_find_node_by_name(struct device_node *from,const char *name)
功能:通过节点的名字获取节点
参数:
    @from:NULL 从根节点开始解析
	@name:节点名
返回值:成功返回节点的指针,失败返回NULL
29.设备树中获取属性
struct property *of_find_property(const struct device_node *np,const char *name,int*lenp)
功能:获取节点的属性
参数:
    @np:节点的指针
    @name:属性名
    @lenp:值的长度
返回值:成功返回property结构体指针,失败返回NULL
        
int of_property_read_string(const struct device_node *np, const char *propname,
						const char **out_string)
功能:解析字符串
参数:
    @np:节点的指针
	@propname:键
    @out_string:获取到的值
返回值:成功返回0,失败返回错误码
        
int of_property_read_u8_array(const struct device_node *np,
				const char *propname,u8 *out_values, size_t sz)
功能:解析u8数组
参数:
    @np:节点的指针
	@propname:键
    @out_values:获取到的值
    @sz:获取的个数
返回值:成功返回0,失败返回错误码
        
int of_property_read_u32_array(const struct device_node *np,
                 const char *propname,u32 *out_values, size_t sz)
功能:解析u32数组
参数:
    @np:节点的指针
	@propname:键
    @out_values:获取到的值
    @sz:获取的个数
返回值:成功返回0,失败返回错误码 
30.gpio子系统
struct device_node *of_find_compatible_node(struct device_node *from,
	const char *type, const char *compatible)
功能:通过compatible获取节点
参数:
    @from:NULL 
    @type:NULL
    @compatible:"厂商名,设备名"
返回值:成功返回节点的指针,失败返回NULL
        
int of_get_named_gpio(struct device_node *np,const char *propname, int index)
功能:获取gpio号
参数:
    @np:节点的指针
	@propname:键
    @index:值的下标,从0开始
返回值:成功返回gpio号,失败返回错误码
        
int gpio_request(unsigned gpio, const char *label)
功能:申请要使用的gpio
参数:
    @gpio:gpio号
    @label:名字,不想使用可以写为NULL
返回值:成功返回0,失败返回错误码

int gpio_direction_output(unsigned gpio, int value)
功能:设置gpio为输出
参数:
	@gpio:gpio号
    @value: 1高电平  0低电平
返回值:成功返回0,失败返回错误码
        
int gpio_direction_input(unsigned gpio)
功能:设置gpio为输入
参数:
	@gpio:gpio号
返回值:成功返回0,失败返回错误码
        
int gpio_get_value(unsigned gpio)   
功能:读取管脚的电平
参数:  
    @gpio:gpio号
返回值:返回1高电平  0低电平
        
void gpio_set_value(unsigned gpio, int value)
功能:设置管脚的电平值
参数:
	@gpio:gpio号
    @value: 1高电平  0低电平
返回值:无

void gpio_free(unsigned gpio)
功能:释放gpio号
参数:
	@gpio:gpio号
返回值:无
31.gpiod子系统
struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,const char *propname, int index,enum gpiod_flags dflags, const char *label)
    功能:解析得到desc,申请要使用的desc,输出状态
    参数:
    	@node:节点的指针
    	@propnanme:键名
    	@index:值的下标,从0开始
    	@dflags:输出状态   // 枚举常量 GPIOD_OUT_HIGH  GPIOD_OUT_LOW  GPIOD_IN等
    	@label:名字,一般填NULL
    返回值:成功返回desc的结构体指针,失败返回错误码 对于返回值结构体指针
    		都可以使用ISS_ERR和PTR_ERR

 int gpiod_direction_input(struct gpio_desc *desc)
    功能:设置gpio为输入
    参数:
    	@desc:结构体指针
    返回值:成功返回0,失败返回错误码
    
int gpiod_direction_output(struct gpio_desc *desc, int value)
    功能:设置gpio为位输出
    参数:
    	@desc:结构体指针
    	@value:1高电平,0低电平
    返回值:成功返回0,失败返回错误码
    
int gpiod_get_value(const struct gpio_desc *desc)
    功能:读取管脚的电平值
    参数:
    	@desc:结构体指针
    返回值:成功返回0,失败返回错误码
    
void gpiod_set_value(struct gpio_desc *desc, int value)
    功能:设置gpio管脚的电平值
    参数:
    	@desc:结构体指针
    	@value:1高电平,0低电平
    返回值:无
    
void gpiod_put(struct gpio_desc *desc)
  功能:释放gpio号
  参数:
      @desc:结构体指针
  返回值:无  
32.内核定时器
#include <linux/timer.h>
1.分配对象
    struct timer_list {
        struct hlist_node	entry; //构成内核链表使用的成员
        unsigned long	expires;//定时的时间 jiffies+100   jiffies+250
        void (*function)(struct timer_list *); //定时器的处理函数,定时时间到了执行的函数
        u32	 flags; //一般填写为0
	};
	eg:
        struct timer_list mytimer;
2.对象的初始化
     void timer_handle(struct timer_list *timer)
	{
    	//定时器的处理函数
	}
     mytimer.expires = jiffies+100;
     timer_setup(&mytimer, 定时器处理函数, 0);	//这个函数中并没有初始化expires变量,要手动初始化	
3.启动定时器
    void add_timer(struct timer_list *timer);
	//同一个定时器只能add_timer一次,如果在次调用add_timer内核就崩溃了。
	//在调用add_timer的定时器就启动了。当定时器时间到了之后执行定时器处理函数
	//定时器处理函数执行结束他就结束了。

	int mod_timer(struct timer_list *timer, unsigned long expires);
	//再次启动定时器,expires是下一次定时器的时间
4.删除定时器
    int del_timer(struct timer_list * timer);
	//删除定时器
34.中断处理
unsigned int irq_of_parse_and_map(struct device_node *np, int index)
功能:解析并映射得到软中断号
参数  
    @np:节点的指针
	@index:中断的索引号
返回值:成功返回软中断号,失败返回0
        
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
	    const char *name, void *dev)
功能:注册中断
参数:
    @irq:软中断号
    @handler:指向中断处理函数的指针
        irqreturn_t irq_handle(int irq, void *dev)  //中断处理函数
    	{
        	//只能做简短的不耗时的操作
        	return IRQ_NONE;   //中断没有被处理
        	//或者
        	return IRQ_HANDLED; //中断被处理完成了
    	}
	@flags:中断触发方式
        IRQF_TRIGGER_RISING   //上升沿
        IRQF_TRIGGER_FALLING  //下降沿
        IRQF_TRIGGER_HIGH	//高电平
        IRQF_TRIGGER_LOW	//低电平
        IRQF_SHARED         //共享中断
	@ name:中断的名字  
        	cat/proc/interrupts可以查看
	@ dev :向中断处理函数传递的参数
返回值:成功返回0,失败返回错误码    

void *free_irq(unsigned int irq, void *dev);
功能:释放中断
参数:
    @irq:软中断号
	@dev:request_irq的第5个参数
返回值:返回的是设备名  
35.中断底半步之tasklet
1.分配对象
    struct tasklet_struct
    {
        struct tasklet_struct *next; //构成链表的成员
        unsigned long state;         //状态变量
        atomic_t count;              //触发底半部的次数
        bool use_callback;           //如果设置为true表示使用callback函数,否则使用func函数
        union {
            void (*func)(unsigned long data);           //旧版本的底半部处理函数
            void (*callback)(struct tasklet_struct *t); //新版本中加入的底半部处理函数
        };
        unsigned long data;   //向底半部处理函数传递的参数
    };
	struct tasklet_struct tasklet;
2.对象的初始化
    void tasklet_init(struct tasklet_struct *t,
		  void (*func)(unsigned long), unsigned long data)
    //旧版本的初始化函数
    
	void tasklet_setup(struct tasklet_struct *t,
		   void (*callback)(struct tasklet_struct *))
	//新版本的初始化函数
    
3.调用执行
    void tasklet_schedule(struct tasklet_struct *t)
36.中断底半部之工作队列
1.分配对象
    struct work_struct {
        atomic_long_t data;   //保存数据的变量
        struct list_head entry; //构成队列
        work_func_t func;     //底半部处理函数
        //typedef void (*work_func_t)(struct work_struct *work);
    };
  struct work_struct work;
2.初始化对象
    INIT_WORK(&work, 底半部处理函数);
3.调用执行
    bool schedule_work(struct work_struct *work)
37.platform
设备信息端:
1.分配并初始化对象
    struct platform_device {
        const char	*name;  //用于匹配的名字
        int		id;         //总线号   PLATFORM_DEVID_AUTO
        struct device	dev; //父类
        u32		num_resources; //设备信息的个数
        struct resource	*resource; //设备信息结构体
    }
	struct device{  //父类
		void	(*release)(struct device *dev); //用来释放资源的函数 
    }
	
    struct resource {         //设备信息结构体  
        resource_size_t start; //资源的起始值  0x50006000       0x56000000        71
        resource_size_t end;   //资源的结束值  0x50006000 + 3   0x56000000+49     71
        unsigned long flags;   //资源的类型    IORESOURCE_IO    IORESOURCE_MEM   IORESOURCE_IRQ
    };

2.注册、注销
    int platform_device_register(struct platform_device *pdev)   //注册
    void platform_device_unregister(struct platform_device *pdev) //注销
    
设备驱动端:
1.分配并初始化对象
    struct platform_driver {
        int (*probe)(struct platform_device *);
        //匹配成功执行的函数
        int (*remove)(struct platform_device *);
        //分离的时候执行的函数
        struct device_driver driver;
        //父类
        const struct platform_device_id *id_table;
        //2.idtable匹配
    };	

    struct device_driver {
        const char		*name; //1.用于匹配的名字
        const struct of_device_id	*of_match_table;
        						//3.设备树匹配方式
    }
2.注册、注销
    platform_driver_register(drv) //注册
	void platform_driver_unregister(struct platform_driver *); //注销

	module_platform_driver(pdrv); //一键注册注销的宏



struct resource *platform_get_resource(struct platform_device *dev,
				       unsigned int type, unsigned int index)
功能:获取resource资源的函数
参数:
    @dev:platform_device结构体指针
	@type:资源的类型 IORESOURCE_IO   IORESOURCE_MEM  IORESOURCE_IRQ
    @index:同类型资源的下标
返回值:成功返回resouce的地址,失败返回NULL
int platform_get_irq(struct platform_device *dev, unsigned int index)
功能:获取中断类型的资源
参数:
    @dev:platform_device结构体指针
	@index:中断类型资源的下标
返回值:成功返回中断号,失败返回错误码
38.i2c总线驱动
1.分配并初始化对象
    struct i2c_driver {
    	int (*probe)(struct i2c_client *client, const struct i2c_device_id *id);
        //匹配成功执行的函数
    	int (*remove)(struct i2c_client *client);
        //分离的时候执行的函数
        struct device_driver driver;
        //父类
		const struct i2c_device_id *id_table;
        //idtable的匹配方式
    }
	struct device_driver {
		const char		*name; //name不用于匹配,但必须填写
        const struct of_device_id	*of_match_table; //设备树匹配方式
    }
2.对象的注册、注销
    i2c_add_driver(driver) //注册
    void i2c_del_driver(struct i2c_driver *driver); //注销

	module_i2c_driver(i2c对象); //一键注册注销的宏

int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
功能:发送消息
参数:
    @adap:总线驱动的指针 client->adapter
	@msgs:消息结构体的首地址
	@num:消息的个数
返回值:如果返回值等于num表示成功,否则就是失败
39.spi总线驱动
1.分配并初始化对象
	struct spi_driver {
		int			(*probe)(struct spi_device *spi);
		int			(*remove)(struct spi_device *spi);
		struct device_driver	driver;
	};
	struct device_driver {
		const char	*name;
        const struct of_device_id	*of_match_table;
    }
2.注册	
    #define spi_register_driver(driver) \
	__spi_register_driver(THIS_MODULE, driver)
3.注销
     void spi_unregister_driver(struct spi_driver *sdrv)
4.一键注册的宏
    module_spi_driver(结构体变量名);
    
    
 int spi_write(struct spi_device *spi, const void *buf, size_t len) //发数据
int spi_read(struct spi_device *spi, void *buf, size_t len)       //接收数据
int spi_write_then_read(struct spi_device *spi,                   //同时收发
		const void *txbuf, unsigned n_tx,
		void *rxbuf, unsigned n_rx);
40.块设备驱动
1.gendisk的结构体对象
    struct gendisk {   
        int major;   //块设备的主设备号
        int first_minor; //起始的次设备号
        int minors; //设备的个数,分区的个数
        char disk_name[DISK_NAME_LEN]; //磁盘的名字
        struct disk_part_tbl  *part_tbl;
        //磁盘的分区表的首地址
        struct hd_struct part0;
        //part0分区的描述
        const struct block_device_operations *fops;
        //块设备的操作方法结构体

        struct request_queue *queue;
        //队列(重要)

        void *private_data;
        //私有数据
    };

    分区的结构体
    struct hd_struct {
        sector_t start_sect; //起始的扇区号
        sector_t nr_sects;   //扇区的个数                                                                                             
        int  partno;        //分区号
    };

    //块设备的操作方法结构体
    struct block_device_operations {
        int (*open) (struct block_device *, fmode_t);
        int (*release) (struct gendisk *, fmode_t);
        int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
        int (*getgeo)(struct block_device *, struct hd_geometry *);	
        //设置磁盘的磁头,磁道,扇区的个数的。hd_geometry
    }	


2.结构体对象的初始化
    struct gendisk *mydisk;

    struct gendisk *alloc_disk(int minors)
    //void put_disk(struct gendisk *disk)
    //归还引用计数
    功能:分配gendisk的内存,然后完成必要的初始化
    参数:
        @minors:分区的个数
    返回值:成功返回分配到的内存的首地址,失败返回NULL


    int register_blkdev(unsigned int major, const char *name)
    //void unregister_blkdev(unsigned int major, const char *name)
    功能:申请设备设备驱动的主设备号
    参数:
        @major : 0:自动申请
                  >0 :静态指定
        @name  :名字  cat /proc/devices
    返回值:	
            major=0 ;成功返回主设备号,失败返回错误码
            major>0 :成功返回0 ,失败返回错误码

    void set_capacity(struct gendisk *disk, sector_t size)
    功能:设置磁盘的容量

    struct request_queue *blk_mq_init_sq_queue(struct blk_mq_tag_set *set,const struct blk_mq_ops 
    *ops,unsigned int queue_depth,unsigned int set_flags)
    //void blk_cleanup_queue(struct request_queue *q)
     功能:用于在给定队列深度的情况下使用mq ops设置队列的助手,以及通过mq ops标志传递的助手
     参数:
     @被初始化的tag对象,tag被上层使用,里面包含硬件队列的个数,队列的操作方法结构体,标志位等
     @放入到tag中的操作方法结构体
     @ tag中指定支持的队列深度
     @将tag中队列的处理标志位,例如BLK_MQ_F_SHOULD_MERGE, BLK_MQ_F_BLOCKING等
     返回值:成功返回队列指针,失败返回错误码指针 

3.注册、注销
    void add_disk(struct gendisk *disk)
    //注册
    void del_gendisk(struct gendisk *disk)
    //注销
41.块设备队列处理
{
    /*双向链表数据结构,将所有加入到队列的IO请求组建成一个双向链表*/
    struct  list_head  queue_head; 
    struct list_head    requeue_list; //request队列
    spinlock_t      requeue_lock;     //队列自旋锁
    unsigned long     nr_requests;     /* 最大的请求数量 */
    unsigned long     queue_flags;/*当前请求队列的状QUEUE_FLAG_STOPPED*/};
struct  request
{
    struct list_head queuelist;/* 请求对象中的链表元素*/
    struct request_queue *q;	/* 指向存放当前请求的请求队列*/
    unsigned int __data_len;	/* 当前请求要求数据传输的总的数据量 */
    sector_t __sector;         /* 当前请求要求数据传输的块设备的起始扇区 */
    struct bio *bio;		/* bio对象所携带的信息转存至请求对象中*/
    struct bio *biotail;	/* bio链表*/};
通常一个request请求可以包含多个bio,一个bio对应一个I/O请求  
 struct bio {		
    struct bio *bi_next;	 /* 指向当前bio的下一个对象*/	
    unsigned long  bi_flags; 	 /* 状态、命令等 */	
    unsigned long bi_rw; 	 /* 表示READ/WRITE*/	
    struct block_device	*bi_bdev;    /* 与请求相关联的块设备对象指针*/	
    unsigned short bi_vcnt;	 /* bi_io_vec数组中元素个数 */	
    unsigned short bi_idx;	 /* 当前处理的bi_io_vec数组元素索引 */
    unsigned int bi_size;	 /* 本次传输需要传输的数据总量,byte(扇区大小整数倍) */	
    struct bio_vec *bi_io_vec;/* 指向一个IO向量的数组,数组中的内各元素对应一个物理页的page对象 */
  };
struct bio_vec {		
    struct page  *bv_page; //指向用于数据传输的页面所对应的struct page对象
    unsigned int bv_len;   //表示当前要传输的数据大小		
    unsigned int bv_offset;//表示数据在页面内的偏移量	
};


blk_mq_start_request(rq); //开始处理队列
blk_mq_end_request(rq, BLK_STS_OK); //结束队列处理
rq_for_each_segment(bvec, rq, iter) //从request->bio_vec
void* b_buf = page_address(bvec.bv_page) + bvec.bv_offset; //将页地址转换为线性地址(内地址)
rq_data_dir(rq))   //从request获取本次读写的方向  WRITE 1   READ 0
dev_addr+(rq->__sector *512) //磁盘设备的地址
  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值