设备驱动(十四)

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

你可能感兴趣的:(linux,设备驱动)