static int adb_port_init(kbd_dev_t *kdev) { kbd_dev = kdev; const char *dev = "adb/kbd"; service_id_t service_id; int rc = loc_service_get_id(dev, &service_id, 0); if (rc != EOK) return rc; dev_sess = loc_service_connect(EXCHANGE_ATOMIC, service_id, 0); if (dev_sess == NULL) { printf("%s: Failed to connect to device\n", NAME); return ENOENT; } async_exch_t *exch = async_exchange_begin(dev_sess); if (exch == NULL) { printf("%s: Failed starting exchange with device\n", NAME); async_hangup(dev_sess); return ENOMEM; } rc = async_connect_to_me(exch, 0, 0, 0, kbd_port_events, NULL); async_exchange_end(exch); if (rc != EOK) { printf("%s: Failed to create callback from device\n", NAME); async_hangup(dev_sess); return rc; } return EOK; }
int usb_device_create_ddf(ddf_dev_t *ddf_dev, const usb_endpoint_description_t **desc, const char **err) { assert(ddf_dev); assert(err); devman_handle_t h = 0; int iface_no = -1; async_sess_t *sess = devman_parent_device_connect( ddf_dev_get_handle(ddf_dev), IPC_FLAG_BLOCKING); if (sess == NULL) return ENOMEM; const int ret = usb_device_get_info(sess, &h, &iface_no); async_hangup(sess); if (ret != EOK) return ret; usb_device_t *usb_dev = ddf_dev_data_alloc(ddf_dev, sizeof(usb_device_t)); if (usb_dev == NULL) { *err = "DDF data alloc"; return ENOMEM; } return usb_device_init(usb_dev, ddf_dev, desc, err, h, iface_no); }
int fclose(FILE *stream) { int rc = 0; fflush(stream); if (stream->sess != NULL) async_hangup(stream->sess); if (stream->fd >= 0) rc = close(stream->fd); list_remove(&stream->link); if ((stream != &stdin_null) && (stream != &stdout_klog) && (stream != &stderr_klog)) free(stream); stream = NULL; if (rc != 0) { /* errno was set by close() */ return EOF; } return 0; }
/** Get address of I/O registers. * * @param[in] dev Device asking for the addresses. * @param[out] io_reg_address Base address of the memory range. * @param[out] io_reg_size Size of the memory range. * @return Error code. */ int hc_get_my_registers( const ddf_dev_t *dev, uintptr_t *io_reg_address, size_t *io_reg_size) { assert(dev); async_sess_t *parent_sess = devman_parent_device_connect(EXCHANGE_SERIALIZE, dev->handle, IPC_FLAG_BLOCKING); if (!parent_sess) return ENOMEM; hw_res_list_parsed_t hw_res; hw_res_list_parsed_init(&hw_res); const int ret = hw_res_get_list_parsed(parent_sess, &hw_res, 0); async_hangup(parent_sess); if (ret != EOK) { return ret; } if (hw_res.io_ranges.count != 1) { hw_res_list_parsed_clean(&hw_res); return EINVAL; } if (io_reg_address != NULL) *io_reg_address = hw_res.io_ranges.ranges[0].address; if (io_reg_size != NULL) *io_reg_size = hw_res.io_ranges.ranges[0].size; hw_res_list_parsed_clean(&hw_res); return EOK; }
static void kbdev_destroy(kbdev_t *kbdev) { if (kbdev->sess != NULL) async_hangup(kbdev->sess); free(kbdev); }
/** Get address of registers and IRQ for given device. * * @param[in] dev Device asking for the addresses. * @param[out] mem_reg_address Base address of the memory range. * @param[out] mem_reg_size Size of the memory range. * @param[out] irq_no IRQ assigned to the device. * @return Error code. */ int get_my_registers(ddf_dev_t *dev, uintptr_t *mem_reg_address, size_t *mem_reg_size, int *irq_no) { assert(dev); async_sess_t *parent_sess = devman_parent_device_connect(EXCHANGE_SERIALIZE, ddf_dev_get_handle(dev), IPC_FLAG_BLOCKING); if (!parent_sess) return ENOMEM; hw_res_list_parsed_t hw_res; hw_res_list_parsed_init(&hw_res); const int ret = hw_res_get_list_parsed(parent_sess, &hw_res, 0); async_hangup(parent_sess); if (ret != EOK) { return ret; } /* We want one irq and one mem range. */ if (hw_res.irqs.count != 1 || hw_res.mem_ranges.count != 1) { hw_res_list_parsed_clean(&hw_res); return EINVAL; } if (mem_reg_address) *mem_reg_address = hw_res.mem_ranges.ranges[0].address; if (mem_reg_size) *mem_reg_size = hw_res.mem_ranges.ranges[0].size; if (irq_no) *irq_no = hw_res.irqs.irqs[0]; hw_res_list_parsed_clean(&hw_res); return EOK; }
void vbd_destroy(vbd_t *vbd) { if (vbd == NULL) return; async_hangup(vbd->sess); free(vbd); }
static int chardev_port_init(kbd_dev_t *kdev) { service_id_t service_id; async_exch_t *exch; unsigned int i; int rc; kbd_dev = kdev; for (i = 0; i < num_devs; i++) { rc = loc_service_get_id(in_devs[i], &service_id, 0); if (rc == EOK) break; } if (i >= num_devs) { printf("%s: Could not find any suitable input device\n", NAME); return -1; } dev_sess = loc_service_connect(EXCHANGE_ATOMIC, service_id, IPC_FLAG_BLOCKING); if (dev_sess == NULL) { printf("%s: Failed connecting to device\n", NAME); return ENOENT; } exch = async_exchange_begin(dev_sess); if (exch == NULL) { printf("%s: Failed starting exchange with device\n", NAME); async_hangup(dev_sess); return ENOMEM; } /* NB: The callback connection is slotted for removal */ rc = async_connect_to_me(exch, 0, 0, 0, kbd_port_events, NULL); async_exchange_end(exch); if (rc != 0) { printf("%s: Failed to create callback from device\n", NAME); async_hangup(dev_sess); return -1; } return 0; }
int sb_enable_interrupts(ddf_dev_t *device) { async_sess_t *parent_sess = devman_parent_device_connect( ddf_dev_get_handle(device), IPC_FLAG_BLOCKING); if (!parent_sess) return ENOMEM; bool enabled = hw_res_enable_interrupt(parent_sess); async_hangup(parent_sess); return enabled ? EOK : EIO; }
/** Destroy UDP client instance. * * @param udp UDP client */ void udp_destroy(udp_t *udp) { if (udp == NULL) return; async_hangup(udp->sess); fibril_mutex_lock(&udp->lock); while (!udp->cb_done) fibril_condvar_wait(&udp->cv, &udp->lock); fibril_mutex_unlock(&udp->lock); free(udp); }
/** Instruct loader to execute the program. * * Note that this function blocks until the loader actually replies * so you cannot expect this function to return if you are debugging * the task and its thread is stopped. * * After using this function, no further operations can be performed * on the loader structure and it is deallocated. * * @param ldr Loader connection structure. * * @return Zero on success or negative error code. * */ int loader_run(loader_t *ldr) { async_exch_t *exch = async_exchange_begin(ldr->sess); int rc = async_req_0_0(exch, LOADER_RUN); async_exchange_end(exch); if (rc != EOK) return rc; async_hangup(ldr->sess); free(ldr); return EOK; }
int inet_init(uint8_t protocol, inet_ev_ops_t *ev_ops) { service_id_t inet_svc; int rc; assert(inet_sess == NULL); assert(inet_ev_ops == NULL); assert(inet_protocol == 0); rc = loc_service_get_id(SERVICE_NAME_INET, &inet_svc, IPC_FLAG_BLOCKING); if (rc != EOK) return ENOENT; inet_sess = loc_service_connect(EXCHANGE_SERIALIZE, inet_svc, IPC_FLAG_BLOCKING); if (inet_sess == NULL) return ENOENT; if (inet_set_proto(protocol) != EOK) { async_hangup(inet_sess); inet_sess = NULL; return EIO; } if (inet_callback_create() != EOK) { async_hangup(inet_sess); inet_sess = NULL; return EIO; } inet_protocol = protocol; inet_ev_ops = ev_ops; return EOK; }
/** Call the PCI driver with a request to clear legacy support register * * @param[in] device Device asking to disable interrupts * @return Error code. */ static int disable_legacy(ddf_dev_t *device) { assert(device); async_sess_t *parent_sess = devman_parent_device_connect( ddf_dev_get_handle(device), IPC_FLAG_BLOCKING); if (!parent_sess) return ENOMEM; /* See UHCI design guide page 45 for these values. * Write all WC bits in USB legacy register */ const int rc = pci_config_space_write_16(parent_sess, 0xc0, 0xaf00); async_hangup(parent_sess); return rc; }
static const char *test_virtchar1_internal(const char *path) { TPRINTF("Opening `%s'...\n", path); int fd = open(path, O_RDONLY); if (fd < 0) { TPRINTF(" ...error: %s\n", str_error(fd)); if (fd == ENOENT) { TPRINTF(" (error was ENOENT: " \ "have you compiled test drivers?)\n"); } return "Failed opening devman driver device for reading"; } TPRINTF(" ...file handle %d\n", fd); TPRINTF(" Asking for session...\n"); async_sess_t *sess = fd_session(EXCHANGE_SERIALIZE, fd); if (!sess) { close(fd); TPRINTF(" ...error: %s\n", str_error(errno)); return "Failed to get session to device"; } TPRINTF(" ...session is %p\n", sess); TPRINTF(" Will try to read...\n"); size_t i; char buffer[BUFFER_SIZE]; char_dev_read(sess, buffer, BUFFER_SIZE); TPRINTF(" ...verifying that we read zeroes only...\n"); for (i = 0; i < BUFFER_SIZE; i++) { if (buffer[i] != 0) { return "Not all bytes are zeroes"; } } TPRINTF(" ...data read okay\n"); /* Clean-up. */ TPRINTF(" Closing session and file descriptor\n"); async_hangup(sess); close(fd); return NULL; }
static int kbdev_ctl_init(kbd_dev_t *kdev) { async_sess_t *sess = loc_service_connect(EXCHANGE_SERIALIZE, kdev->svc_id, 0); if (sess == NULL) { printf("%s: Failed starting session with '%s.'\n", NAME, kdev->svc_name); return ENOENT; } kbdev_t *kbdev = kbdev_new(kdev); if (kbdev == NULL) { printf("%s: Failed allocating device structure for '%s'.\n", NAME, kdev->svc_name); async_hangup(sess); return ENOMEM; } kbdev->sess = sess; async_exch_t *exch = async_exchange_begin(sess); if (exch == NULL) { printf("%s: Failed starting exchange with '%s'.\n", NAME, kdev->svc_name); kbdev_destroy(kbdev); return ENOENT; } int rc = async_connect_to_me(exch, 0, 0, 0, kbdev_callback_conn, kbdev); if (rc != EOK) { printf("%s: Failed creating callback connection from '%s'.\n", NAME, kdev->svc_name); async_exchange_end(exch); kbdev_destroy(kbdev); return rc; } async_exchange_end(exch); kdev->ctl_private = (void *) kbdev; return 0; }
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); } } } }
/** Register root hub in devman. * * @param arg Host controller device (type <code>device_t *</code>). * @return Error code. */ int hub_register_in_devman_fibril(void *arg) { ddf_fun_t *hc_dev = (ddf_fun_t *) arg; /* * Wait until parent device is properly initialized. */ async_sess_t *sess; do { sess = devman_device_connect(EXCHANGE_SERIALIZE, ddf_fun_get_handle(hc_dev), 0); } while (!sess); async_hangup(sess); int rc; usb_hc_connection_t hc_conn; usb_hc_connection_initialize(&hc_conn, ddf_fun_get_handle(hc_dev)); rc = usb_hc_connection_open(&hc_conn); assert(rc == EOK); ddf_fun_t *hub_dev; rc = usb_hc_new_device_wrapper(ddf_fun_get_dev(hc_dev), &hc_conn, USB_SPEED_FULL, pretend_port_rest, NULL, NULL, &rh_ops, hc_dev, &hub_dev); if (rc != EOK) { usb_log_fatal("Failed to create root hub: %s.\n", str_error(rc)); } usb_hc_connection_close(&hc_conn); usb_log_info("Created root hub function (handle %zu).\n", (size_t) ddf_fun_get_handle(hub_dev)); return 0; }
usb_device_t * usb_device_create(devman_handle_t handle) { devman_handle_t h = 0; int iface_no = -1; async_sess_t *sess = devman_device_connect(handle, IPC_FLAG_BLOCKING); int ret = usb_device_get_info(sess, &h, &iface_no); if (sess) async_hangup(sess); if (ret != EOK) return NULL; usb_device_t *usb_dev = malloc(sizeof(usb_device_t)); if (!usb_dev) return NULL; const char* dummy = NULL; ret = usb_device_init(usb_dev, NULL, NULL, &dummy, handle, iface_no); if (ret != EOK) { free(usb_dev); usb_dev = NULL; } return usb_dev; }
/** VFS_REGISTER protocol function. * * @param rid Hash of the call with the request. * @param request Call structure with the request. * */ void vfs_register(ipc_callid_t rid, ipc_call_t *request) { dprintf("Processing VFS_REGISTER request received from %p.\n", request->in_phone_hash); vfs_info_t *vfs_info; int rc = async_data_write_accept((void **) &vfs_info, false, sizeof(vfs_info_t), sizeof(vfs_info_t), 0, NULL); if (rc != EOK) { dprintf("Failed to deliver the VFS info into our AS, rc=%d.\n", rc); async_answer_0(rid, rc); return; } /* * Allocate and initialize a buffer for the fs_info structure. */ fs_info_t *fs_info = (fs_info_t *) malloc(sizeof(fs_info_t)); if (!fs_info) { dprintf("Could not allocate memory for FS info.\n"); async_answer_0(rid, ENOMEM); return; } link_initialize(&fs_info->fs_link); fs_info->vfs_info = *vfs_info; free(vfs_info); dprintf("VFS info delivered.\n"); if (!vfs_info_sane(&fs_info->vfs_info)) { free(fs_info); async_answer_0(rid, EINVAL); return; } fibril_mutex_lock(&fs_list_lock); /* * Check for duplicit registrations. */ if (fs_name_to_handle(fs_info->vfs_info.instance, fs_info->vfs_info.name, false)) { /* * We already register a fs like this. */ dprintf("FS is already registered.\n"); fibril_mutex_unlock(&fs_list_lock); free(fs_info); async_answer_0(rid, EEXISTS); return; } /* * Add fs_info to the list of registered FS's. */ dprintf("Inserting FS into the list of registered file systems.\n"); list_append(&fs_info->fs_link, &fs_list); /* * Now we want the client to send us the IPC_M_CONNECT_TO_ME call so * that a callback connection is created and we have a phone through * which to forward VFS requests to it. */ fs_info->sess = async_callback_receive(EXCHANGE_PARALLEL); if (!fs_info->sess) { dprintf("Callback connection expected\n"); list_remove(&fs_info->fs_link); fibril_mutex_unlock(&fs_list_lock); free(fs_info); async_answer_0(rid, EINVAL); return; } dprintf("Callback connection to FS created.\n"); /* * The client will want us to send him the address space area with PLB. */ size_t size; ipc_callid_t callid; if (!async_share_in_receive(&callid, &size)) { dprintf("Unexpected call, method = %d\n", IPC_GET_IMETHOD(call)); list_remove(&fs_info->fs_link); fibril_mutex_unlock(&fs_list_lock); async_hangup(fs_info->sess); free(fs_info); async_answer_0(callid, EINVAL); async_answer_0(rid, EINVAL); return; } /* * We can only send the client address space area PLB_SIZE bytes long. */ if (size != PLB_SIZE) { dprintf("Client suggests wrong size of PFB, size = %d\n", size); list_remove(&fs_info->fs_link); fibril_mutex_unlock(&fs_list_lock); async_hangup(fs_info->sess); free(fs_info); async_answer_0(callid, EINVAL); async_answer_0(rid, EINVAL); return; } /* * Commit to read-only sharing the PLB with the client. */ (void) async_share_in_finalize(callid, plb, AS_AREA_READ | AS_AREA_CACHEABLE); dprintf("Sharing PLB.\n"); /* * That was it. The FS has been registered. * In reply to the VFS_REGISTER request, we assign the client file * system a global file system handle. */ fs_info->fs_handle = (fs_handle_t) atomic_postinc(&fs_handle_next); async_answer_1(rid, EOK, (sysarg_t) fs_info->fs_handle); fibril_condvar_broadcast(&fs_list_cv); fibril_mutex_unlock(&fs_list_lock); dprintf("\"%.*s\" filesystem successfully registered, handle=%d.\n", FS_NAME_MAXLEN, fs_info->vfs_info.name, fs_info->fs_handle); }
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); }
/** * End an existing audio session. * @param sess The session. */ void hound_service_disconnect(hound_sess_t *sess) { if (sess) async_hangup(sess); }
/** * Processes key events. * * @note This function was copied from AT keyboard driver and modified to suit * USB keyboard. * * @note Lock keys are not sent to the console, as they are completely handled * in the driver. It may, however, be required later that the driver * sends also these keys to application (otherwise it cannot use those * keys at all). * * @param hid_dev * @param multim_dev * @param type Type of the event (press / release). Recognized values: * KEY_PRESS, KEY_RELEASE * @param key Key code of the key according to HID Usage Tables. */ static void usb_multimedia_push_ev( usb_multimedia_t *multim_dev, int type, unsigned int key) { assert(multim_dev != NULL); const kbd_event_t ev = { .type = type, .key = key, .mods = 0, .c = 0, }; usb_log_debug2(NAME " Sending key %d to the console\n", ev.key); if (multim_dev->console_sess == NULL) { usb_log_warning( "Connection to console not ready, key discarded.\n"); return; } async_exch_t *exch = async_exchange_begin(multim_dev->console_sess); if (exch != NULL) { async_msg_4(exch, KBDEV_EVENT, ev.type, ev.key, ev.mods, ev.c); async_exchange_end(exch); } else { usb_log_warning("Failed to send multimedia key.\n"); } } int usb_multimedia_init(struct usb_hid_dev *hid_dev, void **data) { if (hid_dev == NULL || hid_dev->usb_dev == NULL) { return EINVAL; } usb_log_debug(NAME " Initializing HID/multimedia structure...\n"); /* Create the exposed function. */ ddf_fun_t *fun = ddf_fun_create( hid_dev->usb_dev->ddf_dev, fun_exposed, NAME); if (fun == NULL) { usb_log_error("Could not create DDF function node.\n"); return ENOMEM; } ddf_fun_set_ops(fun, &multimedia_ops); usb_multimedia_t *multim_dev = ddf_fun_data_alloc(fun, sizeof(usb_multimedia_t)); if (multim_dev == NULL) { ddf_fun_destroy(fun); return ENOMEM; } multim_dev->console_sess = NULL; //todo Autorepeat? int rc = ddf_fun_bind(fun); if (rc != EOK) { usb_log_error("Could not bind DDF function: %s.\n", str_error(rc)); ddf_fun_destroy(fun); return rc; } usb_log_debug(NAME " function created (handle: %" PRIun ").\n", ddf_fun_get_handle(fun)); rc = ddf_fun_add_to_category(fun, "keyboard"); if (rc != EOK) { usb_log_error( "Could not add DDF function to category 'keyboard': %s.\n", str_error(rc)); if (ddf_fun_unbind(fun) != EOK) { usb_log_error("Failed to unbind %s, won't destroy.\n", ddf_fun_get_name(fun)); } else { ddf_fun_destroy(fun); } return rc; } /* Save the KBD device structure into the HID device structure. */ *data = fun; usb_log_debug(NAME " HID/multimedia structure initialized.\n"); return EOK; } void usb_multimedia_deinit(struct usb_hid_dev *hid_dev, void *data) { ddf_fun_t *fun = data; usb_multimedia_t *multim_dev = ddf_fun_data_get(fun); /* Hangup session to the console */ if (multim_dev->console_sess) async_hangup(multim_dev->console_sess); if (ddf_fun_unbind(fun) != EOK) { usb_log_error("Failed to unbind %s, won't destroy.\n", ddf_fun_get_name(fun)); } else { usb_log_debug2("%s unbound.\n", ddf_fun_get_name(fun)); /* This frees multim_dev too as it was stored in * fun->data */ ddf_fun_destroy(fun); } }
/** Cancel the loader session. * * Tell the loader not to load any program and terminate. * After using this function, no further operations can be performed * on the loader structure and it is deallocated. * * @param ldr Loader connection structure. * * @return Zero on success or negative error code. * */ void loader_abort(loader_t *ldr) { async_hangup(ldr->sess); free(ldr); }
/** Initialize new SB16 driver instance. * * @param[in] device DDF instance of the device to initialize. * @return Error code. */ static int sb_add_device(ddf_dev_t *device) { bool handler_regd = false; const size_t irq_cmd_count = sb16_irq_code_size(); irq_cmd_t irq_cmds[irq_cmd_count]; irq_pio_range_t irq_ranges[1]; sb16_t *soft_state = ddf_dev_data_alloc(device, sizeof(sb16_t)); int rc = soft_state ? EOK : ENOMEM; if (rc != EOK) { ddf_log_error("Failed to allocate sb16 structure."); goto error; } addr_range_t sb_regs; addr_range_t *p_sb_regs = &sb_regs; addr_range_t mpu_regs; addr_range_t *p_mpu_regs = &mpu_regs; int irq = 0, dma8 = 0, dma16 = 0; rc = sb_get_res(device, &p_sb_regs, &p_mpu_regs, &irq, &dma8, &dma16); if (rc != EOK) { ddf_log_error("Failed to get resources: %s.", str_error(rc)); goto error; } sb16_irq_code(p_sb_regs, dma8, dma16, irq_cmds, irq_ranges); irq_code_t irq_code = { .cmdcount = irq_cmd_count, .cmds = irq_cmds, .rangecount = 1, .ranges = irq_ranges }; rc = register_interrupt_handler(device, irq, irq_handler, &irq_code); if (rc != EOK) { ddf_log_error("Failed to register irq handler: %s.", str_error(rc)); goto error; } handler_regd = true; rc = sb_enable_interrupts(device); if (rc != EOK) { ddf_log_error("Failed to enable interrupts: %s.", str_error(rc)); goto error; } rc = sb16_init_sb16(soft_state, p_sb_regs, device, dma8, dma16); if (rc != EOK) { ddf_log_error("Failed to init sb16 driver: %s.", str_error(rc)); goto error; } rc = sb16_init_mpu(soft_state, p_mpu_regs); if (rc == EOK) { ddf_fun_t *mpu_fun = ddf_fun_create(device, fun_exposed, "midi"); if (mpu_fun) { rc = ddf_fun_bind(mpu_fun); if (rc != EOK) ddf_log_error( "Failed to bind midi function: %s.", str_error(rc)); } else { ddf_log_error("Failed to create midi function."); } } else { ddf_log_warning("Failed to init mpu driver: %s.", str_error(rc)); } /* MPU state does not matter */ return EOK; error: if (handler_regd) unregister_interrupt_handler(device, irq); return rc; } static int sb_get_res(ddf_dev_t *device, addr_range_t **pp_sb_regs, addr_range_t **pp_mpu_regs, int *irq, int *dma8, int *dma16) { assert(device); async_sess_t *parent_sess = devman_parent_device_connect( ddf_dev_get_handle(device), IPC_FLAG_BLOCKING); if (!parent_sess) return ENOMEM; hw_res_list_parsed_t hw_res; hw_res_list_parsed_init(&hw_res); const int ret = hw_res_get_list_parsed(parent_sess, &hw_res, 0); async_hangup(parent_sess); if (ret != EOK) { return ret; } /* 1x IRQ, 1-2x DMA(8,16), 1-2x IO (MPU is separate). */ if (hw_res.irqs.count != 1 || (hw_res.io_ranges.count != 1 && hw_res.io_ranges.count != 2) || (hw_res.dma_channels.count != 1 && hw_res.dma_channels.count != 2)) { hw_res_list_parsed_clean(&hw_res); return EINVAL; } if (irq) *irq = hw_res.irqs.irqs[0]; if (dma8) { if (hw_res.dma_channels.channels[0] < 4) { *dma8 = hw_res.dma_channels.channels[0]; } else { if (hw_res.dma_channels.count == 2 && hw_res.dma_channels.channels[1] < 4) { *dma8 = hw_res.dma_channels.channels[1]; } } } if (dma16) { if (hw_res.dma_channels.channels[0] > 4) { *dma16 = hw_res.dma_channels.channels[0]; } else { if (hw_res.dma_channels.count == 2 && hw_res.dma_channels.channels[1] > 4) { *dma16 = hw_res.dma_channels.channels[1]; } } } if (hw_res.io_ranges.count == 1) { if (pp_sb_regs && *pp_sb_regs) **pp_sb_regs = hw_res.io_ranges.ranges[0]; if (pp_mpu_regs) *pp_mpu_regs = NULL; } else { const int sb = (hw_res.io_ranges.ranges[0].size >= sizeof(sb16_regs_t)) ? 0 : 1; const int mpu = 1 - sb; if (pp_sb_regs && *pp_sb_regs) **pp_sb_regs = hw_res.io_ranges.ranges[sb]; if (pp_mpu_regs && *pp_mpu_regs) **pp_mpu_regs = hw_res.io_ranges.ranges[mpu]; } return EOK; }
/** Disconnect the device from virtual host controller. * * @param dev Device to be disconnected. */ void usbvirt_device_unplug(usbvirt_device_t *dev) { async_hangup(dev->vhc_sess); }