Merge android-4.14.109 (80571db
) into msm-4.14
* refs/heads/tmp-80571db: Revert "ANDROID: input: keychord: Add keychord driver" Revert "ANDROID: input: keychord: log when keychord triggered" Revert "ANDROID: input: keychord: Fix a slab out-of-bounds read." Revert "ANDROID: input: keychord: Fix races in keychord_write." Revert "ANDROID: input: keychord: Fix for a memory leak in keychord." ANDROID: drop CONFIG_INPUT_KEYCHORD from cuttlefish UPSTREAM: filemap: add a comment about FAULT_FLAG_RETRY_NOWAIT behavior BACKPORT: filemap: drop the mmap_sem for all blocking operations BACKPORT: filemap: kill page_cache_read usage in filemap_fault UPSTREAM: filemap: pass vm_fault to the mmap ra helpers ANDROID: Remove Android paranoid check for socket creation BACKPORT: mm/debug.c: provide useful debugging information for VM_BUG UPSTREAM: x86/alternative: Print unadorned pointers UPSTREAM: trace_uprobe: Display correct offset in uprobe_events UPSTREAM: usercopy: Remove pointer from overflow report UPSTREAM: Do not hash userspace addresses in fault handlers UPSTREAM: mm/slab.c: do not hash pointers when debugging slab UPSTREAM: kasan: use %px to print addresses instead of %p UPSTREAM: vsprintf: add printk specifier %px UPSTREAM: printk: hash addresses printed with %p UPSTREAM: vsprintf: refactor %pK code out of pointer() UPSTREAM: docs: correct documentation for %pK ANDROID: binder: remove extra declaration left after backport FROMGIT: binder: fix BUG_ON found by selinux-testsuite Linux 4.14.109 ath10k: avoid possible string overflow power: supply: charger-manager: Fix incorrect return value pwm-backlight: Enable/disable the PWM before/after LCD enable toggle. sched/cpufreq/schedutil: Fix error path mutex unlock rtc: Fix overflow when converting time64_t to rtc_time PCI: endpoint: Use EPC's device in dma_alloc_coherent()/dma_free_coherent() PCI: designware-ep: Read-only registers need DBI_RO_WR_EN to be writable PCI: designware-ep: dw_pcie_ep_set_msi() should only set MMC bits scsi: ufs: fix wrong command type of UTRD for UFSHCI v2.1 USB: core: only clean up what we allocated lib/int_sqrt: optimize small argument ALSA: hda - Enforces runtime_resume after S3 and S4 for each codec ALSA: hda - Record the current power state before suspend/resume calls locking/lockdep: Add debug_locks check in __lock_downgrade() x86/unwind: Add hardcoded ORC entry for NULL x86/unwind: Handle NULL pointer calls better in frame unwinder netfilter: ebtables: remove BUGPRINT messages drm: Reorder set_property_atomic to avoid returning with an active ww_ctx Bluetooth: hci_ldisc: Postpone HCI_UART_PROTO_READY bit set in hci_uart_set_proto() Bluetooth: hci_ldisc: Initialize hci_dev before open() Bluetooth: Fix decrementing reference count twice in releasing socket Bluetooth: hci_uart: Check if socket buffer is ERR_PTR in h4_recv_buf() media: v4l2-ctrls.c/uvc: zero v4l2_event ext4: brelse all indirect buffer in ext4_ind_remove_space() ext4: fix data corruption caused by unaligned direct AIO ext4: fix NULL pointer dereference while journal is aborted ALSA: x86: Fix runtime PM for hdmi-lpe-audio objtool: Move objtool_file struct off the stack perf probe: Fix getting the kernel map futex: Ensure that futex address is aligned in handle_futex_death() scsi: ibmvscsi: Fix empty event pool access during host removal scsi: ibmvscsi: Protect ibmvscsi_head from concurrent modificaiton MIPS: Fix kernel crash for R6 in jump label branch function MIPS: Ensure ELF appended dtb is relocated mips: loongson64: lemote-2f: Add IRQF_NO_SUSPEND to "cascade" irqaction. udf: Fix crash on IO error during truncate libceph: wait for latest osdmap in ceph_monc_blacklist_add() iommu/amd: fix sg->dma_address for sg->offset bigger than PAGE_SIZE drm/vmwgfx: Don't double-free the mode stored in par->set_mode mmc: pxamci: fix enum type confusion ANDROID: dm-bow: Fix 32 bit compile errors ANDROID: Add dm-bow to cuttlefish configuration UPSTREAM: binder: fix handling of misaligned binder object UPSTREAM: binder: fix sparse issue in binder_alloc_selftest.c BACKPORT: binder: use userspace pointer as base of buffer space UPSTREAM: binder: fix kerneldoc header for struct binder_buffer BACKPORT: binder: remove user_buffer_offset UPSTREAM: binder: remove kernel vm_area for buffer space UPSTREAM: binder: avoid kernel vm_area for buffer fixups BACKPORT: binder: add function to copy binder object from buffer BACKPORT: binder: add functions to copy to/from binder buffers UPSTREAM: binder: create userspace-to-binder-buffer copy function ANDROID: dm-bow: backport to 4.14 ANDROID: dm-bow: Add dm-bow feature f2fs: set pin_file under CAP_SYS_ADMIN f2fs: fix to avoid deadlock in f2fs_read_inline_dir() f2fs: fix to adapt small inline xattr space in __find_inline_xattr() f2fs: fix to do sanity check with inode.i_inline_xattr_size f2fs: give some messages for inline_xattr_size f2fs: don't trigger read IO for beyond EOF page f2fs: fix to add refcount once page is tagged PG_private f2fs: remove wrong comment in f2fs_invalidate_page() f2fs: fix to use kvfree instead of kzfree f2fs: print more parameters in trace_f2fs_map_blocks f2fs: trace f2fs_ioc_shutdown f2fs: fix to avoid deadlock of atomic file operations f2fs: fix to dirty inode for i_mode recovery f2fs: give random value to i_generation f2fs: no need to take page lock in readdir f2fs: fix to update iostat correctly in IPU path f2fs: fix encrypted page memory leak f2fs: make fault injection covering __submit_flush_wait() f2fs: fix to retry fill_super only if recovery failed f2fs: silence VM_WARN_ON_ONCE in mempool_alloc f2fs: correct spelling mistake f2fs: fix wrong #endif f2fs: don't clear CP_QUOTA_NEED_FSCK_FLAG f2fs: don't allow negative ->write_io_size_bits f2fs: fix to check inline_xattr_size boundary correctly Revert "f2fs: fix to avoid deadlock of atomic file operations" Revert "f2fs: fix to check inline_xattr_size boundary correctly" f2fs: do not use mutex lock in atomic context f2fs: fix potential data inconsistence of checkpoint f2fs: fix to avoid deadlock of atomic file operations f2fs: fix to check inline_xattr_size boundary correctly f2fs: jump to label 'free_node_inode' when failing from d_make_root() f2fs: fix to document inline_xattr_size option f2fs: fix to data block override node segment by mistake f2fs: fix typos in code comments f2fs: use xattr_prefix to wrap up f2fs: sync filesystem after roll-forward recovery f2fs: flush quota blocks after turnning it off f2fs: avoid null pointer exception in dcc_info f2fs: don't wake up too frequently, if there is lots of IOs f2fs: try to keep CP_TRIMMED_FLAG after successful umount f2fs: add quick mode of checkpoint=disable for QA f2fs: run discard jobs when put_super f2fs: fix to set sbi dirty correctly f2fs: fix to initialize variable to avoid UBSAN/smatch warning f2fs: UBSAN: set boolean value iostat_enable correctly f2fs: add brackets for macros f2fs: check if file namelen exceeds max value f2fs: fix to trigger fsck if dirent.name_len is zero f2fs: no need to check return value of debugfs_create functions f2fs: export FS_NOCOW_FL flag to user f2fs: check inject_rate validity during configuring f2fs: remove set but not used variable 'err' f2fs: fix compile warnings: 'struct *' declared inside parameter list f2fs: change error code to -ENOMEM from -EINVAL Conflicts: drivers/md/Makefile mm/filemap.c net/ipv4/af_inet.c Change-Id: Id050d9a819404a8af08f83bf7fcc5c5536980fe9 Signed-off-by: Blagovest Kolenichev <bkolenichev@codeaurora.org>tirimbino
commit
313f4c9c8f
@ -0,0 +1,99 @@ |
||||
dm_bow (backup on write) |
||||
======================== |
||||
|
||||
dm_bow is a device mapper driver that uses the free space on a device to back up |
||||
data that is overwritten. The changes can then be committed by a simple state |
||||
change, or rolled back by removing the dm_bow device and running a command line |
||||
utility over the underlying device. |
||||
|
||||
dm_bow has three states, set by writing ‘1’ or ‘2’ to /sys/block/dm-?/bow/state. |
||||
It is only possible to go from state 0 (initial state) to state 1, and then from |
||||
state 1 to state 2. |
||||
|
||||
State 0: dm_bow collects all trims to the device and assumes that these mark |
||||
free space on the overlying file system that can be safely used. Typically the |
||||
mount code would create the dm_bow device, mount the file system, call the |
||||
FITRIM ioctl on the file system then switch to state 1. These trims are not |
||||
propagated to the underlying device. |
||||
|
||||
State 1: All writes to the device cause the underlying data to be backed up to |
||||
the free (trimmed) area as needed in such a way as they can be restored. |
||||
However, the writes, with one exception, then happen exactly as they would |
||||
without dm_bow, so the device is always in a good final state. The exception is |
||||
that sector 0 is used to keep a log of the latest changes, both to indicate that |
||||
we are in this state and to allow rollback. See below for all details. If there |
||||
isn't enough free space, writes are failed with -ENOSPC. |
||||
|
||||
State 2: The transition to state 2 triggers replacing the special sector 0 with |
||||
the normal sector 0, and the freeing of all state information. dm_bow then |
||||
becomes a pass-through driver, allowing the device to continue to be used with |
||||
minimal performance impact. |
||||
|
||||
Usage |
||||
===== |
||||
dm-bow takes one command line parameter, the name of the underlying device. |
||||
|
||||
dm-bow will typically be used in the following way. dm-bow will be loaded with a |
||||
suitable underlying device and the resultant device will be mounted. A file |
||||
system trim will be issued via the FITRIM ioctl, then the device will be |
||||
switched to state 1. The file system will now be used as normal. At some point, |
||||
the changes can either be committed by switching to state 2, or rolled back by |
||||
unmounting the file system, removing the dm-bow device and running the command |
||||
line utility. Note that rebooting the device will be equivalent to unmounting |
||||
and removing, but the command line utility must still be run |
||||
|
||||
Details of operation in state 1 |
||||
=============================== |
||||
|
||||
dm_bow maintains a type for all sectors. A sector can be any of: |
||||
|
||||
SECTOR0 |
||||
SECTOR0_CURRENT |
||||
UNCHANGED |
||||
FREE |
||||
CHANGED |
||||
BACKUP |
||||
|
||||
SECTOR0 is the first sector on the device, and is used to hold the log of |
||||
changes. This is the one exception. |
||||
|
||||
SECTOR0_CURRENT is a sector picked from the FREE sectors, and is where reads and |
||||
writes from the true sector zero are redirected to. Note that like any backup |
||||
sector, if the sector is written to directly, it must be moved again. |
||||
|
||||
UNCHANGED means that the sector has not been changed since we entered state 1. |
||||
Thus if it is written to or trimmed, the contents must first be backed up. |
||||
|
||||
FREE means that the sector was trimmed in state 0 and has not yet been written |
||||
to or used for backup. On being written to, a FREE sector is changed to CHANGED. |
||||
|
||||
CHANGED means that the sector has been modified, and can be further modified |
||||
without further backup. |
||||
|
||||
BACKUP means that this is a free sector being used as a backup. On being written |
||||
to, the contents must first be backed up again. |
||||
|
||||
All backup operations are logged to the first sector. The log sector has the |
||||
format: |
||||
-------------------------------------------------------- |
||||
| Magic | Count | Sequence | Log entry | Log entry | … |
||||
-------------------------------------------------------- |
||||
|
||||
Magic is a magic number. Count is the number of log entries. Sequence is 0 |
||||
initially. A log entry is |
||||
|
||||
----------------------------------- |
||||
| Source | Dest | Size | Checksum | |
||||
----------------------------------- |
||||
|
||||
When SECTOR0 is full, the log sector is backed up and another empty log sector |
||||
created with sequence number one higher. The first entry in any log entry with |
||||
sequence > 0 therefore must be the log of the backing up of the previous log |
||||
sector. Note that sequence is not strictly needed, but is a useful sanity check |
||||
and potentially limits the time spent trying to restore a corrupted snapshot. |
||||
|
||||
On entering state 1, dm_bow has a list of free sectors. All other sectors are |
||||
unchanged. Sector0_current is selected from the free sectors and the contents of |
||||
sector 0 are copied there. The sector 0 is backed up, which triggers the first |
||||
log entry to be written. |
||||
|
@ -1,467 +0,0 @@ |
||||
/*
|
||||
* drivers/input/misc/keychord.c |
||||
* |
||||
* Copyright (C) 2008 Google, Inc. |
||||
* Author: Mike Lockwood <lockwood@android.com> |
||||
* |
||||
* This software is licensed under the terms of the GNU General Public |
||||
* License version 2, as published by the Free Software Foundation, and |
||||
* may be copied, distributed, and modified under those terms. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
*/ |
||||
|
||||
#include <linux/poll.h> |
||||
#include <linux/slab.h> |
||||
#include <linux/module.h> |
||||
#include <linux/init.h> |
||||
#include <linux/spinlock.h> |
||||
#include <linux/fs.h> |
||||
#include <linux/miscdevice.h> |
||||
#include <linux/keychord.h> |
||||
#include <linux/sched.h> |
||||
|
||||
#define KEYCHORD_NAME "keychord" |
||||
#define BUFFER_SIZE 16 |
||||
|
||||
MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); |
||||
MODULE_DESCRIPTION("Key chord input driver"); |
||||
MODULE_SUPPORTED_DEVICE("keychord"); |
||||
MODULE_LICENSE("GPL"); |
||||
|
||||
#define NEXT_KEYCHORD(kc) ((struct input_keychord *) \ |
||||
((char *)kc + sizeof(struct input_keychord) + \
|
||||
kc->count * sizeof(kc->keycodes[0]))) |
||||
|
||||
struct keychord_device { |
||||
struct input_handler input_handler; |
||||
int registered; |
||||
|
||||
/* list of keychords to monitor */ |
||||
struct input_keychord *keychords; |
||||
int keychord_count; |
||||
|
||||
/* bitmask of keys contained in our keychords */ |
||||
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; |
||||
/* current state of the keys */ |
||||
unsigned long keystate[BITS_TO_LONGS(KEY_CNT)]; |
||||
/* number of keys that are currently pressed */ |
||||
int key_down; |
||||
|
||||
/* second input_device_id is needed for null termination */ |
||||
struct input_device_id device_ids[2]; |
||||
|
||||
spinlock_t lock; |
||||
wait_queue_head_t waitq; |
||||
unsigned char head; |
||||
unsigned char tail; |
||||
__u16 buff[BUFFER_SIZE]; |
||||
/* Bit to serialize writes to this device */ |
||||
#define KEYCHORD_BUSY 0x01 |
||||
unsigned long flags; |
||||
wait_queue_head_t write_waitq; |
||||
}; |
||||
|
||||
static int check_keychord(struct keychord_device *kdev, |
||||
struct input_keychord *keychord) |
||||
{ |
||||
int i; |
||||
|
||||
if (keychord->count != kdev->key_down) |
||||
return 0; |
||||
|
||||
for (i = 0; i < keychord->count; i++) { |
||||
if (!test_bit(keychord->keycodes[i], kdev->keystate)) |
||||
return 0; |
||||
} |
||||
|
||||
/* we have a match */ |
||||
return 1; |
||||
} |
||||
|
||||
static void keychord_event(struct input_handle *handle, unsigned int type, |
||||
unsigned int code, int value) |
||||
{ |
||||
struct keychord_device *kdev = handle->private; |
||||
struct input_keychord *keychord; |
||||
unsigned long flags; |
||||
int i, got_chord = 0; |
||||
|
||||
if (type != EV_KEY || code >= KEY_MAX) |
||||
return; |
||||
|
||||
spin_lock_irqsave(&kdev->lock, flags); |
||||
/* do nothing if key state did not change */ |
||||
if (!test_bit(code, kdev->keystate) == !value) |
||||
goto done; |
||||
__change_bit(code, kdev->keystate); |
||||
if (value) |
||||
kdev->key_down++; |
||||
else |
||||
kdev->key_down--; |
||||
|
||||
/* don't notify on key up */ |
||||
if (!value) |
||||
goto done; |
||||
/* ignore this event if it is not one of the keys we are monitoring */ |
||||
if (!test_bit(code, kdev->keybit)) |
||||
goto done; |
||||
|
||||
keychord = kdev->keychords; |
||||
if (!keychord) |
||||
goto done; |
||||
|
||||
/* check to see if the keyboard state matches any keychords */ |
||||
for (i = 0; i < kdev->keychord_count; i++) { |
||||
if (check_keychord(kdev, keychord)) { |
||||
kdev->buff[kdev->head] = keychord->id; |
||||
kdev->head = (kdev->head + 1) % BUFFER_SIZE; |
||||
got_chord = 1; |
||||
break; |
||||
} |
||||
/* skip to next keychord */ |
||||
keychord = NEXT_KEYCHORD(keychord); |
||||
} |
||||
|
||||
done: |
||||
spin_unlock_irqrestore(&kdev->lock, flags); |
||||
|
||||
if (got_chord) { |
||||
pr_info("keychord: got keychord id %d. Any tasks: %d\n", |
||||
keychord->id, |
||||
!list_empty_careful(&kdev->waitq.head)); |
||||
wake_up_interruptible(&kdev->waitq); |
||||
} |
||||
} |
||||
|
||||
static int keychord_connect(struct input_handler *handler, |
||||
struct input_dev *dev, |
||||
const struct input_device_id *id) |
||||
{ |
||||
int i, ret; |
||||
struct input_handle *handle; |
||||
struct keychord_device *kdev = |
||||
container_of(handler, struct keychord_device, input_handler); |
||||
|
||||
/*
|
||||
* ignore this input device if it does not contain any keycodes |
||||
* that we are monitoring |
||||
*/ |
||||
for (i = 0; i < KEY_MAX; i++) { |
||||
if (test_bit(i, kdev->keybit) && test_bit(i, dev->keybit)) |
||||
break; |
||||
} |
||||
if (i == KEY_MAX) |
||||
return -ENODEV; |
||||
|
||||
handle = kzalloc(sizeof(*handle), GFP_KERNEL); |
||||
if (!handle) |
||||
return -ENOMEM; |
||||
|
||||
handle->dev = dev; |
||||
handle->handler = handler; |
||||
handle->name = KEYCHORD_NAME; |
||||
handle->private = kdev; |
||||
|
||||
ret = input_register_handle(handle); |
||||
if (ret) |
||||
goto err_input_register_handle; |
||||
|
||||
ret = input_open_device(handle); |
||||
if (ret) |
||||
goto err_input_open_device; |
||||
|
||||
pr_info("keychord: using input dev %s for fevent\n", dev->name); |
||||
return 0; |
||||
|
||||
err_input_open_device: |
||||
input_unregister_handle(handle); |
||||
err_input_register_handle: |
||||
kfree(handle); |
||||
return ret; |
||||
} |
||||
|
||||
static void keychord_disconnect(struct input_handle *handle) |
||||
{ |
||||
input_close_device(handle); |
||||
input_unregister_handle(handle); |
||||
kfree(handle); |
||||
} |
||||
|
||||
/*
|
||||
* keychord_read is used to read keychord events from the driver |
||||
*/ |
||||
static ssize_t keychord_read(struct file *file, char __user *buffer, |
||||
size_t count, loff_t *ppos) |
||||
{ |
||||
struct keychord_device *kdev = file->private_data; |
||||
__u16 id; |
||||
int retval; |
||||
unsigned long flags; |
||||
|
||||
if (count < sizeof(id)) |
||||
return -EINVAL; |
||||
count = sizeof(id); |
||||
|
||||
if (kdev->head == kdev->tail && (file->f_flags & O_NONBLOCK)) |
||||
return -EAGAIN; |
||||
|
||||
retval = wait_event_interruptible(kdev->waitq, |
||||
kdev->head != kdev->tail); |
||||
if (retval) |
||||
return retval; |
||||
|
||||
spin_lock_irqsave(&kdev->lock, flags); |
||||
/* pop a keychord ID off the queue */ |
||||
id = kdev->buff[kdev->tail]; |
||||
kdev->tail = (kdev->tail + 1) % BUFFER_SIZE; |
||||
spin_unlock_irqrestore(&kdev->lock, flags); |
||||
|
||||
if (copy_to_user(buffer, &id, count)) |
||||
return -EFAULT; |
||||
|
||||
return count; |
||||
} |
||||
|
||||
/*
|
||||
* serializes writes on a device. can use mutex_lock_interruptible() |
||||
* for this particular use case as well - a matter of preference. |
||||
*/ |
||||
static int |
||||
keychord_write_lock(struct keychord_device *kdev) |
||||
{ |
||||
int ret; |
||||
unsigned long flags; |
||||
|
||||
spin_lock_irqsave(&kdev->lock, flags); |
||||
while (kdev->flags & KEYCHORD_BUSY) { |
||||
spin_unlock_irqrestore(&kdev->lock, flags); |
||||
ret = wait_event_interruptible(kdev->write_waitq, |
||||
((kdev->flags & KEYCHORD_BUSY) == 0)); |
||||
if (ret) |
||||
return ret; |
||||
spin_lock_irqsave(&kdev->lock, flags); |
||||
} |
||||
kdev->flags |= KEYCHORD_BUSY; |
||||
spin_unlock_irqrestore(&kdev->lock, flags); |
||||
return 0; |
||||
} |
||||
|
||||
static void |
||||
keychord_write_unlock(struct keychord_device *kdev) |
||||
{ |
||||
unsigned long flags; |
||||
|
||||
spin_lock_irqsave(&kdev->lock, flags); |
||||
kdev->flags &= ~KEYCHORD_BUSY; |
||||
spin_unlock_irqrestore(&kdev->lock, flags); |
||||
wake_up_interruptible(&kdev->write_waitq); |
||||
} |
||||
|
||||
/*
|
||||
* keychord_write is used to configure the driver |
||||
*/ |
||||
static ssize_t keychord_write(struct file *file, const char __user *buffer, |
||||
size_t count, loff_t *ppos) |
||||
{ |
||||
struct keychord_device *kdev = file->private_data; |
||||
struct input_keychord *keychords = 0; |
||||
struct input_keychord *keychord; |
||||
int ret, i, key; |
||||
unsigned long flags; |
||||
size_t resid = count; |
||||
size_t key_bytes; |
||||
|
||||
if (count < sizeof(struct input_keychord) || count > PAGE_SIZE) |
||||
return -EINVAL; |
||||
keychords = kzalloc(count, GFP_KERNEL); |
||||
if (!keychords) |
||||
return -ENOMEM; |
||||
|
||||
/* read list of keychords from userspace */ |
||||
if (copy_from_user(keychords, buffer, count)) { |
||||
kfree(keychords); |
||||
return -EFAULT; |
||||
} |
||||
|
||||
/*
|
||||
* Serialize writes to this device to prevent various races. |
||||
* 1) writers racing here could do duplicate input_unregister_handler() |
||||
* calls, resulting in attempting to unlink a node from a list that |
||||
* does not exist. |
||||
* 2) writers racing here could do duplicate input_register_handler() calls |
||||
* below, resulting in a duplicate insertion of a node into the list. |
||||
* 3) a double kfree of keychords can occur (in the event that |
||||
* input_register_handler() fails below. |
||||
*/ |
||||
ret = keychord_write_lock(kdev); |
||||
if (ret) { |
||||
kfree(keychords); |
||||
return ret; |
||||
} |
||||
|
||||
/* unregister handler before changing configuration */ |
||||
if (kdev->registered) { |
||||
input_unregister_handler(&kdev->input_handler); |
||||
kdev->registered = 0; |
||||
} |
||||
|
||||
spin_lock_irqsave(&kdev->lock, flags); |
||||
/* clear any existing configuration */ |
||||
kfree(kdev->keychords); |
||||
kdev->keychords = 0; |
||||
kdev->keychord_count = 0; |
||||
kdev->key_down = 0; |
||||
memset(kdev->keybit, 0, sizeof(kdev->keybit)); |
||||
memset(kdev->keystate, 0, sizeof(kdev->keystate)); |
||||
kdev->head = kdev->tail = 0; |
||||
|
||||
keychord = keychords; |
||||
|
||||
while (resid > 0) { |
||||
/* Is the entire keychord entry header present ? */ |
||||
if (resid < sizeof(struct input_keychord)) { |
||||
pr_err("keychord: Insufficient bytes present for header %zu\n", |
||||
resid); |
||||
goto err_unlock_return; |
||||
} |
||||
resid -= sizeof(struct input_keychord); |
||||
if (keychord->count <= 0) { |
||||
pr_err("keychord: invalid keycode count %d\n", |
||||
keychord->count); |
||||
goto err_unlock_return; |
||||
} |
||||
key_bytes = keychord->count * sizeof(keychord->keycodes[0]); |
||||
/* Do we have all the expected keycodes ? */ |
||||
if (resid < key_bytes) { |
||||
pr_err("keychord: Insufficient bytes present for keycount %zu\n", |
||||
resid); |
||||
goto err_unlock_return; |
||||
} |
||||
resid -= key_bytes; |
||||
|
||||
if (keychord->version != KEYCHORD_VERSION) { |
||||
pr_err("keychord: unsupported version %d\n", |
||||
keychord->version); |
||||
goto err_unlock_return; |
||||
} |
||||
|
||||
/* keep track of the keys we are monitoring in keybit */ |
||||
for (i = 0; i < keychord->count; i++) { |
||||
key = keychord->keycodes[i]; |
||||
if (key < 0 || key >= KEY_CNT) { |
||||
pr_err("keychord: keycode %d out of range\n", |
||||
key); |
||||
goto err_unlock_return; |
||||
} |
||||
__set_bit(key, kdev->keybit); |
||||
} |
||||
|
||||
kdev->keychord_count++; |
||||
keychord = NEXT_KEYCHORD(keychord); |
||||
} |
||||
|
||||
kdev->keychords = keychords; |
||||
spin_unlock_irqrestore(&kdev->lock, flags); |
||||
|
||||
ret = input_register_handler(&kdev->input_handler); |
||||
if (ret) { |
||||
kfree(keychords); |
||||
kdev->keychords = 0; |
||||
keychord_write_unlock(kdev); |
||||
return ret; |
||||
} |
||||
kdev->registered = 1; |
||||
|
||||
keychord_write_unlock(kdev); |
||||
|
||||
return count; |
||||
|
||||
err_unlock_return: |
||||
spin_unlock_irqrestore(&kdev->lock, flags); |
||||
kfree(keychords); |
||||
keychord_write_unlock(kdev); |
||||
return -EINVAL; |
||||
} |
||||
|
||||
static unsigned int keychord_poll(struct file *file, poll_table *wait) |
||||
{ |
||||
struct keychord_device *kdev = file->private_data; |
||||
|
||||
poll_wait(file, &kdev->waitq, wait); |
||||
|
||||
if (kdev->head != kdev->tail) |
||||
return POLLIN | POLLRDNORM; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int keychord_open(struct inode *inode, struct file *file) |
||||
{ |
||||
struct keychord_device *kdev; |
||||
|
||||
kdev = kzalloc(sizeof(struct keychord_device), GFP_KERNEL); |
||||
if (!kdev) |
||||
return -ENOMEM; |
||||
|
||||
spin_lock_init(&kdev->lock); |
||||
init_waitqueue_head(&kdev->waitq); |
||||
init_waitqueue_head(&kdev->write_waitq); |
||||
|
||||
kdev->input_handler.event = keychord_event; |
||||
kdev->input_handler.connect = keychord_connect; |
||||
kdev->input_handler.disconnect = keychord_disconnect; |
||||
kdev->input_handler.name = KEYCHORD_NAME; |
||||
kdev->input_handler.id_table = kdev->device_ids; |
||||
|
||||
kdev->device_ids[0].flags = INPUT_DEVICE_ID_MATCH_EVBIT; |
||||
__set_bit(EV_KEY, kdev->device_ids[0].evbit); |
||||
|
||||
file->private_data = kdev; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int keychord_release(struct inode *inode, struct file *file) |
||||
{ |
||||
struct keychord_device *kdev = file->private_data; |
||||
|
||||
if (kdev->registered) |
||||
input_unregister_handler(&kdev->input_handler); |
||||
kfree(kdev->keychords); |
||||
kfree(kdev); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static const struct file_operations keychord_fops = { |
||||
.owner = THIS_MODULE, |
||||
.open = keychord_open, |
||||
.release = keychord_release, |
||||
.read = keychord_read, |
||||
.write = keychord_write, |
||||
.poll = keychord_poll, |
||||
}; |
||||
|
||||
static struct miscdevice keychord_misc = { |
||||
.fops = &keychord_fops, |
||||
.name = KEYCHORD_NAME, |
||||
.minor = MISC_DYNAMIC_MINOR, |
||||
}; |
||||
|
||||
static int __init keychord_init(void) |
||||
{ |
||||
return misc_register(&keychord_misc); |
||||
} |
||||
|
||||
static void __exit keychord_exit(void) |
||||
{ |
||||
misc_deregister(&keychord_misc); |
||||
} |
||||
|
||||
module_init(keychord_init); |
||||
module_exit(keychord_exit); |
File diff suppressed because it is too large
Load Diff
@ -1,23 +0,0 @@ |
||||
/*
|
||||
* Key chord input driver |
||||
* |
||||
* Copyright (C) 2008 Google, Inc. |
||||
* Author: Mike Lockwood <lockwood@android.com> |
||||
* |
||||
* This software is licensed under the terms of the GNU General Public |
||||
* License version 2, as published by the Free Software Foundation, and |
||||
* may be copied, distributed, and modified under those terms. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __LINUX_KEYCHORD_H_ |
||||
#define __LINUX_KEYCHORD_H_ |
||||
|
||||
#include <uapi/linux/keychord.h> |
||||
|
||||
#endif /* __LINUX_KEYCHORD_H_ */ |
@ -1,52 +0,0 @@ |
||||
/*
|
||||
* Key chord input driver |
||||
* |
||||
* Copyright (C) 2008 Google, Inc. |
||||
* Author: Mike Lockwood <lockwood@android.com> |
||||
* |
||||
* This software is licensed under the terms of the GNU General Public |
||||
* License version 2, as published by the Free Software Foundation, and |
||||
* may be copied, distributed, and modified under those terms. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef _UAPI_LINUX_KEYCHORD_H_ |
||||
#define _UAPI_LINUX_KEYCHORD_H_ |
||||
|
||||
#include <linux/input.h> |
||||
|
||||
#define KEYCHORD_VERSION 1 |
||||
|
||||
/*
|
||||
* One or more input_keychord structs are written to /dev/keychord |
||||
* at once to specify the list of keychords to monitor. |
||||
* Reading /dev/keychord returns the id of a keychord when the |
||||
* keychord combination is pressed. A keychord is signalled when |
||||
* all of the keys in the keycode list are in the pressed state. |
||||
* The order in which the keys are pressed does not matter. |
||||
* The keychord will not be signalled if keys not in the keycode |
||||
* list are pressed. |
||||
* Keychords will not be signalled on key release events. |
||||
*/ |
||||
struct input_keychord { |
||||
/* should be KEYCHORD_VERSION */ |
||||
__u16 version; |
||||
/*
|
||||
* client specified ID, returned from read() |
||||
* when this keychord is pressed. |
||||
*/ |
||||
__u16 id; |
||||
|
||||
/* number of keycodes in this keychord */ |
||||
__u16 count; |
||||
|
||||
/* variable length array of keycodes */ |
||||
__u16 keycodes[]; |
||||
}; |
||||
|
||||
#endif /* _UAPI_LINUX_KEYCHORD_H_ */ |
Loading…
Reference in new issue