学习字符驱动程序编程,随笔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); //定义信号量
if (file->f_flags & O_NONBLOCK)
{
if (down_trylock(&button_lock))
return -EBUSY;
}
else
{
down(&button_lock);
}
在卸载驱动时释放信号量
up(&button_lock);
- 学习字符驱动程序编程,随笔1
- Linux设备驱动程序学习(1)-字符设备驱动程序
- Linux设备驱动程序学习(1)-字符设备驱动程序
- Linux设备驱动程序学习(1)-字符设备驱动程序
- Linux设备驱动程序学习(1)-字符设备驱动程序
- Linux设备驱动程序学习(1)-字符设备驱动程序
- Linux设备驱动程序学习(1) -字符设备驱动程序
- 字符驱动程序设计学习笔记4-1
- 字符驱动程序内核编程小结
- linux驱动程序编程学习
- 编程语言学习随笔
- Linux设备驱动程序学习(1)--字符设备驱动
- Linux设备驱动程序第三版学习(1)-字符设备驱动程序源码分析
- Linux设备驱动程序第三版学习(1)(2)-字符设备驱动程序源码分析
- Linux设备驱动程序第三版学习(1)-字符设备驱动程序源码分析
- 毕业设计-----linux驱动程序编程学习
- Linux设备驱动程序学习(3)-字符设备驱动程序
- Linux设备驱动程序学习笔记03:字符设备驱动程序I
- iOS 开发中使用block的注意点
- 基于dileber的android网络图片播放器
- Codeforces 633D Fibonacci-ish(搜索)
- Application Fundamentals --1.2
- anywhere 把目录变静态文件服务器
- 学习字符驱动程序编程,随笔1
- 001Java-IO流的关系
- 【Mac】虚拟机装OS X那些坑
- IIR型高斯滤波的原理及实现
- 【PAT】1038. 统计同成绩学生(20)
- 4.4.1 Android 高手进阶之自定义View,自定义属性(带进度的圆形进度条)
- spring加载资源文件中classpath*与classpath的区别
- JVM:浅析Java虚拟机结构与机制
- [lightOJ 1027]A Dangerous Maze[期望]