zoukankan      html  css  js  c++  java
  • 字符设备驱动(一)---led

    一、总体架构

      

    二、硬件电路

      1.硬件原理图

      

      

      2.寄存器配置

      

    三、代码编写

      写linux的设备驱动操作的是系统的虚拟地址,并不是像裸机程序一样操作的是物理地址。

      物理地址要映射成虚拟地址,就要用到ioremap函数,用来把物理地址映射成虚拟地址。

      3.1 确定主设备号

        执行命令 cat proc/devices 可以查看到已经用了的主设备号,给自己的设备定义设备号的时候,可以选用没有被设备使用的主设备号。或者可以写0,让系统自动给我们的设备分配主设备号。

      3.2 设备节点的创建方法

        a. 手动创建

          

        b. 自动创建

          应用程序里面应用udev机制

          mdev机制:mdev会根据系统的信息,sys目录下有很多系统的信息。注册一个驱动程序的时候,会在此目录下生成设备的信息,mdev可以根据设备的信息自动创建设备节点。

          

          

      3.3 源码

      1 /*
      2  * =====================================================================================
      3  *       Filename:  led.c
      4  *    Description:  
      5  *        Version:  1.0
      6  *        Created:  2017年05月22日 11时40分23秒
      7  *         Author:  YOUR NAME (), 
      8  *   Organization:  
      9  * =====================================================================================
     10  */
     11 
     12 #include <linux/init.h>
     13 #include <linux/module.h>
     14 #include <linux/fs.h>
     15 #include <linux/class.h>
     16 #include <linux/io.h>
     17 
     18 /* 1.建立模块
     19  *    1.1 模块初始化模板
     20  *        1.1.1 映射寄存器
     21  *        1.1.2 注册设备驱动,告诉内核
     22  *            1.1.1.1 主设备号
     23  *        1.1.3 设备类的建立
     24  *                1.1.1.2.1 创建变量:设备类和设备
     25  *                1.1.1.2.2 创建设备类
     26  *                1.1.1.2.3 在设备类下创建设备
     27  *    1.2 模块退出模板
     28  *
     29  * 2.建立文件操作
     30  *    2.1 文件打开和关闭函数
     31  *        2.1.1 文件打开函数
     32  *    2.2 文件读写函数
     33  *        2.2.1 文件读函数
     34  *        2.2.2 文件写函数
     35  *            2.2.2.1 设置GPIO引脚输出的数据
     36  *                2.2.2.1.1 从用户空间读取数据
     37  *    2.3 创建文件操作结构体
     38  */
     39 
     40 #define DEVICE_NAME        "leds"    /* 加载模式后,执行"cat /proc/devices"命令看到设备的名称 */
     41 #define LED_MAJOR        231        /* 主设备号 */
     42 static unsigned long gpio_va;    //次设备号
     43 
     44 /* 1.1.1.2.1 创建变量:设备类和设备 */
     45 static struct class *leds_class; //创建led类
     46 static struct class_device *leds_class_devs[4];//在led类下面创建设备
     47 
     48 
     49 static char leds_status = 0x0;
     50 static DECLARE_MUTEX(leds_lock);    //定义赋值
     51 
     52 //volatile unsigned long *gpfcon = NULL;
     53 //volatile unsigned long *gpfdat = NULL;
     54 #define GPIO_OFT(x) ((x) - 0x56000000)
     55 #define GPFCON  (*(volatile unsigned long *)(gpio_va + GPIO_OFT(0x56000050)))
     56 #define GPFDAT  (*(volatile unsigned long *)(gpio_va + GPIO_OFT(0x56000054)))
     57 
     58 /* 2.1.1 文件打开函数 */
     59 static int led_open(struct inode *inode, struct file *filp)
     60 {
     61     int minor = MINOR(inode->irdev);//获取次设备号
     62 
     63     switch(minor)
     64     {
     65         case 0:
     66             GPFCON &= ~((0x3 << (4 * 2)) | (0x3 << (5 * 2)) | (0x3 << (6 * 2)));
     67             GPFCON |= ((0x1 << (4 * 2)) | (0x1 << (5 * 2)) | (0x1 << (6 * 2)));
     68 
     69             //初始化状态:LED灯全亮,gpf引脚输出0
     70             GPFDAT &= ~((1<<4) | (1<<5) | (1<<6));
     71 
     72             down(&leds_lock);
     73             leds_status = 0x0;
     74             up(&leds_lock);
     75             break;
     76         case 1:
     77             GPFCON &= ~(0x3 <<(4 * 2));
     78             GPFCON |= (1 << (4 * 2));
     79 
     80             //初始化状态:LED4亮,gpf4引脚输出0
     81             GPFDAT &= ~(1 << 4);
     82 
     83             down(&leds_lock);
     84             leds_status &= ~(1 << 0);
     85             up(&leds_lock);
     86             break;
     87         case 2:
     88             GPFCON &= ~(0x3 << (5 * 2));
     89             GPFCON |= (1 << (5 * 2));
     90             
     91             GPFDAT &= ~(1 << 5);
     92             
     93             down(&leds_lock);
     94             leds_status &= ~(1 << 1);
     95             up(&leds_lock);
     96             break;
     97         case 3:
     98             GPFCON &= ~(0x3 << (6 * 2));
     99             GPFCON |= (1 << (6 * 2));
    100             
    101             GPFDAT &= ~(1 << 6);
    102             
    103             down(&leds_lock);
    104             leds_status &= ~(1 << 2);
    105             up(&leds_lock);
    106             break;
    107     }
    108 
    109     return 0;
    110 }
    111 
    112 
    113 /* 2.2.1 文件读函数 */
    114 static ssize_t led_read(struct file *filp, char __user *buff, ssize_t count, loff_t *oops)
    115 {
    116     int minor = MINOR(filp->f_dentry->d_inode->i_rdev);//获取次设备号
    117     char val;
    118 
    119     switch(minor)
    120     {
    121         case 0:
    122             copy_to_user(buff, (const void *)&leds_status, 1);
    123             break;
    124         case 1:
    125             down(&leds_lock);
    126             val = leds_status & 0x1;
    127             up(&leds_lock);
    128             copy_to_user(buff, (const void *)&val, 1);
    129             break;
    130         case 2:
    131             down(&leds_lock);
    132             val = (leds_status>>1) & 0x1;
    133             up(&leds_lock);
    134             copy_to_user(buff, (const void *)&val, 1);
    135             break;
    136         case 3:
    137             down(&leds_lock);
    138             val = (leds_status>>2) & 0x1;
    139             up(&leds_lock);
    140             copy_to_user(buff, (const void *)&val, 1);
    141             break;
    142     }
    143     return 1;
    144 }
    145 
    146 /* 2.2.2 文件写函数 */
    147 static ssize_t led_wirte(struct file *filp, const char __user *buff, ssize_t count, loff_t *oops)
    148 {
    149     int minor = MINOR(file->fdentry->d_inode->i_rdev);
    150     char val;
    151 
    152     /* 2.2.2.1 设置GPIO引脚输出 */
    153         /* 2.2.2.1.1 从用户空间读取设置的数据 */
    154     copy_from_user(&val, buf, conut);
    155 
    156     switch(minor)
    157     {
    158         case 0:
    159             if (0 == val) //亮灯
    160                 GPFDAT &= ~((1 << 4) | (1 << 5) | (1 << 6));
    161             else//灭灯
    162                 GPFDAT |= (1 << 4) | (1 << 5) | (1 << 6); 
    163             down(&leds_lock);
    164             leds_status = val;
    165             up(&leds_lock);
    166             break;
    167         case 1:
    168             if (val == 0)
    169             {
    170                 GPFDAT &= ~(1<<4);
    171                 down(&leds_lock);
    172                 leds_status &= ~(1<<0);
    173                 up(&leds_lock);
    174             }
    175             else
    176             {
    177                 GPFDAT |= (1 << 4);
    178                 down(&leds_lock);
    179                 leds_status |= (1<<0);                
    180                 up(&leds_lock);
    181             }
    182             break;
    183         case 2:
    184             if (val == 0)
    185             {
    186                 GPFDAT &= ~(1 << 5);
    187                 down(&leds_lock);
    188                 leds_status &= ~(1 << 1);
    189                 up(&leds_lock);
    190             }
    191             else
    192             {
    193                 GPFDAT |= (1 << 5);
    194                 down(&leds_lock);
    195                 leds_status |= (1 << 1); 
    196                 up(&leds_lock);
    197             }
    198             break;
    199         case 3:
    200             if(val == 0)
    201             {
    202                 GPFDAT &= ~(1 << 6);
    203                 down(&leds_lock);
    204                 leds_status &= ~(1 << 2);
    205                 up(&leds_lock);
    206             }
    207             else
    208             {
    209                 GPFDAT |= (1 << 6);
    210                 down(&leds_lock);
    211                 leds_status |= (1 << 2);                
    212                 up(&leds_lock);
    213             }
    214             break;
    215     }
    216 
    217     return 1;
    218 }
    219 
    220 struct file_operations led_drv_fops = {
    221     .owner = THIS_MODULE;
    222     .open = led_open;
    223     .release = led_release;
    224     .read = led_read;
    225     .write = led_wirte;
    226 }
    227 
    228 
    229 /* 1.1 模块初始化函数 */
    230 static int __init led_init(void)
    231 {
    232     int ret;
    233     int minor = 0;
    234 
    235     /* 1.1.1 映射寄存器 */
    236     gpio_va = ioremap(0x56000000, 0x100000);
    237     if (!gpio_va) {
    238         return -EIO;
    239     }
    240 
    241 
    242     /* 1.1.2 注册字符设备,将主设备号与file_operations结构联系起来 */
    243     /* LED_MAJOR可以设为0,表示由内核自动分配主设备号 */
    244     ret = register_chrdev(LED_MAJOR, DEVICE_NAME, &led_drv_fops);
    245     if (ret < 0) {
    246         printk(DEVICE_NAME " can't register major number!!!
    ");
    247         return ret;
    248     }
    249 
    250     /* 1.1.3 设备类的创建 */
    251     leds_class = class_create(THIS_MODULE, "leds");
    252     if (IS_ERR(leds_class))
    253         return PTR_ERR(leds_class);
    254 
    255     /* 1.1.4 在leds类下面创建一个设备 */
    256     /* mdev 会自动创建一个/dev/leds 设备节点 */
    257     leds_class_devs[0] = class_device_create(leds_class, NULL, MKDEV(LED_MAJOR, 0), NULL, "leds");
    258     if (unlikely(IS_ERR(leds_class_devs[0])))
    259         return PTR_ERR(leds_class_devs[0]);
    260     for(minor = 1; minor < 4; minor++)
    261     {
    262         leds_class_devs[minor] = class_device_create(leds_class, NULL, MKDEV(LED_MAJOR, minor), NULL, "led%d", minor);
    263         if (unlikely(IS_ERR(leds_class_devs[minor])))
    264             return PTR_ERR(leds_class_devs[minor]);
    265     }
    266 
    267     printk(DEVICE_NAME " initialized
    ");
    268     return 0;
    269 }
    270 
    271 /* 1.2 模块退出函数 */
    272 static void __exit led_exit(void)
    273 {
    274     int minor;
    275     for(minor = 0; minor < 4; minor++)
    276     {
    277         class_device_unregister(leds_class_devs[minor]);
    278     }
    279     class_destroy(leds_class);
    280     unregister_chrdev(LED_MAJOR, DEVICE_NAME);//卸载
    281     iounmap(gpfcon);
    282 
    283     return 0;
    284 }
    285 
    286 module_init(led_init);//定义一个结构体,结构体内有一个函数指针,指向led_init这个入口函数
    287 module_exit(led_exit);
    288 
    289 MODULE_LICENSE("Dual BSD/GPL");
    View Code

      

  • 相关阅读:
    UVALive 6584 Escape (Regionals 2013 >> Europe
    莫比乌斯反演
    POJ 3986 Math teacher's homework
    ACM一些题目
    重探 DFT
    GDSOI2015 task4 ACU
    GDSOI2015 task2 覆盖半径
    USACO 2005 January Gold The Wedding Juicer
    CQOI2015 选数
    计算圆的包含(两两圆不相交)
  • 原文地址:https://www.cnblogs.com/kele-dad/p/6899233.html
Copyright © 2011-2022 走看看