Landfall

pkg/devices/input/src/keypad/input-keypad-client.cc

155:3e41a1f2ddaa
16 months ago Paul Boddie Tidied up and migrated away from the L4Re C++ types where appropriate. idl4re-libipc-libsystypes
     1 /*     2  * Common keypad client functionality for input event generation.     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/input-keypad-client.h>    23     24 #include <pthread.h>    25 #include <pthread-l4.h>    26     27 #include <l4/re/env.h>    28     29 #include <l4/re/event_enums.h>    30 #include <l4/sys/thread.h>    31 #include <l4/util/util.h>    32     33 #include <ipc/cap_alloc.h>    34 #include <ipc/mem_ipc.h>    35     36 #include <stdlib.h>    37     38 #include "keypad_client.h"    39     40     41     42 /* Obtain a reference to the keypad. */    43     44 void Input_keypad_client::init_keypad()    45 {    46   _keypad_cap = l4re_env_get_cap("keypad");    47 }    48     49 /* Access the keypad server memory. */    50     51 void Input_keypad_client::init_keypad_data()    52 {    53   /* Obtain a reference to the keypad data. */    54     55   client_Keypad keypad(_keypad_cap);    56     57   if (keypad.get_keypad_data(&_mem))    58     return;    59     60   /* Attach the keypad data to a region in this task. */    61     62   unsigned long size;    63     64   if (ipc_dataspace_size(_mem, &size))    65     return;    66     67   if (ipc_attach_dataspace(_mem, size, &_keymem))    68     return;    69     70   /* Allocate memory for a copy of the keypad data. */    71     72   _keymem_previous = malloc(size);    73 }    74     75 /* Release capabilities and the memory for a copy of the keypad data. */    76     77 void Input_keypad_client::release_keypad_data()    78 {    79   if (l4_is_valid_cap(_mem))    80     ipc_cap_free(_mem);    81     82   if (l4_is_valid_cap(_keypad_cap))    83     ipc_cap_free(_keypad_cap);    84     85   if (_keymem_previous && (_keymem_previous != NULL))    86     free(_keymem_previous);    87 }    88     89 /* Scan the keypad, compare old and new states, and generate key events. */    90     91 void Input_keypad_client::scan_keypad()    92 {    93   uint32_t *keymem = (uint32_t *) _keymem;    94   uint32_t *keymem_previous = (uint32_t *) _keymem_previous;    95   int row, column, key_pressed;    96   uint32_t changed, mask;    97   Input_event event;    98     99   for (column = 0; column < _keypad->columns(); column++)   100   {   101     /* Test for differences within each column. */   102    103     changed = keymem[column] ^ keymem_previous[column];   104    105     /* Transfer the current values to the previous values once used. */   106    107     keymem_previous[column] = keymem[column];   108    109     /* Move to the next column if no changes occurred. */   110    111     if (!changed) continue;   112    113     /* Inspect each changed row position. */   114    115     mask = 1 << (_keypad->rows() - 1);   116    117     for (row = 0; row < _keypad->rows(); row++)   118     {   119       if (changed & mask)   120       {   121         key_pressed = keymem[column] & mask;   122    123         /* Construct an event using the appropriate key code. */   124    125         event = (Input_event) {   126           L4RE_EV_KEY, _keypad->code(column, row), key_pressed   127           };   128    129         /* Invoke the supplied handler. */   130    131         _handler(event, _priv);   132       }   133       mask >>= 1;   134     }   135   }   136 }   137    138 /* Perform keypad scanning in a separate thread. */   139    140 void *Input_keypad_client::scan_mainloop(void *data)   141 {   142   /* Since this is a static method, obtain instance details from the data. */   143    144   Input_keypad_client *self = reinterpret_cast<Input_keypad_client *>(data);   145    146   while (1)   147   {   148     if (self->_handler) self->scan_keypad();   149     l4_sleep(20); /* 20ms -> 50Hz */   150   }   151    152   return 0;   153 }   154    155 /* Thread initialisation for the keypad scanning activity. */   156    157 void Input_keypad_client::attach(Input_handler handler, void *priv)   158 {   159   pthread_attr_t thread_attr;   160   struct sched_param sp;   161    162   /* Record the handler and bundled private data. */   163    164   _handler = handler;   165   _priv = priv;   166    167   /* Thread initialisation boilerplate. */   168    169   if (pthread_attr_init(&thread_attr))   170     return;   171    172   sp.sched_priority = 0x20;   173   pthread_attr_setschedparam(&thread_attr, &sp);   174   pthread_attr_setschedpolicy(&thread_attr, SCHED_L4);   175   pthread_attr_setinheritsched(&thread_attr, PTHREAD_EXPLICIT_SCHED);   176    177   /* Provide this instance as the private data. */   178    179   pthread_create(&_pthread, &thread_attr, scan_mainloop, this);   180 }