• 私有数据传参


    在串口工具进行输入:
    echo 1 > /dev/myled0 ---->led1灯点亮
    echo 0 > /dev/myled0 ---->led1灯熄灭
    echo 1 > /dev/myled1 ---->led1灯点亮
    echo 0 > /dev/myled1 ---->led1灯熄灭
    echo 1 > /dev/myled2 ---->led1灯点亮
    echo 0 > /dev/myled2 ---->led1灯熄灭
    linux@ubuntu:/sys/class/myled$ ls /dev/myled* -ll

    crw------- 1 root root 236, 0 Nov 18 14:55 /dev/myled0 ----->控制PE10(LED1)
    crw------- 1 root root 236, 1 Nov 18 14:55 /dev/myled1----->控制PF10(LED2)
    crw------- 1 root root 236, 2 Nov 18 14:55 /dev/myled2----->控制PE8(LED3)

    2.驱动:
    open:在open函数中获取到次设备号,用私有数据传参,传递给write函数
    write:在write函数,判断次设备号,就知道操作的是哪盏灯

    3.要求:
    1)分部实现注册字符设备驱动
    2)自动创建设备节点
    3)通过结构体对led灯地址进行映射
    4)次设备号完成私有数据传参

    mychar.c

    #include 
    #include 
    #include 
    #include 
    #include 
    #include "led.h"
    #include 
    #include 
    #include 
    #include 
    
    #define CNAME "myled"
    struct class* clas;
    struct device* devic;
    dev_t dev;
    int major;
    char kbuf[128] = {0};
    
    gpio_t *vir_led1;
    gpio_t *vir_led2;
    gpio_t *vir_led3;
    volatile unsigned int *vir_rcc;
    int i=0;
    struct cdev* cdev;
    #if 1
    int major =0;//动态申请设备号
    #else
    int major = 500;    //静态申请设备号
    #endif
    int minjor=0;
    
    
    int count =3;
    dev_t dev;
    
    int mycdev_open(struct inode *inode, struct file *file)
    {
    
        int minjor;
        printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
        //通过inode结构体取到次设备号
        minjor = MINOR(inode->i_rdev);
        //将次设备号放到file结构体私有数据中
        file->private_data = (void*)minjor;
        return 0;
    }
    
    ssize_t mycdev_write(struct file *file, const char __user *user, size_t size, loff_t *loff)
    {
        int ret;
        int minjor;
        char kbuf[128]={0};
        if(sizeof(kbuf)<size)
        size = sizeof(kbuf);
        //用户空间向内核空间传送数据
        ret = copy_from_user(kbuf,user,size);
        if(ret)
        {
            printk("copy_from_user is error\n");
            return -EIO;
        }
        //利用私有数据传参拿到open函数渠道的次设备号
        minjor = (int)file->private_data;
        switch(minjor)
        {
            //次设备号0控制1号灯
            case 0:
            switch(kbuf[0])
            {
                //终端输入字符0熄灭
                case '0':
                vir_led1->ODR &= (~(0x1 << 10));
                break;
                //终端输入字符1点亮
                case '1':
                vir_led1->ODR |= (0x1 << 10); 
                break;
            }
            break;
            //次设备号1控制2号灯
            case 1:
            switch(kbuf[0])
            {
                //终端输入字符0熄灭
                case '0':
                vir_led2->ODR &= (~(0x1 << 10));
                break;
                 //终端输入字符1点亮
                case '1':
                vir_led2->ODR |= (0x1 << 10); 
                break;
            }
    
            break;
            //次设备号2控制3号灯
            case 2:
            switch(kbuf[0])
            {
                //终端输入字符0熄灭
                case '0':
                vir_led3->ODR &= (~(0x1 << 8));
                break;
                 //终端输入字符1点亮
                case '1':
                vir_led3->ODR |= (0x1 << 8); 
                break;
            }
    
            break;
    
        }
        printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
        return 0;
    }
    ssize_t mycdev_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff)
    {
        printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
        return 0;
    }
    
    
    
    int mycdev_close(struct inode *inode, struct file *file)
    {
        printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
        return 0;
    }
    
    const struct file_operations fops =
        {
            .open = mycdev_open,
            .release = mycdev_close,
            .read = mycdev_read,
            .write = mycdev_write,
    
    };
    
    int leds_init(void)
    {
        //rcc 寄存器地址进行映射
        vir_rcc = ioremap(PHY_RCC_ADDR, 4);
        if (vir_rcc == NULL)
        {
            printk("vir_rcc faild\n");
            return -ENOMEM;
        }
        //led1 的addr寄存器地址进行映射
    
        vir_led1 = ioremap(PHY_LED1_ADDR, sizeof(gpio_t));
        if (vir_led1 == NULL)
        {
            printk("vir_led1 faild\n");
            return -ENOMEM;
        }
          //led2 的addr寄存器地址进行映射
        vir_led2 = ioremap(PHY_LED2_ADDR, sizeof(gpio_t));
        if (vir_led2 == NULL)
        {
            printk("vir_led2 faild\n");
            return -ENOMEM;
        }
          //led3 的addr寄存器地址进行映射
    
        vir_led3 = ioremap(PHY_LED3_ADDR, sizeof(gpio_t));
        if (vir_led3 == NULL)
        {
            printk("vir_led3 faild\n");
            return -ENOMEM;
        }
    
        //初始化寄存器部分
    
        // rcc寄存器初始化
        *vir_rcc |= (0x3 << 4);
    
        // led1-》moder和odr寄存器初始化
        vir_led1->MODER &= ~(0x3 << 20);
        vir_led1->MODER |= (0x1 << 20);
        vir_led1->ODR &= ~(0x1 << 10);
    
        // led2-》moder和odr寄存器初始化
        vir_led2->MODER &= ~(0x3 << 20);
        vir_led2->MODER |= (0x1 << 20);
        vir_led2->ODR &= ~(0x1 << 10);
    
        // led3-》moder和odr寄存器初始化
        vir_led3->MODER &= ~(0x3 << 16);
        vir_led3->MODER |= (0x1 << 16);
        vir_led3->ODR &= ~(0x1 << 8);
    
        return 0;
    }
    
    
    //入口
    static int __init mycdev_init(void)
    {
        int ret;
        
       
    
        //1.分配cdev结构体
        
         cdev = cdev_alloc();
         if(NULL==cdev)
         {
            goto ERR1;
         }
    
        //2.初始化结构体
        cdev_init(cdev, &fops);
        
    
        //3.动态申请设备号
        if(major == 0)
        {
            ret = alloc_chrdev_region(&dev, minjor, count, CNAME);
            if(ret)
            {
                printk("alloc_chrdev_rejion is error\n");
                ret =  -ENOMEM;
                goto ERR2;
                
            }
            major = MAJOR(dev);
            minjor = MINOR(dev);
        }
        //静态动态申请设备号
        else{
            ret = register_chrdev_region(MKDEV(major,minjor),count,CNAME);
            if(ret)
            {
                printk("register is error\n");
                ret = ENOMEM;
                goto ERR2;
            }
        }
        //4.驱动的注册
        ret = cdev_add(cdev, MKDEV(major, minjor), count);
        if(ret)
        {
            printk("cdev_add is err\n");
            ret = EIO;
            goto ERR3;
    
        }
        //5.自动创建设备节点
        printk("major=%d\n", major);
        //向上提交目录
        clas = class_create(THIS_MODULE,"lisi");
        if(IS_ERR(clas))
        {
            ret = PTR_ERR(clas);
            goto ERR4;
        }
        for(i=0; i<3; i++)
        {
            //向上提交设备节点信息,循环创建三个设备节点
            devic = device_create(clas, NULL,MKDEV(major,i),  NULL,"myled%d", i);
            if(IS_ERR(clas))
            {
                    ret = PTR_ERR(clas);
                    goto ERR5;
            }  
        }
        //初始化寄存器和映射物理地址函数
        leds_init();
        return 0;
    //销毁设备节点
    ERR5:
        for(--i; i>=0; i--)
        {
            device_destroy(clas, i);
        }
    ERR4:
    //注销字符设备驱动
        cdev_del(cdev);
    ERR3:
    //释放设备号
        unregister_chrdev_region(MKDEV(major,minjor),count);
    ERR2:
    
    //释放字符设备驱动
        kfree(cdev);
        
    ERR1:
        return EIO;
    
    
    
    }
    
    
    //出口
    static void __exit mycdev_exit(void)
    {
        iounmap(vir_led1);
        iounmap(vir_led2);
        iounmap(vir_led3);
        iounmap(vir_rcc);
    
        
    
        //1。销毁设备节点信息
        for(i=0; i<3; i++)
        {
            device_destroy(clas, MKDEV(major,i));
        }
        //2.销毁目录信息
        class_destroy(clas);
    
        //3.驱动的注销
         cdev_del(cdev);
        //4.销毁设备号
        unregister_chrdev_region(MKDEV(major,minjor),count);
        //5.释放cdev结构体   
        kfree(cdev);
        
    }
    
    module_init(mycdev_init);
    module_exit(mycdev_exit);
    
    MODULE_LICENSE("GPL");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324

    .h

    #ifndef __MYLED_H__
    #define __MYLED_H__
    
    typedef struct 
    {
        volatile unsigned int MODER;
        volatile unsigned int OTYPER;
        volatile unsigned int OSPEEDR;
        volatile unsigned int PUPDR;
        volatile unsigned int IDR;
        volatile unsigned int ODR;
    }gpio_t;
    
    #define PHY_LED1_ADDR 0X50006000
    #define PHY_LED2_ADDR 0X50007000
    #define PHY_LED3_ADDR 0X50006000
    #define PHY_RCC_ADDR  0X50000A28
    
    #define LED_ON _IOW('a',1,int)
    #define LED_OFF _IOW('a',0,int)
    
    
    typedef enum{
        LED1,
        LED2,
        LED3
    }led_t;
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    实验现象截图
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    Python函数与参数
    软件测试/测试开发丨结对编程助手 GitHubCopilot
    以命令行形式执行Postman脚本(使用Newman)
    EOS的共识机制与区块生成
    计算机毕业设计Javaweb唐院寻人表白系统(源码+系统+mysql数据库+lw文档)
    PAT 1022 Digital Library
    如何实现网站首页变为黑白色?
    【JAVA】-- 简易超市管理系统窗口(三)(实现思路+每步代码)
    Openai CLIP模型论文精读及详解
    超参数优化(网格搜索和贝叶斯优化)
  • 原文地址:https://blog.csdn.net/liuchengkun123/article/details/127941036