/* * Universal sensors core class * * Author : Ryunkyun Park */ #include #include #include #include #include #include #include struct class *sensors_class; EXPORT_SYMBOL_GPL(sensors_class); struct class *sensors_event_class; EXPORT_SYMBOL_GPL(sensors_event_class); static atomic_t sensor_count; static struct device *symlink_dev; static struct device *sensor_dev; static struct input_dev *meta_input_dev; /* * Create sysfs interface */ static void set_sensor_attr(struct device *dev, struct device_attribute *attributes[]) { int i; for (i = 0; attributes[i] != NULL; i++) if ((device_create_file(dev, attributes[i])) < 0) pr_err("[SENSOR CORE] fail device_create_file" "(dev, attributes[%d])\n", i); } int sensors_create_symlink(struct input_dev *inputdev) { int err = 0; if (symlink_dev == NULL) { pr_err("%s, symlink_dev is NULL!!!\n", __func__); return err; } err = sysfs_create_link(&symlink_dev->kobj, &inputdev->dev.kobj, inputdev->name); if (err < 0) { pr_err("%s, %s failed!(%d)\n", __func__, inputdev->name, err); return err; } return err; } EXPORT_SYMBOL_GPL(sensors_create_symlink); void sensors_remove_symlink(struct input_dev *inputdev) { if (symlink_dev == NULL) { pr_err("%s, symlink_dev is NULL!!!\n", __func__); return; } sysfs_delete_link(&symlink_dev->kobj, &inputdev->dev.kobj, inputdev->name); } EXPORT_SYMBOL_GPL(sensors_remove_symlink); int sensors_device_register(struct device **pdev, void *drvdata, struct device_attribute *attributes[], char *name) { struct device* dev; if (!sensors_class) { sensors_class = class_create(THIS_MODULE, "sensors"); if (IS_ERR(sensors_class)) { return PTR_ERR(sensors_class); } } dev = device_create(sensors_class, NULL, 0, drvdata, "%s", name); if (IS_ERR(dev)) { int ret = 0; ret = PTR_ERR(dev); pr_err("[SENSORS CORE] device_create failed!"\ "[%d]\n", ret); return ret; } set_sensor_attr(dev, attributes); atomic_inc(&sensor_count); *pdev = dev; return 0; } EXPORT_SYMBOL_GPL(sensors_device_register); int sensors_register(struct device *dev, void *drvdata, struct device_attribute *attributes[], char *name) { if (!sensors_class) { sensors_class = class_create(THIS_MODULE, "sensors"); if (IS_ERR(sensors_class)) { return PTR_ERR(sensors_class); } } dev = device_create(sensors_class, NULL, 0, drvdata, "%s", name); if (IS_ERR(dev)) { int ret = 0; ret = PTR_ERR(dev); pr_err("[SENSORS CORE] device_create failed!"\ "[%d]\n", ret); return ret; } set_sensor_attr(dev, attributes); atomic_inc(&sensor_count); return 0; } EXPORT_SYMBOL_GPL(sensors_register); void sensors_unregister(struct device *dev, struct device_attribute *attributes[]) { int i; for (i = 0; attributes[i] != NULL; i++) { device_remove_file(dev, attributes[i]); } } EXPORT_SYMBOL_GPL(sensors_unregister); void destroy_sensor_class(void) { if (sensors_class) { device_destroy(sensors_class, sensor_dev->devt); class_destroy(sensors_class); sensor_dev = NULL; sensors_class = NULL; } if (sensors_event_class) { device_destroy(sensors_event_class, symlink_dev->devt); class_destroy(sensors_event_class); symlink_dev = NULL; sensors_event_class = NULL; } } EXPORT_SYMBOL_GPL(destroy_sensor_class); static ssize_t set_flush(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { u8 sensor_type = 0; if (kstrtou8(buf, 10, &sensor_type) < 0) return -EINVAL; input_report_rel(meta_input_dev, REL_DIAL, 1); /*META_DATA_FLUSH_COMPLETE*/ input_report_rel(meta_input_dev, REL_HWHEEL, sensor_type + 1); input_sync(meta_input_dev); pr_info("[SENSOR CORE] flush %d\n", sensor_type); return size; } static DEVICE_ATTR(flush, 0220, NULL, set_flush); static struct device_attribute *ap_sensor_attr[] = { &dev_attr_flush, NULL, }; int sensors_meta_input_init(void) { int ret; /* Meta Input Event Initialization */ meta_input_dev = input_allocate_device(); if (!meta_input_dev) { pr_err("[SENSOR CORE] failed alloc meta dev\n"); return -ENOMEM; } meta_input_dev->name = "meta_event"; input_set_capability(meta_input_dev, EV_REL, REL_HWHEEL); input_set_capability(meta_input_dev, EV_REL, REL_DIAL); ret = input_register_device(meta_input_dev); if (ret < 0) { pr_err("[SENSOR CORE] failed register meta dev\n"); input_free_device(meta_input_dev); return ret; } ret = sensors_create_symlink(meta_input_dev); if (ret < 0) { pr_err("[SENSOR CORE] failed create meta symlink\n"); input_unregister_device(meta_input_dev); return ret; } return ret; } void sensors_meta_input_clean(void) { sensors_remove_symlink(meta_input_dev); input_unregister_device(meta_input_dev); } static int __init sensors_class_init(void) { pr_info("[SENSORS CORE] sensors_class_init\n"); sensors_class = class_create(THIS_MODULE, "sensors"); if (IS_ERR(sensors_class)) { pr_err("%s, create sensors_class is failed.(err=%d)\n", __func__, IS_ERR(sensors_class)); return PTR_ERR(sensors_class); } /* For symbolic link */ sensors_event_class = class_create(THIS_MODULE, "sensor_event"); if (IS_ERR(sensors_event_class)) { pr_err("%s, create sensors_class is failed.(err=%d)\n", __func__, IS_ERR(sensors_event_class)); class_destroy(sensors_class); return PTR_ERR(sensors_event_class); } symlink_dev = device_create(sensors_event_class, NULL, 0, NULL, "%s", "symlink"); if (IS_ERR(symlink_dev)) { pr_err("[SENSORS CORE] symlink_dev create failed!"\ "[%d]\n", IS_ERR(symlink_dev)); class_destroy(sensors_class); class_destroy(sensors_event_class); return PTR_ERR(symlink_dev); } sensor_dev = device_create(sensors_class, NULL, 0, NULL, "%s", "sensor_dev"); if (IS_ERR(sensor_dev)) { pr_err("[SENSORS CORE] sensor_dev create failed![%d]\n", IS_ERR(sensor_dev)); } else { if ((device_create_file(sensor_dev, *ap_sensor_attr)) < 0) pr_err("[SENSOR CORE] failed flush device_file\n"); } atomic_set(&sensor_count, 0); sensors_class->dev_uevent = NULL; pr_info("[SENSORS CORE] sensors_class_init succcess\n"); sensors_meta_input_init(); pr_info("[SENSORS CORE] %s succcess\n", __func__); return 0; } static void __exit sensors_class_exit(void) { if (meta_input_dev) sensors_meta_input_clean(); if (sensors_class || sensors_event_class) { class_destroy(sensors_class); sensors_class = NULL; class_destroy(sensors_event_class); sensors_event_class = NULL; } } subsys_initcall(sensors_class_init); module_exit(sensors_class_exit); MODULE_DESCRIPTION("Universal sensors core class"); MODULE_AUTHOR("Ryunkyun Park "); MODULE_LICENSE("GPL");