zoukankan      html  css  js  c++  java
  • iTOP4412设备驱动学习七--LEDS驱动

    资源来源于迅为视频学习教程。

    本节是LEDS驱动的调用学习,根据之前的学习的杂项设备的基础上实现驱动LED2的亮灭。

    1.LED原理图使用了三极管,首先三极管的了解:

    我们这个是NPN鍺管

    三极管:电流控制电源(模电术语)。理解起来:电流指1->2之间的电流。内部构造较为复杂。有时间再学习补充。

    理解:2和3之间有一个可调电阻,其大小由1过来的电流决定。当左边低电平电流小,电阻无穷大。当左边高电平时电流大,电阻值变小,则LED2有电阻电压差,可以发亮。

    2. LED相关头文件

        Linux中申请GPIO的头文件(各平台通用):include/linux/gpio.h  如函数gpio_request等

        三星平台的GPIO配置函数头文件,宏定义头文件:arch/arm/plat-samsung/include/plat/gpio-cfg.h  包括三星所有板子配置函数

        三星平台EXYNOS系列平台,GPIO配置参数宏定义头文件:arch/arm/mach-exynos/include/mach/gpio.h  GPIO管脚拉高拉低配置参数等等

        三星平台4412平台,GPIO宏定义头文件:arch/arm/mach-exynos/include/mach/gpio-exynos4.h  已经包含在头文件gpio.h中,包括4412处理器所有GPIO的宏定义。

    3. LED函数

        Linux的GPIO中申请函数和赋值函数:gpio_request,gpio_set_value

        三星平台配置GPIO函数:s3c_gpio_cfgpin

        GPIO配置输出模式的宏变量:s3c_GPIO_OUTPUT

    4.函数在内核中的实现定义方法

        函数gpio_request,gpio_set_value

    include/linux/gpio.h 
    //参数1是GPIO的宏,参数2是提高可读性的,可直接指定一个字符串 44 static inline int gpio_request(unsigned gpio, const char *label) 45 { 46 return -ENOSYS; 47 }
     98 static inline void gpio_set_value(unsigned gpio, int value)
     99 {
    100         /* GPIO can never have been requested or set as output */
    101         WARN_ON(1);
    102 }

    arch/arm/plat-samsung/include/plat/gpio-cfg.h
     77 /**
     78  * s3c_gpio_cfgpin() - Change the GPIO function of a pin.
     79  * @pin pin The pin number to configure.
     80  * @to to The configuration for the pin's function.
     81  *
     82  * Configure which function is actually connected to the external
     83  * pin, such as an gpio input, output or some form of special function
     84  * connected to an internal peripheral block.
     85  *
     86  * The @to parameter can be one of the generic S3C_GPIO_INPUT, S3C_GPIO_OUTPUT
     87  * or S3C_GPIO_SFN() to indicate one of the possible values that the helper
     88  * will then generate the correct bit mask and shift for the configuration.
     89  *
     90  * If a bank of GPIOs all needs to be set to special-function 2, then
     91  * the following code will work:
     92  *
     93  *      for (gpio = start; gpio < end; gpio++)
     94  *              s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
     95  *
     96  * The @to parameter can also be a specific value already shifted to the
     97  * correct position in the control register, although these are discouraged
     98  * in newer kernels and are only being kept for compatibility.
     99  */
    100 extern int s3c_gpio_cfgpin(unsigned int pin, unsigned int to);    //参数1是GPIO宏,参数2要将其配置为什么样的GPIO,使用宏S3C_GPIO_OUTPUT
    arch/arm/plat-samsung/include/plat/gpio-cfg.h
     69 /* Defines for generic pin configurations */
     70 #define S3C_GPIO_INPUT  (S3C_GPIO_SPECIAL(0))
     71 #define S3C_GPIO_OUTPUT (S3C_GPIO_SPECIAL(1))          //这个是输出模式的宏变量
     72 #define S3C_GPIO_SFN(x) (S3C_GPIO_SPECIAL(x))

    因为系统提供的config中默认是将LEDS打开的,所以我们需要重巡编译内核,去掉LEDS驱动,然后加载我们自己写的LEDS驱动。

    4. 修改config重新编译:

     首先修改config,将LED配置关闭

     1 $ make menuconfig
     2 scripts/kconfig/mconf Kconfig
     3 #
     4 # configuration written to .config
     5 #
     6 
     7 
     8 *** End of the configuration.
     9 *** Execute 'make' to start the build or try 'make help'.
    10 
    11 $ make zImage -j4
    12 ...
    13   OBJCOPY arch/arm/boot/Image
    14   Kernel: arch/arm/boot/Image is ready
    15   GZIP    arch/arm/boot/compressed/piggy.gzip
    16   SHIPPED arch/arm/boot/compressed/lib1funcs.S
    17   AS      arch/arm/boot/compressed/lib1funcs.o
    18   AS      arch/arm/boot/compressed/piggy.gzip.o
    19   LD      arch/arm/boot/compressed/vmlinux
    20   OBJCOPY arch/arm/boot/zImage
    21   Kernel: arch/arm/boot/zImage is ready

    将新的zImage烧写到板子中,烧写方法同之前操作。

    5.LEDS驱动代码:

    此代码与上次相比增加了hello_pobe和hello_ioctl中的调用。

    leds驱动源码leds.c:

      1 #include <linux/init.h>
      2 #include <linux/module.h>
      3 
      4 #include <linux/platform_device.h>
      5 #include <linux/miscdevice.h>
      6 #include <linux/fs.h>
      7 
      8 #include <linux/gpio.h>  //通用的一般会被其他的包含
      9 #include <plat/gpio-cfg.h> //三星平台
     10 #include <mach/gpio.h>  //EXYNOS平台
     11 #include <mach/gpio-exynos4.h>  //4412平台
     12 
     13 #define DRIVER_NAME "hello_ctl"
     14 #define DEVICE_NAME "hello_ctl"
     15 
     16 //参数1是GPIO的值为0或1,参数2是GPIO的个数
     17 static long hello_ctl(struct file *files, unsigned int cmd, unsigned long arg){
     18     printk(KERN_EMERG "cmd is %d, args is %d
    ", cmd, arg);
     19     if(cmd > 1){
     20         printk(KERN_EMERG "ERROR: cmd is 0 or 1
    ");
     21     }
     22     if(arg > 1){
     23         printk(KERN_EMERG "ERROR: arg is only 1
    ");
     24     }
     25     gpio_set_value(EXYNOS4_GPL2(0), cmd);
     26     return 0;
     27 }
     28 static int hello_release(struct inode *inode, struct file *file){
     29     printk(KERN_EMERG "hello release!
    ");
     30     return 0;
     31 }
     32 static int hello_open(struct inode *inode,  struct file *file){
     33     printk(KERN_EMERG "hello open
    ");
     34     return 0;
     35 }
     36 static struct file_operations hello_ops = {
     37     .owner = THIS_MODULE,
     38     .open = hello_open,
     39     .release = hello_release,
     40     .unlocked_ioctl = hello_ctl,
     41 };
     42 
     43 static struct miscdevice hello_dev = {
     44     .minor = MISC_DYNAMIC_MINOR,
     45     .name = DEVICE_NAME,
     46     .fops = &hello_ops,
     47 };
     48 
     49 //资源申请也在probe中
     50 static int hello_probe(struct platform_device *pdv){
     51     int ret;
     52     printk(KERN_EMERG "initialized
    ");
     53 
     54     ret = gpio_request(EXYNOS4_GPL2(0), "LEDS");    //参数宏在文件中查找:arch/arm/mach-exynos/include/mach/gpio-exynos4.h
     55     if(ret < 0){
     56         printk(KERN_EMERG "gpio_request EXYNOS4_GPL2(0) failed
    ");
     57         return ret;
     58     }
     59 
     60     s3c_gpio_cfgpin(EXYNOS4_GPL2(0), S3C_GPIO_OUTPUT);
     61 
     62     gpio_set_value(EXYNOS4_GPL2(0), 0);
     63 
     64     misc_register(&hello_dev);
     65     return 0;
     66 }
     67 static int hello_remove(struct platform_device *pdv){
     68     printk(KERN_EMERG "remove
    ");
     69     misc_deregister(&hello_dev);
     70     return 0;
     71 }
     72 static void hello_shutdown(struct platform_device *pdev){
     73     ;
     74 }
     75 static int hello_suspend(struct platform_device *pdv, pm_message_t pmt){
     76     return 0;
     77 }
     78 static int hello_resume(struct platform_device *pdv){
     79     return 0;
     80 }
     81 
     82 struct platform_driver hello_driver = {
     83     .probe = hello_probe,
     84     .remove = hello_remove,
     85     .shutdown = hello_shutdown,
     86     .suspend = hello_suspend,
     87     .resume = hello_resume,
     88     .driver = {
     89         .name = DRIVER_NAME,
     90         .owner = THIS_MODULE,
     91     }
     92 };
     93 
     94 static int hello_init(void){
     95     int DriverState;
     96 
     97     printk(KERN_EMERG "hello world enter!
    ");
     98     DriverState = platform_driver_register(&hello_driver);
     99 
    100     printk(KERN_EMERG "DriverState is %d
    ", DriverState);
    101     return 0;
    102 }
    103 
    104 static void hello_exit(void){
    105     printk(KERN_EMERG "hello world exit!
    ");
    106     platform_driver_unregister(&hello_driver);
    107 }
    108 
    109 module_init(hello_init);
    110 module_exit(hello_exit);
    111 
    112 MODULE_LICENSE("Dual BSD/GPL");

    Makefile

     1 obj-m += leds.o
     2 
     3 KDIR := /home/nan/iTOP4412/iTop4412_Kernel_3.0
     4 
     5 PWD ?= $(shell pwd)
     6 
     7 all:
     8     make -C $(KDIR) M=$(PWD) modules
     9 clean:
    10     rm -rf *.o

    上层调用invoke_leds.c:

     1 #include <stdio.h>
     2 #include <sys/type.h>
     3 #include <sys/stat.h>
     4 #include <fcntl.h>
     5 #include <unistd.h>
     6 #include <sys/ioctl.h>
     7 
     8 int main()
     9 {
    10     int fd;
    11     char *hello_node = "/dev/hello_ctl"
    12 
    13     if((fd = open(hello_node, O_RDWR|O_NDELAY)) < 0){
    14         printf("App open %s failed!
    ", hello_node);
    15     }
    16     else{
    17         printf("App open %s success
    ", hello_node);
    18         ioctl(fd, 1, 1);   //1:cmd 2:arg
    19         sleep(3);
    20         ioctl(fd, 0, 1);
    21         sleep(3);
    22         ioctl(fd, 1, 1);
    23     }
    24     close(fd);
    25 
    26     return 0;
    27 }

    然后编译:

     1 nan@nanzh:~/iTOP4412/7$ make
     2 make -C /home/nan/iTOP4412/iTop4412_Kernel_3.0 M=/home/nan/iTOP4412/7 modules
     3 make[1]: Entering directory '/home/nan/iTOP4412/iTop4412_Kernel_3.0'
     4   CC [M]  /home/nan/iTOP4412/7/leds.o
     5 /home/nan/iTOP4412/7/leds.c: In function 'hello_ctl':
     6 /home/nan/iTOP4412/7/leds.c:18: warning: format '%d' expects type 'int', but argument 3 has type 'long unsigned int'
     7   Building modules, stage 2.
     8   MODPOST 1 modules
     9   CC      /home/nan/iTOP4412/7/leds.mod.o
    10   LD [M]  /home/nan/iTOP4412/7/leds.ko
    11 make[1]: Leaving directory '/home/nan/iTOP4412/iTop4412_Kernel_3.0'
    12 
    13 nan@nanzh:~/iTOP4412/7$ arm-none-linux-gnueabi-gcc invoke_leds.c -o invoke_leds -static
    14 nan@nanzh:~/iTOP4412/7$ ls invoke_leds*
    15 invoke_leds  invoke_leds.c

    拷贝到板子上运行:

    root@iTOP4412-ubuntu-desktop:~# cat /proc/modules 
    root@iTOP4412-ubuntu-desktop:~# ls /dev/leds
    ls: cannot access /dev/leds: No such file or directory
    root@iTOP4412-ubuntu-desktop:~/tests/7# insmod leds.ko 
    [  946.850211] hello world enter!
    [  946.852131] initialized
    [  946.875142] DriverState is 0
    root@iTOP4412-ubuntu-desktop:~/tests/7# ./invoke_leds 
    [  973.092455] hello open
    [  973.093867] cmd is 1, args is 1
    App open /dev/hello_ctl success
    [  976.100390] cmd is 0, args is 1
    [  979.102297] cmd is 1, args is 1
    [  979.104001] hello release!
    root@iTOP4412-ubuntu-desktop:~/tests/7# rmmod leds
    [ 1078.413217] hello world exit!
    [ 1078.414806] remove

    板子上的现象就是边上LED2一开始是亮的,被uboot点亮,然后运行invoke_leds会灭了三秒再亮。

    以上就是本节内容

  • 相关阅读:
    关于GIS从业人员的定位
    《企业应用架构模式》读书笔记(4)
    各大网络、软件巨头涉足Web GIS
    流水帐(2005.5)
    Xtreme Suite 和 Toolkit 9.6发布
    一个算法问题
    推荐2个最近使用的软件
    linux之pmap命令
    linux 文件系统简介
    百度脚本笔试题两道
  • 原文地址:https://www.cnblogs.com/nanzh/p/12547392.html
Copyright © 2011-2022 走看看