虚拟开发板-字符设备驱动

_______ ______ _______
1
2
3
4
5
6
7
( ____ \|\ /|( ___ ) ( __ \ ( ____ )|\ /|
| ( \/| ) ( || ( ) | | ( \ )| ( )|| ) ( |
| | | (___) || (___) | | | ) || (____)|| | | |
| | | ___ || ___ | | | | || __)( ( ) )
| | | ( ) || ( ) | | | ) || (\ ( \ \_/ /
| (____/\| ) ( || ) ( | | (__/ )| ) \ \__ \ /
(_______/|/ \||/ \| (______/ |/ \__/ \_/

udev机制

udev提供一个基于用户空间的动态设备节点管理和命名的解决方案。
udev提供内核sysfs和tmpfs的支持,sysfs为udev提供设备入口和uevent通道,tmpfs为udev设备文件存放空间。

中断

中断机制减少轮询所带来的CPU高占用率

Poll

Poll机制解决解决阻塞问题。

信号通知

信号通知解决数据异步通知的问题

原子 信号量

原子与信号量机制解决操作同步所带来的问题。

驱动源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/irqreturn.h>
#include <linux/irqnr.h>
#include <linux/hardirq.h>
#include <linux/irqflags.h>
#include <linux/interrupt.h>
#include<mach/gpio.h>
#include<asm/io.h>
#include"mach/../../mx28_pins.h"
#include <mach/pinctrl.h>
#include "mach/mx28.h"
#include <linux/poll.h>
static struct class* first_cha_class;
static struct device* first_cha_device;
volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpfdat = NULL;
static struct fasync_struct* Key_fasync;
#define GPIO_BUTTON_PIN MXS_PIN_TO_GPIO(PINID_SSP0_DATA4)
int irq_no = 0;
int press_id = 1;
const char* irqname = "BoKey";
static DECLARE_WAIT_QUEUE_HEAD(btn_wait_queue);
static volatile int event_press = 0;
static int press_cnt = 0;
atomic_t open_flag = ATOMIC_INIT(1);
//atomic_read
//atomic_inc
//atomic_dec
//atom_dec_and_test
static ssize_t first_ch_read (struct file * pfile, char __user * puser, size_t cnt, loff_t * poff)
{
printk("read\n");
wait_event_interruptible(btn_wait_queue, event_press);
event_press = 0;
copy_to_user(puser, (const void*)&(press_cnt), 4);
return 0;
}
static ssize_t first_ch_write(struct file * pfile, const char __user * pusr, size_t cnt, loff_t * poff)
{
int val;
int count = 4;
printk("write\n");
copy_from_user(&val, pusr, count);
printk("the val is %d\n",val);
return 0;
}
static irqreturn_t key_handler(int irq, void *dev_id)
{
press_cnt += 1;
printk("K: key down %d\n", press_cnt);
event_press = 1;
wake_up_interruptible(&btn_wait_queue);
kill_fasync(&Key_fasync, SIGIO, POLL_IN);
return 0;
}
static int first_ch_open(struct inode * pnode, struct file * pfile)
{
int err = 0;
int iRet = 0;
if(atomic_read(&open_flag) != 1)
{
atomic_dec(&open_flag);
return -EBUSY;
}
printk("open\n");
gpio_free(GPIO_BUTTON_PIN); //先清除原先的复用功能
iRet = gpio_request(GPIO_BUTTON_PIN, "irqtest");
if (iRet != 0) {
printk("request gpio failed \n");
return -EBUSY;
}
gpio_direction_input(GPIO_BUTTON_PIN); //设置输入功能
irq_no = gpio_to_irq(GPIO_BUTTON_PIN); //得到中断号
set_irq_type(irq_no, IRQF_TRIGGER_FALLING); //下降沿中断
err = request_irq(irq_no, key_handler, IRQF_TRIGGER_FALLING, irqname,(void*)&press_id);
printk("The err is %d\n", err);
return 0;
}
static unsigned int first_ch_poll(struct file *fp, poll_table * wait)
{
unsigned int mask = 0;
poll_wait(fp, &btn_wait_queue, wait);
if(event_press)
mask |= POLLIN | POLLRDNORM;
return mask;
}
static int first_ch_sync(int fd, struct file* filp, int on)
{
printk("Async Set\n");
return fasync_helper(fd, filp, on, &Key_fasync);
}
static struct file_operations first_ch_fops = {
.owner = THIS_MODULE,
.open = first_ch_open,
.read = first_ch_read,
.write = first_ch_write,
.poll = first_ch_poll,
.fasync = first_ch_sync,
};
int first_ch_init(void)
{
int major = 0;
major = register_chrdev(0, "first_drv", &first_ch_fops); //当输入为0时,由系统自动分配
printk("The major is %d\n", major);
first_cha_class = class_create(THIS_MODULE, "first_drv");
if(IS_ERR(first_cha_class))
{
printk("class create failed\n");
return -1;
}
first_cha_device = device_create(first_cha_class, NULL, MKDEV(major, 0), NULL, "first_cha");
if(IS_ERR(first_cha_device))
{
printk("create device failed\n");
return -1;
}
//gpfcon = (volatile unsigned long *)ioremap(0x56000000, 0x10);
//gpfdat = gpfcon + 1;
return 0;
}
//函数操作集合
void first_ch_exit(void)
{
device_unregister(first_cha_device);
class_destroy(first_cha_class);
//iounmap(gpfcon);
free_irq(irq_no,(void*)&press_id);
atomic_inc(&open_flag);
}
module_init(first_ch_init);
module_exit(first_ch_exit);
MODULE_LICENSE ("GPL");//开源协议GPL 或者Dual BSD
MODULE_AUTHOR ("TOM");//作者
MODULE_DESCRIPTION ("MY_TEST");//描述此驱动

Makefile

1
2
3
4
5
6
obj-m := first_cha.o
KDIR := /home/bo/Documents/linux-2.6.35.3
all:
make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-none-linux-gnueabi- ARCH=arm
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order

应用程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<poll.h>
#include <signal.h>
void My_SigFun(int nSigNum);
int main()
{
int fd;
int val = 1;
int nStatus = 0;
int Oflags;
struct pollfd pfd[1];
signal(SIGIO, My_SigFun);
fd = open("/dev/first_cha", O_RDWR);
if(fd < 0)
{
printf("open failed\n");
return -1;
}
//将当前进程PID设置为fd文件所对应驱动程序将要发送SIGIO,SIGUSR信号进程PID
fcntl(fd, F_SETOWN, getpid());
//获取fd的打开方式
Oflags = fcntl(fd, F_GETFL);
//将fd的打开方式设置为FASYNC --- 即 支持异步通知
//该行代码执行会触发 驱动程序中 file_operations->fasync 函数 ------fasync函数调用fasync_helper初始化一个fasync_struct结构体,该结构体描述了将要发送信号的进程PID (fasync_struct->fa_file->f_owner->pid)
fcntl(fd, F_SETFL, Oflags | FASYNC);
write(fd, &val, 4);
pfd[0].fd = fd;
pfd[0].events = POLLIN;
while(1)
{
nStatus = poll(pfd, 1, 5000);
if(nStatus == 0)
{
printf("timeout\n");
}
else
{
read(fd, &val);
printf("A: cnt: %d\n", val);
}
}
return 0;
}
void My_SigFun(int nSigNum) // kill -USR1 pid
{
printf("Get Sig\n");
}

版权声明:本文为博主原创文章,转载需声明为转载内容并添加原文地址。

原文地址:http://coderdock.com

Dock wechat
欢迎您扫一扫上面的微信公众号,订阅我的公众号