#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include "fs210_led.h"
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("farsight");
#define GPC0CON 0xe0200060
#define GPC0DAT 0xe0200064
static int led_major = 250;
static int led_minor = 0;
static struct cdev led_cdev;
static void *gpc0con, *gpc0dat;
static void led_init(void)
{
writel((readl(gpc0con) & ~(0xff<<12)) | (0x11<<12), gpc0con);
writel(0, gpc0dat);
}
static void led_on(int num)
{
writel((readl(gpc0dat) | (0x1 << num)), gpc0dat);
}
static void led_off(int num)
{
writel((readl(gpc0dat) & ~(0x1 << num)), gpc0dat);
}
static int fs210_led_open(struct inode *inode, struct file *file)
{
printk("led: device open\n");
return 0;
}
static int fs210_led_release(struct inode *inode, struct file *file)
{
printk("led: device close\n");
return 0;
}
static long fs210_led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int pos[] = {-1, 3, 4};
if ((arg < 1) || (arg > 2)) return -EINVAL;
switch ( cmd )
{
case LED_ON :
led_on(pos[arg]);
break;
case LED_OFF :
led_off(pos[arg]);
break;
default :
return -EINVAL;
}
return 0;
}
static struct file_operations fs210_led_ops = {
.owner = THIS_MODULE,
.open = fs210_led_open,
.release = fs210_led_release,
.unlocked_ioctl = fs210_led_ioctl
};
static int led_setup_cdev(struct cdev *cdev, struct file_operations *fops)
{
int result;
dev_t devno = MKDEV(led_major, led_minor);
cdev_init(cdev, fops);
cdev->owner = THIS_MODULE;
result = cdev_add(cdev, devno, 1);
if(result)
{
printk("led: cdev add failed\n");
return result;
}
return 0;
}
static int __init fs210_led_init(void)
{
int result;
dev_t devno = MKDEV(led_major, led_minor);
result = register_chrdev_region(devno, 1, "fs210_led");
if(result)
{
printk("led: unable to get major %d\n", led_major);
return result;
}
result = led_setup_cdev(&led_cdev, &fs210_led_ops);
if(result)
return result;
gpc0con = ioremap(GPC0CON, 4);
gpc0dat = ioremap(GPC0DAT, 4);
led_init();
printk("led: driver installed, with major %d!\n", led_major);
return 0;
}
static void __exit fs210_led_exit(void)
{
dev_t devno = MKDEV(led_major, led_minor);
cdev_del(&led_cdev);
unregister_chrdev_region(devno, 1);
iounmap(gpc0con);
iounmap(gpc0dat);
printk("led: driver uninstalled!\n");
}
module_init(fs210_led_init);
module_exit(fs210_led_exit);
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
//#include <linux/slab.h>
#include <linux/poll.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <mach/irqs.h>
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("farsight");
#define GPH0CON 0xe0200c00
#define GPH2CON 0xe0200c40
static int key_major = 250;
static int key_minor = 0;
struct key_device
{
int keyval;
struct cdev cdev;
struct semaphore sem;
wait_queue_head_t rq;
struct fasync_struct *async_queue;
} key_device;
void *gph0con;
void *gph2con;
static int fs210_key_open(struct inode *inode, struct file *filp)
{
struct key_device *dev = container_of(inode->i_cdev, struct key_device, cdev);
filp->private_data = dev;
printk("fs210_key is opened\n");
return 0;
}
static int fs210_key_release(struct inode *inode, struct file *filp)
{
struct key_device *dev = container_of(inode->i_cdev, struct key_device, cdev);
fasync_helper(-1, filp, 0, &dev->async_queue);
printk("fs210_key is closed\n");
return 0;
}
static int fs210_key_read(struct file *filp, char __user *buf, size_t size, loff_t *off)
{
struct key_device *dev = filp->private_data;
down(&dev->sem);
while (dev->keyval == 0)
{
up(&dev->sem);
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
if (wait_event_interruptible(dev->rq, dev->keyval != 0))
return -ERESTARTSYS;
down(&dev->sem);
}
if (copy_to_user(buf, &dev->keyval, sizeof(int)))
{
up(&dev->sem);
return -EFAULT;
}
dev->keyval = 0;
up(&dev->sem);
return sizeof(int);
}
static int fs210_key_fasync(int fd, struct file *filp, int mode)
{
struct key_device *dev = filp->private_data;
return fasync_helper(fd, filp, mode, &dev->async_queue);
}
static unsigned int fs210_key_poll(struct file *filp, poll_table *wait)
{
unsigned int mask = 0;
struct key_device *dev = filp->private_data;
poll_wait(filp, &dev->rq, wait);
down(&dev->sem);
if (dev->keyval != 0)
{
mask |= POLLIN | POLLRDNORM; /*标示数据可获得*/
}
up(&dev->sem);
return mask;
}
static struct file_operations fs210_key_ops = {
.owner = THIS_MODULE,
.open = fs210_key_open,
.release = fs210_key_release,
.read = fs210_key_read,
.fasync = fs210_key_fasync,
.poll = fs210_key_poll
};
static irqreturn_t handler(int irqno, void *dev_id)
{
static long old_jiffies = 0;
if (jiffies - old_jiffies < 20) return IRQ_HANDLED;
old_jiffies = jiffies;
printk("irq: interrupt %d\n", irqno);
switch (irqno)
{
case IRQ_EINT(0) :
key_device.keyval = 1;
break;
case IRQ_EINT(1) :
key_device.keyval = 2;
break;
case IRQ_EINT(2) :
key_device.keyval = 3;
break;
case IRQ_EINT(3) :
key_device.keyval = 4;
break;
case IRQ_EINT(4) :
key_device.keyval = 5;
break;
case IRQ_EINT(5) :
key_device.keyval = 6;
break;
case IRQ_EINT(22) :
key_device.keyval = 7;
break;
case IRQ_EINT(23) :
key_device.keyval = 8;
break;
}
wake_up(&key_device.rq);
if (key_device.async_queue != NULL)
{
kill_fasync(&key_device.async_queue, SIGIO, POLL_IN);
}
return IRQ_HANDLED;
}
static int key_request_irq(void)
{
int result;
result = request_irq(IRQ_EINT(0), handler, IRQF_DISABLED|IRQF_TRIGGER_FALLING, "key_1", NULL);
if (result) {
printk("key: request irq %d failed!\n", IRQ_EINT(0));
return result;
}
result = request_irq(IRQ_EINT(1), handler, IRQF_DISABLED|IRQF_TRIGGER_FALLING, "key_2", NULL);
if (result) {
printk("key: request irq %d failed!\n", IRQ_EINT(1));
goto _error_irq1;
}
result = request_irq(IRQ_EINT(2), handler, IRQF_DISABLED|IRQF_TRIGGER_FALLING, "key_3", NULL);
if (result) {
printk("key: request irq %d failed!\n", IRQ_EINT(2));
goto _error_irq2;
}
result = request_irq(IRQ_EINT(3), handler, IRQF_DISABLED|IRQF_TRIGGER_FALLING, "key_4", NULL);
if (result) {
printk("key: request irq %d failed!\n", IRQ_EINT(3));
goto _error_irq3;
}
result = request_irq(IRQ_EINT(4), handler, IRQF_DISABLED|IRQF_TRIGGER_FALLING, "key_5", NULL);
if (result) {
printk("key: request irq %d failed!\n", IRQ_EINT(4));
goto _error_irq4;
}
result = request_irq(IRQ_EINT(5), handler, IRQF_DISABLED|IRQF_TRIGGER_FALLING, "key_6", NULL);
if (result) {
printk("key: request irq %d failed!\n", IRQ_EINT(5));
goto _error_irq5;
}
result = request_irq(IRQ_EINT(22), handler, IRQF_DISABLED|IRQF_TRIGGER_FALLING, "key_7", NULL);
if (result) {
printk("key: request irq %d failed!\n", IRQ_EINT(22));
goto _error_irq22;
}
result = request_irq(IRQ_EINT(23), handler, IRQF_DISABLED|IRQF_TRIGGER_FALLING, "key_8", NULL);
if (result) {
printk("key: request irq %d failed!\n", IRQ_EINT(23));
goto _error_irq23;
}
return 0;
_error_irq23:
free_irq(IRQ_EINT(22), NULL);
_error_irq22:
free_irq(IRQ_EINT(5), NULL);
_error_irq5 :
free_irq(IRQ_EINT(4), NULL);
_error_irq4 :
free_irq(IRQ_EINT(3), NULL);
_error_irq3 :
free_irq(IRQ_EINT(2), NULL);
_error_irq2 :
free_irq(IRQ_EINT(1), NULL);
_error_irq1 :
free_irq(IRQ_EINT(0), NULL);
return result;
}
static void init_key(void)
{
gph0con = ioremap(GPH0CON, 4);
gph2con = ioremap(GPH2CON, 4);
writel((readl(gph0con) | 0xffffff), gph0con);
writel((readl(gph2con) | (0xff<<24)), gph2con);
}
static void key_free_irq(void)
{
free_irq(IRQ_EINT(0), NULL);
free_irq(IRQ_EINT(1), NULL);
free_irq(IRQ_EINT(2), NULL);
free_irq(IRQ_EINT(3), NULL);
free_irq(IRQ_EINT(4), NULL);
free_irq(IRQ_EINT(5), NULL);
free_irq(IRQ_EINT(22), NULL);
free_irq(IRQ_EINT(23), NULL);
}
static int key_setup_cdev(struct cdev *cdev, struct file_operations *ops)
{
int result;
dev_t devno = MKDEV(key_major, key_minor);
cdev_init(cdev, ops);
cdev->owner = THIS_MODULE;
result = cdev_add(cdev, devno, 1);
if (result)
{
printk("key: fail to add cdev\n");
return result;
}
return 0;
}
static int __init fs210_key_init(void)
{
int result;
dev_t devno = MKDEV(key_major, key_minor);
result = register_chrdev_region(devno, 1, "fs210_key");
if (result)
{
printk("key: unable to get major %d\n", key_major);
return result;
}
result = key_setup_cdev(&key_device.cdev, &fs210_key_ops);
if (result)
goto _error1;
result = key_request_irq();
if (result)
goto _error2;
init_key();
key_device.keyval = 0;
//init_MUTEX(&key_device.sem); // can used in kernel which version is no more than 2.6.35
sema_init(&key_device.sem, 1);
init_waitqueue_head(&key_device.rq);
printk("key : init_module\n");
return 0;
_error2:
cdev_del(&key_device.cdev);
_error1:
unregister_chrdev_region(devno, 1);
return result;
}
static void __exit fs210_key_exit(void)
{
dev_t devno = MKDEV(key_major, key_minor);
key_free_irq();
cdev_del(&key_device.cdev);
unregister_chrdev_region(devno, 1);
iounmap(gph0con);
iounmap(gph2con);
printk("key: cleanup_module!\n");
}
module_init(fs210_key_init);
module_exit(fs210_key_exit);