/*说明:通过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);

GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐