1/*
2 * Copyright 2020, J��r��me Duval, jerome.duval@gmail.com.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "I2CPrivate.h"
8
9
10I2CDevice::I2CDevice(device_node *node, I2CBus* bus, i2c_addr slaveAddress)
11	:
12	fNode(node),
13	fBus(bus),
14	fSlaveAddress(slaveAddress)
15{
16	CALLED();
17}
18
19
20I2CDevice::~I2CDevice()
21{
22}
23
24
25status_t
26I2CDevice::InitCheck()
27{
28	return B_OK;
29}
30
31
32status_t
33I2CDevice::ExecCommand(i2c_op op, const void *cmdBuffer,
34	size_t cmdLength, void* dataBuffer, size_t dataLength)
35{
36	CALLED();
37	return fBus->ExecCommand(op, fSlaveAddress, cmdBuffer, cmdLength,
38		dataBuffer, dataLength);
39}
40
41
42status_t
43I2CDevice::AcquireBus()
44{
45	CALLED();
46	return fBus->AcquireBus();
47}
48
49
50void
51I2CDevice::ReleaseBus()
52{
53	CALLED();
54	fBus->ReleaseBus();
55}
56
57
58static status_t
59i2c_init_device(device_node *node, void **_device)
60{
61	CALLED();
62	I2CBus* bus;
63
64	{
65		device_node *parent = gDeviceManager->get_parent_node(node);
66		gDeviceManager->get_driver(parent, NULL, (void **)&bus);
67		gDeviceManager->put_node(parent);
68	}
69
70	uint16 slaveAddress;
71	if (gDeviceManager->get_attr_uint16(node, I2C_DEVICE_SLAVE_ADDR_ITEM,
72		&slaveAddress, false) != B_OK) {
73		return B_ERROR;
74	}
75
76
77	I2CDevice *device = new(std::nothrow) I2CDevice(node, bus, slaveAddress);
78	if (device == NULL)
79		return B_NO_MEMORY;
80
81	status_t result = device->InitCheck();
82	if (result != B_OK) {
83		ERROR("failed to set up i2c device object\n");
84		return result;
85	}
86
87	*_device = device;
88
89	return B_OK;
90}
91
92
93static void
94i2c_uninit_device(void *_device)
95{
96	CALLED();
97	I2CDevice *device = (I2CDevice *)_device;
98	delete device;
99}
100
101
102static void
103i2c_device_removed(void *_device)
104{
105	CALLED();
106	//I2CDevice *device = (I2CDevice *)_device;
107}
108
109
110static status_t
111i2c_exec_command(i2c_device _device, i2c_op op, const void *cmdBuffer,
112	size_t cmdLength, void* dataBuffer, size_t dataLength)
113{
114	I2CDevice *device = (I2CDevice *)_device;
115	return device->ExecCommand(op, cmdBuffer, cmdLength, dataBuffer, dataLength);
116}
117
118
119static status_t
120i2c_acquire_bus(i2c_device _device)
121{
122	I2CDevice *device = (I2CDevice *)_device;
123	return device->AcquireBus();
124}
125
126
127static void
128i2c_release_bus(i2c_device _device)
129{
130	I2CDevice *device = (I2CDevice *)_device;
131	return device->ReleaseBus();
132}
133
134
135static status_t
136std_ops(int32 op, ...)
137{
138	switch (op) {
139		case B_MODULE_INIT:
140		{
141			// Link to I2C bus.
142			// I2C device driver must have I2C bus loaded, but it calls its
143			// functions directly instead via official interface, so this
144			// pointer is never read.
145			module_info *dummy;
146			return get_module(I2C_BUS_MODULE_NAME, &dummy);
147		}
148		case B_MODULE_UNINIT:
149			return put_module(I2C_BUS_MODULE_NAME);
150
151		default:
152			return B_ERROR;
153	}
154}
155
156
157i2c_device_interface gI2CDeviceModule = {
158	{
159		{
160			I2C_DEVICE_MODULE_NAME,
161			0,
162			std_ops
163		},
164
165		NULL,	// supported devices
166		NULL,	// register node
167		i2c_init_device,
168		(void (*)(void *)) i2c_uninit_device,
169		NULL,	// register child devices
170		NULL,	// rescan
171		(void (*)(void *)) i2c_device_removed
172	},
173	i2c_exec_command,
174	i2c_acquire_bus,
175	i2c_release_bus,
176};
177