/*
 * Copyright (c) 2010 Vojtech Horky
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - The name of the author may not be used to endorse or promote products
 *   derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/** @addtogroup drvusbvhc
 * @{
 */
/** @file
 * @brief Representation of an USB hub.
 */
#ifndef VHC_HUB_HUB_H_
#define VHC_HUB_HUB_H_

#include <fibril_synch.h>

#ifndef HUB_PORT_COUNT
#define HUB_PORT_COUNT 2
#endif
#define BITS2BYTES(bits) (bits ? ((((bits)-1)>>3)+1) : 0)

/** Hub port internal state.
 * Some states (e.g. port over current) are not covered as they are not
 * simulated at all.
 */
typedef enum {
	HUB_PORT_STATE_UNKNOWN,
	HUB_PORT_STATE_NOT_CONFIGURED,
	HUB_PORT_STATE_POWERED_OFF,
	HUB_PORT_STATE_DISCONNECTED,
	HUB_PORT_STATE_DISABLED,
	HUB_PORT_STATE_RESETTING,
	HUB_PORT_STATE_ENABLED,
	HUB_PORT_STATE_SUSPENDED,
	HUB_PORT_STATE_RESUMING,
	/* HUB_PORT_STATE_, */
} hub_port_state_t;

char hub_port_state_to_char(hub_port_state_t);

/** Hub status change mask bits. */
typedef enum {
	HUB_STATUS_C_PORT_CONNECTION = (1 << 0),
	HUB_STATUS_C_PORT_ENABLE = (1 << 1),
	HUB_STATUS_C_PORT_SUSPEND = (1 << 2),
	HUB_STATUS_C_PORT_OVER_CURRENT = (1 << 3),
	HUB_STATUS_C_PORT_RESET = (1 << 4),
	/* HUB_STATUS_C_ = (1 << ), */
} hub_status_change_t;

typedef struct hub hub_t;

/** Hub port information. */
typedef struct {
	/** Custom pointer to connected device. */
	void *connected_device;
	/** Port index (one based). */
	size_t index;
	/** Port state. */
	hub_port_state_t state;
	/** Status change bitmap. */
	uint16_t status_change;
	/** Containing hub. */
	hub_t *hub;
} hub_port_t;

/** Hub device type. */
struct hub {
	/** Hub ports. */
	hub_port_t ports[HUB_PORT_COUNT];
	/** Custom hub data. */
	void *custom_data;
	/** Access guard to the whole hub. */
	fibril_mutex_t guard;
	/** Last value of status change bitmap. */
	bool signal_changes;
};

void hub_init(hub_t *);
size_t hub_connect_device(hub_t *, void *);
errno_t hub_disconnect_device(hub_t *, void *);
size_t hub_find_device(hub_t *, void *);
void hub_acquire(hub_t *);
void hub_release(hub_t *);
void hub_set_port_state(hub_t *, size_t, hub_port_state_t);
void hub_set_port_state_all(hub_t *, hub_port_state_t);
hub_port_state_t hub_get_port_state(hub_t *, size_t);
void hub_clear_port_status_change(hub_t *, size_t, hub_status_change_t);
uint16_t hub_get_port_status_change(hub_t *, size_t);
uint32_t hub_get_port_status(hub_t *, size_t);
uint8_t hub_get_status_change_bitmap(hub_t *);

#endif
/**
 * @}
 */
