1. 电路图
2. 使用说明
代码语言:javascript
此驱动实现二种操作模式:
普通操作模式:./LedTest
掩码操作模式:./LedTest led_mask
led_mask只能是:000、001、010、011....111
可以同时设置三个LED,对应1位置的LED被点亮,对应0位置熄灭
3. 驱动代码
代码语言:javascript
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* Description of LED masks */
typedef enum{
LED_MASK_000,
LED_MASK_001,
LED_MASK_010,
LED_MASK_011,
LED_MASK_100,
LED_MASK_101,
LED_MASK_110,
LED_MASK_111,
LED_MASK_INIT,
}s3c2440_led_mask;
/* Describe the mode of operating LED */
typedef enum{
S3C2440_LED_MODE_MASK=0x11,
S3C2440_LED_MODE_GENERAL=0x22,
S3C2440_LED_MODE_INIT=0xff,
}s3c2440_led_mode;
/* Describe the operation of LED */
typedef enum{
S3C2440_LED_OP_ON=0x66,
S3C2440_LED_OP_OFF=0x88,
S3C2440_LED_OP_INIT=0xff,
}s3c2440_led_op;
/* Describe the position of the operating LED */
typedef enum{
S3C2440_LED_POS_GPF4,
S3C2440_LED_POS_GPF5,
S3C2440_LED_POS_GPF6,
S3C2440_LED_POS_INIT,
}s3c2440_led_pos;
/* Description of LED Mask Magic Number */
typedef enum{
S3C2440_BIT_MASK8=8,
S3C2440_BIT_MASK16=16,
}s3c2440_led_bit_mask;
#define FIRST_DRV_MAJOR 111
static struct class *first_drv_class;
static struct class_device *first_drv_class_dev;
volatile unsigned long *GPFCON = NULL;
volatile unsigned long *GPFDAT = NULL;
static int first_drv_open(struct inode *inode, struct file *file)
{
/* 配置 GPF4,5,6为输出 */
*GPFCON &= ~((0x3<<(4*2)) | (0x3<<(5*2)) | (0x3<<(6*2)));
*GPFCON |= ((0x1<<(4*2)) | (0x1<<(5*2)) | (0x1<<(6*2)));
return 0;
}
static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
int val;
s3c2440_led_mode mode = S3C2440_LED_MODE_INIT;
s3c2440_led_op op = S3C2440_LED_OP_INIT;
s3c2440_led_mask mask = LED_MASK_INIT;
s3c2440_led_pos led_pos = S3C2440_LED_POS_INIT;
copy_from_user(&val, buf, count); // copy_to_user
mode = val&0xff;
if(mode & S3C2440_LED_MODE_GENERAL)
{
led_pos = (val&0xff0000)>>S3C2440_BIT_MASK16;
op = (val&0xff00)>>S3C2440_BIT_MASK8;
}
else if(mode&S3C2440_LED_MODE_MASK)
{
mask = (val&0xff00)>>S3C2440_BIT_MASK8;
}
else
{
printk("[%s][%d]:s3c2440_led_mode is invalid!n", __FUNCTION__, __LINE__);
return -1;
}
if(mode==S3C2440_LED_MODE_MASK)
{
switch(mask)
{
case LED_MASK_000: *GPFDAT |= (1<<4) | (1<<5) | (1<<6); break;
case LED_MASK_001: *GPFDAT &= ~(1<<4); *GPFDAT |= (1<<5) | (1<<6); break;
case LED_MASK_010: *GPFDAT &= ~(1<<5); *GPFDAT |= (1<<4) | (1<<6); break;
case LED_MASK_011: *GPFDAT &= ~((1<<4) | (1<<5));*GPFDAT |= (1<<6); break;
case LED_MASK_100: *GPFDAT &= ~(1<<6);*GPFDAT |= (1<<4) | (1<<5); break;
case LED_MASK_101: *GPFDAT &= ~((1<<4) | (1<<6));*GPFDAT |= (1<<5); break;
case LED_MASK_110: *GPFDAT &= ~((1<<5) | (1<<6));*GPFDAT |= (1<<4); break;
case LED_MASK_111: *GPFDAT &= ~((1<<4) | (1<<5) | (1<<6)); break;
default:
printk("[%s][%d]:s3c2440_led_mask is invalid!n", __FUNCTION__, __LINE__);
return -1;
}
}
else
{
if(op==S3C2440_LED_OP_ON)
{
switch(led_pos)
{
case S3C2440_LED_POS_GPF4: *GPFDAT &= ~(1<<4); break;
case S3C2440_LED_POS_GPF5: *GPFDAT &= ~(1<<5); break;
case S3C2440_LED_POS_GPF6: *GPFDAT &= ~(1<<6); break;
default:
printk("[%s][%d]:s3c2440_led_pos is invalid!n", __FUNCTION__, __LINE__);
return -1;
}
}
else if(op==S3C2440_LED_OP_OFF)
{
switch(led_pos)
{
case S3C2440_LED_POS_GPF4: *GPFDAT |= (1<<4); break;
case S3C2440_LED_POS_GPF5: *GPFDAT |= (1<<5); break;
case S3C2440_LED_POS_GPF6: *GPFDAT |= (1<<6); break;
default:
printk("[%s][%d]:s3c2440_led_pos is invalid!n", __FUNCTION__, __LINE__);
return -1;
}
}
else
{
printk("[%s][%d]:s3c2440_led_op is invalid!n", __FUNCTION__, __LINE__);
return -1;
}
}
return 0;
}
static struct file_operations first_drv_fops = {
.owner = THIS_MODULE,
.open = first_drv_open,
.write = first_drv_write,
};
static int __init first_drv_init(void)
{
/* 主设备号, 名字(随便), file_operations结构 如果主设备号写0,就是让系统自动分配设备号 */
register_chrdev(FIRST_DRV_MAJOR, "first_drv", &first_drv_fops); /* 注册驱动程序 */
/* 在系统/sys/class/下创建一个名为first_drv的类 */
first_drv_class = class_create(THIS_MODULE, "first_drv");
if(IS_ERR(first_drv_class))
return PTR_ERR(first_drv_class);
/* 根据类,设备号,名字在/sys/class/first_drv/下创建名为xxx的设备 */
first_drv_class_dev = class_device_create(first_drv_class, NULL,
MKDEV(FIRST_DRV_MAJOR, 0), NULL, "xxx");
if(unlikely(IS_ERR(first_drv_class_dev)))
return PTR_ERR(first_drv_class_dev);
/* 映射寄存器 */
GPFCON = (volatile unsigned long *)ioremap(0x56000050, 16);
GPFDAT = GPFCON + 1;
return 0;
}
static void __exit first_drv_exit(void)
{
unregister_chrdev(FIRST_DRV_MAJOR, "first_drv"); /* 卸载驱动 */
class_device_unregister(first_drv_class_dev);
class_destroy(first_drv_class);
iounmap(GPFCON);
}
module_init(first_drv_init);
module_exit(first_drv_exit);
MODULE_LICENSE("GPL");
4. 测试代码
代码语言:javascript
#include
#include
#include
#include
/* compile: arm-linux-gcc -o FirstDrvTest FirstDrvTest.c */
#define DEV_DEVICE "/dev/xxx"
#define TRUE 1
#define FALSE 0
#define BUF_SIZE_32 32
#define ARRAY_SIZE(array) (sizeof(array)/sizeof((array)[0]))
typedef struct{
char input[BUF_SIZE_32];
unsigned char key;
}s3c2440_turn_key;
typedef enum{
LED_MASK_000,
LED_MASK_001,
LED_MASK_010,
LED_MASK_011,
LED_MASK_100,
LED_MASK_101,
LED_MASK_110,
LED_MASK_111,
LED_MASK_INIT,
}s3c2440_led_mask;
typedef enum{
S3C2440_LED_MODE_MASK=0x11,
S3C2440_LED_MODE_GENERAL=0x22,
S3C2440_LED_MODE_INIT=0xff,
}s3c2440_led_mode;
typedef enum{
S3C2440_LED_OP_ON=0x66,
S3C2440_LED_OP_OFF=0x88,
S3C2440_LED_OP_INIT=0xff,
}s3c2440_led_op;
typedef enum{
S3C2440_LED_POS_GPF4,
S3C2440_LED_POS_GPF5,
S3C2440_LED_POS_GPF6,
S3C2440_LED_POS_INIT,
}s3c2440_led_pos;
typedef enum{
S3C2440_BIT_MASK8=8,
S3C2440_BIT_MASK16=16,
}s3c2440_led_bit_mask;
typedef unsigned int BOOL;
static BOOL check_led_turn_is_legal(s3c2440_turn_key *map,
s3c2440_turn_key *map_array, int map_array_len);
int main(int argc, char *argv[])
{
int fd, val=0;
s3c2440_led_mode mode=S3C2440_LED_MODE_INIT;
s3c2440_led_mask mask=LED_MASK_INIT;
s3c2440_led_pos led_pos=S3C2440_LED_POS_INIT;
s3c2440_led_op op=S3C2440_LED_OP_INIT;
s3c2440_turn_key input_map, led_map, op_map;
s3c2440_turn_key s3c2440_key_map[]={
{
"000", 0},
{
"001", 1},
{
"010", 2},
{
"011", 3},
{
"100", 4},
{
"101", 5},
{
"110", 6},
{
"111", 7},
};
s3c2440_turn_key s3c2440_led_map[]={
{
"led1", S3C2440_LED_POS_GPF4},
{
"led2", S3C2440_LED_POS_GPF5},
{
"led3", S3C2440_LED_POS_GPF6},
};
s3c2440_turn_key s3c2440_op_map[]={
{
"on", S3C2440_LED_OP_ON},
{
"off", S3C2440_LED_OP_OFF},
};
if(argc==3 || argc==2)
;
else
goto usage_error;
switch(argc)
{
case 2: mode=S3C2440_LED_MODE_MASK; break;
case 3: mode=S3C2440_LED_MODE_GENERAL; break;
}
fd = open(DEV_DEVICE, O_RDWR);
if(fd<0)
goto open_error;
switch(mode)
{
case S3C2440_LED_MODE_MASK:
val |= S3C2440_LED_MODE_MASK;
strncpy(input_map.input, argv[1], sizeof(input_map.input));
if(check_led_turn_is_legal(&input_map, s3c2440_key_map, ARRAY_SIZE(s3c2440_key_map))==TRUE)
mask=input_map.key;
else
goto led_mask_error;
val |= (mask<
break;
case S3C2440_LED_MODE_GENERAL:
strncpy(led_map.input, argv[1], sizeof(led_map.input));
if(check_led_turn_is_legal(&led_map,
s3c2440_led_map, ARRAY_SIZE(s3c2440_led_map))==TRUE)
led_pos = led_map.key;
else
goto led_number_error;
strncpy(op_map.input, argv[2], sizeof(op_map.input));
if(check_led_turn_is_legal(&op_map,
s3c2440_op_map, ARRAY_SIZE(s3c2440_op_map))==TRUE)
op = op_map.key;
else
goto input_cmd_error;
val |= S3C2440_LED_MODE_GENERAL;
val |= (op<
val |= (led_pos<
break;
}
printf("val=0x%xn", val);
write(fd, &val, sizeof(val));
close(fd);
return 0;
usage_error:
printf("Usage:%s led_maskn", argv[0]);
printf("Usage:%s
goto ret_error;
open_error:
fprintf(stderr, "open %s fail!n", DEV_DEVICE);
goto ret_error;
led_mask_error:
fprintf(stderr, "led mask error!n");
close(fd);
goto ret_error;
led_number_error:
fprintf(stderr, "led number error!n");
close(fd);
goto ret_error;
input_cmd_error:
close(fd);
fprintf(stderr, "input cmd error!n");
goto ret_error;
ret_error:
return -1;