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