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