Landfall

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

0:89a1bc19c1fc
2018-05-13 Paul Boddie Added device libraries and programs, configuration files and examples. Also added an installation script and copyright and licensing information.
paul@0 1
/*
paul@0 2
 * Common keypad client functionality for input event generation.
paul@0 3
 *
paul@0 4
 * (c) 2018 Paul Boddie <paul@boddie.org.uk>
paul@0 5
 *
paul@0 6
 * This program is free software; you can redistribute it and/or
paul@0 7
 * modify it under the terms of the GNU General Public License as
paul@0 8
 * published by the Free Software Foundation; either version 2 of
paul@0 9
 * the License, or (at your option) any later version.
paul@0 10
 *
paul@0 11
 * This program is distributed in the hope that it will be useful,
paul@0 12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@0 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@0 14
 * GNU General Public License for more details.
paul@0 15
 *
paul@0 16
 * You should have received a copy of the GNU General Public License
paul@0 17
 * along with this program; if not, write to the Free Software
paul@0 18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@0 19
 * Boston, MA  02110-1301, USA
paul@0 20
 */
paul@0 21
paul@0 22
#include <l4/devices/input-keypad-client.h>
paul@0 23
paul@0 24
#include <pthread.h>
paul@0 25
#include <pthread-l4.h>
paul@0 26
paul@0 27
#include <l4/re/dataspace>
paul@0 28
#include <l4/re/env>
paul@0 29
#include <l4/re/rm>
paul@0 30
#include <l4/re/util/cap_alloc>
paul@0 31
paul@0 32
#include <l4/re/event_enums.h>
paul@0 33
#include <l4/sys/thread.h>
paul@0 34
#include <l4/util/util.h>
paul@0 35
paul@0 36
#include <stdlib.h>
paul@0 37
paul@0 38
/* Obtain a capability for the keypad data. */
paul@0 39
paul@0 40
void
paul@0 41
Input_keypad_client::init_memory()
paul@0 42
{
paul@0 43
  _mem = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
paul@0 44
}
paul@0 45
paul@0 46
/* Obtain a reference to the keypad. */
paul@0 47
paul@0 48
void
paul@0 49
Input_keypad_client::init_keypad()
paul@0 50
{
paul@0 51
  _keypad_server = L4Re::Env::env()->get_cap<Keypad_device_interface>("keypad");
paul@0 52
}
paul@0 53
paul@0 54
/* Access the keypad server memory. */
paul@0 55
paul@0 56
void
paul@0 57
Input_keypad_client::init_keypad_data()
paul@0 58
{
paul@0 59
  if (!_mem.is_valid())
paul@0 60
    return;
paul@0 61
paul@0 62
  if (!_keypad_server.is_valid())
paul@0 63
    return;
paul@0 64
paul@0 65
  /* Obtain a reference to the keypad data. */
paul@0 66
paul@0 67
  if (_keypad_server->get_keypad_data(_mem))
paul@0 68
    return;
paul@0 69
paul@0 70
  /* Attach the keypad data to a region in this task. */
paul@0 71
paul@0 72
  if (L4Re::Env::env()->rm()->attach(&_keymem, _mem->size(),
paul@0 73
                                     L4Re::Rm::Search_addr,
paul@0 74
                                     L4::Ipc::make_cap_rw(_mem)))
paul@0 75
    return;
paul@0 76
paul@0 77
  /* Allocate memory for a copy of the keypad data. */
paul@0 78
paul@0 79
  _keymem_previous = malloc(_mem->size());
paul@0 80
}
paul@0 81
paul@0 82
/* Release capabilities and the memory for a copy of the keypad data. */
paul@0 83
paul@0 84
void
paul@0 85
Input_keypad_client::release_keypad_data()
paul@0 86
{
paul@0 87
  if (_mem.is_valid())
paul@0 88
    L4Re::Util::cap_alloc.free(_mem);
paul@0 89
paul@0 90
  if (_keypad_server.is_valid())
paul@0 91
    L4Re::Util::cap_alloc.free(_keypad_server);
paul@0 92
paul@0 93
  if (_keymem_previous && (_keymem_previous != NULL))
paul@0 94
    free(_keymem_previous);
paul@0 95
}
paul@0 96
paul@0 97
/* Scan the keypad, compare old and new states, and generate key events. */
paul@0 98
paul@0 99
void
paul@0 100
Input_keypad_client::scan_keypad()
paul@0 101
{
paul@0 102
  uint32_t *keymem = (uint32_t *) _keymem;
paul@0 103
  uint32_t *keymem_previous = (uint32_t *) _keymem_previous;
paul@0 104
  int row, column, key_pressed;
paul@0 105
  uint32_t changed, mask;
paul@0 106
  Input_event event;
paul@0 107
paul@0 108
  for (column = 0; column < _keypad->columns(); column++)
paul@0 109
  {
paul@0 110
    /* Test for differences within each column. */
paul@0 111
paul@0 112
    changed = keymem[column] ^ keymem_previous[column];
paul@0 113
paul@0 114
    /* Transfer the current values to the previous values once used. */
paul@0 115
paul@0 116
    keymem_previous[column] = keymem[column];
paul@0 117
paul@0 118
    /* Move to the next column if no changes occurred. */
paul@0 119
paul@0 120
    if (!changed) continue;
paul@0 121
paul@0 122
    /* Inspect each changed row position. */
paul@0 123
paul@0 124
    mask = 1 << (_keypad->rows() - 1);
paul@0 125
paul@0 126
    for (row = 0; row < _keypad->rows(); row++)
paul@0 127
    {
paul@0 128
      if (changed & mask)
paul@0 129
      {
paul@0 130
        key_pressed = keymem[column] & mask;
paul@0 131
paul@0 132
        /* Construct an event using the appropriate key code. */
paul@0 133
paul@0 134
        event = (Input_event) {
paul@0 135
          L4RE_EV_KEY, _keypad->code(column, row), key_pressed
paul@0 136
          };
paul@0 137
paul@0 138
        /* Invoke the supplied handler. */
paul@0 139
paul@0 140
        _handler(event, _priv);
paul@0 141
      }
paul@0 142
      mask >>= 1;
paul@0 143
    }
paul@0 144
  }
paul@0 145
}
paul@0 146
paul@0 147
/* Perform keypad scanning in a separate thread. */
paul@0 148
paul@0 149
void *
paul@0 150
Input_keypad_client::scan_mainloop(void *data)
paul@0 151
{
paul@0 152
  /* Since this is a static method, obtain instance details from the data. */
paul@0 153
paul@0 154
  Input_keypad_client *self = reinterpret_cast<Input_keypad_client *>(data);
paul@0 155
paul@0 156
  while (1)
paul@0 157
  {
paul@0 158
    if (self->_handler) self->scan_keypad();
paul@0 159
    l4_sleep(20); /* 20ms -> 50Hz */
paul@0 160
  }
paul@0 161
paul@0 162
  return 0;
paul@0 163
}
paul@0 164
paul@0 165
/* Thread initialisation for the keypad scanning activity. */
paul@0 166
paul@0 167
void
paul@0 168
Input_keypad_client::attach(Input_handler handler, void *priv)
paul@0 169
{
paul@0 170
  pthread_attr_t thread_attr;
paul@0 171
  struct sched_param sp;
paul@0 172
paul@0 173
  /* Record the handler and bundled private data. */
paul@0 174
paul@0 175
  _handler = handler;
paul@0 176
  _priv = priv;
paul@0 177
paul@0 178
  /* Thread initialisation boilerplate. */
paul@0 179
paul@0 180
  if (pthread_attr_init(&thread_attr))
paul@0 181
    return;
paul@0 182
paul@0 183
  sp.sched_priority = 0x20;
paul@0 184
  pthread_attr_setschedparam(&thread_attr, &sp);
paul@0 185
  pthread_attr_setschedpolicy(&thread_attr, SCHED_L4);
paul@0 186
  pthread_attr_setinheritsched(&thread_attr, PTHREAD_EXPLICIT_SCHED);
paul@0 187
paul@0 188
  /* Provide this instance as the private data. */
paul@0 189
paul@0 190
  pthread_create(&_pthread, &thread_attr, scan_mainloop, this);
paul@0 191
}