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); } }
/** 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; } } }
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); } }
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); } } }
/** 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); } }
/** 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); } }
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); } } } }
static void inet_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 INET_EV_RECV: inet_ev_recv(callid, &call); break; default: async_answer_0(callid, ENOTSUP); } } }
/** Main IPC call handling from virtual host controller. * * @param iid Caller identification * @param icall Initial incoming call * @param arg Local argument */ static void callback_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) { assert(DEV != NULL); async_answer_0(iid, EOK); while (true) { ipc_callid_t callid; ipc_call_t call; callid = async_get_call(&call); bool processed = usbvirt_ipc_handle_call(DEV, callid, &call); if (!processed) { if (!IPC_GET_IMETHOD(call)) { async_answer_0(callid, EOK); return; } else async_answer_0(callid, EINVAL); } } }
static void bd_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg) { bd_t *bd = (bd_t *)arg; (void)bd; 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)) { default: async_answer_0(callid, ENOTSUP); } } }
static void mouse_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) { async_answer_0(iid, EOK); async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE); fibril_mutex_lock(&client_mutex); if (client_sess == NULL) { client_sess = sess; } fibril_mutex_unlock(&client_mutex); while (true) { ipc_call_t call; ipc_callid_t callid = async_get_call(&call); if (!IPC_GET_IMETHOD(call)) break; async_answer_0(callid, ENOTSUP); } }
/** * Recording callback. Writes recorded data. * @param iid IPC call id. * @param icall Poitner to IPC call structure. * @param arg Argument. Poitner to recording helper structure. */ static void device_event_callback(ipc_callid_t iid, ipc_call_t *icall, void* arg) { async_answer_0(iid, EOK); record_t *rec = arg; const size_t buffer_part = rec->buffer.size / BUFFER_PARTS; bool record = true; while (record) { ipc_call_t call; ipc_callid_t callid = async_get_call(&call); switch(IPC_GET_IMETHOD(call)) { case PCM_EVENT_CAPTURE_TERMINATED: printf("Recording terminated\n"); record = false; break; case PCM_EVENT_FRAMES_CAPTURED: printf("%" PRIun " frames\n", IPC_GET_ARG1(call)); break; default: printf("Unknown event %" PRIun ".\n", IPC_GET_IMETHOD(call)); async_answer_0(callid, ENOTSUP); continue; } if (!record) { async_answer_0(callid, EOK); break; } /* Write directly from device buffer to file */ const size_t bytes = fwrite(rec->buffer.position, sizeof(uint8_t), buffer_part, rec->file); printf("%zu ", bytes); rec->buffer.position += buffer_part; if (rec->buffer.position >= (rec->buffer.base + rec->buffer.size)) rec->buffer.position = rec->buffer.base; async_answer_0(callid, EOK); } }
int iplink_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg) { iplink_srv_t *srv = (iplink_srv_t *)arg; int rc; fibril_mutex_lock(&srv->lock); if (srv->connected) { fibril_mutex_unlock(&srv->lock); async_answer_0(iid, EBUSY); return EBUSY; } srv->connected = true; fibril_mutex_unlock(&srv->lock); /* Accept the connection */ async_answer_0(iid, EOK); async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE); if (sess == NULL) return ENOMEM; srv->client_sess = sess; rc = srv->ops->open(srv); if (rc != EOK) return rc; while (true) { ipc_call_t call; ipc_callid_t callid = async_get_call(&call); sysarg_t method = IPC_GET_IMETHOD(call); if (!method) { /* The other side has hung up */ fibril_mutex_lock(&srv->lock); srv->connected = false; fibril_mutex_unlock(&srv->lock); async_answer_0(callid, EOK); break; } switch (method) { case IPLINK_GET_MTU: iplink_get_mtu_srv(srv, callid, &call); break; case IPLINK_SEND: iplink_send_srv(srv, callid, &call); break; case IPLINK_ADDR_ADD: iplink_addr_add_srv(srv, callid, &call); break; case IPLINK_ADDR_REMOVE: iplink_addr_remove_srv(srv, callid, &call); break; default: async_answer_0(callid, EINVAL); } } return srv->ops->close(srv); }
/** * Server side implementation of the hound protocol. IPC connection handler. * @param iid initial call id * @param icall pointer to initial call structure. * @param arg (unused) */ void hound_connection_handler(ipc_callid_t iid, ipc_call_t *icall, void *arg) { /* Accept connection if there is a valid iface*/ if (server_iface) { async_answer_0(iid, EOK); } else { async_answer_0(iid, ENOTSUP); return; } while (1) { ipc_call_t call; ipc_callid_t callid = async_get_call(&call); switch (IPC_GET_IMETHOD(call)) { case IPC_M_HOUND_CONTEXT_REGISTER: { /* check interface functions */ if (!server_iface || !server_iface->add_context) { async_answer_0(callid, ENOTSUP); break; } bool record = IPC_GET_ARG1(call); void *name; /* Get context name */ int ret = async_data_write_accept(&name, true, 0, 0, 0, 0); if (ret != EOK) { async_answer_0(callid, ret); break; } hound_context_id_t id = 0; ret = server_iface->add_context(server_iface->server, &id, name, record); /** new context should create a copy */ free(name); if (ret != EOK) { async_answer_0(callid, ret); } else { async_answer_1(callid, EOK, id); } break; } case IPC_M_HOUND_CONTEXT_UNREGISTER: { /* check interface functions */ if (!server_iface || !server_iface->rem_context) { async_answer_0(callid, ENOTSUP); break; } /* get id, 1st param */ hound_context_id_t id = IPC_GET_ARG1(call); const int ret = server_iface->rem_context(server_iface->server, id); async_answer_0(callid, ret); break; } case IPC_M_HOUND_GET_LIST: { /* check interface functions */ if (!server_iface || !server_iface->get_list) { async_answer_0(callid, ENOTSUP); break; } const char **list = NULL; const int flags = IPC_GET_ARG1(call); size_t count = IPC_GET_ARG2(call); const bool conn = IPC_GET_ARG3(call); char *conn_name = NULL; int ret = EOK; /* get connected actor name if provided */ if (conn) ret = async_data_write_accept( (void**)&conn_name, true, 0, 0, 0, 0); if (ret == EOK) ret = server_iface->get_list( server_iface->server, &list, &count, conn_name, flags); free(conn_name); /* Alloc string sizes array */ size_t *sizes = NULL; if (count) sizes = calloc(count, sizeof(size_t)); if (count && !sizes) ret = ENOMEM; async_answer_1(callid, ret, count); /* We are done */ if (count == 0 || ret != EOK) break; /* Prepare sizes table */ for (unsigned i = 0; i < count; ++i) sizes[i] = str_size(list[i]); /* Send sizes table */ ipc_callid_t id; if (async_data_read_receive(&id, NULL)) { ret = async_data_read_finalize(id, sizes, count * sizeof(size_t)); } free(sizes); /* Proceed to send names */ for (unsigned i = 0; i < count; ++i) { size_t size = str_size(list[i]); ipc_callid_t id; if (ret == EOK && async_data_read_receive(&id, NULL)) { ret = async_data_read_finalize(id, list[i], size); } free(list[i]); } free(list); break; } case IPC_M_HOUND_CONNECT: { /* check interface functions */ if (!server_iface || !server_iface->connect) { async_answer_0(callid, ENOTSUP); break; } void *source = NULL; void *sink = NULL; /* read source name */ int ret = async_data_write_accept(&source, true, 0, 0, 0, 0); /* read sink name */ if (ret == EOK) ret = async_data_write_accept(&sink, true, 0, 0, 0, 0); if (ret == EOK) ret = server_iface->connect( server_iface->server, source, sink); free(source); free(sink); async_answer_0(callid, ret); break; } case IPC_M_HOUND_DISCONNECT: { /* check interface functions */ if (!server_iface || !server_iface->disconnect) { async_answer_0(callid, ENOTSUP); break; } void *source = NULL; void *sink = NULL; /* read source name */ int ret = async_data_write_accept(&source, true, 0, 0, 0, 0); /*read sink name */ if (ret == EOK) ret = async_data_write_accept(&sink, true, 0, 0, 0, 0); if (ret == EOK) ret = server_iface->connect( server_iface->server, source, sink); free(source); free(sink); async_answer_0(callid, ret); break; } case IPC_M_HOUND_STREAM_ENTER: { /* check interface functions */ if (!server_iface || !server_iface->is_record_context || !server_iface->add_stream || !server_iface->rem_stream) { async_answer_0(callid, ENOTSUP); break; } /* get parameters */ hound_context_id_t id = IPC_GET_ARG1(call); const int flags = IPC_GET_ARG2(call); const format_convert_t c = {.arg = IPC_GET_ARG3(call)}; const pcm_format_t f = { .sampling_rate = c.f.rate * 100, .channels = c.f.channels, .sample_format = c.f.format, }; size_t bsize = IPC_GET_ARG4(call); void *stream; int ret = server_iface->add_stream(server_iface->server, id, flags, f, bsize, &stream); if (ret != EOK) { async_answer_0(callid, ret); break; } const bool rec = server_iface->is_record_context( server_iface->server, id); if (rec) { if(server_iface->stream_data_read) { async_answer_0(callid, EOK); /* start answering read calls */ hound_server_write_data(stream); server_iface->rem_stream( server_iface->server, stream); } else { async_answer_0(callid, ENOTSUP); } } else { if (server_iface->stream_data_write) { async_answer_0(callid, EOK); /* accept write calls */ hound_server_read_data(stream); server_iface->rem_stream( server_iface->server, stream); } else { async_answer_0(callid, ENOTSUP); } } break; } case IPC_M_HOUND_STREAM_EXIT: case IPC_M_HOUND_STREAM_DRAIN: /* Stream exit/drain is only allowed in stream context*/ async_answer_0(callid, EINVAL); break; default: async_answer_0(callid, ENOTSUP); return; } } } /** * Read data and push it to the stream. * @param stream target stream, will push data there. */ static void hound_server_read_data(void *stream) { ipc_callid_t callid; ipc_call_t call; size_t size = 0; int ret_answer = EOK; /* accept data write or drain */ while (async_data_write_receive_call(&callid, &call, &size) || (IPC_GET_IMETHOD(call) == IPC_M_HOUND_STREAM_DRAIN)) { /* check drain first */ if (IPC_GET_IMETHOD(call) == IPC_M_HOUND_STREAM_DRAIN) { int ret = ENOTSUP; if (server_iface->drain_stream) ret = server_iface->drain_stream(stream); async_answer_0(callid, ret); continue; } /* there was an error last time */ if (ret_answer != EOK) { async_answer_0(callid, ret_answer); continue; } char *buffer = malloc(size); if (!buffer) { async_answer_0(callid, ENOMEM); continue; } const int ret = async_data_write_finalize(callid, buffer, size); if (ret == EOK) { /* push data to stream */ ret_answer = server_iface->stream_data_write( stream, buffer, size); } } const int ret = IPC_GET_IMETHOD(call) == IPC_M_HOUND_STREAM_EXIT ? EOK : EINVAL; async_answer_0(callid, ret); }
static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) { bool cont = true; /* * The connection was opened via the IPC_CONNECT_ME_TO call. * This call needs to be answered. */ async_answer_0(iid, EOK); while (cont) { ipc_call_t call; ipc_callid_t callid = async_get_call(&call); if (!IPC_GET_IMETHOD(call)) break; switch (IPC_GET_IMETHOD(call)) { case VFS_IN_REGISTER: vfs_register(callid, &call); cont = false; break; case VFS_IN_MOUNT: vfs_mount(callid, &call); break; case VFS_IN_UNMOUNT: vfs_unmount(callid, &call); break; case VFS_IN_OPEN: vfs_open(callid, &call); break; case VFS_IN_CLOSE: vfs_close(callid, &call); break; case VFS_IN_READ: vfs_read(callid, &call); break; case VFS_IN_WRITE: vfs_write(callid, &call); break; case VFS_IN_SEEK: vfs_seek(callid, &call); break; case VFS_IN_TRUNCATE: vfs_truncate(callid, &call); break; case VFS_IN_FSTAT: vfs_fstat(callid, &call); break; case VFS_IN_STAT: vfs_stat(callid, &call); break; case VFS_IN_MKDIR: vfs_mkdir(callid, &call); break; case VFS_IN_UNLINK: vfs_unlink(callid, &call); break; case VFS_IN_RENAME: vfs_rename(callid, &call); break; case VFS_IN_SYNC: vfs_sync(callid, &call); break; case VFS_IN_DUP: vfs_dup(callid, &call); break; case VFS_IN_WAIT_HANDLE: vfs_wait_handle(callid, &call); break; case VFS_IN_MTAB_GET: vfs_get_mtab(callid, &call); break; default: async_answer_0(callid, ENOTSUP); break; } } /* * Open files for this client will be cleaned up when its last * connection fibril terminates. */ }
static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) { void *fs_va = NULL; ipc_callid_t callid; ipc_call_t call; sysarg_t method; size_t comm_size; unsigned int flags; int retval; uint64_t ba; size_t cnt; /* Answer the IPC_M_CONNECT_ME_TO call. */ async_answer_0(iid, EOK); if (!async_share_out_receive(&callid, &comm_size, &flags)) { async_answer_0(callid, EHANGUP); return; } (void) async_share_out_finalize(callid, &fs_va); if (fs_va == AS_MAP_FAILED) { async_answer_0(callid, EHANGUP); return; } 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; } switch (method) { case BD_READ_BLOCKS: ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call)); cnt = IPC_GET_ARG3(call); if (cnt * block_size > comm_size) { retval = ELIMIT; break; } retval = file_bd_read_blocks(ba, cnt, fs_va); break; case BD_WRITE_BLOCKS: ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call)); cnt = IPC_GET_ARG3(call); if (cnt * block_size > comm_size) { retval = ELIMIT; break; } retval = file_bd_write_blocks(ba, cnt, fs_va); break; case BD_GET_BLOCK_SIZE: async_answer_1(callid, EOK, block_size); continue; case BD_GET_NUM_BLOCKS: async_answer_2(callid, EOK, LOWER32(num_blocks), UPPER32(num_blocks)); continue; default: retval = EINVAL; break; } async_answer_0(callid, retval); } }
static void tcp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) { ipc_callid_t callid; ipc_call_t call; tcp_client_t client; /* Accept the connection */ async_answer_0(iid, EOK); client.sess = async_callback_receive(EXCHANGE_SERIALIZE); socket_cores_initialize(&client.sockets); while (true) { callid = async_get_call(&call); if (!IPC_GET_IMETHOD(call)) break; log_msg(LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n", (int)IPC_GET_IMETHOD(call)); switch (IPC_GET_IMETHOD(call)) { case NET_SOCKET: tcp_sock_socket(&client, callid, call); break; case NET_SOCKET_BIND: tcp_sock_bind(&client, callid, call); break; case NET_SOCKET_LISTEN: tcp_sock_listen(&client, callid, call); break; case NET_SOCKET_CONNECT: tcp_sock_connect(&client, callid, call); break; case NET_SOCKET_ACCEPT: tcp_sock_accept(&client, callid, call); break; case NET_SOCKET_SEND: tcp_sock_send(&client, callid, call); break; case NET_SOCKET_SENDTO: tcp_sock_sendto(&client, callid, call); break; case NET_SOCKET_RECV: case NET_SOCKET_RECVFROM: tcp_sock_recvfrom(&client, callid, call); break; case NET_SOCKET_CLOSE: tcp_sock_close(&client, callid, call); break; case NET_SOCKET_GETSOCKOPT: tcp_sock_getsockopt(&client, callid, call); break; case NET_SOCKET_SETSOCKOPT: tcp_sock_setsockopt(&client, callid, call); break; default: async_answer_0(callid, ENOTSUP); break; } } /* Clean up */ log_msg(LVL_DEBUG, "tcp_sock_connection: Clean up"); async_hangup(client.sess); socket_cores_release(NULL, &client.sockets, &gsock, tcp_free_sock_data); }