1 /* 2 * Provide access to keypad events on the configured device. 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/dataspace.h> 23 #include <l4/devices/keypad-loader.h> 24 #include "input-event-client.h" 25 #include "input-event-server.h" 26 #include "input-event-ops.h" 27 #include "input-keypad-client.h" 28 29 #include <l4/cxx/ipc_stream> 30 #include <l4/re/dataspace> 31 #include <l4/re/env> 32 #include <l4/re/event> 33 #include <l4/re/util/br_manager> 34 #include <l4/re/util/cap_alloc> 35 #include <l4/re/util/object_registry> 36 #include <l4/sys/capability> 37 #include <l4/sys/icu> 38 #include <l4/sys/kip.h> 39 #include <l4/sys/types.h> 40 #include <l4/util/util.h> 41 42 #include <stdio.h> 43 44 /* Extract a fpage from the message buffers. Provide a Snd_fpage reference for 45 modification. */ 46 47 static 48 void get_fpage(L4::Ipc::Iostream &ios, L4::Ipc::Snd_item &fpage) 49 { 50 l4_msgtag_t tag = ios.tag(); 51 52 if (!tag.items()) 53 return; 54 55 /* Extract the fpage details directly since the stream operator doesn't seem 56 to work. */ 57 58 l4_msg_regs_t *m = l4_utcb_mr_u(l4_utcb()); 59 l4_umword_t b = m->mr[tag.words()], d = m->mr[tag.words() + 1]; 60 fpage = L4::Ipc::Snd_item(b, d); 61 } 62 63 /* Handle invocations. */ 64 65 int 66 Input_event_server::dispatch(l4_umword_t obj, L4::Ipc::Iostream &ios) 67 { 68 l4_msgtag_t tag; 69 l4_umword_t op; 70 unsigned irqnum; 71 L4::Ipc::Snd_fpage fpage; 72 73 (void) obj; 74 ios >> tag; 75 76 switch (tag.label()) 77 { 78 case L4::Meta::Protocol: 79 return L4::Util::handle_meta_request<Input_event_interface>(ios); 80 81 case L4RE_PROTO_EVENT: 82 ios >> op; 83 switch (op) 84 { 85 /* Reset the buffer state and return the buffer memory capability. */ 86 87 case Input_event_op_get_buffer: 88 _events.reset(); 89 ios << _mem; 90 return L4_EOK; 91 92 default: 93 return -L4_EINVAL; 94 } 95 96 case L4_PROTO_IRQ: 97 ios >> op; 98 switch (op) 99 { 100 /* Just obtain the interrupt capability. */ 101 102 case Input_event_op_bind: 103 ios >> irqnum; 104 get_fpage(ios, fpage); 105 106 if (!fpage.cap_received()) 107 return -L4_EINVAL; 108 109 _irq = server_iface()->rcv_cap<L4::Irq>(0); 110 return server_iface()->realloc_rcv_cap(0); 111 112 default: 113 return -L4_EINVAL; 114 } 115 116 default: 117 return -L4_EBADPROTO; 118 } 119 } 120 121 122 123 /* Event sending methods. */ 124 125 void 126 Input_event_server::send_event(int type, int code, int value) 127 { 128 L4Re::Event_buffer::Event event; 129 130 event.time = l4_kip_clock(l4re_kip()); 131 event.payload.stream_id = 0; 132 event.payload.type = type; 133 event.payload.code = code; 134 event.payload.value = value; 135 136 /* Queue the event and trigger the interrupt. */ 137 138 _events.put(event); 139 _irq->trigger(); 140 } 141 142 143 144 static void handler(Input_event event, void *priv) 145 { 146 Input_event_server *server = (Input_event_server *) priv; 147 148 server->send_event(event.type, event.code, event.value); 149 } 150 151 152 153 static L4Re::Util::Registry_server<L4Re::Util::Br_manager_hooks> server; 154 155 156 157 int main(void) 158 { 159 // Load the keypad details from the configured library. 160 161 Keypad *keypad = load_keypad(); 162 Input_keypad_client client(keypad); 163 void *buffer; 164 165 // Memory allocation capability for the event data. 166 167 L4::Cap<L4Re::Dataspace> mem = allocate_data(L4_PAGESIZE, &buffer); 168 if (!mem.is_valid()) return 1; 169 170 /* Obtain a capability for the interrupt. */ 171 172 L4::Cap<L4::Irq> irq = L4Re::Util::cap_alloc.alloc<L4::Irq>(); 173 if (!irq.is_valid()) return 1; 174 175 // Event buffer for the data. 176 177 L4Re::Event_buffer events(buffer, L4_PAGESIZE); 178 179 // Initialise and register a server object. 180 181 Input_event_server server_obj(mem, events); 182 server.registry()->register_obj(&server_obj, "ev"); 183 184 // Attach the event handler and wait for events. 185 186 client.attach(handler, (void *) &server_obj); 187 188 // Enter the IPC server loop. 189 190 server.loop(); 191 return 0; 192 }