Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 227083
b: refs/heads/master
c: 49cc69b
h: refs/heads/master
i:
  227081: af69fa3
  227079: f19c033
v: v3
  • Loading branch information
Axel Lin authored and Dmitry Torokhov committed Nov 12, 2010
1 parent 184e3c8 commit 25c3f42
Show file tree
Hide file tree
Showing 16 changed files with 143 additions and 540 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 7b4b30689d688d9ca2e5c3859db6bbe1c35e6014
refs/heads/master: 49cc69b6789b57d2d8ed78843c4219525b433b58
169 changes: 45 additions & 124 deletions trunk/drivers/char/sysrq.c
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ EXPORT_SYMBOL(handle_sysrq);
#ifdef CONFIG_INPUT

/* Simple translation table for the SysRq keys */
static const unsigned char sysrq_xlate[KEY_CNT] =
static const unsigned char sysrq_xlate[KEY_MAX + 1] =
"\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
"qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
"dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
Expand All @@ -563,158 +563,82 @@ static const unsigned char sysrq_xlate[KEY_CNT] =
"230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
"\r\000/"; /* 0x60 - 0x6f */

struct sysrq_state {
struct input_handle handle;
struct work_struct reinject_work;
unsigned long key_down[BITS_TO_LONGS(KEY_CNT)];
unsigned int alt;
unsigned int alt_use;
bool active;
bool need_reinject;
};

static void sysrq_reinject_alt_sysrq(struct work_struct *work)
{
struct sysrq_state *sysrq =
container_of(work, struct sysrq_state, reinject_work);
struct input_handle *handle = &sysrq->handle;
unsigned int alt_code = sysrq->alt_use;

if (sysrq->need_reinject) {
/* Simulate press and release of Alt + SysRq */
input_inject_event(handle, EV_KEY, alt_code, 1);
input_inject_event(handle, EV_KEY, KEY_SYSRQ, 1);
input_inject_event(handle, EV_SYN, SYN_REPORT, 1);

input_inject_event(handle, EV_KEY, KEY_SYSRQ, 0);
input_inject_event(handle, EV_KEY, alt_code, 0);
input_inject_event(handle, EV_SYN, SYN_REPORT, 1);
}
}
static bool sysrq_down;
static int sysrq_alt_use;
static int sysrq_alt;
static DEFINE_SPINLOCK(sysrq_event_lock);

static bool sysrq_filter(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
static bool sysrq_filter(struct input_handle *handle, unsigned int type,
unsigned int code, int value)
{
struct sysrq_state *sysrq = handle->private;
bool was_active = sysrq->active;
bool suppress;

switch (type) {
/* We are called with interrupts disabled, just take the lock */
spin_lock(&sysrq_event_lock);

case EV_SYN:
suppress = false;
break;
if (type != EV_KEY)
goto out;

case EV_KEY:
switch (code) {
switch (code) {

case KEY_LEFTALT:
case KEY_RIGHTALT:
if (!value) {
/* One of ALTs is being released */
if (sysrq->active && code == sysrq->alt_use)
sysrq->active = false;
case KEY_LEFTALT:
case KEY_RIGHTALT:
if (value)
sysrq_alt = code;
else {
if (sysrq_down && code == sysrq_alt_use)
sysrq_down = false;

sysrq->alt = KEY_RESERVED;

} else if (value != 2) {
sysrq->alt = code;
sysrq->need_reinject = false;
}
break;

case KEY_SYSRQ:
if (value == 1 && sysrq->alt != KEY_RESERVED) {
sysrq->active = true;
sysrq->alt_use = sysrq->alt;
/*
* If nothing else will be pressed we'll need
* to * re-inject Alt-SysRq keysroke.
*/
sysrq->need_reinject = true;
}

/*
* Pretend that sysrq was never pressed at all. This
* is needed to properly handle KGDB which will try
* to release all keys after exiting debugger. If we
* do not clear key bit it KGDB will end up sending
* release events for Alt and SysRq, potentially
* triggering print screen function.
*/
if (sysrq->active)
clear_bit(KEY_SYSRQ, handle->dev->key);

break;

default:
if (sysrq->active && value && value != 2) {
sysrq->need_reinject = false;
__handle_sysrq(sysrq_xlate[code], true);
}
break;
sysrq_alt = 0;
}
break;

suppress = sysrq->active;

if (!sysrq->active) {
/*
* If we are not suppressing key presses keep track of
* keyboard state so we can release keys that have been
* pressed before entering SysRq mode.
*/
if (value)
set_bit(code, sysrq->key_down);
else
clear_bit(code, sysrq->key_down);

if (was_active)
schedule_work(&sysrq->reinject_work);

} else if (value == 0 &&
test_and_clear_bit(code, sysrq->key_down)) {
/*
* Pass on release events for keys that was pressed before
* entering SysRq mode.
*/
suppress = false;
case KEY_SYSRQ:
if (value == 1 && sysrq_alt) {
sysrq_down = true;
sysrq_alt_use = sysrq_alt;
}
break;

default:
suppress = sysrq->active;
if (sysrq_down && value && value != 2)
__handle_sysrq(sysrq_xlate[code], true);
break;
}

out:
suppress = sysrq_down;
spin_unlock(&sysrq_event_lock);

return suppress;
}

static int sysrq_connect(struct input_handler *handler,
struct input_dev *dev,
const struct input_device_id *id)
{
struct sysrq_state *sysrq;
struct input_handle *handle;
int error;

sysrq = kzalloc(sizeof(struct sysrq_state), GFP_KERNEL);
if (!sysrq)
return -ENOMEM;
sysrq_down = false;
sysrq_alt = 0;

INIT_WORK(&sysrq->reinject_work, sysrq_reinject_alt_sysrq);
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
if (!handle)
return -ENOMEM;

sysrq->handle.dev = dev;
sysrq->handle.handler = handler;
sysrq->handle.name = "sysrq";
sysrq->handle.private = sysrq;
handle->dev = dev;
handle->handler = handler;
handle->name = "sysrq";

error = input_register_handle(&sysrq->handle);
error = input_register_handle(handle);
if (error) {
pr_err("Failed to register input sysrq handler, error %d\n",
error);
goto err_free;
}

error = input_open_device(&sysrq->handle);
error = input_open_device(handle);
if (error) {
pr_err("Failed to open input device, error %d\n", error);
goto err_unregister;
Expand All @@ -723,20 +647,17 @@ static int sysrq_connect(struct input_handler *handler,
return 0;

err_unregister:
input_unregister_handle(&sysrq->handle);
input_unregister_handle(handle);
err_free:
kfree(sysrq);
kfree(handle);
return error;
}

static void sysrq_disconnect(struct input_handle *handle)
{
struct sysrq_state *sysrq = handle->private;

input_close_device(handle);
cancel_work_sync(&sysrq->reinject_work);
input_unregister_handle(handle);
kfree(sysrq);
kfree(handle);
}

/*
Expand Down
113 changes: 55 additions & 58 deletions trunk/drivers/input/evdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -534,73 +534,76 @@ static int handle_eviocgbit(struct input_dev *dev,
}
#undef OLD_KEY_MAX

static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p)
static int evdev_handle_get_keycode(struct input_dev *dev,
void __user *p, size_t size)
{
struct input_keymap_entry ke = {
.len = sizeof(unsigned int),
.flags = 0,
};
int __user *ip = (int __user *)p;
struct input_keymap_entry ke;
int error;

/* legacy case */
if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
return -EFAULT;
memset(&ke, 0, sizeof(ke));

error = input_get_keycode(dev, &ke);
if (error)
return error;
if (size == sizeof(unsigned int[2])) {
/* legacy case */
int __user *ip = (int __user *)p;

if (put_user(ke.keycode, ip + 1))
return -EFAULT;
if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
return -EFAULT;

return 0;
}
ke.len = sizeof(unsigned int);
ke.flags = 0;

static int evdev_handle_get_keycode_v2(struct input_dev *dev, void __user *p)
{
struct input_keymap_entry ke;
int error;
error = input_get_keycode(dev, &ke);
if (error)
return error;

if (copy_from_user(&ke, p, sizeof(ke)))
return -EFAULT;
if (put_user(ke.keycode, ip + 1))
return -EFAULT;

error = input_get_keycode(dev, &ke);
if (error)
return error;
} else {
size = min(size, sizeof(ke));

if (copy_to_user(p, &ke, sizeof(ke)))
return -EFAULT;
if (copy_from_user(&ke, p, size))
return -EFAULT;

error = input_get_keycode(dev, &ke);
if (error)
return error;

if (copy_to_user(p, &ke, size))
return -EFAULT;
}
return 0;
}

static int evdev_handle_set_keycode(struct input_dev *dev, void __user *p)
static int evdev_handle_set_keycode(struct input_dev *dev,
void __user *p, size_t size)
{
struct input_keymap_entry ke = {
.len = sizeof(unsigned int),
.flags = 0,
};
int __user *ip = (int __user *)p;
struct input_keymap_entry ke;

if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
return -EFAULT;
memset(&ke, 0, sizeof(ke));

if (get_user(ke.keycode, ip + 1))
return -EFAULT;
if (size == sizeof(unsigned int[2])) {
/* legacy case */
int __user *ip = (int __user *)p;

return input_set_keycode(dev, &ke);
}
if (copy_from_user(ke.scancode, p, sizeof(unsigned int)))
return -EFAULT;

static int evdev_handle_set_keycode_v2(struct input_dev *dev, void __user *p)
{
struct input_keymap_entry ke;
if (get_user(ke.keycode, ip + 1))
return -EFAULT;

if (copy_from_user(&ke, p, sizeof(ke)))
return -EFAULT;
ke.len = sizeof(unsigned int);
ke.flags = 0;

if (ke.len > sizeof(ke.scancode))
return -EINVAL;
} else {
size = min(size, sizeof(ke));

if (copy_from_user(&ke, p, size))
return -EFAULT;

if (ke.len > sizeof(ke.scancode))
return -EINVAL;
}

return input_set_keycode(dev, &ke);
}
Expand Down Expand Up @@ -666,18 +669,6 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
return evdev_grab(evdev, client);
else
return evdev_ungrab(evdev, client);

case EVIOCGKEYCODE:
return evdev_handle_get_keycode(dev, p);

case EVIOCSKEYCODE:
return evdev_handle_set_keycode(dev, p);

case EVIOCGKEYCODE_V2:
return evdev_handle_get_keycode_v2(dev, p);

case EVIOCSKEYCODE_V2:
return evdev_handle_set_keycode_v2(dev, p);
}

size = _IOC_SIZE(cmd);
Expand Down Expand Up @@ -717,6 +708,12 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
return -EFAULT;

return error;

case EVIOC_MASK_SIZE(EVIOCGKEYCODE):
return evdev_handle_get_keycode(dev, p, size);

case EVIOC_MASK_SIZE(EVIOCSKEYCODE):
return evdev_handle_set_keycode(dev, p, size);
}

/* Multi-number variable-length handlers */
Expand Down
Loading

0 comments on commit 25c3f42

Please sign in to comment.