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会灭了三秒再亮。

    以上就是本节内容

  • 相关阅读:
    【校招面试 之 C/C++】第23题 C++ STL(五)之Set
    Cannot create an instance of OLE DB provider “OraOLEDB.Oracle” for linked server "xxxxxxx".
    Redhat Linux安装JDK 1.7
    ORA-10635: Invalid segment or tablespace type
    Symantec Backup Exec 2012 Agent for Linux 卸载
    Symantec Backup Exec 2012 Agent For Linux安装
    You must use the Role Management Tool to install or configure Microsoft .NET Framework 3.5 SP1
    YourSQLDba介绍
    PL/SQL重新编译包无反应
    MS SQL 监控数据/日志文件增长
  • 原文地址:https://www.cnblogs.com/nanzh/p/12547392.html
Copyright © 2011-2022 走看看