xref: /haiku/src/add-ons/kernel/bus_managers/i2c/bus_raw.cpp (revision 1029af1793db4802d0eee5d4bec4a968169eb1c1)
1f6f8cb83SJérôme Duval /*
2f6f8cb83SJérôme Duval  * Copyright 2020, Jérôme Duval. All rights reserved.
3f6f8cb83SJérôme Duval  * Distributed under the terms of the MIT License.
4f6f8cb83SJérôme Duval  */
5f6f8cb83SJérôme Duval 
6f6f8cb83SJérôme Duval 
7f6f8cb83SJérôme Duval #include "I2CPrivate.h"
8f6f8cb83SJérôme Duval 
9*1029af17SAugustin Cavalier #include <kernel.h>
1004ff1cfaSX512 #include <StackOrHeapArray.h>
1104ff1cfaSX512 
12f6f8cb83SJérôme Duval 
13f6f8cb83SJérôme Duval static status_t
i2c_bus_raw_init(void * driverCookie,void ** _cookie)14f6f8cb83SJérôme Duval i2c_bus_raw_init(void* driverCookie, void **_cookie)
15f6f8cb83SJérôme Duval {
16f6f8cb83SJérôme Duval 	CALLED();
17f6f8cb83SJérôme Duval 	I2CBus *bus = (I2CBus*)driverCookie;
18f6f8cb83SJérôme Duval 	TRACE("i2c_bus_raw_init bus %p\n", bus);
19f6f8cb83SJérôme Duval 
20f6f8cb83SJérôme Duval 	*_cookie = bus;
21f6f8cb83SJérôme Duval 	return B_OK;
22f6f8cb83SJérôme Duval }
23f6f8cb83SJérôme Duval 
24f6f8cb83SJérôme Duval 
25f6f8cb83SJérôme Duval static void
i2c_bus_raw_uninit(void * bus)26f6f8cb83SJérôme Duval i2c_bus_raw_uninit(void *bus)
27f6f8cb83SJérôme Duval {
28f6f8cb83SJérôme Duval }
29f6f8cb83SJérôme Duval 
30f6f8cb83SJérôme Duval 
31f6f8cb83SJérôme Duval static status_t
i2c_bus_raw_open(void * bus,const char * path,int openMode,void ** handle_cookie)32f6f8cb83SJérôme Duval i2c_bus_raw_open(void *bus, const char *path, int openMode,
33f6f8cb83SJérôme Duval 	void **handle_cookie)
34f6f8cb83SJérôme Duval {
35f6f8cb83SJérôme Duval 	CALLED();
36f6f8cb83SJérôme Duval 	*handle_cookie = bus;
37f6f8cb83SJérôme Duval 	TRACE("i2c_bus_raw_open bus %p\n", bus);
38f6f8cb83SJérôme Duval 
39f6f8cb83SJérôme Duval 	return B_OK;
40f6f8cb83SJérôme Duval }
41f6f8cb83SJérôme Duval 
42f6f8cb83SJérôme Duval 
43f6f8cb83SJérôme Duval static status_t
i2c_bus_raw_close(void * cookie)44f6f8cb83SJérôme Duval i2c_bus_raw_close(void *cookie)
45f6f8cb83SJérôme Duval {
46f6f8cb83SJérôme Duval 	return B_OK;
47f6f8cb83SJérôme Duval }
48f6f8cb83SJérôme Duval 
49f6f8cb83SJérôme Duval 
50f6f8cb83SJérôme Duval static status_t
i2c_bus_raw_free(void * cookie)51f6f8cb83SJérôme Duval i2c_bus_raw_free(void *cookie)
52f6f8cb83SJérôme Duval {
53f6f8cb83SJérôme Duval 	return B_OK;
54f6f8cb83SJérôme Duval }
55f6f8cb83SJérôme Duval 
56f6f8cb83SJérôme Duval 
57f6f8cb83SJérôme Duval static status_t
i2c_bus_raw_control(void * _cookie,uint32 op,void * data,size_t length)58f6f8cb83SJérôme Duval i2c_bus_raw_control(void *_cookie, uint32 op, void *data, size_t length)
59f6f8cb83SJérôme Duval {
60f6f8cb83SJérôme Duval 	CALLED();
61f6f8cb83SJérôme Duval 	I2CBus *bus = (I2CBus*)_cookie;
62f6f8cb83SJérôme Duval 
63f6f8cb83SJérôme Duval 	TRACE("i2c_bus_raw_control bus %p\n", bus);
64f6f8cb83SJérôme Duval 
65f6f8cb83SJérôme Duval 
66f6f8cb83SJérôme Duval 	switch (op) {
67f6f8cb83SJérôme Duval 		case I2CEXEC:
68f6f8cb83SJérôme Duval 		{
69f6f8cb83SJérôme Duval 			i2c_ioctl_exec exec;
70f6f8cb83SJérôme Duval 			const void*	userCmdBuffer = NULL;
71f6f8cb83SJérôme Duval 			void* userBuffer = NULL;
72f6f8cb83SJérôme Duval 			if (user_memcpy(&exec, data, sizeof(i2c_ioctl_exec)) != B_OK)
73f6f8cb83SJérôme Duval 				return B_BAD_ADDRESS;
7404ff1cfaSX512 
7504ff1cfaSX512 			if (exec.cmdBuffer == NULL)
7604ff1cfaSX512 				exec.cmdLength = 0;
7704ff1cfaSX512 			if (exec.buffer == NULL)
7804ff1cfaSX512 				exec.bufferLength = 0;
7904ff1cfaSX512 			BStackOrHeapArray<uint8, 32> cmdBuffer(exec.cmdLength);
8004ff1cfaSX512 			BStackOrHeapArray<uint8, 32> buffer(exec.bufferLength);
8104ff1cfaSX512 			if (!cmdBuffer.IsValid() || !buffer.IsValid())
8204ff1cfaSX512 				return B_NO_MEMORY;
8304ff1cfaSX512 
84f6f8cb83SJérôme Duval 			if (exec.cmdBuffer != NULL) {
8504ff1cfaSX512 				if (!IS_USER_ADDRESS(exec.cmdBuffer)
8604ff1cfaSX512 					|| user_memcpy(cmdBuffer, exec.cmdBuffer, exec.cmdLength)
87f6f8cb83SJérôme Duval 					!= B_OK) {
88f6f8cb83SJérôme Duval 					return B_BAD_ADDRESS;
89f6f8cb83SJérôme Duval 				}
90f6f8cb83SJérôme Duval 				userCmdBuffer = exec.cmdBuffer;
91f6f8cb83SJérôme Duval 				exec.cmdBuffer = cmdBuffer;
92f6f8cb83SJérôme Duval 			}
93f6f8cb83SJérôme Duval 			if (exec.buffer != NULL) {
9404ff1cfaSX512 				if (!IS_USER_ADDRESS(exec.buffer)
9504ff1cfaSX512 					|| user_memcpy(buffer, exec.buffer, exec.bufferLength)
96f6f8cb83SJérôme Duval 					!= B_OK) {
97f6f8cb83SJérôme Duval 					return B_BAD_ADDRESS;
98f6f8cb83SJérôme Duval 				}
99f6f8cb83SJérôme Duval 				userBuffer = exec.buffer;
100f6f8cb83SJérôme Duval 				exec.buffer = buffer;
101f6f8cb83SJérôme Duval 			}
102f6f8cb83SJérôme Duval 
10301990a00SJérôme Duval 			status_t status = bus->AcquireBus();
10401990a00SJérôme Duval 			if (status != B_OK)
10501990a00SJérôme Duval 				return status;
10601990a00SJérôme Duval 
10701990a00SJérôme Duval 			status = bus->ExecCommand(exec.op, exec.addr,
10804ff1cfaSX512 				exec.cmdBuffer, exec.cmdLength, exec.buffer,
109f6f8cb83SJérôme Duval 				exec.bufferLength);
11001990a00SJérôme Duval 			bus->ReleaseBus();
11101990a00SJérôme Duval 
112f6f8cb83SJérôme Duval 			if (status != B_OK)
113f6f8cb83SJérôme Duval 				return status;
114f6f8cb83SJérôme Duval 
115f6f8cb83SJérôme Duval 			exec.cmdBuffer = userCmdBuffer;
116f6f8cb83SJérôme Duval 			if (exec.buffer != NULL) {
117f6f8cb83SJérôme Duval 				if (user_memcpy(userBuffer, exec.buffer, exec.bufferLength)
118f6f8cb83SJérôme Duval 					!= B_OK) {
119f6f8cb83SJérôme Duval 					return B_BAD_ADDRESS;
120f6f8cb83SJérôme Duval 				}
121f6f8cb83SJérôme Duval 				exec.buffer = userBuffer;
122f6f8cb83SJérôme Duval 			}
123f6f8cb83SJérôme Duval 
124f6f8cb83SJérôme Duval 			if (user_memcpy(data, &exec, sizeof(i2c_ioctl_exec)) != B_OK)
125f6f8cb83SJérôme Duval 				return B_BAD_ADDRESS;
126f6f8cb83SJérôme Duval 
127f6f8cb83SJérôme Duval 			return B_OK;
128f6f8cb83SJérôme Duval 		}
129f6f8cb83SJérôme Duval 	}
130f6f8cb83SJérôme Duval 
131f6f8cb83SJérôme Duval 	return B_ERROR;
132f6f8cb83SJérôme Duval }
133f6f8cb83SJérôme Duval 
134f6f8cb83SJérôme Duval 
135f6f8cb83SJérôme Duval static status_t
i2c_bus_raw_read(void * cookie,off_t position,void * data,size_t * numBytes)136f6f8cb83SJérôme Duval i2c_bus_raw_read(void *cookie, off_t position, void *data,
137f6f8cb83SJérôme Duval 	size_t *numBytes)
138f6f8cb83SJérôme Duval {
139f6f8cb83SJérôme Duval 	*numBytes = 0;
140f6f8cb83SJérôme Duval 	return B_ERROR;
141f6f8cb83SJérôme Duval }
142f6f8cb83SJérôme Duval 
143f6f8cb83SJérôme Duval 
144f6f8cb83SJérôme Duval static status_t
i2c_bus_raw_write(void * cookie,off_t position,const void * data,size_t * numBytes)145f6f8cb83SJérôme Duval i2c_bus_raw_write(void *cookie, off_t position,
146f6f8cb83SJérôme Duval 	const void *data, size_t *numBytes)
147f6f8cb83SJérôme Duval {
148f6f8cb83SJérôme Duval 	*numBytes = 0;
149f6f8cb83SJérôme Duval 	return B_ERROR;
150f6f8cb83SJérôme Duval }
151f6f8cb83SJérôme Duval 
152f6f8cb83SJérôme Duval 
153f6f8cb83SJérôme Duval struct device_module_info gI2CBusRawModule = {
154f6f8cb83SJérôme Duval 	{
155f6f8cb83SJérôme Duval 		I2C_BUS_RAW_MODULE_NAME,
156f6f8cb83SJérôme Duval 		0,
157f6f8cb83SJérôme Duval 		NULL
158f6f8cb83SJérôme Duval 	},
159f6f8cb83SJérôme Duval 
160f6f8cb83SJérôme Duval 	i2c_bus_raw_init,
161f6f8cb83SJérôme Duval 	i2c_bus_raw_uninit,
162f6f8cb83SJérôme Duval 	NULL,	// removed
163f6f8cb83SJérôme Duval 
164f6f8cb83SJérôme Duval 	i2c_bus_raw_open,
165f6f8cb83SJérôme Duval 	i2c_bus_raw_close,
166f6f8cb83SJérôme Duval 	i2c_bus_raw_free,
167f6f8cb83SJérôme Duval 	i2c_bus_raw_read,
168f6f8cb83SJérôme Duval 	i2c_bus_raw_write,
169f6f8cb83SJérôme Duval 	NULL,	// io
170f6f8cb83SJérôme Duval 	i2c_bus_raw_control,
171f6f8cb83SJérôme Duval 	NULL,	// select
172f6f8cb83SJérôme Duval 	NULL	// deselect
173f6f8cb83SJérôme Duval };
174