[PATCH] staging: unisys: add visorhid driver
Greg KH
gregkh at linuxfoundation.org
Wed Jul 15 01:48:51 UTC 2015
On Thu, Jun 25, 2015 at 09:58:51AM -0400, Benjamin Romer wrote:
> From: Erik Arfvidson <erik.arfvidson at unisys.com>
>
> This driver provides mouse and keyboard input to Unisys s-Par
> Partition Desktop application. This device is created by the
> visorbus device.
>
> Signed-off-by: Erik Arfvidson <erik.arfvidson at unisys.com>
> Signed-off-by: Benjamin Romer <benjamin.romer at unisys.com>
> ---
> drivers/staging/unisys/Kconfig | 1 +
> drivers/staging/unisys/Makefile | 1 +
> 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 | 32 +
> drivers/staging/unisys/visorhid/ultrainputreport.h | 82 +++
> drivers/staging/unisys/visorhid/visorhid.c | 798 +++++++++++++++++++++
> 8 files changed, 963 insertions(+)
> create mode 100644 drivers/staging/unisys/visorhid/Kconfig
> create mode 100644 drivers/staging/unisys/visorhid/Makefile
> create mode 100644 drivers/staging/unisys/visorhid/keyboardchannel.h
> create mode 100644 drivers/staging/unisys/visorhid/mousechannel.h
> create mode 100644 drivers/staging/unisys/visorhid/ultrainputreport.h
> create mode 100644 drivers/staging/unisys/visorhid/visorhid.c
>
> diff --git a/drivers/staging/unisys/Kconfig b/drivers/staging/unisys/Kconfig
> index 778f9d0..bdc8ba8 100644
> --- a/drivers/staging/unisys/Kconfig
> +++ b/drivers/staging/unisys/Kconfig
> @@ -13,5 +13,6 @@ if UNISYSSPAR
>
> source "drivers/staging/unisys/visorbus/Kconfig"
> source "drivers/staging/unisys/visornic/Kconfig"
> +source "drivers/staging/unisys/visorhid/Kconfig"
>
> endif # UNISYSSPAR
> diff --git a/drivers/staging/unisys/Makefile b/drivers/staging/unisys/Makefile
> index a515ebc..d071094 100644
> --- a/drivers/staging/unisys/Makefile
> +++ b/drivers/staging/unisys/Makefile
> @@ -3,3 +3,4 @@
> #
> obj-$(CONFIG_UNISYS_VISORBUS) += visorbus/
> obj-$(CONFIG_UNISYS_VISORNIC) += visornic/
> +obj-$(CONFIG_UNISYS_VISORHID) += visorhid/
> diff --git a/drivers/staging/unisys/visorhid/Kconfig b/drivers/staging/unisys/visorhid/Kconfig
> new file mode 100644
> index 0000000..3b83e2c
> --- /dev/null
> +++ b/drivers/staging/unisys/visorhid/Kconfig
> @@ -0,0 +1,10 @@
> +#
> +# 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
> new file mode 100644
> index 0000000..e457bd1
> --- /dev/null
> +++ b/drivers/staging/unisys/visorhid/Makefile
> @@ -0,0 +1,7 @@
> +#
> +# 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
> new file mode 100644
> index 0000000..0722c60
> --- /dev/null
> +++ b/drivers/staging/unisys/visorhid/keyboardchannel.h
> @@ -0,0 +1,32 @@
> +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION
> + * All rights reserved.
2013?
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or (at
> + * your option) any later version.
I have to ask, do you really mean "any later version"?
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
> + * NON INFRINGEMENT. See the GNU General Public License for more
> + * details.
> + */
> +
> +#ifndef __KEYBOARDCHANNEL_H__
> +#define __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_VERSIONID 1
> +#define KEYBOARD_MAXINPUTREPORTS 50
> +
> +#endif
> diff --git a/drivers/staging/unisys/visorhid/mousechannel.h b/drivers/staging/unisys/visorhid/mousechannel.h
> new file mode 100644
> index 0000000..ac6883b
> --- /dev/null
> +++ b/drivers/staging/unisys/visorhid/mousechannel.h
> @@ -0,0 +1,32 @@
> +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION
> + * All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or (at
> + * your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
> + * NON INFRINGEMENT. See the GNU General Public License for more
> + * details.
> + */
> +
> +#ifndef __MOUSECHANNEL_H__
> +#define __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_VERSIONID 1
> +#define MOUSE_MAXINPUTREPORTS 50
> +
> +#endif
> diff --git a/drivers/staging/unisys/visorhid/ultrainputreport.h b/drivers/staging/unisys/visorhid/ultrainputreport.h
> new file mode 100644
> index 0000000..4cd75cc
> --- /dev/null
> +++ b/drivers/staging/unisys/visorhid/ultrainputreport.h
> @@ -0,0 +1,82 @@
> +/* Copyright (C) 2010 - 2013 UNISYS CORPORATION
> + * All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or (at
> + * your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
> + * NON INFRINGEMENT. See the GNU General Public License for more
> + * details.
> + */
> +
> +#ifndef __ULTRAINPUTREPORT_H__
> +#define __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,
> + 4, * 5 */
> + inputaction_mouse_button_up = 3, /*< arg1: 1=left, 2=center, 3=right,
> + 4,* 5 */
Very odd comment style, it's not readable at all. I think you ran this
through some script...
> + inputaction_mouse_button_click = 4, /*< arg1: 1=left, 2=center, 3=right,
> + * 4, 5 */
> + inputaction_mouse_button_dclick = 5, /*< arg1: 1=left, 2=center,
> + 3=right, * 4, 5 */
> + 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
> new file mode 100644
> index 0000000..7384bef
> --- /dev/null
> +++ b/drivers/staging/unisys/visorhid/visorhid.c
> @@ -0,0 +1,798 @@
> +/* visorhid.c
> + *
> + * Copyright (C) 2011 - 2014 UNISYS CORPORATION
> + * All rights reserved.
2014?
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or (at
> + * your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, 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/serio.h>
> +#include <linux/uaccess.h>
> +
> +#include <asm/segment.h>
> +
> +#include "keyboardchannel.h"
> +#include "mousechannel.h"
> +#include "version.h"
> +#include "visorbus.h"
> +
> +#define MAXDEVICES 16384
That's a lot of devices, do you really mean it?
> +#define PIXELS_ACROSS_DEFAULT 800
> +#define PIXELS_DOWN_DEFAULT 600
> +#define DEV_NAME_SIZE 99
No tabs for indenting?
> +#define SYSFS_VIRTUALSIZE "/sys/class/graphics/fb0/virtual_size"
I really hate to even look as to why you have a full sysfs path in a
#define in a kernel file. Luckily I don't see it used anywhere, please
remove it.
> +
> +static spinlock_t devnopool_lock;
> +static void *dev_no_pool; /* < pool to grab device numbers from */
What is up with the '<' character in comments?
> +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 struct input_dev *register_client_wheel(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[] = {
> + {
> + .guid = SPAR_KEYBOARD_CHANNEL_PROTOCOL_UUID,
> + .name = "keyboard"
> + },
> + {
> + .guid = SPAR_MOUSE_CHANNEL_PROTOCOL_UUID,
> + .name = "mouse"
> + },
> + {
> + .guid = NULL_UUID_LE,
> + .name = NULL
> + }
> +};
> +
> +/** 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",
> + .version = VERSION,
Why do we care about "versions"?
> + .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,
> +};
> +
> +/* This is the private data that we store for each device.
> + * A pointer to this struct is kept in each "struct device"
Why isn't this embedded in a struct device?
> + */
> +struct visorhid_devdata {
> + int devno;
> + struct visor_device *dev;
> + /** lock for dev */
> + struct rw_semaphore lock_visor_dev;
> + char name[DEV_NAME_SIZE];
Why duplicate the name, why can't you use the struct device?
> + struct list_head list_all; /* < link within list_all_devices list */
> + struct kref kref;
You don't use this reference at all, why even have it?
> + struct input_dev *visorinput_dev;
> + struct input_dev *visorinput_dev2;
> + bool supported_client_device;
> + bool paused;
> +};
> +
> + /* List of all visorhid_devdata structs,
> + * linked via the list_all member
> + */
> +static LIST_HEAD(list_all_devices);
> +static DEFINE_SPINLOCK(lock_all_devices);
> +
> +/* 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,
> + [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 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, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 */
> + 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)
> +{
> + struct visorhid_devdata *devdata = NULL;
> + int devno = -1;
> + uuid_le guid;
> +
> + guid = visorchannel_get_uuid(dev->visorchannel);
> + devdata = kzalloc(sizeof(*devdata),
> + GFP_KERNEL | __GFP_NORETRY);
> + if (!devdata)
> + goto cleanups;
> +
> + spin_lock(&devnopool_lock);
> + devno = find_first_zero_bit(dev_no_pool, MAXDEVICES);
> + spin_unlock(&devnopool_lock);
Why not use an idr or ida structure? Much simpler, easier, and correct.
> + if (devno == MAXDEVICES)
> + goto cleanups_set_bit;
> + set_bit(devno, dev_no_pool);
> + devdata->devno = devno;
> + devdata->dev = dev;
> + strncpy(devdata->name, dev_name(&dev->device), sizeof(devdata->name));
Again, why is this needed?
> +
> + /* 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.
> + */
> + if (!uuid_le_cmp(guid, spar_keyboard_channel_protocol_uuid)) {
> + devdata->visorinput_dev = register_client_keyboard();
> + if (!devdata->visorinput_dev)
> + goto cleanups_register;
> + devdata->supported_client_device = true;
> + } else if (!uuid_le_cmp(guid, spar_mouse_channel_protocol_uuid)) {
> + devdata->visorinput_dev = register_client_mouse();
> + if (!devdata->visorinput_dev)
> + goto cleanups_register2;
> + devdata->visorinput_dev2 = register_client_wheel();
> + if (!devdata->visorinput_dev2)
> + goto cleanups_register2;
> + devdata->supported_client_device = true;
> + }
> +
> + init_rwsem(&devdata->lock_visor_dev);
> + kref_init(&devdata->kref);
> +
> + spin_lock(&lock_all_devices);
> + list_add_tail(&devdata->list_all, &list_all_devices);
> + spin_unlock(&lock_all_devices);
> + return devdata;
> +
> +cleanups_register2:
> + unregister_client_input(devdata->visorinput_dev);
> + devdata->visorinput_dev = NULL;
> +cleanups_register:
> + clear_bit(devno, dev_no_pool);
> +cleanups_set_bit:
> + kfree(devdata);
> +cleanups:
> + return NULL;
> +}
> +
> +static void
> +devdata_release(struct kref *mykref)
> +{
> + struct visorhid_devdata *devdata =
> + container_of(mykref, struct visorhid_devdata, kref);
> + clear_bit(devdata->devno, dev_no_pool);
> + spin_lock(&lock_all_devices);
> + list_del(&devdata->list_all);
> + spin_unlock(&lock_all_devices);
> +}
> +
> +static int
> +visorhid_probe(struct visor_device *dev)
> +{
> + int rc = 0;
> + struct visorhid_devdata *devdata = NULL;
> + uuid_le guid;
> +
> + devdata = devdata_create(dev);
> + if (!devdata) {
> + rc = -1;
> + goto cleanups;
> + }
> + dev_set_drvdata(&dev->device, devdata);
> + guid = visorchannel_get_uuid(dev->visorchannel);
> + if (uuid_le_cmp(guid, spar_mouse_channel_protocol_uuid) &&
> + uuid_le_cmp(guid, spar_keyboard_channel_protocol_uuid)) {
> + rc = -1;
> + goto cleanups;
> + }
> +
> + if (devdata->supported_client_device)
> + visorbus_enable_channel_interrupts(dev);
> +
> +cleanups:
> + if (rc < 0) {
> + if (devdata)
> + kref_put(&devdata->kref, devdata_release);
> + }
> + return rc;
> +}
> +
> +static void
> +host_side_disappeared(struct visorhid_devdata *devdata)
> +{
> + down_write(&devdata->lock_visor_dev);
> + sprintf(devdata->name, "<dev#%d-history>", devdata->devno);
> + devdata->dev = NULL; /* indicate device destroyed */
> + up_write(&devdata->lock_visor_dev);
> +}
> +
> +static void
> +visorhid_remove(struct visor_device *dev)
> +{
> + struct visorhid_devdata *devdata = dev_get_drvdata(&dev->device);
> +
> + if (!devdata)
> + return;
> +
> + dev_set_drvdata(&dev->device, NULL);
> + host_side_disappeared(devdata);
> + unregister_client_input(devdata->visorinput_dev);
> + devdata->visorinput_dev = NULL;
> + unregister_client_input(devdata->visorinput_dev2);
> + devdata->visorinput_dev2 = NULL;
> + kref_put(&devdata->kref, devdata_release);
> +}
> +
> +static void
> +visorhid_cleanup_guts(void)
> +{
> + visorbus_unregister_visor_driver(&visorhid_driver);
> + kfree(dev_no_pool);
> + dev_no_pool = NULL;
> +}
> +
> +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";
Shouldn't that be "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);
> +
> + 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";
/me hands you a some extra "me" characters...
Again, s/\//\!/g
> + 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_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);
> +
> + return visorinput_dev;
> +}
> +
> +static struct input_dev *
> +register_client_wheel(void)
> +{
> + int error;
> + struct input_dev *visorinput_dev = NULL;
> +
> + visorinput_dev = input_allocate_device();
> + if (!visorinput_dev)
> + return NULL;
> +
> + visorinput_dev->name = "visor Wheel";
> + visorinput_dev->phys = "visorwhl/input0";
Same '!' issue.
> + visorinput_dev->id.bustype = BUS_HOST;
> + visorinput_dev->id.vendor = 0x0001;
> + visorinput_dev->id.product = 0x0001;
> + visorinput_dev->id.version = 0x0100;
> +
> + /* We need to lie a little to prevent the evdev driver "Don't
> + * know how to use device" error. (evdev erroneously thinks
> + * that a device without an X and Y axis is useless.)
> + */
> + visorinput_dev->evbit[0] = BIT_MASK(EV_REL) |
> + /*lie */ BIT_MASK(EV_KEY);
> + visorinput_dev->relbit[0] = BIT_MASK(REL_WHEEL) |
> + /*lie */ BIT_MASK(REL_X) |
> + /*lie */ BIT_MASK(REL_Y);
> + set_bit(BTN_LEFT, visorinput_dev->keybit); /*lie */
> + set_bit(BTN_RIGHT, visorinput_dev->keybit); /*lie */
> + set_bit(BTN_MIDDLE, visorinput_dev->keybit); /*lie */
> +
> + error = input_register_device(visorinput_dev);
> + if (error) {
> + input_free_device(visorinput_dev);
> + return NULL;
> + }
> + 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);
> + 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 = 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;
> + struct input_dev *visorinput_dev2;
> + 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;
> +
> + visorinput_dev2 = devdata->visorinput_dev2;
> + 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);
> + 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:
> + if (!visorinput_dev2)
> + goto out_locked;
> + zmotion = r.activity.arg1;
> + input_report_rel(visorinput_dev2, REL_WHEEL, 1);
> + input_sync(visorinput_dev2);
> + break;
> + case inputaction_wheel_rotate_toward:
> + if (!visorinput_dev2)
> + goto out_locked;
> + zmotion = r.activity.arg1;
> + input_report_rel(visorinput_dev2, REL_WHEEL, -1);
> + input_sync(visorinput_dev2);
> + 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)
> +{
> + int rc = 0;
> +
> + spin_lock_init(&devnopool_lock);
> + dev_no_pool = kzalloc(BITS_TO_LONGS(MAXDEVICES), GFP_KERNEL);
Again, use an idr/ida structure instead please.
> + if (!dev_no_pool) {
> + rc = -ENOMEM;
> + goto cleanups;
> + }
> + visorbus_register_visor_driver(&visorhid_driver);
No error checking?
greg k-h
More information about the devel
mailing list