學習字符驅動程序編程,隨筆1

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);












發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章