blob: fad3200c7c157d9ee3f91ba0db6b7f9654796ac4 [file] [log] [blame]
Rohit Sekharc5949c32023-08-23 15:19:29 +05301/*
2 * Copyright (c) 2021, The Linux Foundation. All rights reserved.
Rohit Sekharc5949c32023-08-23 15:19:29 +05303 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Changes from Qualcomm Innovation Center are provided under the following license:
Michael Bestas4618b562024-09-26 02:28:02 +030030 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
Rohit Sekharc5949c32023-08-23 15:19:29 +053031 * SPDX-License-Identifier: BSD-3-Clause-Clear
32 */
33
34#define LOG_TAG "vendor.qti.vibrator.offload"
35
36#include <stdio.h>
37#include <stdint.h>
38#include <string.h>
39#include <thread>
40#include <linux/input.h>
41#include <log/log.h>
42#include <fcntl.h>
43#include <cutils/log.h>
44#include <cutils/uevent.h>
45#include <cutils/properties.h>
46#include <sys/poll.h>
47#include <sys/ioctl.h>
48
49#include "include/Vibrator.h"
50#include "VibratorPatterns.h"
51
52namespace aidl {
53namespace android {
54namespace hardware {
55namespace vibrator {
56
57#define UEVENT_MSG_LEN 1024
58#define SLATE_EVENT "SLATE_EVENT="
59#define SLATE_EVENT_STRING_LEN 12 //length of SLATE_EVENT
60/*
61 * TODO Need to work on solution to get this from kernel header
62 * without effecting other kernel versions where this change
63 * goes in.
64 */
65#define SLATE_AFTER_POWER_UP 4
66
67PatternOffload::PatternOffload()
68{
69 char prop_str[PROPERTY_VALUE_MAX];
70 mEnabled = 0;
71
72 if (property_get("ro.vendor.qc_aon_presence", prop_str, NULL))
73 mEnabled = atoi(prop_str);
74
75 if (mEnabled != 1)
76 return;
77
78 std::thread t(&PatternOffload::SSREventListener, this);
79 t.detach();
80}
81
82void PatternOffload::SSREventListener(void)
83{
84 int device_fd, n, ssr_event = 0;
85 char msg[UEVENT_MSG_LEN + 2];
86 char *msg_ptr = msg;
87
88 /* Offload during the bootup */
89 SendPatterns();
90
91 device_fd = uevent_open_socket(64*1024, true);
92 if(device_fd < 0)
93 {
94 ALOGE("open socket failed: %d", device_fd);
95 return;
96 }
97
98 while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {
99 if (n <= 0 || n > UEVENT_MSG_LEN) {
100 ALOGE("Message length %d is not correct\n", n);
101 continue;
102 }
103 msg[n] = '\0';
104 msg[n+1] = '\0';
105 if (strstr(msg, "slate_com_dev")) {
106 while(*msg_ptr) {
107 if(!strncmp(msg_ptr, SLATE_EVENT, SLATE_EVENT_STRING_LEN)) {
108 msg_ptr += SLATE_EVENT_STRING_LEN;
109 ssr_event = (atoi(msg_ptr));
110 switch(ssr_event) {
111 case SLATE_AFTER_POWER_UP:
112 ALOGD("SLATE is powered up");
113 SendPatterns();
114 break;
115 }
116 }
117 while(*msg_ptr++);
118 }
119 }
120 }
121}
122
123/** Offload patterns
124 * The sequence of steps in offloading patterns.
125 * 1. Open the Glink channel to offload the patterns
126 * 2. Send the configuration/meta data to co-proc
127 * 3. Wait for the response from the co-proc
128 * 4. Send the pattern data to co-proc
129 * 5. Wait for the response
130 * 6. Exit
131 */
132void PatternOffload::SendPatterns()
133{
134 uint8_t *data;
135 uint32_t len;
136 int32_t rc;
137
138 rc = initChannel();
139 if (rc < 0)
140 return;
141
142 rc = get_pattern_config(&data, &len);
143 if (rc < 0 || !data)
144 return;
145
146 /* Send config data */
147 rc = sendData(data, len);
148 if (rc < 0)
149 return;
150
151 rc = get_pattern_data(&data, &len);
152 if (rc < 0)
153 return;
154
155 /* Send pattern data */
156 rc = sendData(data, len);
157 if (rc < 0)
158 ALOGE("pattern offloaded failed\n");
159 else
160 ALOGI("Patterns offloaded successfully\n");
161
162 free_pattern_mem(data);
163}
164
165int PatternOffload::sendData(uint8_t *data, int len)
166{
167 int rc, status = 0;
168
169 if (!data || !len)
170 return -EINVAL;
171
172 rc = GlinkCh.GlinkWrite(data, len);
173 if (rc < 0)
174 return rc;
175
176 rc = GlinkCh.GlinkPoll();
177 if (rc < 0)
178 return rc;
179
180 rc = GlinkCh.GlinkRead((uint8_t *)&status, 4);
181 if (rc < 0)
182 return rc;
183
184 if (status != OFFLOAD_SUCCESS)
185 return -EIO;
186
187 return 0;
188}
189
190
191int PatternOffload::initChannel()
192{
193 std::string chname = "/dev/glinkpkt_slate_haptics_offload";
194 int rc;
195
196 rc = GlinkCh.GlinkOpen(chname);
197 if (rc < 0)
198 {
199 ALOGE("Failed to open Glink channel name %s\n", chname.c_str());
200 return rc;
201 }
202
203 return 0;
204}
205
206#define GLINK_MAX_CONN_RETRIES 60
207int OffloadGlinkConnection::GlinkOpen(std::string& dev)
208{
209 int tries = GLINK_MAX_CONN_RETRIES;
210 dev_name = dev;
211
212 do {
213 fd = ::open(dev_name.c_str(), O_RDWR);
214 tries--;
215 if (fd < 0)
216 {
217 ALOGE("%s: %s: open error(%s)", __func__, dev.c_str(), strerror(errno));
218 sleep(1);
219 }
220 } while(-ETIMEDOUT == errno && tries > 0 );
221
222 return fd;
223}
224
225int OffloadGlinkConnection::GlinkClose()
226{
227 if (fd >= 0)
228 {
229 ::close(fd);
230 fd = -1;
231 }
232 return 0;
233}
234
235int OffloadGlinkConnection::GlinkPoll()
236{
237 ssize_t rc = 0;
238 struct pollfd poll_fd;
239
240 // wait for Rx data available in fd, for 2 seconds timeout
241 poll_fd.fd = fd;
242 poll_fd.events = POLLIN;
243
244 rc = ::poll(&poll_fd, 1, 2000);
245
246 if(rc > 0)
247 {
248 if (poll_fd.revents & POLLIN)
249 return 0;
250 } else if (rc == 0) {
251 ALOGE("Glink poll timeout");
252 } else {
253 ALOGE("Glink poll error: %s\n", strerror(errno));
254 }
255
256 return -1;
257}
258
259int OffloadGlinkConnection::GlinkRead(uint8_t *data, size_t size)
260{
261 int rc = 0;
262 size_t bytes_read = 0;
263
264 if (fd < 0)
265 return -1;
266
267 if (0 != GlinkPoll())
268 return -1;
269
270 while (bytes_read < size)
271 {
272 rc = ::read(fd, data+bytes_read, size-bytes_read);
273 if (rc < 0) {
274 if (errno != EAGAIN) {
275 ALOGE("%s: Read error: %s, rc %d", __func__,
276 strerror(errno), rc);
277 goto read_error;
278 }
279 } else if (rc == 0) {
280 ALOGE("%s: Zero length packet received or hardware connection went off",
281 __func__);
282 }
283 bytes_read += rc;
284 }
285 return 0;
286
287read_error:
288 return -1;
289}
290
291int OffloadGlinkConnection::GlinkWrite(uint8_t *buf, size_t buflen)
292{
293 size_t bytes_written_out = 0;
294 int rc = 0;
295
296 if (fd < 0)
297 return -1;
298
299 if (!buflen) {
300 ALOGE("%s: Invalid buffer len", __func__);
301 return 0;
302 }
303
304 while (bytes_written_out < buflen) {
305 rc = ::write (fd, buf+bytes_written_out, buflen-bytes_written_out);
306 if (rc < 0) {
307 ALOGE("%s: Write returned failure %d", __func__, rc);
308 return errno;
309 }
310 bytes_written_out += rc;
311 }
312 rc = 0;
313
314 return rc;
315}
316
317} // namespace vibrator
318} // namespace hardware
319} // namespace android
320} // namespace aidl