summaryrefslogtreecommitdiff
path: root/drivers/input/misc/bstclass.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/misc/bstclass.c')
-rw-r--r--drivers/input/misc/bstclass.c234
1 files changed, 234 insertions, 0 deletions
diff --git a/drivers/input/misc/bstclass.c b/drivers/input/misc/bstclass.c
new file mode 100644
index 00000000..11c3c39d
--- /dev/null
+++ b/drivers/input/misc/bstclass.c
@@ -0,0 +1,234 @@
+/*!
+ * @section LICENSE
+ * $license$
+ *
+ * @filename $filename$
+ * @date $date$
+ * @id $id$
+ *
+ * @brief
+ * The core code of bst device driver
+*/
+#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 = 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);