• sysfs方式实现马达驱动


     

    sysfs方式实现马达驱动

    分类: linux驱动   http://blog.csdn.net/tjd0227/article/details/5517256

        由于对sysfs的概念不是太清楚,只是知道sysfs是一种类似于/proc的虚拟文件系统,可以在用户空间读写sysfs中的相应文件访问或控制内核空间数据,后拜读各类文章后终于对sysfs及平台设备有了更深层次的理解,但读的再多不如亲手一试。恰巧公司需要为android系统提供一个马达驱动,并且android又恰巧很多驱动的读写方式都是通过sysfs操作的,于是开始行动……

    #define VIBRA_MINOR 88

    #define STARTUP_VIBRA_DELAY 150

    static unsigned int onkey_stat; 
    static struct timer_list vibra_timer;

    static void vibra_stop_vibration(unsigned long data) 
    {        
        struct micco_vibra *vibra = (void *)data; 
        struct vibra_control *control = vibra->vibra_ctl; 
        control->level = 0x0; 
        micco_write(MICCO_VIBRA_CONTROL, control->level); 
    }

    static int raw_vibrate(int level) //驱动马达,level控制转速 

        u8 val; 
        val = level & 0x00fe; 
        DMSG("+/-vibra_ioctl/n"); 
        micco_write(MICCO_VIBRA_CONTROL, val); 
        return 0;

    }

    static int adv_vibrate(struct vibra_control *ctl) //驱动马达,level控制转速 

        u8 val; 
        val = ctl->level & 0x00fe; 
        micco_write(MICCO_VIBRA_CONTROL, val); 
        mod_timer(&vibra_timer, jiffies + msecs_to_jiffies(ctl->m_time));

        return 0; 
    }

    static int vibra_ioctl(struct inode *inode, struct file *file, 
        unsigned int cmd, unsigned long arg) //用户空间通过ioctl操作马达 

        int ret; 
        unsigned int level; 
        u8 val;
     
        unsigned int onkey_val; 
        struct vibra_control ctl;

        switch(cmd) { 
        case VIBRA_RAW_VIBTATION: 
            ret = copy_from_user(&level, (void *)arg, sizeof(unsigned int)); 
            ret = raw_vibrate(level); 
            break;

        case VIBRA_ADV_VIBTATION: 
            ret = copy_from_user(&ctl, (void *)arg, sizeof(struct vibra_control)); 
            ret = adv_vibrate(&ctl);        
            break;

        case VIBRA_POWERON_STAT_GET: 
            ret = copy_to_user((void *)arg, &onkey_stat, sizeof(unsigned int)); 
            break;

        case VIBRA_ONKEY_STAT_GET: 
            ret = micco_read(MICCO_STATUS_A, &val);

            if (ret < 0) { 
                printk("read  MICCO_STATUS_A failed/n"); 
                onkey_val = 0; 
            }

            onkey_val = !(val & MICCO_STATUS_A_ONKEY);

            ret = copy_to_user((void *)arg, &onkey_val, sizeof(unsigned int));

            break;

        default: 
            if (cmd < 0xFF) 
                ret = raw_vibrate(cmd); 
            else 
                ret = -ENOIOCTLCMD; 
        }

        return ret; 
    }

    /*用户空间读取马达运转时间*/ 
    static ssize_t vibrator_mtime_show(struct device *dev, 
                           struct device_attribute *attr, char *buf)
     

        struct micco_vibra        *vibra = dev_get_drvdata(dev); 
        struct vibra_control     *control = vibra->vibra_ctl;

        return sprintf(buf, "%u/n", control->m_time); 
    }

    /*用户空间修改马达运转时间*/ 
    static ssize_t vibrator_mtime_store(struct device *dev, 
                        struct device_attribute *attr, 
                        const char *buf, size_t count)
     

        struct micco_vibra        *vibra = dev_get_drvdata(dev); 
        struct vibra_control     *control = vibra->vibra_ctl; 
        char *endp;

        control->m_time = simple_strtoul(buf, &endp, 10); 
        DMSG("vibrator_mtime_store: m_tme = %d/n",control->m_time ); 
        adv_vibrate(control); 
        return count; 
    }

    /*属性设置及读写属性注册*/ 
    static DEVICE_ATTR(mtime, 0664, vibrator_mtime_show, 
               vibrator_mtime_store);

    /*用户空间读马达转速*/ 
    static ssize_t vibrator_level_show(struct device *dev, 
                           struct device_attribute *attr, char *buf)
     

        struct micco_vibra        *vibra = dev_get_drvdata(dev); 
        struct vibra_control     *control = vibra->vibra_ctl;

        return sprintf(buf, "%u/n", control->level); 
    }

    /*用户空间调整马达转速*/ 
    static ssize_t vibrator_level_store(struct device *dev, 
                        struct device_attribute *attr, 
                        const char *buf, size_t count)
     

        struct micco_vibra        *vibra = dev_get_drvdata(dev); 
        struct vibra_control     *control = vibra->vibra_ctl; 
        char *endp;

        control->level = simple_strtoul(buf, &endp, 10); 
        DMSG("vibrator_level_store:raw_vibrate(%x)", control->level); 
        adv_vibrate(control); 
        return count; 
    }

    /*属性设置及读写属性注册*/ 
    static DEVICE_ATTR(level, 0664, vibrator_level_show, 
               vibrator_level_store);

    static struct file_operations vibra_fops = { 
        .owner        = THIS_MODULE,  
        .ioctl      = vibra_ioctl, 
    };

    static struct miscdevice vibra_miscdev = { 
        .minor        = VIBRA_MINOR, 
        .name        = "micco_vibra", 
        .fops        = &vibra_fops, 
    };

    static int __devinit vibra_init(struct micco_vibra *vibra) 

        struct vibra_control *ctl; 
        int ret; 
        u8 val;

        ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); 
        if (ctl == NULL) 
            return -ENOMEM; 
        vibra->vibra_ctl = ctl; 
        ctl->level=0; 
        ctl->m_time=0;


        vibra_timer.function = vibra_stop_vibration;  
        vibra_timer.data = (unsigned long) vibra; 
        init_timer(&vibra_timer);

       /*注册vibra_miscdev设备*/ 
       ret = misc_register(&vibra_miscdev);    
       if (ret < 0) { 
            dev_err(&vibra->pdev->dev, "can't register vibra device/n"); 
            goto err2; 
      }


        printk("/nVIBRA Probe vibra_miscdev->minor=%d/n",vibra_miscdev.minor); 
        ret = micco_read(MICCO_FAULT_LOG, &val); 
        printk("Fault Log value is 0x%x---------->/n", val); 
        ret = micco_read(MICCO_STATUS_A, &val); 
        if (ret < 0) { 
            printk("read  MICCO_STATUS_A failed/n"); 
            onkey_stat = 0; 
            return 0; 
        }

        onkey_stat = !(val & MICCO_STATUS_A_ONKEY); 
        if (onkey_stat) { 
            raw_vibrate(0x7e); 
            mdelay(100); 
            raw_vibrate(0x0); 
        }  

       /*创建sysfs文件系统节点*/ 
       if (device_create_file(&vibra->pdev->dev, &dev_attr_level) < 0) 
            goto err3; 
       if (device_create_file(&vibra->pdev->dev, &dev_attr_mtime) < 0) 
            goto err4;

       return 0; 
    /* 
    err5: 
        device_remove_file(&vibra->pdev->dev, &dev_attr_vibrator_mtime); 
    */ 
    err4: 
        device_remove_file(&vibra->pdev->dev, &dev_attr_level); 
    err3: 
        misc_deregister(&vibra_miscdev); 
    err2: 
        kfree(ctl); 
        return ret; 
    }

    static void __devexit vibra_exit(struct micco_vibra *vibra) 

        device_remove_file(&vibra->pdev->dev, &dev_attr_mtime); 
        device_remove_file(&vibra->pdev->dev, &dev_attr_level);

        misc_deregister(&vibra_miscdev); 
    }

    /**************************************************************************** 
    * Initialization / Registeration / Removal 
    ***************************************************************************/ 
    static int vibra_probe(struct platform_device *pdev) 

        struct micco_vibra            *vibra; 
        int r = -ENODEV;

        vibra = kzalloc(sizeof(*vibra), GFP_KERNEL); 
        if (vibra == NULL) 
            return -ENOMEM;

        /*注册驱动数据 */ 
        dev_set_drvdata(&pdev->dev, vibra);

        vibra->pdev = pdev;

        r = vibra_init(vibra); 
        if (r) 
            goto err1;

        return 0; 
    err1: 
        kfree(vibra); 
        return r;

    }

    static int vibra_remove(struct platform_device *pdev) 

        struct micco_vibra *vibra = dev_get_drvdata(&pdev->dev);

        dev_dbg(&vibra->pdev->dev, "%s/n", __FUNCTION__); 
        vibra_exit(vibra); 
        kfree(vibra); 
        return 0; 
    }

    static struct platform_device vibra_plat_device = { 
        .name        = "micco-vibra",  //sysfs设备目录“/sys/devices/platform/micco-vibra.0” 
        .id        = 0, 
    };

    static struct platform_driver vibra_plat_driver = { 
        .driver = { 
           .name     = "micco-vibra", //和vibra_plat_device 的name名字相同 
            .owner = THIS_MODULE, 
        }, 
        .probe        = vibra_probe, 
        .remove        = vibra_remove, 
    };

    static int __init plat_vibra_init(void) 

        int rc; 
        printk("vibra driver initializing/n"); 
       rc = platform_device_register(&vibra_plat_device); 
        if (rc < 0) 
            return rc; 
       rc = platform_driver_register(&vibra_plat_driver); 
        if (rc < 0) 
            goto err_register_vibra_dev; 
        return rc;

    err_register_vibra_dev: 
        platform_device_unregister (&vibra_plat_device); 
        return rc; 

    static void __exit plat_vibra_exit(void) 

        platform_driver_unregister(&vibra_plat_driver); 
        platform_device_unregister (&vibra_plat_device); 
    }

    module_init(plat_vibra_init); 
    module_exit(plat_vibra_exit);

  • 相关阅读:
    互动留言赠书:《Oracle高性能系统实战大全》
    超融合硬件损坏导致Oracle RAC异常恢复实录
    架构师不得不了解的硬件知识
    加班做的可视化被老板嫌弃,是因为你不会用这些数据工具
    iOS开发之七:常用控件--UISlider、UISegmentedControl、UIPageControl的使用
    iOS开发之六:常用控件--UIImageView的使用
    iOS开发之五:常用控件--UITextField的使用
    Objective-C实现常用的4种排序算法
    C语言实现4种常用排序
    面试常用的4种数组排序
  • 原文地址:https://www.cnblogs.com/yuzaipiaofei/p/4124231.html
Copyright © 2020-2023  润新知