/** Default handler for IPC methods not handled by DDF. * * @param fun Device function handling the call. * @param icallid Call id. * @param icall Call data. * */ static void default_connection_handler(ddf_fun_t *fun, ipc_callid_t icallid, ipc_call_t *icall) { const sysarg_t method = IPC_GET_IMETHOD(*icall); xt_kbd_t *kbd = ddf_dev_data_get(ddf_fun_get_dev(fun)); switch (method) { case KBDEV_SET_IND: { /* * XT keyboards do not support setting mods, * assume AT keyboard with Scan Code Set 1. */ const unsigned mods = IPC_GET_ARG1(*icall); const uint8_t status = 0 | ((mods & KM_CAPS_LOCK) ? LI_CAPS : 0) | ((mods & KM_NUM_LOCK) ? LI_NUM : 0) | ((mods & KM_SCROLL_LOCK) ? LI_SCROLL : 0); uint8_t cmds[] = { KBD_CMD_SET_LEDS, status }; async_exch_t *exch = async_exchange_begin(kbd->parent_sess); const ssize_t size = chardev_write(exch, cmds, sizeof(cmds)); async_exchange_end(exch); async_answer_0(icallid, size < 0 ? size : EOK); break; } /* * This might be ugly but async_callback_receive_start makes no * difference for incorrect call and malloc failure. */ case IPC_M_CONNECT_TO_ME: { async_sess_t *sess = async_callback_receive_start(EXCHANGE_SERIALIZE, icall); /* Probably ENOMEM error, try again. */ if (sess == NULL) { ddf_msg(LVL_WARN, "Failed creating callback session"); async_answer_0(icallid, EAGAIN); break; } if (kbd->client_sess == NULL) { kbd->client_sess = sess; ddf_msg(LVL_DEBUG, "Set client session"); async_answer_0(icallid, EOK); } else { ddf_msg(LVL_ERROR, "Client session already set"); async_answer_0(icallid, ELIMIT); } break; } default: ddf_msg(LVL_ERROR, "Unknown method: %d.", (int)method); async_answer_0(icallid, EINVAL); break; } }
/** Character device connection handler */ static void cuda_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) { ipc_callid_t callid; ipc_call_t call; sysarg_t method; service_id_t dsid; int dev_addr, i; /* Get the device handle. */ dsid = IPC_GET_ARG1(*icall); /* Determine which disk device is the client connecting to. */ dev_addr = -1; for (i = 0; i < ADB_MAX_ADDR; i++) { if (adb_dev[i].service_id == dsid) dev_addr = i; } if (dev_addr < 0) { async_answer_0(iid, EINVAL); return; } /* Answer the IPC_M_CONNECT_ME_TO call. */ async_answer_0(iid, EOK); while (true) { callid = async_get_call(&call); method = IPC_GET_IMETHOD(call); if (!method) { /* The other side has hung up. */ async_answer_0(callid, EOK); return; } async_sess_t *sess = async_callback_receive_start(EXCHANGE_SERIALIZE, &call); if (sess != NULL) { if (adb_dev[dev_addr].client_sess == NULL) { adb_dev[dev_addr].client_sess = sess; /* * A hack so that we send the data to the session * regardless of which address the device is on. */ for (i = 0; i < ADB_MAX_ADDR; ++i) { if (adb_dev[i].service_id == dsid) adb_dev[i].client_sess = sess; } async_answer_0(callid, EOK); } else async_answer_0(callid, ELIMIT); } else async_answer_0(callid, EINVAL); } }
/** Default handler for IPC methods not handled by DDF. * * @param fun Device function handling the call. * @param icallid Call id. * @param icall Call data. * */ static void default_connection_handler(ddf_fun_t *fun, ipc_callid_t icallid, ipc_call_t *icall) { const sysarg_t method = IPC_GET_IMETHOD(*icall); at_kbd_t *kbd = ddf_dev_data_get(ddf_fun_get_dev(fun)); switch (method) { case KBDEV_SET_IND: { async_answer_0(icallid, ENOTSUP); break; } /* * This might be ugly but async_callback_receive_start makes no * difference for incorrect call and malloc failure. */ case IPC_M_CONNECT_TO_ME: { async_sess_t *sess = async_callback_receive_start(EXCHANGE_SERIALIZE, icall); /* Probably ENOMEM error, try again. */ if (sess == NULL) { ddf_msg(LVL_WARN, "Failed creating callback session"); async_answer_0(icallid, EAGAIN); break; } if (kbd->client_sess == NULL) { kbd->client_sess = sess; ddf_msg(LVL_DEBUG, "Set client session"); async_answer_0(icallid, EOK); } else { ddf_msg(LVL_ERROR, "Client session already set"); async_answer_0(icallid, ELIMIT); } break; } default: ddf_msg(LVL_ERROR, "Unknown method: %d.", (int)method); async_answer_0(icallid, EINVAL); break; } }
static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) { async_answer_0(iid, EOK); while (true) { ipc_call_t call; ipc_callid_t callid = async_get_call(&call); if (!IPC_GET_IMETHOD(call)) { if (client_sess != NULL) { async_hangup(client_sess); client_sess = NULL; } async_answer_0(callid, EOK); return; } async_sess_t *sess = async_callback_receive_start(EXCHANGE_SERIALIZE, &call); if (sess != NULL) { if (client_sess == NULL) { client_sess = sess; async_answer_0(callid, EOK); } else async_answer_0(callid, ELIMIT); } else { switch (IPC_GET_IMETHOD(call)) { case INPUT_YIELD: kbd_devs_yield(); async_answer_0(callid, EOK); break; case INPUT_RECLAIM: kbd_devs_reclaim(); async_answer_0(callid, EOK); break; default: async_answer_0(callid, EINVAL); } } } }
/** * Default handler for IPC methods not handled by DDF. * * Currently recognizes only one method (IPC_M_CONNECT_TO_ME), in which case it * assumes the caller is the console and thus it stores IPC session to it for * later use by the driver to notify about key events. * * @param fun Device function handling the call. * @param icallid Call id. * @param icall Call data. */ static void default_connection_handler(ddf_fun_t *fun, ipc_callid_t icallid, ipc_call_t *icall) { usb_log_debug(NAME " default_connection_handler()\n"); usb_multimedia_t *multim_dev = ddf_fun_data_get(fun); async_sess_t *sess = async_callback_receive_start(EXCHANGE_SERIALIZE, icall); if (sess != NULL) { if (multim_dev->console_sess == NULL) { multim_dev->console_sess = sess; usb_log_debug(NAME " Saved session to console: %p\n", sess); async_answer_0(icallid, EOK); } else async_answer_0(icallid, ELIMIT); } else async_answer_0(icallid, EINVAL); }