sysfs方式實現馬達驅動

來源:互聯網
上載者:User

由於對
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);



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.