sensors: created virtual device for accel, gyro, geo, light, and proxi 14/23214/1
authorJinhyung Choi <jinhyung2.choi@samsung.com>
Mon, 16 Jun 2014 01:37:27 +0000 (10:37 +0900)
committerJinhyung Choi <jinhyung2.choi@samsung.com>
Fri, 20 Jun 2014 05:21:05 +0000 (14:21 +0900)
Change-Id: I554643e382212dcb06ef82e8b7cc00424b321e42
Signed-off-by: Jinhyung Choi <jinhyung2.choi@samsung.com>
drivers/maru/Makefile
drivers/maru/maru_virtio_sensor.c [deleted file]
drivers/maru/sensors/Makefile [new file with mode: 0644]
drivers/maru/sensors/maru_accel.c [new file with mode: 0644]
drivers/maru/sensors/maru_geo.c [new file with mode: 0644]
drivers/maru/sensors/maru_gyro.c [new file with mode: 0644]
drivers/maru/sensors/maru_light.c [new file with mode: 0644]
drivers/maru/sensors/maru_proxi.c [new file with mode: 0644]
drivers/maru/sensors/maru_virtio_sensor.c [new file with mode: 0644]
drivers/maru/sensors/maru_virtio_sensor.h [new file with mode: 0644]

index 9001653b030e69b3c5da5622caf0eb64008a471b..ff7408b1078a445ba8ee01fef6f35eb85d0e8f1a 100644 (file)
@@ -7,6 +7,6 @@ obj-$(CONFIG_MARU_POWER_SUPPLY) += maru_power_supply.o
 obj-$(CONFIG_MARU_VIRTIO_KEYBOARD) += maru_virtio_keyboard.o
 obj-$(CONFIG_MARU_VIRTIO_NFC) += maru_virtio_nfc.o
 obj-$(CONFIG_MARU_VIRTIO_EVDI) += maru_virtio_evdi.o
-obj-$(CONFIG_MARU_VIRTIO_SENSOR) += maru_virtio_sensor.o
+obj-$(CONFIG_MARU_VIRTIO_SENSOR) += sensors/ #maru_virtio_sensor.o
 obj-$(CONFIG_MARU_BRILLCODEC) += maru_brillcodec.o
 obj-$(CONFIG_MARU_VIRTIO_VMODEM) += maru_virtio_vmodem.o
diff --git a/drivers/maru/maru_virtio_sensor.c b/drivers/maru/maru_virtio_sensor.c
deleted file mode 100644 (file)
index c7d9eaa..0000000
+++ /dev/null
@@ -1,659 +0,0 @@
-/*
- * Maru Virtio Sensor Device Driver
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * Contact:
- *  Jinhyung Choi <jinhyung2.choi@samsung.com>
- *  Daiyoung Kim <daiyoung777.kim@samsung.com>
- *  YeongKyoon Lee <yeongkyoon.lee@samsung.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/uaccess.h>
-#include <linux/miscdevice.h>
-#include <linux/slab.h>
-#include <linux/virtio.h>
-#include <linux/virtio_ids.h>
-#include <linux/virtio_config.h>
-#include <linux/wait.h>
-#include <linux/sched.h>
-#include <linux/cdev.h>
-
-
-#define LOG(log_level, fmt, ...) \
-       printk(log_level "%s: " fmt "\n", SENSOR_CLASS_NAME, ##__VA_ARGS__)
-
-#define SENSOR_CLASS_NAME      "sensor"
-
-#define DRIVER_ACCEL_NAME      "accel"
-#define DRIVER_GEO_NAME                "geo"
-#define DRIVER_GYRO_NAME       "gyro"
-#define DRIVER_LIGHT_NAME      "light"
-#define DRIVER_PROXI_NAME      "proxi"
-
-#define __MAX_BUF_SIZE         1024
-#define __MAX_BUF_SENSOR       32
-
-#define DEVICE_COUNT           5
-
-enum sensor_types {
-       sensor_type_list = 0,
-       sensor_type_accel,
-       sensor_type_geo,
-       sensor_type_gyro,
-       sensor_type_gyro_x,
-       sensor_type_gyro_y,
-       sensor_type_gyro_z,
-       sensor_type_light,
-       sensor_type_light_adc,
-       sensor_type_light_level,
-       sensor_type_proxi,
-       sensor_type_mag,
-       sensor_type_tilt,
-       sensor_type_max
-};
-
-enum sensor_capabilities {
-       sensor_cap_accel = 0x01,
-       sensor_cap_geo   = 0x02,
-       sensor_cap_gyro  = 0x04,
-       sensor_cap_light = 0x08,
-       sensor_cap_proxi = 0x10
-};
-
-enum sensor_attributes {
-       sensor_attr_accel = 0,
-       sensor_attr_geo,
-       sensor_attr_gyro,
-       sensor_attr_light,
-       sensor_attr_proxi
-};
-
-enum request_cmd {
-       request_get = 0,
-       request_set,
-       request_answer
-};
-
-struct msg_info {
-       char buf[__MAX_BUF_SIZE];
-
-       uint16_t type;
-       uint16_t req;
-};
-
-struct virtio_sensor {
-       struct virtio_device* vdev;
-       struct virtqueue* vq;
-
-       struct msg_info msginfo;
-
-       struct scatterlist sg_vq[2];
-
-       int flags;
-       struct mutex lock;
-};
-
-static struct virtio_device_id id_table[] = { { VIRTIO_ID_SENSOR,
-               VIRTIO_DEV_ANY_ID }, { 0 }, };
-
-struct virtio_sensor *vs;
-
-static struct class* sensor_class;
-
-static DECLARE_WAIT_QUEUE_HEAD(wq);
-
-#define ___ATTR_RONLY(_name,_show) { \
-       .attr   = { .name = __stringify(_name), .mode = 0444 }, \
-       .show   = _show,                                        \
-}
-
-#define ___ATTR_RW(_name) { \
-       .attr = {.name = __stringify(_name), .mode = 0644 },    \
-       .show   = _name##_show,                                 \
-       .store  = _name##_store,                                        \
-}
-
-static char sensor_data [PAGE_SIZE];
-static int sensor_capability = 0;
-
-static void sensor_vq_done(struct virtqueue *rvq) {
-       unsigned int len;
-       struct msg_info* msg;
-
-       msg = (struct msg_info*) virtqueue_get_buf(vs->vq, &len);
-       if (msg == NULL) {
-               LOG(KERN_ERR, "failed to virtqueue_get_buf");
-               return;
-       }
-
-       if (msg->req != request_answer || msg->buf == NULL) {
-               LOG(KERN_ERR, "message from host is cracked.");
-               return;
-       }
-
-       LOG(KERN_DEBUG, "msg buf: %s, req: %d, type: %d", msg->buf, msg->req, msg->type);
-
-       mutex_lock(&vs->lock);
-       strcpy(sensor_data, msg->buf);
-       vs->flags = 1;
-       mutex_unlock(&vs->lock);
-
-       wake_up_interruptible(&wq);
-}
-
-static int sensor_atoi(const char *name)
-{
-       int val = 0;
-
-       for (;; name++) {
-               switch (*name) {
-                       case '0' ... '9':
-                               val = 10*val+(*name-'0');
-                               break;
-                       default:
-                               return val;
-               }
-       }
-}
-
-static void set_sensor_data(int type, const char* buf)
-{
-       int err = 0;
-
-       if (buf == NULL) {
-               LOG(KERN_ERR, "set_sensor buf is NULL.");
-               return;
-       }
-
-       if (vs == NULL) {
-               LOG(KERN_ERR, "Invalid sensor handle");
-               return;
-       }
-
-       mutex_lock(&vs->lock);
-       memset(sensor_data, 0, PAGE_SIZE);
-       memset(&vs->msginfo, 0, sizeof(vs->msginfo));
-
-       strcpy(sensor_data, buf);
-
-       vs->msginfo.req = request_set;
-       vs->msginfo.type = type;
-       strcpy(vs->msginfo.buf, buf);
-       mutex_unlock(&vs->lock);
-
-       LOG(KERN_DEBUG, "set_sensor_data type: %d, req: %d, buf: %s",
-                       vs->msginfo.type, vs->msginfo.req, vs->msginfo.buf);
-
-       err = virtqueue_add_outbuf(vs->vq, vs->sg_vq, 1, &vs->msginfo, GFP_ATOMIC);
-       if (err < 0) {
-               LOG(KERN_ERR, "failed to add out buffer to virtqueue (err = %d)", err);
-               return;
-       }
-
-       virtqueue_kick(vs->vq);
-}
-
-static void get_sensor_data(int type)
-{
-       struct scatterlist *sgs[2];
-       int err = 0;
-
-       if (vs == NULL) {
-               LOG(KERN_ERR, "Invalid sensor handle");
-               return;
-       }
-
-       mutex_lock(&vs->lock);
-       memset(sensor_data, 0, PAGE_SIZE);
-       memset(&vs->msginfo, 0, sizeof(vs->msginfo));
-
-       vs->msginfo.req = request_get;
-       vs->msginfo.type = type;
-
-       mutex_unlock(&vs->lock);
-
-       LOG(KERN_DEBUG, "get_sensor_data type: %d, req: %d",
-                       vs->msginfo.type, vs->msginfo.req);
-
-       sgs[0] = &vs->sg_vq[0];
-       sgs[1] = &vs->sg_vq[1];
-       err = virtqueue_add_sgs(vs->vq, sgs, 1, 1, &vs->msginfo, GFP_ATOMIC);
-       if (err < 0) {
-               LOG(KERN_ERR, "failed to add in buffer to virtqueue (err = %d)", err);
-               return;
-       }
-
-       virtqueue_kick(vs->vq);
-
-       wait_event_interruptible(wq, vs->flags != 0);
-
-       mutex_lock(&vs->lock);
-       vs->flags = 0;
-       mutex_unlock(&vs->lock);
-}
-
-/*
- * Accelerometer
- */
-#define ACCEL_NAME_STR         "accel_sim"
-#define ACCEL_FILE_NUM         2
-
-static ssize_t accel_name_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, ACCEL_NAME_STR);
-}
-
-static ssize_t xyz_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       get_sensor_data(sensor_type_accel);
-       return snprintf(buf, PAGE_SIZE, "%s", sensor_data);
-}
-
-static ssize_t xyz_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       set_sensor_data(sensor_type_accel, buf);
-       return strnlen(buf, PAGE_SIZE);
-}
-
-static struct device_attribute da_accel [] =
-{
-       ___ATTR_RONLY(name, accel_name_show),
-       ___ATTR_RW(xyz),
-};
-
-/*
- * GeoMagnetic
- */
-#define GEO_NAME_STR           "geo_sim"
-#define GEO_FILE_NUM           3
-
-static ssize_t geo_name_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, GEO_NAME_STR);
-}
-
-static ssize_t raw_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       get_sensor_data(sensor_type_tilt);
-       return snprintf(buf, PAGE_SIZE, "%s", sensor_data);
-}
-
-static ssize_t raw_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       set_sensor_data(sensor_type_tilt, buf);
-       return strnlen(buf, PAGE_SIZE);
-}
-
-static ssize_t tesla_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       get_sensor_data(sensor_type_mag);
-       return snprintf(buf, PAGE_SIZE, "%s", sensor_data);
-}
-
-static ssize_t tesla_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       set_sensor_data(sensor_type_mag, buf);
-       return strnlen(buf, PAGE_SIZE);
-}
-
-static struct device_attribute da_geo [] =
-{
-       ___ATTR_RONLY(name, geo_name_show),
-       ___ATTR_RW(raw),
-       ___ATTR_RW(tesla),
-};
-
-
-/*
- * Gyroscope
- */
-
-#define GYRO_NAME_STR          "gyro_sim"
-#define GYRO_FILE_NUM          4
-
-static ssize_t gyro_name_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, GYRO_NAME_STR);
-}
-
-static ssize_t gyro_x_raw_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       get_sensor_data(sensor_type_gyro_x);
-       return snprintf(buf, PAGE_SIZE, "%s", sensor_data);
-}
-
-static ssize_t gyro_x_raw_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       set_sensor_data(sensor_type_gyro_x, buf);
-       return strnlen(buf, PAGE_SIZE);
-}
-
-static ssize_t gyro_y_raw_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       get_sensor_data(sensor_type_gyro_y);
-       return snprintf(buf, PAGE_SIZE, "%s", sensor_data);
-}
-
-static ssize_t gyro_y_raw_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       set_sensor_data(sensor_type_gyro_y, buf);
-       return strnlen(buf, PAGE_SIZE);
-}
-
-static ssize_t gyro_z_raw_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       get_sensor_data(sensor_type_gyro_z);
-       return snprintf(buf, PAGE_SIZE, "%s", sensor_data);
-}
-
-static ssize_t gyro_z_raw_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       set_sensor_data(sensor_type_gyro_z, buf);
-       return strnlen(buf, PAGE_SIZE);
-}
-
-static struct device_attribute da_gyro [] =
-{
-       ___ATTR_RONLY(name, gyro_name_show),
-       ___ATTR_RW(gyro_x_raw),
-       ___ATTR_RW(gyro_y_raw),
-       ___ATTR_RW(gyro_z_raw),
-};
-
-/*
- * Light
- */
-
-#define LIGHT_NAME_STR         "light_sim"
-#define LIGHT_FILE_NUM         3
-
-static ssize_t light_name_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, LIGHT_NAME_STR);
-}
-
-static ssize_t adc_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       get_sensor_data(sensor_type_light_adc);
-       return snprintf(buf, PAGE_SIZE, "%s", sensor_data);
-}
-
-static ssize_t adc_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       set_sensor_data(sensor_type_light_adc, buf);
-       return strnlen(buf, PAGE_SIZE);
-}
-
-static ssize_t level_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       get_sensor_data(sensor_type_light_level);
-       return snprintf(buf, PAGE_SIZE, "%s", sensor_data);
-}
-
-static ssize_t level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       set_sensor_data(sensor_type_light_level, buf);
-       return strnlen(buf, PAGE_SIZE);
-}
-
-static struct device_attribute da_light [] =
-{
-       ___ATTR_RONLY(name, light_name_show),
-       ___ATTR_RW(adc),
-       ___ATTR_RW(level),
-};
-
-
-/*
- * Proxi
- */
-
-#define PROXI_NAME_STR         "proxi_sim"
-#define PROXI_FILE_NUM         3
-
-static int proxi_enable = 1;
-
-static ssize_t proxi_name_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, PROXI_NAME_STR);
-}
-
-static ssize_t enable_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, "%d", proxi_enable);
-}
-
-static ssize_t enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       sscanf(buf, "%d", &proxi_enable);
-       return strnlen(buf, PAGE_SIZE);
-}
-
-static ssize_t vo_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       get_sensor_data(sensor_type_proxi);
-       return snprintf(buf, PAGE_SIZE, "%s", sensor_data);
-}
-
-static ssize_t vo_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       set_sensor_data(sensor_type_proxi, buf);
-       return strnlen(buf, PAGE_SIZE);
-}
-
-static struct device_attribute da_proxi [] =
-{
-       ___ATTR_RONLY(name, proxi_name_show),
-       ___ATTR_RW(enable),
-       ___ATTR_RW(vo),
-};
-
-/*
- * Initialize Devices
- */
-
-static struct device* device_list[DEVICE_COUNT];
-
-const char *device_name_list[] = { DRIVER_ACCEL_NAME, DRIVER_GEO_NAME, DRIVER_GYRO_NAME, DRIVER_LIGHT_NAME, DRIVER_PROXI_NAME };
-
-const int device_file_num[] = {ACCEL_FILE_NUM, GEO_FILE_NUM, GYRO_FILE_NUM, LIGHT_FILE_NUM, PROXI_FILE_NUM};
-
-static struct device_attribute* da_list[] = {da_accel, da_geo, da_gyro, da_light, da_proxi };
-
-static void class_cleanup (void)
-{
-       int i = 0, j = 0;
-
-       for (i = 0; i < DEVICE_COUNT; i++) {
-
-               if (device_list[i] == NULL)
-                       continue;
-
-               for (j = 0; j < device_file_num[i]; j++) {
-                       device_remove_file(device_list[i], &da_list[i][j]);
-               }
-
-               device_destroy(sensor_class, (dev_t)NULL);
-               device_list[i] = NULL;
-       }
-
-       class_destroy(sensor_class);
-       sensor_class = NULL;
-}
-
-static int init_device(void)
-{
-       int i = 0;
-       int j = 0;
-       int ret = 0;
-
-       for (i = 0; i < DEVICE_COUNT; i++) {
-               if (i == sensor_attr_accel && !(sensor_capability & sensor_cap_accel)) {
-                       continue;
-               } else if (i == sensor_attr_geo && !(sensor_capability & sensor_cap_geo)) {
-                       continue;
-               } else if (i == sensor_attr_gyro && !(sensor_capability & sensor_cap_gyro)) {
-                       continue;
-               } else if (i == sensor_attr_light && !(sensor_capability & sensor_cap_light)) {
-                       continue;
-               } else if (i == sensor_attr_proxi && !(sensor_capability & sensor_cap_proxi)) {
-                       continue;
-               }
-               device_list[i] = device_create(sensor_class, NULL, (dev_t)NULL, NULL, device_name_list[i]);
-               if (device_list[i] < 0) {
-                       LOG(KERN_ERR, "%dth sensor device creation is failed.", i);
-                       goto device_err;
-               }
-
-               for (j = 0; j < device_file_num[i]; j++) {
-                       ret = device_create_file(device_list[i], &da_list[i][j]);
-                       if (ret) {
-                               LOG(KERN_ERR, "%dth file creation is failed from %dth sensor device.", i, j);
-                               goto device_err;
-                       }
-               }
-       }
-
-       return ret;
-device_err:
-       class_cleanup();
-       return -1;
-}
-
-static void cleanup(struct virtio_device* dev) {
-       dev->config->del_vqs(dev);
-
-       if (vs) {
-               kfree(vs);
-               vs = NULL;
-       }
-
-       class_cleanup();
-}
-
-static int sensor_probe(struct virtio_device* dev)
-{
-       int err = 0;
-       int ret = 0;
-       int index = 0;
-
-       LOG(KERN_INFO, "Sensor probe starts");
-
-       vs = kmalloc(sizeof(struct virtio_sensor), GFP_KERNEL);
-
-       vs->vdev = dev;
-       dev->priv = vs;
-
-       sensor_class = class_create(THIS_MODULE, SENSOR_CLASS_NAME);
-       if (sensor_class == NULL) {
-               LOG(KERN_ERR, "sensor class creation is failed.");
-               return -1;
-       }
-
-       vs->vq = virtio_find_single_vq(dev, sensor_vq_done, "sensor");
-       if (IS_ERR(vs->vq)) {
-               cleanup(dev);
-               LOG(KERN_ERR, "failed to init virt queue");
-               return ret;
-       }
-
-       virtqueue_enable_cb(vs->vq);
-
-       memset(&vs->msginfo, 0x00, sizeof(vs->msginfo));
-
-       sg_init_table(vs->sg_vq, 2);
-       for (; index < 2; index++) {
-               sg_set_buf(&vs->sg_vq[index], &vs->msginfo, sizeof(vs->msginfo));
-       }
-
-       mutex_init(&vs->lock);
-
-       LOG(KERN_INFO, "Sensor probe completes");
-
-       get_sensor_data(sensor_type_list);
-       sensor_capability = sensor_atoi(sensor_data);
-       LOG(KERN_INFO, "sensor capability is %02x", sensor_capability);
-
-       ret = init_device();
-       if (ret) {
-               LOG(KERN_ERR, "failed initialing devices");
-               cleanup(dev);
-               return ret;
-       }
-
-       return err;
-}
-
-static void sensor_remove(struct virtio_device* dev)
-{
-       struct virtio_sensor* vs = dev->priv;
-       if (!vs)
-       {
-               LOG(KERN_ERR, "vs is NULL");
-               return;
-       }
-
-       dev->config->reset(dev);
-
-       cleanup(dev);
-
-       LOG(KERN_INFO, "Sensor driver is removed.");
-}
-
-MODULE_DEVICE_TABLE(virtio, id_table);
-
-static struct virtio_driver virtio_sensor_driver = {
-               .driver = {
-                               .name = KBUILD_MODNAME,
-                               .owner = THIS_MODULE ,
-               },
-               .id_table = id_table,
-               .probe = sensor_probe,
-               .remove = sensor_remove,
-};
-
-
-static int __init sensor_init(void)
-{
-       LOG(KERN_INFO, "Sensor driver initialized.");
-
-       return register_virtio_driver(&virtio_sensor_driver);
-}
-
-static void __exit sensor_exit(void)
-{
-       unregister_virtio_driver(&virtio_sensor_driver);
-
-       LOG(KERN_INFO, "Sensor driver is destroyed.");
-}
-
-module_init(sensor_init);
-module_exit(sensor_exit);
-
-MODULE_LICENSE("GPL2");
-MODULE_AUTHOR("Jinhyung Choi <jinhyung2.choi@samsung.com>");
-MODULE_DESCRIPTION("Emulator Virtio Sensor Driver");
-
diff --git a/drivers/maru/sensors/Makefile b/drivers/maru/sensors/Makefile
new file mode 100644 (file)
index 0000000..57259aa
--- /dev/null
@@ -0,0 +1,6 @@
+obj-$(CONFIG_MARU_VIRTIO_SENSOR) += maru_virtio_sensor.o       \
+                                                                       maru_accel.o                    \
+                                                                       maru_geo.o                              \
+                                                                       maru_gyro.o                             \
+                                                                       maru_light.o                    \
+                                                                       maru_proxi.o
diff --git a/drivers/maru/sensors/maru_accel.c b/drivers/maru/sensors/maru_accel.c
new file mode 100644 (file)
index 0000000..442fcbb
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * Maru Virtio Accelerometer Sensor Device Driver
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *  Jinhyung Choi <jinhyung2.choi@samsung.com>
+ *  Sangho Park <sangho1206.park@samsung.com>
+ *  YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "maru_virtio_sensor.h"
+
+struct maru_accel_data {
+       struct input_dev *input_data;
+       struct delayed_work work;
+       struct mutex data_mutex;
+
+       struct virtio_sensor* vs;
+
+       atomic_t enable;
+       atomic_t poll_delay;
+};
+
+static struct device *accel_sensor_device;
+
+#ifdef SUPPORT_LEGACY_SENSOR
+static struct device *l_accel_sensor_device;
+#endif
+
+static void maru_accel_input_work_func(struct work_struct *work) {
+
+       int poll_time = 200000000;
+       int enable = 0;
+       int ret = 0;
+       int accel_x, accel_y, accel_z;
+       char sensor_data[__MAX_BUF_SENSOR];
+       struct maru_accel_data *data = container_of((struct delayed_work *)work,
+                       struct maru_accel_data, work);
+
+       LOG(KERN_DEBUG, "maru_accel_input_work_func starts");
+
+       memset(sensor_data, 0, __MAX_BUF_SENSOR);
+       poll_time = atomic_read(&data->poll_delay);
+
+       mutex_lock(&data->data_mutex);
+       enable = atomic_read(&data->enable);
+       mutex_unlock(&data->data_mutex);
+
+       if (enable) {
+               mutex_lock(&data->data_mutex);
+               ret = get_sensor_data(sensor_type_accel, sensor_data);
+               mutex_unlock(&data->data_mutex);
+               if (!ret) {
+                       sscanf(sensor_data, "%d,%d,%d", &accel_x, &accel_y, &accel_z);
+                       LOG(KERN_INFO, "accel_set %d, %d, %d", accel_x, accel_y, accel_z);
+
+                       input_report_rel(data->input_data, REL_RX, accel_x);
+                       input_report_rel(data->input_data, REL_RY, accel_y);
+                       input_report_rel(data->input_data, REL_RZ, accel_z);
+                       input_sync(data->input_data);
+               }
+       }
+
+       mutex_lock(&data->data_mutex);
+       enable = atomic_read(&data->enable);
+       mutex_unlock(&data->data_mutex);
+
+       LOG(KERN_DEBUG, "enable: %d, poll_time: %d", enable, poll_time);
+       if (enable) {
+               if (poll_time > 0) {
+                       schedule_delayed_work(&data->work, nsecs_to_jiffies(poll_time));
+               } else {
+                       schedule_delayed_work(&data->work, 0);
+               }
+       }
+
+       LOG(KERN_DEBUG, "maru_accel_input_work_func ends");
+
+}
+
+static ssize_t maru_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s", MARU_ACCEL_DEVICE_NAME);
+}
+
+static ssize_t maru_vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s", MARU_SENSOR_DEVICE_VENDOR);
+}
+
+static ssize_t maru_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_accel_enable, buf);
+}
+
+static ssize_t maru_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct input_dev *input_data = to_input_dev(dev);
+       struct maru_accel_data *data = input_get_drvdata(input_data);
+       int value = simple_strtoul(buf, NULL, 10);
+
+       if (value != 0 && value != 1)
+               return count;
+
+       set_sensor_data(sensor_type_accel_enable, buf);
+
+       if (value) {
+               if (atomic_read(&data->enable) != 1) {
+                       atomic_set(&data->enable, 1);
+                       schedule_delayed_work(&data->work, 0);
+
+               }
+       } else {
+               if (atomic_read(&data->enable) != 0) {
+                       atomic_set(&data->enable, 0);
+                       cancel_delayed_work(&data->work);
+               }
+       }
+
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static ssize_t maru_poll_delay_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_accel_delay, buf);
+}
+
+static ssize_t maru_poll_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct input_dev *input_data = to_input_dev(dev);
+       struct maru_accel_data *data = input_get_drvdata(input_data);
+       int value = simple_strtoul(buf, NULL, 10);
+
+       set_sensor_data(sensor_type_accel_delay, buf);
+       atomic_set(&data->poll_delay, value);
+
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static struct device_attribute dev_attr_sensor_name =
+               __ATTR(name, S_IRUGO, maru_name_show, NULL);
+
+static struct device_attribute dev_attr_sensor_vendor =
+               __ATTR(vendor, S_IRUGO, maru_vendor_show, NULL);
+
+static struct device_attribute *accel_sensor_attrs [] = {
+       &dev_attr_sensor_name,
+       &dev_attr_sensor_vendor,
+       NULL,
+};
+
+#ifdef SUPPORT_LEGACY_SENSOR
+#define ACCEL_NAME_STR         "accel_sim"
+
+static ssize_t accel_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s", ACCEL_NAME_STR);
+}
+
+static ssize_t xyz_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_accel, buf);
+}
+
+static ssize_t xyz_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       set_sensor_data(sensor_type_accel, buf);
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static struct device_attribute dev_attr_l_sensor_name =
+               __ATTR(name, S_IRUGO, accel_name_show, NULL);
+
+static DEVICE_ATTR(xyz, 0644, xyz_show, xyz_store);
+
+static struct device_attribute *l_accel_sensor_attrs [] = {
+       &dev_attr_l_sensor_name,
+       &dev_attr_xyz,
+       NULL,
+};
+#endif
+
+static struct device_attribute attr_accel [] =
+{
+       MARU_ATTR_RW(enable),
+       MARU_ATTR_RW(poll_delay),
+};
+
+static struct attribute *maru_accel_attribute[] = {
+       &attr_accel[0].attr,
+       &attr_accel[1].attr,
+       NULL
+};
+
+static struct attribute_group maru_accel_attribute_group = {
+       .attrs = maru_accel_attribute
+};
+
+static void accel_clear(struct maru_accel_data *data) {
+       if (data == NULL)
+               return;
+
+       if (data->input_data) {
+               sysfs_remove_group(&data->input_data->dev.kobj,
+                       &maru_accel_attribute_group);
+               input_free_device(data->input_data);
+       }
+
+       kfree(data);
+       data = NULL;
+}
+
+static int set_initial_value(struct maru_accel_data *data)
+{
+       int delay = 0;
+       int ret = 0;
+       int enable = 0;
+       char sensor_data [__MAX_BUF_SENSOR];
+
+       memset(sensor_data, 0, __MAX_BUF_SENSOR);
+
+       ret = get_sensor_data(sensor_type_accel_delay, sensor_data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to get initial delay time");
+               return ret;
+       }
+
+       delay = sensor_atoi(sensor_data);
+
+       ret = get_sensor_data(sensor_type_accel_enable, sensor_data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to get initial enable");
+               return ret;
+       }
+
+       enable = sensor_atoi(sensor_data);
+
+       if (delay < 0) {
+               LOG(KERN_ERR, "weird value is set initial delay");
+               return ret;
+       }
+
+       atomic_set(&data->poll_delay, delay);
+
+       if (enable) {
+               atomic_set(&data->enable, 1);
+               schedule_delayed_work(&data->work, 0);
+       }
+
+       return ret;
+}
+
+static int create_input_device(struct maru_accel_data *data)
+{
+       int ret = 0;
+       struct input_dev *input_data = NULL;
+
+       input_data = input_allocate_device();
+       if (input_data == NULL) {
+               LOG(KERN_ERR, "failed initialing input handler");
+               accel_clear(data);
+               return -ENOMEM;
+       }
+
+       input_data->name = SENSOR_ACCEL_INPUT_NAME;
+       input_data->id.bustype = BUS_I2C;
+
+       set_bit(EV_REL, input_data->evbit);
+       set_bit(EV_SYN, input_data->evbit);
+       input_set_capability(input_data, EV_REL, REL_RX);
+       input_set_capability(input_data, EV_REL, REL_RY);
+       input_set_capability(input_data, EV_REL, REL_RZ);
+
+       data->input_data = input_data;
+
+       ret = input_register_device(input_data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to register input data");
+               accel_clear(data);
+               return ret;
+       }
+
+       input_set_drvdata(input_data, data);
+
+       ret = sysfs_create_group(&input_data->dev.kobj,
+                       &maru_accel_attribute_group);
+       if (ret) {
+               accel_clear(data);
+               LOG(KERN_ERR, "failed initialing devices");
+               return ret;
+       }
+
+       return ret;
+}
+
+int maru_accel_init(struct virtio_sensor *vs) {
+       int ret = 0;
+       struct maru_accel_data *data = NULL;
+
+       LOG(KERN_INFO, "maru_accel device init starts.");
+
+       data = kmalloc(sizeof(struct maru_accel_data), GFP_KERNEL);
+       if (data == NULL) {
+               LOG(KERN_ERR, "failed to create accel data.");
+               return -ENOMEM;
+       }
+
+       vs->accel_handle = data;
+       data->vs = vs;
+
+       mutex_init(&data->data_mutex);
+
+       INIT_DELAYED_WORK(&data->work, maru_accel_input_work_func);
+
+       // create name & vendor
+       ret = register_sensor_device(accel_sensor_device, vs,
+                       accel_sensor_attrs, DRIVER_ACCEL_NAME);
+       if (ret) {
+               LOG(KERN_ERR, "failed to register accel device");
+               accel_clear(data);
+               return -1;
+       }
+
+#ifdef SUPPORT_LEGACY_SENSOR
+               ret = l_register_sensor_device(l_accel_sensor_device, vs,
+                       l_accel_sensor_attrs, DRIVER_ACCEL_NAME);
+       if (ret) {
+               LOG(KERN_ERR, "failed to register legacy accel device");
+               accel_clear(data);
+               return -1;
+       }
+#endif
+
+       // create input
+       ret = create_input_device(data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to create input device");
+               return ret;
+       }
+
+       // set initial delay & enable
+       ret = set_initial_value(data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to set initial value");
+               return ret;
+       }
+
+       LOG(KERN_INFO, "maru_accel device init ends.");
+
+       return ret;
+}
+
+int maru_accel_exit(struct virtio_sensor *vs) {
+       struct maru_accel_data *data = NULL;
+
+       data = (struct maru_accel_data *)vs->accel_handle;
+       accel_clear(data);
+       return 0;
+}
diff --git a/drivers/maru/sensors/maru_geo.c b/drivers/maru/sensors/maru_geo.c
new file mode 100644 (file)
index 0000000..3406f8c
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * Maru Virtio Geomagnetic Sensor Device Driver
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *  Jinhyung Choi <jinhyung2.choi@samsung.com>
+ *  Sangho Park <sangho1206.park@samsung.com>
+ *  YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "maru_virtio_sensor.h"
+
+struct maru_geo_data {
+       struct input_dev *input_data;
+       struct delayed_work work;
+       struct mutex data_mutex;
+
+       struct virtio_sensor* vs;
+
+       atomic_t enable;
+       atomic_t poll_delay;
+};
+
+static struct device *geo_sensor_device;
+
+#ifdef SUPPORT_LEGACY_SENSOR
+static struct device *l_geo_sensor_device;
+#endif
+
+static void maru_geo_input_work_func(struct work_struct *work) {
+
+       int poll_time = 200000000;
+       int enable = 0;
+       int ret = 0;
+       int geo_x, geo_y, geo_z, hdst;
+       char sensor_data[__MAX_BUF_SENSOR];
+       struct maru_geo_data *data = container_of((struct delayed_work *)work,
+                       struct maru_geo_data, work);
+
+       LOG(KERN_DEBUG, "maru_geo_input_work_func starts");
+
+       memset(sensor_data, 0, __MAX_BUF_SENSOR);
+       poll_time = atomic_read(&data->poll_delay);
+
+       mutex_lock(&data->data_mutex);
+       enable = atomic_read(&data->enable);
+       mutex_unlock(&data->data_mutex);
+
+       if (enable) {
+               mutex_lock(&data->data_mutex);
+               ret = get_sensor_data(sensor_type_tilt, sensor_data);
+               mutex_unlock(&data->data_mutex);
+               if (!ret) {
+                       sscanf(sensor_data, "%d %d %d %d", &geo_x, &geo_y, &geo_z, &hdst);
+                       LOG(KERN_INFO, "geo_set %d, %d, %d, %d", geo_x, geo_y, geo_z, hdst);
+
+                       input_report_rel(data->input_data, REL_RX, geo_x);
+                       input_report_rel(data->input_data, REL_RY, geo_y);
+                       input_report_rel(data->input_data, REL_RZ, geo_z);
+                       input_report_rel(data->input_data, REL_HWHEEL, hdst);
+                       input_sync(data->input_data);
+               }
+       }
+
+       mutex_lock(&data->data_mutex);
+       enable = atomic_read(&data->enable);
+       mutex_unlock(&data->data_mutex);
+
+       LOG(KERN_DEBUG, "enable: %d, poll_time: %d", enable, poll_time);
+       if (enable) {
+               if (poll_time > 0) {
+                       schedule_delayed_work(&data->work, nsecs_to_jiffies(poll_time));
+               } else {
+                       schedule_delayed_work(&data->work, 0);
+               }
+       }
+
+       LOG(KERN_DEBUG, "maru_geo_input_work_func ends");
+
+}
+
+static ssize_t maru_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s", MARU_GEO_DEVICE_NAME);
+}
+
+static ssize_t maru_vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s", MARU_SENSOR_DEVICE_VENDOR);
+}
+
+static ssize_t maru_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_geo_enable, buf);
+}
+
+static ssize_t maru_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct input_dev *input_data = to_input_dev(dev);
+       struct maru_geo_data *data = input_get_drvdata(input_data);
+       int value = simple_strtoul(buf, NULL, 10);
+
+       if (value != 0 && value != 1)
+               return count;
+
+       set_sensor_data(sensor_type_geo_enable, buf);
+
+       if (value) {
+               if (atomic_read(&data->enable) != 1) {
+                       atomic_set(&data->enable, 1);
+                       schedule_delayed_work(&data->work, 0);
+
+               }
+       } else {
+               if (atomic_read(&data->enable) != 0) {
+                       atomic_set(&data->enable, 0);
+                       cancel_delayed_work(&data->work);
+               }
+       }
+
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static ssize_t maru_poll_delay_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_geo_delay, buf);
+}
+
+static ssize_t maru_poll_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct input_dev *input_data = to_input_dev(dev);
+       struct maru_geo_data *data = input_get_drvdata(input_data);
+       int value = simple_strtoul(buf, NULL, 10);
+
+       set_sensor_data(sensor_type_geo_delay, buf);
+       atomic_set(&data->poll_delay, value);
+
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static struct device_attribute dev_attr_sensor_name =
+               __ATTR(name, S_IRUGO, maru_name_show, NULL);
+
+static struct device_attribute dev_attr_sensor_vendor =
+               __ATTR(vendor, S_IRUGO, maru_vendor_show, NULL);
+
+static struct device_attribute *geo_sensor_attrs [] = {
+       &dev_attr_sensor_name,
+       &dev_attr_sensor_vendor,
+       NULL,
+};
+
+#ifdef SUPPORT_LEGACY_SENSOR
+#define GEO_NAME_STR           "geo_sim"
+
+static ssize_t geo_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s", GEO_NAME_STR);
+}
+
+static ssize_t raw_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_tilt, buf);
+}
+
+static ssize_t raw_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       set_sensor_data(sensor_type_tilt, buf);
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static ssize_t tesla_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_mag, buf);
+}
+
+static ssize_t tesla_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       set_sensor_data(sensor_type_mag, buf);
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static struct device_attribute dev_attr_l_sensor_name =
+               __ATTR(name, S_IRUGO, geo_name_show, NULL);
+
+static DEVICE_ATTR(raw, 0644, raw_show, raw_store);
+static DEVICE_ATTR(tesla, 0644, tesla_show, tesla_store);
+
+static struct device_attribute *l_geo_sensor_attrs [] = {
+       &dev_attr_l_sensor_name,
+       &dev_attr_raw,
+       &dev_attr_tesla,
+       NULL,
+};
+#endif
+
+static struct device_attribute attr_geo [] =
+{
+       MARU_ATTR_RW(enable),
+       MARU_ATTR_RW(poll_delay),
+};
+
+static struct attribute *maru_geo_attribute[] = {
+       &attr_geo[0].attr,
+       &attr_geo[1].attr,
+       NULL
+};
+
+static struct attribute_group maru_geo_attribute_group = {
+       .attrs = maru_geo_attribute
+};
+
+static void geo_clear(struct maru_geo_data *data) {
+       if (data == NULL)
+               return;
+
+       if (data->input_data) {
+               sysfs_remove_group(&data->input_data->dev.kobj,
+                       &maru_geo_attribute_group);
+               input_free_device(data->input_data);
+       }
+
+       kfree(data);
+       data = NULL;
+}
+
+static int set_initial_value(struct maru_geo_data *data)
+{
+       int delay = 0;
+       int ret = 0;
+       int enable = 0;
+       char sensor_data [__MAX_BUF_SENSOR];
+
+       memset(sensor_data, 0, __MAX_BUF_SENSOR);
+
+       ret = get_sensor_data(sensor_type_geo_delay, sensor_data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to get initial delay time");
+               return ret;
+       }
+
+       delay = sensor_atoi(sensor_data);
+
+       ret = get_sensor_data(sensor_type_geo_enable, sensor_data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to get initial enable");
+               return ret;
+       }
+
+       enable = sensor_atoi(sensor_data);
+
+       if (delay < 0) {
+               LOG(KERN_ERR, "weird value is set initial delay");
+               return ret;
+       }
+
+       atomic_set(&data->poll_delay, delay);
+
+       if (enable) {
+               atomic_set(&data->enable, 1);
+               schedule_delayed_work(&data->work, 0);
+       }
+
+       return ret;
+}
+
+static int create_input_device(struct maru_geo_data *data)
+{
+       int ret = 0;
+       struct input_dev *input_data = NULL;
+
+       input_data = input_allocate_device();
+       if (input_data == NULL) {
+               LOG(KERN_ERR, "failed initialing input handler");
+               geo_clear(data);
+               return -ENOMEM;
+       }
+
+       input_data->name = SENSOR_GEO_INPUT_NAME;
+       input_data->id.bustype = BUS_I2C;
+
+       set_bit(EV_REL, input_data->evbit);
+       set_bit(EV_SYN, input_data->evbit);
+       input_set_capability(input_data, EV_REL, REL_RX);
+       input_set_capability(input_data, EV_REL, REL_RY);
+       input_set_capability(input_data, EV_REL, REL_RZ);
+       input_set_capability(input_data, EV_REL, REL_HWHEEL);
+
+       data->input_data = input_data;
+
+       ret = input_register_device(input_data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to register input data");
+               geo_clear(data);
+               return ret;
+       }
+
+       input_set_drvdata(input_data, data);
+
+       ret = sysfs_create_group(&input_data->dev.kobj,
+                       &maru_geo_attribute_group);
+       if (ret) {
+               geo_clear(data);
+               LOG(KERN_ERR, "failed initialing devices");
+               return ret;
+       }
+
+       return ret;
+}
+
+int maru_geo_init(struct virtio_sensor *vs) {
+       int ret = 0;
+       struct maru_geo_data *data = NULL;
+
+       LOG(KERN_INFO, "maru_geo device init starts.");
+
+       data = kmalloc(sizeof(struct maru_geo_data), GFP_KERNEL);
+       if (data == NULL) {
+               LOG(KERN_ERR, "failed to create geo data.");
+               return -ENOMEM;
+       }
+
+       vs->geo_handle = data;
+       data->vs = vs;
+
+       mutex_init(&data->data_mutex);
+
+       INIT_DELAYED_WORK(&data->work, maru_geo_input_work_func);
+
+       // create name & vendor
+       ret = register_sensor_device(geo_sensor_device, vs,
+                       geo_sensor_attrs, DRIVER_GEO_NAME);
+       if (ret) {
+               LOG(KERN_ERR, "failed to register geo device");
+               geo_clear(data);
+               return -1;
+       }
+
+#ifdef SUPPORT_LEGACY_SENSOR
+               ret = l_register_sensor_device(l_geo_sensor_device, vs,
+                       l_geo_sensor_attrs, DRIVER_GEO_NAME);
+       if (ret) {
+               LOG(KERN_ERR, "failed to register legacy geo device");
+               geo_clear(data);
+               return -1;
+       }
+#endif
+
+       // create input
+       ret = create_input_device(data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to create input device");
+               return ret;
+       }
+
+       // set initial delay & enable
+       ret = set_initial_value(data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to set initial value");
+               return ret;
+       }
+
+       LOG(KERN_INFO, "maru_geo device init ends.");
+
+       return ret;
+}
+
+int maru_geo_exit(struct virtio_sensor *vs) {
+       struct maru_geo_data *data = NULL;
+
+       data = (struct maru_geo_data *)vs->geo_handle;
+       geo_clear(data);
+       return 0;
+}
diff --git a/drivers/maru/sensors/maru_gyro.c b/drivers/maru/sensors/maru_gyro.c
new file mode 100644 (file)
index 0000000..030032d
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * Maru Virtio Gyroscope Sensor Device Driver
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *  Jinhyung Choi <jinhyung2.choi@samsung.com>
+ *  Sangho Park <sangho1206.park@samsung.com>
+ *  YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "maru_virtio_sensor.h"
+
+struct maru_gyro_data {
+       struct input_dev *input_data;
+       struct delayed_work work;
+       struct mutex data_mutex;
+
+       struct virtio_sensor* vs;
+
+       atomic_t enable;
+       atomic_t poll_delay;
+};
+
+static struct device *gyro_sensor_device;
+
+#ifdef SUPPORT_LEGACY_SENSOR
+static struct device *l_gyro_sensor_device;
+#endif
+
+static void maru_gyro_input_work_func(struct work_struct *work) {
+
+       int poll_time = 200000000;
+       int enable = 0;
+       int ret = 0;
+       int gyro_x, gyro_y, gyro_z;
+       char sensor_data[__MAX_BUF_SENSOR];
+       struct maru_gyro_data *data = container_of((struct delayed_work *)work,
+                       struct maru_gyro_data, work);
+
+       LOG(KERN_DEBUG, "maru_gyro_input_work_func starts");
+
+       memset(sensor_data, 0, __MAX_BUF_SENSOR);
+       poll_time = atomic_read(&data->poll_delay);
+
+       mutex_lock(&data->data_mutex);
+       enable = atomic_read(&data->enable);
+       mutex_unlock(&data->data_mutex);
+
+       if (enable) {
+               mutex_lock(&data->data_mutex);
+               ret = get_sensor_data(sensor_type_gyro, sensor_data);
+               mutex_unlock(&data->data_mutex);
+               if (!ret) {
+                       sscanf(sensor_data, "%d,%d,%d", &gyro_x, &gyro_y, &gyro_z);
+                       LOG(KERN_INFO, "gyro_set %d, %d, %d", gyro_x, gyro_y, gyro_z);
+
+                       input_report_rel(data->input_data, REL_RX, gyro_x);
+                       input_report_rel(data->input_data, REL_RY, gyro_y);
+                       input_report_rel(data->input_data, REL_RZ, gyro_z);
+                       input_sync(data->input_data);
+               }
+       }
+
+       mutex_lock(&data->data_mutex);
+       enable = atomic_read(&data->enable);
+       mutex_unlock(&data->data_mutex);
+
+       LOG(KERN_DEBUG, "enable: %d, poll_time: %d", enable, poll_time);
+       if (enable) {
+               if (poll_time > 0) {
+                       schedule_delayed_work(&data->work, nsecs_to_jiffies(poll_time));
+               } else {
+                       schedule_delayed_work(&data->work, 0);
+               }
+       }
+
+       LOG(KERN_DEBUG, "maru_gyro_input_work_func ends");
+
+}
+
+static ssize_t maru_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s", MARU_GYRO_DEVICE_NAME);
+}
+
+static ssize_t maru_vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s", MARU_SENSOR_DEVICE_VENDOR);
+}
+
+static ssize_t maru_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_gyro_enable, buf);
+}
+
+static ssize_t maru_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct input_dev *input_data = to_input_dev(dev);
+       struct maru_gyro_data *data = input_get_drvdata(input_data);
+       int value = simple_strtoul(buf, NULL, 10);
+
+       if (value != 0 && value != 1)
+               return count;
+
+       set_sensor_data(sensor_type_gyro_enable, buf);
+
+       if (value) {
+               if (atomic_read(&data->enable) != 1) {
+                       atomic_set(&data->enable, 1);
+                       schedule_delayed_work(&data->work, 0);
+
+               }
+       } else {
+               if (atomic_read(&data->enable) != 0) {
+                       atomic_set(&data->enable, 0);
+                       cancel_delayed_work(&data->work);
+               }
+       }
+
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static ssize_t maru_poll_delay_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_gyro_delay, buf);
+}
+
+static ssize_t maru_poll_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct input_dev *input_data = to_input_dev(dev);
+       struct maru_gyro_data *data = input_get_drvdata(input_data);
+       int value = simple_strtoul(buf, NULL, 10);
+
+       set_sensor_data(sensor_type_gyro_delay, buf);
+       atomic_set(&data->poll_delay, value);
+
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static struct device_attribute dev_attr_sensor_name =
+               __ATTR(name, S_IRUGO, maru_name_show, NULL);
+
+static struct device_attribute dev_attr_sensor_vendor =
+               __ATTR(vendor, S_IRUGO, maru_vendor_show, NULL);
+
+static struct device_attribute *gyro_sensor_attrs [] = {
+       &dev_attr_sensor_name,
+       &dev_attr_sensor_vendor,
+       NULL,
+};
+
+#ifdef SUPPORT_LEGACY_SENSOR
+#define GYRO_NAME_STR          "gyro_sim"
+
+static ssize_t gyro_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s", GYRO_NAME_STR);
+}
+
+static ssize_t gyro_x_raw_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_gyro_x, buf);
+}
+
+static ssize_t gyro_x_raw_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       set_sensor_data(sensor_type_gyro_x, buf);
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static ssize_t gyro_y_raw_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_gyro_y, buf);
+}
+
+static ssize_t gyro_y_raw_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       set_sensor_data(sensor_type_gyro_y, buf);
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static ssize_t gyro_z_raw_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_gyro_z, buf);
+}
+
+static ssize_t gyro_z_raw_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       set_sensor_data(sensor_type_gyro_z, buf);
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static struct device_attribute dev_attr_l_sensor_name =
+               __ATTR(name, S_IRUGO, gyro_name_show, NULL);
+
+static DEVICE_ATTR(gyro_x_raw, 0644, gyro_x_raw_show, gyro_x_raw_store);
+static DEVICE_ATTR(gyro_y_raw, 0644, gyro_y_raw_show, gyro_y_raw_store);
+static DEVICE_ATTR(gyro_z_raw, 0644, gyro_z_raw_show, gyro_z_raw_store);
+
+static struct device_attribute *l_gyro_sensor_attrs [] = {
+       &dev_attr_l_sensor_name,
+       &dev_attr_gyro_x_raw,
+       &dev_attr_gyro_y_raw,
+       &dev_attr_gyro_z_raw,
+       NULL,
+};
+#endif
+
+static struct device_attribute attr_gyro [] =
+{
+       MARU_ATTR_RW(enable),
+       MARU_ATTR_RW(poll_delay),
+};
+
+static struct attribute *maru_gyro_attribute[] = {
+       &attr_gyro[0].attr,
+       &attr_gyro[1].attr,
+       NULL
+};
+
+static struct attribute_group maru_gyro_attribute_group = {
+       .attrs = maru_gyro_attribute
+};
+
+static void gyro_clear(struct maru_gyro_data *data) {
+       if (data == NULL)
+               return;
+
+       if (data->input_data) {
+               sysfs_remove_group(&data->input_data->dev.kobj,
+                       &maru_gyro_attribute_group);
+               input_free_device(data->input_data);
+       }
+
+       kfree(data);
+       data = NULL;
+}
+
+static int set_initial_value(struct maru_gyro_data *data)
+{
+       int delay = 0;
+       int ret = 0;
+       int enable = 0;
+       char sensor_data [__MAX_BUF_SENSOR];
+
+       memset(sensor_data, 0, __MAX_BUF_SENSOR);
+
+       ret = get_sensor_data(sensor_type_gyro_delay, sensor_data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to get initial delay time");
+               return ret;
+       }
+
+       delay = sensor_atoi(sensor_data);
+
+       ret = get_sensor_data(sensor_type_gyro_enable, sensor_data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to get initial enable");
+               return ret;
+       }
+
+       enable = sensor_atoi(sensor_data);
+
+       if (delay < 0) {
+               LOG(KERN_ERR, "weird value is set initial delay");
+               return ret;
+       }
+
+       atomic_set(&data->poll_delay, delay);
+
+       if (enable) {
+               atomic_set(&data->enable, 1);
+               schedule_delayed_work(&data->work, 0);
+       }
+
+       return ret;
+}
+
+static int create_input_device(struct maru_gyro_data *data)
+{
+       int ret = 0;
+       struct input_dev *input_data = NULL;
+
+       input_data = input_allocate_device();
+       if (input_data == NULL) {
+               LOG(KERN_ERR, "failed initialing input handler");
+               gyro_clear(data);
+               return -ENOMEM;
+       }
+
+       input_data->name = SENSOR_GYRO_INPUT_NAME;
+       input_data->id.bustype = BUS_I2C;
+
+       set_bit(EV_REL, input_data->evbit);
+       set_bit(EV_SYN, input_data->evbit);
+       input_set_capability(input_data, EV_REL, REL_RX);
+       input_set_capability(input_data, EV_REL, REL_RY);
+       input_set_capability(input_data, EV_REL, REL_RZ);
+
+       data->input_data = input_data;
+
+       ret = input_register_device(input_data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to register input data");
+               gyro_clear(data);
+               return ret;
+       }
+
+       input_set_drvdata(input_data, data);
+
+       ret = sysfs_create_group(&input_data->dev.kobj,
+                       &maru_gyro_attribute_group);
+       if (ret) {
+               gyro_clear(data);
+               LOG(KERN_ERR, "failed initialing devices");
+               return ret;
+       }
+
+       return ret;
+}
+
+int maru_gyro_init(struct virtio_sensor *vs) {
+       int ret = 0;
+       struct maru_gyro_data *data = NULL;
+
+       LOG(KERN_INFO, "maru_gyro device init starts.");
+
+       data = kmalloc(sizeof(struct maru_gyro_data), GFP_KERNEL);
+       if (data == NULL) {
+               LOG(KERN_ERR, "failed to create gyro data.");
+               return -ENOMEM;
+       }
+
+       vs->gyro_handle = data;
+       data->vs = vs;
+
+       mutex_init(&data->data_mutex);
+
+       INIT_DELAYED_WORK(&data->work, maru_gyro_input_work_func);
+
+       // create name & vendor
+       ret = register_sensor_device(gyro_sensor_device, vs,
+                       gyro_sensor_attrs, DRIVER_GYRO_NAME);
+       if (ret) {
+               LOG(KERN_ERR, "failed to register gyro device");
+               gyro_clear(data);
+               return -1;
+       }
+
+#ifdef SUPPORT_LEGACY_SENSOR
+               ret = l_register_sensor_device(l_gyro_sensor_device, vs,
+                       l_gyro_sensor_attrs, DRIVER_GYRO_NAME);
+       if (ret) {
+               LOG(KERN_ERR, "failed to register legacy gyro device");
+               gyro_clear(data);
+               return -1;
+       }
+#endif
+
+       // create input
+       ret = create_input_device(data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to create input device");
+               return ret;
+       }
+
+       // set initial delay & enable
+       ret = set_initial_value(data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to set initial value");
+               return ret;
+       }
+
+       LOG(KERN_INFO, "maru_gyro device init ends.");
+
+       return ret;
+}
+
+int maru_gyro_exit(struct virtio_sensor *vs) {
+       struct maru_gyro_data *data = NULL;
+
+       data = (struct maru_gyro_data *)vs->gyro_handle;
+       gyro_clear(data);
+       return 0;
+}
diff --git a/drivers/maru/sensors/maru_light.c b/drivers/maru/sensors/maru_light.c
new file mode 100644 (file)
index 0000000..7fc1854
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+ * Maru Virtio Light Sensor Device Driver
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *  Jinhyung Choi <jinhyung2.choi@samsung.com>
+ *  Sangho Park <sangho1206.park@samsung.com>
+ *  YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "maru_virtio_sensor.h"
+
+struct maru_light_data {
+       struct input_dev *input_data;
+       struct delayed_work work;
+       struct mutex data_mutex;
+
+       struct virtio_sensor* vs;
+
+       atomic_t enable;
+       atomic_t poll_delay;
+};
+
+static struct device *light_sensor_device;
+
+#ifdef SUPPORT_LEGACY_SENSOR
+static struct device *l_light_sensor_device;
+#endif
+
+static void maru_light_input_work_func(struct work_struct *work) {
+
+       int poll_time = 200000000;
+       int enable = 0;
+       int ret = 0;
+       int light = 0;
+       char sensor_data[__MAX_BUF_SENSOR];
+       struct maru_light_data *data = container_of((struct delayed_work *)work,
+                       struct maru_light_data, work);
+
+       LOG(KERN_DEBUG, "maru_light_input_work_func starts");
+
+       memset(sensor_data, 0, __MAX_BUF_SENSOR);
+       poll_time = atomic_read(&data->poll_delay);
+
+       mutex_lock(&data->data_mutex);
+       enable = atomic_read(&data->enable);
+       mutex_unlock(&data->data_mutex);
+
+       if (enable) {
+               mutex_lock(&data->data_mutex);
+               ret = get_sensor_data(sensor_type_light, sensor_data);
+               mutex_unlock(&data->data_mutex);
+               if (!ret) {
+                       sscanf(sensor_data, "%d", &light);
+                       LOG(KERN_INFO, "light_set %d", light);
+
+                       input_report_rel(data->input_data, REL_RX, light);      // LUX
+                       input_report_rel(data->input_data, REL_HWHEEL, 0);      // red
+                       input_report_rel(data->input_data, REL_DIAL, 0);        // green
+                       input_report_rel(data->input_data, REL_WHEEL, 0);       // blue
+                       input_report_rel(data->input_data, REL_MISC, 0);        // white
+                       input_sync(data->input_data);
+               }
+       }
+
+       mutex_lock(&data->data_mutex);
+       enable = atomic_read(&data->enable);
+       mutex_unlock(&data->data_mutex);
+
+       LOG(KERN_DEBUG, "enable: %d, poll_time: %d", enable, poll_time);
+       if (enable) {
+               if (poll_time > 0) {
+                       schedule_delayed_work(&data->work, nsecs_to_jiffies(poll_time));
+               } else {
+                       schedule_delayed_work(&data->work, 0);
+               }
+       }
+
+       LOG(KERN_DEBUG, "maru_light_input_work_func ends");
+
+}
+
+static ssize_t maru_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s", MARU_LIGHT_DEVICE_NAME);
+}
+
+static ssize_t maru_vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s", MARU_SENSOR_DEVICE_VENDOR);
+}
+
+static ssize_t maru_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_light_enable, buf);
+}
+
+static ssize_t maru_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct input_dev *input_data = to_input_dev(dev);
+       struct maru_light_data *data = input_get_drvdata(input_data);
+       int value = simple_strtoul(buf, NULL, 10);
+
+       if (value != 0 && value != 1)
+               return count;
+
+       set_sensor_data(sensor_type_light_enable, buf);
+
+       if (value) {
+               if (atomic_read(&data->enable) != 1) {
+                       atomic_set(&data->enable, 1);
+                       schedule_delayed_work(&data->work, 0);
+
+               }
+       } else {
+               if (atomic_read(&data->enable) != 0) {
+                       atomic_set(&data->enable, 0);
+                       cancel_delayed_work(&data->work);
+               }
+       }
+
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static ssize_t maru_poll_delay_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_light_delay, buf);
+}
+
+static ssize_t maru_poll_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct input_dev *input_data = to_input_dev(dev);
+       struct maru_light_data *data = input_get_drvdata(input_data);
+       int value = simple_strtoul(buf, NULL, 10);
+
+       set_sensor_data(sensor_type_light_delay, buf);
+       atomic_set(&data->poll_delay, value);
+
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static struct device_attribute dev_attr_sensor_name =
+               __ATTR(name, S_IRUGO, maru_name_show, NULL);
+
+static struct device_attribute dev_attr_sensor_vendor =
+               __ATTR(vendor, S_IRUGO, maru_vendor_show, NULL);
+
+static struct device_attribute *light_sensor_attrs [] = {
+       &dev_attr_sensor_name,
+       &dev_attr_sensor_vendor,
+       NULL,
+};
+
+#ifdef SUPPORT_LEGACY_SENSOR
+#define LIGHT_NAME_STR         "light_sim"
+
+static ssize_t light_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s", LIGHT_NAME_STR);
+}
+
+static ssize_t adc_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_light_adc, buf);
+}
+
+static ssize_t adc_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       set_sensor_data(sensor_type_light_adc, buf);
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static ssize_t level_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_light_level, buf);
+}
+
+static ssize_t level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       set_sensor_data(sensor_type_light_level, buf);
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static struct device_attribute dev_attr_l_sensor_name =
+               __ATTR(name, S_IRUGO, light_name_show, NULL);
+
+static DEVICE_ATTR(adc, 0644, adc_show, adc_store);
+static DEVICE_ATTR(level, 0644, level_show, level_store);
+
+static struct device_attribute *l_light_sensor_attrs [] = {
+       &dev_attr_l_sensor_name,
+       &dev_attr_adc,
+       &dev_attr_level,
+       NULL,
+};
+#endif
+
+static struct device_attribute attr_light [] =
+{
+       MARU_ATTR_RW(enable),
+       MARU_ATTR_RW(poll_delay),
+};
+
+static struct attribute *maru_light_attribute[] = {
+       &attr_light[0].attr,
+       &attr_light[1].attr,
+       NULL
+};
+
+static struct attribute_group maru_light_attribute_group = {
+       .attrs = maru_light_attribute
+};
+
+static void light_clear(struct maru_light_data *data) {
+       if (data == NULL)
+               return;
+
+       if (data->input_data) {
+               sysfs_remove_group(&data->input_data->dev.kobj,
+                       &maru_light_attribute_group);
+               input_free_device(data->input_data);
+       }
+
+       kfree(data);
+       data = NULL;
+}
+
+static int set_initial_value(struct maru_light_data *data)
+{
+       int delay = 0;
+       int ret = 0;
+       int enable = 0;
+       char sensor_data [__MAX_BUF_SENSOR];
+
+       memset(sensor_data, 0, __MAX_BUF_SENSOR);
+
+       ret = get_sensor_data(sensor_type_light_delay, sensor_data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to get initial delay time");
+               return ret;
+       }
+
+       delay = sensor_atoi(sensor_data);
+
+       ret = get_sensor_data(sensor_type_light_enable, sensor_data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to get initial enable");
+               return ret;
+       }
+
+       enable = sensor_atoi(sensor_data);
+
+       if (delay < 0) {
+               LOG(KERN_ERR, "weird value is set initial delay");
+               return ret;
+       }
+
+       atomic_set(&data->poll_delay, delay);
+
+       if (enable) {
+               atomic_set(&data->enable, 1);
+               schedule_delayed_work(&data->work, 0);
+       }
+
+       return ret;
+}
+
+static int create_input_device(struct maru_light_data *data)
+{
+       int ret = 0;
+       struct input_dev *input_data = NULL;
+
+       input_data = input_allocate_device();
+       if (input_data == NULL) {
+               LOG(KERN_ERR, "failed initialing input handler");
+               light_clear(data);
+               return -ENOMEM;
+       }
+
+       input_data->name = SENSOR_LIGHT_INPUT_NAME;
+       input_data->id.bustype = BUS_I2C;
+
+       set_bit(EV_REL, input_data->evbit);
+       input_set_capability(input_data, EV_REL, REL_RX);
+       input_set_capability(input_data, EV_REL, REL_HWHEEL);
+       input_set_capability(input_data, EV_REL, REL_DIAL);
+       input_set_capability(input_data, EV_REL, REL_WHEEL);
+       input_set_capability(input_data, EV_REL, REL_MISC);
+
+       data->input_data = input_data;
+
+       ret = input_register_device(input_data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to register input data");
+               light_clear(data);
+               return ret;
+       }
+
+       input_set_drvdata(input_data, data);
+
+       ret = sysfs_create_group(&input_data->dev.kobj,
+                       &maru_light_attribute_group);
+       if (ret) {
+               light_clear(data);
+               LOG(KERN_ERR, "failed initialing devices");
+               return ret;
+       }
+
+       return ret;
+}
+
+int maru_light_init(struct virtio_sensor *vs) {
+       int ret = 0;
+       struct maru_light_data *data = NULL;
+
+       LOG(KERN_INFO, "maru_light device init starts.");
+
+       data = kmalloc(sizeof(struct maru_light_data), GFP_KERNEL);
+       if (data == NULL) {
+               LOG(KERN_ERR, "failed to create light data.");
+               return -ENOMEM;
+       }
+
+       vs->light_handle = data;
+       data->vs = vs;
+
+       mutex_init(&data->data_mutex);
+
+       INIT_DELAYED_WORK(&data->work, maru_light_input_work_func);
+
+       // create name & vendor
+       ret = register_sensor_device(light_sensor_device, vs,
+                       light_sensor_attrs, DRIVER_LIGHT_NAME);
+       if (ret) {
+               LOG(KERN_ERR, "failed to register light device");
+               light_clear(data);
+               return -1;
+       }
+
+#ifdef SUPPORT_LEGACY_SENSOR
+               ret = l_register_sensor_device(l_light_sensor_device, vs,
+                       l_light_sensor_attrs, DRIVER_LIGHT_NAME);
+       if (ret) {
+               LOG(KERN_ERR, "failed to register legacy light device");
+               light_clear(data);
+               return -1;
+       }
+#endif
+
+       // create input
+       ret = create_input_device(data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to create input device");
+               return ret;
+       }
+
+       // set initial delay & enable
+       ret = set_initial_value(data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to set initial value");
+               return ret;
+       }
+
+       LOG(KERN_INFO, "maru_light device init ends.");
+
+       return ret;
+}
+
+int maru_light_exit(struct virtio_sensor *vs) {
+       struct maru_light_data *data = NULL;
+
+       data = (struct maru_light_data *)vs->light_handle;
+       light_clear(data);
+       return 0;
+}
diff --git a/drivers/maru/sensors/maru_proxi.c b/drivers/maru/sensors/maru_proxi.c
new file mode 100644 (file)
index 0000000..ce3554a
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * Maru Virtio Proximity Sensor Device Driver
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *  Jinhyung Choi <jinhyung2.choi@samsung.com>
+ *  Sangho Park <sangho1206.park@samsung.com>
+ *  YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include "maru_virtio_sensor.h"
+
+struct maru_proxi_data {
+       struct input_dev *input_data;
+       struct delayed_work work;
+       struct mutex data_mutex;
+
+       struct virtio_sensor* vs;
+
+       atomic_t enable;
+       atomic_t poll_delay;
+};
+
+static struct device *proxi_sensor_device;
+
+#ifdef SUPPORT_LEGACY_SENSOR
+static struct device *l_proxi_sensor_device;
+#endif
+
+static void maru_proxi_input_work_func(struct work_struct *work) {
+
+       int poll_time = 200000000;
+       int enable = 0;
+       int ret = 0;
+       int proxi = 0;
+       char sensor_data[__MAX_BUF_SENSOR];
+       struct maru_proxi_data *data = container_of((struct delayed_work *)work,
+                       struct maru_proxi_data, work);
+
+       LOG(KERN_DEBUG, "maru_proxi_input_work_func starts");
+
+       memset(sensor_data, 0, __MAX_BUF_SENSOR);
+       poll_time = atomic_read(&data->poll_delay);
+
+       mutex_lock(&data->data_mutex);
+       enable = atomic_read(&data->enable);
+       mutex_unlock(&data->data_mutex);
+
+       if (enable) {
+               mutex_lock(&data->data_mutex);
+               ret = get_sensor_data(sensor_type_proxi, sensor_data);
+               mutex_unlock(&data->data_mutex);
+               if (!ret) {
+                       sscanf(sensor_data, "%d", &proxi);
+                       if (proxi)
+                               proxi = 1;
+                       LOG(KERN_INFO, "proxi_set %d", proxi);
+
+                       input_report_rel(data->input_data, ABS_DISTANCE, proxi);
+                       input_sync(data->input_data);
+               }
+       }
+
+       mutex_lock(&data->data_mutex);
+       enable = atomic_read(&data->enable);
+       mutex_unlock(&data->data_mutex);
+
+       LOG(KERN_DEBUG, "enable: %d, poll_time: %d", enable, poll_time);
+       if (enable) {
+               if (poll_time > 0) {
+                       schedule_delayed_work(&data->work, nsecs_to_jiffies(poll_time));
+               } else {
+                       schedule_delayed_work(&data->work, 0);
+               }
+       }
+
+       LOG(KERN_DEBUG, "maru_proxi_input_work_func ends");
+
+}
+
+static ssize_t maru_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s", MARU_PROXI_DEVICE_NAME);
+}
+
+static ssize_t maru_vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s", MARU_SENSOR_DEVICE_VENDOR);
+}
+
+static ssize_t maru_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_proxi_enable, buf);
+}
+
+static ssize_t maru_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct input_dev *input_data = to_input_dev(dev);
+       struct maru_proxi_data *data = input_get_drvdata(input_data);
+       int value = simple_strtoul(buf, NULL, 10);
+
+       if (value != 0 && value != 1)
+               return count;
+
+       set_sensor_data(sensor_type_proxi_enable, buf);
+
+       if (value) {
+               if (atomic_read(&data->enable) != 1) {
+                       atomic_set(&data->enable, 1);
+                       schedule_delayed_work(&data->work, 0);
+
+               }
+       } else {
+               if (atomic_read(&data->enable) != 0) {
+                       atomic_set(&data->enable, 0);
+                       cancel_delayed_work(&data->work);
+               }
+       }
+
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static ssize_t maru_poll_delay_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_proxi_delay, buf);
+}
+
+static ssize_t maru_poll_delay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct input_dev *input_data = to_input_dev(dev);
+       struct maru_proxi_data *data = input_get_drvdata(input_data);
+       int value = simple_strtoul(buf, NULL, 10);
+
+       set_sensor_data(sensor_type_proxi_delay, buf);
+       atomic_set(&data->poll_delay, value);
+
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static struct device_attribute dev_attr_sensor_name =
+               __ATTR(name, S_IRUGO, maru_name_show, NULL);
+
+static struct device_attribute dev_attr_sensor_vendor =
+               __ATTR(vendor, S_IRUGO, maru_vendor_show, NULL);
+
+static struct device_attribute *proxi_sensor_attrs [] = {
+       &dev_attr_sensor_name,
+       &dev_attr_sensor_vendor,
+       NULL,
+};
+
+#ifdef SUPPORT_LEGACY_SENSOR
+#define PROXI_NAME_STR         "proxi_sim"
+
+static ssize_t proxi_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s", PROXI_NAME_STR);
+}
+
+static ssize_t enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_proxi_enable, buf);
+}
+
+static ssize_t enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       set_sensor_data(sensor_type_proxi_enable, buf);
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static ssize_t vo_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return get_data_for_show(sensor_type_proxi, buf);
+}
+
+static ssize_t vo_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       set_sensor_data(sensor_type_proxi, buf);
+       return strnlen(buf, __MAX_BUF_SENSOR);
+}
+
+static struct device_attribute dev_attr_l_sensor_name =
+               __ATTR(name, S_IRUGO, proxi_name_show, NULL);
+
+static DEVICE_ATTR(enable, 0644, enable_show, enable_store);
+static DEVICE_ATTR(vo, 0644, vo_show, vo_store);
+
+static struct device_attribute *l_proxi_sensor_attrs [] = {
+       &dev_attr_l_sensor_name,
+       &dev_attr_enable,
+       &dev_attr_vo,
+       NULL,
+};
+#endif
+
+static struct device_attribute attr_proxi [] =
+{
+       MARU_ATTR_RW(enable),
+       MARU_ATTR_RW(poll_delay),
+};
+
+static struct attribute *maru_proxi_attribute[] = {
+       &attr_proxi[0].attr,
+       &attr_proxi[1].attr,
+       NULL
+};
+
+static struct attribute_group maru_proxi_attribute_group = {
+       .attrs = maru_proxi_attribute
+};
+
+static void proxi_clear(struct maru_proxi_data *data) {
+       if (data == NULL)
+               return;
+
+       if (data->input_data) {
+               sysfs_remove_group(&data->input_data->dev.kobj,
+                       &maru_proxi_attribute_group);
+               input_free_device(data->input_data);
+       }
+
+       kfree(data);
+       data = NULL;
+}
+
+static int set_initial_value(struct maru_proxi_data *data)
+{
+       int delay = 0;
+       int ret = 0;
+       int enable = 0;
+       char sensor_data [__MAX_BUF_SENSOR];
+
+       memset(sensor_data, 0, __MAX_BUF_SENSOR);
+
+       ret = get_sensor_data(sensor_type_proxi_delay, sensor_data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to get initial delay time");
+               return ret;
+       }
+
+       delay = sensor_atoi(sensor_data);
+
+       ret = get_sensor_data(sensor_type_proxi_enable, sensor_data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to get initial enable");
+               return ret;
+       }
+
+       enable = sensor_atoi(sensor_data);
+
+       if (delay < 0) {
+               LOG(KERN_ERR, "weird value is set initial delay");
+               return ret;
+       }
+
+       atomic_set(&data->poll_delay, delay);
+
+       if (enable) {
+               atomic_set(&data->enable, 1);
+               schedule_delayed_work(&data->work, 0);
+       }
+
+       return ret;
+}
+
+static int create_input_device(struct maru_proxi_data *data)
+{
+       int ret = 0;
+       struct input_dev *input_data = NULL;
+
+       input_data = input_allocate_device();
+       if (input_data == NULL) {
+               LOG(KERN_ERR, "failed initialing input handler");
+               proxi_clear(data);
+               return -ENOMEM;
+       }
+
+       input_data->name = SENSOR_PROXI_INPUT_NAME;
+       input_data->id.bustype = BUS_I2C;
+
+       set_bit(EV_ABS, input_data->evbit);
+       input_set_capability(input_data, EV_ABS, ABS_DISTANCE);
+
+       data->input_data = input_data;
+
+       ret = input_register_device(input_data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to register input data");
+               proxi_clear(data);
+               return ret;
+       }
+
+       input_set_drvdata(input_data, data);
+
+       ret = sysfs_create_group(&input_data->dev.kobj,
+                       &maru_proxi_attribute_group);
+       if (ret) {
+               proxi_clear(data);
+               LOG(KERN_ERR, "failed initialing devices");
+               return ret;
+       }
+
+       return ret;
+}
+
+int maru_proxi_init(struct virtio_sensor *vs) {
+       int ret = 0;
+       struct maru_proxi_data *data = NULL;
+
+       LOG(KERN_INFO, "maru_proxi device init starts.");
+
+       data = kmalloc(sizeof(struct maru_proxi_data), GFP_KERNEL);
+       if (data == NULL) {
+               LOG(KERN_ERR, "failed to create proxi data.");
+               return -ENOMEM;
+       }
+
+       vs->proxi_handle = data;
+       data->vs = vs;
+
+       mutex_init(&data->data_mutex);
+
+       INIT_DELAYED_WORK(&data->work, maru_proxi_input_work_func);
+
+       // create name & vendor
+       ret = register_sensor_device(proxi_sensor_device, vs,
+                       proxi_sensor_attrs, DRIVER_PROXI_NAME);
+       if (ret) {
+               LOG(KERN_ERR, "failed to register proxi device");
+               proxi_clear(data);
+               return -1;
+       }
+
+#ifdef SUPPORT_LEGACY_SENSOR
+               ret = l_register_sensor_device(l_proxi_sensor_device, vs,
+                       l_proxi_sensor_attrs, DRIVER_PROXI_NAME);
+       if (ret) {
+               LOG(KERN_ERR, "failed to register legacy proxi device");
+               proxi_clear(data);
+               return -1;
+       }
+#endif
+
+       // create input
+       ret = create_input_device(data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to create input device");
+               return ret;
+       }
+
+       // set initial delay & enable
+       ret = set_initial_value(data);
+       if (ret) {
+               LOG(KERN_ERR, "failed to set initial value");
+               return ret;
+       }
+
+       LOG(KERN_INFO, "maru_proxi device init ends.");
+
+       return ret;
+}
+
+int maru_proxi_exit(struct virtio_sensor *vs) {
+       struct maru_proxi_data *data = NULL;
+
+       data = (struct maru_proxi_data *)vs->proxi_handle;
+       proxi_clear(data);
+       return 0;
+}
diff --git a/drivers/maru/sensors/maru_virtio_sensor.c b/drivers/maru/sensors/maru_virtio_sensor.c
new file mode 100644 (file)
index 0000000..c17de0a
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+ * Maru Virtio Sensor Device Driver
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *  Jinhyung Choi <jinhyung2.choi@samsung.com>
+ *  Daiyoung Kim <daiyoung777.kim@samsung.com>
+ *  YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/virtio.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/cdev.h>
+
+#include "maru_virtio_sensor.h"
+
+static struct virtio_device_id id_table[] = { { VIRTIO_ID_SENSOR,
+               VIRTIO_DEV_ANY_ID }, { 0 }, };
+
+static char sensor_data[__MAX_BUF_SENSOR];
+
+struct virtio_sensor *vs;
+
+static DECLARE_WAIT_QUEUE_HEAD(wq);
+
+int sensor_atoi(const char *value)
+{
+    int val = 0;
+
+    for (;; value++) {
+        switch (*value) {
+            case '0' ... '9':
+                val = 10*val+(*value-'0');
+                break;
+            default:
+                return val;
+        }
+    }
+}
+
+int register_sensor_device(struct device *dev, struct virtio_sensor *vs,
+               struct device_attribute *attributes[], const char* name)
+{
+       int i = 0, err = 0;
+
+       if (!vs->sensor_class) {
+               LOG(KERN_ERR, "sensor class is not created before make device");
+               return -1;
+       }
+
+       LOG(KERN_INFO, "device creation: %s.", name);
+
+       dev = device_create(vs->sensor_class, NULL, 0, NULL, "%s", name);
+       if (dev < 0) {
+               LOG(KERN_ERR, "register_device_create failed!");
+               return -1;
+       }
+
+       if (attributes == NULL) {
+               LOG(KERN_ERR, "attributes is NULL.");
+               return -1;
+       }
+
+       for (i = 0; attributes[i] != NULL; i++) {
+               if ((err = device_create_file(dev, attributes[i])) < 0) {
+                       LOG(KERN_ERR, "failed to create device file with attribute[%d - %d]", i, err);
+                       return -1;
+               }
+       }
+
+       LOG(KERN_INFO, "register_sensor_device ends: %s.", name);
+
+       return 0;
+}
+
+#ifdef SUPPORT_LEGACY_SENSOR
+
+int l_register_sensor_device(struct device *dev, struct virtio_sensor *vs,
+               struct device_attribute *attributes[], const char* name)
+{
+       int i = 0, err = 0;
+
+       if (!vs->l_sensor_class) {
+               LOG(KERN_ERR, "l sensor class is not created before make device");
+               return -1;
+       }
+
+       dev = device_create(vs->l_sensor_class, NULL, 0, NULL, "%s", name);
+       if (dev < 0) {
+               LOG(KERN_ERR, "legacy register_device_create failed!");
+               return -1;
+       }
+
+       if (attributes == NULL) {
+               LOG(KERN_ERR, "l sensor attributes is NULL.");
+               return -1;
+       }
+
+       for (i = 0; attributes[i] != NULL; i++) {
+               if ((err = device_create_file(dev, attributes[i])) < 0) {
+                       LOG(KERN_ERR, "failed to create legacy device file with attribute[%d - %d]", i, err);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+#endif
+
+static void sensor_vq_done(struct virtqueue *rvq) {
+       unsigned int len;
+       struct msg_info* msg;
+
+       msg = (struct msg_info*) virtqueue_get_buf(vs->vq, &len);
+       if (msg == NULL) {
+               LOG(KERN_ERR, "failed to virtqueue_get_buf");
+               return;
+       }
+
+       if (msg->req != request_answer) {
+               LOG(KERN_DEBUG, "receive queue- not an answer message: %d", msg->req);
+               return;
+       }
+       if (msg->buf == NULL) {
+               LOG(KERN_ERR, "receive queue- message from host is NULL.");
+               return;
+       }
+
+       LOG(KERN_DEBUG, "msg buf: %s, req: %d, type: %d", msg->buf, msg->req, msg->type);
+
+       mutex_lock(&vs->lock);
+       memset(sensor_data, 0, __MAX_BUF_SENSOR);
+       strcpy(sensor_data, msg->buf);
+       vs->flags = 1;
+       mutex_unlock(&vs->lock);
+
+       wake_up_interruptible(&wq);
+}
+
+void set_sensor_data(int type, const char* buf)
+{
+       int err = 0;
+
+       if (buf == NULL) {
+               LOG(KERN_ERR, "set_sensor buf is NULL.");
+               return;
+       }
+
+       if (vs == NULL) {
+               LOG(KERN_ERR, "Invalid sensor handle");
+               return;
+       }
+
+       mutex_lock(&vs->lock);
+       memset(&vs->msginfo, 0, sizeof(vs->msginfo));
+
+       vs->msginfo.req = request_set;
+       vs->msginfo.type = type;
+       strcpy(vs->msginfo.buf, buf);
+       mutex_unlock(&vs->lock);
+
+       LOG(KERN_DEBUG, "set_sensor_data type: %d, req: %d, buf: %s",
+                       vs->msginfo.type, vs->msginfo.req, vs->msginfo.buf);
+
+       err = virtqueue_add_outbuf(vs->vq, vs->sg_vq, 1, &vs->msginfo, GFP_ATOMIC);
+       if (err < 0) {
+               LOG(KERN_ERR, "failed to add buffer to virtqueue (err = %d)", err);
+               return;
+       }
+
+       virtqueue_kick(vs->vq);
+}
+
+int get_sensor_data(int type, char* data)
+{
+       struct scatterlist *sgs[2];
+       int err = 0;
+
+       if (vs == NULL || data == NULL) {
+               LOG(KERN_ERR, "Invalid sensor handle or data is NULL.");
+               return -1;
+       }
+
+       mutex_lock(&vs->lock);
+       memset(&vs->msginfo, 0, sizeof(vs->msginfo));
+
+       vs->msginfo.req = request_get;
+       vs->msginfo.type = type;
+       mutex_unlock(&vs->lock);
+
+       LOG(KERN_DEBUG, "get_sensor_data type: %d, req: %d",
+                       vs->msginfo.type, vs->msginfo.req);
+
+       sgs[0] = &vs->sg_vq[0];
+       sgs[1] = &vs->sg_vq[1];
+       err = virtqueue_add_sgs(vs->vq, sgs, 1, 1, &vs->msginfo, GFP_ATOMIC);
+       if (err < 0) {
+               LOG(KERN_ERR, "failed to add buffer to virtqueue (err = %d)", err);
+               return err;
+       }
+
+       virtqueue_kick(vs->vq);
+
+       wait_event_interruptible(wq, vs->flags != 0);
+
+       mutex_lock(&vs->lock);
+       vs->flags = 0;
+       memcpy(data, sensor_data, strlen(sensor_data));
+       mutex_unlock(&vs->lock);
+
+       return 0;
+}
+
+int get_data_for_show(int type, char* buf)
+{
+       char sensor_data[__MAX_BUF_SENSOR];
+       int ret;
+
+       memset(sensor_data, 0, __MAX_BUF_SENSOR);
+       ret = get_sensor_data(type, sensor_data);
+       if (ret)
+               return sprintf(buf, "%d", -1);
+
+       return sprintf(buf, "%s", sensor_data);
+}
+
+static int device_init(struct virtio_sensor *vs)
+{
+       int ret = 0;
+
+       if (vs->sensor_capability & sensor_cap_accel) {
+               ret = maru_accel_init(vs);
+               if (ret)
+                       return ret;
+       }
+
+       if (vs->sensor_capability & sensor_cap_geo) {
+               ret = maru_geo_init(vs);
+               if (ret)
+                       return ret;
+       }
+
+       if (vs->sensor_capability & sensor_cap_gyro) {
+               ret = maru_gyro_init(vs);
+               if (ret)
+                       return ret;
+       }
+
+       if (vs->sensor_capability & sensor_cap_light) {
+               ret = maru_light_init(vs);
+               if (ret)
+                       return ret;
+       }
+
+       if (vs->sensor_capability & sensor_cap_proxi) {
+               ret = maru_proxi_init(vs);
+               if (ret)
+                       return ret;
+       }
+
+       return ret;
+}
+
+static void device_exit(struct virtio_sensor *vs)
+{
+       if (vs->sensor_capability & sensor_cap_accel) {
+               maru_accel_exit(vs);
+       }
+
+       if (vs->sensor_capability & sensor_cap_geo) {
+               maru_geo_exit(vs);
+       }
+
+       if (vs->sensor_capability & sensor_cap_gyro) {
+               maru_gyro_exit(vs);
+       }
+
+       if (vs->sensor_capability & sensor_cap_light) {
+               maru_light_exit(vs);
+       }
+
+       if (vs->sensor_capability & sensor_cap_proxi) {
+               maru_proxi_exit(vs);
+       }
+}
+
+static void cleanup(struct virtio_device* dev) {
+       dev->config->del_vqs(dev);
+
+       if (vs == NULL)
+               return;
+
+       if (vs->sensor_class) {
+               device_destroy(vs->sensor_class, (dev_t)NULL);
+               class_destroy(vs->sensor_class);
+       }
+
+#ifdef SUPPORT_LEGACY_SENSOR
+       if (vs->l_sensor_class) {
+               device_destroy(vs->l_sensor_class, (dev_t)NULL);
+               class_destroy(vs->l_sensor_class);
+       }
+#endif
+
+       kfree(vs);
+       vs = NULL;
+}
+
+static int sensor_probe(struct virtio_device* dev)
+{
+       int ret = 0;
+       int index = 0;
+       char sensor_data[__MAX_BUF_SENSOR];
+
+       LOG(KERN_INFO, "Sensor probe starts");
+
+       vs = kmalloc(sizeof(struct virtio_sensor), GFP_KERNEL);
+       if (!vs) {
+               LOG(KERN_ERR, "failed to allocate sensor structure.");
+               return -ENOMEM;
+       }
+
+       vs->vdev = dev;
+       dev->priv = vs;
+
+       vs->sensor_class = class_create(THIS_MODULE, SENSOR_CLASS_NAME);
+       if (IS_ERR(vs->sensor_class)) {
+               LOG(KERN_ERR, "sensor class creation is failed.");
+               return PTR_ERR(vs->sensor_class);
+       }
+
+#ifdef SUPPORT_LEGACY_SENSOR
+       vs->l_sensor_class = class_create(THIS_MODULE, L_SENSOR_CLASS_NAME);
+       if (IS_ERR(vs->sensor_class)) {
+               LOG(KERN_ERR, "sensor class creation is failed.");
+               return PTR_ERR(vs->sensor_class);
+       }
+#endif
+
+       vs->vq = virtio_find_single_vq(dev, sensor_vq_done, "sensor");
+       if (IS_ERR(vs->vq)) {
+               cleanup(dev);
+               LOG(KERN_ERR, "failed to init virt queue");
+               return ret;
+       }
+
+       virtqueue_enable_cb(vs->vq);
+
+       sg_init_table(vs->sg_vq, 2);
+       for (; index < 2; index++) {
+               sg_set_buf(&vs->sg_vq[index], &vs->msginfo, sizeof(vs->msginfo));
+       }
+
+       mutex_init(&vs->lock);
+
+       memset(sensor_data, 0, __MAX_BUF_SENSOR);
+       ret = get_sensor_data(sensor_type_list, sensor_data);
+       if (ret) {
+               LOG(KERN_ERR, "sensor capability data is null.");
+               cleanup(dev);
+               return ret;
+       }
+
+       vs->sensor_capability = sensor_atoi(sensor_data);
+       LOG(KERN_INFO, "sensor capability is %02x", vs->sensor_capability);
+
+       ret = device_init(vs);
+       if (ret) {
+               LOG(KERN_ERR, "failed initialing devices");
+               cleanup(dev);
+               return ret;
+       }
+
+       LOG(KERN_INFO, "Sensor probe completes");
+
+       return ret;
+}
+
+static void sensor_remove(struct virtio_device* dev)
+{
+       struct virtio_sensor* vs = dev->priv;
+       if (!vs)
+       {
+               LOG(KERN_ERR, "vs is NULL");
+               return;
+       }
+
+       dev->config->reset(dev);
+
+       device_exit(vs);
+
+       cleanup(dev);
+
+       LOG(KERN_INFO, "Sensor driver is removed.");
+}
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+
+static struct virtio_driver virtio_sensor_driver = {
+               .driver = {
+                               .name = KBUILD_MODNAME,
+                               .owner = THIS_MODULE ,
+               },
+               .id_table = id_table,
+               .probe = sensor_probe,
+               .remove = sensor_remove,
+};
+
+
+static int __init sensor_init(void)
+{
+       LOG(KERN_INFO, "Sensor driver initialized.");
+
+       return register_virtio_driver(&virtio_sensor_driver);
+}
+
+static void __exit sensor_exit(void)
+{
+       unregister_virtio_driver(&virtio_sensor_driver);
+
+       LOG(KERN_INFO, "Sensor driver is destroyed.");
+}
+
+module_init(sensor_init);
+module_exit(sensor_exit);
+
+MODULE_LICENSE("GPL2");
+MODULE_AUTHOR("Jinhyung Choi <jinhyung2.choi@samsung.com>");
+MODULE_DESCRIPTION("Emulator Virtio Sensor Driver");
+
diff --git a/drivers/maru/sensors/maru_virtio_sensor.h b/drivers/maru/sensors/maru_virtio_sensor.h
new file mode 100644 (file)
index 0000000..f0c5b8d
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Maru Virtio Sensor Device Driver
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ *  Jinhyung Choi <jinhyung2.choi@samsung.com>
+ *  Sangho Park <sangho1206.park@samsung.com>
+ *  YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+#ifndef _MARU_VIRTIO_SENSOR_H
+#define _MARU_VIRTIO_SENSOR_H
+
+#include <linux/kernel.h>
+#include <linux/virtio.h>
+#include <linux/input.h>
+
+#define SUPPORT_LEGACY_SENSOR  1
+
+enum request_cmd {
+       request_get = 0,
+       request_set,
+       request_answer
+};
+
+enum sensor_types {
+    sensor_type_list = 0,
+    sensor_type_accel,
+    sensor_type_accel_enable,
+    sensor_type_accel_delay,
+       sensor_type_geo,
+    sensor_type_geo_enable,
+    sensor_type_geo_delay,
+       sensor_type_gyro,
+    sensor_type_gyro_enable,
+    sensor_type_gyro_delay,
+       sensor_type_gyro_x,
+       sensor_type_gyro_y,
+       sensor_type_gyro_z,
+       sensor_type_light,
+       sensor_type_light_enable,
+       sensor_type_light_delay,
+       sensor_type_light_adc,
+       sensor_type_light_level,
+       sensor_type_proxi,
+       sensor_type_proxi_enable,
+       sensor_type_proxi_delay,
+       sensor_type_mag,
+       sensor_type_tilt,
+       sensor_type_max
+};
+
+enum sensor_capabilities {
+       sensor_cap_accel = 0x01,
+       sensor_cap_geo   = 0x02,
+       sensor_cap_gyro  = 0x04,
+       sensor_cap_light = 0x08,
+       sensor_cap_proxi = 0x10
+};
+
+#define __MAX_BUF_SIZE                 1024
+#define __MAX_BUF_SENSOR               128
+
+struct msg_info {
+       char buf[__MAX_BUF_SIZE];
+
+       uint16_t type;
+       uint16_t req;
+};
+
+#ifdef SUPPORT_LEGACY_SENSOR
+#  define L_SENSOR_CLASS_NAME          "sensor"
+#endif
+
+struct virtio_sensor {
+       struct virtio_device* vdev;
+       struct virtqueue* vq;
+
+       struct msg_info msginfo;
+       struct scatterlist sg_vq[2];
+
+       int flags;
+       struct mutex lock;
+
+       struct class* sensor_class;
+
+#ifdef SUPPORT_LEGACY_SENSOR
+       struct class* l_sensor_class;
+#endif
+
+       int sensor_capability;
+
+       void* accel_handle;
+       void* geo_handle;
+       void* gyro_handle;
+       void* light_handle;
+       void* proxi_handle;
+};
+
+#define MARU_DEVICE_ATTR(_name)        \
+       struct device_attribute dev_attr_##_name = MARU_ATTR_RONLY(_name)
+
+#define MARU_ATTR_RONLY(_name) { \
+       .attr   = { .name = __stringify(_name), .mode = 0444 }, \
+       .show   = maru_##_name##_show,                                  \
+}
+
+#define MARU_ATTR_RW(_name) { \
+       .attr = {.name = __stringify(_name), .mode = 0644 },    \
+       .show   = maru_##_name##_show,                                  \
+       .store  = maru_##_name##_store,                                 \
+}
+
+int sensor_atoi(const char *value);
+
+int get_data_for_show(int type, char* buf);
+int register_sensor_device(struct device *dev, struct virtio_sensor *vs,
+               struct device_attribute *attributes[], const char* name);
+
+#ifdef SUPPORT_LEGACY_SENSOR
+int l_register_sensor_device(struct device *dev, struct virtio_sensor *vs,
+               struct device_attribute *attributes[], const char* name);
+#endif
+
+void set_sensor_data(int type, const char* buf);
+int get_sensor_data(int type, char* data);
+
+#define SENSOR_CLASS_NAME                      "sensors"
+#define MARU_SENSOR_DEVICE_VENDOR      "Tizen"
+
+#define DRIVER_ACCEL_NAME                      "accel"
+#define SENSOR_ACCEL_INPUT_NAME                "accelerometer_sensor"
+#define MARU_ACCEL_DEVICE_NAME         "EMULATOR_ACCEL"
+
+#define DRIVER_GEO_NAME                                "geo"
+#define SENSOR_GEO_INPUT_NAME          "geomagnetic_sensor"
+#define MARU_GEO_DEVICE_NAME           "EMULATOR_GEO"
+
+#define DRIVER_GYRO_NAME                       "gyro"
+#define SENSOR_GYRO_INPUT_NAME         "gyro_sensor"
+#define MARU_GYRO_DEVICE_NAME          "EMULATOR_GYRO"
+
+#define DRIVER_LIGHT_NAME                      "light"
+#define SENSOR_LIGHT_INPUT_NAME                "light_sensor"
+#define MARU_LIGHT_DEVICE_NAME         "EMULATOR_LIGHT"
+
+#define DRIVER_PROXI_NAME                      "proxi"
+#define SENSOR_PROXI_INPUT_NAME                "proximity_sensor"
+#define MARU_PROXI_DEVICE_NAME         "EMULATOR_PROXI"
+
+#define LOG(log_level, fmt, ...) \
+       printk(log_level "%s: " fmt "\n", SENSOR_CLASS_NAME, ##__VA_ARGS__)
+
+/*
+ * Accelerometer device
+ */
+int maru_accel_init(struct virtio_sensor *vs);
+int maru_accel_exit(struct virtio_sensor *vs);
+
+/*
+ * Geomagnetic device
+ */
+int maru_geo_init(struct virtio_sensor *vs);
+int maru_geo_exit(struct virtio_sensor *vs);
+
+/*
+ * Gyroscope device
+ */
+int maru_gyro_init(struct virtio_sensor *vs);
+int maru_gyro_exit(struct virtio_sensor *vs);
+
+/*
+ * Light device
+ */
+int maru_light_init(struct virtio_sensor *vs);
+int maru_light_exit(struct virtio_sensor *vs);
+
+/*
+ * Proximity device
+ */
+int maru_proxi_init(struct virtio_sensor *vs);
+int maru_proxi_exit(struct virtio_sensor *vs);
+
+#endif