• 绑定设备文件与设备


    head.h

    #ifndef __HEAD_H__

    #define __HEAD_H__

    typedef struct

    {

        unsigned int MODER;

        unsigned int OTYPER;

        unsigned int OSPEEDR;

        unsigned int PUPDR;

        unsigned int IDR;

        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('l',1,int)

    #define LED_OFF _IOW('l',0,int)

    #endif

    test.c

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include"head.h"

    int main(int argc,const char * argv[])

    {

        char buf[128]={0};

        int a,b;

       

        printf("打开设备文件成功\n");

         while(1)

        {

            //从终端读取

            int fd;

            printf("请选择要控制的灯:1(LED1)2(LED2)3(LED3)\n");

            printf("请输入>");

            scanf("%d",&a);

            printf("请输入要实现的功能 ");

            printf("0(关灯) 1(开灯)\n");

            printf("请输入>");

            scanf("%d",&b);

           

    switch(a)

            {

                case 1:

                fd=open("/dev/mycdev0",O_RDWR);

                if(fd < 0)

                 {

                    printf("打开设备文件失败\n");

                  return -1;

                 }

                if(b==1)

                    ioctl(fd,LED_ON,&b);

                else if(b==0)

                    ioctl(fd,LED_OFF,&b);

                else

                   b=0;

                    break;

                case 2:

                fd=open("/dev/mycdev1",O_RDWR);

                if(fd < 0)

                 {

                    printf("打开设备文件失败\n");

                  return -1;

                 }

                if(b==1)

                    ioctl(fd,LED_ON,&b);

               else if(b==0)

                    ioctl(fd,LED_OFF,&b);

                else

                   b=0;

                    break;

                case 3:

                fd=open("/dev/mycdev2",O_RDWR);

                if(fd < 0)

                 {

                    printf("打开设备文件失败\n");

                  return -1;

                 }

                 if(b==1)

                    ioctl(fd,LED_ON,&b);

                 else if(b==0)

                    ioctl(fd,LED_OFF,&b);

                else

                   b=0;

                    break;

            }

            close(fd);

        }

       

        return 0;

    }

    mycdev.c

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include"head.h"

    char kbuf[128]={0};

    gpio_t *vir_led1;

    gpio_t *vir_led2;

    gpio_t *vir_led3;

    unsigned int *vir_rcc;

    struct cdev *cdev;

    unsigned int major=0;

    unsigned int minor=0;

    dev_t devno;

    struct class *cls;

    struct device *dev;

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

    {

        int min=MINOR(inode->i_rdev);//获取打开的的文件的次设备号

        file->private_data= (void *)min;

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

        return 0;

    }

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

    {

       int min=(int)file->private_data;//获取到文件的次设备号

       switch(min)

       {

            case 0://操作LED1

                switch(cmd)

                {

                    case LED_ON://开灯

                    vir_led1->ODR |= (0X1<<10);

                        break;

                    case LED_OFF: //关灯

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

                        break;

                }

                break;

            case 1://操作LED2

                switch(cmd)

                {

                    case LED_ON://开灯

                    vir_led2->ODR |= (0X1<<10);

                        break;

                    case LED_OFF: //关灯

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

                        break;

                }

                break;

            case 2://操作LED3

                switch(cmd)

                {

                    case LED_ON://开灯

                    vir_led3->ODR |= (0X1<<10);

                        break;

                    case LED_OFF://关灯

                    vir_led3->ODR &= (~(0X1<<10));

                        break;

                }

                break;

       }

        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;

    }

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

    struct file_operations fops = {

        .open = mycdev_open,

        .unlocked_ioctl = mycdev_ioctl,

        .release = 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) |= (3<<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_led1->MODER |= (1<<16);

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

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

        return 0;

    }

    static int __init mycdev_init(void)

    {

        int ret;

        //申请一个对象空间 cdev_alloc

        cdev=cdev_alloc();

        if(cdev==NULL)

        {

            printk("申请对象空间失败\n");

            ret=-EFAULT;

            goto out1;

        }

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

        //初始化对象 cdev_init

        cdev_init(cdev, &fops);

        //申请设备号

        if (major==0)

        {

            ret=alloc_chrdev_region(&devno, minor, 3,"mychrdev");

            if(ret)

            {

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

                goto out2;

            }

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

            minor=MINOR(devno);//根据设备获取次设备号

            printk("字符主设备驱动注册成功:major=%d\n",major);

            printk("字符次设备驱动注册成功:minor=%d\n",minor);

        }

        else

        {

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

            if(ret)

            {

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

                goto out2;

            }

        }

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

        //注册驱动对象

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

        if(ret)

        {

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

            goto out3;

        }

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

        //向上提交目录

        cls=class_create(THIS_MODULE,"mychrdev");

        if(IS_ERR(cls))

        {

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

            goto out4;

        }

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

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

        int i;

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

        {

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

            if(IS_ERR(dev))

            {

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

                goto out5;

            }

        }

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

        all_led_init();

        return 0;

    out5:

        //将提交成功的信息释放

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

        {

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

        }

        //将提交失败的信息销毁

        class_destroy(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;

        iounmap(vir_led1);

        iounmap(vir_led2);

        iounmap(vir_led3);

        iounmap(vir_rcc);

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

        {

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

        }

        //销毁目录

        class_destroy(cls);

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

        cdev_del(cdev);

        //释放设备号

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

        //释放申请到的字符设备驱动对象空间

        kfree(cdev);

    }

    module_init(mycdev_init);

    module_exit(mycdev_exit);

    MODULE_LICENSE("GPL");

  • 相关阅读:
    Day23——修剪二叉搜索树、将有序数组转化为二叉搜索树、把二叉搜索树转化为累加树
    【数据结构】二叉树必刷题
    x86 --- 任务隔离特权级保护
    【LeetCode与《代码随想录》】链表篇:做题笔记与总结-JavaScript版
    万字详解C++避坑指南总结
    代码随想录算法训练营第56天 | 编辑距离
    time,datetime模块时间序列讲解
    SpringBoot整合Websocket(Java websocket怎么使用)
    3D模型格式转换工具HOOPS Exchange:如何将3D PDF转换为STEP格式?
    手撕SparkSQL五大JOIN的底层机制
  • 原文地址:https://blog.csdn.net/whytobe/article/details/133997801