void remote_audio_mixer_get_item_info( ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) { audio_mixer_iface_t *mixer_iface = iface; if (!mixer_iface->get_item_info) { async_answer_0(callid, ENOTSUP); return; } const unsigned item = DEV_IPC_GET_ARG1(*call); const char *name = NULL; unsigned values = 0; const int ret = mixer_iface->get_item_info(fun, item, &name, &values); const size_t name_size = name ? str_size(name) + 1 : 0; async_answer_2(callid, ret, name_size, values); /* Send the name. */ if (ret == EOK && name_size > 0) { size_t size; ipc_callid_t name_id; if (!async_data_read_receive(&name_id, &size)) { async_answer_0(name_id, EPARTY); return; } if (size != name_size) { async_answer_0(name_id, ELIMIT); return; } async_data_read_finalize(name_id, name, name_size); } }
static void loc_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg) { while (true) { ipc_call_t call; ipc_callid_t callid = async_get_call(&call); if (!IPC_GET_IMETHOD(call)) { /* TODO: Handle hangup */ return; } switch (IPC_GET_IMETHOD(call)) { case LOC_EVENT_CAT_CHANGE: fibril_mutex_lock(&loc_callback_mutex); loc_cat_change_cb_t cb_fun = cat_change_cb; fibril_mutex_unlock(&loc_callback_mutex); async_answer_0(callid, EOK); if (cb_fun != NULL) (*cb_fun)(); break; default: async_answer_0(callid, ENOTSUP); } } }
static void tcp_sock_socket(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call) { tcp_sockdata_t *sock; int sock_id; int rc; ipc_call_t answer; log_msg(LVL_DEBUG, "tcp_sock_socket()"); rc = tcp_sock_create(client, &sock); if (rc != EOK) { async_answer_0(callid, rc); return; } sock->laddr.ipv4 = TCP_IPV4_ANY; sock->lconn = NULL; sock->backlog = 0; sock_id = SOCKET_GET_SOCKET_ID(call); rc = tcp_sock_finish_setup(sock, &sock_id); if (rc != EOK) { tcp_sock_uncreate(sock); async_answer_0(callid, rc); return; } SOCKET_SET_SOCKET_ID(answer, sock_id); SOCKET_SET_DATA_FRAGMENT_SIZE(answer, TCP_SOCK_FRAGMENT_SIZE); SOCKET_SET_HEADER_SIZE(answer, sizeof(tcp_header_t)); async_answer_3(callid, EOK, IPC_GET_ARG1(answer), IPC_GET_ARG2(answer), IPC_GET_ARG3(answer)); }
static void udp_sock_close(udp_client_t *client, ipc_callid_t callid, ipc_call_t call) { int socket_id; socket_core_t *sock_core; udp_sockdata_t *socket; int rc; log_msg(LVL_DEBUG, "tcp_sock_close()"); socket_id = SOCKET_GET_SOCKET_ID(call); sock_core = socket_cores_find(&client->sockets, socket_id); if (sock_core == NULL) { async_answer_0(callid, ENOTSOCK); return; } socket = (udp_sockdata_t *)sock_core->specific_data; fibril_mutex_lock(&socket->lock); rc = socket_destroy(NULL, socket_id, &client->sockets, &gsock, udp_free_sock_data); if (rc != EOK) { fibril_mutex_unlock(&socket->lock); async_answer_0(callid, rc); return; } fibril_mutex_unlock(&socket->lock); async_answer_0(callid, EOK); }
void remote_ahci_write_blocks(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) { const ahci_iface_t *ahci_iface = (ahci_iface_t *) iface; if (ahci_iface->read_blocks == NULL) { async_answer_0(callid, ENOTSUP); return; } size_t maxblock_size; unsigned int flags; ipc_callid_t cid; async_share_out_receive(&cid, &maxblock_size, &flags); void *buf; async_share_out_finalize(cid, &buf); const uint64_t blocknum = (((uint64_t)(DEV_IPC_GET_ARG1(*call))) << 32) | (((uint64_t)(DEV_IPC_GET_ARG2(*call))) & 0xffffffff); const size_t cnt = (size_t) DEV_IPC_GET_ARG3(*call); const int ret = ahci_iface->write_blocks(fun, blocknum, cnt, buf); async_answer_0(callid, ret); }
static void remote_ieee80211_get_scan_results(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) { ieee80211_iface_t *ieee80211_iface = (ieee80211_iface_t *) iface; assert(ieee80211_iface->get_scan_results); ieee80211_scan_results_t scan_results; memset(&scan_results, 0, sizeof(ieee80211_scan_results_t)); bool now = IPC_GET_ARG2(*call); int rc = ieee80211_iface->get_scan_results(fun, &scan_results, now); if (rc == EOK) { ipc_callid_t data_callid; size_t max_len; if (!async_data_read_receive(&data_callid, &max_len)) { async_answer_0(data_callid, EINVAL); async_answer_0(callid, EINVAL); return; } if (max_len < sizeof(ieee80211_scan_results_t)) { async_answer_0(data_callid, ELIMIT); async_answer_0(callid, ELIMIT); return; } async_data_read_finalize(data_callid, &scan_results, sizeof(ieee80211_scan_results_t)); } async_answer_0(callid, rc); }
void remote_ahci_get_sata_device_name(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) { const ahci_iface_t *ahci_iface = (ahci_iface_t *) iface; if (ahci_iface->get_sata_device_name == NULL) { async_answer_0(callid, ENOTSUP); return; } const size_t sata_dev_name_length = (size_t) DEV_IPC_GET_ARG1(*call); char* sata_dev_name = malloc(sata_dev_name_length); if (sata_dev_name == NULL) { async_answer_0(callid, ENOMEM); return; } const int ret = ahci_iface->get_sata_device_name(fun, sata_dev_name_length, sata_dev_name); size_t real_size; ipc_callid_t cid; if ((async_data_read_receive(&cid, &real_size)) && (real_size == sata_dev_name_length)) async_data_read_finalize(cid, sata_dev_name, sata_dev_name_length); free(sata_dev_name); async_answer_0(callid, ret); }
/** Handle data requests. * * @param fun ddf_fun_t function. * @param id callid * @param call IPC request. * */ void default_handler(ddf_fun_t *fun, ipc_callid_t id, ipc_call_t *call) { const sysarg_t method = IPC_GET_IMETHOD(*call); const size_t size = IPC_GET_ARG1(*call); switch (method) { case IPC_CHAR_READ: if (size <= 4 * sizeof(sysarg_t)) { sysarg_t message[4] = {}; i8042_read(fun, (char *) message, size); async_answer_4(id, size, message[0], message[1], message[2], message[3]); } else async_answer_0(id, ELIMIT); break; case IPC_CHAR_WRITE: if (size <= 3 * sizeof(sysarg_t)) { const sysarg_t message[3] = { IPC_GET_ARG2(*call), IPC_GET_ARG3(*call), IPC_GET_ARG4(*call) }; i8042_write(fun, (char *) message, size); async_answer_0(id, size); } else async_answer_0(id, ELIMIT); default: async_answer_0(id, EINVAL); } }
/** Handle one connection to APIC. * * @param iid Hash of the request that opened the connection. * @param icall Call data of the request that opened the connection. * @param arg Local argument. */ static void apic_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) { ipc_callid_t callid; ipc_call_t call; /* * Answer the first IPC_M_CONNECT_ME_TO call. */ async_answer_0(iid, EOK); while (true) { callid = async_get_call(&call); if (!IPC_GET_IMETHOD(call)) { /* The other side has hung up. */ async_answer_0(callid, EOK); return; } switch (IPC_GET_IMETHOD(call)) { case IRC_ENABLE_INTERRUPT: async_answer_0(callid, apic_enable_irq(IPC_GET_ARG1(call))); break; case IRC_CLEAR_INTERRUPT: /* Noop */ async_answer_0(callid, EOK); break; default: async_answer_0(callid, EINVAL); break; } } }
/** Receive a call setting arguments of the program to execute. * * @param rid * @param request */ static void ldr_set_args(ipc_callid_t rid, ipc_call_t *request) { char *buf; size_t buf_size; int rc = async_data_write_accept((void **) &buf, true, 0, 0, 0, &buf_size); if (rc == EOK) { /* * Count number of arguments */ char *cur = buf; int count = 0; while (cur < buf + buf_size) { size_t arg_size = str_size(cur); cur += arg_size + 1; count++; } /* * Allocate new argv */ char **_argv = (char **) malloc((count + 1) * sizeof(char *)); if (_argv == NULL) { free(buf); async_answer_0(rid, ENOMEM); return; } /* * Fill the new argv with argument pointers */ cur = buf; count = 0; while (cur < buf + buf_size) { _argv[count] = cur; size_t arg_size = str_size(cur); cur += arg_size + 1; count++; } _argv[count] = NULL; /* * Copy temporary data to global variables */ if (arg_buf != NULL) free(arg_buf); if (argv != NULL) free(argv); argc = count; arg_buf = buf; argv = _argv; } async_answer_0(rid, rc); }
/** 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; } }
/** Handle loader connection. * * Receive and carry out commands (of which the last one should be * to execute the loaded program). */ static void ldr_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) { /* Already have a connection? */ if (connected) { async_answer_0(iid, ELIMIT); return; } connected = true; /* Accept the connection */ async_answer_0(iid, EOK); /* Ignore parameters, the connection is already open */ (void) icall; while (true) { int retval; ipc_call_t call; ipc_callid_t callid = async_get_call(&call); if (!IPC_GET_IMETHOD(call)) exit(0); switch (IPC_GET_IMETHOD(call)) { case LOADER_GET_TASKID: ldr_get_taskid(callid, &call); continue; case LOADER_SET_CWD: ldr_set_cwd(callid, &call); continue; case LOADER_SET_PATHNAME: ldr_set_pathname(callid, &call); continue; case LOADER_SET_ARGS: ldr_set_args(callid, &call); continue; case LOADER_SET_FILES: ldr_set_files(callid, &call); continue; case LOADER_LOAD: ldr_load(callid, &call); continue; case LOADER_RUN: ldr_run(callid, &call); /* Not reached */ default: retval = EINVAL; break; } async_answer_0(callid, retval); } }
void remote_audio_mixer_set_item_level( ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) { audio_mixer_iface_t *mixer_iface = iface; if (!mixer_iface->set_item_level) { async_answer_0(callid, ENOTSUP); return; } const unsigned item = DEV_IPC_GET_ARG1(*call); const unsigned value = DEV_IPC_GET_ARG2(*call); const int ret = mixer_iface->set_item_level(fun, item, value); async_answer_0(callid, ret); }
static void kbd_port_events(ipc_callid_t iid, ipc_call_t *icall, void *arg) { /* Ignore parameters, the connection is already opened */ while (true) { ipc_call_t call; ipc_callid_t callid = async_get_call(&call); int retval = EOK; if (!IPC_GET_IMETHOD(call)) { /* TODO: Handle hangup */ return; } switch (IPC_GET_IMETHOD(call)) { case ADB_REG_NOTIF: adb_kbd_reg0_data(IPC_GET_ARG1(call)); break; default: retval = ENOENT; } async_answer_0(callid, retval); } }
void ne2k_interrupt_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call) { nic_t *nic_data = DRIVER_DATA(dev); ne2k_interrupt(nic_data, IRQ_GET_ISR(*call), IRQ_GET_TSR(*call)); async_answer_0(iid, EOK); }
static void kbdev_callback_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg) { kbdev_t *kbdev; int retval; int type, key; /* Kbdev device structure */ kbdev = arg; while (true) { ipc_call_t call; ipc_callid_t callid; callid = async_get_call(&call); if (!IPC_GET_IMETHOD(call)) { kbdev_destroy(kbdev); return; } switch (IPC_GET_IMETHOD(call)) { case KBDEV_EVENT: /* Got event from keyboard device */ retval = 0; type = IPC_GET_ARG1(call); key = IPC_GET_ARG2(call); kbd_push_event(kbdev->kbd_dev, type, key); break; default: retval = ENOTSUP; break; } async_answer_0(callid, retval); } }
void remote_config_space_write_32(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) { assert(iface); pci_dev_iface_t *pci_iface = (pci_dev_iface_t *)iface; if (pci_iface->config_space_write_32 == NULL) { async_answer_0(callid, ENOTSUP); return; } uint32_t address = DEV_IPC_GET_ARG1(*call); uint32_t value = DEV_IPC_GET_ARG2(*call); int ret = pci_iface->config_space_write_32(fun, address, value); if (ret != EOK) { async_answer_0(callid, ret); } else { async_answer_0(callid, EOK); } }
static void remote_ieee80211_disconnect(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) { ieee80211_iface_t *ieee80211_iface = (ieee80211_iface_t *) iface; assert(ieee80211_iface->disconnect); int rc = ieee80211_iface->disconnect(fun); async_answer_0(callid, rc); }
static void tcp_sock_close(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call) { int socket_id; socket_core_t *sock_core; tcp_sockdata_t *socket; tcp_error_t trc; int rc; log_msg(LVL_DEBUG, "tcp_sock_close()"); socket_id = SOCKET_GET_SOCKET_ID(call); sock_core = socket_cores_find(&client->sockets, socket_id); if (sock_core == NULL) { async_answer_0(callid, ENOTSOCK); return; } socket = (tcp_sockdata_t *)sock_core->specific_data; fibril_mutex_lock(&socket->lock); if (socket->conn != NULL) { trc = tcp_uc_close(socket->conn); if (trc != TCP_EOK && trc != TCP_ENOTEXIST) { fibril_mutex_unlock(&socket->lock); async_answer_0(callid, EBADF); return; } } /* Grab recv_buffer_lock because of CV wait in tcp_sock_recv_fibril() */ fibril_mutex_lock(&socket->recv_buffer_lock); socket->sock_core = NULL; fibril_mutex_unlock(&socket->recv_buffer_lock); rc = socket_destroy(NULL, socket_id, &client->sockets, &gsock, tcp_free_sock_data); if (rc != EOK) { fibril_mutex_unlock(&socket->lock); async_answer_0(callid, rc); return; } fibril_mutex_unlock(&socket->lock); async_answer_0(callid, EOK); }
static void remote_ahci_get_block_size(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) { const ahci_iface_t *ahci_iface = (ahci_iface_t *) iface; if (ahci_iface->get_block_size == NULL) { async_answer_0(callid, ENOTSUP); return; } size_t blocks; const int ret = ahci_iface->get_block_size(fun, &blocks); if (ret != EOK) async_answer_0(callid, ret); else async_answer_1(callid, EOK, blocks); }
static void remote_ahci_get_num_blocks(ddf_fun_t *fun, void *iface, ipc_callid_t callid, ipc_call_t *call) { const ahci_iface_t *ahci_iface = (ahci_iface_t *) iface; if (ahci_iface->get_num_blocks == NULL) { async_answer_0(callid, ENOTSUP); return; } uint64_t blocks; const int ret = ahci_iface->get_num_blocks(fun, &blocks); if (ret != EOK) async_answer_0(callid, ret); else async_answer_2(callid, EOK, HI(blocks), LO(blocks)); }
static void inet_ev_recv(ipc_callid_t callid, ipc_call_t *call) { int rc; inet_dgram_t dgram; dgram.src.ipv4 = IPC_GET_ARG1(*call); dgram.dest.ipv4 = IPC_GET_ARG2(*call); dgram.tos = IPC_GET_ARG3(*call); rc = async_data_write_accept(&dgram.data, false, 0, 0, 0, &dgram.size); if (rc != EOK) { async_answer_0(callid, rc); return; } rc = inet_ev_ops->recv(&dgram); async_answer_0(callid, rc); }
/** 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 iplink_send_srv(iplink_srv_t *srv, ipc_callid_t callid, ipc_call_t *call) { iplink_srv_sdu_t sdu; int rc; sdu.lsrc.ipv4 = IPC_GET_ARG1(*call); sdu.ldest.ipv4 = IPC_GET_ARG2(*call); rc = async_data_write_accept(&sdu.data, false, 0, 0, 0, &sdu.size); if (rc != EOK) { async_answer_0(callid, rc); return; } rc = srv->ops->send(srv, &sdu); free(sdu.data); async_answer_0(callid, rc); }
/** Process the battery_charge_level_get() request from the remote client * * @param fun The function from which the battery charge level is read * @param ops The local ops structure * */ static void remote_battery_charge_level_get(ddf_fun_t *fun, void *ops, ipc_callid_t callid, ipc_call_t *call) { const battery_dev_ops_t *bops = (battery_dev_ops_t *) ops; if (bops->battery_charge_level_get == NULL) { async_answer_0(callid, ENOTSUP); return; } int battery_level; const int rc = bops->battery_charge_level_get(fun, &battery_level); if (rc != EOK) async_answer_0(callid, rc); else async_answer_1(callid, rc, battery_level); }
static void iplink_addr_remove_srv(iplink_srv_t *srv, ipc_callid_t callid, ipc_call_t *call) { int rc; iplink_srv_addr_t addr; addr.ipv4 = IPC_GET_ARG1(*call); rc = srv->ops->addr_remove(srv, &addr); async_answer_0(callid, rc); }
/** * 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); }
static void ldr_get_taskid(ipc_callid_t rid, ipc_call_t *request) { ipc_callid_t callid; task_id_t task_id; size_t len; task_id = task_get_id(); if (!async_data_read_receive(&callid, &len)) { async_answer_0(callid, EINVAL); async_answer_0(rid, EINVAL); return; } if (len > sizeof(task_id)) len = sizeof(task_id); async_data_read_finalize(callid, &task_id, len); async_answer_0(rid, EOK); }
static void remote_graph_connect(ddf_fun_t *fun, void *ops, ipc_callid_t callid, ipc_call_t *call) { graph_dev_ops_t *graph_dev_ops = (graph_dev_ops_t *) ops; if (!graph_dev_ops->connect || !ddf_fun_data_get(fun)) { async_answer_0(callid, ENOTSUP); return; } (*graph_dev_ops->connect)(ddf_fun_data_get(fun), callid, call, NULL); }
/** Callback when client connects to a telnet terminal. */ static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) { /* Find the user. */ telnet_user_t *user = telnet_user_get_for_client_connection(IPC_GET_ARG1(*icall)); if (user == NULL) { async_answer_0(iid, ENOENT); return; } /* Handle messages. */ con_conn(iid, icall, &user->srvs); }