0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #include <linux/module.h>
0017 #include <linux/init.h>
0018 #include <linux/input.h>
0019 #include <linux/delay.h>
0020 #include <linux/interrupt.h>
0021 #include <linux/keyboard.h>
0022 #include <linux/platform_device.h>
0023
0024 #include <asm/amigaints.h>
0025 #include <asm/amigahw.h>
0026 #include <asm/irq.h>
0027
0028 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
0029 MODULE_DESCRIPTION("Amiga keyboard driver");
0030 MODULE_LICENSE("GPL");
0031
0032 #ifdef CONFIG_HW_CONSOLE
0033 static unsigned char amikbd_keycode[0x78] __initdata = {
0034 [0] = KEY_GRAVE,
0035 [1] = KEY_1,
0036 [2] = KEY_2,
0037 [3] = KEY_3,
0038 [4] = KEY_4,
0039 [5] = KEY_5,
0040 [6] = KEY_6,
0041 [7] = KEY_7,
0042 [8] = KEY_8,
0043 [9] = KEY_9,
0044 [10] = KEY_0,
0045 [11] = KEY_MINUS,
0046 [12] = KEY_EQUAL,
0047 [13] = KEY_BACKSLASH,
0048 [15] = KEY_KP0,
0049 [16] = KEY_Q,
0050 [17] = KEY_W,
0051 [18] = KEY_E,
0052 [19] = KEY_R,
0053 [20] = KEY_T,
0054 [21] = KEY_Y,
0055 [22] = KEY_U,
0056 [23] = KEY_I,
0057 [24] = KEY_O,
0058 [25] = KEY_P,
0059 [26] = KEY_LEFTBRACE,
0060 [27] = KEY_RIGHTBRACE,
0061 [29] = KEY_KP1,
0062 [30] = KEY_KP2,
0063 [31] = KEY_KP3,
0064 [32] = KEY_A,
0065 [33] = KEY_S,
0066 [34] = KEY_D,
0067 [35] = KEY_F,
0068 [36] = KEY_G,
0069 [37] = KEY_H,
0070 [38] = KEY_J,
0071 [39] = KEY_K,
0072 [40] = KEY_L,
0073 [41] = KEY_SEMICOLON,
0074 [42] = KEY_APOSTROPHE,
0075 [43] = KEY_BACKSLASH,
0076 [45] = KEY_KP4,
0077 [46] = KEY_KP5,
0078 [47] = KEY_KP6,
0079 [48] = KEY_102ND,
0080 [49] = KEY_Z,
0081 [50] = KEY_X,
0082 [51] = KEY_C,
0083 [52] = KEY_V,
0084 [53] = KEY_B,
0085 [54] = KEY_N,
0086 [55] = KEY_M,
0087 [56] = KEY_COMMA,
0088 [57] = KEY_DOT,
0089 [58] = KEY_SLASH,
0090 [60] = KEY_KPDOT,
0091 [61] = KEY_KP7,
0092 [62] = KEY_KP8,
0093 [63] = KEY_KP9,
0094 [64] = KEY_SPACE,
0095 [65] = KEY_BACKSPACE,
0096 [66] = KEY_TAB,
0097 [67] = KEY_KPENTER,
0098 [68] = KEY_ENTER,
0099 [69] = KEY_ESC,
0100 [70] = KEY_DELETE,
0101 [74] = KEY_KPMINUS,
0102 [76] = KEY_UP,
0103 [77] = KEY_DOWN,
0104 [78] = KEY_RIGHT,
0105 [79] = KEY_LEFT,
0106 [80] = KEY_F1,
0107 [81] = KEY_F2,
0108 [82] = KEY_F3,
0109 [83] = KEY_F4,
0110 [84] = KEY_F5,
0111 [85] = KEY_F6,
0112 [86] = KEY_F7,
0113 [87] = KEY_F8,
0114 [88] = KEY_F9,
0115 [89] = KEY_F10,
0116 [90] = KEY_KPLEFTPAREN,
0117 [91] = KEY_KPRIGHTPAREN,
0118 [92] = KEY_KPSLASH,
0119 [93] = KEY_KPASTERISK,
0120 [94] = KEY_KPPLUS,
0121 [95] = KEY_HELP,
0122 [96] = KEY_LEFTSHIFT,
0123 [97] = KEY_RIGHTSHIFT,
0124 [98] = KEY_CAPSLOCK,
0125 [99] = KEY_LEFTCTRL,
0126 [100] = KEY_LEFTALT,
0127 [101] = KEY_RIGHTALT,
0128 [102] = KEY_LEFTMETA,
0129 [103] = KEY_RIGHTMETA
0130 };
0131
0132 static void __init amikbd_init_console_keymaps(void)
0133 {
0134
0135 unsigned short temp_map[NR_KEYS];
0136 int i, j;
0137
0138 for (i = 0; i < MAX_NR_KEYMAPS; i++) {
0139 if (!key_maps[i])
0140 continue;
0141 memset(temp_map, 0, sizeof(temp_map));
0142 for (j = 0; j < 0x78; j++) {
0143 if (!amikbd_keycode[j])
0144 continue;
0145 temp_map[j] = key_maps[i][amikbd_keycode[j]];
0146 }
0147 for (j = 0; j < NR_KEYS; j++) {
0148 if (!temp_map[j])
0149 temp_map[j] = 0xf200;
0150 }
0151 memcpy(key_maps[i], temp_map, sizeof(temp_map));
0152 }
0153 }
0154 #else
0155 static inline void amikbd_init_console_keymaps(void) {}
0156 #endif
0157
0158 static const char *amikbd_messages[8] = {
0159 [0] = KERN_ALERT "amikbd: Ctrl-Amiga-Amiga reset warning!!\n",
0160 [1] = KERN_WARNING "amikbd: keyboard lost sync\n",
0161 [2] = KERN_WARNING "amikbd: keyboard buffer overflow\n",
0162 [3] = KERN_WARNING "amikbd: keyboard controller failure\n",
0163 [4] = KERN_ERR "amikbd: keyboard selftest failure\n",
0164 [5] = KERN_INFO "amikbd: initiate power-up key stream\n",
0165 [6] = KERN_INFO "amikbd: terminate power-up key stream\n",
0166 [7] = KERN_WARNING "amikbd: keyboard interrupt\n"
0167 };
0168
0169 static irqreturn_t amikbd_interrupt(int irq, void *data)
0170 {
0171 struct input_dev *dev = data;
0172 unsigned char scancode, down;
0173
0174 scancode = ~ciaa.sdr;
0175 ciaa.cra |= 0x40;
0176 udelay(85);
0177 ciaa.cra &= ~0x40;
0178
0179 down = !(scancode & 1);
0180 scancode >>= 1;
0181
0182 if (scancode < 0x78) {
0183 if (scancode == 98) {
0184 input_report_key(dev, scancode, 1);
0185 input_report_key(dev, scancode, 0);
0186 } else {
0187 input_report_key(dev, scancode, down);
0188 }
0189
0190 input_sync(dev);
0191 } else
0192 printk(amikbd_messages[scancode - 0x78]);
0193
0194 return IRQ_HANDLED;
0195 }
0196
0197 static int __init amikbd_probe(struct platform_device *pdev)
0198 {
0199 struct input_dev *dev;
0200 int i, err;
0201
0202 dev = input_allocate_device();
0203 if (!dev) {
0204 dev_err(&pdev->dev, "Not enough memory for input device\n");
0205 return -ENOMEM;
0206 }
0207
0208 dev->name = pdev->name;
0209 dev->phys = "amikbd/input0";
0210 dev->id.bustype = BUS_AMIGA;
0211 dev->id.vendor = 0x0001;
0212 dev->id.product = 0x0001;
0213 dev->id.version = 0x0100;
0214 dev->dev.parent = &pdev->dev;
0215
0216 dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
0217
0218 for (i = 0; i < 0x78; i++)
0219 set_bit(i, dev->keybit);
0220
0221 amikbd_init_console_keymaps();
0222
0223 ciaa.cra &= ~0x41;
0224 err = request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd",
0225 dev);
0226 if (err)
0227 goto fail2;
0228
0229 err = input_register_device(dev);
0230 if (err)
0231 goto fail3;
0232
0233 platform_set_drvdata(pdev, dev);
0234
0235 return 0;
0236
0237 fail3: free_irq(IRQ_AMIGA_CIAA_SP, dev);
0238 fail2: input_free_device(dev);
0239 return err;
0240 }
0241
0242 static int __exit amikbd_remove(struct platform_device *pdev)
0243 {
0244 struct input_dev *dev = platform_get_drvdata(pdev);
0245
0246 free_irq(IRQ_AMIGA_CIAA_SP, dev);
0247 input_unregister_device(dev);
0248 return 0;
0249 }
0250
0251 static struct platform_driver amikbd_driver = {
0252 .remove = __exit_p(amikbd_remove),
0253 .driver = {
0254 .name = "amiga-keyboard",
0255 },
0256 };
0257
0258 module_platform_driver_probe(amikbd_driver, amikbd_probe);
0259
0260 MODULE_ALIAS("platform:amiga-keyboard");