summaryrefslogtreecommitdiff
path: root/drivers/tty/vt/keyboard.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/vt/keyboard.c')
-rw-r--r--drivers/tty/vt/keyboard.c464
1 files changed, 214 insertions, 250 deletions
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 78acc270e39a..52922d21a49f 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -26,36 +26,34 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/consolemap.h>
-#include <linux/module.h>
-#include <linux/sched/signal.h>
-#include <linux/sched/debug.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/mm.h>
-#include <linux/nospec.h>
-#include <linux/string.h>
#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/leds.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/kbd_diacr.h>
-#include <linux/vt_kern.h>
#include <linux/input.h>
-#include <linux/reboot.h>
-#include <linux/notifier.h>
#include <linux/jiffies.h>
+#include <linux/kbd_diacr.h>
+#include <linux/kbd_kern.h>
+#include <linux/leds.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/nospec.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/sched/debug.h>
+#include <linux/sched/signal.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
#include <linux/uaccess.h>
+#include <linux/vt_kern.h>
#include <asm/irq_regs.h>
-extern void ctrl_alt_del(void);
-
/*
* Exported functions/variables
*/
-#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
+#define KBD_DEFMODE (BIT(VC_REPEAT) | BIT(VC_META))
#if defined(CONFIG_X86) || defined(CONFIG_PARISC)
#include <asm/kbdleds.h>
@@ -113,10 +111,22 @@ static struct kbd_struct kbd_table[MAX_NR_CONSOLES];
static struct kbd_struct *kbd = kbd_table;
/* maximum values each key_handler can handle */
-static const int max_vals[] = {
- 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1,
- NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1,
- 255, NR_LOCK - 1, 255, NR_BRL - 1
+static const unsigned char max_vals[] = {
+ [ KT_LATIN ] = 255,
+ [ KT_FN ] = ARRAY_SIZE(func_table) - 1,
+ [ KT_SPEC ] = ARRAY_SIZE(fn_handler) - 1,
+ [ KT_PAD ] = NR_PAD - 1,
+ [ KT_DEAD ] = NR_DEAD - 1,
+ [ KT_CONS ] = 255,
+ [ KT_CUR ] = 3,
+ [ KT_SHIFT ] = NR_SHIFT - 1,
+ [ KT_META ] = 255,
+ [ KT_ASCII ] = NR_ASCII - 1,
+ [ KT_LOCK ] = NR_LOCK - 1,
+ [ KT_LETTER ] = 255,
+ [ KT_SLOCK ] = NR_LOCK - 1,
+ [ KT_DEAD2 ] = 255,
+ [ KT_BRL ] = NR_BRL - 1,
};
static const int NR_TYPES = ARRAY_SIZE(max_vals);
@@ -125,7 +135,7 @@ static struct input_handler kbd_handler;
static DEFINE_SPINLOCK(kbd_event_lock);
static DEFINE_SPINLOCK(led_lock);
static DEFINE_SPINLOCK(func_buf_lock); /* guard 'func_buf' and friends */
-static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */
+static DECLARE_BITMAP(key_down, KEY_CNT); /* keyboard key bitmap */
static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */
static bool dead_key_next;
@@ -134,7 +144,7 @@ static bool npadch_active;
static unsigned int npadch_value;
static unsigned int diacr;
-static char rep; /* flag telling character repeat */
+static bool rep; /* flag telling character repeat */
static int shift_state = 0;
@@ -314,12 +324,9 @@ static void put_queue(struct vc_data *vc, int ch)
tty_schedule_flip(&vc->port);
}
-static void puts_queue(struct vc_data *vc, char *cp)
+static void puts_queue(struct vc_data *vc, const char *cp)
{
- while (*cp) {
- tty_insert_flip_char(&vc->port, *cp, 0);
- cp++;
- }
+ tty_insert_flip_string(&vc->port, cp, strlen(cp));
tty_schedule_flip(&vc->port);
}
@@ -455,9 +462,9 @@ static void fn_enter(struct vc_data *vc)
diacr = 0;
}
- put_queue(vc, 13);
+ put_queue(vc, '\r');
if (vc_kbd_mode(kbd, VC_CRLF))
- put_queue(vc, 10);
+ put_queue(vc, '\n');
}
static void fn_caps_toggle(struct vc_data *vc)
@@ -820,7 +827,7 @@ static void k_pad(struct vc_data *vc, unsigned char value, char up_flag)
put_queue(vc, pad_chars[value]);
if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
- put_queue(vc, 10);
+ put_queue(vc, '\n');
}
static void k_shift(struct vc_data *vc, unsigned char value, char up_flag)
@@ -850,9 +857,9 @@ static void k_shift(struct vc_data *vc, unsigned char value, char up_flag)
shift_down[value]++;
if (shift_down[value])
- shift_state |= (1 << value);
+ shift_state |= BIT(value);
else
- shift_state &= ~(1 << value);
+ shift_state &= ~BIT(value);
/* kludge */
if (up_flag && shift_state != old_state && npadch_active) {
@@ -873,7 +880,7 @@ static void k_meta(struct vc_data *vc, unsigned char value, char up_flag)
put_queue(vc, '\033');
put_queue(vc, value);
} else
- put_queue(vc, value | 0x80);
+ put_queue(vc, value | BIT(7));
}
static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag)
@@ -969,7 +976,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
return;
if (!up_flag) {
- pressed |= 1 << (value - 1);
+ pressed |= BIT(value - 1);
if (!brl_timeout)
committing = pressed;
} else if (brl_timeout) {
@@ -979,7 +986,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
committing = pressed;
releasestart = jiffies;
}
- pressed &= ~(1 << (value - 1));
+ pressed &= ~BIT(value - 1);
if (!pressed && committing) {
k_brlcommit(vc, committing, 0);
committing = 0;
@@ -989,7 +996,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
k_brlcommit(vc, committing, 0);
committing = 0;
}
- pressed &= ~(1 << (value - 1));
+ pressed &= ~BIT(value - 1);
}
}
@@ -1089,9 +1096,9 @@ static int kbd_update_leds_helper(struct input_handle *handle, void *data)
unsigned int leds = *(unsigned int *)data;
if (test_bit(EV_LED, handle->dev->evbit)) {
- input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
- input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02));
- input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04));
+ input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & BIT(0)));
+ input_inject_event(handle, EV_LED, LED_NUML, !!(leds & BIT(1)));
+ input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & BIT(2)));
input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
}
@@ -1249,8 +1256,14 @@ DECLARE_TASKLET_DISABLED_OLD(keyboard_tasklet, kbd_bh);
defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
(defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC))
-#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
- ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
+static inline bool kbd_is_hw_raw(const struct input_dev *dev)
+{
+ if (!test_bit(EV_MSC, dev->evbit) || !test_bit(MSC_RAW, dev->mscbit))
+ return false;
+
+ return dev->id.bustype == BUS_I8042 &&
+ dev->id.vendor == 0x0001 && dev->id.product == 0x0001;
+}
static const unsigned short x86_keycodes[256] =
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
@@ -1335,7 +1348,10 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode,
#else
-#define HW_RAW(dev) 0
+static inline bool kbd_is_hw_raw(const struct input_dev *dev)
+{
+ return false;
+}
static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag)
{
@@ -1356,7 +1372,7 @@ static void kbd_rawcode(unsigned char data)
put_queue(vc, data);
}
-static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
+static void kbd_keycode(unsigned int keycode, int down, bool hw_raw)
{
struct vc_data *vc = vc_cons[fg_console].d;
unsigned short keysym, *key_map;
@@ -1411,16 +1427,13 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
put_queue(vc, keycode | (!down << 7));
} else {
put_queue(vc, !down << 7);
- put_queue(vc, (keycode >> 7) | 0x80);
- put_queue(vc, keycode | 0x80);
+ put_queue(vc, (keycode >> 7) | BIT(7));
+ put_queue(vc, keycode | BIT(7));
}
raw_mode = true;
}
- if (down)
- set_bit(keycode, key_down);
- else
- clear_bit(keycode, key_down);
+ assign_bit(keycode, key_down, down);
if (rep &&
(!vc_kbd_mode(kbd, VC_REPEAT) ||
@@ -1471,7 +1484,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
if (type == KT_LETTER) {
type = KT_LATIN;
if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
- key_map = key_maps[shift_final ^ (1 << KG_SHIFT)];
+ key_map = key_maps[shift_final ^ BIT(KG_SHIFT)];
if (key_map)
keysym = key_map[keycode];
}
@@ -1501,10 +1514,11 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type,
/* We are called with interrupts disabled, just take the lock */
spin_lock(&kbd_event_lock);
- if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
+ if (event_type == EV_MSC && event_code == MSC_RAW &&
+ kbd_is_hw_raw(handle->dev))
kbd_rawcode(value);
if (event_type == EV_KEY && event_code <= KEY_MAX)
- kbd_keycode(event_code, value, HW_RAW(handle->dev));
+ kbd_keycode(event_code, value, kbd_is_hw_raw(handle->dev));
spin_unlock(&kbd_event_lock);
@@ -1515,18 +1529,16 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type,
static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
{
- int i;
-
if (test_bit(EV_SND, dev->evbit))
return true;
if (test_bit(EV_KEY, dev->evbit)) {
- for (i = KEY_RESERVED; i < BTN_MISC; i++)
- if (test_bit(i, dev->keybit))
- return true;
- for (i = KEY_BRL_DOT1; i <= KEY_BRL_DOT10; i++)
- if (test_bit(i, dev->keybit))
- return true;
+ if (find_next_bit(dev->keybit, BTN_MISC, KEY_RESERVED) <
+ BTN_MISC)
+ return true;
+ if (find_next_bit(dev->keybit, KEY_BRL_DOT10 + 1,
+ KEY_BRL_DOT1) <= KEY_BRL_DOT10)
+ return true;
}
return false;
@@ -1887,239 +1899,191 @@ int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc,
return kc;
}
-#define i (tmp.kb_index)
-#define s (tmp.kb_table)
-#define v (tmp.kb_value)
-
-int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
- int console)
+static unsigned short vt_kdgkbent(unsigned char kbdmode, unsigned char idx,
+ unsigned char map)
{
- struct kbd_struct *kb = kbd_table + console;
- struct kbentry tmp;
- ushort *key_map, *new_map, val, ov;
+ unsigned short *key_map, val;
unsigned long flags;
- if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
- return -EFAULT;
+ /* Ensure another thread doesn't free it under us */
+ spin_lock_irqsave(&kbd_event_lock, flags);
+ key_map = key_maps[map];
+ if (key_map) {
+ val = U(key_map[idx]);
+ if (kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
+ val = K_HOLE;
+ } else
+ val = idx ? K_HOLE : K_NOSUCHMAP;
+ spin_unlock_irqrestore(&kbd_event_lock, flags);
- if (!capable(CAP_SYS_TTY_CONFIG))
- perm = 0;
+ return val;
+}
- switch (cmd) {
- case KDGKBENT:
- /* Ensure another thread doesn't free it under us */
+static int vt_kdskbent(unsigned char kbdmode, unsigned char idx,
+ unsigned char map, unsigned short val)
+{
+ unsigned long flags;
+ unsigned short *key_map, *new_map, oldval;
+
+ if (!idx && val == K_NOSUCHMAP) {
spin_lock_irqsave(&kbd_event_lock, flags);
- key_map = key_maps[s];
- if (key_map) {
- val = U(key_map[i]);
- if (kb->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
- val = K_HOLE;
- } else
- val = (i ? K_HOLE : K_NOSUCHMAP);
- spin_unlock_irqrestore(&kbd_event_lock, flags);
- return put_user(val, &user_kbe->kb_value);
- case KDSKBENT:
- if (!perm)
- return -EPERM;
- if (!i && v == K_NOSUCHMAP) {
- spin_lock_irqsave(&kbd_event_lock, flags);
- /* deallocate map */
- key_map = key_maps[s];
- if (s && key_map) {
- key_maps[s] = NULL;
- if (key_map[0] == U(K_ALLOCATED)) {
- kfree(key_map);
- keymap_count--;
- }
+ /* deallocate map */
+ key_map = key_maps[map];
+ if (map && key_map) {
+ key_maps[map] = NULL;
+ if (key_map[0] == U(K_ALLOCATED)) {
+ kfree(key_map);
+ keymap_count--;
}
- spin_unlock_irqrestore(&kbd_event_lock, flags);
- break;
}
+ spin_unlock_irqrestore(&kbd_event_lock, flags);
+
+ return 0;
+ }
- if (KTYP(v) < NR_TYPES) {
- if (KVAL(v) > max_vals[KTYP(v)])
- return -EINVAL;
- } else
- if (kb->kbdmode != VC_UNICODE)
- return -EINVAL;
+ if (KTYP(val) < NR_TYPES) {
+ if (KVAL(val) > max_vals[KTYP(val)])
+ return -EINVAL;
+ } else if (kbdmode != VC_UNICODE)
+ return -EINVAL;
- /* ++Geert: non-PC keyboards may generate keycode zero */
+ /* ++Geert: non-PC keyboards may generate keycode zero */
#if !defined(__mc68000__) && !defined(__powerpc__)
- /* assignment to entry 0 only tests validity of args */
- if (!i)
- break;
+ /* assignment to entry 0 only tests validity of args */
+ if (!idx)
+ return 0;
#endif
- new_map = kmalloc(sizeof(plain_map), GFP_KERNEL);
- if (!new_map)
- return -ENOMEM;
- spin_lock_irqsave(&kbd_event_lock, flags);
- key_map = key_maps[s];
- if (key_map == NULL) {
- int j;
-
- if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
- !capable(CAP_SYS_RESOURCE)) {
- spin_unlock_irqrestore(&kbd_event_lock, flags);
- kfree(new_map);
- return -EPERM;
- }
- key_maps[s] = new_map;
- key_map = new_map;
- key_map[0] = U(K_ALLOCATED);
- for (j = 1; j < NR_KEYS; j++)
- key_map[j] = U(K_HOLE);
- keymap_count++;
- } else
- kfree(new_map);
+ new_map = kmalloc(sizeof(plain_map), GFP_KERNEL);
+ if (!new_map)
+ return -ENOMEM;
- ov = U(key_map[i]);
- if (v == ov)
- goto out;
- /*
- * Attention Key.
- */
- if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) {
+ spin_lock_irqsave(&kbd_event_lock, flags);
+ key_map = key_maps[map];
+ if (key_map == NULL) {
+ int j;
+
+ if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
+ !capable(CAP_SYS_RESOURCE)) {
spin_unlock_irqrestore(&kbd_event_lock, flags);
+ kfree(new_map);
return -EPERM;
}
- key_map[i] = U(v);
- if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
- do_compute_shiftstate();
-out:
+ key_maps[map] = new_map;
+ key_map = new_map;
+ key_map[0] = U(K_ALLOCATED);
+ for (j = 1; j < NR_KEYS; j++)
+ key_map[j] = U(K_HOLE);
+ keymap_count++;
+ } else
+ kfree(new_map);
+
+ oldval = U(key_map[idx]);
+ if (val == oldval)
+ goto out;
+
+ /* Attention Key */
+ if ((oldval == K_SAK || val == K_SAK) && !capable(CAP_SYS_ADMIN)) {
spin_unlock_irqrestore(&kbd_event_lock, flags);
- break;
+ return -EPERM;
}
+
+ key_map[idx] = U(val);
+ if (!map && (KTYP(oldval) == KT_SHIFT || KTYP(val) == KT_SHIFT))
+ do_compute_shiftstate();
+out:
+ spin_unlock_irqrestore(&kbd_event_lock, flags);
+
return 0;
}
-#undef i
-#undef s
-#undef v
-/* FIXME: This one needs untangling */
-int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
+int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
+ int console)
{
- struct kbsentry *kbs;
- u_char *q;
- int sz, fnw_sz;
- int delta;
- char *first_free, *fj, *fnw;
- int i, j, k;
- int ret;
- unsigned long flags;
+ struct kbd_struct *kb = kbd_table + console;
+ struct kbentry kbe;
- if (!capable(CAP_SYS_TTY_CONFIG))
- perm = 0;
+ if (copy_from_user(&kbe, user_kbe, sizeof(struct kbentry)))
+ return -EFAULT;
- kbs = kmalloc(sizeof(*kbs), GFP_KERNEL);
- if (!kbs) {
- ret = -ENOMEM;
- goto reterr;
+ switch (cmd) {
+ case KDGKBENT:
+ return put_user(vt_kdgkbent(kb->kbdmode, kbe.kb_index,
+ kbe.kb_table),
+ &user_kbe->kb_value);
+ case KDSKBENT:
+ if (!perm || !capable(CAP_SYS_TTY_CONFIG))
+ return -EPERM;
+ return vt_kdskbent(kb->kbdmode, kbe.kb_index, kbe.kb_table,
+ kbe.kb_value);
}
+ return 0;
+}
- /* we mostly copy too much here (512bytes), but who cares ;) */
- if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) {
- ret = -EFAULT;
- goto reterr;
+static char *vt_kdskbsent(char *kbs, unsigned char cur)
+{
+ static DECLARE_BITMAP(is_kmalloc, MAX_NR_FUNC);
+ char *cur_f = func_table[cur];
+
+ if (cur_f && strlen(cur_f) >= strlen(kbs)) {
+ strcpy(cur_f, kbs);
+ return kbs;
}
- kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
- i = array_index_nospec(kbs->kb_func, MAX_NR_FUNC);
+
+ func_table[cur] = kbs;
+
+ return __test_and_set_bit(cur, is_kmalloc) ? cur_f : NULL;
+}
+
+int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
+{
+ unsigned char kb_func;
+ unsigned long flags;
+ char *kbs;
+ int ret;
+
+ if (get_user(kb_func, &user_kdgkb->kb_func))
+ return -EFAULT;
+
+ kb_func = array_index_nospec(kb_func, MAX_NR_FUNC);
switch (cmd) {
case KDGKBSENT: {
/* size should have been a struct member */
ssize_t len = sizeof(user_kdgkb->kb_string);
+ kbs = kmalloc(len, GFP_KERNEL);
+ if (!kbs)
+ return -ENOMEM;
+
spin_lock_irqsave(&func_buf_lock, flags);
- len = strlcpy(kbs->kb_string, func_table[i] ? : "", len);
+ len = strlcpy(kbs, func_table[kb_func] ? : "", len);
spin_unlock_irqrestore(&func_buf_lock, flags);
- ret = copy_to_user(user_kdgkb->kb_string, kbs->kb_string,
- len + 1) ? -EFAULT : 0;
+ ret = copy_to_user(user_kdgkb->kb_string, kbs, len + 1) ?
+ -EFAULT : 0;
- goto reterr;
+ break;
}
case KDSKBSENT:
- if (!perm) {
- ret = -EPERM;
- goto reterr;
- }
+ if (!perm || !capable(CAP_SYS_TTY_CONFIG))
+ return -EPERM;
+
+ kbs = strndup_user(user_kdgkb->kb_string,
+ sizeof(user_kdgkb->kb_string));
+ if (IS_ERR(kbs))
+ return PTR_ERR(kbs);
- fnw = NULL;
- fnw_sz = 0;
- /* race aginst other writers */
- again:
spin_lock_irqsave(&func_buf_lock, flags);
- q = func_table[i];
-
- /* fj pointer to next entry after 'q' */
- first_free = funcbufptr + (funcbufsize - funcbufleft);
- for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++)
- ;
- if (j < MAX_NR_FUNC)
- fj = func_table[j];
- else
- fj = first_free;
- /* buffer usage increase by new entry */
- delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
-
- if (delta <= funcbufleft) { /* it fits in current buf */
- if (j < MAX_NR_FUNC) {
- /* make enough space for new entry at 'fj' */
- memmove(fj + delta, fj, first_free - fj);
- for (k = j; k < MAX_NR_FUNC; k++)
- if (func_table[k])
- func_table[k] += delta;
- }
- if (!q)
- func_table[i] = fj;
- funcbufleft -= delta;
- } else { /* allocate a larger buffer */
- sz = 256;
- while (sz < funcbufsize - funcbufleft + delta)
- sz <<= 1;
- if (fnw_sz != sz) {
- spin_unlock_irqrestore(&func_buf_lock, flags);
- kfree(fnw);
- fnw = kmalloc(sz, GFP_KERNEL);
- fnw_sz = sz;
- if (!fnw) {
- ret = -ENOMEM;
- goto reterr;
- }
- goto again;
- }
-
- if (!q)
- func_table[i] = fj;
- /* copy data before insertion point to new location */
- if (fj > funcbufptr)
- memmove(fnw, funcbufptr, fj - funcbufptr);
- for (k = 0; k < j; k++)
- if (func_table[k])
- func_table[k] = fnw + (func_table[k] - funcbufptr);
-
- /* copy data after insertion point to new location */
- if (first_free > fj) {
- memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
- for (k = j; k < MAX_NR_FUNC; k++)
- if (func_table[k])
- func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
- }
- if (funcbufptr != func_buf)
- kfree(funcbufptr);
- funcbufptr = fnw;
- funcbufleft = funcbufleft - delta + sz - funcbufsize;
- funcbufsize = sz;
- }
- /* finally insert item itself */
- strcpy(func_table[i], kbs->kb_string);
+ kbs = vt_kdskbsent(kbs, kb_func);
spin_unlock_irqrestore(&func_buf_lock, flags);
+
+ ret = 0;
break;
}
- ret = 0;
-reterr:
+
kfree(kbs);
+
return ret;
}