/*说明:通过OK6410开发板自带的user key 的前四个控制led的开关,对应的,按key1,led1亮,亲自验证无误*/
#include
#include
#include
#include
#include /*包含struct file_operations,MAJOR等*/
#include /*kmalloc*/
#include /*class_creat,device_creat*/
#include /*ioread8...*/
#include /*s3c_gpio_cfgpin*/
#include /*gpio_set_value*/
#include /*request_irq()*/
#include /*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;icdev);
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 ");
module_init(key_init);
module_exit(key_exit);