ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

GPIO硬件资源的申请,内核空间和用户空间的数据交换,ioctl(.....),设备文件的自动创建

2019-11-12 20:02:32  阅读:271  来源: 互联网

标签:硬件资源 led struct int dev ioctl ..... cdev GPIO


1、通过GPIO库函数控制LED
   open("/dev/myleds",...)       close(fd)
   ---------------------------------------------
   sys_open                      sys_close
       led_open(...)                led_release(...)
       {                            {
           亮灯                        灭灯
       }                            }
   
   电路原理图:
       控制LED1 实则控制CPU上的管脚GPIOC12输出低/高电平
   如何控制GPIOC12输出低/高电平:cpu datasheet
       GPIOCALTFN0  0xc001c020
       GPIOCOUTENB  0xc001c004
       GPIOCOUT     0xc001c000
   linux系统中如何控制GPIO管脚输出:本质上就是操作以上特殊功能寄存器
       1)将物理地址映射为虚拟地址
          然后通过虚拟地址访问特殊功能寄存器
       2)内核中提供了一套控制GPIO的库函数   
   
   GPIO库函数控制GPIO管脚有固定的步骤:
       1)申请GPIO管脚 (可选的)
          int gpio_request(unsigned gpio, const char *name)
              gpio,要申请的管脚编号
                   arch/arm/plat-s5p6818/common/cfg_type.h
              name,名称
              返回值,0 申请成功
                      非0 失败
                      
                      
       2)使用GPIO管脚
          //将参数指定的管脚设置为输入模式
          int gpio_direction_input(unsigned gpio)
          //获取指定管脚的电平状态
          // 0/1, 低/高
          int gpio_get_value(unsigned gpio)
          
          
          //将参数指定的管脚设置为输出模式
          //value 为0 默认输出低电平
                  非0 默认输出高电平
          int gpio_direction_output(unsigned gpio, int value)
          //设置指定管脚输出高/低电平
          void gpio_set_value(unsigned gpio, int value)   
       3)释放GPIO管脚 (可选的)
          //释放管脚
          void gpio_free(unsigned gpio)          
    
   安装模块前将内核中自带的LED驱动裁剪掉
      cd kernel/
      make menuconfig
         Device Drivers  --->
           -*- LED Support  --->
              < >   LED Support for GPIO connected LEDs
              < >   PWM driven LED Support
              [ ]   LED Trigger support
      make uImage
      
      让开发板使用新内核        
         cp arch/arm/boot/uImage /tftpboot/
         setenv bootcmd ping 192.168.1.8\;ping 192.168.1.8 \; tftp 48000000 uImage \; bootm 48000000
         saveenv
         
      insmod led_drv.ko           
      mknod /dev/myleds c 244 5
      ./test
      观察LED1的变化     
   练习:LED1/2/3/4    

2、内核空间和用户空间的数据交换
   用户空间代码不能(直接)访问内核空间
   内核空间代码访问用户空间时也加了限制
       
   long copy_to_user(void __user *to,
        const void *from, unsigned long n)
    to, 目标地址
        该地址应该介于0~3G
    from, 源数据地址
         该地址应该介于3G~4G
    n, 希望连续拷贝的字节数
    返回值,拷贝失败的字节数        
        
        
   long copy_from_user(void *to,
        const void __user * from, unsigned long n)    
        to, 目标地址 (3G~4G)
        from,源数据地址(0~3G)
        n, 连续拷贝的字节数
        返回值,操作失败的字节数
练习:
     用户空间向led1设备写入1时灭灯
                           0  亮
                       读取 1 灯是灭            
 
3、ioctl
   对LED写操作实现LED亮灭控制不合理?
   
   如果需要去实现uart驱动程序
       应用程序通过uart发数据 应该实现write
                       收             read
       如何在用户空间改变通信时的波特率?
           用户空间使用ioctl----->unlocked_ioctl
 
   ioctl,用于设置或者获取设备工作属性信息
        例如uart 通信时 设置使用8n1 115200
            查询当前uart通信时使用的波特率        
   
   函数原型:int ioctl(int d, int request, ...)
   通常使用
            1)ioctl(fd, cmd)
            2)ioctl(fd, cmd, &arg)
            
   练习:./test on/off   1/2/3/4         

4、设备文件的自动创建  
   1) 根文件系统中有mdev
   
   2) 挂载了proc sys 文件系统
      rootfs/etc/init.d/rcS
         mount -a
      rootfs/etc/fstab
         proc    /proc   proc    defaults    0   0
         sysfs   /sys    sysfs   defaults    0   0
   3)配置热插拔事件产生后要执行的动作
      echo /sbin/mdev > /proc/sys/kernel/hotplug
                   产生热插拔事件后,自动到proc/sys/kernel/hotplug执行/sbin/mdev产生相应的设备文件。
      热插拔事件:
          狭义: U盘的插入和拔出
          广义: 也包括/sys目录的文件变化
      
   4)编程产生热插拔事件
      
      class_create
      struct device *device_create(struct class *class, struct device *parent,
                       dev_t devt, void *drvdata, const char *fmt, ...)
             class, 该device属于那种类型的设备
                    该果实挂在哪个树枝上
             parent, 该device的父设备
             devt, 设备号
             drvdata,创建设备时传递给设备的附加信息
                     通常给NULL                       
             fmt, ...:决定了将来/dev目录下产生的设备文件的名称
                     例如:  "ttySAC%d",i
                     
                     for(i=0; i<4; i++)
                     {
                         device_create(...., "ttySAC%d",i);
                     }
                     
                     
      device_destroy
      class_destroy

 1 #include "../../global.h"
 2 #include <linux/fs.h>
 3 #include <linux/cdev.h>
 4 #include <linux/gpio.h>
 5 #include <mach/platform.h>
 6 
 7 unsigned int major = 0;
 8 unsigned int minor = 5;
 9 dev_t dev ; //设备号
10 
11 /*1 定义一个struct cdev变量*/
12 struct cdev led_cdev;
13 
14 
15 static int led_open(struct inode *inode, 
16                     struct file *filp)
17 {
18     /*输出低电平*/
19     gpio_set_value(PAD_GPIO_C+12, 0);
20     return 0;
21 }
22 static int led_close(struct inode *inode, 
23                     struct file *filp)
24 {
25     gpio_set_value(PAD_GPIO_C+12, 1);
26     return 0;
27 }
28 
29 struct file_operations led_fops =
30 {
31     .owner = THIS_MODULE,
32     .open  = led_open,
33     .release = led_close,
34 };
35 int __init led_drv_init(void)
36 {
37     if(major) //静态
38     {
39         //dev = major<<20|minor;
40         dev = MKDEV(major, minor);
41 
42         register_chrdev_region(dev, 1, "myleds");
43     }
44     else //动态注册
45     {
46         alloc_chrdev_region(&dev, minor, 1, "myleds");
47         printk("<1>" "major=%d minor=%d\n",
48                 MAJOR(dev), MINOR(dev));
49     }
50     /*2 初始化cdev变量*/
51     cdev_init(&led_cdev, &led_fops);
52     /*3 注册cdev变量*/
53     cdev_add(&led_cdev, dev, 1);
54     /*申请GPIO管脚*/
55     gpio_request(PAD_GPIO_C+12, "led1");
56     /*使用GPIO管脚*/
57     gpio_direction_output(PAD_GPIO_C+12, 1);
58 
59     return 0;
60 }
61 void __exit led_drv_exit(void)
62 {
63     /*释放GPIO管脚*/
64     gpio_free(PAD_GPIO_C+12);
65     /*4 注销cdev*/
66     cdev_del(&led_cdev);
67 
68     unregister_chrdev_region(dev, 1);
69 }
70 module_init(led_drv_init);
71 module_exit(led_drv_exit);
  1 #include "../../global.h"
  2 #include <linux/fs.h>
  3 #include <linux/cdev.h>
  4 #include <linux/gpio.h>
  5 #include <mach/platform.h>
  6 #include <linux/uaccess.h>
  7 
  8 unsigned int major = 0;
  9 unsigned int minor = 5;
 10 dev_t dev ; //设备号
 11 
 12 /*1 定义一个struct cdev变量*/
 13 struct cdev led_cdev;
 14 
 15 
 16 static int led_open(struct inode *inode, 
 17                     struct file *filp)
 18 {
 19     return 0;
 20 }
 21 static int led_close(struct inode *inode, 
 22                     struct file *filp)
 23 {
 24     return 0;
 25 }
 26 int k_stat = 0; //记录灯的当前状态
 27 ssize_t led_write(struct file *filp, 
 28                   const char __user *buf,
 29                   size_t len, loff_t *offset)
 30 {
 31     int ret = 0;
 32     int k_cmd = 0;
 33     //buf中保存的是用户空间地址 
 34     //*buf在直接读取用户空间内存 没有权限检查 不安全
 35     //*buf
 36     ret = copy_from_user(&k_cmd, buf, len);
 37     /*
 38      *cmd=0 亮灯
 39      *   =1 灭灯
 40      * */
 41     gpio_set_value(PAD_GPIO_C+12, k_cmd);
 42     /*
 43      * 1,灭的状态
 44      * 0,亮的状态
 45      * */
 46     k_stat = k_cmd;
 47     return len;
 48 
 49 }
 50 ssize_t led_read(struct file *filp, 
 51                  char __user *buf,
 52                  size_t len, loff_t *offset)
 53 {
 54     int ret = 0;
 55     /*
 56      *buf 保存的是用户空间stat变量的地址
 57      *内核需要向其中写入数据应该先检查是否有写权限
 58      *以下做法不安全
 59      * */
 60     //*buf = k_stat;
 61     
 62     ret = copy_to_user(buf, &k_stat, len);
 63 
 64     return len;
 65 
 66 }
 67 struct file_operations led_fops =
 68 {
 69     .owner = THIS_MODULE,
 70     .open  = led_open,
 71     .release = led_close,
 72     .write = led_write,
 73     .read = led_read,
 74 };
 75 int __init led_drv_init(void)
 76 {
 77     if(major) //静态
 78     {
 79         //dev = major<<20|minor;
 80         dev = MKDEV(major, minor);
 81 
 82         register_chrdev_region(dev, 1, "myleds");
 83     }
 84     else //动态注册
 85     {
 86         alloc_chrdev_region(&dev, minor, 1, "myleds");
 87         printk("<1>" "major=%d minor=%d\n",
 88                 MAJOR(dev), MINOR(dev));
 89     }
 90     /*2 初始化cdev变量*/
 91     cdev_init(&led_cdev, &led_fops);
 92     /*3 注册cdev变量*/
 93     cdev_add(&led_cdev, dev, 1);
 94     /*申请GPIO管脚*/
 95     gpio_request(PAD_GPIO_C+12, "led1");
 96     /*使用GPIO管脚*/
 97     gpio_direction_output(PAD_GPIO_C+12, 1);
 98 
 99     return 0;
100 }
101 void __exit led_drv_exit(void)
102 {
103     /*释放GPIO管脚*/
104     gpio_free(PAD_GPIO_C+12);
105     /*4 注销cdev*/
106     cdev_del(&led_cdev);
107 
108     unregister_chrdev_region(dev, 1);
109 }
110 module_init(led_drv_init);
111 module_exit(led_drv_exit);
#include "../../global.h"
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/gpio.h>
#include <mach/platform.h>
#include <linux/uaccess.h>

#define CMD_LED_ON  (0x10001)
#define CMD_LED_OFF (0x10002)

unsigned int major = 0;
unsigned int minor = 5;
dev_t dev ; //设备号

/*1 定义一个struct cdev变量*/
struct cdev led_cdev;

typedef struct led_desc
{
    int gpio;//管脚编号
    char *name;//名称
}led_desc_t;

led_desc_t leds[]=
{
    {PAD_GPIO_C+12, "led1"},
    {PAD_GPIO_C+7 , "led2"},
    {PAD_GPIO_C+11, "led3"},
    {PAD_GPIO_B+26, "led4"},
};


static int led_open(struct inode *inode, 
                    struct file *filp)
{
    return 0;
}
static int led_close(struct inode *inode, 
                    struct file *filp)
{
    return 0;
}
ssize_t led_write(struct file *filp, 
                  const char __user *buf,
                  size_t len, loff_t *offset)
{
    return len;
}
ssize_t led_read(struct file *filp, 
                 char __user *buf,
                 size_t len, loff_t *offset)
{
    return len;
}

long led_ioctl(struct file *filp, 
               unsigned int cmd,
               unsigned long arg)
{
    int ret = 0;
    int k_index = 0;

    ret = copy_from_user(&k_index, 
                         (const void *)arg, 4);
    
    if(k_index> 4 || k_index<1)
    {
        return -EINVAL;
    }

    switch(cmd)
    {
        case CMD_LED_ON:
            gpio_set_value(leds[k_index-1].gpio, 0);
            break;
        case CMD_LED_OFF:
            gpio_set_value(leds[k_index-1].gpio, 1);
            break;
        default:
            return -EINVAL;
    }

    return 0;
}

struct file_operations led_fops =
{
    .owner = THIS_MODULE,
    .open  = led_open,
    .release = led_close,
    .write = led_write,
    .read = led_read,
    .unlocked_ioctl = led_ioctl,
};
int __init led_drv_init(void)
{
    int i = 0;
    if(major) //静态
    {
        //dev = major<<20|minor;
        dev = MKDEV(major, minor);

        register_chrdev_region(dev, 1, "myleds");
    }
    else //动态注册
    {
        alloc_chrdev_region(&dev, minor, 1, "myleds");
        printk("<1>" "major=%d minor=%d\n",
                MAJOR(dev), MINOR(dev));
    }
    /*2 初始化cdev变量*/
    cdev_init(&led_cdev, &led_fops);
    /*3 注册cdev变量*/
    cdev_add(&led_cdev, dev, 1);
    
    for(i=0; i<ARRAY_SIZE(leds); i++)
    {
        /*申请GPIO管脚*/
        gpio_request(leds[i].gpio, leds[i].name);
        /*使用GPIO管脚*/
        gpio_direction_output(leds[i].gpio, 1);
    }
    return 0;
}
void __exit led_drv_exit(void)
{
    int i = 0;
    for(i=0; i<ARRAY_SIZE(leds); i++)
    {
        /*释放GPIO管脚*/
        gpio_free(leds[i].gpio);
    }
    /*4 注销cdev*/
    cdev_del(&led_cdev);

    unregister_chrdev_region(dev, 1);
}
module_init(led_drv_init);
module_exit(led_drv_exit);
  1 #include "../../global.h"
  2 #include <linux/fs.h>
  3 #include <linux/cdev.h>
  4 #include <linux/gpio.h>
  5 #include <mach/platform.h>
  6 #include <linux/uaccess.h>
  7 #include <linux/device.h>
  8 
  9 #define CMD_LED_ON  (0x10001)
 10 #define CMD_LED_OFF (0x10002)
 11 
 12 struct class *cls = NULL;
 13 
 14 unsigned int major = 0;
 15 unsigned int minor = 5;
 16 dev_t dev ; //设备号
 17 
 18 /*1 定义一个struct cdev变量*/
 19 struct cdev led_cdev;
 20 
 21 typedef struct led_desc
 22 {
 23     int gpio;//管脚编号
 24     char *name;//名称
 25 }led_desc_t;
 26 
 27 led_desc_t leds[]=
 28 {
 29     {PAD_GPIO_C+12, "led1"},
 30     {PAD_GPIO_C+7 , "led2"},
 31     {PAD_GPIO_C+11, "led3"},
 32     {PAD_GPIO_B+26, "led4"},
 33 };
 34 
 35 
 36 static int led_open(struct inode *inode, 
 37                     struct file *filp)
 38 {
 39     return 0;
 40 }
 41 static int led_close(struct inode *inode, 
 42                     struct file *filp)
 43 {
 44     return 0;
 45 }
 46 ssize_t led_write(struct file *filp, 
 47                   const char __user *buf,
 48                   size_t len, loff_t *offset)
 49 {
 50     return len;
 51 }
 52 ssize_t led_read(struct file *filp, 
 53                  char __user *buf,
 54                  size_t len, loff_t *offset)
 55 {
 56     return len;
 57 }
 58 
 59 long led_ioctl(struct file *filp, 
 60                unsigned int cmd,
 61                unsigned long arg)
 62 {
 63     int ret = 0;
 64     int k_index = 0;
 65 
 66     ret = copy_from_user(&k_index, 
 67                          (const void *)arg, 4);
 68     
 69     if(k_index> 4 || k_index<1)
 70     {
 71         return -EINVAL;
 72     }
 73 
 74     switch(cmd)
 75     {
 76         case CMD_LED_ON:
 77             gpio_set_value(leds[k_index-1].gpio, 0);
 78             break;
 79         case CMD_LED_OFF:
 80             gpio_set_value(leds[k_index-1].gpio, 1);
 81             break;
 82         default:
 83             return -EINVAL;
 84     }
 85 
 86     return 0;
 87 }
 88 
 89 struct file_operations led_fops =
 90 {
 91     .owner = THIS_MODULE,
 92     .open  = led_open,
 93     .release = led_close,
 94     .write = led_write,
 95     .read = led_read,
 96     .unlocked_ioctl = led_ioctl,
 97 };
 98 int __init led_drv_init(void)
 99 {
100     int i = 0;
101     if(major) //静态
102     {
103         //dev = major<<20|minor;
104         dev = MKDEV(major, minor);
105 
106         register_chrdev_region(dev, 1, "myleds");
107     }
108     else //动态注册
109     {
110         alloc_chrdev_region(&dev, minor, 1, "myleds");
111         printk("<1>" "major=%d minor=%d\n",
112                 MAJOR(dev), MINOR(dev));
113     }
114     /*2 初始化cdev变量*/
115     cdev_init(&led_cdev, &led_fops);
116     /*3 注册cdev变量*/
117     cdev_add(&led_cdev, dev, 1);
118     /*自动产生设备文件*/
119     /*会产生 /sys/class/LEDS/*/
120     cls = class_create(THIS_MODULE, "LEDS");
121     /*会产生 /sys/class/LEDS/myleds/ */
122     device_create(cls,NULL,dev, NULL,"myleds");
123 
124     for(i=0; i<ARRAY_SIZE(leds); i++)
125     {
126         /*申请GPIO管脚*/
127         gpio_request(leds[i].gpio, leds[i].name);
128         /*使用GPIO管脚*/
129         gpio_direction_output(leds[i].gpio, 1);
130     }
131     return 0;
132 }
133 void __exit led_drv_exit(void)
134 {
135     int i = 0;
136     for(i=0; i<ARRAY_SIZE(leds); i++)
137     {
138         /*释放GPIO管脚*/
139         gpio_free(leds[i].gpio);
140     }
141     /*自动销毁设备文件*/
142     device_destroy(cls, dev);
143     class_destroy(cls);
144 
145     /*4 注销cdev*/
146     cdev_del(&led_cdev);
147 
148     unregister_chrdev_region(dev, 1);
149 }
150 module_init(led_drv_init);
151 module_exit(led_drv_exit);

 

标签:硬件资源,led,struct,int,dev,ioctl,.....,cdev,GPIO
来源: https://www.cnblogs.com/DXGG-Bond/p/11844763.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有