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