#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/semaphore.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
#include <mach/hardware.h>
#include <mach/regs-gpio.h>
#include <mach/regs-gpioj.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/delay.h>
#include "key_io.h"
#define KEY_MAJOR 0 // 定义主设备号 0--自动分配 非零手动分配
#define KEY_MINOR 0 // 定义次设备号 一般由0开始
typedef struct
{
struct cdev cdev; // 字符设备结构体
struct class *cls;
struct device *dev;
struct rw_semaphore rw_sem;
struct timer_list timer;
struct work_struct key_work;
u16 key_data;
u16 key_bak_data;
u32 key_count;
} ST_S3C_KEY_DRV, *LPST_S3C_KEY_DRV;
static int key_open(struct inode *inode, struct file *filp);
static int key_release(struct inode *inode, struct file *filp);
static ssize_t key_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos);
static void key_work_handler(struct work_struct *work);
static inline u16 to_real_key_val(u32 ch);
static inline void key_setup_pin(void);
static void timer_handler(unsigned long data);
static int key_major = KEY_MAJOR;
static int key_minor = KEY_MINOR;
static int key_nr_devs = 1; // 字符设备的个数
static const char key_dev_name[] = "s3c_key"; // 注册的名称
ST_S3C_KEY_DRV *pstS3ckeyDrv = NULL;
//文件操作结构体
static const struct file_operations key_fops =
{
.owner = THIS_MODULE,
.read = key_read,
.open = key_open,
.release = key_release,
};
static int __init s3c_key_init(void)
{
int err;
dev_t devno = MKDEV(key_major, 0);
/***********************申请字符设备************************/
if(key_major)
{// 手动申请
err = register_chrdev_region(devno, key_nr_devs, key_dev_name);
}
else
{// 内核自动申请
err = alloc_chrdev_region(&devno, key_minor, key_nr_devs, key_dev_name);
key_major = MAJOR(devno);
}
if (err < 0)
{
printk("s3c_key can't get the major %d\n", key_major);
return err;
}
else
{
printk(KERN_DEBUG "s3c_key success get the major is %d\n", key_major);
}
/**************注册字符设备的具体方法**********************/
pstS3ckeyDrv = kmalloc(sizeof(ST_S3C_KEY_DRV), GFP_KERNEL);
if (pstS3ckeyDrv == NULL)
{
err = -ENOMEM;
goto fail_malloc;
}
memset(pstS3ckeyDrv, 0, sizeof(ST_S3C_KEY_DRV));
cdev_init(&pstS3ckeyDrv->cdev, &key_fops); // 与文件操作函数关联起来
pstS3ckeyDrv->cdev.owner = THIS_MODULE;
init_rwsem(&pstS3ckeyDrv->rw_sem);
INIT_WORK(&pstS3ckeyDrv->key_work, key_work_handler);
init_timer(&pstS3ckeyDrv->timer);
//add 后所有方法生效 在此之前进一步设置硬件
key_setup_pin();
pstS3ckeyDrv->key_data = to_real_key_val(0);
pstS3ckeyDrv->key_bak_data = to_real_key_val(0);
pstS3ckeyDrv->key_count = 10;
err = cdev_add(&pstS3ckeyDrv->cdev, devno, 1);
if (err < 0)
{
printk("cdev_add fail\n");
goto fail_cdev_add;
}
// 为proc文件系统 创建一个设备类
pstS3ckeyDrv->cls = class_create(THIS_MODULE, key_dev_name);
// 为该类 创建一个设备
pstS3ckeyDrv->dev = device_create(pstS3ckeyDrv->cls, NULL,
MKDEV(key_major, 0), NULL,
"%s", "s3c_key_dev");
pstS3ckeyDrv->timer.function = timer_handler;
pstS3ckeyDrv->timer.data = (unsigned long)pstS3ckeyDrv;
pstS3ckeyDrv->timer.expires = jiffies + (10 * HZ / 1000); // 10ms为单位
add_timer(&pstS3ckeyDrv->timer);
return 0;
fail_cdev_add:
kfree(pstS3ckeyDrv);
fail_malloc:
unregister_chrdev_region(MKDEV(key_major, key_minor),key_nr_devs);
return err;
}
static void __exit s3c_key_exit(void)
{
del_timer(&pstS3ckeyDrv->timer);
cdev_del(&pstS3ckeyDrv->cdev);
unregister_chrdev_region(MKDEV(KEY_MAJOR, KEY_MINOR),
key_nr_devs);
device_destroy(pstS3ckeyDrv->cls, MKDEV(KEY_MAJOR, 0));
class_destroy(pstS3ckeyDrv->cls);
kfree(pstS3ckeyDrv);
printk(KERN_DEBUG "s3c_di exit...\n");
}
static int key_open(struct inode *inode, struct file *filp)
{
return 0;
}
static int key_release(struct inode *inode, struct file *filp)
{
return 0;
}
static ssize_t key_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
if (size != sizeof(u16))
{
//printk("size error\n");
return -EINVAL;
}
down_read(&pstS3ckeyDrv->rw_sem);
if (copy_to_user(buf, &pstS3ckeyDrv->key_data, sizeof(u16)))
{
up_read(&pstS3ckeyDrv->rw_sem);
//printk("copy_to_user error\n");
return -EBUSY;
}
else
{
up_read(&pstS3ckeyDrv->rw_sem);
//printk("copy_to_user success\n");
return sizeof(u16);
}
}
static inline u16 to_real_key_val(u32 ch)
{
if (ch >= 0 && ch <= 3)
{
if (s3c2410_gpio_getpin(S3C2410_GPF4 + ch))
{
return 500;
}
else
{
return 0;
}
}
else
{// 超出范围 返回高电平
return 500;
}
}
static void key_work_handler(struct work_struct *work)
{
LPST_S3C_KEY_DRV pS3cDiDrv = container_of(work, ST_S3C_KEY_DRV, key_work);
pS3cDiDrv->key_bak_data = to_real_key_val(0);
// 获取读锁
down_read(&pS3cDiDrv->rw_sem);
if (pS3cDiDrv->key_bak_data != pS3cDiDrv->key_data)
{
up_read(&pS3cDiDrv->rw_sem);
if (pS3cDiDrv->key_count)
{
pS3cDiDrv->key_count -= 1;
if (pS3cDiDrv->key_count == 0)
{// 更新key_data
down_write(&pS3cDiDrv->rw_sem);
pS3cDiDrv->key_data = pS3cDiDrv->key_bak_data;
up_write(&pS3cDiDrv->rw_sem);
}
}
}
else
{
up_read(&pS3cDiDrv->rw_sem);
pS3cDiDrv->key_count = 10;
}
}
static void timer_handler(unsigned long data)
{
LPST_S3C_KEY_DRV pS3cDiDrv = (LPST_S3C_KEY_DRV)data;
schedule_work(&pS3cDiDrv->key_work);
mod_timer(&pS3cDiDrv->timer, jiffies + (10 * HZ / 1000));
}
static inline void key_setup_pin(void)
{
// 4路DI输入 //
// 9
s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_INP); // 设置为输入
s3c2410_gpio_pullup(S3C2410_GPF4, 0); // 设置为内部上拉
// 10
//s3c2410_gpio_cfgpin(S3C2440_GPJ10, S3C2440_GPJ10_INP); // 设置为输入
//s3c2410_gpio_pullup(S3C2440_GPJ10, 0); // 设置为内部上拉
// 11
//s3c2410_gpio_cfgpin(S3C2440_GPJ11, S3C2440_GPJ11_INP); // 设置为输入
//s3c2410_gpio_pullup(S3C2440_GPJ11, 0); // 设置为内部上拉
// 12
//s3c2410_gpio_cfgpin(S3C2440_GPJ12, S3C2440_GPJ12_INP); // 设置为输入
//s3c2410_gpio_pullup(S3C2440_GPJ12, 0); // 设置为内部上拉
}
module_init(s3c_key_init);
module_exit(s3c_key_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("henry");