driver: added sensor and jack driver 41/19241/4
authorJinhyung Choi <jinhyung2.choi@samsung.com>
Wed, 9 Apr 2014 07:47:59 +0000 (16:47 +0900)
committerJinhyung Choi <jinhyung2.choi@samsung.com>
Fri, 11 Apr 2014 05:59:19 +0000 (14:59 +0900)
Maru power supply device driver is added, but it is not built.
It will be fixed.

Change-Id: Ib4a10e9c4434d272c445f8551ef9cb74b89b963f
Signed-off-by: Jinhyung Choi <jinhyung2.choi@samsung.com>
arch/x86/configs/i386_tizen_emul_defconfig
drivers/maru/Kconfig
drivers/maru/Makefile
drivers/maru/maru_jack.c [new file with mode: 0644]
drivers/maru/maru_power_supply.c [new file with mode: 0644]
drivers/maru/maru_virtio_sensor.c
include/uapi/linux/virtio_ids.h

index a047a5a790567a70356859265e2ebef6c30e405c..bad8c9b283da13dea56abc30e950e289be3eca3c 100644 (file)
@@ -3085,6 +3085,8 @@ CONFIG_MARU_FB=y
 CONFIG_MARU_CAMERA=y
 CONFIG_MARU_BACKLIGHT=y
 CONFIG_MARU_OVERLAY=y
+CONFIG_MARU_JACK=y
+CONFIG_MARU_POWER_SUPPLY=y
 CONFIG_MARU_VIRTIO_EVDI=y
 CONFIG_MARU_VIRTIO_NFC=y
 CONFIG_MARU_VIRTIO_SENSOR=y
index d188ace60de0e18f3c6fd0bbf70c6a82132ed26b..4fd7b20a532ac38d5888845dd0abea420c9696c7 100644 (file)
@@ -26,17 +26,15 @@ config MARU_OVERLAY
        tristate "MARU overlay Driver"
        depends on MARU != n && VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
 
-config MARU_VIRTIO_EVDI
-       tristate "MARU VirtIO Emulator Virtual Device Interface Driver"
+config MARU_JACK
+       tristate "MARU Jack Driver"
        depends on MARU != n
 
-config MARU_VIRTIO_NFC
-       tristate "MARU VirtIO Virtual NFC Device Driver"
+config MARU_POWER_SUPPLY
+       tristate "MARU Power supply Driver"
        depends on MARU != n
 
-config MARU_VIRTIO_SENSOR
-       tristate "MARU VirtIO Emulator Sensor Device Driver"
-       depends on MARU != n
+
 
 config MARU_VIRTIO_HWKEY
        tristate "MARU Virtio HW Key Driver"
@@ -46,6 +44,18 @@ config MARU_VIRTIO_KEYBOARD
        tristate "MARU Virtio Keyboard Driver"
        depends on MARU != n
 
+config MARU_VIRTIO_EVDI
+       tristate "MARU VirtIO Emulator Virtual Device Interface Driver"
+       depends on MARU != n
+
+config MARU_VIRTIO_SENSOR
+       tristate "MARU VirtIO Virtual Sensor Device Driver"
+       depends on MARU != n
+
+config MARU_VIRTIO_NFC
+       tristate "MARU VirtIO Virtual NFC Device Driver"
+       depends on MARU != n
+
 config MARU_BRILLCODEC
        tristate "MARU brillcodec driver"
        depends on MARU != n
index 1c4005dab86ba259da762512050a7df1a38bf2c0..df7ca774fc0fa7e9293bfef5575e52e3f12d0526 100644 (file)
@@ -4,6 +4,8 @@ obj-$(CONFIG_MARU_CAMERA) += maru_camera.o
 obj-$(CONFIG_MARU_BACKLIGHT) += maru_bl.o
 obj-$(CONFIG_MARU_OVERLAY) += maru_overlay.o
 obj-$(CONFIG_MARU_VIRTIO_HWKEY) += maru_virtio_hwkey.o
+obj-$(CONFIG_MARU_JACK) += maru_jack.o
+#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
diff --git a/drivers/maru/maru_jack.c b/drivers/maru/maru_jack.c
new file mode 100644 (file)
index 0000000..c20b845
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * Virtual device node
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * JinHyung Choi <jinhyung2.choi@samsung.com>
+ * SooYoung Ha <yoosah.ha@samsung.com>
+ * Sungmin Ha <sungmin82.ha@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/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <linux/virtio.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+
+#define __MAX_BUF_SIZE         1024
+
+struct msg_info {
+       char buf[__MAX_BUF_SIZE];
+
+       uint16_t type;
+       uint16_t req;
+};
+
+struct virtio_jack {
+       struct virtio_device* vdev;
+       struct virtqueue* vq;
+
+       struct msg_info msginfo;
+
+       struct scatterlist sg_vq[2];
+
+       int flags;
+       struct mutex lock;
+};
+
+enum jack_types {
+       jack_type_list = 0,
+       jack_type_charger,
+       jack_type_earjack,
+       jack_type_earkey,
+       jack_type_hdmi,
+       jack_type_usb,
+       jack_type_max
+};
+
+enum jack_capabilities {
+       jack_cap_charger = 0x01,
+       jack_cap_earjack = 0x02,
+       jack_cap_earkey  = 0x04,
+       jack_cap_hdmi    = 0x08,
+       jack_cap_usb     = 0x10
+};
+
+enum request_cmd {
+       request_get = 0,
+       request_set,
+       request_answer
+};
+
+struct jack_data {
+       int no;
+       char buffer[50];
+};
+
+struct virtio_jack *v_jack;
+
+static char jack_data [PAGE_SIZE];
+static int jack_capability = 0;
+
+static DECLARE_WAIT_QUEUE_HEAD(wq);
+
+static struct virtio_device_id id_table[] = { { VIRTIO_ID_JACK,
+               VIRTIO_DEV_ANY_ID }, { 0 }, };
+
+#define DEVICE_NAME    "jack"
+#define JACK_DEBUG
+
+#ifdef JACK_DEBUG
+#define DLOG(level, fmt, ...) \
+       printk(level "maru_%s: " fmt, DEVICE_NAME, ##__VA_ARGS__)
+#else
+// do nothing
+#define DLOG(level, fmt, ...)
+#endif
+
+static int jack_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 jack_vq_done(struct virtqueue *vq) {
+       unsigned int len;
+       struct msg_info* msg;
+
+       msg = (struct msg_info*) virtqueue_get_buf(v_jack->vq, &len);
+       if (msg == NULL) {
+               DLOG(KERN_ERR, "failed to virtqueue_get_buf");
+               return;
+       }
+
+       if (msg->req != request_answer || msg->buf == NULL) {
+               return;
+       }
+
+       DLOG(KERN_DEBUG, "msg buf: %s, req: %d, type: %d", msg->buf, msg->req, msg->type);
+
+       mutex_lock(&v_jack->lock);
+       strcpy(jack_data, msg->buf);
+       v_jack->flags ++;
+       DLOG(KERN_DEBUG, "flags : %d", v_jack->flags);
+       mutex_unlock(&v_jack->lock);
+
+       wake_up_interruptible(&wq);
+}
+
+static void set_jack_data(int type, const char* buf)
+{
+       int err = 0;
+
+       if (buf == NULL) {
+               DLOG(KERN_ERR, "set_jack buf is NULL.");
+               return;
+       }
+
+       if (v_jack == NULL) {
+               DLOG(KERN_ERR, "Invalid jack handle");
+               return;
+       }
+
+       mutex_lock(&v_jack->lock);
+       memset(jack_data, 0, PAGE_SIZE);
+       memset(&v_jack->msginfo, 0, sizeof(v_jack->msginfo));
+
+       strcpy(jack_data, buf);
+
+       v_jack->msginfo.req = request_set;
+       v_jack->msginfo.type = type;
+       strcpy(v_jack->msginfo.buf, buf);
+       mutex_unlock(&v_jack->lock);
+
+       DLOG(KERN_DEBUG, "set_jack_data type: %d, req: %d, buf: %s",
+                       v_jack->msginfo.type, v_jack->msginfo.req, v_jack->msginfo.buf);
+
+       err = virtqueue_add_outbuf(v_jack->vq, v_jack->sg_vq, 1, &v_jack->msginfo, GFP_ATOMIC);
+       if (err < 0) {
+               DLOG(KERN_ERR, "failed to add buffer to virtqueue (err = %d)", err);
+               return;
+       }
+
+       virtqueue_kick(v_jack->vq);
+}
+
+static void get_jack_data(int type)
+{
+       struct scatterlist *sgs[2];
+       int err = 0;
+
+       if (v_jack == NULL) {
+               DLOG(KERN_ERR, "Invalid jack handle");
+               return;
+       }
+
+       mutex_lock(&v_jack->lock);
+       memset(jack_data, 0, PAGE_SIZE);
+       memset(&v_jack->msginfo, 0, sizeof(v_jack->msginfo));
+
+       v_jack->msginfo.req = request_get;
+       v_jack->msginfo.type = type;
+
+       mutex_unlock(&v_jack->lock);
+
+       DLOG(KERN_DEBUG, "get_jack_data type: %d, req: %d",
+                       v_jack->msginfo.type, v_jack->msginfo.req);
+
+       sgs[0] = &v_jack->sg_vq[0];
+       sgs[1] = &v_jack->sg_vq[1];
+       err = virtqueue_add_sgs(v_jack->vq, sgs, 1, 1, &v_jack->msginfo, GFP_ATOMIC);
+       if (err < 0) {
+               DLOG(KERN_ERR, "failed to add buffer to virtqueue (err = %d)", err);
+               return;
+       }
+
+       virtqueue_kick(v_jack->vq);
+
+       wait_event_interruptible(wq, v_jack->flags != 0);
+
+       mutex_lock(&v_jack->lock);
+       v_jack->flags --;
+       DLOG(KERN_DEBUG, "flags : %d", v_jack->flags);
+       mutex_unlock(&v_jack->lock);
+}
+
+static ssize_t show_charger_online(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       get_jack_data(jack_type_charger);
+       return snprintf(buf, PAGE_SIZE, "%s", jack_data);
+}
+
+static ssize_t store_charger_online(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       set_jack_data(jack_type_charger, buf);
+       return strnlen(buf, PAGE_SIZE);
+}
+
+static ssize_t show_earjack_online(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       get_jack_data(jack_type_earjack);
+       return snprintf(buf, PAGE_SIZE, "%s", jack_data);
+}
+
+static ssize_t store_earjack_online(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       set_jack_data(jack_type_earjack, buf);
+       return strnlen(buf, PAGE_SIZE);
+}
+
+static ssize_t show_earkey_online(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       get_jack_data(jack_type_earkey);
+       return snprintf(buf, PAGE_SIZE, "%s", jack_data);
+}
+
+static ssize_t store_earkey_online(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       set_jack_data(jack_type_earkey, buf);
+       return strnlen(buf, PAGE_SIZE);
+}
+
+static ssize_t show_hdmi_online(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       get_jack_data(jack_type_hdmi);
+       return snprintf(buf, PAGE_SIZE, "%s", jack_data);
+}
+
+static ssize_t store_hdmi_online(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       set_jack_data(jack_type_hdmi, buf);
+       return strnlen(buf, PAGE_SIZE);
+}
+
+static ssize_t show_usb_online(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       get_jack_data(jack_type_usb);
+       return snprintf(buf, PAGE_SIZE, "%s", jack_data);
+}
+
+static ssize_t store_usb_online(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       set_jack_data(jack_type_usb, buf);
+       return strnlen(buf, PAGE_SIZE);
+}
+
+static DEVICE_ATTR(charger_online, S_IRUGO | S_IWUSR, show_charger_online, store_charger_online);
+static DEVICE_ATTR(earjack_online, S_IRUGO | S_IWUSR, show_earjack_online, store_earjack_online);
+static DEVICE_ATTR(earkey_online, S_IRUGO | S_IWUSR, show_earkey_online, store_earkey_online);
+static DEVICE_ATTR(hdmi_online, S_IRUGO | S_IWUSR, show_hdmi_online, store_hdmi_online);
+static DEVICE_ATTR(usb_online, S_IRUGO | S_IWUSR, show_usb_online, store_usb_online);
+
+static int maru_jack_sysfs_create_file(struct device *dev)
+{
+       int result = 0;
+
+       DLOG(KERN_INFO, "sysfs_create_file\n");
+
+       if (jack_capability & jack_cap_charger) {
+               result = device_create_file(dev, &dev_attr_charger_online);
+               if (result){
+                       DLOG(KERN_ERR, "failed to create charger_online file\n");
+                       return result;
+               }
+       }
+
+       if (jack_capability & jack_cap_earjack) {
+               result = device_create_file(dev, &dev_attr_earjack_online);
+               if (result){
+                       DLOG(KERN_ERR, "failed to create earjack_online file\n");
+                       return result;
+               }
+       }
+
+       if (jack_capability & jack_cap_earkey) {
+               result = device_create_file(dev, &dev_attr_earkey_online);
+               if (result){
+                       DLOG(KERN_ERR, "failed to create earkey_online file\n");
+                       return result;
+               }
+       }
+
+       if (jack_capability & jack_cap_hdmi) {
+               result = device_create_file(dev, &dev_attr_hdmi_online);
+               if (result){
+                       DLOG(KERN_ERR, "failed to create hdmi_online file\n");
+                       return result;
+               }
+       }
+
+       if (jack_capability & jack_cap_usb) {
+               result = device_create_file(dev, &dev_attr_usb_online);
+               if (result){
+                       DLOG(KERN_ERR, "failed to create usb_online file\n");
+                       return result;
+               }
+       }
+
+       return 0;
+}
+
+
+static void maru_jack_sysfs_remove_file(struct device *dev)
+{
+       DLOG(KERN_INFO, "sysfs_remove_file\n");
+
+       device_remove_file(dev, &dev_attr_charger_online);
+       device_remove_file(dev, &dev_attr_earjack_online);
+       device_remove_file(dev, &dev_attr_earkey_online);
+       device_remove_file(dev, &dev_attr_hdmi_online);
+       device_remove_file(dev, &dev_attr_usb_online);
+}
+
+static void maru_jack_sysfs_dev_release(struct device *dev)
+{
+       DLOG(KERN_INFO, "sysfs_dev_release\n");
+}
+
+static struct platform_device the_pdev = {
+       .name = DEVICE_NAME,
+       .id = -1,
+       .dev = {
+               .release = maru_jack_sysfs_dev_release,
+       }
+};
+
+static int jack_probe(struct virtio_device* dev){
+       int err = 0, index = 0;
+       struct jack_data *data;
+
+       DLOG(KERN_INFO, "jack_probe\n");
+
+       v_jack = kmalloc(sizeof(struct virtio_jack), GFP_KERNEL);
+
+       v_jack->vdev = dev;
+       dev->priv = v_jack;
+       v_jack->flags = 0;
+
+       err = platform_device_register(&the_pdev);
+       if (err) {
+               DLOG(KERN_ERR, "platform_device_register failure\n");
+               return err;
+       }
+
+       data = kzalloc(sizeof(struct jack_data), GFP_KERNEL);
+       if (!data) {
+               DLOG(KERN_ERR, "kzalloc failure\n");
+               platform_device_unregister(&the_pdev);
+               return -ENOMEM;
+       }
+
+       dev_set_drvdata(&the_pdev.dev, (void*)data);
+
+       v_jack->vq = virtio_find_single_vq(dev, jack_vq_done, "jack");
+       if (IS_ERR(v_jack->vq)) {
+               DLOG(KERN_ERR, "virtio queue is not found.\n");
+               kfree(data);
+               platform_device_unregister(&the_pdev);
+               return err;
+       }
+
+       virtqueue_enable_cb(v_jack->vq);
+
+       memset(&v_jack->msginfo, 0x00, sizeof(v_jack->msginfo));
+
+       sg_init_table(v_jack->sg_vq, 2);
+       for (; index < 2; index++) {
+               sg_set_buf(&v_jack->sg_vq[index], &v_jack->msginfo, sizeof(v_jack->msginfo));
+       }
+
+       mutex_init(&v_jack->lock);
+
+       DLOG(KERN_INFO, "request jack capability");
+
+       get_jack_data(jack_type_list);
+       jack_capability = jack_atoi(jack_data);
+       DLOG(KERN_INFO, "jack capability is %02x", jack_capability);
+
+       err = maru_jack_sysfs_create_file(&the_pdev.dev);
+       if (err) {
+               DLOG(KERN_ERR, "sysfs_create_file failure\n");
+               kfree(data);
+               platform_device_unregister(&the_pdev);
+               return err;
+       }
+
+       return 0;
+}
+
+static void jack_remove(struct virtio_device* dev){
+       void *data = dev_get_drvdata(&the_pdev.dev);
+
+       DLOG(KERN_INFO, "sysfs_exit\n");
+
+       if (data) {
+               kfree(data);
+       }
+       maru_jack_sysfs_remove_file(&the_pdev.dev);
+       platform_device_unregister(&the_pdev);
+
+       if (v_jack) {
+               kfree(v_jack);
+               v_jack = NULL;
+       }
+}
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+
+static struct virtio_driver virtio_jack_driver = {
+               .driver = {
+                               .name = KBUILD_MODNAME,
+                               .owner = THIS_MODULE ,
+               },
+               .id_table = id_table,
+               .probe = jack_probe,
+               .remove = jack_remove,
+};
+
+static int __init maru_jack_init(void)
+{
+       DLOG(KERN_INFO, "maru_%s: init\n", DEVICE_NAME);
+       return register_virtio_driver(&virtio_jack_driver);
+}
+
+static void __exit maru_jack_exit(void)
+{
+       DLOG(KERN_INFO, "maru_%s: exit\n", DEVICE_NAME);
+       unregister_virtio_driver(&virtio_jack_driver);
+}
+
+module_init(maru_jack_init);
+module_exit(maru_jack_exit);
+
+MODULE_LICENSE("GPL2");
+MODULE_AUTHOR("Jinhyung Choi <jinhyung2.choi@samsung.com>");
+MODULE_DESCRIPTION("Emulator Virtio Power Driver");
diff --git a/drivers/maru/maru_power_supply.c b/drivers/maru/maru_power_supply.c
new file mode 100644 (file)
index 0000000..414d614
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * Virtual device node
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * JinHyung Choi <jinhyung2.choi@samsung.com>
+ * SooYoung Ha <yoosah.ha@samsung.com>
+ * Sungmin Ha <sungmin82.ha@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/device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <linux/virtio.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+
+
+#define DEVICE_NAME                            "power_supply"
+#define FILE_PERMISSION                        (S_IRUGO | S_IWUSR)
+
+//#define DEBUG_MARU_POWER_SUPPLY
+
+#ifdef DEBUG_MARU_POWER_SUPPLY
+#define DLOG(level, fmt, ...) \
+       printk(level "maru_%s: " fmt, DEVICE_NAME, ##__VA_ARGS__)
+#else
+// do nothing
+#define DLOG(level, fmt, ...)
+#endif
+
+#define __MAX_BUF_SIZE         1024
+
+static struct virtio_device_id id_table[] = { { VIRTIO_ID_POWER,
+               VIRTIO_DEV_ANY_ID }, { 0 }, };
+
+struct msg_info {
+       char buf[__MAX_BUF_SIZE];
+
+       uint16_t type;
+       uint16_t req;
+};
+
+struct virtio_power {
+       struct virtio_device* vdev;
+       struct virtqueue* vq;
+
+       struct msg_info msginfo;
+
+       struct scatterlist sg_vq[2];
+
+       int flags;
+       struct mutex lock;
+};
+
+enum power_types {
+       power_type_capacity = 0,
+       power_type_charge_full,
+       power_type_charge_now,
+       power_type_max
+};
+
+enum request_cmd {
+       request_get = 0,
+       request_set,
+       request_answer
+};
+
+struct virtio_power *v_power;
+
+static struct class* power_class;
+static struct device* power_device;
+
+static char power_data [PAGE_SIZE];
+
+static DECLARE_WAIT_QUEUE_HEAD(wq);
+
+static void power_vq_done(struct virtqueue *vq) {
+       unsigned int len;
+       struct msg_info* msg;
+
+       msg = (struct msg_info*) virtqueue_get_buf(v_power->vq, &len);
+       if (msg == NULL) {
+               DLOG(KERN_ERR, "failed to virtqueue_get_buf");
+               return;
+       }
+
+       if (msg->req != request_answer || msg->buf == NULL) {
+               return;
+       }
+
+       DLOG(KERN_DEBUG, "msg buf: %s, req: %d, type: %d", msg->buf, msg->req, msg->type);
+
+       mutex_lock(&v_power->lock);
+       strcpy(power_data, msg->buf);
+       v_power->flags ++;
+       DLOG(KERN_DEBUG, "flags : %d", v_power->flags);
+       mutex_unlock(&v_power->lock);
+
+       wake_up_interruptible(&wq);
+}
+
+static void set_power_data(int type, const char* buf)
+{
+       int err = 0;
+
+       if (buf == NULL) {
+               DLOG(KERN_ERR, "set_power buf is NULL.");
+               return;
+       }
+
+       if (v_power == NULL) {
+               DLOG(KERN_ERR, "Invalid power handle");
+               return;
+       }
+
+       mutex_lock(&v_power->lock);
+       memset(power_data, 0, PAGE_SIZE);
+       memset(&v_power->msginfo, 0, sizeof(v_power->msginfo));
+
+       strcpy(power_data, buf);
+
+       v_power->msginfo.req = request_set;
+       v_power->msginfo.type = type;
+       strcpy(v_power->msginfo.buf, buf);
+       mutex_unlock(&v_power->lock);
+
+       DLOG(KERN_DEBUG, "set_power_data type: %d, req: %d, buf: %s",
+                       v_power->msginfo.type, v_power->msginfo.req, v_power->msginfo.buf);
+
+       err = virtqueue_add_outbuf(v_power->vq, v_power->sg_vq, 1, &v_power->msginfo, GFP_ATOMIC);
+       if (err < 0) {
+               DLOG(KERN_ERR, "failed to add buffer to virtqueue (err = %d)", err);
+               return;
+       }
+
+       virtqueue_kick(v_power->vq);
+}
+
+static void get_power_data(int type)
+{
+       struct scatterlist *sgs[2];
+       int err = 0;
+
+       if (v_power == NULL) {
+               DLOG(KERN_ERR, "Invalid power handle");
+               return;
+       }
+
+       mutex_lock(&v_power->lock);
+       memset(power_data, 0, PAGE_SIZE);
+       memset(&v_power->msginfo, 0, sizeof(v_power->msginfo));
+
+       v_power->msginfo.req = request_get;
+       v_power->msginfo.type = type;
+
+       mutex_unlock(&v_power->lock);
+
+       DLOG(KERN_DEBUG, "get_power_data type: %d, req: %d",
+                       v_power->msginfo.type, v_power->msginfo.req);
+
+       sgs[0] = &v_power->sg_vq[0];
+       sgs[1] = &v_power->sg_vq[1];
+       err = virtqueue_add_sgs(v_power->vq, sgs, 1, 1, &v_power->msginfo, GFP_ATOMIC);
+       if (err < 0) {
+               DLOG(KERN_ERR, "failed to add buffer to virtqueue (err = %d)", err);
+               return;
+       }
+
+       virtqueue_kick(v_power->vq);
+
+       wait_event_interruptible(wq, v_power->flags != 0);
+
+       mutex_lock(&v_power->lock);
+       v_power->flags --;
+       DLOG(KERN_DEBUG, "flags : %d", v_power->flags);
+       mutex_unlock(&v_power->lock);
+}
+
+static ssize_t show_capacity(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       get_power_data(power_type_capacity);
+       return snprintf(buf, PAGE_SIZE, "%s", power_data);
+}
+
+static ssize_t store_capacity(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       set_power_data(power_type_capacity, buf);
+       return strnlen(buf, PAGE_SIZE);
+}
+
+static ssize_t show_charge_full(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       get_power_data(power_type_charge_full);
+       return snprintf(buf, PAGE_SIZE, "%s", power_data);
+}
+
+static ssize_t store_charge_full(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       set_power_data(power_type_charge_full, buf);
+       return strnlen(buf, PAGE_SIZE);
+}
+
+static ssize_t show_charge_now(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       get_power_data(power_type_charge_now);
+       return snprintf(buf, PAGE_SIZE, "%s", power_data);
+}
+
+static ssize_t store_charge_now(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       set_power_data(power_type_charge_now, buf);
+       return strnlen(buf, PAGE_SIZE);
+}
+
+static struct device_attribute ps_device_attributes[] = {
+       __ATTR(capacity, FILE_PERMISSION, show_capacity, store_capacity),
+       __ATTR(charge_full, FILE_PERMISSION, show_charge_full, store_charge_full),
+       __ATTR(charge_now, FILE_PERMISSION, show_charge_now, store_charge_now),
+};
+
+static void class_cleanup (void)
+{
+       int i = 2;
+
+       for (; i > 0; i--) {
+
+               if (power_device == NULL)
+                       continue;
+
+               device_remove_file(power_device, &ps_device_attributes[i]);
+
+               device_unregister(power_device);
+
+               device_destroy(power_class, (dev_t)NULL);
+       }
+
+       class_destroy(power_class);
+       power_class = NULL;
+}
+
+static int init_device(void)
+{
+       int err = 0, i = 0;
+       power_device = device_create(power_class, NULL, (dev_t)NULL, NULL, "battery");
+
+       for (i = 0; i < 3; i++) {
+               err = device_create_file(power_device, &ps_device_attributes[i]);
+               if (err) {
+                       printk(KERN_ERR
+                               "maru_%s: failed to create power_supply files\n", DEVICE_NAME);
+                       goto device_err;
+               }
+       }
+
+       return err;
+device_err:
+       class_cleanup();
+       return -1;
+}
+
+static void cleanup(struct virtio_device* dev) {
+       dev->config->del_vqs(dev);
+
+       if (v_power) {
+               kfree(v_power);
+               v_power = NULL;
+       }
+
+       class_cleanup();
+}
+
+static int power_probe(struct virtio_device* dev)
+{
+       int err = 0;
+       int ret = 0;
+       int index = 0;
+
+       DLOG(KERN_INFO, "Power probe starts");
+
+       v_power = kmalloc(sizeof(struct virtio_power), GFP_KERNEL);
+
+       v_power->vdev = dev;
+       dev->priv = v_power;
+       v_power->flags = 0;
+
+       power_class = class_create(THIS_MODULE, DEVICE_NAME);
+       if (power_class == NULL) {
+               DLOG(KERN_ERR, "Power class creation is failed.");
+               return -1;
+       }
+
+       ret = init_device();
+       if (ret) {
+               cleanup(dev);
+               return ret;
+       }
+
+       v_power->vq = virtio_find_single_vq(dev, power_vq_done, "power");
+       if (IS_ERR(v_power->vq)) {
+               cleanup(dev);
+               DLOG(KERN_ERR, "failed to init virt queue");
+               return ret;
+       }
+
+       virtqueue_enable_cb(v_power->vq);
+
+       memset(&v_power->msginfo, 0x00, sizeof(v_power->msginfo));
+
+       sg_init_table(v_power->sg_vq, 2);
+       for (; index < 2; index++) {
+               sg_set_buf(&v_power->sg_vq[index], &v_power->msginfo, sizeof(v_power->msginfo));
+       }
+
+       mutex_init(&v_power->lock);
+
+       DLOG(KERN_INFO, "Power probe completes");
+
+       return err;
+}
+
+static void power_remove(struct virtio_device* dev)
+{
+       struct virtio_power* v_power = dev->priv;
+       if (!v_power)
+       {
+               DLOG(KERN_ERR, "virtio_power is NULL");
+               return;
+       }
+
+       dev->config->reset(dev);
+
+       cleanup(dev);
+
+       DLOG(KERN_INFO, "Power driver is removed.");
+}
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+
+static struct virtio_driver virtio_power_driver = {
+               .driver = {
+                               .name = KBUILD_MODNAME,
+                               .owner = THIS_MODULE ,
+               },
+               .id_table = id_table,
+               .probe = power_probe,
+               .remove = power_remove,
+};
+
+static int __init maru_power_supply_init(void)
+{
+       DLOG(KERN_INFO, "maru_%s: init\n", DEVICE_NAME);
+       return register_virtio_driver(&virtio_power_driver);
+}
+
+static void __exit maru_power_supply_exit(void)
+{
+       DLOG(KERN_INFO, "maru_%s: exit\n", DEVICE_NAME);
+       unregister_virtio_driver(&virtio_power_driver);
+}
+
+module_init(maru_power_supply_init);
+module_exit(maru_power_supply_exit);
+
+MODULE_LICENSE("GPL2");
+MODULE_AUTHOR("Jinhyung Choi <jinhyung2.choi@samsung.com>");
+MODULE_DESCRIPTION("Emulator Virtio Power Driver");
index 1c6b330f1820135787a244ea15fb47d5fc4590a9..c7d9eaa899fc1d3f95490cd3451d4697509d85b0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Maru Virtio Sensor Device Driver
  *
- * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * Contact:
  *  Jinhyung Choi <jinhyung2.choi@samsung.com>
@@ -37,6 +37,8 @@
 #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 DEVICE_COUNT           5
 
 enum sensor_types {
-       sensor_type_accel = 0,
+       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,
@@ -82,14 +106,14 @@ struct msg_info {
 
 struct virtio_sensor {
        struct virtio_device* vdev;
-       struct virtqueue* rvq;
-       struct virtqueue* svq;
+       struct virtqueue* vq;
+
+       struct msg_info msginfo;
 
-       struct msg_info read_msginfo;
-       struct msg_info send_msginfo;
+       struct scatterlist sg_vq[2];
 
-       struct scatterlist sg_read[2];
-       struct scatterlist sg_send[2];
+       int flags;
+       struct mutex lock;
 };
 
 static struct virtio_device_id id_table[] = { { VIRTIO_ID_SENSOR,
@@ -99,6 +123,8 @@ 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,                                        \
@@ -110,14 +136,131 @@ static struct class* sensor_class;
        .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 char accel_xyz [__MAX_BUF_SENSOR] = {'0',',','9','8','0','6','6','5',',','0'};
-
 static ssize_t accel_name_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        return snprintf(buf, PAGE_SIZE, ACCEL_NAME_STR);
@@ -125,12 +268,13 @@ static ssize_t accel_name_show(struct device *dev, struct device_attribute *attr
 
 static ssize_t xyz_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%s", accel_xyz);
+       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)
 {
-       strcpy(accel_xyz, buf);
+       set_sensor_data(sensor_type_accel, buf);
        return strnlen(buf, PAGE_SIZE);
 }
 
@@ -146,9 +290,6 @@ static struct device_attribute da_accel [] =
 #define GEO_NAME_STR           "geo_sim"
 #define GEO_FILE_NUM           3
 
-static char geo_raw [__MAX_BUF_SENSOR] = {'0',' ','-','9','0',' ','0',' ','3'};
-static char geo_tesla [__MAX_BUF_SENSOR] = {'1',' ','0',' ','-','1','0'};
-
 static ssize_t geo_name_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        return snprintf(buf, PAGE_SIZE, GEO_NAME_STR);
@@ -156,23 +297,25 @@ static ssize_t geo_name_show(struct device *dev, struct device_attribute *attr,
 
 static ssize_t raw_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%s", geo_raw);
+       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)
 {
-       strcpy(geo_raw, buf);
+       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)
 {
-       return snprintf(buf, PAGE_SIZE, "%s", geo_tesla);
+       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)
 {
-       strcpy(geo_tesla, buf);
+       set_sensor_data(sensor_type_mag, buf);
        return strnlen(buf, PAGE_SIZE);
 }
 
@@ -191,10 +334,6 @@ static struct device_attribute da_geo [] =
 #define GYRO_NAME_STR          "gyro_sim"
 #define GYRO_FILE_NUM          4
 
-static int gyro_x_raw = 0;
-static int gyro_y_raw = 0;
-static int gyro_z_raw = 0;
-
 static ssize_t gyro_name_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        return snprintf(buf, PAGE_SIZE, GYRO_NAME_STR);
@@ -202,34 +341,37 @@ static ssize_t gyro_name_show(struct device *dev, struct device_attribute *attr,
 
 static ssize_t gyro_x_raw_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%d", gyro_x_raw);
+       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)
 {
-       sscanf(buf, "%d", &gyro_x_raw);
+       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)
 {
-       return snprintf(buf, PAGE_SIZE, "%d", gyro_y_raw);
+       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)
 {
-       sscanf(buf, "%d", &gyro_y_raw);
+       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)
 {
-       return snprintf(buf, PAGE_SIZE, "%d", gyro_z_raw);
+       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)
 {
-       sscanf(buf, "%d", &gyro_z_raw);
+       set_sensor_data(sensor_type_gyro_z, buf);
        return strnlen(buf, PAGE_SIZE);
 }
 
@@ -248,9 +390,6 @@ static struct device_attribute da_gyro [] =
 #define LIGHT_NAME_STR         "light_sim"
 #define LIGHT_FILE_NUM         3
 
-static int light_adc = 65535;
-static int light_level = 10;
-
 static ssize_t light_name_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        return snprintf(buf, PAGE_SIZE, LIGHT_NAME_STR);
@@ -258,23 +397,25 @@ static ssize_t light_name_show(struct device *dev, struct device_attribute *attr
 
 static ssize_t adc_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%d", light_adc);
+       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)
 {
-       sscanf(buf, "%d", &light_adc);
+       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)
 {
-       return snprintf(buf, PAGE_SIZE, "%d", light_level);
+       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)
 {
-       sscanf(buf, "%d", &light_level);
+       set_sensor_data(sensor_type_light_level, buf);
        return strnlen(buf, PAGE_SIZE);
 }
 
@@ -294,7 +435,6 @@ static struct device_attribute da_light [] =
 #define PROXI_FILE_NUM         3
 
 static int proxi_enable = 1;
-static int proxi_vo = 8;
 
 static ssize_t proxi_name_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -314,12 +454,13 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr, c
 
 static ssize_t vo_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%d", proxi_vo);
+       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)
 {
-       sscanf(buf, "%d", &proxi_vo);
+       set_sensor_data(sensor_type_proxi, buf);
        return strnlen(buf, PAGE_SIZE);
 }
 
@@ -370,7 +511,17 @@ static int init_device(void)
        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);
@@ -392,155 +543,6 @@ device_err:
        return -1;
 }
 
-static int _make_buf_and_kick(void)
-{
-       int ret;
-       memset(&vs->read_msginfo, 0x00, sizeof(vs->read_msginfo));
-       ret = virtqueue_add_inbuf(vs->rvq, vs->sg_read, 1, &vs->read_msginfo, GFP_ATOMIC );
-       if (ret < 0) {
-               LOG(KERN_ERR, "failed to add buffer to virtqueue.(%d)\n", ret);
-               return ret;
-       }
-
-       virtqueue_kick(vs->rvq);
-
-       return 0;
-}
-
-static void get_sensor_value(int type)
-{
-       int err = 0;
-
-       if (vs == NULL) {
-               LOG(KERN_ERR, "Invalid sensor handle");
-               return;
-       }
-
-       memset(&vs->send_msginfo, 0, sizeof(vs->send_msginfo));
-
-       vs->send_msginfo.req = request_answer;
-
-       switch (type) {
-               case sensor_type_accel:
-                       vs->send_msginfo.type = sensor_type_accel;
-                       strcpy(vs->send_msginfo.buf, accel_xyz);
-                       break;
-               case sensor_type_mag:
-                       vs->send_msginfo.type = sensor_type_mag;
-                       strcpy(vs->send_msginfo.buf, geo_tesla);
-                       break;
-               case sensor_type_gyro:
-                       vs->send_msginfo.type = sensor_type_gyro;
-                       sprintf(vs->send_msginfo.buf, "%d, %d, %d", gyro_x_raw, gyro_y_raw, gyro_z_raw);
-                       break;
-               case sensor_type_light:
-                       vs->send_msginfo.type = sensor_type_light;
-                       sprintf(vs->send_msginfo.buf, "%d", light_adc);
-                       break;
-               case sensor_type_proxi:
-                       vs->send_msginfo.type = sensor_type_proxi;
-                       sprintf(vs->send_msginfo.buf, "%d", proxi_vo);
-                       break;
-               default:
-                       return;
-       }
-
-       LOG(KERN_INFO, "vs->send_msginfo type: %d, req: %d, buf: %s",
-                       vs->send_msginfo.type, vs->send_msginfo.req, vs->send_msginfo.buf);
-
-       err = virtqueue_add_outbuf(vs->svq, vs->sg_send, 1, &vs->send_msginfo, GFP_ATOMIC);
-       if (err < 0) {
-               LOG(KERN_ERR, "failed to add buffer to virtqueue (err = %d)", err);
-               return;
-       }
-
-       virtqueue_kick(vs->svq);
-}
-
-static void set_sensor_value(char* buf, int type)
-{
-
-       LOG(KERN_INFO, "set_sensor_value- type: %d, buf: %s", type, buf);
-
-       switch (type) {
-               case sensor_type_accel:
-                       strcpy(accel_xyz, buf);
-                       break;
-               case sensor_type_gyro:
-                       sscanf(buf, "%d %d %d", &gyro_x_raw, &gyro_y_raw, &gyro_z_raw);
-                       break;
-               case sensor_type_light:
-                       sscanf(buf, "%d", &light_adc);
-                       light_level = (light_adc / 6554) % 10 + 1;
-                       break;
-               case sensor_type_proxi:
-                       sscanf(buf, "%d", &proxi_vo);
-                       break;
-               case sensor_type_mag:
-                       strcpy(geo_tesla, buf);
-                       break;
-               case sensor_type_tilt:
-                       strcpy(geo_raw, buf);
-                       break;
-               default:
-                       return;
-       }
-
-}
-
-static void message_handler(char* buf, int req, int type)
-{
-       if (req == request_get) {
-               get_sensor_value(type);
-       } else if (req == request_set) {
-               set_sensor_value(buf, type);
-       } else {
-               LOG(KERN_INFO, "wrong message request");
-       }
-}
-
-static void sensor_recv_done(struct virtqueue *rvq) {
-       unsigned int len;
-       struct msg_info* msg;
-
-       msg = (struct msg_info*) virtqueue_get_buf(vs->rvq, &len);
-       if (msg == NULL ) {
-               LOG(KERN_ERR, "failed to virtqueue_get_buf");
-               return;
-       }
-
-       LOG(KERN_INFO, "msg buf: %s, req: %d, type: %d", msg->buf, msg->req, msg->type);
-
-       message_handler(msg->buf, msg->req, msg->type);
-
-       _make_buf_and_kick();
-}
-
-static void sensor_send_done(struct virtqueue *svq) {
-       unsigned int len = 0;
-
-       virtqueue_get_buf(svq, &len);
-}
-
-static int init_vqs(struct virtio_sensor *vsensor) {
-       struct virtqueue *vqs[2];
-       vq_callback_t *vq_callbacks[] = { sensor_recv_done, sensor_send_done };
-       const char *vq_names[] = { "sensor_input", "sensor_output" };
-       int err;
-
-       err = vs->vdev->config->find_vqs(vs->vdev, 2, vqs, vq_callbacks, vq_names);
-       if (err < 0)
-               return err;
-
-       vs->rvq = vqs[0];
-       vs->svq = vqs[1];
-
-       virtqueue_enable_cb(vs->rvq);
-       virtqueue_enable_cb(vs->svq);
-
-       return 0;
-}
-
 static void cleanup(struct virtio_device* dev) {
        dev->config->del_vqs(dev);
 
@@ -556,6 +558,7 @@ static int sensor_probe(struct virtio_device* dev)
 {
        int err = 0;
        int ret = 0;
+       int index = 0;
 
        LOG(KERN_INFO, "Sensor probe starts");
 
@@ -570,37 +573,37 @@ static int sensor_probe(struct virtio_device* dev)
                return -1;
        }
 
-       ret = init_device();
-       if (ret) {
+       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;
        }
 
-       ret = init_vqs(vs);
-       if (ret) {
-               cleanup(dev);
-               LOG(KERN_ERR, "failed to init vqs");
-               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));
        }
 
-       memset(&vs->read_msginfo, 0x00, sizeof(vs->read_msginfo));
-       sg_set_buf(vs->sg_read, &vs->read_msginfo, sizeof(struct msg_info));
+       mutex_init(&vs->lock);
 
-       memset(&vs->send_msginfo, 0x00, sizeof(vs->send_msginfo));
-       sg_set_buf(vs->sg_send, &vs->send_msginfo, sizeof(struct msg_info));
+       LOG(KERN_INFO, "Sensor probe completes");
 
-       sg_init_one(vs->sg_read, &vs->read_msginfo, sizeof(vs->read_msginfo));
-       sg_init_one(vs->sg_send, &vs->send_msginfo, sizeof(vs->send_msginfo));
+       get_sensor_data(sensor_type_list);
+       sensor_capability = sensor_atoi(sensor_data);
+       LOG(KERN_INFO, "sensor capability is %02x", sensor_capability);
 
-       ret = _make_buf_and_kick();
+       ret = init_device();
        if (ret) {
+               LOG(KERN_ERR, "failed initialing devices");
                cleanup(dev);
-               LOG(KERN_ERR, "failed to send buf");
                return ret;
        }
 
-       LOG(KERN_INFO, "Sensor probe completes");
-
        return err;
 }
 
index 62a1f323892106d8a20d143ee07b7c031dddc045..2f2d83c7bb91ef67e94e80ec4edbf3d9be2d0bbb 100755 (executable)
@@ -50,6 +50,8 @@
 #define VIRTIO_ID_GL                   36 /* virtio glmem */
 #define VIRTIO_ID_SENSOR               37 /* virtio sensor */
 #define VIRTIO_ID_NFC                  38 /* virtio nfc */
+#define VIRTIO_ID_JACK                 39 /* virtio jack */
+#define VIRTIO_ID_POWER                        40 /* virtio power supply */
 #endif
 
 #endif /* _LINUX_VIRTIO_IDS_H */