From: Tim Sell <Timothy.Sell@xxxxxxxxxx> This visorhid driver provides a Human Interface Device, but is not at all using HID, the protocol. It's a plain input driver, so for clarity, it is being renamed to visorinput. Signed-off-by: Tim Sell <Timothy.Sell@xxxxxxxxxx> Signed-off-by: Benjamin Romer <benjamin.romer@xxxxxxxxxx> --- drivers/staging/unisys/Documentation/overview.txt | 22 +- drivers/staging/unisys/Kconfig | 2 +- drivers/staging/unisys/Makefile | 2 +- drivers/staging/unisys/visorhid/Kconfig | 10 - drivers/staging/unisys/visorhid/Makefile | 7 - drivers/staging/unisys/visorhid/keyboardchannel.h | 32 - drivers/staging/unisys/visorhid/mousechannel.h | 33 - drivers/staging/unisys/visorhid/ultrainputreport.h | 74 --- drivers/staging/unisys/visorhid/visorhid.c | 671 --------------------- drivers/staging/unisys/visorinput/Kconfig | 10 + drivers/staging/unisys/visorinput/Makefile | 7 + .../staging/unisys/visorinput/keyboardchannel.h | 32 + drivers/staging/unisys/visorinput/mousechannel.h | 33 + .../staging/unisys/visorinput/ultrainputreport.h | 74 +++ drivers/staging/unisys/visorinput/visorinput.c | 671 +++++++++++++++++++++ 15 files changed, 840 insertions(+), 840 deletions(-) delete mode 100644 drivers/staging/unisys/visorhid/Kconfig delete mode 100644 drivers/staging/unisys/visorhid/Makefile delete mode 100644 drivers/staging/unisys/visorhid/keyboardchannel.h delete mode 100644 drivers/staging/unisys/visorhid/mousechannel.h delete mode 100644 drivers/staging/unisys/visorhid/ultrainputreport.h delete mode 100644 drivers/staging/unisys/visorhid/visorhid.c create mode 100644 drivers/staging/unisys/visorinput/Kconfig create mode 100644 drivers/staging/unisys/visorinput/Makefile create mode 100644 drivers/staging/unisys/visorinput/keyboardchannel.h create mode 100644 drivers/staging/unisys/visorinput/mousechannel.h create mode 100644 drivers/staging/unisys/visorinput/ultrainputreport.h create mode 100644 drivers/staging/unisys/visorinput/visorinput.c diff --git a/drivers/staging/unisys/Documentation/overview.txt b/drivers/staging/unisys/Documentation/overview.txt index 25f93f2..c2d8dd4 100644 --- a/drivers/staging/unisys/Documentation/overview.txt +++ b/drivers/staging/unisys/Documentation/overview.txt @@ -12,7 +12,7 @@ normally be unsharable, specifically: * visornic - network interface * visorhba - scsi disk adapter -* visorhid - keyboard and mouse +* visorinput - keyboard and mouse These drivers conform to the standard Linux bus/device model described within Documentation/driver-model/, and utilize a driver named visorbus to @@ -44,7 +44,7 @@ NOT covered in this document: * Because the s-Par back-end provides a standard EFI framebuffer to each guest, the already-existing efifb Linux driver is used to provide guest video access. Thus, the only s-Par-unique support that is necessary to - provide a guest graphics console are for keyboard and mouse (via visorhid). + provide a guest graphics console are for keyboard and mouse (via visorinput). 2. Driver Descriptions @@ -296,13 +296,13 @@ i.e.: alias visorbus:8cd5994d-c58e-11da-95a9-00e08161165f visornic -2.4. visorhid -------------- +2.4. visorinput +--------------- -The visorhid driver registers with visorbus as the function driver to +The visorinput driver registers with visorbus as the function driver to handle human input devices, specified using the SPAR_KEYBOARD_CHANNEL_PROTOCOL_UUID and SPAR_MOUSE_CHANNEL_PROTOCOL_UUID -types in the visorbus_register_visor_driver() call. visorhid uses +types in the visorbus_register_visor_driver() call. visorinput uses input_register_device() to expose devices of class input (e.g., /sys/class/input/) for virtual keyboard and virtual mouse devices. A s-Par virtual keyboard device maps 1-to-1 with a Linux input device @@ -312,7 +312,7 @@ devices created for it: 1 named "visor Wheel", and 1 named "visor Mouse". By registering as input class devices, modern versions of X will automatically find and properly use s-Par virtual keyboard and mouse devices. As the s-Par back-end reports keyboard and mouse activity via events on the -virtual device channel, the visorhid driver delivers the activity to the +virtual device channel, the visorinput driver delivers the activity to the Linux environment by calling input_report_key() and input_report_abs(). You can interact with the guest console using the usyscon Partition Desktop @@ -322,7 +322,7 @@ usyscon_partitiondesktop-*.rpm, or into a Windows environment via PartitionDesktop.msi, you will be able to launch a console for your guest Linux environment by clicking the console icon in the s-Par web UI. -When compiled as a module, visorhid can be autoloaded by visorbus in +When compiled as a module, visorinput can be autoloaded by visorbus in standard udev/systemd environments, as it includes the modules.alias definition: @@ -331,8 +331,8 @@ definition: i.e.: - alias visorbus:c73416d0-b0b8-44af-b304-9d2ae99f1b3d visorhid - alias visorbus:addf07d4-94a9-46e2-81c3-61abcdbdbd87 visorhid + alias visorbus:c73416d0-b0b8-44af-b304-9d2ae99f1b3d visorinput + alias visorbus:addf07d4-94a9-46e2-81c3-61abcdbdbd87 visorinput 3. Minimum Required Driver Set @@ -352,5 +352,5 @@ the s-Par back-end, which is the default configuration. However, for configurations where the Linux guest is provided with an SR-IOV NIC for example, visornic is not technically required. -visorhid is only required for a Linux guest running under s-Par if you +visorinput is only required for a Linux guest running under s-Par if you require graphics-mode access to your guest console. diff --git a/drivers/staging/unisys/Kconfig b/drivers/staging/unisys/Kconfig index 5cbb791..4f1f5e6 100644 --- a/drivers/staging/unisys/Kconfig +++ b/drivers/staging/unisys/Kconfig @@ -13,7 +13,7 @@ if UNISYSSPAR source "drivers/staging/unisys/visorbus/Kconfig" source "drivers/staging/unisys/visornic/Kconfig" -source "drivers/staging/unisys/visorhid/Kconfig" +source "drivers/staging/unisys/visorinput/Kconfig" source "drivers/staging/unisys/visorhba/Kconfig" endif # UNISYSSPAR diff --git a/drivers/staging/unisys/Makefile b/drivers/staging/unisys/Makefile index 79c9036..20eb098 100644 --- a/drivers/staging/unisys/Makefile +++ b/drivers/staging/unisys/Makefile @@ -3,5 +3,5 @@ # obj-$(CONFIG_UNISYS_VISORBUS) += visorbus/ obj-$(CONFIG_UNISYS_VISORNIC) += visornic/ -obj-$(CONFIG_UNISYS_VISORHID) += visorhid/ +obj-$(CONFIG_UNISYS_VISORINPUT) += visorinput/ obj-$(CONFIG_UNISYS_VISORHBA) += visorhba/ diff --git a/drivers/staging/unisys/visorhid/Kconfig b/drivers/staging/unisys/visorhid/Kconfig deleted file mode 100644 index 3b83e2c..0000000 --- a/drivers/staging/unisys/visorhid/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -# -# Unisys visorhid configuration -# - -config UNISYS_VISORHID - tristate "Unisys visorhid driver" - depends on UNISYSSPAR && UNISYS_VISORBUS && FB - ---help--- - If you say Y here, you will enable the Unisys visorhid driver. - diff --git a/drivers/staging/unisys/visorhid/Makefile b/drivers/staging/unisys/visorhid/Makefile deleted file mode 100644 index e457bd1..0000000 --- a/drivers/staging/unisys/visorhid/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for Unisys visorhid -# - -obj-$(CONFIG_UNISYS_VISORHID) += visorhid.o - -ccflags-y += -Idrivers/staging/unisys/include diff --git a/drivers/staging/unisys/visorhid/keyboardchannel.h b/drivers/staging/unisys/visorhid/keyboardchannel.h deleted file mode 100644 index 2ed2602..0000000 --- a/drivers/staging/unisys/visorhid/keyboardchannel.h +++ /dev/null @@ -1,32 +0,0 @@ -/* Copyright (C) 2010 - 2015 UNISYS CORPORATION - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - */ - -#ifndef __SPAR_KEYBOARDCHANNEL_H__ -#define __SPAR_KEYBOARDCHANNEL_H__ - -#include <linux/kernel.h> -#include <linux/uuid.h> - -#include "channel.h" -#include "ultrainputreport.h" - -/* {c73416d0-b0b8-44af-b304-9d2ae99f1b3d} */ -#define SPAR_KEYBOARD_CHANNEL_PROTOCOL_UUID \ - UUID_LE(0xc73416d0, 0xb0b8, 0x44af, \ - 0xb3, 0x4, 0x9d, 0x2a, 0xe9, 0x9f, 0x1b, 0x3d) -#define SPAR_KEYBOARD_CHANNEL_PROTOCOL_UUID_STR "c73416d0-b0b8-44af-b304-9d2ae99f1b3d" -#define SPAR_KEYBOARD_CHANNEL_PROTOCOL_VERSIONID 1 -#define KEYBOARD_MAXINPUTREPORTS 50 - -#endif diff --git a/drivers/staging/unisys/visorhid/mousechannel.h b/drivers/staging/unisys/visorhid/mousechannel.h deleted file mode 100644 index 256477a..0000000 --- a/drivers/staging/unisys/visorhid/mousechannel.h +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright (C) 2010 - 2015 UNISYS CORPORATION - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - */ - -#ifndef __SPAR_MOUSECHANNEL_H__ -#define __SPAR_MOUSECHANNEL_H__ - -#include <linux/kernel.h> -#include <linux/uuid.h> - -#include "channel.h" -#include "ultrainputreport.h" - -/* {addf07d4-94a9-46e2-81c3-61abcdbdbd87} */ -#define SPAR_MOUSE_CHANNEL_PROTOCOL_UUID \ - UUID_LE(0xaddf07d4, 0x94a9, 0x46e2, \ - 0x81, 0xc3, 0x61, 0xab, 0xcd, 0xbd, 0xbd, 0x87) -#define SPAR_MOUSE_CHANNEL_PROTOCOL_UUID_STR \ - "addf07d4-94a9-46e2-81c3-61abcdbdbd87" -#define SPAR_MOUSE_CHANNEL_PROTOCOL_VERSIONID 1 -#define MOUSE_MAXINPUTREPORTS 50 - -#endif diff --git a/drivers/staging/unisys/visorhid/ultrainputreport.h b/drivers/staging/unisys/visorhid/ultrainputreport.h deleted file mode 100644 index 3e6a52f..0000000 --- a/drivers/staging/unisys/visorhid/ultrainputreport.h +++ /dev/null @@ -1,74 +0,0 @@ -/* Copyright (C) 2010 - 2015 UNISYS CORPORATION - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - */ - -#ifndef __SPAR_ULTRAINPUTREPORT_H__ -#define __SPAR_ULTRAINPUTREPORT_H__ - -#include <linux/types.h> - -#include "ultrainputreport.h" - -/* Identifies mouse and keyboard activity which is specified by the firmware to - * the host using the cmsimpleinput protocol. @ingroup coretypes - */ -enum ultra_inputaction { - inputaction_none = 0, - inputaction_xy_motion = 1, /* only motion; arg1=x, arg2=y */ - inputaction_mouse_button_down = 2, /* arg1: 1=left,2=center,3=right */ - inputaction_mouse_button_up = 3, /* arg1: 1=left,2=center,3=right */ - inputaction_mouse_button_click = 4, /* arg1: 1=left,2=center,3=right */ - inputaction_mouse_button_dclick = 5, /* arg1: 1=left,2=center, - 3=right */ - inputaction_wheel_rotate_away = 6, /* arg1: wheel rotation away from - user */ - inputaction_wheel_rotate_toward = 7, /* arg1: wheel rotation toward - user */ - inputaction_set_max_xy = 8, /* set screen maxXY; arg1=x, arg2=y */ - inputaction_key_down = 64, /* arg1: scancode, as follows: - If arg1 <= 0xff, it's a 1-byte - scancode and arg1 is that scancode. - If arg1 > 0xff, it's a 2-byte - scanecode, with the 1st byte in the - low 8 bits, and the 2nd byte in the - high 8 bits. E.g., the right ALT key - would appear as x'38e0'. */ - inputaction_key_up = 65, /* arg1: scancode (in same format as - inputaction_keyDown) */ - inputaction_set_locking_key_state = 66, - /* arg1: scancode (in same format - as inputaction_keyDown); - MUST refer to one of the - locking keys, like capslock, - numlock, or scrolllock - arg2: 1 iff locking key should be - in the LOCKED position - (e.g., light is ON) */ - inputaction_key_down_up = 67, /* arg1: scancode (in same format - as inputaction_keyDown) */ - inputaction_last -}; - -struct ultra_inputactivity { - u16 action; - u16 arg1; - u16 arg2; - u16 arg3; -} __packed; - -struct ultra_inputreport { - u64 seq_no; - struct ultra_inputactivity activity; -} __packed; - -#endif diff --git a/drivers/staging/unisys/visorhid/visorhid.c b/drivers/staging/unisys/visorhid/visorhid.c deleted file mode 100644 index c24aaf5..0000000 --- a/drivers/staging/unisys/visorhid/visorhid.c +++ /dev/null @@ -1,671 +0,0 @@ -/* visorhid.c - * - * Copyright (C) 2011 - 2015 UNISYS CORPORATION - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - */ - -/* This driver lives in a generic guest Linux partition, and registers to - * receive keyboard and mouse channels from the visorbus driver. It reads - * inputs from such channels, and delivers it to the Linux OS in the - * standard way the Linux expects for input drivers. - */ - -#include <linux/buffer_head.h> -#include <linux/fb.h> -#include <linux/fs.h> -#include <linux/input.h> -#include <linux/uaccess.h> - -#include "keyboardchannel.h" -#include "mousechannel.h" -#include "version.h" -#include "visorbus.h" - -#define PIXELS_ACROSS_DEFAULT 800 -#define PIXELS_DOWN_DEFAULT 600 - -static const uuid_le spar_keyboard_channel_protocol_uuid = - SPAR_KEYBOARD_CHANNEL_PROTOCOL_UUID; -static const uuid_le spar_mouse_channel_protocol_uuid = - SPAR_MOUSE_CHANNEL_PROTOCOL_UUID; -static int visorhid_probe(struct visor_device *dev); -static void visorhid_remove(struct visor_device *dev); -static void visorhid_channel_interrupt(struct visor_device *dev); -static int visorhid_pause(struct visor_device *dev, - visorbus_state_complete_func complete_func); -static int visorhid_resume(struct visor_device *dev, - visorbus_state_complete_func complete_func); -static struct input_dev *register_client_keyboard(void); -static struct input_dev *register_client_mouse(void); -static void unregister_client_input(struct input_dev *visorinput_dev); - -/* GUIDS for all channel types supported by this driver. */ -static struct visor_channeltype_descriptor visorhid_channel_types[] = { - { SPAR_KEYBOARD_CHANNEL_PROTOCOL_UUID, "keyboard"}, - { SPAR_MOUSE_CHANNEL_PROTOCOL_UUID, "mouse"}, - { NULL_UUID_LE, NULL } -}; -MODULE_DEVICE_TABLE(visorbus, visorhid_channel_types); -MODULE_ALIAS("visorbus:" SPAR_MOUSE_CHANNEL_PROTOCOL_UUID_STR); -MODULE_ALIAS("visorbus:" SPAR_KEYBOARD_CHANNEL_PROTOCOL_UUID_STR); - -/** This is used to tell the visor bus driver which types of visor devices - * we support, and what functions to call when a visor device that we support - * is attached or removed. - */ -static struct visor_driver visorhid_driver = { - .name = "visorhid", - .vertag = NULL, - .owner = THIS_MODULE, - .channel_types = visorhid_channel_types, - .probe = visorhid_probe, - .remove = visorhid_remove, - .channel_interrupt = visorhid_channel_interrupt, - .pause = visorhid_pause, - .resume = visorhid_resume, -}; - -enum visorhid_device_type { - visorhid_keyboard, - visorhid_mouse, -}; - -/* This is the private data that we store for each device. - * A pointer to this struct is maintained via - * dev_get_drvdata() / dev_set_drvdata() for each struct device. - */ -struct visorhid_devdata { - struct visor_device *dev; - /** lock for dev */ - struct rw_semaphore lock_visor_dev; - struct input_dev *visorinput_dev; - bool paused; -}; - -/* Borrowed from drivers/input/keyboard/atakbd.c */ -/* This maps 1-byte scancodes to keycodes. */ -static unsigned char visorkbd_keycode[256] = { /* American layout */ - [0] = KEY_GRAVE, - [1] = KEY_ESC, - [2] = KEY_1, - [3] = KEY_2, - [4] = KEY_3, - [5] = KEY_4, - [6] = KEY_5, - [7] = KEY_6, - [8] = KEY_7, - [9] = KEY_8, - [10] = KEY_9, - [11] = KEY_0, - [12] = KEY_MINUS, - [13] = KEY_EQUAL, - [14] = KEY_BACKSPACE, - [15] = KEY_TAB, - [16] = KEY_Q, - [17] = KEY_W, - [18] = KEY_E, - [19] = KEY_R, - [20] = KEY_T, - [21] = KEY_Y, - [22] = KEY_U, - [23] = KEY_I, - [24] = KEY_O, - [25] = KEY_P, - [26] = KEY_LEFTBRACE, - [27] = KEY_RIGHTBRACE, - [28] = KEY_ENTER, - [29] = KEY_LEFTCTRL, - [30] = KEY_A, - [31] = KEY_S, - [32] = KEY_D, - [33] = KEY_F, - [34] = KEY_G, - [35] = KEY_H, - [36] = KEY_J, - [37] = KEY_K, - [38] = KEY_L, - [39] = KEY_SEMICOLON, - [40] = KEY_APOSTROPHE, - [41] = KEY_GRAVE, /* FIXME, '#' */ - [42] = KEY_LEFTSHIFT, - [43] = KEY_BACKSLASH, /* FIXME, '~' */ - [44] = KEY_Z, - [45] = KEY_X, - [46] = KEY_C, - [47] = KEY_V, - [48] = KEY_B, - [49] = KEY_N, - [50] = KEY_M, - [51] = KEY_COMMA, - [52] = KEY_DOT, - [53] = KEY_SLASH, - [54] = KEY_RIGHTSHIFT, - [55] = KEY_KPASTERISK, - [56] = KEY_LEFTALT, - [57] = KEY_SPACE, - [58] = KEY_CAPSLOCK, - [59] = KEY_F1, - [60] = KEY_F2, - [61] = KEY_F3, - [62] = KEY_F4, - [63] = KEY_F5, - [64] = KEY_F6, - [65] = KEY_F7, - [66] = KEY_F8, - [67] = KEY_F9, - [68] = KEY_F10, - [69] = KEY_NUMLOCK, - [70] = KEY_SCROLLLOCK, - [71] = KEY_KP7, - [72] = KEY_KP8, - [73] = KEY_KP9, - [74] = KEY_KPMINUS, - [75] = KEY_KP4, - [76] = KEY_KP5, - [77] = KEY_KP6, - [78] = KEY_KPPLUS, - [79] = KEY_KP1, - [80] = KEY_KP2, - [81] = KEY_KP3, - [82] = KEY_KP0, - [83] = KEY_KPDOT, - [86] = KEY_102ND, /* enables UK backslash+pipe key, - * and FR lessthan+greaterthan key */ - [87] = KEY_F11, - [88] = KEY_F12, - [90] = KEY_KPLEFTPAREN, - [91] = KEY_KPRIGHTPAREN, - [92] = KEY_KPASTERISK, /* FIXME */ - [93] = KEY_KPASTERISK, - [94] = KEY_KPPLUS, - [95] = KEY_HELP, - [96] = KEY_KPENTER, - [97] = KEY_RIGHTCTRL, - [98] = KEY_KPSLASH, - [99] = KEY_KPLEFTPAREN, - [100] = KEY_KPRIGHTPAREN, - [101] = KEY_KPSLASH, - [102] = KEY_HOME, - [103] = KEY_UP, - [104] = KEY_PAGEUP, - [105] = KEY_LEFT, - [106] = KEY_RIGHT, - [107] = KEY_END, - [108] = KEY_DOWN, - [109] = KEY_PAGEDOWN, - [110] = KEY_INSERT, - [111] = KEY_DELETE, - [112] = KEY_MACRO, - [113] = KEY_MUTE -}; - -/* This maps the <xx> in extended scancodes of the form "0xE0 <xx>" into - * keycodes. - */ -static unsigned char visorkbd_ext_keycode[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */ - 0, 0, 0, 0, KEY_KPENTER, KEY_RIGHTCTRL, 0, 0, /* 0x18 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */ - KEY_RIGHTALT, 0, 0, 0, 0, 0, 0, 0, /* 0x28 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 */ - KEY_RIGHTALT /* AltGr */, 0, 0, 0, 0, 0, 0, 0, /* 0x38 */ - 0, 0, 0, 0, 0, 0, 0, KEY_HOME, /* 0x40 */ - KEY_UP, KEY_PAGEUP, 0, KEY_LEFT, 0, KEY_RIGHT, 0, KEY_END, /* 0x48 */ - KEY_DOWN, KEY_PAGEDOWN, KEY_INSERT, KEY_DELETE, 0, 0, 0, 0, /* 0x50 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x58 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */ -}; - -static struct visorhid_devdata * -devdata_create(struct visor_device *dev, enum visorhid_device_type devtype) -{ - struct visorhid_devdata *devdata = NULL; - - devdata = kzalloc(sizeof(*devdata), GFP_KERNEL); - if (!devdata) - return NULL; - devdata->dev = dev; - - /* This is an input device in a client guest partition, - * so we need to create whatever gizmos are necessary to - * deliver our inputs to the guest OS. - */ - switch (devtype) { - case visorhid_keyboard: - devdata->visorinput_dev = register_client_keyboard(); - if (!devdata->visorinput_dev) - goto cleanups_register; - break; - case visorhid_mouse: - devdata->visorinput_dev = register_client_mouse(); - if (!devdata->visorinput_dev) - goto cleanups_register; - break; - } - - init_rwsem(&devdata->lock_visor_dev); - - return devdata; - -cleanups_register: - kfree(devdata); - return NULL; -} - -static int -visorhid_probe(struct visor_device *dev) -{ - struct visorhid_devdata *devdata = NULL; - uuid_le guid; - enum visorhid_device_type devtype; - - guid = visorchannel_get_uuid(dev->visorchannel); - if (uuid_le_cmp(guid, spar_mouse_channel_protocol_uuid) == 0) - devtype = visorhid_mouse; - else if (uuid_le_cmp(guid, spar_keyboard_channel_protocol_uuid) == 0) - devtype = visorhid_keyboard; - else - return -ENODEV; - devdata = devdata_create(dev, devtype); - if (!devdata) - return -ENOMEM; - dev_set_drvdata(&dev->device, devdata); - visorbus_enable_channel_interrupts(dev); - return 0; -} - -static void -visorhid_remove(struct visor_device *dev) -{ - struct visorhid_devdata *devdata = dev_get_drvdata(&dev->device); - - if (!devdata) - return; - - visorbus_disable_channel_interrupts(dev); - - /* due to above, at this time no thread of execution will be - * in visorhid_channel_interrupt() - */ - - down_write(&devdata->lock_visor_dev); - dev_set_drvdata(&dev->device, NULL); - unregister_client_input(devdata->visorinput_dev); - up_write(&devdata->lock_visor_dev); - kfree(devdata); -} - -static void -unregister_client_input(struct input_dev *visorinput_dev) -{ - if (visorinput_dev) - input_unregister_device(visorinput_dev); -} - -/* register_client_keyboard() initializes and returns a Linux gizmo that we - * can use to deliver keyboard inputs to Linux. We of course do this when - * we see keyboard inputs coming in on a keyboard channel. - */ -static struct input_dev * -register_client_keyboard(void) -{ - int i, error; - struct input_dev *visorinput_dev = NULL; - - visorinput_dev = input_allocate_device(); - if (!visorinput_dev) - return NULL; - - visorinput_dev->name = "visor Keyboard"; - visorinput_dev->phys = "visorkbd:input0"; - visorinput_dev->id.bustype = BUS_HOST; - visorinput_dev->id.vendor = 0x0001; - visorinput_dev->id.product = 0x0001; - visorinput_dev->id.version = 0x0100; - - visorinput_dev->evbit[0] = BIT_MASK(EV_KEY) | - BIT_MASK(EV_REP) | - BIT_MASK(EV_LED); - visorinput_dev->ledbit[0] = BIT_MASK(LED_CAPSL) | - BIT_MASK(LED_SCROLLL) | - BIT_MASK(LED_NUML); - visorinput_dev->keycode = visorkbd_keycode; - visorinput_dev->keycodesize = sizeof(unsigned char); - visorinput_dev->keycodemax = ARRAY_SIZE(visorkbd_keycode); - - for (i = 1; i < ARRAY_SIZE(visorkbd_keycode); i++) - set_bit(visorkbd_keycode[i], visorinput_dev->keybit); - - for (i = 1; i < ARRAY_SIZE(visorkbd_ext_keycode); i++) - set_bit(visorkbd_ext_keycode[i], visorinput_dev->keybit); - - error = input_register_device(visorinput_dev); - if (error) { - input_free_device(visorinput_dev); - return NULL; - } - return visorinput_dev; -} - -static struct input_dev * -register_client_mouse(void) -{ - int error; - struct input_dev *visorinput_dev = NULL; - int xres, yres; - struct fb_info *fb0; - - visorinput_dev = input_allocate_device(); - if (!visorinput_dev) - return NULL; - - visorinput_dev->name = "visor Mouse"; - visorinput_dev->phys = "visormou:input0"; - visorinput_dev->id.bustype = BUS_HOST; - visorinput_dev->id.vendor = 0x0001; - visorinput_dev->id.product = 0x0002; - visorinput_dev->id.version = 0x0100; - - visorinput_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - set_bit(BTN_LEFT, visorinput_dev->keybit); - set_bit(BTN_RIGHT, visorinput_dev->keybit); - set_bit(BTN_MIDDLE, visorinput_dev->keybit); - - if (registered_fb[0]) { - fb0 = registered_fb[0]; - xres = fb0->var.xres_virtual; - yres = fb0->var.yres_virtual; - } else { - xres = PIXELS_ACROSS_DEFAULT; - yres = PIXELS_DOWN_DEFAULT; - } - input_set_abs_params(visorinput_dev, ABS_X, 0, xres, 0, 0); - input_set_abs_params(visorinput_dev, ABS_Y, 0, yres, 0, 0); - - error = input_register_device(visorinput_dev); - if (error) { - input_free_device(visorinput_dev); - return NULL; - } - - /* Sending top-left and bottom-right positions is ABSOLUTELY - * REQUIRED if we want X to move the mouse to the exact points - * we tell it. I have NO IDEA why. - */ - input_report_abs(visorinput_dev, ABS_X, 0); - input_report_abs(visorinput_dev, ABS_Y, 0); - input_sync(visorinput_dev); - input_report_abs(visorinput_dev, ABS_X, xres - 1); - input_report_abs(visorinput_dev, ABS_Y, yres - 1); - input_sync(visorinput_dev); - - input_set_capability(visorinput_dev, EV_REL, REL_WHEEL); - - return visorinput_dev; -} - -static void -do_key(struct input_dev *inpt, int keycode, int down) -{ - input_report_key(inpt, keycode, down); -} - -/* Make it so the current locking state of the locking key indicated by - * <keycode> is as indicated by <desired_state> (1=locked, 0=unlocked). - */ -static void -handle_locking_key(struct input_dev *visorinput_dev, - int keycode, int desired_state) -{ - int led; - char *sled; - - switch (keycode) { - case KEY_CAPSLOCK: - led = LED_CAPSL; - sled = "CAP"; - break; - case KEY_SCROLLLOCK: - led = LED_SCROLLL; - sled = "SCR"; - break; - case KEY_NUMLOCK: - led = LED_NUML; - sled = "NUM"; - break; - default: - led = -1; - break; - } - if (led >= 0) { - int old_state = (test_bit(led, visorinput_dev->led) != 0); - - if (old_state != desired_state) { - do_key(visorinput_dev, keycode, 1); - input_sync(visorinput_dev); - do_key(visorinput_dev, keycode, 0); - input_sync(visorinput_dev); - __change_bit(led, visorinput_dev->led); - } - } -} - -/* <scancode> is either a 1-byte scancode, or an extended 16-bit scancode - * with 0xE0 in the low byte and the extended scancode value in the next - * higher byte. - */ -static int -scancode_to_keycode(int scancode) -{ - int keycode; - - if (scancode > 0xff) - keycode = visorkbd_ext_keycode[(scancode >> 8) & 0xff]; - else - keycode = visorkbd_keycode[scancode]; - return keycode; -} - -static int -calc_button(int x) -{ - switch (x) { - case 1: - return BTN_LEFT; - case 2: - return BTN_MIDDLE; - case 3: - return BTN_RIGHT; - default: - return -1; - } -} - -/* This is used only when this driver is active as an input driver in the - * client guest partition. It is called periodically so we can obtain inputs - * from the channel, and deliver them to the guest OS. - */ -static void -visorhid_channel_interrupt(struct visor_device *dev) -{ - struct ultra_inputreport r; - int scancode, keycode; - struct input_dev *visorinput_dev; - int xmotion, ymotion, zmotion, button; - int i; - - struct visorhid_devdata *devdata = dev_get_drvdata(&dev->device); - - if (!devdata) - return; - - down_write(&devdata->lock_visor_dev); - if (devdata->paused) /* don't touch device/channel when paused */ - goto out_locked; - - visorinput_dev = devdata->visorinput_dev; - if (!visorinput_dev) - goto out_locked; - - while (visorchannel_signalremove(dev->visorchannel, 0, &r)) { - scancode = r.activity.arg1; - keycode = scancode_to_keycode(scancode); - switch (r.activity.action) { - case inputaction_key_down: - do_key(visorinput_dev, keycode, 1); - input_sync(visorinput_dev); - break; - case inputaction_key_up: - do_key(visorinput_dev, keycode, 0); - input_sync(visorinput_dev); - break; - case inputaction_key_down_up: - do_key(visorinput_dev, keycode, 1); - input_sync(visorinput_dev); - do_key(visorinput_dev, keycode, 0); - input_sync(visorinput_dev); - break; - case inputaction_set_locking_key_state: - handle_locking_key(visorinput_dev, keycode, - r.activity.arg2); - break; - case inputaction_xy_motion: - xmotion = r.activity.arg1; - ymotion = r.activity.arg2; - input_report_abs(visorinput_dev, ABS_X, xmotion); - input_report_abs(visorinput_dev, ABS_Y, ymotion); - input_sync(visorinput_dev); - break; - case inputaction_mouse_button_down: - button = calc_button(r.activity.arg1); - if (button < 0) - break; - input_report_key(visorinput_dev, button, 1); - input_sync(visorinput_dev); - break; - case inputaction_mouse_button_up: - button = calc_button(r.activity.arg1); - if (button < 0) - break; - input_report_key(visorinput_dev, button, 0); - input_sync(visorinput_dev); - break; - case inputaction_mouse_button_click: - button = calc_button(r.activity.arg1); - if (button < 0) - break; - input_report_key(visorinput_dev, button, 1); - - input_sync(visorinput_dev); - input_report_key(visorinput_dev, button, 0); - input_sync(visorinput_dev); - break; - case inputaction_mouse_button_dclick: - button = calc_button(r.activity.arg1); - if (button < 0) - break; - for (i = 0; i < 2; i++) { - input_report_key(visorinput_dev, button, 1); - input_sync(visorinput_dev); - input_report_key(visorinput_dev, button, 0); - input_sync(visorinput_dev); - } - break; - case inputaction_wheel_rotate_away: - zmotion = r.activity.arg1; - input_report_rel(visorinput_dev, REL_WHEEL, 1); - input_sync(visorinput_dev); - break; - case inputaction_wheel_rotate_toward: - zmotion = r.activity.arg1; - input_report_rel(visorinput_dev, REL_WHEEL, -1); - input_sync(visorinput_dev); - break; - } - } -out_locked: - up_write(&devdata->lock_visor_dev); -} - -static int -visorhid_pause(struct visor_device *dev, - visorbus_state_complete_func complete_func) -{ - int rc; - struct visorhid_devdata *devdata = dev_get_drvdata(&dev->device); - - if (!devdata) { - rc = -ENODEV; - goto out; - } - - down_write(&devdata->lock_visor_dev); - if (devdata->paused) { - rc = -EBUSY; - goto out_locked; - } - devdata->paused = true; - complete_func(dev, 0); - rc = 0; -out_locked: - up_write(&devdata->lock_visor_dev); -out: - return rc; -} - -static int -visorhid_resume(struct visor_device *dev, - visorbus_state_complete_func complete_func) -{ - int rc; - struct visorhid_devdata *devdata = dev_get_drvdata(&dev->device); - - if (!devdata) { - rc = -ENODEV; - goto out; - } - down_write(&devdata->lock_visor_dev); - if (!devdata->paused) { - rc = -EBUSY; - goto out_locked; - } - devdata->paused = false; - complete_func(dev, 0); - rc = 0; -out_locked: - up_write(&devdata->lock_visor_dev); -out: - return rc; -} - -static int -visorhid_init(void) -{ - return visorbus_register_visor_driver(&visorhid_driver); -} - -static void -visorhid_cleanup(void) -{ - visorbus_unregister_visor_driver(&visorhid_driver); -} - -module_init(visorhid_init); -module_exit(visorhid_cleanup); - -MODULE_AUTHOR("Unisys"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("s-Par human input driver for guest Linux"); -MODULE_VERSION(VERSION); diff --git a/drivers/staging/unisys/visorinput/Kconfig b/drivers/staging/unisys/visorinput/Kconfig new file mode 100644 index 0000000..d83deb4 --- /dev/null +++ b/drivers/staging/unisys/visorinput/Kconfig @@ -0,0 +1,10 @@ +# +# Unisys visorinput configuration +# + +config UNISYS_VISORINPUT + tristate "Unisys visorinput driver" + depends on UNISYSSPAR && UNISYS_VISORBUS && FB + ---help--- + If you say Y here, you will enable the Unisys visorinput driver. + diff --git a/drivers/staging/unisys/visorinput/Makefile b/drivers/staging/unisys/visorinput/Makefile new file mode 100644 index 0000000..beedca7 --- /dev/null +++ b/drivers/staging/unisys/visorinput/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for Unisys visorinput +# + +obj-$(CONFIG_UNISYS_VISORINPUT) += visorinput.o + +ccflags-y += -Idrivers/staging/unisys/include diff --git a/drivers/staging/unisys/visorinput/keyboardchannel.h b/drivers/staging/unisys/visorinput/keyboardchannel.h new file mode 100644 index 0000000..2ed2602 --- /dev/null +++ b/drivers/staging/unisys/visorinput/keyboardchannel.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2010 - 2015 UNISYS CORPORATION + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + +#ifndef __SPAR_KEYBOARDCHANNEL_H__ +#define __SPAR_KEYBOARDCHANNEL_H__ + +#include <linux/kernel.h> +#include <linux/uuid.h> + +#include "channel.h" +#include "ultrainputreport.h" + +/* {c73416d0-b0b8-44af-b304-9d2ae99f1b3d} */ +#define SPAR_KEYBOARD_CHANNEL_PROTOCOL_UUID \ + UUID_LE(0xc73416d0, 0xb0b8, 0x44af, \ + 0xb3, 0x4, 0x9d, 0x2a, 0xe9, 0x9f, 0x1b, 0x3d) +#define SPAR_KEYBOARD_CHANNEL_PROTOCOL_UUID_STR "c73416d0-b0b8-44af-b304-9d2ae99f1b3d" +#define SPAR_KEYBOARD_CHANNEL_PROTOCOL_VERSIONID 1 +#define KEYBOARD_MAXINPUTREPORTS 50 + +#endif diff --git a/drivers/staging/unisys/visorinput/mousechannel.h b/drivers/staging/unisys/visorinput/mousechannel.h new file mode 100644 index 0000000..256477a --- /dev/null +++ b/drivers/staging/unisys/visorinput/mousechannel.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2010 - 2015 UNISYS CORPORATION + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + +#ifndef __SPAR_MOUSECHANNEL_H__ +#define __SPAR_MOUSECHANNEL_H__ + +#include <linux/kernel.h> +#include <linux/uuid.h> + +#include "channel.h" +#include "ultrainputreport.h" + +/* {addf07d4-94a9-46e2-81c3-61abcdbdbd87} */ +#define SPAR_MOUSE_CHANNEL_PROTOCOL_UUID \ + UUID_LE(0xaddf07d4, 0x94a9, 0x46e2, \ + 0x81, 0xc3, 0x61, 0xab, 0xcd, 0xbd, 0xbd, 0x87) +#define SPAR_MOUSE_CHANNEL_PROTOCOL_UUID_STR \ + "addf07d4-94a9-46e2-81c3-61abcdbdbd87" +#define SPAR_MOUSE_CHANNEL_PROTOCOL_VERSIONID 1 +#define MOUSE_MAXINPUTREPORTS 50 + +#endif diff --git a/drivers/staging/unisys/visorinput/ultrainputreport.h b/drivers/staging/unisys/visorinput/ultrainputreport.h new file mode 100644 index 0000000..3e6a52f --- /dev/null +++ b/drivers/staging/unisys/visorinput/ultrainputreport.h @@ -0,0 +1,74 @@ +/* Copyright (C) 2010 - 2015 UNISYS CORPORATION + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + +#ifndef __SPAR_ULTRAINPUTREPORT_H__ +#define __SPAR_ULTRAINPUTREPORT_H__ + +#include <linux/types.h> + +#include "ultrainputreport.h" + +/* Identifies mouse and keyboard activity which is specified by the firmware to + * the host using the cmsimpleinput protocol. @ingroup coretypes + */ +enum ultra_inputaction { + inputaction_none = 0, + inputaction_xy_motion = 1, /* only motion; arg1=x, arg2=y */ + inputaction_mouse_button_down = 2, /* arg1: 1=left,2=center,3=right */ + inputaction_mouse_button_up = 3, /* arg1: 1=left,2=center,3=right */ + inputaction_mouse_button_click = 4, /* arg1: 1=left,2=center,3=right */ + inputaction_mouse_button_dclick = 5, /* arg1: 1=left,2=center, + 3=right */ + inputaction_wheel_rotate_away = 6, /* arg1: wheel rotation away from + user */ + inputaction_wheel_rotate_toward = 7, /* arg1: wheel rotation toward + user */ + inputaction_set_max_xy = 8, /* set screen maxXY; arg1=x, arg2=y */ + inputaction_key_down = 64, /* arg1: scancode, as follows: + If arg1 <= 0xff, it's a 1-byte + scancode and arg1 is that scancode. + If arg1 > 0xff, it's a 2-byte + scanecode, with the 1st byte in the + low 8 bits, and the 2nd byte in the + high 8 bits. E.g., the right ALT key + would appear as x'38e0'. */ + inputaction_key_up = 65, /* arg1: scancode (in same format as + inputaction_keyDown) */ + inputaction_set_locking_key_state = 66, + /* arg1: scancode (in same format + as inputaction_keyDown); + MUST refer to one of the + locking keys, like capslock, + numlock, or scrolllock + arg2: 1 iff locking key should be + in the LOCKED position + (e.g., light is ON) */ + inputaction_key_down_up = 67, /* arg1: scancode (in same format + as inputaction_keyDown) */ + inputaction_last +}; + +struct ultra_inputactivity { + u16 action; + u16 arg1; + u16 arg2; + u16 arg3; +} __packed; + +struct ultra_inputreport { + u64 seq_no; + struct ultra_inputactivity activity; +} __packed; + +#endif diff --git a/drivers/staging/unisys/visorinput/visorinput.c b/drivers/staging/unisys/visorinput/visorinput.c new file mode 100644 index 0000000..e1c328e --- /dev/null +++ b/drivers/staging/unisys/visorinput/visorinput.c @@ -0,0 +1,671 @@ +/* visorinput.c + * + * Copyright (C) 2011 - 2015 UNISYS CORPORATION + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + +/* This driver lives in a generic guest Linux partition, and registers to + * receive keyboard and mouse channels from the visorbus driver. It reads + * inputs from such channels, and delivers it to the Linux OS in the + * standard way the Linux expects for input drivers. + */ + +#include <linux/buffer_head.h> +#include <linux/fb.h> +#include <linux/fs.h> +#include <linux/input.h> +#include <linux/uaccess.h> + +#include "keyboardchannel.h" +#include "mousechannel.h" +#include "version.h" +#include "visorbus.h" + +#define PIXELS_ACROSS_DEFAULT 800 +#define PIXELS_DOWN_DEFAULT 600 + +static const uuid_le spar_keyboard_channel_protocol_uuid = + SPAR_KEYBOARD_CHANNEL_PROTOCOL_UUID; +static const uuid_le spar_mouse_channel_protocol_uuid = + SPAR_MOUSE_CHANNEL_PROTOCOL_UUID; +static int visorinput_probe(struct visor_device *dev); +static void visorinput_remove(struct visor_device *dev); +static void visorinput_channel_interrupt(struct visor_device *dev); +static int visorinput_pause(struct visor_device *dev, + visorbus_state_complete_func complete_func); +static int visorinput_resume(struct visor_device *dev, + visorbus_state_complete_func complete_func); +static struct input_dev *register_client_keyboard(void); +static struct input_dev *register_client_mouse(void); +static void unregister_client_input(struct input_dev *visorinput_dev); + +/* GUIDS for all channel types supported by this driver. */ +static struct visor_channeltype_descriptor visorinput_channel_types[] = { + { SPAR_KEYBOARD_CHANNEL_PROTOCOL_UUID, "keyboard"}, + { SPAR_MOUSE_CHANNEL_PROTOCOL_UUID, "mouse"}, + { NULL_UUID_LE, NULL } +}; +MODULE_DEVICE_TABLE(visorbus, visorinput_channel_types); +MODULE_ALIAS("visorbus:" SPAR_MOUSE_CHANNEL_PROTOCOL_UUID_STR); +MODULE_ALIAS("visorbus:" SPAR_KEYBOARD_CHANNEL_PROTOCOL_UUID_STR); + +/** This is used to tell the visor bus driver which types of visor devices + * we support, and what functions to call when a visor device that we support + * is attached or removed. + */ +static struct visor_driver visorinput_driver = { + .name = "visorinput", + .vertag = NULL, + .owner = THIS_MODULE, + .channel_types = visorinput_channel_types, + .probe = visorinput_probe, + .remove = visorinput_remove, + .channel_interrupt = visorinput_channel_interrupt, + .pause = visorinput_pause, + .resume = visorinput_resume, +}; + +enum visorinput_device_type { + visorinput_keyboard, + visorinput_mouse, +}; + +/* This is the private data that we store for each device. + * A pointer to this struct is maintained via + * dev_get_drvdata() / dev_set_drvdata() for each struct device. + */ +struct visorinput_devdata { + struct visor_device *dev; + /** lock for dev */ + struct rw_semaphore lock_visor_dev; + struct input_dev *visorinput_dev; + bool paused; +}; + +/* Borrowed from drivers/input/keyboard/atakbd.c */ +/* This maps 1-byte scancodes to keycodes. */ +static unsigned char visorkbd_keycode[256] = { /* American layout */ + [0] = KEY_GRAVE, + [1] = KEY_ESC, + [2] = KEY_1, + [3] = KEY_2, + [4] = KEY_3, + [5] = KEY_4, + [6] = KEY_5, + [7] = KEY_6, + [8] = KEY_7, + [9] = KEY_8, + [10] = KEY_9, + [11] = KEY_0, + [12] = KEY_MINUS, + [13] = KEY_EQUAL, + [14] = KEY_BACKSPACE, + [15] = KEY_TAB, + [16] = KEY_Q, + [17] = KEY_W, + [18] = KEY_E, + [19] = KEY_R, + [20] = KEY_T, + [21] = KEY_Y, + [22] = KEY_U, + [23] = KEY_I, + [24] = KEY_O, + [25] = KEY_P, + [26] = KEY_LEFTBRACE, + [27] = KEY_RIGHTBRACE, + [28] = KEY_ENTER, + [29] = KEY_LEFTCTRL, + [30] = KEY_A, + [31] = KEY_S, + [32] = KEY_D, + [33] = KEY_F, + [34] = KEY_G, + [35] = KEY_H, + [36] = KEY_J, + [37] = KEY_K, + [38] = KEY_L, + [39] = KEY_SEMICOLON, + [40] = KEY_APOSTROPHE, + [41] = KEY_GRAVE, /* FIXME, '#' */ + [42] = KEY_LEFTSHIFT, + [43] = KEY_BACKSLASH, /* FIXME, '~' */ + [44] = KEY_Z, + [45] = KEY_X, + [46] = KEY_C, + [47] = KEY_V, + [48] = KEY_B, + [49] = KEY_N, + [50] = KEY_M, + [51] = KEY_COMMA, + [52] = KEY_DOT, + [53] = KEY_SLASH, + [54] = KEY_RIGHTSHIFT, + [55] = KEY_KPASTERISK, + [56] = KEY_LEFTALT, + [57] = KEY_SPACE, + [58] = KEY_CAPSLOCK, + [59] = KEY_F1, + [60] = KEY_F2, + [61] = KEY_F3, + [62] = KEY_F4, + [63] = KEY_F5, + [64] = KEY_F6, + [65] = KEY_F7, + [66] = KEY_F8, + [67] = KEY_F9, + [68] = KEY_F10, + [69] = KEY_NUMLOCK, + [70] = KEY_SCROLLLOCK, + [71] = KEY_KP7, + [72] = KEY_KP8, + [73] = KEY_KP9, + [74] = KEY_KPMINUS, + [75] = KEY_KP4, + [76] = KEY_KP5, + [77] = KEY_KP6, + [78] = KEY_KPPLUS, + [79] = KEY_KP1, + [80] = KEY_KP2, + [81] = KEY_KP3, + [82] = KEY_KP0, + [83] = KEY_KPDOT, + [86] = KEY_102ND, /* enables UK backslash+pipe key, + * and FR lessthan+greaterthan key */ + [87] = KEY_F11, + [88] = KEY_F12, + [90] = KEY_KPLEFTPAREN, + [91] = KEY_KPRIGHTPAREN, + [92] = KEY_KPASTERISK, /* FIXME */ + [93] = KEY_KPASTERISK, + [94] = KEY_KPPLUS, + [95] = KEY_HELP, + [96] = KEY_KPENTER, + [97] = KEY_RIGHTCTRL, + [98] = KEY_KPSLASH, + [99] = KEY_KPLEFTPAREN, + [100] = KEY_KPRIGHTPAREN, + [101] = KEY_KPSLASH, + [102] = KEY_HOME, + [103] = KEY_UP, + [104] = KEY_PAGEUP, + [105] = KEY_LEFT, + [106] = KEY_RIGHT, + [107] = KEY_END, + [108] = KEY_DOWN, + [109] = KEY_PAGEDOWN, + [110] = KEY_INSERT, + [111] = KEY_DELETE, + [112] = KEY_MACRO, + [113] = KEY_MUTE +}; + +/* This maps the <xx> in extended scancodes of the form "0xE0 <xx>" into + * keycodes. + */ +static unsigned char visorkbd_ext_keycode[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */ + 0, 0, 0, 0, KEY_KPENTER, KEY_RIGHTCTRL, 0, 0, /* 0x18 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */ + KEY_RIGHTALT, 0, 0, 0, 0, 0, 0, 0, /* 0x28 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 */ + KEY_RIGHTALT /* AltGr */, 0, 0, 0, 0, 0, 0, 0, /* 0x38 */ + 0, 0, 0, 0, 0, 0, 0, KEY_HOME, /* 0x40 */ + KEY_UP, KEY_PAGEUP, 0, KEY_LEFT, 0, KEY_RIGHT, 0, KEY_END, /* 0x48 */ + KEY_DOWN, KEY_PAGEDOWN, KEY_INSERT, KEY_DELETE, 0, 0, 0, 0, /* 0x50 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x58 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */ +}; + +static struct visorinput_devdata * +devdata_create(struct visor_device *dev, enum visorinput_device_type devtype) +{ + struct visorinput_devdata *devdata = NULL; + + devdata = kzalloc(sizeof(*devdata), GFP_KERNEL); + if (!devdata) + return NULL; + devdata->dev = dev; + + /* This is an input device in a client guest partition, + * so we need to create whatever gizmos are necessary to + * deliver our inputs to the guest OS. + */ + switch (devtype) { + case visorinput_keyboard: + devdata->visorinput_dev = register_client_keyboard(); + if (!devdata->visorinput_dev) + goto cleanups_register; + break; + case visorinput_mouse: + devdata->visorinput_dev = register_client_mouse(); + if (!devdata->visorinput_dev) + goto cleanups_register; + break; + } + + init_rwsem(&devdata->lock_visor_dev); + + return devdata; + +cleanups_register: + kfree(devdata); + return NULL; +} + +static int +visorinput_probe(struct visor_device *dev) +{ + struct visorinput_devdata *devdata = NULL; + uuid_le guid; + enum visorinput_device_type devtype; + + guid = visorchannel_get_uuid(dev->visorchannel); + if (uuid_le_cmp(guid, spar_mouse_channel_protocol_uuid) == 0) + devtype = visorinput_mouse; + else if (uuid_le_cmp(guid, spar_keyboard_channel_protocol_uuid) == 0) + devtype = visorinput_keyboard; + else + return -ENODEV; + devdata = devdata_create(dev, devtype); + if (!devdata) + return -ENOMEM; + dev_set_drvdata(&dev->device, devdata); + visorbus_enable_channel_interrupts(dev); + return 0; +} + +static void +visorinput_remove(struct visor_device *dev) +{ + struct visorinput_devdata *devdata = dev_get_drvdata(&dev->device); + + if (!devdata) + return; + + visorbus_disable_channel_interrupts(dev); + + /* due to above, at this time no thread of execution will be + * in visorinput_channel_interrupt() + */ + + down_write(&devdata->lock_visor_dev); + dev_set_drvdata(&dev->device, NULL); + unregister_client_input(devdata->visorinput_dev); + up_write(&devdata->lock_visor_dev); + kfree(devdata); +} + +static void +unregister_client_input(struct input_dev *visorinput_dev) +{ + if (visorinput_dev) + input_unregister_device(visorinput_dev); +} + +/* register_client_keyboard() initializes and returns a Linux gizmo that we + * can use to deliver keyboard inputs to Linux. We of course do this when + * we see keyboard inputs coming in on a keyboard channel. + */ +static struct input_dev * +register_client_keyboard(void) +{ + int i, error; + struct input_dev *visorinput_dev = NULL; + + visorinput_dev = input_allocate_device(); + if (!visorinput_dev) + return NULL; + + visorinput_dev->name = "visor Keyboard"; + visorinput_dev->phys = "visorkbd:input0"; + visorinput_dev->id.bustype = BUS_HOST; + visorinput_dev->id.vendor = 0x0001; + visorinput_dev->id.product = 0x0001; + visorinput_dev->id.version = 0x0100; + + visorinput_dev->evbit[0] = BIT_MASK(EV_KEY) | + BIT_MASK(EV_REP) | + BIT_MASK(EV_LED); + visorinput_dev->ledbit[0] = BIT_MASK(LED_CAPSL) | + BIT_MASK(LED_SCROLLL) | + BIT_MASK(LED_NUML); + visorinput_dev->keycode = visorkbd_keycode; + visorinput_dev->keycodesize = sizeof(unsigned char); + visorinput_dev->keycodemax = ARRAY_SIZE(visorkbd_keycode); + + for (i = 1; i < ARRAY_SIZE(visorkbd_keycode); i++) + set_bit(visorkbd_keycode[i], visorinput_dev->keybit); + + for (i = 1; i < ARRAY_SIZE(visorkbd_ext_keycode); i++) + set_bit(visorkbd_ext_keycode[i], visorinput_dev->keybit); + + error = input_register_device(visorinput_dev); + if (error) { + input_free_device(visorinput_dev); + return NULL; + } + return visorinput_dev; +} + +static struct input_dev * +register_client_mouse(void) +{ + int error; + struct input_dev *visorinput_dev = NULL; + int xres, yres; + struct fb_info *fb0; + + visorinput_dev = input_allocate_device(); + if (!visorinput_dev) + return NULL; + + visorinput_dev->name = "visor Mouse"; + visorinput_dev->phys = "visormou:input0"; + visorinput_dev->id.bustype = BUS_HOST; + visorinput_dev->id.vendor = 0x0001; + visorinput_dev->id.product = 0x0002; + visorinput_dev->id.version = 0x0100; + + visorinput_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + set_bit(BTN_LEFT, visorinput_dev->keybit); + set_bit(BTN_RIGHT, visorinput_dev->keybit); + set_bit(BTN_MIDDLE, visorinput_dev->keybit); + + if (registered_fb[0]) { + fb0 = registered_fb[0]; + xres = fb0->var.xres_virtual; + yres = fb0->var.yres_virtual; + } else { + xres = PIXELS_ACROSS_DEFAULT; + yres = PIXELS_DOWN_DEFAULT; + } + input_set_abs_params(visorinput_dev, ABS_X, 0, xres, 0, 0); + input_set_abs_params(visorinput_dev, ABS_Y, 0, yres, 0, 0); + + error = input_register_device(visorinput_dev); + if (error) { + input_free_device(visorinput_dev); + return NULL; + } + + /* Sending top-left and bottom-right positions is ABSOLUTELY + * REQUIRED if we want X to move the mouse to the exact points + * we tell it. I have NO IDEA why. + */ + input_report_abs(visorinput_dev, ABS_X, 0); + input_report_abs(visorinput_dev, ABS_Y, 0); + input_sync(visorinput_dev); + input_report_abs(visorinput_dev, ABS_X, xres - 1); + input_report_abs(visorinput_dev, ABS_Y, yres - 1); + input_sync(visorinput_dev); + + input_set_capability(visorinput_dev, EV_REL, REL_WHEEL); + + return visorinput_dev; +} + +static void +do_key(struct input_dev *inpt, int keycode, int down) +{ + input_report_key(inpt, keycode, down); +} + +/* Make it so the current locking state of the locking key indicated by + * <keycode> is as indicated by <desired_state> (1=locked, 0=unlocked). + */ +static void +handle_locking_key(struct input_dev *visorinput_dev, + int keycode, int desired_state) +{ + int led; + char *sled; + + switch (keycode) { + case KEY_CAPSLOCK: + led = LED_CAPSL; + sled = "CAP"; + break; + case KEY_SCROLLLOCK: + led = LED_SCROLLL; + sled = "SCR"; + break; + case KEY_NUMLOCK: + led = LED_NUML; + sled = "NUM"; + break; + default: + led = -1; + break; + } + if (led >= 0) { + int old_state = (test_bit(led, visorinput_dev->led) != 0); + + if (old_state != desired_state) { + do_key(visorinput_dev, keycode, 1); + input_sync(visorinput_dev); + do_key(visorinput_dev, keycode, 0); + input_sync(visorinput_dev); + __change_bit(led, visorinput_dev->led); + } + } +} + +/* <scancode> is either a 1-byte scancode, or an extended 16-bit scancode + * with 0xE0 in the low byte and the extended scancode value in the next + * higher byte. + */ +static int +scancode_to_keycode(int scancode) +{ + int keycode; + + if (scancode > 0xff) + keycode = visorkbd_ext_keycode[(scancode >> 8) & 0xff]; + else + keycode = visorkbd_keycode[scancode]; + return keycode; +} + +static int +calc_button(int x) +{ + switch (x) { + case 1: + return BTN_LEFT; + case 2: + return BTN_MIDDLE; + case 3: + return BTN_RIGHT; + default: + return -1; + } +} + +/* This is used only when this driver is active as an input driver in the + * client guest partition. It is called periodically so we can obtain inputs + * from the channel, and deliver them to the guest OS. + */ +static void +visorinput_channel_interrupt(struct visor_device *dev) +{ + struct ultra_inputreport r; + int scancode, keycode; + struct input_dev *visorinput_dev; + int xmotion, ymotion, zmotion, button; + int i; + + struct visorinput_devdata *devdata = dev_get_drvdata(&dev->device); + + if (!devdata) + return; + + down_write(&devdata->lock_visor_dev); + if (devdata->paused) /* don't touch device/channel when paused */ + goto out_locked; + + visorinput_dev = devdata->visorinput_dev; + if (!visorinput_dev) + goto out_locked; + + while (visorchannel_signalremove(dev->visorchannel, 0, &r)) { + scancode = r.activity.arg1; + keycode = scancode_to_keycode(scancode); + switch (r.activity.action) { + case inputaction_key_down: + do_key(visorinput_dev, keycode, 1); + input_sync(visorinput_dev); + break; + case inputaction_key_up: + do_key(visorinput_dev, keycode, 0); + input_sync(visorinput_dev); + break; + case inputaction_key_down_up: + do_key(visorinput_dev, keycode, 1); + input_sync(visorinput_dev); + do_key(visorinput_dev, keycode, 0); + input_sync(visorinput_dev); + break; + case inputaction_set_locking_key_state: + handle_locking_key(visorinput_dev, keycode, + r.activity.arg2); + break; + case inputaction_xy_motion: + xmotion = r.activity.arg1; + ymotion = r.activity.arg2; + input_report_abs(visorinput_dev, ABS_X, xmotion); + input_report_abs(visorinput_dev, ABS_Y, ymotion); + input_sync(visorinput_dev); + break; + case inputaction_mouse_button_down: + button = calc_button(r.activity.arg1); + if (button < 0) + break; + input_report_key(visorinput_dev, button, 1); + input_sync(visorinput_dev); + break; + case inputaction_mouse_button_up: + button = calc_button(r.activity.arg1); + if (button < 0) + break; + input_report_key(visorinput_dev, button, 0); + input_sync(visorinput_dev); + break; + case inputaction_mouse_button_click: + button = calc_button(r.activity.arg1); + if (button < 0) + break; + input_report_key(visorinput_dev, button, 1); + + input_sync(visorinput_dev); + input_report_key(visorinput_dev, button, 0); + input_sync(visorinput_dev); + break; + case inputaction_mouse_button_dclick: + button = calc_button(r.activity.arg1); + if (button < 0) + break; + for (i = 0; i < 2; i++) { + input_report_key(visorinput_dev, button, 1); + input_sync(visorinput_dev); + input_report_key(visorinput_dev, button, 0); + input_sync(visorinput_dev); + } + break; + case inputaction_wheel_rotate_away: + zmotion = r.activity.arg1; + input_report_rel(visorinput_dev, REL_WHEEL, 1); + input_sync(visorinput_dev); + break; + case inputaction_wheel_rotate_toward: + zmotion = r.activity.arg1; + input_report_rel(visorinput_dev, REL_WHEEL, -1); + input_sync(visorinput_dev); + break; + } + } +out_locked: + up_write(&devdata->lock_visor_dev); +} + +static int +visorinput_pause(struct visor_device *dev, + visorbus_state_complete_func complete_func) +{ + int rc; + struct visorinput_devdata *devdata = dev_get_drvdata(&dev->device); + + if (!devdata) { + rc = -ENODEV; + goto out; + } + + down_write(&devdata->lock_visor_dev); + if (devdata->paused) { + rc = -EBUSY; + goto out_locked; + } + devdata->paused = true; + complete_func(dev, 0); + rc = 0; +out_locked: + up_write(&devdata->lock_visor_dev); +out: + return rc; +} + +static int +visorinput_resume(struct visor_device *dev, + visorbus_state_complete_func complete_func) +{ + int rc; + struct visorinput_devdata *devdata = dev_get_drvdata(&dev->device); + + if (!devdata) { + rc = -ENODEV; + goto out; + } + down_write(&devdata->lock_visor_dev); + if (!devdata->paused) { + rc = -EBUSY; + goto out_locked; + } + devdata->paused = false; + complete_func(dev, 0); + rc = 0; +out_locked: + up_write(&devdata->lock_visor_dev); +out: + return rc; +} + +static int +visorinput_init(void) +{ + return visorbus_register_visor_driver(&visorinput_driver); +} + +static void +visorinput_cleanup(void) +{ + visorbus_unregister_visor_driver(&visorinput_driver); +} + +module_init(visorinput_init); +module_exit(visorinput_cleanup); + +MODULE_AUTHOR("Unisys"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("s-Par human input driver for guest Linux"); +MODULE_VERSION(VERSION); -- 2.1.4 _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel