125 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			125 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *  GRUB  --  GRand Unified Bootloader
 | |
|  *
 | |
|  *  Copyright (C) 2012  Google Inc.
 | |
|  *  Copyright (C) 2016  Free Software Foundation, Inc.
 | |
|  *
 | |
|  *  This is based on depthcharge code.
 | |
|  *
 | |
|  *  GRUB is free software: you can redistribute it and/or modify
 | |
|  *  it under the terms of the GNU General Public License as published by
 | |
|  *  the Free Software Foundation, either version 3 of the License, or
 | |
|  *  (at your option) any later version.
 | |
|  *
 | |
|  *  GRUB is distributed in the hope that it will be useful,
 | |
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  *  GNU General Public License for more details.
 | |
|  *
 | |
|  *  You should have received a copy of the GNU General Public License
 | |
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| 
 | |
| #include <grub/ps2.h>
 | |
| #include <grub/fdtbus.h>
 | |
| #include <grub/err.h>
 | |
| #include <grub/machine/kernel.h>
 | |
| #include <grub/misc.h>
 | |
| #include <grub/term.h>
 | |
| #include <grub/time.h>
 | |
| #include <grub/fdtbus.h>
 | |
| #include <grub/arm/cros_ec.h>
 | |
| 
 | |
| struct grub_ps2_state ps2_state;
 | |
| 
 | |
| struct grub_cros_ec_keyscan old_scan;
 | |
| 
 | |
| static const struct grub_fdtbus_dev *cros_ec;
 | |
| 
 | |
| static grub_uint8_t map_code[GRUB_CROS_EC_KEYSCAN_COLS][GRUB_CROS_EC_KEYSCAN_ROWS];
 | |
| 
 | |
| static grub_uint8_t e0_translate[16] =
 | |
|   {
 | |
|     0x1c, 0x1d, 0x35, 0x00,
 | |
|     0x38, 0x00, 0x47, 0x48,
 | |
|     0x49, 0x4b, 0x4d, 0x4f,
 | |
|     0x50, 0x51, 0x52, 0x53,
 | |
|   };
 | |
| 
 | |
| /* If there is a character pending, return it;
 | |
|    otherwise return GRUB_TERM_NO_KEY.  */
 | |
| static int
 | |
| grub_cros_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused)))
 | |
| {
 | |
|   struct grub_cros_ec_keyscan scan;
 | |
|   int i, j;
 | |
|   if (grub_cros_ec_scan_keyboard (cros_ec, &scan) < 0)
 | |
|     return GRUB_TERM_NO_KEY;
 | |
|   for (i = 0; i < GRUB_CROS_EC_KEYSCAN_COLS; i++)
 | |
|     if (scan.data[i] ^ old_scan.data[i])
 | |
|       for (j = 0; j < GRUB_CROS_EC_KEYSCAN_ROWS; j++)
 | |
| 	if ((scan.data[i] ^ old_scan.data[i]) & (1 << j))
 | |
| 	  {
 | |
| 	    grub_uint8_t code = map_code[i][j];
 | |
| 	    int ret;
 | |
| 	    grub_uint8_t brk = 0;
 | |
| 	    if (!(scan.data[i] & (1 << j)))
 | |
| 	      brk = 0x80;
 | |
| 	    grub_dprintf ("cros_keyboard", "key <%d, %d> code %x\n", i, j, code);
 | |
| 	    if (code < 0x60)
 | |
| 	      ret = grub_ps2_process_incoming_byte (&ps2_state, code | brk);
 | |
| 	    else if (code >= 0x60 && code < 0x70 && e0_translate[code - 0x60])
 | |
| 	      {
 | |
| 		grub_ps2_process_incoming_byte (&ps2_state, 0xe0);
 | |
| 		ret = grub_ps2_process_incoming_byte (&ps2_state, e0_translate[code - 0x60] | brk);
 | |
| 	      }
 | |
| 	    else
 | |
| 	      ret = GRUB_TERM_NO_KEY;
 | |
| 	    old_scan.data[i] ^= (1 << j);
 | |
| 	    if (ret != GRUB_TERM_NO_KEY)
 | |
| 	      return ret;
 | |
| 	  }
 | |
|   return GRUB_TERM_NO_KEY;
 | |
| }
 | |
| 
 | |
| static struct grub_term_input grub_cros_keyboard_term =
 | |
|   {
 | |
|     .name = "cros_keyboard",
 | |
|     .getkey = grub_cros_keyboard_getkey
 | |
|   };
 | |
| 
 | |
| static grub_err_t
 | |
| cros_attach (const struct grub_fdtbus_dev *dev)
 | |
| {
 | |
|   grub_size_t keymap_size, i;
 | |
|   const grub_uint8_t *keymap = grub_fdtbus_get_prop (dev, "linux,keymap", &keymap_size);
 | |
| 
 | |
|   if (!dev->parent || !grub_cros_ec_validate (dev->parent))
 | |
|     return GRUB_ERR_IO;
 | |
| 
 | |
|   if (keymap)
 | |
|     {
 | |
|       for (i = 0; i + 3 < keymap_size; i += 4)
 | |
| 	if (keymap[i+1] < GRUB_CROS_EC_KEYSCAN_COLS && keymap[i] < GRUB_CROS_EC_KEYSCAN_ROWS
 | |
| 	    && keymap[i+2] == 0 && keymap[i+3] < 0x80)
 | |
| 	  map_code[keymap[i+1]][keymap[i]] = keymap[i+3];
 | |
|     }
 | |
| 
 | |
|   cros_ec = dev->parent;
 | |
|   ps2_state.current_set = 1;
 | |
|   ps2_state.at_keyboard_status = 0;
 | |
|   grub_term_register_input ("cros_keyboard", &grub_cros_keyboard_term);
 | |
|   return GRUB_ERR_NONE;
 | |
| }
 | |
| 
 | |
| static struct grub_fdtbus_driver cros =
 | |
| {
 | |
|   .compatible = "google,cros-ec-keyb",
 | |
|   .attach = cros_attach
 | |
| };
 | |
| 
 | |
| void
 | |
| grub_cros_init (void)
 | |
| {
 | |
|   grub_fdtbus_register (&cros);
 | |
| }
 |