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
+++ /dev/null
-/*
- * 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");
-
--- /dev/null
+obj-$(CONFIG_MARU_VIRTIO_SENSOR) += maru_virtio_sensor.o \
+ maru_accel.o \
+ maru_geo.o \
+ maru_gyro.o \
+ maru_light.o \
+ maru_proxi.o
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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");
+
--- /dev/null
+/*
+ * 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