查看: 4124|回复: 7

pcDuino Linux驱动开发三 -- 最简单的GPIO驱动

[复制链接]
  • TA的每日心情
    奋斗
    2022-9-16 05:52
  • 签到天数: 1368 天

    连续签到: 1 天

    [LV.10]以坛为家III

    发表于 2014-8-14 08:27:04 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 tjCFeng 于 2014-8-17 08:46 编辑

    本着从易到难的过程,现有程序完全基于那个最精简的驱动程序框架来实现,也就是字符设备+寄存器操作的方式,以后有时间再改为总线设备驱动。

    pcDuino上有两个LED,TX和RX,就用它们来做实验了。

    下面上代码,可参照《pcDuino Linux驱动开发二 -- 最简单的驱动程序框架》这个最精简的框架来看看增加的部分,无非就是多了些寄存器的操作:
    1. #include <linux/init.h>
    2. #include <linux/module.h>
    3. #include <linux/fs.h>
    4. #include <linux/cdev.h>
    5. #include <linux/device.h>
    6. #include <asm/io.h>
    7. #include <asm/uaccess.h>

    8. #include "../A10.h"

    9. /**********************************************************************/
    10.         #define LED_TX                15
    11.         #define LED_RX                16
    12.         #define LED_ON(Pin)                                (*REG_PH_DAT &=  ~(0x1 << Pin))
    13.         #define LED_OFF(Pin)                                (*REG_PH_DAT |= (0x1 << Pin) )
    14.         #define LED_REVERSE(Pin)        (*REG_PH_DAT ^= (0x1 << Pin) )

    15.         volatile static unsigned long* REG_PH_CFG1;
    16.         volatile static unsigned long* REG_PH_DAT;
    17.         
    18.         int Inited = 0;

    19. int LED_open(struct inode* n, struct file* f)
    20. {
    21.         Inited++;
    22.         if (Inited > 1) return Inited;

    23.         REG_PH_CFG1 = (volatile unsigned long*) ioremap(PH_CFG1, 4);
    24.         REG_PH_DAT = (volatile unsigned long*) ioremap(PH_DAT, 4);
    25.         
    26.         *REG_PH_CFG1 &= ~(0xF << 28);
    27.         *REG_PH_CFG1 |= (0x1 << 28);

    28.         LED_OFF(LED_TX);
    29.         LED_OFF(LED_RX);
    30.         
    31.         printk("Open Finished!\n");
    32.         return 0;
    33. }

    34. ssize_t LED_write(struct file* f, const char __user* buf, size_t len, loff_t* l)
    35. {
    36.         unsigned char Buf[2];
    37.         
    38.         if (copy_from_user(&Buf, buf, len)) return -1;
    39.         
    40.         if ((Buf[0] != LED_TX) && (Buf[0] != LED_RX)) return -1;

    41.         switch (Buf[1])
    42.         {
    43.                 case 0:
    44.                         LED_OFF(Buf[0]);
    45.                         break;
    46.                 case 1:
    47.                         LED_ON(Buf[0]);
    48.                         break;
    49.                 case 2:
    50.                         LED_REVERSE(Buf[0]);
    51.                         break;
    52.                 default:
    53.                         return -1;
    54.         }

    55.         return len;
    56. }

    57. ssize_t LED_read(struct file* f, char __user* buf, size_t len, loff_t* l)
    58. {
    59.         //int Buf;
    60.         //copy_to_user(&Buf, buf, sizeof(int));
    61.         
    62.         printk("Read Finished!\n");
    63.         return 0;
    64. }

    65. int LED_release(struct inode* n, struct file* f)
    66. {
    67.         Inited--;
    68.         if (Inited <= 0)
    69.         {
    70.                 Inited = 0;
    71.                 return 0;
    72.         }
    73.         
    74.         iounmap(REG_PH_CFG1);
    75.         iounmap(REG_PH_DAT);
    76.         
    77.         printk("Release Finished!\n");
    78.         return 0;
    79. }

    80. /**********************************************************************/
    81.         #define DEV_NAME        "LED"
    82.         #define DEV_COUNT        1
    83.         
    84.         static dev_t Dev_Num;
    85.         static struct cdev* pDev;
    86.         static struct class* pClass;
    87.         
    88.         static struct file_operations fops =
    89.         {
    90.                 .owner = THIS_MODULE,
    91.                 .open = LED_open,
    92.                 .write = LED_write,
    93.                 .read = LED_read,
    94.                 .release = LED_release,
    95.         };

    96. static int __init LED_init(void)
    97. {
    98.         int Result;
    99.         
    100.         Result = alloc_chrdev_region(&Dev_Num, 0, DEV_COUNT, DEV_NAME);
    101.         if (Result)
    102.         {
    103.                 printk("alloc_chrdev_region fail!\n");
    104.                 return Result;
    105.         }
    106.         
    107.         pDev = cdev_alloc();
    108.         if (pDev == NULL)
    109.         {
    110.                 printk("cdev_alloc fail!\n");
    111.                 unregister_chrdev_region(Dev_Num, DEV_COUNT);
    112.                 return -1;
    113.         }
    114.         
    115.         cdev_init(pDev, &fops);
    116.         Result = cdev_add(pDev, Dev_Num, DEV_COUNT);
    117.         if (Result)
    118.         {
    119.                 printk("cdev_add fail!\n");
    120.                 cdev_del(pDev);
    121.                 return Result;
    122.         }
    123.         
    124.         pClass = class_create(THIS_MODULE, DEV_NAME);
    125.         if (pClass == NULL)
    126.         {
    127.                 printk("class_create fail!\n");
    128.                 cdev_del(pDev);
    129.                 unregister_chrdev_region(Dev_Num, DEV_COUNT);
    130.                 return -1;
    131.         }
    132.         
    133.         device_create(pClass, NULL, Dev_Num, "%s", DEV_NAME);
    134.         printk("Init Finished!\n");
    135.         return 0;
    136. }

    137. static void __exit LED_exit(void)
    138. {
    139.         if (pClass)
    140.         {
    141.                 device_destroy(pClass, Dev_Num);
    142.                 class_destroy(pClass);
    143.         }
    144.         
    145.         if (pDev)
    146.         {
    147.                 cdev_del(pDev);
    148.         }
    149.         
    150.         unregister_chrdev_region(Dev_Num, DEV_COUNT);
    151.         printk("Exit Finished!\n");
    152. }

    153. MODULE_LICENSE("GPL");
    154. MODULE_AUTHOR("LiuYang");
    155. module_init(LED_init);
    156. module_exit(LED_exit);
    复制代码
    这里没有实现Read函数,可以略过。

    make 后生成LED.ko,使用insmod LED.ko加载模块,可以在/dev文件夹中看到,或者使用cat /proc/devices也可以看到。
    调用rmmod LED后,该设备驱动模块被卸载,使用dmesg | tail -10来观察各个接口的加载情况,调试用。
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2016-8-15 09:28
  • 签到天数: 222 天

    连续签到: 1 天

    [LV.7]常住居民III

    发表于 2014-8-14 08:47:19 | 显示全部楼层
    沙发看教程,顶!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2014-8-14 10:11
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2014-8-14 10:27:32 | 显示全部楼层
    谢谢楼主,学习了。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2019-3-28 19:29
  • 签到天数: 45 天

    连续签到: 1 天

    [LV.5]常住居民I

    发表于 2014-9-11 13:44:42 | 显示全部楼层
    樓主你好~~想請教一下 #include "../A10.h" 這行header files 是在哪個資料夾的呢?我一直找不到...麻煩樓主指引一下~~感謝
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2022-9-16 05:52
  • 签到天数: 1368 天

    连续签到: 1 天

    [LV.10]以坛为家III

     楼主| 发表于 2014-9-11 13:58:59 | 显示全部楼层
    shuffelin 发表于 2014-9-11 13:44
    樓主你好~~想請教一下 #include "../A10.h" 這行header files 是在哪個資料夾的呢?我一直找不到...麻煩樓 ...

    这个是我自己写的一个头文件,就是手册上的各个寄存器的那个地址。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2013-4-30 14:45
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2015-1-19 17:49:56 | 显示全部楼层
    A10.h 能发一份给我吗?谢了!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2022-9-16 05:52
  • 签到天数: 1368 天

    连续签到: 1 天

    [LV.10]以坛为家III

     楼主| 发表于 2015-1-19 17:55:21 | 显示全部楼层
    xiaotiaosangtuo 发表于 2015-1-19 17:49
    A10.h 能发一份给我吗?谢了!

    A10.h就是寄存器地址的定义,手册中有,格式就是

    #define GPIO  0xXXXXXXXX
    #define ADC   0xXXXXXXXX


    我回去找一下,如果找到了就发出来
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2013-4-30 14:45
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2015-1-25 11:50:29 | 显示全部楼层
    tjcfeng 发表于 2015-1-19 17:55
    A10.h就是寄存器地址的定义,手册中有,格式就是

    #define GPIO  0xXXXXXXXX

    嗯,多谢 啦!
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-3-29 20:48 , Processed in 0.184429 second(s), 30 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.