Landfall

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

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