⛏️ index : haiku.git

/*
 * Copyright 2020, JΓ©rΓ΄me Duval, jerome.duval@gmail.com.
 * Distributed under the terms of the MIT License.
 */


#include "I2CPrivate.h"


I2CBus::I2CBus(device_node *node, uint8 id)
	:
	fNode(node),
	fID(id),
	fController(NULL),
	fCookie(NULL)
{
	CALLED();
	device_node *parent = gDeviceManager->get_parent_node(node);
	status_t status = gDeviceManager->get_driver(parent,
		(driver_module_info **)&fController, &fCookie);
	gDeviceManager->put_node(parent);

	if (status != B_OK)
		return;

	fController->set_i2c_bus(fCookie, this);

}


I2CBus::~I2CBus()
{
}


status_t
I2CBus::InitCheck()
{
	return B_OK;
}


status_t
I2CBus::ExecCommand(i2c_op op, i2c_addr slaveAddress, const void *cmdBuffer,
	size_t cmdLength, void* dataBuffer, size_t dataLength)
{
	CALLED();
	return fController->exec_command(fCookie, op, slaveAddress, cmdBuffer, cmdLength,
		dataBuffer, dataLength);
}


status_t
I2CBus::RegisterDevice(i2c_addr slaveAddress, char* hid, char** cid,
	acpi_handle acpiHandle)
{
	CALLED();

	device_attr attrs[] = {
		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "I2C device" }},

		// connection
		{ I2C_DEVICE_SLAVE_ADDR_ITEM, B_UINT16_TYPE, { .ui16 = slaveAddress }},

		// description of peripheral drivers
		{ B_DEVICE_BUS, B_STRING_TYPE, { .string = "i2c" }},

		{ B_DEVICE_FLAGS, B_UINT32_TYPE, { .ui32 = B_FIND_MULTIPLE_CHILDREN }},

		{ ACPI_DEVICE_HID_ITEM, B_STRING_TYPE, { .string = hid }},

		{ ACPI_DEVICE_CID_ITEM, B_STRING_TYPE, { .string = cid[0] }},

		{ ACPI_DEVICE_HANDLE_ITEM, B_UINT64_TYPE, { .ui64 = (addr_t)acpiHandle }},

		{ NULL }
	};

	return gDeviceManager->register_node(fNode, I2C_DEVICE_MODULE_NAME, attrs,
		NULL, NULL);
}


status_t
I2CBus::Scan()
{
	CALLED();
	if (fController->scan_bus != NULL)
		fController->scan_bus(fCookie);
	return B_OK;
}


status_t
I2CBus::AcquireBus()
{
	CALLED();
	if (fController->acquire_bus != NULL)
		return fController->acquire_bus(fCookie);
	return B_OK;
}


void
I2CBus::ReleaseBus()
{
	CALLED();
	if (fController->release_bus != NULL)
		fController->release_bus(fCookie);
}


static status_t
i2c_init_bus(device_node *node, void **_bus)
{
	CALLED();
	uint8 pathID;
	if (gDeviceManager->get_attr_uint8(node, I2C_BUS_PATH_ID_ITEM, &pathID,
		false) != B_OK) {
		return B_ERROR;
	}

	I2CBus *bus = new(std::nothrow) I2CBus(node, pathID);
	if (bus == NULL)
		return B_NO_MEMORY;

	status_t result = bus->InitCheck();
	if (result != B_OK) {
		ERROR("failed to set up i2c bus object\n");
		return result;
	}

	*_bus = bus;

	char name[128];
	snprintf(name, sizeof(name), "bus/i2c/%d/bus_raw", pathID);

	return gDeviceManager->publish_device(node, name, I2C_BUS_RAW_MODULE_NAME);
}


static void
i2c_uninit_bus(void *_bus)
{
	CALLED();
	I2CBus *bus = (I2CBus *)_bus;
	delete bus;
}


static status_t
i2c_scan_bus(void *_bus)
{
	I2CBus *bus = (I2CBus *)_bus;
	return bus->Scan();
}


status_t
i2c_bus_exec_command(void* _bus, i2c_op op, i2c_addr slaveAddress,
		const void *cmdBuffer, size_t cmdLength, void* dataBuffer,
		size_t dataLength)
{
	CALLED();
	I2CBus* bus = (I2CBus*)_bus;
	return bus->ExecCommand(op, slaveAddress, cmdBuffer, cmdLength,
		dataBuffer, dataLength);
}


static status_t
i2c_bus_acquire_bus(void* _bus)
{
	CALLED();
	I2CBus* bus = (I2CBus*)_bus;
	return bus->AcquireBus();
}


static void
i2c_bus_release_bus(void* _bus)
{
	CALLED();
	I2CBus* bus = (I2CBus*)_bus;
	return bus->ReleaseBus();
}


static status_t
std_ops(int32 op, ...)
{
	switch (op) {
		case B_MODULE_INIT:
		case B_MODULE_UNINIT:
			return B_OK;

		default:
			break;
	}

	return B_ERROR;
}


i2c_bus_interface gI2CBusModule = {
	{
		{
			I2C_BUS_MODULE_NAME,
			0,
			std_ops
		},

		NULL, // supported devices
		NULL, // register node
		i2c_init_bus,
		i2c_uninit_bus,
		i2c_scan_bus, // register child devices
		NULL, // rescan
	},

	i2c_bus_exec_command,
	i2c_bus_acquire_bus,
	i2c_bus_release_bus,
};