Example #1
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;
}
Example #2
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;
}
Example #3
0
ddf_fun_t *usb_device_ddf_fun_create(usb_device_t *usb_dev, fun_type_t ftype,
    const char* name)
{
	assert(usb_dev);
	if (usb_dev->ddf_dev)
		return ddf_fun_create(usb_dev->ddf_dev, ftype, name);
	return NULL;
}
Example #4
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;
}
Example #5
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;
}
Example #6
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;
}
Example #7
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;
}
Example #8
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;
}
Example #9
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;
}
Example #10
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;
}
Example #11
0
/** 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;
}
Example #12
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;
}
Example #13
0
/** 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;
}
Example #14
0
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;
}
Example #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;
}
Example #16
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;
}
Example #17
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);
	}
}
Example #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;
}