嵌入式LINUX驱动学习之8竞态和并发相关问题(一)中断屏蔽
一、中断屏蔽的方法头文件及说明
#define local_irq_save(flags) \
do { \
raw_local_irq_save(flags); \
} while (0)
#define local_irq_restore(flags) do { raw_local_irq_restore(flags); } while (0)
二、代码举例(内核空间)
include < linux/ init. h>
#include <linux/module.h>
#include <cfg_type.h>
#include <linux/gpio.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
struct led_src {
char * name;
int gpio;
} ;
struct led_src led_info[ ] = {
{
. name = "LED1" ,
. gpio = PAD_GPIO_B + 26
} ,
{
. name = "LED2" ,
. gpio = PAD_GPIO_C + 11
} ,
{
. name = "LED3" ,
. gpio = PAD_GPIO_C + 7
} ,
{
. name = "LED4" ,
. gpio = PAD_GPIO_C + 12
}
} ;
int file_open_state = 1 ;
int led_open_state = 1 ;
static int led_open ( struct inode * inode , struct file * file) {
unsigned long flags;
local_irq_save ( flags) ;
if ( -- file_open_state) {
printk ( "设备已经被打开\n" ) ;
fil_open_state ++ ;
local_irq_restore ( flags) ;
return - EBUSY;
}
local_irq_restore ( flags) ;
printk ( "设备文件打开成功\n" ) ;
return 0 ;
}
static int led_close ( struct inode * inode, struct file * file) {
unsigned long flags;
local_irq_save ( flags) ;
file_open_state = 1 ;
local_irq_restore ( flags) ;
printk ( "设备文件关闭\n" ) ;
return 0 ;
}
void led_on ( unsigned int num) {
if ( gpio_get_value ( led_info[ num- 1 ] . gpio) ) {
gpio_set_value ( led_info[ num- 1 ] . gpio, 0 ) ;
printk ( "%s开启\n" , led_info[ num- 1 ] . name) ;
}
else
printk ( "%s已经开启\n" , led_info[ num- 1 ] . name) ;
}
void led_off ( unsigned int num) {
if ( gpio_get_value ( led_info[ num- 1 ] . gpio) )
printk ( "%s已经关闭\n" , led_info[ num- 1 ] . name) ;
else {
gpio_set_value ( led_info[ num- 1 ] . gpio, 1 ) ;
printk ( "%s关闭完成\n" , led_info[ num- 1 ] . name) ;
}
}
void led_state ( unsigned long kbuf[ 4 ] ) {
int i = 0 ;
if ( kbuf[ 0 ] ) {
kbuf[ 0 ] = gpio_get_value ( led_info[ kbuf[ 0 ] - 1 ] . gpio) ;
}
else {
for ( ; i < ARRAY_SIZE ( led_info) ; i++ ) {
kbuf[ i] = gpio_get_value ( led_info[ i] . gpio) ;
}
}
}
#define LED_ON 0X100
#define LED_OFF 0X101
#define LED_STATE 0X110
static long led_ioctl ( struct file * file , unsigned int ucmd , \
unsigned long ubuf) {
unsigned long kbuf[ 4 ] ;
unsigned int kcmd = ucmd;
copy_from_user ( kbuf, ( unsigned long * ) ubuf, sizeof ( int ) * 4 ) ;
printk ( "kcmd : %u , kbuf[0] : %lu\n" , kcmd , kbuf[ 0 ] ) ;
switch ( kcmd) {
case LED_ON :
led_on ( kbuf[ 0 ] ) ;
break ;
case LED_OFF :
led_off ( kbuf[ 0 ] ) ;
break ;
case LED_STATE :
led_state ( kbuf) ;
copy_to_user ( ( unsigned long * ) ubuf, kbuf, sizeof ( long ) * 4 ) ;
default :
break ;
}
return 0 ;
}
struct file_operations led_fops = {
. owner = THIS_MODULE,
. open = led_open,
. release = led_close,
. unlocked_ioctl = led_ioctl
} ;
struct miscdevice misc_fops = {
. minor = MISC_DYNAMIC_MINOR,
. fops = & led_fops,
. name = "myled_drv"
} ;
static int led_int ( void ) {
int i = 0 ;
for ( ; i < ARRAY_SIZE ( led_info) ; i++ ) {
gpio_request ( led_info[ i] . gpio, led_info[ i] . name) ;
gpio_direction_output ( led_info[ i] . gpio, 1 ) ;
}
misc_register ( & misc_fops) ;
return 0 ;
}
static void led_exit ( void ) {
int i = 0 ;
for ( ; i< ARRAY_SIZE ( led_info) ; i++ ) {
gpio_set_value ( led_info[ i] . gpio, 1 ) ;
gpio_free ( led_info[ i] . gpio) ;
}
misc_deregister ( & misc_fops) ;
}
module_init ( led_int) ;
module_exit ( led_exit) ;
MODULE_LICENSE ( "GPL" ) ;
三、代码举例(用户空间)
#include <stdio.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#define LED_ON 0X100
#define LED_OFF 0X101
#define LED_STATE 0X110
void led_state_printf ( int num, int ubuf[ 4 ] ) {
int i = 0 ;
if ( num)
printf ( "LED%d灯状态为%s\n" , num, ubuf[ 0 ] ? "关闭" : "打开" ) ;
else
for ( ; i < 4 ; i++ )
printf ( "LED%d灯状态为%s\n" , i + 1 , ubuf[ i] ? "关闭" : "打开" ) ;
}
int main ( int argc , char * argv[ ] ) {
int ubuf[ 4 ] = { 0 } ;
int ucmd = 0 ;
unsigned long tmp_state_num = 0 ;
if ( ( argc < 3 ) || ( argc > 4 ) ) {
goto err;
}
int fp = open ( argv[ 1 ] , O_RDWR) ;
if ( fp < 0 ) {
printf ( "打开文件失败!\n" ) ;
return - 1 ;
}
if ( argc == 4 ) {
ubuf[ 0 ] = strtoul ( argv[ 3 ] , NULL , 0 ) ;
tmp_state_num = ubuf[ 0 ] ;
if ( ( ubuf[ 0 ] > 4 ) || ( ubuf[ 0 ] < 1 ) ) {
printf ( "LED灯编号为:LED1 ~ 4\n" ) ;
return - 1 ;
}
}
if ( ( argc == 3 ) && \
( ! strcmp ( argv[ 2 ] , "state" ) ) ) {
ucmd= LED_STATE;
}
else if ( argc == 4 ) {
if ( ! strcmp ( argv[ 2 ] , "on" ) )
ucmd = LED_ON;
else if ( ! strcmp ( argv[ 2 ] , "off" ) )
ucmd = LED_OFF;
else if ( ! strcmp ( argv[ 2 ] , "state" ) )
ucmd = LED_STATE;
else
goto err;
}
else {
goto err;
}
ioctl ( fp, ucmd, ubuf) ;
if ( ! strcmp ( argv[ 2 ] , "state" ) )
led_state_printf ( tmp_state_num, ubuf) ;
sleep ( 30 ) ;
close ( fp) ;
return 0 ;
err:
printf ( "命令错误!\n" ) ;
printf ( " comm <cdev_name> <state>\n" ) ;
printf ( " comm <cdev_name> <state> <led_num>\n" ) ;
printf ( " comm <cdev_name> <on|off> <led_num>\n" ) ;
return - 1 ;
}
四、测试
/drivers/test
/drivers/test
设备文件打开成功
kcmd : 256 , kbuf[ 0] : 1
LED1开启
/drivers/test
设备已经被打开
打开文件失败
/drivers/test
/drivers/test
设备文件打开成功
kcmd : 256 , kbuf[ 0] : 2
LED2开启