^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 1999-2001 Vojtech Pavlik
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Sun keyboard driver for Linux
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/serio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/workqueue.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define DRIVER_DESC "Sun keyboard driver"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) MODULE_DESCRIPTION(DRIVER_DESC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static unsigned char sunkbd_keycode[128] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) 0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64,112,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) 65, 66, 67, 56,103,119, 99, 70,105,130,131,108,106, 1, 2, 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 41, 14,110,113, 98, 55,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) 116,132, 83,133,102, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) 26, 27,111,127, 71, 72, 73, 74,134,135,107, 0, 29, 30, 31, 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) 33, 34, 35, 36, 37, 38, 39, 40, 43, 28, 96, 75, 76, 77, 82,136,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) 104,137, 69, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,101,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) 79, 80, 81, 0, 0, 0,138, 58,125, 57,126,109, 86, 78
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define SUNKBD_CMD_RESET 0x1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define SUNKBD_CMD_BELLON 0x2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define SUNKBD_CMD_BELLOFF 0x3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define SUNKBD_CMD_CLICK 0xa
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define SUNKBD_CMD_NOCLICK 0xb
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define SUNKBD_CMD_SETLED 0xe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define SUNKBD_CMD_LAYOUT 0xf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define SUNKBD_RET_RESET 0xff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define SUNKBD_RET_ALLUP 0x7f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define SUNKBD_RET_LAYOUT 0xfe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define SUNKBD_LAYOUT_5_MASK 0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define SUNKBD_RELEASE 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define SUNKBD_KEY 0x7f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * Per-keyboard data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct sunkbd {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) unsigned char keycode[ARRAY_SIZE(sunkbd_keycode)];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct input_dev *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct serio *serio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct work_struct tq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) wait_queue_head_t wait;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) char name[64];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) char phys[32];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) char type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) bool enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) volatile s8 reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) volatile s8 layout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * sunkbd_interrupt() is called by the low level driver when a character
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * is received.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static irqreturn_t sunkbd_interrupt(struct serio *serio,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) unsigned char data, unsigned int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct sunkbd *sunkbd = serio_get_drvdata(serio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if (sunkbd->reset <= -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * If cp[i] is 0xff, sunkbd->reset will stay -1.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * The keyboard sends 0xff 0xff 0xID on powerup.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) sunkbd->reset = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) wake_up_interruptible(&sunkbd->wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (sunkbd->layout == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) sunkbd->layout = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) wake_up_interruptible(&sunkbd->wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) switch (data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) case SUNKBD_RET_RESET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (sunkbd->enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) schedule_work(&sunkbd->tq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) sunkbd->reset = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) case SUNKBD_RET_LAYOUT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) sunkbd->layout = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) case SUNKBD_RET_ALLUP: /* All keys released */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (!sunkbd->enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (sunkbd->keycode[data & SUNKBD_KEY]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) input_report_key(sunkbd->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) sunkbd->keycode[data & SUNKBD_KEY],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) !(data & SUNKBD_RELEASE));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) input_sync(sunkbd->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) printk(KERN_WARNING
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) "sunkbd.c: Unknown key (scancode %#x) %s.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) data & SUNKBD_KEY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) data & SUNKBD_RELEASE ? "released" : "pressed");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * sunkbd_event() handles events from the input module.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static int sunkbd_event(struct input_dev *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) unsigned int type, unsigned int code, int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) struct sunkbd *sunkbd = input_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) switch (type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) case EV_LED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) serio_write(sunkbd->serio, SUNKBD_CMD_SETLED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) serio_write(sunkbd->serio,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) (!!test_bit(LED_CAPSL, dev->led) << 3) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) (!!test_bit(LED_SCROLLL, dev->led) << 2) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) (!!test_bit(LED_COMPOSE, dev->led) << 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) !!test_bit(LED_NUML, dev->led));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) case EV_SND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) switch (code) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) case SND_CLICK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) serio_write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) case SND_BELL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) serio_write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) * sunkbd_initialize() checks for a Sun keyboard attached, and determines
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * its type.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) static int sunkbd_initialize(struct sunkbd *sunkbd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) sunkbd->reset = -2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) serio_write(sunkbd->serio, SUNKBD_CMD_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) if (sunkbd->reset < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) sunkbd->type = sunkbd->reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (sunkbd->type == 4) { /* Type 4 keyboard */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) sunkbd->layout = -2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) serio_write(sunkbd->serio, SUNKBD_CMD_LAYOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) wait_event_interruptible_timeout(sunkbd->wait,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) sunkbd->layout >= 0, HZ / 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (sunkbd->layout < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) sunkbd->type = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) * sunkbd_set_leds_beeps() sets leds and beeps to a state the computer remembers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) * they were in.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) static void sunkbd_set_leds_beeps(struct sunkbd *sunkbd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) serio_write(sunkbd->serio, SUNKBD_CMD_SETLED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) serio_write(sunkbd->serio,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) (!!test_bit(LED_CAPSL, sunkbd->dev->led) << 3) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) (!!test_bit(LED_SCROLLL, sunkbd->dev->led) << 2) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) (!!test_bit(LED_COMPOSE, sunkbd->dev->led) << 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) !!test_bit(LED_NUML, sunkbd->dev->led));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) serio_write(sunkbd->serio,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev->snd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) serio_write(sunkbd->serio,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) * sunkbd_reinit() wait for the keyboard reset to complete and restores state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * of leds and beeps.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) static void sunkbd_reinit(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) struct sunkbd *sunkbd = container_of(work, struct sunkbd, tq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) * It is OK that we check sunkbd->enabled without pausing serio,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) * as we only want to catch true->false transition that will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) * happen once and we will be woken up for it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) wait_event_interruptible_timeout(sunkbd->wait,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) sunkbd->reset >= 0 || !sunkbd->enabled,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) if (sunkbd->reset >= 0 && sunkbd->enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) sunkbd_set_leds_beeps(sunkbd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) static void sunkbd_enable(struct sunkbd *sunkbd, bool enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) serio_pause_rx(sunkbd->serio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) sunkbd->enabled = enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) serio_continue_rx(sunkbd->serio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) if (!enable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) wake_up_interruptible(&sunkbd->wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) cancel_work_sync(&sunkbd->tq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) * sunkbd_connect() probes for a Sun keyboard and fills the necessary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) * structures.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) struct sunkbd *sunkbd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) struct input_dev *input_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) int err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) sunkbd = kzalloc(sizeof(struct sunkbd), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) input_dev = input_allocate_device();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (!sunkbd || !input_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) goto fail1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) sunkbd->serio = serio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) sunkbd->dev = input_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) init_waitqueue_head(&sunkbd->wait);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) INIT_WORK(&sunkbd->tq, sunkbd_reinit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) snprintf(sunkbd->phys, sizeof(sunkbd->phys), "%s/input0", serio->phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) serio_set_drvdata(serio, sunkbd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) err = serio_open(serio, drv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) goto fail2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (sunkbd_initialize(sunkbd) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) goto fail3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) snprintf(sunkbd->name, sizeof(sunkbd->name),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) "Sun Type %d keyboard", sunkbd->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) input_dev->name = sunkbd->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) input_dev->phys = sunkbd->phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) input_dev->id.bustype = BUS_RS232;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) input_dev->id.vendor = SERIO_SUNKBD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) input_dev->id.product = sunkbd->type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) input_dev->id.version = 0x0100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) input_dev->dev.parent = &serio->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) input_set_drvdata(input_dev, sunkbd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) input_dev->event = sunkbd_event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) BIT_MASK(EV_SND) | BIT_MASK(EV_REP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) input_dev->ledbit[0] = BIT_MASK(LED_CAPSL) | BIT_MASK(LED_COMPOSE) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_NUML);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) input_dev->sndbit[0] = BIT_MASK(SND_CLICK) | BIT_MASK(SND_BELL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) input_dev->keycode = sunkbd->keycode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) input_dev->keycodesize = sizeof(unsigned char);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) input_dev->keycodemax = ARRAY_SIZE(sunkbd_keycode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) for (i = 0; i < ARRAY_SIZE(sunkbd_keycode); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) __set_bit(sunkbd->keycode[i], input_dev->keybit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) __clear_bit(KEY_RESERVED, input_dev->keybit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) sunkbd_enable(sunkbd, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) err = input_register_device(sunkbd->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) goto fail4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) fail4: sunkbd_enable(sunkbd, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) fail3: serio_close(serio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) fail2: serio_set_drvdata(serio, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) fail1: input_free_device(input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) kfree(sunkbd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) * sunkbd_disconnect() unregisters and closes behind us.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) static void sunkbd_disconnect(struct serio *serio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) struct sunkbd *sunkbd = serio_get_drvdata(serio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) sunkbd_enable(sunkbd, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) input_unregister_device(sunkbd->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) serio_close(serio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) serio_set_drvdata(serio, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) kfree(sunkbd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) static const struct serio_device_id sunkbd_serio_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) .type = SERIO_RS232,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) .proto = SERIO_SUNKBD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) .id = SERIO_ANY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) .extra = SERIO_ANY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) .type = SERIO_RS232,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) .proto = SERIO_UNKNOWN, /* sunkbd does probe */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) .id = SERIO_ANY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) .extra = SERIO_ANY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) { 0 }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) MODULE_DEVICE_TABLE(serio, sunkbd_serio_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) static struct serio_driver sunkbd_drv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) .name = "sunkbd",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) .description = DRIVER_DESC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) .id_table = sunkbd_serio_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) .interrupt = sunkbd_interrupt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) .connect = sunkbd_connect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) .disconnect = sunkbd_disconnect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) module_serio_driver(sunkbd_drv);