/*! * @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 #include #include #include #include #include #include #include #include #include #include #include #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);