/** 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; }
/** 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; }
/** 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; }
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; }
/** * 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 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; }