int usb_generic_hid_init(usb_hid_dev_t *hid_dev, void **data) { if (hid_dev == NULL) { return EINVAL; } /* Create the exposed function. */ usb_log_debug("Creating DDF function %s...\n", HID_GENERIC_FUN_NAME); ddf_fun_t *fun = ddf_fun_create(hid_dev->usb_dev->ddf_dev, fun_exposed, HID_GENERIC_FUN_NAME); if (fun == NULL) { usb_log_error("Could not create DDF function node.\n"); return ENOMEM; } /* This is nasty, both device and this function have the same * driver data, thus destruction causes to double free */ fun->driver_data = hid_dev; fun->ops = &usb_generic_hid_ops; int rc = ddf_fun_bind(fun); if (rc != EOK) { usb_log_error("Could not bind DDF function: %s.\n", str_error(rc)); fun->driver_data = NULL; ddf_fun_destroy(fun); return rc; } usb_log_debug("HID function created. Handle: %" PRIun "\n", fun->handle); *data = fun; return EOK; }
/** Register child and inform user about it. * * @param parent Parent device. * @param message Message for the user. * @param name Device name. * @param match_id Device match id. * @param score Device match score. */ static int register_fun_verbose(ddf_dev_t *parent, const char *message, const char *name, const char *match_id, int match_score, ddf_fun_t **pfun) { ddf_fun_t *fun; int rc; ddf_msg(LVL_DEBUG, "Registering function `%s': %s.", name, message); fun = ddf_fun_create(parent, fun_inner, name); if (fun == NULL) { ddf_msg(LVL_ERROR, "Failed creating function %s", name); return ENOMEM; } rc = ddf_fun_add_match_id(fun, match_id, match_score); if (rc != EOK) { ddf_msg(LVL_ERROR, "Failed adding match IDs to function %s", name); ddf_fun_destroy(fun); return rc; } rc = ddf_fun_bind(fun); if (rc != EOK) { ddf_msg(LVL_ERROR, "Failed binding function %s: %s", name, str_error(rc)); ddf_fun_destroy(fun); return rc; } *pfun = fun; ddf_msg(LVL_NOTE, "Registered child device `%s'", name); return EOK; }
/** Callback when new device is passed to this driver. * This function is the body of the test: it shall register new child * (named `clone') that shall be driven by the same task. When the clone * is added, it registers another child (named `child') that is also driven * by this task. The conditions ensure that we do not recurse indefinitely. * When successful, the device tree shall contain following fragment: * * /virtual/test1 * /virtual/test1/clone * /virtual/test1/clone/child * * and devman shall not deadlock. * * * @param dev New device. * @return Error code reporting success of the operation. */ static int test1_dev_add(ddf_dev_t *dev) { ddf_fun_t *fun_a; test1_t *test1; int rc; ddf_msg(LVL_DEBUG, "dev_add(name=\"%s\", handle=%d)", dev->name, (int) dev->handle); test1 = ddf_dev_data_alloc(dev, sizeof(test1_t)); if (test1 == NULL) { ddf_msg(LVL_ERROR, "Failed allocating soft state.\n"); return ENOMEM; } fun_a = ddf_fun_create(dev, fun_exposed, "a"); if (fun_a == NULL) { ddf_msg(LVL_ERROR, "Failed creating function 'a'."); return ENOMEM; } test1->fun_a = fun_a; rc = ddf_fun_bind(fun_a); if (rc != EOK) { ddf_msg(LVL_ERROR, "Failed binding function 'a'."); ddf_fun_destroy(fun_a); return rc; } ddf_fun_add_to_category(fun_a, "virtual"); if (str_cmp(dev->name, "null") == 0) { fun_a->ops = &char_device_ops; ddf_fun_add_to_category(fun_a, "virt-null"); } else if (str_cmp(dev->name, "test1") == 0) { (void) register_fun_verbose(dev, "cloning myself ;-)", "clone", "virtual&test1", 10, EOK, &test1->clone); (void) register_fun_verbose(dev, "cloning myself twice ;-)", "clone", "virtual&test1", 10, EEXISTS, NULL); } else if (str_cmp(dev->name, "clone") == 0) { (void) register_fun_verbose(dev, "run by the same task", "child", "virtual&test1&child", 10, EOK, &test1->child); } ddf_msg(LVL_DEBUG, "Device `%s' accepted.", dev->name); return EOK; }
static int amdm37x_dispc_dev_add(ddf_dev_t *dev) { assert(dev); /* Visualizer part */ ddf_fun_t *fun = ddf_fun_create(dev, fun_exposed, "viz"); if (!fun) { ddf_log_error("Failed to create visualizer function\n"); return ENOMEM; } visualizer_t *vis = ddf_fun_data_alloc(fun, sizeof(visualizer_t)); if (!vis) { ddf_log_error("Failed to allocate visualizer structure\n"); ddf_fun_destroy(fun); return ENOMEM; } graph_init_visualizer(vis); vis->reg_svc_handle = ddf_fun_get_handle(fun); ddf_fun_set_ops(fun, &graph_fun_ops); /* Hw part */ amdm37x_dispc_t *dispc = ddf_dev_data_alloc(dev, sizeof(amdm37x_dispc_t)); if (!dispc) { ddf_log_error("Failed to allocate dispc structure\n"); ddf_fun_destroy(fun); return ENOMEM; } int ret = amdm37x_dispc_init(dispc, vis); if (ret != EOK) { ddf_log_error("Failed to init dispc: %s\n", str_error(ret)); ddf_fun_destroy(fun); return ret; } /* Report to devman */ ret = ddf_fun_bind(fun); if (ret != EOK) { ddf_log_error("Failed to bind function: %s\n", str_error(ret)); amdm37x_dispc_fini(dispc); ddf_fun_destroy(fun); return ret; } ddf_fun_add_to_category(fun, "visualizer"); ddf_log_note("Added device `%s'\n", ddf_dev_get_name(dev)); return EOK; }
/** Register child and inform user about it. * * @param parent Parent device. * @param message Message for the user. * @param name Device name. * @param match_id Device match id. * @param score Device match score. */ static int register_fun_verbose(ddf_dev_t *parent, const char *message, const char *name, const char *match_id, int match_score, int expected_rc, ddf_fun_t **pfun) { ddf_fun_t *fun = NULL; int rc; ddf_msg(LVL_DEBUG, "Registering function `%s': %s.", name, message); fun = ddf_fun_create(parent, fun_inner, name); if (fun == NULL) { ddf_msg(LVL_ERROR, "Failed creating function %s", name); rc = ENOMEM; goto leave; } rc = ddf_fun_add_match_id(fun, match_id, match_score); if (rc != EOK) { ddf_msg(LVL_ERROR, "Failed adding match IDs to function %s", name); goto leave; } rc = ddf_fun_bind(fun); if (rc != EOK) { ddf_msg(LVL_ERROR, "Failed binding function %s: %s", name, str_error(rc)); goto leave; } ddf_msg(LVL_NOTE, "Registered child device `%s'", name); rc = EOK; leave: if (rc != expected_rc) { fprintf(stderr, NAME ": Unexpected error registering function `%s'.\n" NAME ": Expected \"%s\" but got \"%s\".\n", name, str_error(expected_rc), str_error(rc)); } if ((rc != EOK) && (fun != NULL)) { ddf_fun_destroy(fun); } if (pfun != NULL) *pfun = fun; return rc; }
/** Initialize keyboard driver structure. * * @param kbd Keyboard driver structure to initialize. * @param dev DDF device structure. * * Connects to parent, creates keyboard function, starts polling fibril. * */ int at_kbd_init(at_kbd_t *kbd, ddf_dev_t *dev) { assert(kbd); assert(dev); kbd->client_sess = NULL; kbd->parent_sess = ddf_dev_parent_sess_create(dev); if (!kbd->parent_sess) { ddf_msg(LVL_ERROR, "Failed creating parent session."); return EIO; } kbd->kbd_fun = ddf_fun_create(dev, fun_exposed, "kbd"); if (!kbd->kbd_fun) { ddf_msg(LVL_ERROR, "Failed creating function 'kbd'."); return ENOMEM; } ddf_fun_set_ops(kbd->kbd_fun, &kbd_ops); int ret = ddf_fun_bind(kbd->kbd_fun); if (ret != EOK) { ddf_msg(LVL_ERROR, "Failed binding function 'kbd'."); ddf_fun_destroy(kbd->kbd_fun); return EEXIST; } ret = ddf_fun_add_to_category(kbd->kbd_fun, "keyboard"); if (ret != EOK) { ddf_msg(LVL_ERROR, "Failed adding function 'kbd' to category " "'keyboard'."); ddf_fun_unbind(kbd->kbd_fun); ddf_fun_destroy(kbd->kbd_fun); return ENOMEM; } kbd->polling_fibril = fibril_create(polling, kbd); if (!kbd->polling_fibril) { ddf_msg(LVL_ERROR, "Failed creating polling fibril."); ddf_fun_unbind(kbd->kbd_fun); ddf_fun_destroy(kbd->kbd_fun); return ENOMEM; } fibril_add_ready(kbd->polling_fibril); return EOK; }
static int register_fun_and_add_to_category(ddf_dev_t *parent, const char *base_name, size_t index, const char *class_name, ddf_fun_t **pfun) { ddf_fun_t *fun = NULL; int rc; char *fun_name = NULL; rc = asprintf(&fun_name, "%s%zu", base_name, index); if (rc < 0) { ddf_msg(LVL_ERROR, "Failed to format string: %s", str_error(rc)); goto leave; } fun = ddf_fun_create(parent, fun_exposed, fun_name); if (fun == NULL) { ddf_msg(LVL_ERROR, "Failed creating function %s", fun_name); rc = ENOMEM; goto leave; } rc = ddf_fun_bind(fun); if (rc != EOK) { ddf_msg(LVL_ERROR, "Failed binding function %s: %s", fun_name, str_error(rc)); goto leave; } ddf_fun_add_to_category(fun, class_name); ddf_msg(LVL_NOTE, "Registered exposed function `%s'.", fun_name); leave: free(fun_name); if ((rc != EOK) && (fun != NULL)) { ddf_fun_destroy(fun); } *pfun = fun; return rc; }
static bool mac_add_fun(ddf_dev_t *dev, const char *name, const char *str_match_id, mac_fun_t *fun_proto) { ddf_msg(LVL_DEBUG, "Adding new function '%s'.", name); ddf_fun_t *fnode = NULL; int rc; /* Create new device. */ fnode = ddf_fun_create(dev, fun_inner, name); if (fnode == NULL) goto failure; mac_fun_t *fun = ddf_fun_data_alloc(fnode, sizeof(mac_fun_t)); *fun = *fun_proto; /* Add match ID */ rc = ddf_fun_add_match_id(fnode, str_match_id, 100); if (rc != EOK) goto failure; /* Set provided operations to the device. */ ddf_fun_set_ops(fnode, &mac_fun_ops); /* Register function. */ if (ddf_fun_bind(fnode) != EOK) { ddf_msg(LVL_ERROR, "Failed binding function %s.", name); goto failure; } return true; failure: if (fnode != NULL) ddf_fun_destroy(fnode); ddf_msg(LVL_ERROR, "Failed adding function '%s'.", name); return false; }
static int rootamdm37x_add_fun(ddf_dev_t *dev, const char *name, const char *str_match_id, const rootamdm37x_fun_t *fun) { ddf_msg(LVL_DEBUG, "Adding new function '%s'.", name); /* Create new device function. */ ddf_fun_t *fnode = ddf_fun_create(dev, fun_inner, name); if (fnode == NULL) return ENOMEM; /* Add match id */ int ret = ddf_fun_add_match_id(fnode, str_match_id, 100); if (ret != EOK) { ddf_fun_destroy(fnode); return ret; } /* Alloc needed data */ rootamdm37x_fun_t *rf = ddf_fun_data_alloc(fnode, sizeof(rootamdm37x_fun_t)); if (!rf) { ddf_fun_destroy(fnode); return ENOMEM; } *rf = *fun; /* Set provided operations to the device. */ ddf_fun_set_ops(fnode, &rootamdm37x_fun_ops); /* Register function. */ ret = ddf_fun_bind(fnode); if (ret != EOK) { ddf_msg(LVL_ERROR, "Failed binding function %s.", name); ddf_fun_destroy(fnode); return ret; } return EOK; }
/** Simulate plugging and surprise unplugging. * * @param arg Parent device structure (ddf_dev_t *). * @return Always EOK. */ static int plug_unplug(void *arg) { test2_t *test2 = (test2_t *) arg; ddf_fun_t *fun_a; int rc; async_usleep(1000); (void) register_fun_verbose(test2->dev, "child driven by the same task", "child", "virtual&test2", 10, &test2->child); (void) register_fun_verbose(test2->dev, "child driven by test1", "test1", "virtual&test1", 10, &test2->test1); fun_a = ddf_fun_create(test2->dev, fun_exposed, "a"); if (fun_a == NULL) { ddf_msg(LVL_ERROR, "Failed creating function 'a'."); return ENOMEM; } rc = ddf_fun_bind(fun_a); if (rc != EOK) { ddf_msg(LVL_ERROR, "Failed binding function 'a'."); return rc; } ddf_fun_add_to_category(fun_a, "virtual"); test2->fun_a = fun_a; async_usleep(10000000); ddf_msg(LVL_NOTE, "Unbinding function test1."); ddf_fun_unbind(test2->test1); async_usleep(1000000); ddf_msg(LVL_NOTE, "Unbinding function child."); ddf_fun_unbind(test2->child); return EOK; }
/** Initialize keyboard driver structure. * @param kbd Keyboard driver structure to initialize. * @param dev DDF device structure. * * Connects to parent, creates mouse function, starts polling fibril. */ int xt_kbd_init(xt_kbd_t *kbd, ddf_dev_t *dev) { assert(kbd); assert(dev); kbd->client_sess = NULL; kbd->parent_sess = ddf_dev_parent_sess_create(dev, EXCHANGE_SERIALIZE); if (!kbd->parent_sess) return ENOMEM; kbd->kbd_fun = ddf_fun_create(dev, fun_exposed, "kbd"); if (!kbd->kbd_fun) { return ENOMEM; } ddf_fun_set_ops(kbd->kbd_fun, &kbd_ops); int ret = ddf_fun_bind(kbd->kbd_fun); if (ret != EOK) { ddf_fun_destroy(kbd->kbd_fun); return ENOMEM; } ret = ddf_fun_add_to_category(kbd->kbd_fun, "keyboard"); if (ret != EOK) { ddf_fun_unbind(kbd->kbd_fun); ddf_fun_destroy(kbd->kbd_fun); return ENOMEM; } kbd->polling_fibril = fibril_create(polling, kbd); if (!kbd->polling_fibril) { ddf_fun_unbind(kbd->kbd_fun); ddf_fun_destroy(kbd->kbd_fun); return ENOMEM; } fibril_add_ready(kbd->polling_fibril); return EOK; }
/** 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; }
static int vhc_dev_add(ddf_dev_t *dev) { static int vhc_count = 0; int rc; if (vhc_count > 0) { return ELIMIT; } vhc_data_t *data = ddf_dev_data_alloc(dev, sizeof(vhc_data_t)); if (data == NULL) { usb_log_fatal("Failed to allocate memory.\n"); return ENOMEM; } data->magic = 0xDEADBEEF; rc = usb_endpoint_manager_init(&data->ep_manager, (size_t) -1, bandwidth_count_usb11); if (rc != EOK) { usb_log_fatal("Failed to initialize endpoint manager.\n"); free(data); return rc; } usb_device_manager_init(&data->dev_manager, USB_SPEED_MAX); ddf_fun_t *hc = ddf_fun_create(dev, fun_exposed, "hc"); if (hc == NULL) { usb_log_fatal("Failed to create device function.\n"); free(data); return ENOMEM; } ddf_fun_set_ops(hc, &vhc_ops); list_initialize(&data->devices); fibril_mutex_initialize(&data->guard); data->hub = &virtual_hub_device; data->hc_fun = hc; rc = ddf_fun_bind(hc); if (rc != EOK) { usb_log_fatal("Failed to bind HC function: %s.\n", str_error(rc)); free(data); return rc; } rc = ddf_fun_add_to_category(hc, USB_HC_CATEGORY); if (rc != EOK) { usb_log_fatal("Failed to add function to HC class: %s.\n", str_error(rc)); free(data); return rc; } virtual_hub_device_init(hc); usb_log_info("Virtual USB host controller ready (dev %zu, hc %zu).\n", (size_t) ddf_dev_get_handle(dev), (size_t) ddf_fun_get_handle(hc)); rc = vhc_virtdev_plug_hub(data, data->hub, NULL); if (rc != EOK) { usb_log_fatal("Failed to plug root hub: %s.\n", str_error(rc)); free(data); return rc; } return EOK; }
/** * Initialize hub device driver structure. * * Creates hub representation and fibril that periodically checks hub's status. * Hub representation is passed to the fibril. * @param usb_dev generic usb device information * @return error code */ int usb_hub_device_add(usb_device_t *usb_dev) { assert(usb_dev); /* Create driver soft-state structure */ usb_hub_dev_t *hub_dev = usb_device_data_alloc(usb_dev, sizeof(usb_hub_dev_t)); if (hub_dev == NULL) { usb_log_error("Failed to create hub driver structure.\n"); return ENOMEM; } hub_dev->usb_device = usb_dev; hub_dev->pending_ops_count = 0; hub_dev->running = false; fibril_mutex_initialize(&hub_dev->pending_ops_mutex); fibril_condvar_initialize(&hub_dev->pending_ops_cv); int opResult = usb_pipe_start_long_transfer(&usb_dev->ctrl_pipe); if (opResult != EOK) { usb_log_error("Failed to start long ctrl pipe transfer: %s\n", str_error(opResult)); return opResult; } /* Set hub's first configuration. (There should be only one) */ opResult = usb_set_first_configuration(usb_dev); if (opResult != EOK) { usb_pipe_end_long_transfer(&usb_dev->ctrl_pipe); usb_log_error("Could not set hub configuration: %s\n", str_error(opResult)); return opResult; } /* Get port count and create attached_devices. */ opResult = usb_hub_process_hub_specific_info(hub_dev); if (opResult != EOK) { usb_pipe_end_long_transfer(&usb_dev->ctrl_pipe); usb_log_error("Could process hub specific info, %s\n", str_error(opResult)); return opResult; } /* Create hub control function. */ usb_log_debug("Creating DDF function '" HUB_FNC_NAME "'.\n"); hub_dev->hub_fun = ddf_fun_create(hub_dev->usb_device->ddf_dev, fun_exposed, HUB_FNC_NAME); if (hub_dev->hub_fun == NULL) { usb_pipe_end_long_transfer(&usb_dev->ctrl_pipe); usb_log_error("Failed to create hub function.\n"); return ENOMEM; } /* Bind hub control function. */ opResult = ddf_fun_bind(hub_dev->hub_fun); if (opResult != EOK) { usb_pipe_end_long_transfer(&usb_dev->ctrl_pipe); usb_log_error("Failed to bind hub function: %s.\n", str_error(opResult)); ddf_fun_destroy(hub_dev->hub_fun); return opResult; } /* Start hub operation. */ opResult = usb_device_auto_poll(hub_dev->usb_device, 0, hub_port_changes_callback, ((hub_dev->port_count + 1 + 8) / 8), usb_hub_polling_terminated_callback, hub_dev); if (opResult != EOK) { usb_pipe_end_long_transfer(&usb_dev->ctrl_pipe); /* Function is already bound */ ddf_fun_unbind(hub_dev->hub_fun); ddf_fun_destroy(hub_dev->hub_fun); usb_log_error("Failed to create polling fibril: %s.\n", str_error(opResult)); return opResult; } hub_dev->running = true; usb_log_info("Controlling hub '%s' (%zu ports).\n", hub_dev->usb_device->ddf_dev->name, hub_dev->port_count); usb_pipe_end_long_transfer(&usb_dev->ctrl_pipe); return EOK; }
/** Initialize i8042 driver structure. * * @param dev Driver structure to initialize. * @param regs I/O address of registers. * @param reg_size size of the reserved I/O address space. * @param irq_kbd IRQ for primary port. * @param irq_mouse IRQ for aux port. * @param ddf_dev DDF device structure of the device. * * @return Error code. * */ int i8042_init(i8042_t *dev, void *regs, size_t reg_size, int irq_kbd, int irq_mouse, ddf_dev_t *ddf_dev) { const size_t range_count = sizeof(i8042_ranges) / sizeof(irq_pio_range_t); irq_pio_range_t ranges[range_count]; const size_t cmd_count = sizeof(i8042_cmds) / sizeof(irq_cmd_t); irq_cmd_t cmds[cmd_count]; int rc; bool kbd_bound = false; bool aux_bound = false; dev->kbd_fun = NULL; dev->aux_fun = NULL; if (reg_size < sizeof(i8042_regs_t)) { rc = EINVAL; goto error; } if (pio_enable(regs, sizeof(i8042_regs_t), (void **) &dev->regs) != 0) { rc = EIO; goto error; } dev->kbd_fun = ddf_fun_create(ddf_dev, fun_inner, "ps2a"); if (dev->kbd_fun == NULL) { rc = ENOMEM; goto error; }; rc = ddf_fun_add_match_id(dev->kbd_fun, "char/xtkbd", 90); if (rc != EOK) goto error; dev->aux_fun = ddf_fun_create(ddf_dev, fun_inner, "ps2b"); if (dev->aux_fun == NULL) { rc = ENOMEM; goto error; } rc = ddf_fun_add_match_id(dev->aux_fun, "char/ps2mouse", 90); if (rc != EOK) goto error; ddf_fun_set_ops(dev->kbd_fun, &ops); ddf_fun_set_ops(dev->aux_fun, &ops); buffer_init(&dev->kbd_buffer, dev->kbd_data, BUFFER_SIZE); buffer_init(&dev->aux_buffer, dev->aux_data, BUFFER_SIZE); fibril_mutex_initialize(&dev->write_guard); rc = ddf_fun_bind(dev->kbd_fun); if (rc != EOK) { ddf_msg(LVL_ERROR, "Failed to bind keyboard function: %s.", ddf_fun_get_name(dev->kbd_fun)); goto error; } kbd_bound = true; rc = ddf_fun_bind(dev->aux_fun); if (rc != EOK) { ddf_msg(LVL_ERROR, "Failed to bind aux function: %s.", ddf_fun_get_name(dev->aux_fun)); goto error; } aux_bound = true; /* Disable kbd and aux */ wait_ready(dev); pio_write_8(&dev->regs->status, i8042_CMD_WRITE_CMDB); wait_ready(dev); pio_write_8(&dev->regs->data, i8042_KBD_DISABLE | i8042_AUX_DISABLE); /* Flush all current IO */ while (pio_read_8(&dev->regs->status) & i8042_OUTPUT_FULL) (void) pio_read_8(&dev->regs->data); memcpy(ranges, i8042_ranges, sizeof(i8042_ranges)); ranges[0].base = (uintptr_t) regs; memcpy(cmds, i8042_cmds, sizeof(i8042_cmds)); cmds[0].addr = (void *) &(((i8042_regs_t *) regs)->status); cmds[3].addr = (void *) &(((i8042_regs_t *) regs)->data); irq_code_t irq_code = { .rangecount = range_count, .ranges = ranges, .cmdcount = cmd_count, .cmds = cmds }; rc = register_interrupt_handler(ddf_dev, irq_kbd, i8042_irq_handler, &irq_code); if (rc != EOK) { ddf_msg(LVL_ERROR, "Failed set handler for kbd: %s.", ddf_dev_get_name(ddf_dev)); goto error; } rc = register_interrupt_handler(ddf_dev, irq_mouse, i8042_irq_handler, &irq_code); if (rc != EOK) { ddf_msg(LVL_ERROR, "Failed set handler for mouse: %s.", ddf_dev_get_name(ddf_dev)); goto error; } /* Enable interrupts */ async_sess_t *parent_sess = ddf_dev_parent_sess_get(ddf_dev); assert(parent_sess != NULL); const bool enabled = hw_res_enable_interrupt(parent_sess); if (!enabled) { log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to enable interrupts: %s.", ddf_dev_get_name(ddf_dev)); rc = EIO; goto error; } /* Enable port interrupts. */ wait_ready(dev); pio_write_8(&dev->regs->status, i8042_CMD_WRITE_CMDB); wait_ready(dev); pio_write_8(&dev->regs->data, i8042_KBD_IE | i8042_KBD_TRANSLATE | i8042_AUX_IE); return EOK; error: if (kbd_bound) ddf_fun_unbind(dev->kbd_fun); if (aux_bound) ddf_fun_unbind(dev->aux_fun); if (dev->kbd_fun != NULL) ddf_fun_destroy(dev->kbd_fun); if (dev->aux_fun != NULL) ddf_fun_destroy(dev->aux_fun); return rc; }
/** * 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); } }
static int ne2k_dev_add(ddf_dev_t *dev) { ddf_fun_t *fun; /* Allocate driver data for the device. */ nic_t *nic_data = nic_create_and_bind(dev); if (nic_data == NULL) return ENOMEM; nic_set_send_frame_handler(nic_data, ne2k_send); nic_set_state_change_handlers(nic_data, ne2k_on_activating, NULL, ne2k_on_stopping); nic_set_filtering_change_handlers(nic_data, ne2k_on_unicast_mode_change, ne2k_on_multicast_mode_change, ne2k_on_broadcast_mode_change, NULL, NULL); ne2k_t *ne2k = malloc(sizeof(ne2k_t)); if (NULL != ne2k) { memset(ne2k, 0, sizeof(ne2k_t)); nic_set_specific(nic_data, ne2k); } else { nic_unbind_and_destroy(dev); return ENOMEM; } int rc = ne2k_dev_init(nic_data); if (rc != EOK) { ne2k_dev_cleanup(dev); return rc; } rc = nic_report_address(nic_data, &ne2k->mac); if (rc != EOK) { ne2k_dev_cleanup(dev); return rc; } rc = nic_connect_to_services(nic_data); if (rc != EOK) { ne2k_dev_cleanup(dev); return rc; } fun = ddf_fun_create(nic_get_ddf_dev(nic_data), fun_exposed, "port0"); if (fun == NULL) { ne2k_dev_cleanup(dev); return ENOMEM; } nic_set_ddf_fun(nic_data, fun); ddf_fun_set_ops(fun, &ne2k_dev_ops); ddf_fun_data_implant(fun, nic_data); rc = ddf_fun_bind(fun); if (rc != EOK) { ddf_fun_destroy(fun); ne2k_dev_cleanup(dev); return rc; } rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC); if (rc != EOK) { ddf_fun_unbind(fun); ddf_fun_destroy(fun); return rc; } return EOK; }