clps711x_keyb.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:16k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * drivers/char/clps711x_keyb.c
  3.  *
  4.  * Copyright (C) 2001 Thomas Gleixner <gleixner@autronix.de>
  5.  *
  6.  * based on drivers/edb7211_keyb.c, which is copyright (C) 2000 Bluemug Inc.
  7.  * 
  8.  * Keyboard driver for ARM Linux on EP7xxx and CS89712 processors
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License version 2 as
  12.  * published by the Free Software Foundation. See the file COPYING 
  13.  * in the main directory of this archive for more details.
  14.  *
  15.  *
  16.  * Hardware: 
  17.  *
  18.  * matrix scan keyboards based on EP7209,7211,7212,7312 and CS89712 
  19.  * on chip keyboard scanner.
  20.  * Adaption for different machines is done in init function.
  21.  *
  22.  * Basic Function:
  23.  *
  24.  * Basicly the driver is interrupt driven. It sets all column drivers
  25.  * high. If any key is pressed, a interrupt occures. Now a seperate scan of
  26.  * each column is done. This scan is timer based, because we use a keyboard 
  27.  * interface with decoupling capacitors (neccecary if you want to survive 
  28.  * EMC compliance tests). Always one line is set high. When next timer event 
  29.  * occures the scan data on port A are valid. This makes also sure, that no
  30.  * spurious keys are scanned. The kbd int on these CPU's is not deglitched!
  31.  * After scanning all columns, we switch back to int mode, if no key is
  32.  * pressed. If any is pressed we reschedule the scan within a programmable
  33.  * delay. If we would switch back to interrupt mode as long as a key is pressed,
  34.  * we come right back to the interrupt, because the int. is level triggered !
  35.  * The timer based scan of the seperate columns can also be done in one
  36.  * timer event (set fastscan to 1).
  37.  *
  38.  * Summary:
  39.  * The design of this keyboard controller chip is stupid at all !
  40.  *
  41.  * Matrix translation:
  42.  * The matrix translation table is based on standard XT scancodes. Maybe
  43.  * you have to adjust the KEYISPRINTABLE macro if you set other codes.
  44.  *
  45.  * HandyKey:
  46.  *
  47.  * On small matrix keyboards you don't have enough keys for operation.
  48.  * The intention was to implement a operation mode as it's used on handys.
  49.  * You can rotate trough four scancode levels and produce e.g. with a 4x3
  50.  * matrix 4*3*4 = 48 different keycodes. That's basicly enough for editing
  51.  * filenames or things like that. The HandyKey function takes care about 
  52.  * nonprintable keys like cursors, backspace, del ...
  53.  * If a key is pressed and is a printable keycode, the code is put to the
  54.  * main keyboard handler and a cursor left is applied. If you press the same
  55.  * key again, the current character is deleted and the next level character
  56.  * is applied. (e.g. 1, a, b, c, 1 ....). If you press a different key, the
  57.  * driver applies cursor right, before processing the new key.
  58.  * The autocomplete feature moves the cursor right, if you do not press a
  59.  * key within a programmable time.
  60.  * If HandyKey is off, the keyboard behaviour is that of a standard keyboard
  61.  * HandyKey can be en/disabled from userspace with the proc/keyboard entry
  62.  * 
  63.  * proc/keyboard:
  64.  * 
  65.  * Read access gives back the actual state of the HandyKey function
  66.  * h:0 Disabled
  67.  * h:1 Enabled
  68.  * Write access has two functions. Changing the HandyKey mode and applying
  69.  * a different scancode translation table.
  70.  * Syntax is:  h:0 disable Handykey
  71.  * h:1 enabled Handykey
  72.  * t:array[256] of bytes Transfer translation table
  73.  */
  74. #include <linux/config.h>
  75. #include <linux/sched.h>
  76. #include <linux/interrupt.h>
  77. #include <linux/tty.h>
  78. #include <linux/tty_flip.h>
  79. #include <linux/mm.h>
  80. #include <linux/slab.h>
  81. #include <linux/ptrace.h>
  82. #include <linux/signal.h>
  83. #include <linux/timer.h>
  84. #include <linux/tqueue.h>
  85. #include <linux/random.h>
  86. #include <linux/ctype.h>
  87. #include <linux/init.h>
  88. #include <linux/kbd_ll.h>
  89. #include <linux/kbd_kern.h>
  90. #include <linux/delay.h>
  91. #include <linux/proc_fs.h>
  92. #include <asm/bitops.h>
  93. #include <asm/keyboard.h>
  94. #include <asm/irq.h>
  95. #include <asm/hardware.h>
  96. #include <asm/uaccess.h>
  97. #include <asm/io.h>
  98. #include <asm/system.h>
  99. void clps711x_kbd_init_hw(void);
  100. /*
  101.  * Values for the keyboard column scan control register.
  102.  */
  103. #define KBSC_HI     0x0     /*   All driven high */
  104. #define KBSC_LO     0x1     /*   All driven low */
  105. #define KBSC_X     0x2     /*   All high impedance */
  106. #define KBSC_COL0   0x8     /*   Column 0 high, others high impedance */
  107. #define KBSC_COL1   0x9     /*   Column 1 high, others high impedance */
  108. #define KBSC_COL2   0xa     /*   Column 2 high, others high impedance */
  109. #define KBSC_COL3   0xb     /*   Column 3 high, others high impedance */
  110. #define KBSC_COL4   0xc     /*   Column 4 high, others high impedance */
  111. #define KBSC_COL5   0xd     /*   Column 5 high, others high impedance */
  112. #define KBSC_COL6   0xe     /*   Column 6 high, others high impedance */
  113. #define KBSC_COL7   0xf     /*   Column 7 high, others high impedance */
  114. /*
  115. * Keycodes for cursor left/right and delete (used by HandyKey)
  116. */
  117. #define KEYCODE_CLEFT 0x4b
  118. #define KEYCODE_CRIGHT  0x4d
  119. #define KEYCODE_DEL 0x53
  120. #define KEYISPRINTABLE(code) ( (code > 0x01 && code < 0x37 && code != 0x1c 
  121.  && code != 0x0e) || code == 0x39) 
  122. /* Simple translation table for the SysRq keys */
  123. #ifdef CONFIG_MAGIC_SYSRQ
  124. unsigned char clps711x_kbd_sysrq_xlate[128] =
  125. "00331234567890-=177t" /* 0x00 - 0x0f */
  126. "qwertyuiop[]r00as" /* 0x10 - 0x1f */
  127. "dfghjkl;'`00\zxcv" /* 0x20 - 0x2f */
  128. "bnm,./00*00 00201202203204205" /* 0x30 - 0x3f */
  129. "2062072102112120000789-456+1" /* 0x40 - 0x4f */
  130. "230177000021321400000000000000000000" /* 0x50 - 0x5f */
  131. "r00/"; /* 0x60 - 0x6f */
  132. #endif
  133. /* 
  134.  * This table maps row/column keyboard matrix positions to XT scancodes.
  135.  * It's a default table, which can be overriden by writing to proc/keyboard 
  136.  */
  137. #ifdef CONFIG_ARCH_AUTCPU12
  138. static unsigned char autcpu12_scancode[256] = 
  139. {
  140. /*  Column: 
  141.   Row       0     1     2     3     4     5     6     7   */
  142. /* A0 */  0x08, 0x09, 0x0a, 0x0e, 0x05, 0x06, 0x00, 0x00,
  143. /* A1 */  0x07, 0x53, 0x02, 0x03, 0x04, 0x0f, 0x00, 0x00,
  144. /* A2 */  0x0c, 0x0b, 0x33, 0x1c, 0xff, 0x4b, 0x00, 0x00,
  145. /* A3 */  0x48, 0x50, 0x4d, 0x3b, 0x3c, 0x3d, 0x00, 0x00,
  146. /* A4 */  0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  147. /* A5 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  148. /* A6 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  149. /* A7 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  150. /* A0 */  0x1e, 0x20, 0x22, 0x0e, 0x24, 0x32, 0x00, 0x00,
  151. /* A1 */  0x19, 0x53, 0x1f, 0x2f, 0x15, 0x0f, 0x00, 0x00,
  152. /* A2 */  0x0c, 0x39, 0x34, 0x1c, 0xff, 0x4b, 0x00, 0x00,
  153. /* A3 */  0x48, 0x50, 0x4d, 0x3b, 0x3c, 0x3d, 0x00, 0x00,
  154. /* A4 */  0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  155. /* A5 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  156. /* A6 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  157. /* A7 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  158. /* A0 */  0x30, 0x12, 0x23, 0x0e, 0x25, 0x31, 0x00, 0x00,
  159. /* A1 */  0x10, 0x53, 0x14, 0x11, 0x2c, 0x0f, 0x00, 0x00,
  160. /* A2 */  0x0c, 0x0b, 0x27, 0x1c, 0xff, 0x4b, 0x00, 0x00,
  161. /* A3 */  0x48, 0x50, 0x4d, 0x3b, 0x3c, 0x3d, 0x00, 0x00,
  162. /* A4 */  0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  163. /* A5 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  164. /* A6 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  165. /* A7 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  166. /* A0 */  0x2e, 0x21, 0x17, 0x0e, 0x26, 0x18, 0x00, 0x00,
  167. /* A1 */  0x13, 0x53, 0x16, 0x2D, 0x04, 0x0f, 0x00, 0x00,
  168. /* A2 */  0x0c, 0x39, 0x35, 0x1c, 0xff, 0x4b, 0x00, 0x00,
  169. /* A3 */  0x48, 0x50, 0x4d, 0x3b, 0x3c, 0x3d, 0x00, 0x00,
  170. /* A4 */  0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  171. /* A5 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  172. /* A6 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  173. /* A7 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  174. };
  175. #endif
  176. static int keys[8];
  177. static int new_keys[8];
  178. static int previous_keys[8];
  179. static int fastscan;
  180. static int scan_interval;
  181. static int scan_delay;
  182. static int last_column; 
  183. static int key_is_pressed;
  184. static unsigned char *act_scancode;
  185. static struct kbd_handy_key {
  186. int ena;
  187. int code;
  188. int shift;
  189. int autocomplete;
  190. unsigned long  expires;
  191. unsigned long delay;
  192. unsigned char  left;
  193. unsigned char right;
  194. unsigned char   del;
  195. } khandy;
  196. static struct tq_struct kbd_process_task;
  197. static struct timer_list clps711x_kbd_timer;
  198. static struct timer_list clps711x_kbdhandy_timer;
  199. static struct proc_dir_entry *clps711x_keyboard_proc_entry = NULL;
  200. /*
  201.  * Translate a raw keycode to an XT keyboard scancode.
  202.  */
  203. static int clps711x_translate(unsigned char scancode, unsigned char *keycode,
  204.    char raw_mode)
  205. {
  206. *keycode = act_scancode[scancode];
  207. return 1;
  208. }
  209. /*
  210. * Initialize handykey structure
  211. * clear code, clear shift
  212. * scan scancode for cursor right/left and delete
  213. */
  214. static void clps711x_handykey_init(void) {
  215. int i;
  216. khandy.ena = 0;
  217. khandy.code = 0;
  218. khandy.shift = 0;
  219. khandy.autocomplete = 0;
  220. for(i = 0; i < 64; i++) {
  221. switch(act_scancode[i]) {
  222. case KEYCODE_CLEFT:  khandy.left = i; break;
  223. case KEYCODE_CRIGHT:  khandy.right = i; break;
  224. case KEYCODE_DEL:  khandy.del = i; break;
  225. }
  226. }
  227. /*
  228. * Check for handy key and process it
  229. */
  230. void inline clps711x_checkhandy(int col, int row) {
  231. int scode, down;
  232. unsigned char kcode;
  233. scode = (row<<3) + col;
  234. down  = keys[col]>>row & 0x01;
  235. kcode = act_scancode[scode];
  236. if (!khandy.ena) {
  237. if (khandy.code) {
  238. handle_scancode(khandy.right,1);
  239. handle_scancode(khandy.right,0);
  240. }
  241. khandy.code = 0;
  242. khandy.shift = 0;
  243. khandy.autocomplete = 0;
  244. }
  245. if(!kcode)
  246. return;
  247. if (!down || !khandy.ena) {
  248. if (khandy.ena && KEYISPRINTABLE(act_scancode[scode]))
  249. khandy.autocomplete = 1;
  250. else
  251. handle_scancode(scode + khandy.shift, down);
  252. return;
  253. }
  254. khandy.autocomplete = 0;
  255. if (KEYISPRINTABLE(kcode)) {
  256. if (khandy.code) {
  257. if(khandy.code == (scode|0x100)) {
  258. handle_scancode(khandy.del,1);
  259. handle_scancode(khandy.del,0);
  260. khandy.shift = khandy.shift < 3*64 ? khandy.shift + 64 : 0 ;
  261. } else {
  262. handle_scancode(khandy.right,1);
  263. handle_scancode(khandy.right,0);
  264. khandy.shift = 0;
  265. }
  266. }
  267. handle_scancode(scode + khandy.shift, 1);
  268. handle_scancode(scode + khandy.shift, 0);
  269. khandy.code = scode | 0x100;
  270. handle_scancode(khandy.left,1);
  271. handle_scancode(khandy.left,0);
  272. } else {
  273. if (khandy.code) {
  274. khandy.code = 0;
  275. handle_scancode(khandy.right,1);
  276. handle_scancode(khandy.right,0);
  277. }
  278. khandy.shift = 0;
  279. handle_scancode(scode, down);
  280. }
  281. }
  282. /*
  283.  * Process the new key data 
  284.  */
  285. static void clps711x_kbd_process(void* data)
  286. {
  287. int col,row,res;
  288. for (col = 0; col < 8; col++) {
  289. if (( res = previous_keys[col] ^ keys[col]) == 0) 
  290. continue;
  291. for(row = 0; row < 8; row++) {
  292. if ( ((res >> row) & 0x01) != 0) 
  293. clps711x_checkhandy(col,row);
  294. }
  295. }
  296. /* Update the state variables. */
  297. memcpy(previous_keys, keys, 8 * sizeof(int));
  298. /* reschedule, if autocomplete pending */
  299. if (khandy.autocomplete) {
  300. khandy.expires = jiffies + khandy.delay;
  301. mod_timer(&clps711x_kbdhandy_timer,khandy.expires);
  302. }
  303. }
  304. static char clps711x_unexpected_up(unsigned char scancode)
  305. {
  306. return 0200;
  307. }
  308. /*
  309. * Handle timer event, for autocomplete function
  310. * Reschedule keyboard process task
  311. */
  312. static void clps711x_kbdhandy_timeout(unsigned long data) 
  313. {
  314. if(khandy.autocomplete) {
  315. khandy.code = 0;
  316. khandy.shift = 0;
  317. khandy.autocomplete = 0;
  318. handle_scancode(khandy.right,1);
  319. handle_scancode(khandy.right,0);
  320. }
  321. }
  322. /*
  323. * Handle timer event, while in pollmode
  324. */
  325. static void clps711x_kbd_timeout(unsigned long data)
  326. {
  327. int i;
  328. unsigned long flags;
  329. /* 
  330. * read bits of actual column or all columns in fastscan-mode
  331. */
  332. for (i = 0; i < 8; i++) {
  333. new_keys[last_column - KBSC_COL0] = clps_readb(PADR) & 0xff;
  334. key_is_pressed |= new_keys[last_column - KBSC_COL0];
  335. last_column = last_column < KBSC_COL7 ? last_column + 1 : KBSC_COL0;
  336. local_irq_save(flags);
  337. clps_writel( (clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK) 
  338. | last_column, SYSCON1);
  339. local_irq_restore(flags);
  340. /*
  341. * For fastscan, apply a short delay to settle scanlines
  342. * else break and wait for next timeout
  343. */
  344. if (fastscan)
  345. udelay(5);
  346. else
  347. break;
  348. }
  349. if (key_is_pressed)
  350. khandy.autocomplete = 0;
  351. /*
  352. * switch to interupt mode, if all columns scanned and no key pressed
  353. * else reschedule scan
  354. */
  355. if (last_column == KBSC_COL0) {
  356. if (!key_is_pressed) {
  357. local_irq_save(flags);
  358. clps_writel( (clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK)
  359.  | KBSC_HI, SYSCON1);
  360. local_irq_restore(flags);
  361. clps_writel(0,KBDEOI);
  362. enable_irq(IRQ_KBDINT);
  363. } else {
  364. clps711x_kbd_timer.expires = jiffies + scan_interval;
  365. add_timer(&clps711x_kbd_timer);
  366. }
  367. key_is_pressed = 0;
  368. memcpy(keys, new_keys, 8 * sizeof(int));
  369. for (i = 0; i < 8; i++) {
  370. if (previous_keys[i] != keys[i]) {
  371. queue_task(&kbd_process_task, &tq_timer);
  372. return;
  373. }
  374. }
  375. } else {
  376. clps711x_kbd_timer.expires = jiffies + scan_delay;
  377. add_timer(&clps711x_kbd_timer);
  378. }
  379. }
  380. /*
  381. * Keyboard interrupt, change to scheduling mode
  382. */
  383. static void clps711x_kbd_int(int irq, void *dev_id, struct pt_regs *regs)
  384. {
  385. #ifdef CONFIG_VT
  386. kbd_pt_regs = regs;
  387. #endif
  388. disable_irq(IRQ_KBDINT);
  389. khandy.autocomplete = 0;
  390. clps_writel( (clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK)
  391.  | KBSC_COL0, SYSCON1);
  392. clps711x_kbd_timer.expires = jiffies + scan_delay;
  393. add_timer(&clps711x_kbd_timer);
  394. }
  395. static int clps711x_kbd_proc_keyboard_read(char *page, char **start, off_t off,
  396. int count, int *eof, void *data)
  397. {
  398. if (count < 2) 
  399. return -EINVAL;
  400. return sprintf(page,"h:%dn",khandy.ena);
  401. }
  402. static int clps711x_kbd_proc_keyboard_write(struct file *file, const char *buffer, 
  403. unsigned long count, void *data)
  404. {
  405. unsigned char buf[260];
  406. if (count < 3|| count > 258)
  407. return -EINVAL;
  408. if (copy_from_user(buf, buffer, count)) 
  409. return -EFAULT;
  410. if (buf[1] != ':')
  411. return -EINVAL;
  412. if (buf[0] == 'h') {
  413. switch (buf[2]) {
  414. case '0':
  415. case '1':
  416. case '2': khandy.ena = buf[2]-'0'; return count;
  417. }
  418. }
  419. if (buf[0] == 't' && count == 258) {
  420. memcpy(act_scancode,buf+2,256);
  421. /* rescan cursor left/right and del */ 
  422. clps711x_handykey_init();
  423. return count;
  424. }
  425. return -EINVAL;
  426. }
  427. /*
  428.  * Initialize the keyboard hardware. 
  429.  * Set all columns high
  430.  * Install interrupt handler
  431.  *
  432.  * Machine dependent parameters:
  433.  *
  434.  * fastscan:  0 = timer based scan for each column
  435.  * 1 = full scan is done in one timer event
  436.  * scan_delay: time between column scans 
  437.  *  setup even if you use fastscan (leeds to timer mode)
  438.  * scan_interval: time between full scans
  439.  * handy.delay: timeout before last entry get's automatically valid
  440.  * 
  441.  */
  442. void __init clps711x_kbd_init_hw(void)
  443. {
  444. /*
  445. * put here  machine dependent init stuff 
  446. */
  447. if (machine_is_autcpu12()) {
  448. fastscan = 0;
  449. scan_interval = 50*HZ/1000;
  450. scan_delay = 20*HZ/1000;
  451. khandy.delay = 750*HZ/1000;
  452. act_scancode = autcpu12_scancode;
  453. } else {
  454. printk("No initialization, keyboard killedn");
  455. return;
  456. }
  457. last_column = KBSC_COL0;
  458. key_is_pressed = 0;
  459. clps711x_handykey_init();
  460. /* Register the /proc entry */
  461. clps711x_keyboard_proc_entry = create_proc_entry("keyboard", 0444,
  462. &proc_root);
  463. if (clps711x_keyboard_proc_entry == NULL)
  464.      printk("Couldn't create the /proc entry for the keyboardn");
  465. else {
  466. clps711x_keyboard_proc_entry->read_proc = 
  467. &clps711x_kbd_proc_keyboard_read;
  468. clps711x_keyboard_proc_entry->write_proc = 
  469. &clps711x_kbd_proc_keyboard_write;
  470. }
  471. /* Initialize the matrix processing task. */
  472. k_translate = clps711x_translate;
  473. k_unexpected_up = clps711x_unexpected_up;
  474. kbd_process_task.routine = clps711x_kbd_process;
  475. kbd_process_task.data = 0;
  476. /* Setup the timer for keyboard polling, after kbd int */
  477. init_timer(&clps711x_kbd_timer);
  478. clps711x_kbd_timer.function = clps711x_kbd_timeout;
  479. clps711x_kbd_timer.data = 0;
  480. init_timer(&clps711x_kbdhandy_timer);
  481. clps711x_kbdhandy_timer.function = clps711x_kbdhandy_timeout;
  482. clps711x_kbdhandy_timer.data = 1;
  483. /* Initialise scan hardware, request int */
  484. clps_writel( (clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK)
  485.  | KBSC_HI, SYSCON1);
  486. request_irq(IRQ_KBDINT, clps711x_kbd_int, 0,"keyboard", NULL);
  487. printk("clps711x keyboard init donen");
  488. }