sysfs方式实现马达驱动

来源:互联网 发布:淘宝儿童玩具 编辑:程序博客网 时间:2024/05/17 06:52
 由于对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);

原创粉丝点击