Refactor input backend-system
authorDavid Herrmann <dh.herrmann@googlemail.com>
Sat, 21 Jul 2012 17:06:50 +0000 (19:06 +0200)
committerDavid Herrmann <dh.herrmann@googlemail.com>
Sat, 21 Jul 2012 17:06:50 +0000 (19:06 +0200)
This is a rewrite of the input system. The backends itself are not
modified. However, it is now possible to have multiple backends and change
them on runtime.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
Makefile.am
configure.ac
src/main.c
src/uterm_input.c
src/uterm_input_plain.c [moved from src/uterm_input_dumb.c with 85% similarity]
src/uterm_input_uxkb.c [moved from src/uterm_input_xkb.c with 75% similarity]
src/uterm_internal.h

index 2ae0218..fc33494 100644 (file)
@@ -152,6 +152,9 @@ libuterm_la_SOURCES = \
        src/uterm_video.c \
        src/uterm_monitor.c \
        src/uterm_input.c \
+       src/uterm_input_plain.c \
+       external/imKStoUCS.h \
+       external/imKStoUCS.c \
        src/uterm_vt.c \
        src/vt.h \
        src/vt.c
@@ -195,12 +198,7 @@ endif
 
 if UTERM_HAVE_XKBCOMMON
 libuterm_la_SOURCES += \
-       src/uterm_input_xkb.c
-else
-libuterm_la_SOURCES += \
-       src/uterm_input_dumb.c \
-       external/imKStoUCS.h \
-       external/imKStoUCS.c
+       src/uterm_input_uxkb.c
 endif
 
 include_HEADERS += \
index 655b704..af71388 100644 (file)
@@ -336,7 +336,8 @@ if test ! x$enable_xkbcommon = xno ; then
 fi
 
 if test x$xkbcommon_enabled = xyes ; then
-        test # dummy
+        AC_DEFINE([UTERM_HAVE_XKBCOMMON], [1],
+                  [Use xkbcommon as input keyboard handling backend])
 else
         XKBCOMMON_CFLAGS=""
         XKBCOMMON_LIBS=""
index 0a7f8c9..02e9d1f 100644 (file)
@@ -182,8 +182,10 @@ static void seat_add_video(struct kmscon_seat *seat,
 
        ret = kmscon_ui_new(&seat->ui, seat->app->eloop, seat->video,
                            seat->input);
-       if (ret)
+       if (ret) {
+               log_error("cannot create UI object");
                goto err_video;
+       }
 
        seat->vdev = dev;
        log_debug("new graphics device on seat %s", seat->sname);
index baa0232..387e845 100644 (file)
@@ -88,7 +88,7 @@ static void notify_key(struct uterm_input_dev *dev,
        if (type != EV_KEY)
                return;
 
-       ret = kbd_dev_process_key(dev->kbd, value, code, &ev);
+       ret = kbd_dev_process(dev->kbd, value, code, &ev);
        if (ret)
                return;
 
@@ -200,7 +200,7 @@ static void input_new_dev(struct uterm_input *input,
        if (!dev->node)
                goto err_free;
 
-       ret = kbd_dev_new(&dev->kbd, input->desc);
+       ret = kbd_desc_alloc(input->desc, &dev->kbd);
        if (ret)
                goto err_node;
 
@@ -254,11 +254,22 @@ int uterm_input_new(struct uterm_input **out,
                goto err_free;
 
        ret = kbd_desc_new(&input->desc,
-                                       conf_global.xkb_layout,
-                                       conf_global.xkb_variant,
-                                       conf_global.xkb_options);
-       if (ret)
+                          conf_global.xkb_layout,
+                          conf_global.xkb_variant,
+                          conf_global.xkb_options,
+                          KBD_UXKB);
+       if (ret == -EOPNOTSUPP) {
+               log_info("XKB keyboard backend not available, trying plain backend");
+               ret = kbd_desc_new(&input->desc,
+                                  conf_global.xkb_layout,
+                                  conf_global.xkb_variant,
+                                  conf_global.xkb_options,
+                                  KBD_PLAIN);
+               if (ret)
+                       goto err_hook;
+       } else if (ret) {
                goto err_hook;
+       }
 
        log_debug("new object %p", input);
        ev_eloop_ref(input->eloop);
similarity index 85%
rename from src/uterm_input_dumb.c
rename to src/uterm_input_plain.c
index b443a8e..38b4a25 100644 (file)
 #include "uterm.h"
 #include "uterm_internal.h"
 
-#define LOG_SUBSYSTEM "input_dumb"
-
-struct kbd_dev {
-       unsigned long ref;
-       unsigned int mods;
-};
+#define LOG_SUBSYSTEM "input_plain"
 
 /*
  * These tables do not contain all possible keys from linux/input.h.
@@ -284,21 +279,7 @@ static const struct {
        [KEY_RIGHTMETA]   =  {  UTERM_MOD4_MASK,     MOD_NORMAL  },
 };
 
-int kbd_dev_new(struct kbd_dev **out, struct kbd_desc *desc)
-{
-       struct kbd_dev *kbd;
-
-       kbd = malloc(sizeof(*kbd));
-       if (!kbd)
-               return -ENOMEM;
-       memset(kbd, 0, sizeof(*kbd));
-       kbd->ref = 1;
-
-       *out = kbd;
-       return 0;
-}
-
-void kbd_dev_ref(struct kbd_dev *kbd)
+static void plain_dev_ref(struct kbd_dev *kbd)
 {
        if (!kbd || !kbd->ref)
                return;
@@ -306,7 +287,7 @@ void kbd_dev_ref(struct kbd_dev *kbd)
        ++kbd->ref;
 }
 
-void kbd_dev_unref(struct kbd_dev *kbd)
+static void plain_dev_unref(struct kbd_dev *kbd)
 {
        if (!kbd || !kbd->ref || --kbd->ref)
                return;
@@ -314,23 +295,23 @@ void kbd_dev_unref(struct kbd_dev *kbd)
        free(kbd);
 }
 
-void kbd_dev_reset(struct kbd_dev *kbd, const unsigned long *ledbits)
+static void plain_dev_reset(struct kbd_dev *kbd, const unsigned long *ledbits)
 {
        if (!kbd)
                return;
 
-       kbd->mods = 0;
+       kbd->plain.mods = 0;
 
        if (input_bit_is_set(ledbits, LED_NUML))
-               kbd->mods |= UTERM_MOD2_MASK;
+               kbd->plain.mods |= UTERM_MOD2_MASK;
        if (input_bit_is_set(ledbits, LED_CAPSL))
-               kbd->mods |= UTERM_LOCK_MASK;
+               kbd->plain.mods |= UTERM_LOCK_MASK;
 }
 
-int kbd_dev_process_key(struct kbd_dev *kbd,
-                       uint16_t key_state,
-                       uint16_t code,
-                       struct uterm_input_event *out)
+static int plain_dev_process(struct kbd_dev *kbd,
+                            uint16_t key_state,
+                            uint16_t code,
+                            struct uterm_input_event *out)
 {
        uint32_t keysym;
        unsigned int mod;
@@ -353,12 +334,12 @@ int kbd_dev_process_key(struct kbd_dev *kbd,
                 */
                if (key_state == 1) {
                        if (mod_type == MOD_NORMAL)
-                               kbd->mods |= mod;
+                               kbd->plain.mods |= mod;
                        else if (mod_type == MOD_LOCK)
-                               kbd->mods ^= mod;
+                               kbd->plain.mods ^= mod;
                } else if (key_state == 0) {
                        if (mod_type == MOD_NORMAL)
-                               kbd->mods &= ~mod;
+                               kbd->plain.mods &= ~mod;
                }
 
                /* Don't deliver events purely for modifiers. */
@@ -370,11 +351,11 @@ int kbd_dev_process_key(struct kbd_dev *kbd,
 
        keysym = 0;
 
-       if (!keysym && kbd->mods & UTERM_MOD2_MASK)
+       if (!keysym && kbd->plain.mods & UTERM_MOD2_MASK)
                keysym = keytab_numlock[code];
-       if (!keysym && kbd->mods & UTERM_SHIFT_MASK)
+       if (!keysym && kbd->plain.mods & UTERM_SHIFT_MASK)
                keysym = keytab_shift[code];
-       if (!keysym && kbd->mods & UTERM_LOCK_MASK)
+       if (!keysym && kbd->plain.mods & UTERM_LOCK_MASK)
                keysym = keytab_capslock[code];
        if (!keysym)
                keysym = keytab_normal[code];
@@ -385,34 +366,81 @@ int kbd_dev_process_key(struct kbd_dev *kbd,
        out->keycode = code;
        out->keysym = keysym;
        out->unicode = KeysymToUcs4(keysym) ?: UTERM_INPUT_INVALID;
-       out->mods = kbd->mods;
+       out->mods = kbd->plain.mods;
 
        return 0;
 }
 
-int kbd_desc_new(struct kbd_desc **out,
-                       const char *layout,
-                       const char *variant,
-                       const char *options)
+static int plain_desc_init(struct kbd_desc **out,
+                          const char *layout,
+                          const char *variant,
+                          const char *options)
 {
+       struct kbd_desc *desc;
+
        if (!out)
                return -EINVAL;
 
+       desc = malloc(sizeof(*desc));
+       if (!desc)
+               return -ENOMEM;
+       memset(desc, 0, sizeof(*desc));
+       desc->ops = &plain_desc_ops;
+
        log_debug("new keyboard description (%s, %s, %s)",
-                                               layout, variant, options);
-       *out = NULL;
+                 layout, variant, options);
+       *out = desc;
        return 0;
 }
 
-void kbd_desc_ref(struct kbd_desc *desc)
+static void plain_desc_ref(struct kbd_desc *desc)
 {
+       if (!desc || !desc->ref)
+               return;
+
+       ++desc->ref;
 }
 
-void kbd_desc_unref(struct kbd_desc *desc)
+static void plain_desc_unref(struct kbd_desc *desc)
 {
+       if (!desc || !desc->ref || --desc->ref)
+               return;
+
+       log_debug("destroying keyboard description");
+       free(desc);
 }
 
-void kbd_keysym_to_string(uint32_t keysym, char *str, size_t size)
+static int plain_desc_alloc(struct kbd_desc *desc, struct kbd_dev **out)
+{
+       struct kbd_dev *kbd;
+
+       kbd = malloc(sizeof(*kbd));
+       if (!kbd)
+               return -ENOMEM;
+       memset(kbd, 0, sizeof(*kbd));
+       kbd->ref = 1;
+       kbd->ops = &plain_dev_ops;
+
+       *out = kbd;
+       return 0;
+}
+
+static void plain_keysym_to_string(uint32_t keysym, char *str, size_t size)
 {
        snprintf(str, size, "%#x", keysym);
 }
+
+const struct kbd_desc_ops plain_desc_ops = {
+       .init = plain_desc_init,
+       .ref = plain_desc_ref,
+       .unref = plain_desc_unref,
+       .alloc = plain_desc_alloc,
+       .keysym_to_string = plain_keysym_to_string,
+};
+
+const struct kbd_dev_ops plain_dev_ops = {
+       .ref = plain_dev_ref,
+       .unref = plain_dev_unref,
+       .reset = plain_dev_reset,
+       .process = plain_dev_process,
+};
similarity index 75%
rename from src/uterm_input_xkb.c
rename to src/uterm_input_uxkb.c
index f786cc6..717cda4 100644 (file)
 #include "uterm.h"
 #include "uterm_internal.h"
 
-#define LOG_SUBSYSTEM "input_xkb"
+#define LOG_SUBSYSTEM "input_uxkb"
 
-struct kbd_desc {
-       unsigned long ref;
-       struct xkb_context *ctx;
-       struct xkb_keymap *keymap;
-};
-
-struct kbd_dev {
-       unsigned long ref;
-       struct kbd_desc *desc;
-       struct xkb_state *state;
-};
-
-int kbd_dev_new(struct kbd_dev **out, struct kbd_desc *desc)
-{
-       struct kbd_dev *kbd;
-
-       kbd = malloc(sizeof(*kbd));
-       if (!kbd)
-               return -ENOMEM;
-
-       memset(kbd, 0, sizeof(*kbd));
-       kbd->ref = 1;
-       kbd->desc = desc;
-
-       kbd->state = xkb_state_new(desc->keymap);
-       if (!kbd->state) {
-               free(kbd);
-               return -ENOMEM;
-       }
-
-       kbd_desc_ref(desc);
-       *out = kbd;
-       return 0;
-}
-
-void kbd_dev_ref(struct kbd_dev *kbd)
+static void uxkb_dev_ref(struct kbd_dev *kbd)
 {
        if (!kbd || !kbd->ref)
                return;
@@ -80,12 +45,12 @@ void kbd_dev_ref(struct kbd_dev *kbd)
        ++kbd->ref;
 }
 
-void kbd_dev_unref(struct kbd_dev *kbd)
+static void uxkb_dev_unref(struct kbd_dev *kbd)
 {
        if (!kbd || !kbd->ref || --kbd->ref)
                return;
 
-       xkb_state_unref(kbd->state);
+       xkb_state_unref(kbd->uxkb.state);
        kbd_desc_unref(kbd->desc);
        free(kbd);
 }
@@ -120,10 +85,10 @@ static unsigned int get_effective_modmask(struct xkb_state *state)
        return mods;
 }
 
-int kbd_dev_process_key(struct kbd_dev *kbd,
-                       uint16_t key_state,
-                       uint16_t code,
-                       struct uterm_input_event *out)
+static int uxkb_dev_process(struct kbd_dev *kbd,
+                           uint16_t key_state,
+                           uint16_t code,
+                           struct uterm_input_event *out)
 {
        struct xkb_state *state;
        struct xkb_keymap *keymap;
@@ -134,7 +99,7 @@ int kbd_dev_process_key(struct kbd_dev *kbd,
        if (!kbd)
                return -EINVAL;
 
-       state = kbd->state;
+       state = kbd->uxkb.state;
        keymap = xkb_state_get_map(state);
        keycode = code + EVDEV_KEYCODE_OFFSET;
 
@@ -161,8 +126,8 @@ int kbd_dev_process_key(struct kbd_dev *kbd,
         */
        out->keycode = code;
        out->keysym = keysyms[0];
-       out->mods = get_effective_modmask(state);;
-       out->unicode = xkb_keysym_to_utf32(out->keysym) ?: UTERM_INPUT_INVALID;
+       out->mods = get_effective_modmask(state);
+       out->unicode = xkb_keysym_to_utf32(out->keysym) ? : UTERM_INPUT_INVALID;
 
        return 0;
 }
@@ -172,7 +137,7 @@ int kbd_dev_process_key(struct kbd_dev *kbd,
  * We don't reset the locked group, this should survive a VT switch, etc. The
  * locked modifiers are reset according to the keyboard LEDs.
  */
-void kbd_dev_reset(struct kbd_dev *kbd, const unsigned long *ledbits)
+static void uxkb_dev_reset(struct kbd_dev *kbd, const unsigned long *ledbits)
 {
        unsigned int i;
        struct xkb_state *state;
@@ -188,7 +153,7 @@ void kbd_dev_reset(struct kbd_dev *kbd, const unsigned long *ledbits)
        if (!kbd)
                return;
 
-       state = kbd->state;
+       state = kbd->uxkb.state;
 
        for (i = 0; i < sizeof(led_names) / sizeof(*led_names); i++) {
                if (!input_bit_is_set(ledbits, led_names[i].led))
@@ -205,10 +170,10 @@ void kbd_dev_reset(struct kbd_dev *kbd, const unsigned long *ledbits)
        (void)state;
 }
 
-int kbd_desc_new(struct kbd_desc **out,
-                       const char *layout,
-                       const char *variant,
-                       const char *options)
+static int uxkb_desc_init(struct kbd_desc **out,
+                         const char *layout,
+                         const char *variant,
+                         const char *options)
 {
        int ret;
        struct kbd_desc *desc;
@@ -229,15 +194,16 @@ int kbd_desc_new(struct kbd_desc **out,
 
        memset(desc, 0, sizeof(*desc));
        desc->ref = 1;
+       desc->ops = &uxkb_desc_ops;
 
-       desc->ctx = xkb_context_new(0);
-       if (!desc->ctx) {
+       desc->uxkb.ctx = xkb_context_new(0);
+       if (!desc->uxkb.ctx) {
                ret = -ENOMEM;
                goto err_desc;
        }
 
-       desc->keymap = xkb_map_new_from_names(desc->ctx, &rmlvo, 0);
-       if (!desc->keymap) {
+       desc->uxkb.keymap = xkb_map_new_from_names(desc->uxkb.ctx, &rmlvo, 0);
+       if (!desc->uxkb.keymap) {
                log_warn("failed to create keymap (%s, %s, %s), "
                         "reverting to default US keymap",
                         layout, variant, options);
@@ -246,8 +212,9 @@ int kbd_desc_new(struct kbd_desc **out,
                rmlvo.variant = "";
                rmlvo.options = "";
 
-               desc->keymap = xkb_map_new_from_names(desc->ctx, &rmlvo, 0);
-               if (!desc->keymap) {
+               desc->uxkb.keymap = xkb_map_new_from_names(desc->uxkb.ctx,
+                                                          &rmlvo, 0);
+               if (!desc->uxkb.keymap) {
                        log_warn("failed to create keymap");
                        ret = -EFAULT;
                        goto err_ctx;
@@ -260,13 +227,13 @@ int kbd_desc_new(struct kbd_desc **out,
        return 0;
 
 err_ctx:
-       xkb_context_unref(desc->ctx);
+       xkb_context_unref(desc->uxkb.ctx);
 err_desc:
        free(desc);
        return ret;
 }
 
-void kbd_desc_ref(struct kbd_desc *desc)
+static void uxkb_desc_ref(struct kbd_desc *desc)
 {
        if (!desc || !desc->ref)
                return;
@@ -274,18 +241,57 @@ void kbd_desc_ref(struct kbd_desc *desc)
        ++desc->ref;
 }
 
-void kbd_desc_unref(struct kbd_desc *desc)
+static void uxkb_desc_unref(struct kbd_desc *desc)
 {
        if (!desc || !desc->ref || --desc->ref)
                return;
 
        log_debug("destroying keyboard description");
-       xkb_map_unref(desc->keymap);
-       xkb_context_unref(desc->ctx);
+       xkb_map_unref(desc->uxkb.keymap);
+       xkb_context_unref(desc->uxkb.ctx);
        free(desc);
 }
 
-void kbd_keysym_to_string(uint32_t keysym, char *str, size_t size)
+static int uxkb_desc_alloc(struct kbd_desc *desc, struct kbd_dev **out)
+{
+       struct kbd_dev *kbd;
+
+       kbd = malloc(sizeof(*kbd));
+       if (!kbd)
+               return -ENOMEM;
+
+       memset(kbd, 0, sizeof(*kbd));
+       kbd->ref = 1;
+       kbd->desc = desc;
+       kbd->ops = &uxkb_dev_ops;
+
+       kbd->uxkb.state = xkb_state_new(desc->uxkb.keymap);
+       if (!kbd->uxkb.state) {
+               free(kbd);
+               return -ENOMEM;
+       }
+
+       kbd_desc_ref(desc);
+       *out = kbd;
+       return 0;
+}
+
+static void uxkb_keysym_to_string(uint32_t keysym, char *str, size_t size)
 {
        xkb_keysym_get_name(keysym, str, size);
 }
+
+const struct kbd_desc_ops uxkb_desc_ops = {
+       .init = uxkb_desc_init,
+       .ref = uxkb_desc_ref,
+       .unref = uxkb_desc_unref,
+       .alloc = uxkb_desc_alloc,
+       .keysym_to_string = uxkb_keysym_to_string,
+};
+
+const struct kbd_dev_ops uxkb_dev_ops = {
+       .ref = uxkb_dev_ref,
+       .unref = uxkb_dev_unref,
+       .reset = uxkb_dev_reset,
+       .process = uxkb_dev_process,
+};
index 8336a95..6637666 100644 (file)
@@ -372,37 +372,189 @@ static inline bool input_bit_is_set(const unsigned long *array, int bit)
 struct kbd_desc;
 struct kbd_dev;
 
-int kbd_desc_new(struct kbd_desc **out,
-                       const char *layout,
-                       const char *variant,
-                       const char *options);
-void kbd_desc_ref(struct kbd_desc *desc);
-void kbd_desc_unref(struct kbd_desc *desc);
+struct kbd_desc_ops {
+       int (*init) (struct kbd_desc **out, const char *layout,
+                    const char *variant, const char *options);
+       void (*ref) (struct kbd_desc *desc);
+       void (*unref) (struct kbd_desc *desc);
+       int (*alloc) (struct kbd_desc *desc, struct kbd_dev **out);
+       void (*keysym_to_string) (uint32_t keysym, char *str, size_t size);
+};
 
-int kbd_dev_new(struct kbd_dev **out, struct kbd_desc *desc);
-void kbd_dev_ref(struct kbd_dev *state);
-void kbd_dev_unref(struct kbd_dev *state);
+struct kbd_dev_ops {
+       void (*ref) (struct kbd_dev *dev);
+       void (*unref) (struct kbd_dev *dev);
+       void (*reset) (struct kbd_dev *dev, const unsigned long *ledbits);
+       int (*process) (struct kbd_dev *dev, uint16_t state, uint16_t code,
+                       struct uterm_input_event *out);
+};
 
-/*
- * This resets the keyboard state in case it got out of sync. It's mainly used
- * to sync our notion of the keyboard state with what the keyboard LEDs show.
- */
-void kbd_dev_reset(struct kbd_dev *kbd, const unsigned long *ledbits);
+struct plain_desc {
+       int unused;
+};
 
-/*
- * This is the entry point to the keyboard processing.
- * We get an evdev scancode and the keyboard state, and should put out a
- * proper input event.
- * Some evdev input events shouldn't result in us sending an input event
- * (e.g. a key release):
- * - If the event was filled out, 0 is returned.
- * - Otherwise, if there was no error, -ENOKEY is returned.
- */
-int kbd_dev_process_key(struct kbd_dev *kbd,
-                       uint16_t key_state,
-                       uint16_t code,
-                       struct uterm_input_event *out);
+struct plain_dev {
+       unsigned int mods;
+};
+
+static const bool plain_available = true;
+extern const struct kbd_desc_ops plain_desc_ops;
+extern const struct kbd_dev_ops plain_dev_ops;
+
+#ifdef UTERM_HAVE_XKBCOMMON
+
+struct uxkb_desc {
+       struct xkb_context *ctx;
+       struct xkb_keymap *keymap;
+};
+
+struct uxkb_dev {
+       struct xkb_state *state;
+};
+
+static const bool uxkb_available = true;
+extern const struct kbd_desc_ops uxkb_desc_ops;
+extern const struct kbd_dev_ops uxkb_dev_ops;
+
+#else /* !UTERM_HAVE_XKBCOMMON */
 
-void kbd_dev_keysym_to_string(uint32_t keysym, char *str, size_t size);
+struct uxkb_desc {
+       int unused;
+};
+
+struct uxkb_dev {
+       int unused;
+};
+
+static const bool xkb_available = false;
+static const struct kbd_desc_ops uxkb_desc_ops;
+static const struct kbd_dev_ops uxkb_dev_ops;
+
+#endif /* UTERM_HAVE_XKBCOMMON */
+
+struct kbd_desc {
+       unsigned long ref;
+       const struct kbd_desc_ops *ops;
+
+       union {
+               struct plain_desc plain;
+               struct uxkb_desc uxkb;
+       };
+};
+
+struct kbd_dev {
+       unsigned long ref;
+       struct kbd_desc *desc;
+       const struct kbd_dev_ops *ops;
+
+       union {
+               struct plain_dev plain;
+               struct uxkb_dev uxkb;
+       };
+};
+
+enum kbd_mode {
+       KBD_PLAIN,
+       KBD_UXKB,
+};
+
+static inline int kbd_desc_new(struct kbd_desc **out, const char *layout,
+                              const char *variant, const char *options,
+                              unsigned int mode)
+{
+       const struct kbd_desc_ops *ops;
+
+       switch (mode) {
+       case KBD_UXKB:
+               if (!uxkb_available) {
+                       log_error("XKB KBD backend not available");
+                       return -EOPNOTSUPP;
+               }
+               ops = &uxkb_desc_ops;
+               break;
+       case KBD_PLAIN:
+               if (!plain_available) {
+                       log_error("plain KBD backend not available");
+                       return -EOPNOTSUPP;
+               }
+               ops = &plain_desc_ops;
+               break;
+       default:
+               log_error("unknown KBD backend %u", mode);
+               return -EINVAL;
+       }
+
+       return ops->init(out, layout, variant, options);
+}
+
+static inline void kbd_desc_ref(struct kbd_desc *desc)
+{
+       if (!desc)
+               return;
+
+       return desc->ops->ref(desc);
+}
+
+static inline void kbd_desc_unref(struct kbd_desc *desc)
+{
+       if (!desc)
+               return;
+
+       return desc->ops->unref(desc);
+}
+
+static inline int kbd_desc_alloc(struct kbd_desc *desc, struct kbd_dev **out)
+{
+       if (!desc)
+               return -EINVAL;
+
+       return desc->ops->alloc(desc, out);
+}
+
+static inline void kbd_desc_keysym_to_string(struct kbd_desc *desc,
+                                            uint32_t keysym,
+                                            char *str, size_t size)
+{
+       if (!desc)
+               return;
+
+       return desc->ops->keysym_to_string(keysym, str, size);
+}
+
+static inline void kbd_dev_ref(struct kbd_dev *dev)
+{
+       if (!dev)
+               return;
+
+       return dev->ops->ref(dev);
+}
+
+static inline void kbd_dev_unref(struct kbd_dev *dev)
+{
+       if (!dev)
+               return;
+
+       return dev->ops->unref(dev);
+}
+
+static inline void kbd_dev_reset(struct kbd_dev *dev,
+                                const unsigned long *ledbits)
+{
+       if (!dev)
+               return;
+
+       return dev->ops->reset(dev, ledbits);
+}
+
+static inline int kbd_dev_process(struct kbd_dev *dev,
+                                 uint16_t key_state,
+                                 uint16_t code,
+                                 struct uterm_input_event *out)
+{
+       if (!dev)
+               return -EINVAL;
+
+       return dev->ops->process(dev, key_state, code, out);
+}
 
 #endif /* UTERM_INTERNAL_H */