学习字符驱动程序编程,随笔1

来源:互联网 发布:算法竞赛入门经典 微盘 编辑:程序博客网 时间:2024/06/05 17:53

1.驱动程序结构

module_init(drv_init);//定义驱动初始化函数为 static int __init  drv_init(void){}(__init  表示注册后该函数丢失)

module_exit(drv_exit);//定义驱动卸载函数为 static void __exit third_drv_exit(void){}(__exit 表示驱动不可以卸载时函数丢失)

MODULE_LICENSE("GPL");

2.注册驱动时使用函数

/*

major 为返回的主设备号

第一个参数为0时自动分配主设备号,不为0时注册的字符驱动为该参数

第二个参数为设备名称

第三个参数为结构体file_operations在头文件 linux/fs.h中定义,用来存储驱动内核模块提供的对设备进行各种操作的函数的指针

mi = MINOR(Dev_id)用宏从设备号得出次设备号

ma = MAJOR(Dev_id)用宏重设备号得出主设备号

Dev_id = MKDEV(ma,mi)用宏重主次设备号得出设备号

static struct file_operations drv_fops = {

.owner =  THIS_MODULE,   

.open =  drv_open,     

.read  =drv_read,

.release =  drv_close,   
};

*/

major = register_chrdev(0, "drv", &drv_fops);

/*

创建一个设备类,需要包含头文件 linux/device.h

static struct class *drv_class;

*/

drv_class = class_create(THIS_MODULE, "drv");

/
*

创建设备

第一个参数为设备类

第三个参数为设备号

第五个参数为设备名,/dev/buttons

static struct device *drv_class_dev;

*/

drv_class_dev = device_create(drv_class, NULL, MKDEV(major, 0), NULL, "buttons");

3.注册卸载是使用函数

unregister_chrdev(major, "drv");

device_unregister(drv_class_dev);

class_destroy(drv_class);


4.常用头文件

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/fs.h>

#include <linux/init.h>

#include <linux/delay.h>

#include <linux/irq.h>

#include <asm/uaccess.h>

#include <mach/irqs.h>

#include <asm/io.h>

#include <mach/regs-gpio.h>

#include <mach/gpio.h>

#include <mach/hardware.h>

#include <linux/wait.h>

#include <linux/device.h>

#include <linux/sched.h>

#include <linux/interrupt.h>

5.信号量

static DEFINE_SEMAPHORE(lock_r); // 定义赋值

down(&lock_r); //信号量减1

up(&lock_r); //信号量加1


6.管脚操作

/*需要包含头文件 mach/regs-gpio.h 和 mach/gpio.h*/

s3c_gpio_cfgpin(S5PV210_GPJ2(0),S3C_GPIO_OUTPUT);//设置GPJ2_0为输出管脚

s3c_gpio_cfgpin(S5PV210_GPJ2(1),S3C_GPIO_INPUT);//设置GPJ2_1为输入管脚

gpio_set_value(S5PV210_GPJ2(0),0);//设置GPJ2_0输出电平为低电平 

val = gpio_get_value(S5PV210_GPJ2(1));//读取GPJ2_1电平,为返回值


7.等待队列

/*等待队列需要包含头文件 linux/wait.h */

static DECLARE_WAIT_QUEUE_HEAD(waitq_r); //定义等待队列

wait_event_interruptible(waitq_r, flag_wait); //休眠等待唤醒,应该同时满足两个条件

//1.唤醒休眠的进程2.标志flag_wait 为真

wake_up_interruptible(&waitq_r);   //唤醒休眠的进程


8.中断的使用

/*

中断注册使用函数,需要包含头文件 linux/interrupt.h linux/sched.h

request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev_id)

irq 是申请的硬件中断号 ,IRQ_EINT(16)表示中断16,需要包含头文件 linux/irq.h

handler 是一个回调函数,发生中断时使用该函数。将参数dev_id传入。static irqreturn_t func_irq(int irq, void *dev_id)

flags 为中断参数 IRQF_TRIGGER_FALLING下降沿有效 IRQF_TRIGGER_RISING上升沿有效 IRQF_TRIGGER_HIGH高电平有效 IRQF_TRIGGER_LOW低电平有效

name 名称

*/

request_irq(IRQ_EINT(16), func_irq, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "S1", &pins_desc[0]);

/*

释放中断

void free_irq(unsigned int irq, void *dev_id)

irq 是申请的硬件中断号 ,IRQ_EINT(16)表示中断16,需要包含头文件 linux/irq.h

dev_id 传给free_irq的参数

*/

free_irq(IRQ_EINT(16), &pins_desc[0]);


9.poll机制和使用

/*

包含头文件linux/poll.h

在驱动程序的poll要实现两个功能1.调用poll_wait将进程加入某个休眠队列(button_waitq),但不会立刻休眠。2.返回掩码,确定有没数据可读写

驱动程序可有使用    wake_up_interruptible(&button_waitq);   唤醒休眠进程,不然应用程序要等待相应时间后才唤醒。

应用程序调用int poll(struct pollfd fd[], nfds_t nfds, int timeout)  -->>sys_poll  -->>...-->>驱动程序poll

struct pollfd{

  int fd;              //文件描述符

  short events;    //请求的事件

  short revents;   //返回的事件

  };

nfds:要监视的描述符的数目。

timeout:是一个用毫秒表示的时间,是指定poll在返回前没有接收事件时应该等待的时间。如果  它的值为-1,poll就永远都不会超时。如果整数值为32个比特,那么最大的超时周期大约是30分钟。

*/

static unsigned drv_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
poll_wait(file, &button_waitq, wait); // 不会立即休眠
if (ev_press)
mask |= POLLIN | POLLRDNORM;
return mask;
}

static struct file_operations poll_fops = {

.owner = THIS_MODULE;

.open = 

.release = 

.poll = drv_poll;

};


10.异步通信,信号

/*

在应用程序需要做以下事情

signal(SIGIO, my_signal_fun); //定义接受信号类型和处理函数 void my_signal_fun(int signum)

fcntl(fd, F_SETOWN, getpid()); //告诉驱动程序进程的PID

Oflags = fcntl(fd, F_GETFL);  //先读取标志位

fcntl(fd, F_SETFL, Oflags | FASYNC);//在原先标志位的基础上增加FASYNC,这个时候驱动程序调用file_operations中的.fasync函数

在驱动程序中需要定义file_operations结构体中的.fasync函数以及发送信号

*/

/*

调用该函数时初始化button_async结构体(static struct fasync_struct *button_async;)


*/

static int drv_fasync (int fd, struct file *filp, int on)
{
return fasync_helper (fd, filp, on, &button_async);
}

static struct file_operations poll_fops = {

.owner = THIS_MODULE;

.open = 

.release = 

.fasync = drv_fasync ;

};

/*

发送信号给应用程序

void kill_fasync(struct fasync_struct **fp, int sig, int band)

*/

 kill_fasync (&button_async, SIGIO, POLL_IN); //发信号给应用程序


11.防止驱动程序重复加载

static DEFINE_SEMAPHORE(button_lock);     //定义信号量

在open函数中判断打开方式

if (file->f_flags & O_NONBLOCK)
{
if (down_trylock(&button_lock))
return -EBUSY;
}
else
{
down(&button_lock);
}

在卸载驱动时释放信号量

up(&button_lock);












0 0
原创粉丝点击