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