相关源码在资源中下载。
信号量实现互斥的一个方法。
只有得到信号量的进程才能执行临界区的代码,当得不到信号量时,进程会进入休眠等待状态。
用到的函数,结构体及其他:
/*定义并初始化信号量*/
DECLARE_MUTEX(name)
/*获得信号量,此时进程处于D状态,
*进程处于睡眠状态,但是此刻进程是不可中断的。
*不可中断,指的并不是CPU不响应外部硬件的中断,而是指进程不响应异步信号。
*/
void down(struct semaphore *sem)
/*释放信号量*/
void up(struct semaphore *sem)
驱动程序:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*不同的linux版本,头文件会有所不同*/
static int major;
/*定义一个类*/
static struct class *second_key_class;
/*定义一个设备*/
static struct device *second_key_device;
/*定义一个等待的头文件*/
static DECLARE_WAIT_QUEUE_HEAD(button_wait_head);
/*定义一个定时器*/
struct timer_list second_key_timer;
/*中断事件标志*/
static int ev_press=0;
static unsigned int key_val;
static struct fasync_struct *fasync_q;
/*定义信号量并初始化*/
static DECLARE_MUTEX(button_sem);
/*定义一个引脚描述的结构体*/
struct pindec
{
unsigned int pin;
unsigned int val;
};
/*定义引脚描述的数组,
*松开按键时,值为;0x01,0x02,0x03,0x04
*按下按键时,值为; 0x81,0x82,0x83,0x84*/
static struct pindec pin_dec[4]={
{S3C2410_GPF1,0x01},
{S3C2410_GPF4,0x02},
{S3C2410_GPF2,0x03},
{S3C2410_GPF0,0x04},
};
static struct pindec *irq_dec;
static irqreturn_t button_irq(int irq,void *dev)
{
irq_dec = (struct pindec*)dev;
/*修改定时器的超时时间*/
mod_timer(&second_key_timer,jiffies+HZ/100);
return IRQ_RETVAL(IRQ_HANDLED);
}
static int second_key_fasync_open(struct inode *inode, struct file *file)
{
/*获取信号量*/
down(&button_sem);
/*注册中断*/
request_irq(IRQ_EINT1,button_irq,IRQ_TYPE_EDGE_BOTH,"s1",&pin_dec[0]);
request_irq(IRQ_EINT4,button_irq,IRQ_TYPE_EDGE_BOTH,"s2",&pin_dec[1]);
request_irq(IRQ_EINT2,button_irq,IRQ_TYPE_EDGE_BOTH,"s3",&pin_dec[2]);
request_irq(IRQ_EINT0,button_irq,IRQ_TYPE_EDGE_BOTH,"s4",&pin_dec[3]);
return 0;
}
static ssize_t second_key_fasync_read(struct file *file, char __user *user_buffer,
size_t count, loff_t *ppos)
{
if(count != 1)
return -EINVAL;
/*ev_press中断标志为0,休眠,即未发生中断时,休眠*/
wait_event_interruptible(button_wait_head,ev_press);
/*传数据到用户空间*/
copy_to_user(user_buffer,&key_val,1);
/*中断结束,中断标志置0,休眠*/
ev_press = 0;
return 1;
}
static unsigned int second_key_poll(struct file *file,
struct poll_table_struct*wait)
{
unsigned int mask = 0;
/*挂载到队列中去*/
poll_wait(file, &button_wait_head, wait);
if(ev_press)
mask = POLLIN; /*普通或优先级带数据可读*/
return mask;
}
static int second_key_fasync(int fd, struct file * file, int on)
{
int result;
result = fasync_helper(fd, file, on, &fasync_q);
return (result);
}
static int second_key_fasync_close(struct inode *inode, struct file *file)
{
free_irq(IRQ_EINT1,&pin_dec[0]);
free_irq(IRQ_EINT4,&pin_dec[1]);
free_irq(IRQ_EINT2,&pin_dec[2]);
free_irq(IRQ_EINT0,&pin_dec[3]);
/*释放信号量*/
up(&button_sem);
return 0;
}
void second_timer_function(unsigned long data)
{
unsigned int pinval;
struct pindec *pin_desc =irq_dec;
/*获得引脚状态*/
pinval=s3c2410_gpio_getpin(pin_desc->pin);
if(pinval)
key_val = pin_desc->val;
else
key_val = pin_desc->val|0x80;
/*唤醒*/
ev_press = 1;
wake_up_interruptible(&button_wait_head);
kill_fasync(&fasync_q, SIGIO, POLL_IN);
}
/*定义一个file_operations结构*/
static struct file_operations second_key_fasync_fops = {
.owner = THIS_MODULE,
.open = second_key_fasync_open,
.read = second_key_fasync_read,
.poll = second_key_poll,
.release = second_key_fasync_close,
.fasync= second_key_fasync,
};
static int second_key_init(void)
{
/*注册*/
major = register_chrdev(0,"second_key",&second_key_fasync_fops);
/*创建类在/sys/class可以查找到*/
second_key_class = class_create(THIS_MODULE,"second_key_class");
/*类下创建设备可以在/sys/class/second_key_class可以查找到*/
second_key_device =
device_create(second_key_class,NULL,MKDEV(major,0),NULL,"second_key_device");
/*初始化定时器*/
init_timer(&second_key_timer);
second_key_timer.function = second_timer_function;
/*启动定时器*/
add_timer(&second_key_timer);
return 0;
}
static void second_key_exit(void)
{
/*注销*/
unregister_chrdev(major,"second_key");
/*删除定时器*/
del_timer(&second_key_timer);
/*注销类*/
device_unregister(second_key_device);
/*销毁定义的类*/
class_destroy(second_key_class);
}
/*修饰*/
module_init(second_key_init);
module_exit(second_key_exit);
MODULE_LICENSE("GPL");
测试程序:
#include
#include
#include
#include
int fd;
/*接到信号调用的函数*/
void my_signal_fun(int signum)
{
static char key_val;
read(fd,&key_val,1);
printf("key_val: 0x%x\n",key_val);
}
int main(int argc,char **argv){
int oflags;
fd=open("/dev/second_key_device",O_RDWR);
if(fd<0)
printf("can't open!\n");
/*void (*signal)(int signo,void(*func)(int))(int )
*signo : 信号名,func;信号处理程序
*/
signal(SIGIO,my_signal_fun);
/*F_SETOWN设置接收SIGIO和SIGURG信号的进程ID*/
fcntl(fd,F_SETOWN,getpid());
/*F_GETFL 获得文件状态标志 */
oflags = fcntl(fd,F_GETFL);
/*F_SETFL设置文件状态标志*/
fcntl(fd,F_SETFL,oflags | FASYNC);
while(1){
sleep(1000);
}
return 0;
}