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