From: Jinhyung Choi Date: Wed, 9 Apr 2014 07:47:59 +0000 (+0900) Subject: driver: added sensor and jack driver X-Git-Tag: submit/tizen_common/20140905.094502~113 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F41%2F19241%2F4;p=sdk%2Femulator%2Femulator-kernel.git driver: added sensor and jack driver Maru power supply device driver is added, but it is not built. It will be fixed. Change-Id: Ib4a10e9c4434d272c445f8551ef9cb74b89b963f Signed-off-by: Jinhyung Choi --- diff --git a/arch/x86/configs/i386_tizen_emul_defconfig b/arch/x86/configs/i386_tizen_emul_defconfig index a047a5a79056..bad8c9b283da 100644 --- a/arch/x86/configs/i386_tizen_emul_defconfig +++ b/arch/x86/configs/i386_tizen_emul_defconfig @@ -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 diff --git a/drivers/maru/Kconfig b/drivers/maru/Kconfig index d188ace60de0..4fd7b20a532a 100644 --- a/drivers/maru/Kconfig +++ b/drivers/maru/Kconfig @@ -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 diff --git a/drivers/maru/Makefile b/drivers/maru/Makefile index 1c4005dab86b..df7ca774fc0f 100644 --- a/drivers/maru/Makefile +++ b/drivers/maru/Makefile @@ -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 index 000000000000..c20b845f4271 --- /dev/null +++ b/drivers/maru/maru_jack.c @@ -0,0 +1,493 @@ +/* + * Virtual device node + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * JinHyung Choi + * SooYoung Ha + * Sungmin Ha + * YeongKyoon Lee +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 "); +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 index 000000000000..414d614412f4 --- /dev/null +++ b/drivers/maru/maru_power_supply.c @@ -0,0 +1,395 @@ +/* + * Virtual device node + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: + * JinHyung Choi + * SooYoung Ha + * Sungmin Ha + * YeongKyoon Lee +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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 "); +MODULE_DESCRIPTION("Emulator Virtio Power Driver"); diff --git a/drivers/maru/maru_virtio_sensor.c b/drivers/maru/maru_virtio_sensor.c index 1c6b330f1820..c7d9eaa899fc 100644 --- a/drivers/maru/maru_virtio_sensor.c +++ b/drivers/maru/maru_virtio_sensor.c @@ -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 @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include @@ -57,16 +59,38 @@ #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; } diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h index 62a1f3238921..2f2d83c7bb91 100755 --- a/include/uapi/linux/virtio_ids.h +++ b/include/uapi/linux/virtio_ids.h @@ -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 */