root/drivers/staging/nvec/nvec_kbd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ARRAY_SIZE
  2. nvec_kbd_toggle_led
  3. nvec_keys_notifier
  4. nvec_kbd_event
  5. nvec_kbd_probe
  6. nvec_kbd_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * nvec_kbd: keyboard driver for a NVIDIA compliant embedded controller
   4  *
   5  * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.launchpad.net>
   6  *
   7  * Authors:  Pierre-Hugues Husson <phhusson@free.fr>
   8  *           Marc Dietrich <marvin24@gmx.de>
   9  */
  10 
  11 #include <linux/module.h>
  12 #include <linux/slab.h>
  13 #include <linux/input.h>
  14 #include <linux/delay.h>
  15 #include <linux/platform_device.h>
  16 
  17 #include "nvec-keytable.h"
  18 #include "nvec.h"
  19 
  20 enum kbd_subcmds {
  21         CNFG_WAKE = 3,
  22         CNFG_WAKE_KEY_REPORTING,
  23         SET_LEDS = 0xed,
  24         ENABLE_KBD = 0xf4,
  25         DISABLE_KBD,
  26 };
  27 
  28 static unsigned char keycodes[ARRAY_SIZE(code_tab_102us)
  29                               + ARRAY_SIZE(extcode_tab_us102)];
  30 
  31 struct nvec_keys {
  32         struct input_dev *input;
  33         struct notifier_block notifier;
  34         struct nvec_chip *nvec;
  35         bool caps_lock;
  36 };
  37 
  38 static struct nvec_keys keys_dev;
  39 
  40 static void nvec_kbd_toggle_led(void)
  41 {
  42         char buf[] = { NVEC_KBD, SET_LEDS, 0 };
  43 
  44         keys_dev.caps_lock = !keys_dev.caps_lock;
  45 
  46         if (keys_dev.caps_lock)
  47                 /* should be BIT(0) only, firmware bug? */
  48                 buf[2] = BIT(0) | BIT(1) | BIT(2);
  49 
  50         nvec_write_async(keys_dev.nvec, buf, sizeof(buf));
  51 }
  52 
  53 static int nvec_keys_notifier(struct notifier_block *nb,
  54                               unsigned long event_type, void *data)
  55 {
  56         int code, state;
  57         unsigned char *msg = data;
  58 
  59         if (event_type == NVEC_KB_EVT) {
  60                 int _size = (msg[0] & (3 << 5)) >> 5;
  61 
  62 /* power on/off button */
  63                 if (_size == NVEC_VAR_SIZE)
  64                         return NOTIFY_STOP;
  65 
  66                 if (_size == NVEC_3BYTES)
  67                         msg++;
  68 
  69                 code = msg[1] & 0x7f;
  70                 state = msg[1] & 0x80;
  71 
  72                 if (code_tabs[_size][code] == KEY_CAPSLOCK && state)
  73                         nvec_kbd_toggle_led();
  74 
  75                 input_report_key(keys_dev.input, code_tabs[_size][code],
  76                                  !state);
  77                 input_sync(keys_dev.input);
  78 
  79                 return NOTIFY_STOP;
  80         }
  81 
  82         return NOTIFY_DONE;
  83 }
  84 
  85 static int nvec_kbd_event(struct input_dev *dev, unsigned int type,
  86                           unsigned int code, int value)
  87 {
  88         struct nvec_chip *nvec = keys_dev.nvec;
  89         char buf[] = { NVEC_KBD, SET_LEDS, 0 };
  90 
  91         if (type == EV_REP)
  92                 return 0;
  93 
  94         if (type != EV_LED)
  95                 return -1;
  96 
  97         if (code != LED_CAPSL)
  98                 return -1;
  99 
 100         buf[2] = !!value;
 101         nvec_write_async(nvec, buf, sizeof(buf));
 102 
 103         return 0;
 104 }
 105 
 106 static int nvec_kbd_probe(struct platform_device *pdev)
 107 {
 108         struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
 109         int i, j, err;
 110         struct input_dev *idev;
 111         char    clear_leds[] = { NVEC_KBD, SET_LEDS, 0 },
 112                 enable_kbd[] = { NVEC_KBD, ENABLE_KBD },
 113                 cnfg_wake[] = { NVEC_KBD, CNFG_WAKE, true, true },
 114                 cnfg_wake_key_reporting[] = { NVEC_KBD, CNFG_WAKE_KEY_REPORTING,
 115                                                 true };
 116 
 117         j = 0;
 118 
 119         for (i = 0; i < ARRAY_SIZE(code_tab_102us); ++i)
 120                 keycodes[j++] = code_tab_102us[i];
 121 
 122         for (i = 0; i < ARRAY_SIZE(extcode_tab_us102); ++i)
 123                 keycodes[j++] = extcode_tab_us102[i];
 124 
 125         idev = devm_input_allocate_device(&pdev->dev);
 126         idev->name = "nvec keyboard";
 127         idev->phys = "nvec";
 128         idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_LED);
 129         idev->ledbit[0] = BIT_MASK(LED_CAPSL);
 130         idev->event = nvec_kbd_event;
 131         idev->keycode = keycodes;
 132         idev->keycodesize = sizeof(unsigned char);
 133         idev->keycodemax = ARRAY_SIZE(keycodes);
 134 
 135         for (i = 0; i < ARRAY_SIZE(keycodes); ++i)
 136                 set_bit(keycodes[i], idev->keybit);
 137 
 138         clear_bit(0, idev->keybit);
 139         err = input_register_device(idev);
 140         if (err)
 141                 return err;
 142 
 143         keys_dev.input = idev;
 144         keys_dev.notifier.notifier_call = nvec_keys_notifier;
 145         keys_dev.nvec = nvec;
 146         nvec_register_notifier(nvec, &keys_dev.notifier, 0);
 147 
 148         /* Enable keyboard */
 149         nvec_write_async(nvec, enable_kbd, 2);
 150 
 151         /* configures wake on special keys */
 152         nvec_write_async(nvec, cnfg_wake, 4);
 153         /* enable wake key reporting */
 154         nvec_write_async(nvec, cnfg_wake_key_reporting, 3);
 155 
 156         /* Disable caps lock LED */
 157         nvec_write_async(nvec, clear_leds, sizeof(clear_leds));
 158 
 159         return 0;
 160 }
 161 
 162 static int nvec_kbd_remove(struct platform_device *pdev)
 163 {
 164         struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
 165         char disable_kbd[] = { NVEC_KBD, DISABLE_KBD },
 166              uncnfg_wake_key_reporting[] = { NVEC_KBD, CNFG_WAKE_KEY_REPORTING,
 167                                                 false };
 168         nvec_write_async(nvec, uncnfg_wake_key_reporting, 3);
 169         nvec_write_async(nvec, disable_kbd, 2);
 170         nvec_unregister_notifier(nvec, &keys_dev.notifier);
 171 
 172         return 0;
 173 }
 174 
 175 static struct platform_driver nvec_kbd_driver = {
 176         .probe  = nvec_kbd_probe,
 177         .remove = nvec_kbd_remove,
 178         .driver = {
 179                 .name = "nvec-kbd",
 180         },
 181 };
 182 
 183 module_platform_driver(nvec_kbd_driver);
 184 
 185 MODULE_AUTHOR("Marc Dietrich <marvin24@gmx.de>");
 186 MODULE_DESCRIPTION("NVEC keyboard driver");
 187 MODULE_ALIAS("platform:nvec-kbd");
 188 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */