GPIO控制LED
一、原理图、芯片手册
GPC0_3/4
GPC0CON
GPC0DAT
二、驱动
- 模块许可
- 加载函数
- 构建设备号
- 申请设备号
- 注册字符设备
- 映射寄存器
- 初始化设备
- 卸载函数
- 逆向卸载
- file_operations
键盘驱动编写:
一、原理图
gph0 0~5gph2 6~7
二、驱动
- 定义设备结构体
- struct key_device{
- int keyval;
- struct semaphore sem;
- wait_queue_head_t rq;
- struct cdev cdev;
- } key_device;
- 模块许可
- 加载函数
- 申请设备号
- 注册支付设备
- 注册中断
- 初始信号量
- 初始化等待队列 init_waitqueue_head
- 映射内存
- 初始化设备
- 卸载函数
- 实现file_operations
- 中断处理interrupt
- 保存键值
- 唤醒等待队列
LED参考代码
#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.35sema_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);