| /*! |
| * @section LICENSE |
| * (C) Copyright 2011~2016 Bosch Sensortec GmbH All Rights Reserved |
| * |
| * This software program is licensed subject to the GNU General |
| * Public License (GPL).Version 2,June 1991, |
| * available at http://www.fsf.org/copyleft/gpl.html |
| * |
| * @filename bstclass.c |
| * @date 2015/11/17 13:44 |
| * @id "836294d" |
| * @version 1.5.9 |
| * |
| * @brief |
| */ |
| #include <linux/init.h> |
| #include <linux/types.h> |
| #include <linux/module.h> |
| #include <linux/slab.h> |
| #include <linux/random.h> |
| #include <linux/sched.h> |
| #include <linux/seq_file.h> |
| #include <linux/poll.h> |
| #include <linux/mutex.h> |
| #include <linux/rcupdate.h> |
| #include <linux/compiler.h> |
| #include <linux/compat.h> |
| #include "bstclass.h" |
| #include "bs_log.h" |
| |
| static LIST_HEAD(bst_dev_list); |
| |
| /* |
| * bst_mutex protects access to both bst_dev_list and input_handler_list. |
| * This also causes bst_[un]register_device and bst_[un]register_handler |
| * be mutually exclusive which simplifies locking in drivers implementing |
| * input handlers. |
| */ |
| static DEFINE_MUTEX(bst_mutex); |
| |
| |
| static void bst_dev_release(struct device *device) |
| { |
| struct bst_dev *dev = to_bst_dev(device); |
| if (NULL != dev) |
| kfree(dev); |
| module_put(THIS_MODULE); |
| } |
| |
| |
| #ifdef CONFIG_PM |
| static int bst_dev_suspend(struct device *dev) |
| { |
| return 0; |
| } |
| |
| static int bst_dev_resume(struct device *dev) |
| { |
| return 0; |
| } |
| |
| static const struct dev_pm_ops bst_dev_pm_ops = { |
| .suspend = bst_dev_suspend, |
| .resume = bst_dev_resume, |
| .poweroff = bst_dev_suspend, |
| .restore = bst_dev_resume, |
| }; |
| #endif /* CONFIG_PM */ |
| |
| static const struct attribute_group *bst_dev_attr_groups[] = { |
| NULL |
| }; |
| |
| static struct device_type bst_dev_type = { |
| .groups = bst_dev_attr_groups, |
| .release = bst_dev_release, |
| #ifdef CONFIG_PM |
| .pm = &bst_dev_pm_ops, |
| #endif |
| }; |
| |
| |
| |
| static char *bst_devnode(struct device *dev, mode_t *mode) |
| { |
| return kasprintf(GFP_KERNEL, "%s", dev_name(dev)); |
| } |
| |
| struct class bst_class = { |
| .name = "bst", |
| .owner = THIS_MODULE, |
| .devnode = (void*)bst_devnode, |
| .dev_release = bst_dev_release, |
| }; |
| EXPORT_SYMBOL_GPL(bst_class); |
| |
| /** |
| * bst_allocate_device - allocate memory for new input device |
| * |
| * Returns prepared struct bst_dev or NULL. |
| * |
| * NOTE: Use bst_free_device() to free devices that have not been |
| * registered; bst_unregister_device() should be used for already |
| * registered devices. |
| */ |
| struct bst_dev *bst_allocate_device(void) |
| { |
| struct bst_dev *dev; |
| |
| dev = kzalloc(sizeof(struct bst_dev), GFP_KERNEL); |
| if (dev) { |
| dev->dev.type = &bst_dev_type; |
| dev->dev.class = &bst_class; |
| device_initialize(&dev->dev); |
| mutex_init(&dev->mutex); |
| INIT_LIST_HEAD(&dev->node); |
| __module_get(THIS_MODULE); |
| } |
| return dev; |
| } |
| EXPORT_SYMBOL(bst_allocate_device); |
| |
| |
| |
| /** |
| * bst_free_device - free memory occupied by bst_dev structure |
| * @dev: input device to free |
| * |
| * This function should only be used if bst_register_device() |
| * was not called yet or if it failed. Once device was registered |
| * use bst_unregister_device() and memory will be freed once last |
| * reference to the device is dropped. |
| * |
| * Device should be allocated by bst_allocate_device(). |
| * |
| * NOTE: If there are references to the input device then memory |
| * will not be freed until last reference is dropped. |
| */ |
| void bst_free_device(struct bst_dev *dev) |
| { |
| if (dev) |
| bst_put_device(dev); |
| } |
| EXPORT_SYMBOL(bst_free_device); |
| |
| /** |
| * bst_register_device - register device with input core |
| * @dev: device to be registered |
| * |
| * This function registers device with input core. The device must be |
| * allocated with bst_allocate_device() and all it's capabilities |
| * set up before registering. |
| * If function fails the device must be freed with bst_free_device(). |
| * Once device has been successfully registered it can be unregistered |
| * with bst_unregister_device(); bst_free_device() should not be |
| * called in this case. |
| */ |
| int bst_register_device(struct bst_dev *dev) |
| { |
| const char *path; |
| int error; |
| |
| |
| /* |
| * If delay and period are pre-set by the driver, then autorepeating |
| * is handled by the driver itself and we don't do it in input.c. |
| */ |
| dev_set_name(&dev->dev, dev->name); |
| |
| error = device_add(&dev->dev); |
| if (error) |
| return error; |
| |
| path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); |
| PINFO("%s as %s\n", |
| dev->name ? dev->name : "Unspecified device", |
| path ? path : "N/A"); |
| kfree(path); |
| error = mutex_lock_interruptible(&bst_mutex); |
| if (error) { |
| device_del(&dev->dev); |
| return error; |
| } |
| |
| list_add_tail(&dev->node, &bst_dev_list); |
| |
| mutex_unlock(&bst_mutex); |
| return 0; |
| } |
| EXPORT_SYMBOL(bst_register_device); |
| |
| /** |
| * bst_unregister_device - unregister previously registered device |
| * @dev: device to be unregistered |
| * |
| * This function unregisters an input device. Once device is unregistered |
| * the caller should not try to access it as it may get freed at any moment. |
| */ |
| void bst_unregister_device(struct bst_dev *dev) |
| { |
| int ret = 0; |
| ret = mutex_lock_interruptible(&bst_mutex); |
| if(ret){ |
| return; |
| } |
| |
| list_del_init(&dev->node); |
| mutex_unlock(&bst_mutex); |
| device_unregister(&dev->dev); |
| } |
| EXPORT_SYMBOL(bst_unregister_device); |
| |
| static int __init bst_init(void) |
| { |
| int err; |
| /*bst class register*/ |
| err = class_register(&bst_class); |
| if (err) { |
| pr_err("unable to register bst_dev class\n"); |
| return err; |
| } |
| return err; |
| } |
| |
| static void __exit bst_exit(void) |
| { |
| /*bst class*/ |
| class_unregister(&bst_class); |
| } |
| |
| /*subsys_initcall(bst_init);*/ |
| |
| MODULE_AUTHOR("contact@bosch-sensortec.com"); |
| MODULE_DESCRIPTION("BST CLASS CORE"); |
| MODULE_LICENSE("GPL V2"); |
| |
| module_init(bst_init); |
| module_exit(bst_exit); |