Landfall

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

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