• 9.13作业


    #include <linux/init.h>

    #include

    #include

    #include

    #include

    #include

    #include

    struct cdev *cdev

    char kbuf[128]=0;

    unsigned int major=0;

    unsigned int minor=0;

    dev_t devno;

    module-param(major,unit,0664); //方便在命令行传递major的值

    struct class*cls;

    struct device *dev;

    struct mutex mutex; //定义互斥体



     

    int mycdev_open(struct inode *inode,struct file*file)

    {

        mutex_lock(&mutex);//上锁

        printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);

        return 0;

    }

    long mycdev_ioctl(struct file *file,unsigned int cmd,unsigned long arg)

    {

        int which;

        //获取arg对应的用户空间中的值

        int ret=copy_from_user(&which,(void *)arg,4);

        if(ret)

        {

            printk("从用户空间获取数据失败\n");

            return -EIO;

        }

        switch (cmd)

        {

            case LED_ON:

            switch(which)

            {

                case 1: //LED1

                    vir_led1->ODR |= 1 << 10;

                    break;

                case 2:

                    vir_led2->ODR |= 1 << 10;

                    break;

                case 3:

                    vir_led3->ODR |= 1 << 8;

                    break;

            }

            break;

            case LED_OFF:

            switch(which)

            {

                case 1: //LED1

                     vir_led1->ODR &= (~(1 << 10));

                     break;

                case 2:

                     vir_led2->ODR &= (~(1 << 10));

                     break;

                case 3:

                     vir_led3->ODR &= (~(1 << 8));

                     break;

            }

            break;

        }

        return 0;

    }

    nt mycdev_close(struct inode *inode,struct file *file)

    {

         mutex_unlock(mutex);//解锁

         printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);

         return 0;

    }

    //定义操作方法结构体变量并赋值

    struct file_operation fops={

        .open=mycdev_open,

        .read=mycdev_read,

        .write=mycdev_write,

        .realease=mycdev_close,

    };

    int all_led_init(void)

    {

        vir_led1=ioremap(PHY_LED1_ADDR,sizeof(gpio_t));

        if(vir_led1==NULL)

        {

            printk("ioremap filed: %d\n",__LINE__);

            return -ENOMEM;

        }

          vir_led2=ioremap(PHY_LED2_ADDR,sizeof(gpio_t));

        if(vir_led2==NULL)

        {

            printk("ioremap filed: %d\n",__LINE__);

            return -ENOMEM;

        }

        vir_led3=vir_led1;

        vir_rcc=ioremap(PHY_RCC_ADDR,4);

        if(vir_rcc==NULL)

        {

            printk("ioremap filed: %d\n",__LINE__);

            return -ENOMEM;

        }

    printk("物理地址映射成功\n");

    //寄存器的初始化

    //rcc

    (*vir_rcc) |= (0x3<<4);

    //LED1

    vir_led1->MODER &= (~(3<<20));

    vir_led1->MODER |= (1<<20);

    vir_led1->ODR &= (~(1<<10));

    //LED2

    vir_led2->MODER &= (~(3<<20));

    vir_led2->MODER |= (1<<20);

    vir_led2->ODR &= (~(1<<10));

    //LED3

    vir_led3->MODER &= (~(3<<16));

    vir_led3->MODER |= (1<<16;

    vir_led3->ODR &= (~(1<<8));

    printk("寄存器初始化成功\n");

    return 0;

    }

    static int __init mycdev_init(void)

    {

        int ret;

        //为字符设备驱动对象申请空间

        cdev=cdev_alloc();

        if(cdev==NULL)

        {

            printk(" 字符设备驱动对象申请空间失败\n");

            ret=-EFAULT;

            goto out1;

           

        }

        printk("申请对象空间成功");

        //初始化字符设备驱动对象

        cdev——init(cdev,&fops);

        //申请设备号

        if(major>0)//静态指定设备号

        {

            ret=register_chrdev_region(MKDEV(major,minor),3,"myled");

            if(ret)

            {

                printk("静态申请设备号失败\n");

                goto out2;

            }

        }

        else if(major==0)//动态申请设备号

        {

           ret=register_chrdev_region(MKDEV(major,minor),3,"myled");

            if(ret)

            {

                printk("动态申请设备号失败\n");

                goto out2;

            }

            major=MAJOR(devno);//获取主设备号

            major=MINOR(devno);//获取次设备号

        }

        printk("申请设备号成功\n");

       

        mutex_init(&mutex);//初始化互斥体  

        //字符设备驱动对象注册

        ret=cdev_add(cdev,MKDEV(major,minor),3);

        if(ret)

        {

            printk("字符设备驱动对象注册失败\n");

            goto out3;

        }

        printk("字符设备驱动对象注册成功\n");

        //寄存器映射以及初始化

        all_led_init();

        //向上提交目录

        cls=class_create(THIS_MODULE,"myled");

        if(IS_ERR(cls))

        {

            printk("向上提交目录失败\n");

            return -PTR_ERR(cls);

            goto out4;

        }

        printk("向上提交目录成功\n");

        //向上提交设备节点信息

        int i;

        for(i=0;i<3;i++)

        {

            dev=device_create(cls,NULL,MKDEV(major,i)NULL,"mychrdevv%d",i);

            if(IS_ERR(dev))

            {

                printk("向上提交设备节点信息失败\n");

                return -PTR_ERR(dev);

            }

        }

        printk("向上提交设备节点信息成功\n");

        return 0;

    }

    out5:

         //释放前一次提交成功的设备信息

         for(--i;i>=0;i--)

         {

            device_destory(cls,MKDEV(major,i));

         }

         class_destory(cls);//释放目录

    out4:

        cdev_del(cdev);

    out3:

         unregister_chrdev_region(MKDEV(major,minor),3);

    out2:

        kfree(cdev);

    out1:

        return ret;

    static void __exit mycdev_exit(void)

    {

        //销毁设备节点信息

        int i;

        for(i=0;i<3;i++)

        {

            device_destory(cls,MKDEV(major,i));

        }

        //销毁目录信息

        class_destory(cls);

        //取消地址映射

        iounmap(vir_led1);

        iounmap(vir_led2);

        iounmap(vir_rcc);

        //注销字符设备驱动对象

        cdev_del(cdev);

        //释放设备号

        unregister_chrdev_region(MKDEV(major,minor),3);

        //释放对象空间

        kfree(cdev);

       

    }

    module_init(mycdev_init);

    module_exit(mycdev_exit);

    MODULE_LICENSE("GPL");

  • 相关阅读:
    触摸一体机广告机开发板_MTK联发科平台超小型安卓主板方案
    数据结构— —循环队列
    如何使用mysql binlog 恢复数据
    2023年【电工(中级)】考试题库及电工(中级)模拟考试
    Qt QWidget 简约美观的加载动画 第五季 - 小方块风格
    【T+】删除/取消畅捷通T+软件登录账套后的“查看认证”按钮
    UE4 C++:Actor与Component的创建、销毁
    SpringSecurity系列一:04 SpringSecurity 的默认用户是如何生成的?
    隔离第68天,我把“大厂面试指南”进行了重新梳理,V3.0版已上线
    Elasticsearch如何聚合查询多个统计值,如何嵌套聚合?并相互引用,统计索引中某一个字段的空值率?语法是怎么样的?
  • 原文地址:https://blog.csdn.net/weixin_72099373/article/details/132863586