1/* 2 * linux/arch/m68k/hp300/hil.c 3 * 4 * Copyright (C) 1998 Philip Blundell <philb@gnu.org> 5 * 6 * HP300 Human Interface Loop driver. This handles the keyboard and mouse. 7 */ 8 9#include <linux/stddef.h> 10#include <linux/kernel.h> 11#include <linux/sched.h> 12#include <linux/init.h> 13#include <linux/keyboard.h> 14#include <linux/kbd_ll.h> 15#include <asm/io.h> 16#include <asm/hwtest.h> 17#include <asm/ptrace.h> 18#include <asm/irq.h> 19#include <asm/system.h> 20 21#define HILBASE 0xf0428000 22#define HIL_DATA 0x1 23#define HIL_CMD 0x3 24 25#define HIL_BUSY 0x02 26#define HIL_DATA_RDY 0x01 27 28#define hil_busy() (in_8(HILBASE + HIL_CMD) & HIL_BUSY) 29#define hil_data_available() (in_8(HILBASE + HIL_CMD) & HIL_DATA_RDY) 30#define hil_status() (in_8(HILBASE + HIL_CMD)) 31#define hil_command(x) out_8(HILBASE + HIL_CMD, (x)) 32#define hil_read_data() (in_8(HILBASE + HIL_DATA)) 33#define hil_write_data(x) out_8(HILBASE + HIL_DATA, (x)) 34 35#define HIL_SETARD 0xA0 /* set auto-repeat delay */ 36#define HIL_SETARR 0xA2 /* set auto-repeat rate */ 37#define HIL_SETTONE 0xA3 /* set tone generator */ 38#define HIL_CNMT 0xB2 /* clear nmi */ 39#define HIL_INTON 0x5C /* Turn on interrupts. */ 40#define HIL_INTOFF 0x5D /* Turn off interrupts. */ 41#define HIL_TRIGGER 0xC5 /* trigger command */ 42#define HIL_STARTCMD 0xE0 /* start loop command */ 43#define HIL_TIMEOUT 0xFE /* timeout */ 44#define HIL_READTIME 0x13 /* Read real time register */ 45 46#define HIL_READBUSY 0x02 /* internal "busy" register */ 47#define HIL_READKBDLANG 0x12 /* read keyboard language code */ 48#define HIL_READKBDSADR 0xF9 49#define HIL_WRITEKBDSADR 0xE9 50#define HIL_READLPSTAT 0xFA 51#define HIL_WRITELPSTAT 0xEA 52#define HIL_READLPCTRL 0xFB 53#define HIL_WRITELPCTRL 0xEB 54 55#define HIL_IRQ 1 56 57#define plain_map hp_plain_map 58#define shift_map hp_shift_map 59#define altgr_map hp_altgr_map 60#define ctrl_map hp_ctrl_map 61#define shift_ctrl_map hp_shift_ctrl_map 62#define alt_map hp_alt_map 63#define ctrl_alt_map hp_ctrl_alt_map 64 65u_short plain_map[NR_KEYS] = { 66 0xf200, 0xf200, 0xf703, 0xf703, 0xf700, 0xf700, 0xf702, 0xf200, 67 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 68 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 69 0xfb62, 0xfb76, 0xfb63, 0xfb78, 0xfb7a, 0xf200, 0xf200, 0xf01b, 70 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 71 0xfb68, 0xfb67, 0xfb66, 0xfb64, 0xfb73, 0xfb61, 0xf200, 0xf207, 72 0xfb75, 0xfb79, 0xfb74, 0xfb72, 0xfb65, 0xfb77, 0xfb71, 0xf009, 73 0xf037, 0xf036, 0xf035, 0xf034, 0xf033, 0xf032, 0xf031, 0xf060, 74 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 75 0xf200, 0xf103, 0xf102, 0xf101, 0xf100, 0xf200, 0xf200, 0xf200, 76 0xf200, 0xf104, 0xf105, 0xf106, 0xf107, 0xf200, 0xf200, 0xf200, 77 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf200, 0xf200, 78 0xfb69, 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf05c, 0xf200, 0xf200, 79 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b, 0xf027, 0xf201, 0xf200, 0xf200, 80 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf200, 0xf200, 0xf200, 0xf200, 81 0xfb6e, 0xf020, 0xf200, 0xf200, 0xf601, 0xf600, 0xf603, 0xf602, 82}; 83 84u_short shift_map[NR_KEYS] = { 85 0xf200, 0xf200, 0xf703, 0xf703, 0xf700, 0xf700, 0xf702, 0xf200, 86 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 87 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 88 0xfb42, 0xfb56, 0xfb43, 0xfb58, 0xfb5a, 0xf200, 0xf200, 0xf07f, 89 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 90 0xfb48, 0xfb47, 0xfb46, 0xfb44, 0xfb53, 0xfb41, 0xf200, 0xf207, 91 0xfb55, 0xfb59, 0xfb54, 0xfb52, 0xfb45, 0xfb57, 0xfb51, 0xf009, 92 0xf026, 0xf05e, 0xf025, 0xf024, 0xf023, 0xf040, 0xf021, 0xf07e, 93 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 94 0xf200, 0xf103, 0xf102, 0xf101, 0xf100, 0xf200, 0xf200, 0xf200, 95 0xf200, 0xf104, 0xf105, 0xf106, 0xf107, 0xf200, 0xf200, 0xf200, 96 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf200, 0xf200, 0xf200, 97 0xfb49, 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf07c, 0xf200, 0xf200, 98 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a, 0xf022, 0xf201, 0xf200, 0xf200, 99 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf200, 0xf200, 0xf200, 0xf200, 100 0xfb4e, 0xf020, 0xf200, 0xf200, 0xf601, 0xf600, 0xf603, 0xf602, 101}; 102 103u_short altgr_map[NR_KEYS] = { 104 0xf200, 0xf200, 0xf703, 0xf703, 0xf700, 0xf700, 0xf702, 0xf200, 105 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 106 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 107 0xfb62, 0xfb76, 0xfb63, 0xfb78, 0xfb7a, 0xf200, 0xf200, 0xf200, 108 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 109 0xfb68, 0xfb67, 0xfb66, 0xfb64, 0xfb73, 0xfb61, 0xf200, 0xf207, 110 0xfb75, 0xfb79, 0xfb74, 0xfb72, 0xfb65, 0xfb77, 0xfb71, 0xf200, 111 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf040, 0xf021, 0xf200, 112 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 113 0xf200, 0xf103, 0xf102, 0xf101, 0xf100, 0xf200, 0xf200, 0xf200, 114 0xf200, 0xf104, 0xf105, 0xf106, 0xf107, 0xf200, 0xf200, 0xf200, 115 0xf02a, 0xf05b, 0xf05d, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 116 0xfb69, 0xfb6f, 0xfb70, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 117 0xfb6a, 0xfb6b, 0xfb6c, 0xf200, 0xf200, 0xf201, 0xf200, 0xf200, 118 0xfb6d, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 119 0xfb6e, 0xf200, 0xf200, 0xf200, 0xf601, 0xf600, 0xf603, 0xf602, 120}; 121 122u_short ctrl_map[NR_KEYS] = { 123 0xf200, 0xf200, 0xf703, 0xf703, 0xf700, 0xf700, 0xf702, 0xf200, 124 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 125 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 126 0xf002, 0xf016, 0xf003, 0xf018, 0xf01a, 0xf200, 0xf200, 0xf200, 127 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 128 0xf008, 0xf007, 0xf006, 0xf004, 0xf013, 0xf001, 0xf200, 0xf207, 129 0xf015, 0xf019, 0xf014, 0xf012, 0xf005, 0xf017, 0xf011, 0xf200, 130 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf000, 131 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 132 0xf200, 0xf503, 0xf502, 0xf501, 0xf500, 0xf200, 0xf200, 0xf200, 133 0xf200, 0xf504, 0xf505, 0xf506, 0xf507, 0xf200, 0xf200, 0xf200, 134 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 135 0xf009, 0xf00f, 0xf010, 0xf200, 0xf200, 0xf01c, 0xf200, 0xf200, 136 0xf00a, 0xf00b, 0xf00c, 0xf200, 0xf007, 0xf201, 0xf200, 0xf200, 137 0xf00d, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 138 0xf00e, 0xf200, 0xf200, 0xf200, 0xf601, 0xf600, 0xf603, 0xf602, 139}; 140 141u_short shift_ctrl_map[NR_KEYS] = { 142 0xf200, 0xf200, 0xf703, 0xf703, 0xf700, 0xf700, 0xf702, 0xf200, 143 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 144 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 145 0xf002, 0xf016, 0xf003, 0xf018, 0xf01a, 0xf200, 0xf200, 0xf200, 146 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 147 0xf008, 0xf007, 0xf006, 0xf004, 0xf013, 0xf001, 0xf200, 0xf207, 148 0xf015, 0xf019, 0xf014, 0xf012, 0xf005, 0xf017, 0xf011, 0xf200, 149 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 150 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 151 0xf200, 0xf103, 0xf102, 0xf101, 0xf100, 0xf200, 0xf200, 0xf200, 152 0xf200, 0xf104, 0xf105, 0xf106, 0xf107, 0xf200, 0xf200, 0xf200, 153 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 154 0xf009, 0xf00f, 0xf010, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 155 0xf00a, 0xf00b, 0xf00c, 0xf200, 0xf200, 0xf201, 0xf200, 0xf200, 156 0xf00d, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 157 0xf00e, 0xf200, 0xf200, 0xf200, 0xf601, 0xf600, 0xf603, 0xf602, 158}; 159 160u_short alt_map[NR_KEYS] = { 161 0xf200, 0xf200, 0xf703, 0xf703, 0xf700, 0xf700, 0xf702, 0xf200, 162 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 163 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 164 0xf862, 0xf876, 0xf863, 0xf878, 0xf87a, 0xf200, 0xf200, 0xf200, 165 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 166 0xf868, 0xf867, 0xf866, 0xf864, 0xf873, 0xf861, 0xf200, 0xf207, 167 0xf875, 0xf879, 0xf874, 0xf872, 0xf865, 0xf877, 0xf871, 0xf809, 168 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf860, 169 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 170 0xf200, 0xf103, 0xf102, 0xf101, 0xf100, 0xf200, 0xf200, 0xf200, 171 0xf200, 0xf104, 0xf105, 0xf106, 0xf107, 0xf200, 0xf200, 0xf200, 172 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 173 0xf869, 0xf86f, 0xf870, 0xf200, 0xf200, 0xf85c, 0xf200, 0xf200, 174 0xf86a, 0xf86b, 0xf86c, 0xf83b, 0xf827, 0xf201, 0xf200, 0xf200, 175 0xf86d, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 176 0xf86e, 0xf200, 0xf200, 0xf200, 0xf601, 0xf600, 0xf603, 0xf602, 177}; 178 179u_short ctrl_alt_map[NR_KEYS] = { 180 0xf200, 0xf200, 0xf703, 0xf703, 0xf700, 0xf700, 0xf702, 0xf200, 181 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 182 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 183 0xf802, 0xf816, 0xf803, 0xf818, 0xf81a, 0xf200, 0xf200, 0xf200, 184 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 185 0xf808, 0xf807, 0xf806, 0xf804, 0xf813, 0xf801, 0xf200, 0xf207, 186 0xf815, 0xf819, 0xf814, 0xf812, 0xf805, 0xf817, 0xf811, 0xf200, 187 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 188 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 189 0xf200, 0xf103, 0xf102, 0xf101, 0xf100, 0xf200, 0xf200, 0xf200, 190 0xf200, 0xf104, 0xf105, 0xf106, 0xf107, 0xf200, 0xf200, 0xf200, 191 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 192 0xf809, 0xf80f, 0xf810, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 193 0xf80a, 0xf80b, 0xf80c, 0xf200, 0xf200, 0xf201, 0xf200, 0xf200, 194 0xf80d, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 195 0xf80e, 0xf200, 0xf200, 0xf200, 0xf601, 0xf600, 0xf603, 0xf602, 196}; 197 198#undef plain_map 199#undef ctrl_alt_map 200#undef shift_map 201#undef altgr_map 202#undef ctrl_map 203#undef shift_ctrl_map 204#undef alt_map 205 206struct { 207 unsigned char s, c; 208 int valid; 209} hil_last; 210 211#define hil_getlast(s,c) do { s = hil_last.s; c = hil_last.c; hil_last.valid = 0; } while (0) 212 213struct { 214 unsigned char data[16]; 215 unsigned int ptr; 216} poll; 217 218unsigned char curdev = 0; 219 220static void poll_finished(void) 221{ 222 switch (poll.data[0]) 223 { 224 case 0x40: 225 { 226 int down = (poll.data[1] & 1) == 0; 227 unsigned char scode = poll.data[1] >> 1; 228 handle_scancode(scode, down); 229 } 230 break; 231 } 232 curdev = 0; 233} 234 235static inline void handle_status(unsigned char s, unsigned char c) 236{ 237 if (c & 0x8) { 238 /* End of block */ 239 if (c & 0x10) 240 poll_finished(); 241 } else { 242 if (c & 0x10) { 243 if (curdev) 244 poll_finished(); /* just in case */ 245 curdev = c & 7; 246 poll.ptr = 0; 247 } 248 } 249} 250 251static inline void handle_data(unsigned char s, unsigned char c) 252{ 253 if (curdev) 254 poll.data[poll.ptr++] = c; 255} 256 257/* 258 * Handle HIL interrupts. 259 */ 260 261static void hil_interrupt(int irq, void *handle, struct pt_regs *regs) 262{ 263 unsigned char s, c; 264 s = hil_status(); c = hil_read_data(); 265 switch (s >> 4) 266 { 267 case 0x5: 268 handle_status(s, c); 269 break; 270 case 0x6: 271 handle_data(s, c); 272 break; 273 case 0x4: 274 hil_last.s = s; 275 hil_last.c = c; 276 mb(); 277 hil_last.valid = 1; 278 break; 279 } 280} 281 282/* 283 * Send a command to the HIL 284 */ 285 286static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len) 287{ 288 unsigned long flags; 289 save_flags(flags); cli(); 290 while (hil_busy()); 291 hil_command(cmd); 292 while (len--) { 293 while (hil_busy()); 294 hil_write_data(*(data++)); 295 } 296 restore_flags(flags); 297} 298 299/* 300 * Initialise HIL. 301 */ 302 303int __init hp300_keyb_init(void) 304{ 305 unsigned char s, c, kbid; 306 unsigned int n = 0; 307 308 memcpy(key_maps[0], hp_plain_map, sizeof(plain_map)); 309 memcpy(key_maps[1], hp_shift_map, sizeof(plain_map)); 310 memcpy(key_maps[4], hp_ctrl_map, sizeof(plain_map)); 311 312 if (!hwreg_present((void *)(HILBASE + HIL_DATA))) 313 return 1; /* maybe this can happen */ 314 315 request_irq(HIL_IRQ, hil_interrupt, 0, "HIL", NULL); 316 317 /* Turn on interrupts */ 318 hil_do(HIL_INTON, NULL, 0); 319 320 /* Look for keyboards */ 321 hil_do(HIL_READKBDSADR, NULL, 0); 322 while (!hil_last.valid) { 323 if (n++ > 100000) { 324 printk("HIL: timed out, assuming no keyboard present.\n"); 325 return 1; 326 } 327 mb(); 328 } 329 hil_getlast(s, c); 330 if (c == 0) { 331 printk("HIL: no keyboard present.\n"); 332 return 1; 333 } 334 for (kbid = 0; (kbid < 8) && ((c & (1<<kbid)) == 0); kbid++); 335 printk("HIL: keyboard found at id %d\n", kbid); 336 /* set it to raw mode */ 337 c = 0; 338 hil_do(HIL_WRITEKBDSADR, &c, 1); 339 return 0; 340} 341