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
i2c_bus_raw_init(void * driverCookie,void ** _cookie)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
i2c_bus_raw_uninit(void * bus)26 i2c_bus_raw_uninit(void *bus)
27 {
28 }
29
30
31 static status_t
i2c_bus_raw_open(void * bus,const char * path,int openMode,void ** handle_cookie)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
i2c_bus_raw_close(void * cookie)44 i2c_bus_raw_close(void *cookie)
45 {
46 return B_OK;
47 }
48
49
50 static status_t
i2c_bus_raw_free(void * cookie)51 i2c_bus_raw_free(void *cookie)
52 {
53 return B_OK;
54 }
55
56
57 static status_t
i2c_bus_raw_control(void * _cookie,uint32 op,void * data,size_t length)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
i2c_bus_raw_read(void * cookie,off_t position,void * data,size_t * numBytes)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
i2c_bus_raw_write(void * cookie,off_t position,const void * data,size_t * numBytes)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