zoukankan      html  css  js  c++  java
  • 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);

  • 相关阅读:
    Educational Codeforces Round 67 D. Subarray Sorting
    2019 Multi-University Training Contest 5
    Educational Codeforces Round 69 (Rated for Div. 2) E. Culture Code
    Educational Codeforces Round 69 D. Yet Another Subarray Problem
    2019牛客暑期多校训练第六场
    Educational Codeforces Round 68 E. Count The Rectangles
    2019牛客多校第五场题解
    2019 Multi-University Training Contest 3
    2019 Multi-University Training Contest 2
    [模板] 三维偏序
  • 原文地址:https://www.cnblogs.com/yuzaipiaofei/p/4124231.html
Copyright © 2011-2022 走看看