您的位置:首页 > 运维架构 > Linux

Linux驱动开发--通过按键控制led灯

2013-06-10 20:53 453 查看
/*说明:通过OK6410开发板自带的user key 的前四个控制led的开关,对应的,按key1,led1亮,亲自验证无误*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>/*包含struct file_operations,MAJOR等*/
#include <linux/slab.h>/*kmalloc*/
#include <linux/device.h>/*class_creat,device_creat*/
#include <asm/io.h>/*ioread8...*/
#include <plat/gpio-cfg.h>/*s3c_gpio_cfgpin*/
#include <linux/gpio.h>/*gpio_set_value*/
#include <linux/interrupt.h>/*request_irq()*/
#include <linux/workqueue.h>/*work_struct*/

#define KEY_MAJOR 125
#define KEY_COUNT 4
#define DEVICE_NAME "key_led"

int key_major=KEY_MAJOR;

struct KEY{
int irq;
unsigned long flags;
char* name;
};
static struct KEY key[]={
{IRQ_EINT(0),IRQF_TRIGGER_LOW,"key1"},
{IRQ_EINT(1),IRQF_TRIGGER_LOW,"key2"},
{IRQ_EINT(2),IRQF_TRIGGER_LOW,"key3"},
{IRQ_EINT(3),IRQF_TRIGGER_LOW,"key4"},
};

struct KEY_DEV{
struct cdev cdev;
struct class* key_class;
struct work_struct key_workstruct;
int value;
};

struct KEY_DEV *key_dev;

int  key_open(struct inode* inode,struct file* filp)
{
struct KEY_DEV* dev;
dev=container_of(inode->i_cdev,struct KEY_DEV,cdev);
filp->private_data=dev;
return 0;
}

int  key_release(struct inode* inode,struct file* filp)
{
return 0;
}

ssize_t key_read(struct file* filp,char __user *buf,size_t count,loff_t *f_pos)
{
return 0;
}

ssize_t key_write(struct file *filp,const char __user *buf,size_t count,loff_t *f_pos)
{
return 0;
}

long key_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
{
struct KEY_DEV *key_dev=filp->private_data;
switch(cmd){
default:
return -ENOTTY;
}
return 0;
}

struct file_operations key_fops={
.owner=THIS_MODULE,
.open=key_open,
.read=key_read,
.write=key_write,
.unlocked_ioctl=key_ioctl,
.release=key_release,
};

void init_led(void)
{
int i;
s3c_gpio_cfgpin_range(S3C64XX_GPM(0),S3C64XX_GPM(3),S3C_GPIO_SFN(1));
for(i=0;i<4;i++){
gpio_set_value(S3C64XX_GPM(i),1);
}
for(i=0;i<4;i++){
s3c_gpio_setpull(S3C64XX_GPM(i),S3C_GPIO_PULL_NONE);
}
}

void led_on(int led_no)
{
switch(led_no)
{
case 1:
gpio_set_value(S3C64XX_GPM(0),0);
break;
case 2:
gpio_set_value(S3C64XX_GPM(1),0);
break;
case 3:
gpio_set_value(S3C64XX_GPM(2),0);
break;
case 4:
gpio_set_value(S3C64XX_GPM(3),0);
break;
default:
break;

}
}

irqreturn_t key_interrupt(int irq,void* dev_id)
{
switch(irq){
case IRQ_EINT(0):
key_dev->value=IRQ_EINT(0);
schedule_work(&(key_dev->key_workstruct));
break;
case IRQ_EINT(1):
key_dev->value=IRQ_EINT(1);
schedule_work(&(key_dev->key_workstruct));
break;
case IRQ_EINT(2):
key_dev->value=IRQ_EINT(2);
schedule_work(&(key_dev->key_workstruct));
break;
case IRQ_EINT(3):
key_dev->value=IRQ_EINT(3);
schedule_work(&(key_dev->key_workstruct));
break;
default:
schedule_work(&(key_dev->key_workstruct));
break;
}
return IRQ_HANDLED;
}

void do_workstruct(struct work_struct *work)
{
struct KEY_DEV* dev=container_of(work,struct KEY_DEV,key_workstruct);
init_led();
switch(dev->value)
{
case IRQ_EINT(0):
led_on(1);
break;
case IRQ_EINT(1):
led_on(2);
break;
case IRQ_EINT(2):
led_on(3);
break;
case IRQ_EINT(3):
led_on(4);
break;
default:
break;
}
printk("has key\n");
}

static int __init key_init(void)
{
int result,i;
dev_t devno;
if(KEY_MAJOR){
devno=MKDEV(KEY_MAJOR,0);
result=register_chrdev_region(devno,1,DEVICE_NAME);
}else{
result=alloc_chrdev_region(&devno,0,1,DEVICE_NAME);
key_major=MAJOR(devno);
}
if(result<0){
printk(KERN_WARNING "ERROR: can not register\n");
return result;
}

key_dev=kmalloc(sizeof(struct KEY_DEV),GFP_KERNEL);
if(!key_dev){
result=-ENOMEM;
goto fail;
}
memset(key_dev,0,sizeof(struct KEY_DEV));
cdev_init(&key_dev->cdev,&key_fops);
key_dev->cdev.owner=THIS_MODULE;
result=cdev_add(&key_dev->cdev,devno,1);
if(result){
printk(KERN_WARNING "ERROR: can not add cdev\n");
goto fail;
}
key_dev->key_class= class_create(THIS_MODULE,"key_class");

if(IS_ERR(key_dev->key_class)){
printk("Err: failed increating class.\n");
return -1;
}
device_create(key_dev->key_class, NULL, devno,NULL,DEVICE_NAME);

INIT_WORK(&(key_dev->key_workstruct),do_workstruct);
for(i=0;i<KEY_COUNT;i++){
result=request_irq(key[i].irq,key_interrupt,key[i].flags,key[i].name,(void *)devno);
if(result){
printk(KERN_ERR"request irq failed!\n");
return -1;
}
}
return 0;
fail:
unregister_chrdev_region(devno,1);
return result;
}

static void __exit key_exit(void)
{
dev_t devno=MKDEV(key_major,0);

free_irq(IRQ_EINT(0),key_interrupt);

if(key_dev){
cdev_del(&key_dev->cdev);
kfree(key_dev);
}
device_destroy(key_dev->key_class,devno);
class_destroy(key_dev->key_class);
unregister_chrdev_region(devno,1);
}

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("yixuaning <yixuaning@sina.com>");
module_init(key_init);
module_exit(key_exit);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: