/** * Callback for passing a new device to the driver. * * @note Currently, only boot-protocol keyboards are supported by this driver. * * @param dev Structure representing the new device. * @return Error code. */ static int usb_hid_device_add(usb_device_t *dev) { usb_log_debug("%s\n", __FUNCTION__); if (dev == NULL) { usb_log_error("Wrong parameter given for add_device().\n"); return EINVAL; } if (usb_device_get_iface_number(dev) < 0) { usb_log_error("Failed to add HID device: endpoints not found." "\n"); return ENOTSUP; } usb_hid_dev_t *hid_dev = usb_device_data_alloc(dev, sizeof(usb_hid_dev_t)); if (hid_dev == NULL) { usb_log_error("Failed to create USB/HID device structure.\n"); return ENOMEM; } int rc = usb_hid_init(hid_dev, dev); if (rc != EOK) { usb_log_error("Failed to initialize USB/HID device.\n"); usb_hid_deinit(hid_dev); return rc; } usb_log_debug("USB/HID device structure initialized.\n"); /* Start automated polling function. * This will create a separate fibril that will query the device * for the data continuously. */ rc = usb_device_auto_poll_desc(dev, /* Index of the polling pipe. */ hid_dev->poll_pipe_mapping->description, /* Callback when data arrives. */ usb_hid_polling_callback, /* How much data to request. */ hid_dev->poll_pipe_mapping->pipe.max_packet_size, /* Delay */ -1, /* Callback when the polling ends. */ usb_hid_polling_ended_callback, /* Custom argument. */ hid_dev); if (rc != EOK) { usb_log_error("Failed to start polling fibril for `%s'.\n", usb_device_get_name(dev)); usb_hid_deinit(hid_dev); return rc; } hid_dev->running = true; usb_log_info("HID device `%s' ready.\n", usb_device_get_name(dev)); 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; }