/** 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; } }
/** Read data from i8042 port. * * @param fun DDF function. * @param buffer Data place. * @param size Data place size. * * @return Bytes read. * */ static int i8042_read(ddf_fun_t *fun, char *data, size_t size) { i8042_t *controller = dev_i8042(ddf_fun_get_dev(fun)); buffer_t *buffer = (fun == controller->aux_fun) ? &controller->aux_buffer : &controller->kbd_buffer; for (size_t i = 0; i < size; ++i) *data++ = buffer_read(buffer); return size; }
static int ne2k_set_address(ddf_fun_t *fun, const nic_address_t *address) { nic_t *nic_data = DRIVER_DATA(ddf_fun_get_dev(fun)); int rc = nic_report_address(nic_data, address); if (rc != EOK) { return EINVAL; } /* Note: some frame with previous physical address may slip to NIL here * (for a moment the filtering is not exact), but ethernet should be OK with * that. Some frames may also be lost, but this is not a problem. */ ne2k_set_physical_address((ne2k_t *) nic_get_specific(nic_data), address); return EOK; }
/** 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; } }
/** Write data to i8042 port. * * @param fun DDF function. * @param buffer Data source. * @param size Data size. * * @return Bytes written. * */ static int i8042_write(ddf_fun_t *fun, char *buffer, size_t size) { i8042_t *controller = dev_i8042(ddf_fun_get_dev(fun)); fibril_mutex_lock(&controller->write_guard); for (size_t i = 0; i < size; ++i) { if (controller->aux_fun == fun) { wait_ready(controller); pio_write_8(&controller->regs->status, i8042_CMD_WRITE_AUX); } wait_ready(controller); pio_write_8(&controller->regs->data, buffer[i]); } fibril_mutex_unlock(&controller->write_guard); return size; }
/** 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; }
static hda_t *fun_to_hda(ddf_fun_t *fun) { return (hda_t *)ddf_dev_data_get(ddf_fun_get_dev(fun)); }
static sb_mixer_t *fun_to_mixer(ddf_fun_t *fun) { sb16_t *sb = (sb16_t *)ddf_dev_data_get(ddf_fun_get_dev(fun)); return &sb->mixer; }