/* * SAMSUNG DBMDx event driver * * Copyright (c) 2014 Samsung Electronics Co. Ltd. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ #include #include #include #include #include #include #include struct platform_device *this_dev; struct samsung_dbmdx_event_priv { struct class *svoice_class; struct device *keyword_dev; unsigned int keyword_type; struct wake_lock wake_lock; }; static ssize_t svoice_keyword_type_show(struct device *dev, struct device_attribute *attr, char *buf) { struct samsung_dbmdx_event_priv *priv= dev_get_drvdata(dev); int ret; ret = snprintf(buf, PAGE_SIZE, "%x\n", priv->keyword_type); return ret; } static DEVICE_ATTR(keyword_type, S_IRUGO, svoice_keyword_type_show, NULL); void samsung_dbmdx_voicewakeup_cb(int word_id) { struct samsung_dbmdx_event_priv *priv; char keyword_buf[100]; char *envp[2]; memset(keyword_buf, 0, sizeof(keyword_buf)); dev_info(&this_dev->dev, "%s: word_id = %d\n", __func__, word_id); WARN_ON(!this_dev); if (!this_dev) return; priv = platform_get_drvdata(this_dev); if (!priv) return; priv->keyword_type = word_id; switch (word_id) { case 0: snprintf(keyword_buf, sizeof(keyword_buf), "VOICE_WAKEUP_WORD_ID=LPSD"); break; case 1: case 2: snprintf(keyword_buf, sizeof(keyword_buf), "VOICE_WAKEUP_WORD_ID=%x", priv->keyword_type); break; default: dev_err(&this_dev->dev, "Invalid word_id =%d", word_id); return; } envp[0] = keyword_buf; envp[1] = NULL; dev_info(&this_dev->dev, "%s : raise the uevent, string = %s\n", __func__, keyword_buf); wake_lock_timeout(&priv->wake_lock, 5000); kobject_uevent_env(&this_dev->dev.kobj, KOBJ_CHANGE, envp); return; } static int samsung_dbmdx_probe(struct platform_device *pdev) { struct samsung_dbmdx_event_priv *priv; int ret; priv = devm_kzalloc(&pdev->dev, sizeof(struct samsung_dbmdx_event_priv), GFP_KERNEL); if (!priv) return -ENOMEM; /* TO DO * It need dbmd patches to register callback func */ dbmdx_remote_register_event_callback(samsung_dbmdx_voicewakeup_cb); wake_lock_init(&priv->wake_lock, WAKE_LOCK_SUSPEND, "samsung-voicewakeup"); priv->svoice_class = class_create(THIS_MODULE, "svoice"); ret = IS_ERR(priv->svoice_class); if (ret) { pr_err("Failed to create class(svoice)!\n"); goto err_class_create; } priv->keyword_dev = device_create(priv->svoice_class, NULL, 0, priv, "keyword"); ret = IS_ERR(priv->keyword_dev); if (ret) { pr_err("Failed to create device(keyword)!\n"); goto err_device_create; } ret = device_create_file(priv->keyword_dev, &dev_attr_keyword_type); if (ret < 0) { pr_err("Failed to create device file in sysfs entries(%s)!\n", dev_attr_keyword_type.attr.name); goto err_device_create_file; } this_dev = pdev; platform_set_drvdata(pdev, priv); return 0; err_device_create_file: device_destroy(priv->svoice_class, 0); err_device_create: class_destroy(priv->svoice_class); err_class_create: wake_lock_destroy(&priv->wake_lock); devm_kfree(&pdev->dev, priv); return ret; } static int samsung_dbmdx_remove(struct platform_device *pdev) { struct samsung_dbmdx_event_priv *priv = platform_get_drvdata(pdev); device_remove_file(priv->keyword_dev, &dev_attr_keyword_type); device_destroy(priv->svoice_class, 0); class_destroy(priv->svoice_class); wake_lock_destroy(&priv->wake_lock); devm_kfree(&pdev->dev, priv); return 0; } static const struct of_device_id samsung_dbmdx_of_match[] = { {.compatible = "samsung,dbmdx-event",}, {}, }; MODULE_DEVICE_TABLE(of, samsung_dbmdx_of_match); static struct platform_driver samsung_dbmdx_event_driver = { .driver = { .name = "dbmdx-event", .owner = THIS_MODULE, .of_match_table = of_match_ptr(samsung_dbmdx_of_match), }, .probe = samsung_dbmdx_probe, .remove = samsung_dbmdx_remove, }; module_platform_driver(samsung_dbmdx_event_driver); MODULE_DESCRIPTION("SAMSUNG DBMDx event driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:dbmdx-event");