Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Copyright (c) 2000-2001 Vojtech Pavlik
0004  *
0005  *  Based on the work of:
0006  *  Hamish Macdonald
0007  */
0008 
0009 /*
0010  * Amiga keyboard driver for Linux/m68k
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     /* We can spare 512 bytes on stack for temp_map in init path. */
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 /* !CONFIG_HW_CONSOLE */
0155 static inline void amikbd_init_console_keymaps(void) {}
0156 #endif /* !CONFIG_HW_CONSOLE */
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;       /* get and invert scancode (keyboard is active low) */
0175     ciaa.cra |= 0x40;       /* switch SP pin to output for handshake */
0176     udelay(85);         /* wait until 85 us have expired */
0177     ciaa.cra &= ~0x40;      /* switch CIA serial port to input mode */
0178 
0179     down = !(scancode & 1);     /* lowest bit is release bit */
0180     scancode >>= 1;
0181 
0182     if (scancode < 0x78) {      /* scancodes < 0x78 are keys */
0183         if (scancode == 98) {   /* CapsLock is a toggle switch key on Amiga */
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              /* scancodes >= 0x78 are error codes */
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;   /* serial data in, turn off TA */
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");