1 /* This file contains the device independent input driver interface. */ 2 /* 3 * Changes: 4 * Sep 22, 2013 created (D.C. van Moolenbroek) 5 */ 6 7 #include <minix/drivers.h> 8 #include <minix/inputdriver.h> 9 #include <minix/ds.h> 10 11 static endpoint_t input_endpt = NONE; 12 static int kbd_id = INVALID_INPUT_ID; 13 static int mouse_id = INVALID_INPUT_ID; 14 15 static int running; 16 17 /* 18 * Announce that we are up after a fresh start or restart. 19 */ 20 void 21 inputdriver_announce(unsigned int type) 22 { 23 const char *driver_prefix = "drv.inp."; 24 char key[DS_MAX_KEYLEN]; 25 char label[DS_MAX_KEYLEN]; 26 int r; 27 28 /* Publish a driver up event. */ 29 if ((r = ds_retrieve_label_name(label, sef_self())) != OK) 30 panic("libinputdriver: unable to retrieve own label: %d", r); 31 32 snprintf(key, sizeof(key), "%s%s", driver_prefix, label); 33 if ((r = ds_publish_u32(key, type, DSF_OVERWRITE)) != OK) 34 panic("libinputdriver: unable to publish up event: %d", r); 35 36 /* Now we wait for the input server to contact us. */ 37 } 38 39 /* 40 * Send an event to the input server. 41 */ 42 void 43 inputdriver_send_event(int mouse, unsigned short page, unsigned short code, 44 int value, int flags) 45 { 46 message m; 47 int id; 48 49 if (input_endpt == NONE) 50 return; 51 52 id = mouse ? mouse_id : kbd_id; 53 if (id == INVALID_INPUT_ID) 54 return; 55 56 memset(&m, 0, sizeof(m)); 57 58 m.m_type = INPUT_EVENT; 59 m.m_linputdriver_input_event.id = id; 60 m.m_linputdriver_input_event.page = page; 61 m.m_linputdriver_input_event.code = code; 62 m.m_linputdriver_input_event.value = value; 63 m.m_linputdriver_input_event.flags = flags; 64 65 /* 66 * Use a blocking send call, for two reasons. First, this avoids the 67 * situation that we ever end up queuing too many asynchronous messages 68 * to the input server. Second, it allows us to detect trivially if 69 * the input server has crashed, in which case we should stop sending 70 * more messages to it. 71 */ 72 if (ipc_send(input_endpt, &m) != OK) 73 input_endpt = NONE; 74 } 75 76 /* 77 * The input server requests that we configure the driver. This request should 78 * be sent to us once, although it may be sent multiple times if the input 79 * server crashes and recovers. The configuration consists of device IDs for 80 * use in keyboard and/or mouse events, one per each device type. 81 */ 82 static void 83 do_conf(message *m_ptr) 84 { 85 endpoint_t ep; 86 int r; 87 88 /* Make sure that the sender is actually the input server. */ 89 if ((r = ds_retrieve_label_endpt("input", &ep)) != OK) { 90 printf("libinputdriver: unable to get input endpoint (%d)\n", 91 r); 92 93 return; /* ignore message */ 94 } 95 96 if (ep != m_ptr->m_source) { 97 printf("libinputdriver: ignoring CONF request from %u\n", 98 m_ptr->m_source); 99 100 return; 101 } 102 103 /* Save the new state. */ 104 input_endpt = m_ptr->m_source; 105 kbd_id = m_ptr->m_input_linputdriver_input_conf.kbd_id; 106 mouse_id = m_ptr->m_input_linputdriver_input_conf.mouse_id; 107 108 /* If the input server is "full" there's nothing for us to do. */ 109 if (kbd_id == INVALID_INPUT_ID && mouse_id == INVALID_INPUT_ID) 110 printf("libinputdriver: no IDs given, driver disabled\n"); 111 } 112 113 /* 114 * The input server is telling us to change the LEDs to a particular mask. 115 * For now this is for keyboards only, so no device type is provided. 116 * This approach was chosen over sending toggle events for the individual LEDs 117 * for convenience reasons only. 118 */ 119 static void 120 do_setleds(struct inputdriver *idp, message *m_ptr) 121 { 122 unsigned int mask; 123 124 if (m_ptr->m_source != input_endpt) { 125 printf("libinputdriver: ignoring SETLEDS request from %u\n", 126 m_ptr->m_source); 127 128 return; 129 } 130 131 mask = m_ptr->m_input_linputdriver_setleds.led_mask; 132 133 if (idp->idr_leds) 134 idp->idr_leds(mask); 135 } 136 137 /* 138 * Call the appropriate driver function, based on the type of message. 139 * All messages in the input protocol are one-way, so we never send a reply. 140 */ 141 void 142 inputdriver_process(struct inputdriver *idp, message *m_ptr, int ipc_status) 143 { 144 /* Check for notifications first. */ 145 if (is_ipc_notify(ipc_status)) { 146 switch (_ENDPOINT_P(m_ptr->m_source)) { 147 case HARDWARE: 148 if (idp->idr_intr) 149 idp->idr_intr(m_ptr->m_notify.interrupts); 150 break; 151 152 case CLOCK: 153 if (idp->idr_alarm) 154 idp->idr_alarm(m_ptr->m_notify.timestamp); 155 break; 156 157 default: 158 if (idp->idr_other) 159 idp->idr_other(m_ptr, ipc_status); 160 } 161 162 return; 163 } 164 165 switch (m_ptr->m_type) { 166 case INPUT_CONF: do_conf(m_ptr); break; 167 case INPUT_SETLEDS: do_setleds(idp, m_ptr); break; 168 default: 169 if (idp->idr_other) 170 idp->idr_other(m_ptr, ipc_status); 171 } 172 } 173 174 /* 175 * Break out of the main loop after finishing the current request. 176 */ 177 void 178 inputdriver_terminate(void) 179 { 180 running = FALSE; 181 182 sef_cancel(); 183 } 184 185 /* 186 * Main program of any input driver task. 187 */ 188 void 189 inputdriver_task(struct inputdriver *idp) 190 { 191 message m; 192 int r, ipc_status; 193 194 running = TRUE; 195 196 while (running) { 197 if ((r = sef_receive_status(ANY, &m, &ipc_status)) != OK) { 198 if (r == EINTR && !running) 199 break; 200 201 panic("libinputdriver: receive failed: %d", r); 202 } 203 204 inputdriver_process(idp, &m, ipc_status); 205 } 206 } 207