Ejemplo n.º 1
0
/** 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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
/** 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;
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
/** 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;
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 7
0
static int fun_unbind(ddf_fun_t *fun, const char *name)
{
	int rc;

	ddf_msg(LVL_DEBUG, "fun_unbind(%p, '%s')", fun, name);
	rc = ddf_fun_unbind(fun);
	if (rc != EOK) {
		ddf_msg(LVL_ERROR, "Failed unbinding function '%s'.", name);
		return rc;
	}

	ddf_fun_destroy(fun);
	return EOK;
}
Ejemplo n.º 8
0
/** 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;
}
Ejemplo n.º 9
0
/** 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;
}
Ejemplo n.º 10
0
void usb_generic_hid_deinit(usb_hid_dev_t *hid_dev, void *data)
{
	ddf_fun_t *fun = data;
	if (fun == NULL)
		return;

	if (ddf_fun_unbind(fun) != EOK) {
		usb_log_error("Failed to unbind generic hid fun.\n");
		return;
	}
	usb_log_debug2("%s unbound.\n", fun->name);
	/* We did not allocate this, so leave this alone
	 * the device would take care of it */
	fun->driver_data = NULL;
	ddf_fun_destroy(fun);
}
Ejemplo n.º 11
0
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;
}
Ejemplo n.º 12
0
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;
}
Ejemplo n.º 13
0
/**
 * Remove all attached devices
 * @param usb_dev generic usb device information
 * @return error code
 */
int usb_hub_device_gone(usb_device_t *usb_dev)
{
	assert(usb_dev);
	usb_hub_dev_t *hub = usb_dev->driver_data;
	assert(hub);
	unsigned tries = 10;
	while (hub->running) {
		async_usleep(100000);
		if (!tries--) {
			usb_log_error("Can't remove hub, still running.\n");
			return EINPROGRESS;
		}
	}

	assert(!hub->running);

	for (size_t port = 0; port < hub->port_count; ++port) {
		if (hub->ports[port].attached_device.fun) {
			const int ret =
			    usb_hub_port_fini(&hub->ports[port], hub);
			if (ret != EOK)
				return ret;
		}
	}
	free(hub->ports);

	const int ret = ddf_fun_unbind(hub->hub_fun);
	if (ret != EOK) {
		usb_log_error("Failed to unbind '%s' function: %s.\n",
		   HUB_FNC_NAME, str_error(ret));
		return ret;
	}
	ddf_fun_destroy(hub->hub_fun);

	usb_log_info("USB hub driver, stopped and cleaned.\n");
	return EOK;
}
Ejemplo n.º 14
0
/** 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;
}
Ejemplo n.º 15
0
/**
 * 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;
}
Ejemplo n.º 16
0
/**
 * 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);
	}
}
Ejemplo n.º 17
0
/** Wrapper for registering attached device to the hub.
 *
 * The @p enable_port function is expected to enable signaling on given
 * port.
 * The argument can have arbitrary meaning and it is not touched at all
 * by this function (it is passed as is to the @p enable_port function).
 *
 * If the @p enable_port fails (i.e. does not return EOK), the device
 * addition is canceled.
 * The return value is then returned (it is good idea to use different
 * error codes than those listed as return codes by this function itself).
 *
 * The @p connection representing connection with host controller does not
 * need to be started.
 * This function duplicates the connection to allow simultaneous calls of
 * this function (i.e. from different fibrils).
 *
 * @param[in] parent Parent device (i.e. the hub device).
 * @param[in] connection Connection to host controller. Must be non-null.
 * @param[in] dev_speed New device speed.
 * @param[in] enable_port Function for enabling signaling through the port the
 *	device is attached to.
 * @param[in] arg Any data argument to @p enable_port.
 * @param[out] assigned_address USB address of the device.
 * @param[in] dev_ops Child device ops. Will use default if not provided.
 * @param[in] new_dev_data Arbitrary pointer to be stored in the child
 *	as @c driver_data. Will allocate and assign usb_hub_attached_device_t
 *	structure if NULL.
 * @param[out] new_fun Storage where pointer to allocated child function
 *	will be written. Must be non-null.
 * @return Error code.
 * @retval EINVAL Either connection or new_fun is a NULL pointer.
 * @retval ENOENT Connection to HC not opened.
 * @retval EADDRNOTAVAIL Failed retrieving free address from host controller.
 * @retval EBUSY Failed reserving default USB address.
 * @retval ENOTCONN Problem connecting to the host controller via USB pipe.
 * @retval ESTALL Problem communication with device (either SET_ADDRESS
 *	request or requests for descriptors when creating match ids).
 */
int usb_hc_new_device_wrapper(ddf_dev_t *parent,
                              usb_hc_connection_t *hc_conn, usb_speed_t dev_speed,
                              int (*enable_port)(void *arg), void *arg, usb_address_t *assigned_address,
                              ddf_dev_ops_t *dev_ops, void *new_dev_data, ddf_fun_t **new_fun)
{
    if ((new_fun == NULL) || (hc_conn == NULL))
        return EINVAL;

    int rc;
    struct timeval start_time;

    rc = gettimeofday(&start_time, NULL);
    if (rc != EOK) {
        return rc;
    }

    /* We are gona do a lot of communication better open it in advance. */
    rc = usb_hc_connection_open(hc_conn);
    if (rc != EOK) {
        return rc;
    }

    /* Request a new address. */
    usb_address_t dev_addr =
        usb_hc_request_address(hc_conn, 0, false, dev_speed);
    if (dev_addr < 0) {
        rc = EADDRNOTAVAIL;
        goto close_connection;
    }

    /* Initialize connection to device. */
    usb_device_connection_t dev_conn;
    rc = usb_device_connection_initialize(
             &dev_conn, hc_conn, USB_ADDRESS_DEFAULT);
    if (rc != EOK) {
        rc = ENOTCONN;
        goto leave_release_free_address;
    }

    /* Initialize control pipe on default address. Don't register yet. */
    usb_pipe_t ctrl_pipe;
    rc = usb_pipe_initialize_default_control(&ctrl_pipe, &dev_conn);
    if (rc != EOK) {
        rc = ENOTCONN;
        goto leave_release_free_address;
    }

    /*
     * The default address request might fail.
     * That means that someone else is already using that address.
     * We will simply wait and try again.
     * (Someone else already wants to add a new device.)
     */
    do {
        rc = usb_hc_request_address(hc_conn, USB_ADDRESS_DEFAULT,
                                    true, dev_speed);
        if (rc == ENOENT) {
            /* Do not overheat the CPU ;-). */
            async_usleep(DEFAULT_ADDRESS_ATTEMPT_DELAY_USEC);
        }
    } while (rc == ENOENT);
    if (rc < 0) {
        goto leave_release_free_address;
    }

    /* Register control pipe on default address. 0 means no interval. */
    rc = usb_pipe_register(&ctrl_pipe, 0);
    if (rc != EOK) {
        rc = ENOTCONN;
        goto leave_release_default_address;
    }

    struct timeval end_time;
    rc = gettimeofday(&end_time, NULL);
    if (rc != EOK) {
        goto leave_release_default_address;
    }

    /* According to the USB spec part 9.1.2 host allows 100ms time for
     * the insertion process to complete. According to 7.1.7.1 this is the
     * time between attach detected and port reset. However, the setup done
     * above might use much of this time so we should only wait to fill
     * up the 100ms quota*/
    const suseconds_t elapsed = tv_sub(&end_time, &start_time);
    if (elapsed < 100000) {
        async_usleep(100000 - elapsed);
    }

    /* Endpoint is registered. We can enable the port and change address. */
    rc = enable_port(arg);
    if (rc != EOK) {
        goto leave_release_default_address;
    }
    /* USB spec 7.1.7.1: The USB System Software guarantees a minimum of
     * 10ms for reset recovery. Device response to any bus transactions
     * addressed to the default device address during the reset recovery
     * time is undefined.
     */
    async_usleep(10000);

    /* Get max_packet_size value. */
    rc = usb_pipe_probe_default_control(&ctrl_pipe);
    if (rc != EOK) {
        rc = ESTALL;
        goto leave_release_default_address;
    }

    rc = usb_request_set_address(&ctrl_pipe, dev_addr);
    if (rc != EOK) {
        rc = ESTALL;
        goto leave_release_default_address;
    }


    /* Register the device with devman. */
    /* FIXME: create device_register that will get opened ctrl pipe. */
    ddf_fun_t *child_fun;
    rc = usb_device_register_child_in_devman(&ctrl_pipe,
            parent, dev_ops, new_dev_data, &child_fun);
    if (rc != EOK) {
        goto leave_release_free_address;
    }

    const usb_hub_attached_device_t new_device = {
        .address = dev_addr,
        .fun = child_fun,
    };


    /* Inform the host controller about the handle. */
    rc = usb_hub_register_device(hc_conn, &new_device);
    if (rc != EOK) {
        /* We know nothing about that data. */
        if (new_dev_data)
            child_fun->driver_data = NULL;
        /* The child function is already created. */
        ddf_fun_destroy(child_fun);
        rc = EDESTADDRREQ;
        goto leave_release_free_address;
    }

    if (assigned_address != NULL) {
        *assigned_address = dev_addr;
    }

    *new_fun = child_fun;

    rc = EOK;
    goto close_connection;

    /*
     * Error handling (like nested exceptions) starts here.
     * Completely ignoring errors here.
     */
leave_release_default_address:
    if (usb_hc_release_address(hc_conn, USB_ADDRESS_DEFAULT) != EOK)
        usb_log_warning("%s: Failed to release defaut address.\n",
                        __FUNCTION__);

leave_release_free_address:
    /* This might be either 0:0 or dev_addr:0 */
    if (usb_pipe_unregister(&ctrl_pipe) != EOK)
        usb_log_warning("%s: Failed to unregister default pipe.\n",
                        __FUNCTION__);

    if (usb_hc_release_address(hc_conn, dev_addr) != EOK)
        usb_log_warning("%s: Failed to release address: %d.\n",
                        __FUNCTION__, dev_addr);

close_connection:
    if (usb_hc_connection_close(hc_conn) != EOK)
        usb_log_warning("%s: Failed to close hc connection.\n",
                        __FUNCTION__);

    return rc;
}
Ejemplo n.º 18
0
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;
}