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/re/c/dataspace.h> 23 #include <l4/re/c/rm.h> 24 #include <l4/re/env.h> 25 26 #include <l4/re/c/util/video/goos_fb.h> 27 #include <l4/re/c/video/view.h> 28 29 #include <ipc/cap_alloc.h> 30 31 #include <stdio.h> 32 #include <unistd.h> 33 #include <stdint.h> 34 #include <stdlib.h> 35 36 #include "keypad_client.h" 37 38 39 40 /* Video abstractions. */ 41 42 static l4re_util_video_goos_fb_t gfb; 43 static l4re_video_view_info_t fbi; 44 static void *fb; 45 46 /* Keypad status and dimensions. */ 47 48 uint32_t *keymem = 0; 49 int columns, rows; 50 51 52 53 static uint32_t bitmask(uint32_t size) 54 { 55 return (1 << size) - 1; 56 } 57 58 static uint32_t truncate_channel(uint32_t value, uint32_t size) 59 { 60 return (value >> (8 - size)) & bitmask(size); 61 } 62 63 static void set_pixel(uint32_t pos, uint8_t bpp, uint32_t value) 64 { 65 if (bpp <= 8) *(uint8_t *) pos = value; 66 else if (bpp <= 16) *(uint16_t *) pos = value; 67 else *(uint32_t *) pos = value; 68 } 69 70 /* Show the state of a key on the display. */ 71 72 static void show_keystate(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t rgb) 73 { 74 uint8_t bpp = l4re_video_bits_per_pixel(&fbi.pixel_info); 75 uint8_t bytes_per_pixel = fbi.pixel_info.bytes_per_pixel; 76 uint32_t bytes_per_line = fbi.bytes_per_line; 77 uint32_t pos; 78 uint32_t col, row; 79 80 rgb = (truncate_channel(rgb >> 16, fbi.pixel_info.r.size) << fbi.pixel_info.r.shift) | 81 (truncate_channel(rgb >> 8, fbi.pixel_info.g.size) << fbi.pixel_info.g.shift) | 82 (truncate_channel(rgb, fbi.pixel_info.b.size) << fbi.pixel_info.b.shift); 83 84 for (row = 0; row < h; row++) 85 { 86 pos = (uint32_t) fb + (y + row) * bytes_per_line + x * bytes_per_pixel; 87 88 for (col = 0; col < w; col++) 89 { 90 set_pixel(pos, bpp, rgb); 91 pos += bytes_per_pixel; 92 } 93 } 94 } 95 96 /* Show the keypad status on the display. */ 97 98 static void show_keypad(void) 99 { 100 uint32_t colsize = fbi.width / columns, 101 rowsize = fbi.height / rows; 102 uint8_t column, row; 103 uint32_t mask; 104 105 for (column = 0; column < columns; column++) 106 107 for (row = 0, mask = 1 << (rows - 1); 108 row < rows; 109 row++, mask >>= 1) 110 111 show_keystate(column * colsize, row * rowsize, colsize, rowsize, 112 keymem[column] & mask ? 0xffffff : 0); 113 114 /* Refresh the display. */ 115 116 l4re_util_video_goos_fb_refresh(&gfb, 0, 0, fbi.width, fbi.height); 117 } 118 119 120 121 int main(int argc, char *argv[]) 122 { 123 l4_cap_idx_t keypad_cap; 124 l4re_ds_t mem; 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_cap = l4re_env_get_cap("keypad"); 146 147 if (l4_is_invalid_cap(keypad_cap)) 148 return 1; 149 150 /* Obtain a capability for the keypad data. */ 151 152 mem = ipc_cap_alloc(); 153 154 if (l4_is_invalid_cap(mem)) 155 return 1; 156 157 /* Obtain a reference to the keypad data. */ 158 159 client_Keypad keypad(keypad_cap); 160 161 if (keypad.get_keypad_data(&mem)) 162 return 1; 163 164 /* Attach the keypad data to a region in this task. */ 165 166 if (l4re_rm_attach((void **) &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 while (1) 175 show_keypad(); 176 177 return 0; 178 }