1 #include <sys/syscall.h>
2 #include <sys/types.h>
3 #include <dirent.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <stdint.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <pthread.h>
10 #include <string.h>
11 #include <unistd.h>
12
13 #include "rmtfs.h"
14
15 #define RPROC_BASE_PATH "/sys/bus/platform/drivers/qcom-q6v5-mss/"
16 #define RPROC_CLASS_PATH "/sys/class/remoteproc/"
17
18 static pthread_t start_thread;
19 static pthread_t stop_thread;
20 static int rproc_state_fd;
21 static int rproc_pipe[2];
22
rproc_init_by_modalias(void)23 static int rproc_init_by_modalias(void)
24 {
25 struct dirent *rproc_de;
26 char modalias[256];
27 DIR *base_dir;
28 int modalias_fd;
29 int rproc_fd;
30 int state_fd = -1;
31 int base_fd;
32 int ret;
33
34 base_fd = open(RPROC_CLASS_PATH, O_RDONLY | O_DIRECTORY);
35 if (base_fd < 0)
36 return -1;
37
38 base_dir = fdopendir(base_fd);
39 if (!base_dir) {
40 fprintf(stderr, "failed to open remoteproc class path\n");
41 close(base_fd);
42 return -1;
43 }
44
45 while (state_fd < 0 && (rproc_de = readdir(base_dir)) != NULL) {
46 if (!strcmp(rproc_de->d_name, ".") ||
47 !strcmp(rproc_de->d_name, ".."))
48 continue;
49
50 rproc_fd = openat(base_fd, rproc_de->d_name, O_RDONLY | O_DIRECTORY);
51 if (rproc_fd < 0)
52 continue;
53
54 modalias_fd = openat(rproc_fd, "device/modalias", O_RDONLY);
55 if (modalias_fd < 0)
56 goto close_rproc_fd;
57
58 ret = read(modalias_fd, modalias, sizeof(modalias) - 1);
59 if (ret < 0)
60 goto close_modalias_fd;
61 modalias[ret] = '\0';
62
63 if (!strstr(modalias, "-mpss-pas") && !strstr(modalias, "-mss-pil"))
64 goto close_modalias_fd;
65
66 state_fd = openat(rproc_fd, "state", O_WRONLY);
67 if (state_fd < 0) {
68 fprintf(stderr,
69 "unable to open remoteproc \"state\" control file of %s\n",
70 rproc_de->d_name);
71 }
72
73 close_modalias_fd:
74 close(modalias_fd);
75 close_rproc_fd:
76 close(rproc_fd);
77 }
78 closedir(base_dir);
79 close(base_fd);
80
81 return state_fd;
82 }
83
rproc_init_by_mss_driver(void)84 static int rproc_init_by_mss_driver(void)
85 {
86 struct dirent *device_de;
87 struct dirent *rproc_de;
88 int rproc_base_fd;
89 DIR *rproc_dir;
90 DIR *base_dir;
91 int device_fd;
92 int rproc_fd;
93 int state_fd = -1;
94 int base_fd;
95
96 base_fd = open(RPROC_BASE_PATH, O_RDONLY | O_DIRECTORY);
97 if (base_fd < 0)
98 return -1;
99
100 base_dir = fdopendir(base_fd);
101 if (!base_dir) {
102 fprintf(stderr, "failed to open mss driver path\n");
103 close(base_fd);
104 return -1;
105 }
106
107 while (state_fd < 0 && (device_de = readdir(base_dir)) != NULL) {
108 if (!strcmp(device_de->d_name, ".") ||
109 !strcmp(device_de->d_name, ".."))
110 continue;
111
112 device_fd = openat(base_fd, device_de->d_name, O_RDONLY | O_DIRECTORY);
113 if (device_fd < 0)
114 continue;
115
116 rproc_base_fd = openat(device_fd, "remoteproc", O_RDONLY | O_DIRECTORY);
117 if (rproc_base_fd < 0) {
118 close(device_fd);
119 continue;
120 }
121
122 rproc_dir = fdopendir(rproc_base_fd);
123 while (state_fd < 0 && (rproc_de = readdir(rproc_dir)) != NULL) {
124 if (!strcmp(rproc_de->d_name, ".") ||
125 !strcmp(rproc_de->d_name, ".."))
126 continue;
127
128 rproc_fd = openat(rproc_base_fd, rproc_de->d_name, O_RDONLY | O_DIRECTORY);
129 if (rproc_fd < 0)
130 continue;
131
132 state_fd = openat(rproc_fd, "state", O_WRONLY);
133 if (state_fd < 0) {
134 fprintf(stderr,
135 "unable to open remoteproc \"state\" control file of %s\n",
136 device_de->d_name);
137 }
138
139 close(rproc_fd);
140
141 }
142 closedir(rproc_dir);
143 close(rproc_base_fd);
144 close(device_fd);
145 }
146 closedir(base_dir);
147 close(base_fd);
148
149 return state_fd;
150 }
151
rproc_init(void)152 int rproc_init(void)
153 {
154 int state_fd;
155 int ret;
156
157 state_fd = rproc_init_by_modalias();
158 if (state_fd < 0) {
159 state_fd = rproc_init_by_mss_driver();
160 if (state_fd < 0)
161 return -1;
162 }
163
164 ret = pipe(rproc_pipe);
165 if (ret < 0) {
166 close(state_fd);
167 return -1;
168 }
169
170 rproc_state_fd = state_fd;
171
172 return rproc_pipe[0];
173 }
174
do_rproc_start(void * unused __unused)175 static void *do_rproc_start(void *unused __unused)
176 {
177 ssize_t ret;
178
179 ret = pwrite(rproc_state_fd, "start", 5, 0);
180 if (ret < 4) {
181 fprintf(stderr, "failed to update start state: %s\n",
182 strerror(errno));
183 }
184
185 return NULL;
186 }
187
rproc_start()188 int rproc_start()
189 {
190 pthread_attr_t attr;
191
192 pthread_attr_init(&attr);
193 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
194
195 return pthread_create(&start_thread, &attr, do_rproc_start, NULL);
196 }
197
do_rproc_stop(void * unused __unused)198 static void *do_rproc_stop(void *unused __unused)
199 {
200 ssize_t ret;
201
202 ret = pwrite(rproc_state_fd, "stop", 4, 0);
203 if (ret < 4) {
204 fprintf(stderr, "failed to update stop state: %s\n",
205 strerror(errno));
206 }
207
208 ret = write(rproc_pipe[1], "Y", 1);
209 if (ret != 1) {
210 fprintf(stderr, "failed to signal event loop about exit\n");
211 exit(0);
212 }
213
214 return NULL;
215 }
216
rproc_stop(void)217 int rproc_stop(void)
218 {
219 pthread_attr_t attr;
220
221 pthread_attr_init(&attr);
222 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
223
224 return pthread_create(&stop_thread, &attr, do_rproc_stop, NULL);
225 }
226