/
usb_moded-modules.c
276 lines (223 loc) · 7.51 KB
1
/**
2
3
4
* @file usb_moded-modules.c
*
* Copyright (C) 2010 Nokia Corporation. All rights reserved.
5
* Copyright (C) 2012-2019 Jolla. All rights reserved.
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
*
* @author: Philippe De Swert <philippe.de-swert@nokia.com>
* @author: Philippe De Swert <phdeswer@lumi.maa>
* @author: Philippe De Swert <philippedeswert@gmail.com>
* @author: Philippe De Swert <philippe.deswert@jollamobile.com>
* @author: Thomas Perl <m@thp.io>
* @author: Slava Monich <slava.monich@jolla.com>
* @author: Simo Piiroinen <simo.piiroinen@jollamobile.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the Lesser GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
29
30
31
32
33
#include "usb_moded-modules.h"
#include "usb_moded-log.h"
34
35
36
#include <stdlib.h>
#include <string.h>
37
38
#include <libkmod.h>
39
#include <glib.h>
40
41
42
43
44
/* ========================================================================= *
* Prototypes
* ========================================================================= */
45
46
47
/* ------------------------------------------------------------------------- *
* MODULES
* ------------------------------------------------------------------------- */
48
49
50
51
52
53
54
55
static bool modules_have_module (const char *module);
bool modules_in_use (void);
static bool modules_probe (void);
bool modules_init (void);
void modules_quit (void);
int modules_load_module (const char *module);
int modules_unload_module(const char *module);
56
57
58
59
60
/* ========================================================================= *
* Data
* ========================================================================= */
61
62
63
64
65
66
67
68
/** Availability of kernel module based gadget configuration functionality
*
* -1 = not checked yet
* 0 = not available
* 1 = chosen as means of gadget configuration for usb-moded
*/
static int modules_probed = -1;
69
70
/* kmod context - initialized at start in usbmoded_init by ctx_init()
* and cleaned up by ctx_cleanup() functions */
71
static struct kmod_ctx *modules_ctx = 0;
72
73
74
75
76
77
78
/* ========================================================================= *
* Functions
* ========================================================================= */
static bool modules_have_module(const char *module)
{
79
80
LOG_REGISTER_CONTEXT;
81
82
83
84
85
// TODO: not fully untested due to lack of suitable hw
bool ack = false;
struct kmod_list *list = 0;
86
if( kmod_module_new_from_lookup(modules_ctx, module, &list) < 0 )
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
goto EXIT;
if( list == 0 )
goto EXIT;
ack = true;
EXIT:
if( list )
kmod_module_unref_list(list);
log_debug("module %s does%s exist", module, ack ? "" : "not ");
return ack;
}
bool modules_in_use(void)
{
105
106
LOG_REGISTER_CONTEXT;
107
108
109
110
111
112
113
114
if( modules_probed < 0 )
log_debug("modules_in_use() called before modules_probe()");
return modules_probed > 0;
}
static bool modules_probe(void)
{
115
116
LOG_REGISTER_CONTEXT;
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
static const char * const lut[] = {
MODULE_MASS_STORAGE,
MODULE_FILE_STORAGE,
MODULE_DEVELOPER,
MODULE_MTP,
0
};
if( modules_probed == -1 ) {
modules_probed = false;
/* Check if we have at least one of the kernel modules we
* expect to use for something.
*/
for( size_t i = 0; lut[i] ; ++i ) {
if( modules_have_module(lut[i]) ) {
modules_probed = true;
break;
}
}
log_warning("MODULES %sdetected", modules_probed ? "" : "not ");
}
return modules_in_use();
}
142
143
144
145
/** kmod module init
*
* @return true if modules backend is ready for use, false otherwise
*/
146
bool modules_init(void)
147
{
148
149
LOG_REGISTER_CONTEXT;
150
151
bool ack = false;
152
153
if( !modules_ctx ) {
if( !(modules_ctx = kmod_new(NULL, NULL)) )
154
155
156
goto EXIT;
}
157
if( kmod_load_resources(modules_ctx) < 0 )
158
159
160
161
162
163
164
165
goto EXIT;
if( !modules_probe() )
goto EXIT;
ack = true;
EXIT:
return ack;
166
167
168
}
/* kmod module cleanup */
169
void modules_quit(void)
170
{
171
172
LOG_REGISTER_CONTEXT;
173
174
if( modules_ctx )
kmod_unref(modules_ctx), modules_ctx = 0;
175
176
}
177
/** load module
178
179
180
181
182
*
* @param module Name of the module to load
* @return 0 on success, non-zero on failure
*
*/
183
int modules_load_module(const char *module)
184
{
185
186
LOG_REGISTER_CONTEXT;
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
int ret = 0;
const int probe_flags = KMOD_PROBE_APPLY_BLACKLIST;
struct kmod_module *mod;
char *charging_args = NULL;
char *load = NULL;
if(!strcmp(module, MODULE_NONE))
return 0;
if( !modules_in_use() ) {
log_warning("load module %s - without module support", module);
return -1;
}
/* copy module to load as it might be modified if we're trying charging mode */
load = strdup(module);
if(!strcmp(module, MODULE_CHARGING) || !strcmp(module, MODULE_CHARGE_FALLBACK))
{
/* split the string in module name and argument, they are the same for MODULE_CHARGE_FALLBACK
207
* so no need to handle them separately */
208
209
210
gchar **strings;
/* since the mass_storage module is the newer one and we check against it to avoid
211
212
* loading failures we use it here, as we fall back to g_file_storage if g_mass_storage
* fails to load */
213
214
215
216
217
218
219
220
221
strings = g_strsplit(MODULE_CHARGE_FALLBACK, " ", 2);
//log_debug("module args = %s, module = %s\n", strings[1], strings[0]);
charging_args = strdup(strings[1]);
/* load was already assigned. Free it to re-assign */
free(load);
load = strdup(strings[0]);
g_strfreev(strings);
}
222
ret = kmod_module_new_from_name(modules_ctx, load, &mod);
223
/* since kmod_module_new_from_name does not check if the module
224
* exists we test it's path in case we deal with the mass-storage one */
225
226
227
228
if(!strcmp(module, MODULE_MASS_STORAGE) &&
(kmod_module_get_path(mod) == NULL))
{
log_debug("Fallback on older g_file_storage\n");
229
ret = kmod_module_new_from_name(modules_ctx, MODULE_FILE_STORAGE, &mod);
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
}
if(!charging_args)
ret = kmod_module_probe_insert_module(mod, probe_flags, NULL, NULL, NULL, NULL);
else
{
ret = kmod_module_probe_insert_module(mod, probe_flags, charging_args, NULL, NULL, NULL);
free(charging_args);
}
kmod_module_unref(mod);
free(load);
if( ret == 0)
log_info("Module %s loaded successfully\n", module);
else
log_info("Module %s failed to load\n", module);
246
return ret;
247
248
249
}
/** unload module
250
*
251
252
253
254
* @param module Name of the module to unload
* @return 0 on success, non-zero on failure
*
*/
255
int modules_unload_module(const char *module)
256
{
257
258
LOG_REGISTER_CONTEXT;
259
int ret = 0;
260
261
struct kmod_module *mod;
262
263
264
if(!strcmp(module, MODULE_NONE))
return 0;
265
266
267
268
269
if( !modules_in_use() ) {
log_warning("unload module %s - without module support", module);
return -1;
}
270
271
kmod_module_new_from_name(modules_ctx, module, &mod);
272
273
274
ret = kmod_module_remove_module(mod, KMOD_REMOVE_NOWAIT);
kmod_module_unref(mod);
275
return ret;
276
}