1 /* 2 * Display the keypad matrix using the specified dimensions. 3 * 4 * Copyright (C) 2018, 2023 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include <l4/devices/keypad-ops.h> 23 24 #include <l4/re/c/rm.h> 25 #include <l4/re/c/util/cap_alloc.h> 26 #include <l4/re/env.h> 27 #include <l4/util/util.h> 28 #include <l4/sys/ipc.h> 29 30 #include <l4/re/c/util/video/goos_fb.h> 31 #include <l4/re/c/video/view.h> 32 33 #include <stdio.h> 34 #include <unistd.h> 35 #include <stdint.h> 36 #include <stdlib.h> 37 38 /* Video abstractions. */ 39 40 static l4re_util_video_goos_fb_t gfb; 41 static l4re_video_view_info_t fbi; 42 static void *fb; 43 44 /* Keypad status and dimensions. */ 45 46 uint32_t *keypad = 0; 47 void *keymem = 0; 48 int columns, rows; 49 50 51 52 static uint32_t bitmask(uint32_t size) 53 { 54 return (1 << size) - 1; 55 } 56 57 static uint32_t truncate_channel(uint32_t value, uint32_t size) 58 { 59 return (value >> (8 - size)) & bitmask(size); 60 } 61 62 static void set_pixel(uint32_t pos, uint8_t bpp, uint32_t value) 63 { 64 if (bpp <= 8) *(uint8_t *) pos = value; 65 else if (bpp <= 16) *(uint16_t *) pos = value; 66 else *(uint32_t *) pos = value; 67 } 68 69 /* Show the state of a key on the display. */ 70 71 static void show_keystate(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t rgb) 72 { 73 uint8_t bpp = l4re_video_bits_per_pixel(&fbi.pixel_info); 74 uint8_t bytes_per_pixel = fbi.pixel_info.bytes_per_pixel; 75 uint32_t bytes_per_line = fbi.bytes_per_line; 76 uint32_t pos; 77 uint32_t col, row; 78 79 rgb = (truncate_channel(rgb >> 16, fbi.pixel_info.r.size) << fbi.pixel_info.r.shift) | 80 (truncate_channel(rgb >> 8, fbi.pixel_info.g.size) << fbi.pixel_info.g.shift) | 81 (truncate_channel(rgb, fbi.pixel_info.b.size) << fbi.pixel_info.b.shift); 82 83 for (row = 0; row < h; row++) 84 { 85 pos = (uint32_t) fb + (y + row) * bytes_per_line + x * bytes_per_pixel; 86 87 for (col = 0; col < w; col++) 88 { 89 set_pixel(pos, bpp, rgb); 90 pos += bytes_per_pixel; 91 } 92 } 93 } 94 95 /* Show the keypad status on the display. */ 96 97 static void show_keypad(void) 98 { 99 uint32_t colsize = fbi.width / columns, 100 rowsize = fbi.height / rows; 101 uint8_t column, row; 102 uint32_t mask; 103 104 for (column = 0; column < columns; column++) 105 106 for (row = 0, mask = 1 << (rows - 1); 107 row < rows; 108 row++, mask >>= 1) 109 110 show_keystate(column * colsize, row * rowsize, colsize, rowsize, 111 keypad[column] & mask ? 0xffffff : 0); 112 113 /* Refresh the display. */ 114 115 l4re_util_video_goos_fb_refresh(&gfb, 0, 0, fbi.width, fbi.height); 116 } 117 118 119 120 int main(int argc, char *argv[]) 121 { 122 l4_cap_idx_t keypad_server; 123 l4re_ds_t mem; 124 l4_msgtag_t tag; 125 126 /* Obtain the keypad matrix dimensions. */ 127 128 if (argc < 3) 129 return 1; 130 131 columns = atoi(argv[1]); 132 rows = atoi(argv[2]); 133 134 if (l4re_util_video_goos_fb_setup_name(&gfb, "fb")) 135 return 1; 136 137 if (l4re_util_video_goos_fb_view_info(&gfb, &fbi)) 138 return 1; 139 140 if (!(fb = l4re_util_video_goos_fb_attach_buffer(&gfb))) 141 return 1; 142 143 /* Obtain a reference to the keypad. */ 144 145 keypad_server = l4re_env_get_cap("keypad"); 146 if (l4_is_invalid_cap(keypad_server)) return 1; 147 148 /* Obtain a capability for the keypad data. */ 149 150 mem = l4re_util_cap_alloc(); 151 if (l4_is_invalid_cap(mem)) return 1; 152 153 /* Obtain a reference to the keypad data. */ 154 155 l4_utcb_br()->bdr = 0; 156 l4_utcb_br()->br[0] = L4_RCV_ITEM_SINGLE_CAP | mem; 157 158 tag = l4_ipc_call(keypad_server, l4_utcb(), 159 l4_msgtag(Keypad_op_get_keypad_data, 0, 0, 0), /* zero words, zero *sent* items */ 160 L4_IPC_NEVER); 161 162 if (l4_ipc_error(tag, l4_utcb())) return 1; 163 164 /* Attach the keypad data to a region in this task. */ 165 166 if (l4re_rm_attach(&keymem, l4re_ds_size(mem), 167 L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_R, 168 mem, 0, 169 L4_PAGESHIFT)) 170 return 1; 171 172 /* Show the keypad state. */ 173 174 keypad = (uint32_t *) keymem; 175 176 while (1) show_keypad(); 177 178 return 0; 179 }