=============================================================================== Driver Name : drv_keys Author : DRAAPHO License : GPL Description : LINUX DEVICE DRIVER PROJECT =============================================================================== */
#include"drv_keys.h"
#define DRV_KEYS_N_MINORS 1 #define DRV_KEYS_FIRST_MINOR 0 #define DRV_KEYS_NODE_NAME "key" #define DRV_KEYS_BUFF_SIZE 1024
MODULE_LICENSE("GPL"); MODULE_AUTHOR("DRAAPHO");
int drv_keys_major=0; dev_t drv_keys_device_num; struct class *drv_keys_class; struct fasync_struct *keys_async; static DECLARE_MUTEX(keys_lock);
typedef struct privatedata { int nMinor; struct cdev cdev; struct device *drv_keys_device; } drv_keys_private;
drv_keys_private devices[DRV_KEYS_N_MINORS];
static DECLARE_WAIT_QUEUE_HEAD(key_waitq); static volatile int ev_press = 0; static unsigned char keys_val; struct pin_desc * pindesc; struct timer_list keys_timer;
struct pin_desc { unsigned int pin; unsigned int key_val; };
struct pin_desc pins_desc[3] = { {S3C2410_GPF0, 0x01}, {S3C2410_GPF2, 0x02}, {S3C2410_GPG3, 0x04}, };
static irqreturn_t keys_irq(int irq, void *dev_id) { PINFO("keys_irq, irq=%d\n", irq); pindesc = (struct pin_desc *)dev_id; mod_timer(&keys_timer, jiffies+HZ/100); return IRQ_RETVAL(IRQ_HANDLED); }
static void keys_wait_10ms(unsigned long data) { unsigned int pinval;
if (!pindesc) return;
pinval = s3c2410_gpio_getpin(pindesc->pin); if (pinval) { keys_val &= ~pindesc->key_val; } else { keys_val |= pindesc->key_val; }
ev_press = 1; wake_up_interruptible(&key_waitq); kill_fasync(&keys_async, SIGIO, POLL_IN); }
static int drv_keys_open(struct inode *inode,struct file *filp) { if (filp->f_flags & O_NONBLOCK) { if (down_trylock(&keys_lock)) return -EBUSY; } else { down(&keys_lock); }
int ret; drv_keys_private *priv = container_of(inode->i_cdev , drv_keys_private ,cdev); filp->private_data = priv; PINFO("drv_keys_open\n");
ret = request_irq(IRQ_EINT0, keys_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]); ret |= request_irq(IRQ_EINT2, keys_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]); ret |= request_irq(IRQ_EINT11, keys_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
setup_timer(&keys_timer, keys_wait_10ms, 0); add_timer(&keys_timer);
if (ret) return -EINVAL; else return 0; }
static int drv_keys_release(struct inode *inode,struct file *filp) { drv_keys_private *priv; priv=filp->private_data; PINFO("drv_keys_release\n");
del_timer_sync(&keys_timer); free_irq(IRQ_EINT11, &pins_desc[2]); free_irq(IRQ_EINT2, &pins_desc[1]); free_irq(IRQ_EINT0, &pins_desc[0]);
up(&keys_lock); return 0; }
static ssize_t drv_keys_read(struct file *filp, char __user *ubuff,size_t count,loff_t *offp) { drv_keys_private *priv; priv = filp->private_data; PINFO("drv_keys_read()\n");
if (count != 1) return -EINVAL;
if (filp->f_flags & O_NONBLOCK) { if (!ev_press) return -EAGAIN; } else { wait_event_interruptible(key_waitq, ev_press); }
ev_press = 0; if (copy_to_user(ubuff, &keys_val, 1)) { return -EFAULT; } return 1; }
static unsigned drv_keys_poll(struct file *file, poll_table *wait) { unsigned int mask = 0; poll_wait(file, &key_waitq, wait);
if (ev_press) mask |= POLLIN | POLLRDNORM;
return mask; }
static int drv_keys_fasync (int fd, struct file *filp, int on) { PINFO("drv_key_fasync\n"); return fasync_helper (fd, filp, on, &keys_async); }
static const struct file_operations drv_keys_fops= { .owner = THIS_MODULE, .open = drv_keys_open, .release = drv_keys_release, .read = drv_keys_read, .poll = drv_keys_poll, .fasync = drv_keys_fasync, };
static int __init drv_keys_init(void) {
int i; int res;
res = alloc_chrdev_region(&drv_keys_device_num,DRV_KEYS_FIRST_MINOR,DRV_KEYS_N_MINORS ,DRIVER_NAME); if(res) { PERR("register device no failed\n"); return -1; } drv_keys_major = MAJOR(drv_keys_device_num);
drv_keys_class = class_create(THIS_MODULE , DRIVER_NAME); if(!drv_keys_class) { PERR("class creation failed\n"); return -1; }
for(i=0;i<DRV_KEYS_N_MINORS;i++) { drv_keys_device_num= MKDEV(drv_keys_major ,DRV_KEYS_FIRST_MINOR+i); cdev_init(&devices[i].cdev , &drv_keys_fops); cdev_add(&devices[i].cdev,drv_keys_device_num,1);
devices[i].drv_keys_device = device_create(drv_keys_class , NULL ,drv_keys_device_num , DRV_KEYS_NODE_NAME"%d",DRV_KEYS_FIRST_MINOR+i); if(!devices[i].drv_keys_device) { class_destroy(drv_keys_class); PERR("device creation failed\n"); return -1; }
devices[i].nMinor = DRV_KEYS_FIRST_MINOR+i; }
PINFO("INIT\n");
return 0; }
static void __exit drv_keys_exit(void) {
int i;
PINFO("EXIT\n");
for(i=0;i<DRV_KEYS_N_MINORS;i++) { drv_keys_device_num= MKDEV(drv_keys_major ,DRV_KEYS_FIRST_MINOR+i);
cdev_del(&devices[i].cdev);
device_destroy(drv_keys_class ,drv_keys_device_num);
}
class_destroy(drv_keys_class);
unregister_chrdev_region(drv_keys_device_num ,DRV_KEYS_N_MINORS);
}
module_init(drv_keys_init); module_exit(drv_keys_exit);
|