blob: 27ac2f2ada55b27a7b0defafad4d4e537737ac73 [file] [log] [blame]
Enrico Granata60b1cbc2019-05-20 11:06:46 -07001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Enrico Granata51cdb942019-06-18 16:40:17 -07005#include "mems_setup/configuration.h"
6
Harvey Yang34f464c2020-01-08 17:43:46 +08007#include <algorithm>
Enrico Granata064a25c2019-07-15 15:48:03 -07008#include <initializer_list>
Gwendal Grignouba911fe2019-12-08 17:14:53 -08009#include <string>
Enrico Granata60b1cbc2019-05-20 11:06:46 -070010#include <vector>
11
Qijiang Fan713061e2021-03-08 15:45:12 +090012#include <base/check.h>
Harvey Yang34f464c2020-01-08 17:43:46 +080013#include <base/files/file_enumerator.h>
Enrico Granata10e19de2019-05-21 14:17:36 -070014#include <base/files/file_util.h>
Harvey Yang34f464c2020-01-08 17:43:46 +080015#include <base/files/file_path.h>
Enrico Granata60b1cbc2019-05-20 11:06:46 -070016#include <base/logging.h>
Harvey Yang34f464c2020-01-08 17:43:46 +080017#include <base/process/launch.h>
18#include <base/stl_util.h>
Enrico Granata60b1cbc2019-05-20 11:06:46 -070019#include <base/strings/string_number_conversions.h>
Gwendal Grignouaee37402019-12-18 23:51:43 -080020#include <base/strings/string_split.h>
Enrico Granata60b1cbc2019-05-20 11:06:46 -070021#include <base/strings/stringprintf.h>
22
Harvey Yang34f464c2020-01-08 17:43:46 +080023#include <libmems/common_types.h>
Enrico Granata51cdb942019-06-18 16:40:17 -070024#include <libmems/iio_channel.h>
25#include <libmems/iio_context.h>
26#include <libmems/iio_device.h>
Harvey Yang34f464c2020-01-08 17:43:46 +080027#include <libmems/iio_device_impl.h>
28
Enrico Granata60b1cbc2019-05-20 11:06:46 -070029#include "mems_setup/sensor_location.h"
30
31namespace mems_setup {
32
33namespace {
34
Enrico Granata651d2572019-07-16 15:17:01 -070035struct ImuVpdCalibrationEntry {
36 std::string name;
37 std::string calib;
Gwendal Grignou4460a0d2020-01-06 14:07:00 -080038 base::Optional<int> max_value;
Enrico Granata651d2572019-07-16 15:17:01 -070039 base::Optional<int> value;
Enrico Granatafc7227d2019-07-26 13:51:19 -070040 bool missing_is_error;
Enrico Granata651d2572019-07-16 15:17:01 -070041};
42
43struct LightVpdCalibrationEntry {
44 std::string vpd_name;
45 std::string iio_name;
Enrico Granata60b1cbc2019-05-20 11:06:46 -070046};
47
Gwendal Grignouaee37402019-12-18 23:51:43 -080048struct LightColorCalibrationEntry {
49 std::string iio_name;
50 base::Optional<double> value;
51};
52
Harvey Yang1d50fff2020-10-27 12:24:38 +080053#if USE_IIOSERVICE
Harvey Yang34f464c2020-01-08 17:43:46 +080054constexpr char kIioServiceGroupName[] = "iioservice";
Harvey Yang1d50fff2020-10-27 12:24:38 +080055#else
Harvey Yang34f464c2020-01-08 17:43:46 +080056constexpr char kArcSensorGroupName[] = "arc-sensor";
Harvey Yang1d50fff2020-10-27 12:24:38 +080057#endif // USE_IIOSERVICE
Harvey Yang34f464c2020-01-08 17:43:46 +080058
Enrico Granata60b1cbc2019-05-20 11:06:46 -070059constexpr char kCalibrationBias[] = "bias";
Enrico Granatafc7227d2019-07-26 13:51:19 -070060constexpr char kCalibrationScale[] = "scale";
Gwendal Grignou1a663372020-01-24 09:36:49 -080061constexpr char kSysfsTriggerPrefix[] = "sysfstrig";
Enrico Granata60b1cbc2019-05-20 11:06:46 -070062
Enrico Granata7a622342019-05-21 11:10:59 -070063constexpr int kGyroMaxVpdCalibration = 16384; // 16dps
Gwendal Grignou4bf5ae62020-01-06 14:16:47 -080064constexpr int kAccelMaxVpdCalibration = 103; // .100g
Enrico Granata10e19de2019-05-21 14:17:36 -070065constexpr int kAccelSysfsTriggerId = 0;
Enrico Granata064a25c2019-07-15 15:48:03 -070066
Harvey Yang0c0dab52019-11-18 12:04:30 +080067constexpr int kSysfsTriggerId = -1;
68
Enrico Granata064a25c2019-07-15 15:48:03 -070069constexpr std::initializer_list<const char*> kAccelAxes = {
70 "x",
71 "y",
72 "z",
73};
Harvey Yang34f464c2020-01-08 17:43:46 +080074
75constexpr char kTriggerString[] = "trigger";
76
Harvey Yang1d50fff2020-10-27 12:24:38 +080077#if USE_IIOSERVICE
Harvey Yang34f464c2020-01-08 17:43:46 +080078constexpr char kDevString[] = "/dev/";
Harvey Yang1d50fff2020-10-27 12:24:38 +080079#endif // USE_IIOSERVICE
Harvey Yang34f464c2020-01-08 17:43:46 +080080
Harvey Yang68188d42021-01-22 10:47:12 +080081constexpr char kFilesToSetReadAndOwnership[][28] = {
82 "buffer/hwfifo_timeout", "buffer/hwfifo_watermark_max", "buffer/enable",
83 "buffer/length", "trigger/current_trigger"};
Harvey Yang2e5587f2020-09-29 00:12:35 +080084constexpr char kFilesToSetWriteAndOwnership[][24] = {"sampling_frequency",
85 "buffer/hwfifo_timeout",
86 "buffer/hwfifo_flush",
87 "buffer/enable",
88 "buffer/length",
89 "trigger/current_trigger",
90 "flush",
91 "frequency"};
Harvey Yang34f464c2020-01-08 17:43:46 +080092
93constexpr char kScanElementsString[] = "scan_elements";
94constexpr char kChnEnableFormatString[] = "in_%s_en";
95
Enrico Granata60b1cbc2019-05-20 11:06:46 -070096} // namespace
97
Harvey Yang34f464c2020-01-08 17:43:46 +080098// static
99const char* Configuration::GetGroupNameForSysfs() {
Harvey Yang1d50fff2020-10-27 12:24:38 +0800100#if USE_IIOSERVICE
101 return kIioServiceGroupName;
102#else
Harvey Yang34f464c2020-01-08 17:43:46 +0800103 return kArcSensorGroupName;
Harvey Yang1d50fff2020-10-27 12:24:38 +0800104#endif // USE_IIOSERVICE
Harvey Yang34f464c2020-01-08 17:43:46 +0800105}
106
Gwendal Grignouba911fe2019-12-08 17:14:53 -0800107Configuration::Configuration(libmems::IioContext* context,
108 libmems::IioDevice* sensor,
Enrico Granata51cdb942019-06-18 16:40:17 -0700109 Delegate* del)
Harvey Yang73394622020-02-12 10:57:57 +0800110 : delegate_(del), sensor_(sensor), context_(context) {
111 DCHECK(sensor_);
112
113 kind_ = mems_setup::SensorKindFromString(
114 sensor_->GetName() ? sensor_->GetName() : "");
115}
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700116
117bool Configuration::Configure() {
Harvey Yangee5a26d2021-03-23 17:19:27 +0800118 iioservice_gid_ = delegate_->FindGroupId(GetGroupNameForSysfs());
119 if (!iioservice_gid_.has_value()) {
120 LOG(ERROR) << "iioservice group not found";
121 return false;
122 }
123
124 if (!ConfigureOnKind())
125 return false;
126
Harvey Yang34f464c2020-01-08 17:43:46 +0800127 if (!SetupPermissions())
128 return false;
129
Harvey Yang1d50fff2020-10-27 12:24:38 +0800130#if USE_IIOSERVICE
131 // If the buffer is enabled, which means mems_setup has already been used on
132 // this sensor and iioservice is reading the samples from it, skip setting the
133 // frequency.
134 if (!sensor_->IsBufferEnabled())
135 sensor_->WriteDoubleAttribute(libmems::kSamplingFrequencyAttr, 0.0);
136#endif // USE_IIOSERVICE
137
Harvey Yang72b89f82020-12-02 16:23:01 +0800138 // Ignores the error as it may fail on kernel 4.4.
139 sensor_->WriteStringAttribute("current_timestamp_clock", "boottime");
140
Harvey Yangee5a26d2021-03-23 17:19:27 +0800141 return true;
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700142}
143
Enrico Granata651d2572019-07-16 15:17:01 -0700144bool Configuration::CopyLightCalibrationFromVpd() {
145 std::vector<LightVpdCalibrationEntry> calib_attributes = {
Harvey Yangfc9178f2020-03-16 14:26:53 +0800146 {"als_cal_intercept", "calibbias"},
147 {"als_cal_slope", "calibscale"},
Enrico Granata651d2572019-07-16 15:17:01 -0700148 };
149
150 for (auto& calib_attribute : calib_attributes) {
151 auto attrib_value = delegate_->ReadVpdValue(calib_attribute.vpd_name);
152 if (!attrib_value.has_value()) {
153 LOG(ERROR) << "VPD missing calibration value "
154 << calib_attribute.vpd_name;
155 continue;
156 }
157
158 double value;
159 if (!base::StringToDouble(attrib_value.value(), &value)) {
160 LOG(ERROR) << "VPD calibration value " << calib_attribute.vpd_name
161 << " has invalid value " << attrib_value.value();
162 continue;
163 }
Harvey Yangfc9178f2020-03-16 14:26:53 +0800164 auto chn = sensor_->GetChannel("illuminance");
165 if (!chn) {
166 LOG(ERROR) << "No channel illuminance";
167 return false;
168 }
169 LOG(INFO) << "iio: " << calib_attribute.iio_name;
170 if (!chn->WriteDoubleAttribute(calib_attribute.iio_name, value))
Enrico Granata651d2572019-07-16 15:17:01 -0700171 LOG(ERROR) << "failed to set calibration value "
172 << calib_attribute.iio_name;
173 }
174
Gwendal Grignouaee37402019-12-18 23:51:43 -0800175 /*
176 * RGB sensors may need per channel calibration.
177 */
178 std::vector<LightColorCalibrationEntry> calib_color_entries = {
Harvey Yangfc9178f2020-03-16 14:26:53 +0800179 {"illuminance_red", base::nullopt},
180 {"illuminance_green", base::nullopt},
181 {"illuminance_blue", base::nullopt},
Gwendal Grignouaee37402019-12-18 23:51:43 -0800182 };
183 auto attrib_value = delegate_->ReadVpdValue("als_cal_slope_color");
184
185 if (attrib_value.has_value()) {
186 /*
187 * Split the attributes in 3 doubles.
188 */
Tom Hughes09483d12020-08-27 15:55:08 -0700189 std::vector<std::string> attrs =
190 base::SplitString(attrib_value.value(), " ", base::TRIM_WHITESPACE,
191 base::SPLIT_WANT_NONEMPTY);
Gwendal Grignouaee37402019-12-18 23:51:43 -0800192
193 if (attrs.size() == 3) {
194 for (int i = 0; i < 3; i++) {
195 double value;
196 if (!base::StringToDouble(attrs[i], &value)) {
197 LOG(ERROR) << "VPD_entry " << i << " of als_cal_slope_color "
198 << "is not a float: " << attrs[i];
199 break;
200 }
201 calib_color_entries[i].value = value;
202 }
203
204 for (auto& color_entry : calib_color_entries) {
205 if (!color_entry.value) {
Tom Hughes09483d12020-08-27 15:55:08 -0700206 LOG(ERROR) << "No value set for " << color_entry.iio_name;
207 continue;
Gwendal Grignouaee37402019-12-18 23:51:43 -0800208 }
209 LOG(ERROR) << "writing " << *color_entry.value;
Harvey Yangfc9178f2020-03-16 14:26:53 +0800210 auto chn = sensor_->GetChannel(color_entry.iio_name);
211 if (!chn) {
212 LOG(ERROR) << "No channel " << color_entry.iio_name;
213 return false;
214 }
215 if (!chn->WriteDoubleAttribute("calibscale", *color_entry.value))
216 LOG(WARNING) << "failed to to set calibration value "
217 << color_entry.iio_name << " to " << *color_entry.value;
Gwendal Grignouaee37402019-12-18 23:51:43 -0800218 }
219 } else {
220 LOG(ERROR) << "VPD_entry als_cal_slope_color is malformed : "
221 << attrib_value.value();
222 }
223 }
Enrico Granata651d2572019-07-16 15:17:01 -0700224 return true;
225}
226
227bool Configuration::CopyImuCalibationFromVpd(int max_value) {
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700228 if (sensor_->IsSingleSensor()) {
229 auto location = sensor_->ReadStringAttribute("location");
230 if (!location || location->empty()) {
231 LOG(ERROR) << "cannot read a valid sensor location";
232 return false;
233 }
Enrico Granata651d2572019-07-16 15:17:01 -0700234 return CopyImuCalibationFromVpd(max_value, location->c_str());
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700235 } else {
Enrico Granata651d2572019-07-16 15:17:01 -0700236 bool base_config = CopyImuCalibationFromVpd(max_value, kBaseSensorLocation);
237 bool lid_config = CopyImuCalibationFromVpd(max_value, kLidSensorLocation);
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700238 return base_config && lid_config;
239 }
240}
241
Enrico Granata651d2572019-07-16 15:17:01 -0700242bool Configuration::CopyImuCalibationFromVpd(int max_value,
243 const std::string& location) {
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700244 const bool is_single_sensor = sensor_->IsSingleSensor();
245 std::string kind = SensorKindToString(kind_);
246
Enrico Granata651d2572019-07-16 15:17:01 -0700247 std::vector<ImuVpdCalibrationEntry> calib_attributes = {
Gwendal Grignou4460a0d2020-01-06 14:07:00 -0800248 {"x", kCalibrationBias, max_value, base::nullopt, true},
249 {"y", kCalibrationBias, max_value, base::nullopt, true},
250 {"z", kCalibrationBias, max_value, base::nullopt, true},
Enrico Granatafc7227d2019-07-26 13:51:19 -0700251
Gwendal Grignou4460a0d2020-01-06 14:07:00 -0800252 {"x", kCalibrationScale, base::nullopt, base::nullopt, false},
253 {"y", kCalibrationScale, base::nullopt, base::nullopt, false},
254 {"z", kCalibrationScale, base::nullopt, base::nullopt, false},
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700255 };
256
257 for (auto& calib_attribute : calib_attributes) {
258 auto attrib_name = base::StringPrintf(
Enrico Granata651d2572019-07-16 15:17:01 -0700259 "in_%s_%s_%s_calib%s", kind.c_str(), calib_attribute.name.c_str(),
260 location.c_str(), calib_attribute.calib.c_str());
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700261 auto attrib_value = delegate_->ReadVpdValue(attrib_name.c_str());
Harvey Yangfc9178f2020-03-16 14:26:53 +0800262 LOG(INFO) << attrib_name
263 << " attrib_value: " << attrib_value.value_or("nan");
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700264 if (!attrib_value.has_value()) {
Enrico Granatafc7227d2019-07-26 13:51:19 -0700265 if (calib_attribute.missing_is_error)
266 LOG(ERROR) << "VPD missing calibration value " << attrib_name;
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700267 continue;
268 }
269
270 int value;
271 if (!base::StringToInt(attrib_value.value(), &value)) {
272 LOG(ERROR) << "VPD calibration value " << attrib_name
273 << " has invalid value " << attrib_value.value();
Gwendal Grignou4460a0d2020-01-06 14:07:00 -0800274 // TODO(crbug/1039454: gwendal): Add uma stats.
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700275 continue;
276 }
Gwendal Grignou4460a0d2020-01-06 14:07:00 -0800277 if (calib_attribute.max_value && abs(value) > calib_attribute.max_value) {
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700278 LOG(ERROR) << "VPD calibration value " << attrib_name
279 << " has out-of-range value " << attrib_value.value();
Gwendal Grignou4460a0d2020-01-06 14:07:00 -0800280 // TODO(crbug/1039454: gwendal): Add uma stats.
281 return false;
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700282 } else {
Enrico Granata651d2572019-07-16 15:17:01 -0700283 calib_attribute.value = value;
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700284 }
285 }
286
287 for (const auto& calib_attribute : calib_attributes) {
Enrico Granata651d2572019-07-16 15:17:01 -0700288 if (!calib_attribute.value)
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700289 continue;
Harvey Yangfc9178f2020-03-16 14:26:53 +0800290 auto chn_id =
291 base::StringPrintf("%s_%s", kind.c_str(), calib_attribute.name.c_str());
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700292
293 if (!is_single_sensor)
Harvey Yangfc9178f2020-03-16 14:26:53 +0800294 chn_id = base::StringPrintf("%s_%s", chn_id.c_str(), location.c_str());
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700295
Harvey Yangfc9178f2020-03-16 14:26:53 +0800296 auto chn = sensor_->GetChannel(chn_id);
297 if (!chn) {
298 LOG(ERROR) << "No channel with id " << chn_id;
299 return false;
300 }
301 auto attrib_name =
302 base::StringPrintf("calib%s", calib_attribute.calib.c_str());
303 if (!chn->WriteNumberAttribute(attrib_name, *calib_attribute.value)) {
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700304 LOG(ERROR) << "failed to set calibration value " << attrib_name;
Harvey Yangfc9178f2020-03-16 14:26:53 +0800305 return false;
306 }
307 LOG(INFO) << attrib_name << ": "
308 << chn->ReadNumberAttribute(attrib_name).value_or(-88888);
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700309 }
310
311 LOG(INFO) << "VPD calibration complete";
312 return true;
313}
314
Gwendal Grignou1a663372020-01-24 09:36:49 -0800315bool Configuration::AddSysfsTrigger(int sysfs_trigger_id) {
Harvey Yang34f464c2020-01-08 17:43:46 +0800316 std::string dev_name =
317 libmems::IioDeviceImpl::GetStringFromId(sensor_->GetId());
318 // /sys/bus/iio/devices/iio:deviceX
Harvey Yang9fae3712020-10-29 22:45:03 +0800319 base::FilePath sys_dev_path = sensor_->GetPath();
Harvey Yang34f464c2020-01-08 17:43:46 +0800320
321 if (!delegate_->Exists(sys_dev_path.Append(kTriggerString))) {
322 // Uses FIFO and doesn't need a trigger.
323 return true;
324 }
325
Enrico Granata10e19de2019-05-21 14:17:36 -0700326 // There is a potential cross-process race here, where multiple instances
327 // of this tool may be trying to access the trigger at once. To solve this,
328 // first see if the trigger is already there. If not, try to create it, and
329 // then try to access it again. Only if the latter access fails then
330 // error out.
Tom Hughes09483d12020-08-27 15:55:08 -0700331 auto trigger_name =
332 base::StringPrintf("%s%d", kSysfsTriggerPrefix, sysfs_trigger_id);
Gwendal Grignou1a663372020-01-24 09:36:49 -0800333 auto triggers = context_->GetTriggersByName(trigger_name);
334
335 if (triggers.size() > 1) {
336 LOG(ERROR) << "Several triggers with the same name " << trigger_name
337 << " is not expected.";
338 return false;
339 }
340 if (triggers.size() == 0) {
341 LOG(INFO) << "trigger " << trigger_name << " not found; adding";
342
343 auto iio_sysfs_trigger = context_->GetTriggerById(kSysfsTriggerId);
344 if (iio_sysfs_trigger == nullptr) {
345 LOG(ERROR) << "cannot find iio_trig_sysfs kernel module";
346 return false;
347 }
348
349 if (!iio_sysfs_trigger->WriteNumberAttribute("add_trigger",
350 sysfs_trigger_id)) {
351 // It may happen if another instance of mems_setup is running in parallel.
352 LOG(WARNING) << "cannot instantiate trigger " << trigger_name;
Enrico Granata10e19de2019-05-21 14:17:36 -0700353 }
354
Gwendal Grignouba911fe2019-12-08 17:14:53 -0800355 context_->Reload();
Gwendal Grignou1a663372020-01-24 09:36:49 -0800356 triggers = context_->GetTriggersByName(trigger_name);
357 if (triggers.size() != 1) {
358 LOG(ERROR) << "Trigger " << trigger_name << " not been created properly";
Enrico Granata10e19de2019-05-21 14:17:36 -0700359 return false;
360 }
361 }
362
Gwendal Grignou1a663372020-01-24 09:36:49 -0800363 if (!sensor_->SetTrigger(triggers[0])) {
364 LOG(ERROR) << "cannot set sensor's trigger to " << trigger_name;
Enrico Granata10e19de2019-05-21 14:17:36 -0700365 return false;
366 }
367
Gwendal Grignou1a663372020-01-24 09:36:49 -0800368 base::FilePath trigger_now = triggers[0]->GetPath().Append("trigger_now");
Enrico Granata10e19de2019-05-21 14:17:36 -0700369
370 base::Optional<gid_t> chronos_gid = delegate_->FindGroupId("chronos");
371 if (!chronos_gid) {
372 LOG(ERROR) << "chronos group not found";
373 return false;
374 }
375
376 if (!delegate_->SetOwnership(trigger_now, -1, chronos_gid.value())) {
377 LOG(ERROR) << "cannot configure ownership on the trigger";
378 return false;
379 }
380
381 int permission = delegate_->GetPermissions(trigger_now);
382 permission |= base::FILE_PERMISSION_WRITE_BY_GROUP;
383 if (!delegate_->SetPermissions(trigger_now, permission)) {
384 LOG(ERROR) << "cannot configure permissions on the trigger";
385 return false;
386 }
387
388 LOG(INFO) << "sysfs trigger setup complete";
389 return true;
390}
391
Enrico Granata064a25c2019-07-15 15:48:03 -0700392bool Configuration::EnableAccelScanElements() {
393 auto timestamp = sensor_->GetChannel("timestamp");
394 if (!timestamp) {
395 LOG(ERROR) << "cannot find timestamp channel";
396 return false;
397 }
Harvey Yang1d50fff2020-10-27 12:24:38 +0800398 if (!timestamp->SetScanElementsEnabled(false)) {
Enrico Granata064a25c2019-07-15 15:48:03 -0700399 LOG(ERROR) << "failed to disable timestamp channel";
400 return false;
401 }
402
403 std::vector<std::string> channels_to_enable;
404
405 if (sensor_->IsSingleSensor()) {
406 for (const auto& axis : kAccelAxes) {
407 channels_to_enable.push_back(base::StringPrintf("accel_%s", axis));
408 }
409 } else {
410 for (const auto& axis : kAccelAxes) {
411 channels_to_enable.push_back(
412 base::StringPrintf("accel_%s_%s", axis, kBaseSensorLocation));
413 channels_to_enable.push_back(
414 base::StringPrintf("accel_%s_%s", axis, kLidSensorLocation));
415 }
416 }
417
418 for (const auto& chan_name : channels_to_enable) {
419 auto channel = sensor_->GetChannel(chan_name);
420 if (!channel) {
421 LOG(ERROR) << "cannot find channel " << chan_name;
422 return false;
423 }
Harvey Yang1d50fff2020-10-27 12:24:38 +0800424 if (!channel->SetScanElementsEnabled(true)) {
Enrico Granata064a25c2019-07-15 15:48:03 -0700425 LOG(ERROR) << "failed to enable channel " << chan_name;
426 return false;
427 }
428 }
429
430 sensor_->EnableBuffer(1);
431 if (!sensor_->IsBufferEnabled()) {
432 LOG(ERROR) << "failed to enable buffer";
433 return false;
434 }
435
436 LOG(INFO) << "buffer enabled";
437 return true;
438}
439
Gwendal Grignou7397fe72019-11-18 10:03:59 -0800440bool Configuration::EnableCalibration(bool enable) {
441 auto calibration = sensor_->GetChannel("calibration");
442 if (!calibration) {
443 LOG(ERROR) << "cannot find calibration channel";
444 return false;
445 }
Harvey Yang1d50fff2020-10-27 12:24:38 +0800446 return calibration->SetScanElementsEnabled(enable);
Gwendal Grignou7397fe72019-11-18 10:03:59 -0800447}
448
Enrico Granatafc2e3472019-07-16 11:23:25 -0700449bool Configuration::EnableKeyboardAngle() {
450 base::FilePath kb_wake_angle;
451 if (sensor_->IsSingleSensor()) {
452 kb_wake_angle = base::FilePath("/sys/class/chromeos/cros_ec/kb_wake_angle");
453 } else {
454 kb_wake_angle = sensor_->GetPath().Append("in_angl_offset");
455 }
456
457 if (!delegate_->Exists(kb_wake_angle)) {
458 LOG(INFO) << kb_wake_angle.value()
459 << " not found; will not enable EC wake angle";
460 return true;
461 }
462
463 base::Optional<gid_t> power_gid = delegate_->FindGroupId("power");
464 if (!power_gid) {
465 LOG(ERROR) << "cannot configure ownership on the wake angle file";
466 return false;
467 }
468
469 delegate_->SetOwnership(kb_wake_angle, -1, power_gid.value());
470 int permission = delegate_->GetPermissions(kb_wake_angle);
471 permission |= base::FILE_PERMISSION_WRITE_BY_GROUP;
472 delegate_->SetPermissions(kb_wake_angle, permission);
473
474 LOG(INFO) << "keyboard angle enabled";
475 return true;
476}
477
Harvey Yangee5a26d2021-03-23 17:19:27 +0800478bool Configuration::ConfigureOnKind() {
479 switch (kind_) {
480 case SensorKind::ACCELEROMETER:
481 return ConfigAccelerometer();
482 case SensorKind::GYROSCOPE:
483 return ConfigGyro();
484 case SensorKind::LIGHT:
485 return ConfigIlluminance();
486 case SensorKind::SYNC:
487 // No other configs needed.
488 return true;
489 case SensorKind::MAGNETOMETER:
490 // No other configs needed.
491 return true;
492 case SensorKind::LID_ANGLE:
493 // No other configs needed.
494 return true;
495 case SensorKind::BAROMETER:
496 // TODO(chenghaoyang): Setup calibrations for the barometer.
497 return true;
498 default:
499 CHECK(kind_ == SensorKind::OTHERS);
500 LOG(ERROR) << sensor_->GetName() << " unimplemented";
501 return false;
502 }
503}
504
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700505bool Configuration::ConfigGyro() {
Gwendal Grignou4460a0d2020-01-06 14:07:00 -0800506 CopyImuCalibationFromVpd(kGyroMaxVpdCalibration);
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700507
508 LOG(INFO) << "gyroscope configuration complete";
509 return true;
510}
511
Enrico Granata7a622342019-05-21 11:10:59 -0700512bool Configuration::ConfigAccelerometer() {
Gwendal Grignou4460a0d2020-01-06 14:07:00 -0800513 CopyImuCalibationFromVpd(kAccelMaxVpdCalibration);
Enrico Granata7a622342019-05-21 11:10:59 -0700514
Enrico Granata10e19de2019-05-21 14:17:36 -0700515 if (!AddSysfsTrigger(kAccelSysfsTriggerId))
516 return false;
517
Harvey Yangaa650ed2020-09-24 13:03:02 +0800518 if (!USE_IIOSERVICE && !EnableAccelScanElements())
Enrico Granata064a25c2019-07-15 15:48:03 -0700519 return false;
520
Enrico Granatafc2e3472019-07-16 11:23:25 -0700521 if (!EnableKeyboardAngle())
522 return false;
523
Gwendal Grignouba911fe2019-12-08 17:14:53 -0800524 /*
525 * Gather gyroscope. If one of them is on the same plane, set
526 * accelerometer range to 4g to meet Android 10 CCD Requirements
527 * (Sectiom 7.1.4, C.1.4).
528 * If no gyro found, set range to 4g on the lid accel.
529 */
530 int range = 0;
531 auto location = sensor_->ReadStringAttribute("location");
532 if (location && !location->empty()) {
533 auto gyros = context_->GetDevicesByName("cros-ec-gyro");
534 if (gyros.size() != 1 && strcmp(location->c_str(), kLidSensorLocation) == 0)
535 range = 4;
536 else if (gyros.size() == 1 &&
537 strcmp(location->c_str(),
538 gyros[0]->ReadStringAttribute("location")->c_str()) == 0)
539 range = 4;
540 else
541 range = 2;
542
Harvey Yang34f464c2020-01-08 17:43:46 +0800543 if (!sensor_->WriteNumberAttribute(kCalibrationScale, range))
544 return false;
Gwendal Grignouba911fe2019-12-08 17:14:53 -0800545 }
546
Enrico Granata7a622342019-05-21 11:10:59 -0700547 LOG(INFO) << "accelerometer configuration complete";
548 return true;
549}
550
Enrico Granata651d2572019-07-16 15:17:01 -0700551bool Configuration::ConfigIlluminance() {
Harvey Yang06ce00f2020-12-01 18:05:23 +0800552 if (USE_IIOSERVICE && strcmp(sensor_->GetName(), "acpi-als") == 0) {
Harvey Yangee5a26d2021-03-23 17:19:27 +0800553 std::string trigger_name =
554 base::StringPrintf(libmems::kHrtimerNameFormatString, sensor_->GetId());
555 if (context_->GetTriggersByName(trigger_name).empty()) {
Harvey Yang06ce00f2020-12-01 18:05:23 +0800556 base::FilePath hrtimer_path("/sys/kernel/config/iio/triggers/hrtimer");
Harvey Yangee5a26d2021-03-23 17:19:27 +0800557 hrtimer_path = hrtimer_path.Append(trigger_name);
Harvey Yang06ce00f2020-12-01 18:05:23 +0800558
559 if (!delegate_->Exists(hrtimer_path) &&
560 !delegate_->ProbeKernelModule("iio-trig-hrtimer")) {
561 LOG(ERROR) << "cannot load iio-trig-hrtimer module";
562 return false;
563 }
564
565 if (!delegate_->CreateDirectory(hrtimer_path)) {
566 LOG(ERROR) << "cannot mkdir " << hrtimer_path.value()
567 << " to create the hrtimer device";
568 return false;
569 }
570 }
571
572 context_->Reload();
Harvey Yangee5a26d2021-03-23 17:19:27 +0800573 auto triggers = context_->GetTriggersByName(trigger_name);
Harvey Yang06ce00f2020-12-01 18:05:23 +0800574 if (triggers.empty()) {
575 LOG(ERROR) << "cannot find acpi-als's trigger";
576 return false;
577 }
578
Harvey Yangee5a26d2021-03-23 17:19:27 +0800579 // Don't set |trigger| as |sensor_|'s trigger, or else the samples start
580 // flowing.
Harvey Yang06ce00f2020-12-01 18:05:23 +0800581 auto trigger = triggers.front();
582 // /sys/bus/iio/devices/triggerX
583 base::FilePath sys_trg_path =
584 trigger->GetPath().Append(libmems::kSamplingFrequencyAttr);
585 SetReadPermissionAndOwnership(sys_trg_path);
586 SetWritePermissionAndOwnership(sys_trg_path);
Harvey Yang06ce00f2020-12-01 18:05:23 +0800587 }
588
Enrico Granata651d2572019-07-16 15:17:01 -0700589 if (!CopyLightCalibrationFromVpd())
590 return false;
591
Gwendal Grignou7397fe72019-11-18 10:03:59 -0800592 // Disable calibration: it can fail if the light sensor does not support
593 // calibration mode.
594 EnableCalibration(false);
595
Enrico Granata651d2572019-07-16 15:17:01 -0700596 LOG(INFO) << "light configuration complete";
597 return true;
598}
599
Harvey Yang34f464c2020-01-08 17:43:46 +0800600bool Configuration::SetupPermissions() {
Harvey Yang34f464c2020-01-08 17:43:46 +0800601 std::vector<base::FilePath> files_to_set_read_own;
602 std::vector<base::FilePath> files_to_set_write_own;
603
604 std::string dev_name =
605 libmems::IioDeviceImpl::GetStringFromId(sensor_->GetId());
Harvey Yang1d50fff2020-10-27 12:24:38 +0800606#if USE_IIOSERVICE
607 // /dev/iio:deviceX
608 base::FilePath dev_path = base::FilePath(kDevString).Append(dev_name.c_str());
609 if (!delegate_->Exists(dev_path)) {
610 LOG(ERROR) << "Missing path: " << dev_path.value();
611 return false;
Harvey Yang34f464c2020-01-08 17:43:46 +0800612 }
613
Harvey Yang1d50fff2020-10-27 12:24:38 +0800614 files_to_set_read_own.push_back(dev_path);
615 files_to_set_write_own.push_back(dev_path);
616#endif // USE_IIOSERVICE
617
Harvey Yang34f464c2020-01-08 17:43:46 +0800618 // /sys/bus/iio/devices/iio:deviceX
Harvey Yang9fae3712020-10-29 22:45:03 +0800619 base::FilePath sys_dev_path = sensor_->GetPath();
Harvey Yang34f464c2020-01-08 17:43:46 +0800620
Harvey Yang34f464c2020-01-08 17:43:46 +0800621 // Files under /sys/bus/iio/devices/iio:deviceX/.
622 auto files = EnumerateAllFiles(sys_dev_path);
623 files_to_set_read_own.insert(files_to_set_read_own.end(), files.begin(),
624 files.end());
625 // Files under /sys/bus/iio/devices/iio:deviceX/scan_elements/.
626 files = EnumerateAllFiles(sys_dev_path.Append(kScanElementsString));
627 files_to_set_read_own.insert(files_to_set_read_own.end(), files.begin(),
628 files.end());
629
630 for (auto file : kFilesToSetReadAndOwnership)
631 files_to_set_read_own.push_back(sys_dev_path.Append(file));
632
Harvey Yang34f464c2020-01-08 17:43:46 +0800633 for (auto file : kFilesToSetWriteAndOwnership)
634 files_to_set_write_own.push_back(sys_dev_path.Append(file));
635
636 for (auto channel : sensor_->GetAllChannels()) {
637 files_to_set_write_own.push_back(
638 sys_dev_path.Append(kScanElementsString)
639 .Append(
640 base::StringPrintf(kChnEnableFormatString, channel->GetId())));
641 }
642
643 // Set permissions and ownerships.
644 bool result = true;
645
646 for (base::FilePath path : files_to_set_read_own)
647 result &= SetReadPermissionAndOwnership(path);
648
649 for (base::FilePath path : files_to_set_write_own)
650 result &= SetWritePermissionAndOwnership(path);
651
652 return result;
653}
654
655std::vector<base::FilePath> Configuration::EnumerateAllFiles(
656 base::FilePath file_path) {
657 std::vector<base::FilePath> files;
658
659 base::FileEnumerator file_enumerator(file_path, false,
660 base::FileEnumerator::FILES);
661
662 for (base::FilePath file = file_enumerator.Next(); !file.empty();
663 file = file_enumerator.Next())
664 files.push_back(file);
665
666 return files;
667}
668
669bool Configuration::SetReadPermissionAndOwnership(base::FilePath file_path) {
670 DCHECK(iioservice_gid_.has_value());
671
672 if (!delegate_->Exists(file_path))
673 return true;
674
675 bool result = true;
676
677 int permission = delegate_->GetPermissions(file_path);
678 permission |= base::FILE_PERMISSION_READ_BY_GROUP;
679
680 if (!delegate_->SetPermissions(file_path, permission)) {
681 LOG(ERROR) << "cannot configure permissions on " << file_path.value();
682 result = false;
683 }
684
685 if (!delegate_->SetOwnership(file_path, -1, iioservice_gid_.value())) {
686 LOG(ERROR) << "cannot configure ownership on " << file_path.value();
687 result = false;
688 }
689
690 return result;
691}
692
693bool Configuration::SetWritePermissionAndOwnership(base::FilePath file_path) {
694 DCHECK(iioservice_gid_.has_value());
695
696 if (!delegate_->Exists(file_path))
697 return true;
698
699 bool result = true;
700
701 int permission = delegate_->GetPermissions(file_path);
702 permission |= base::FILE_PERMISSION_WRITE_BY_GROUP;
703
704 if (!delegate_->SetPermissions(file_path, permission)) {
705 LOG(ERROR) << "cannot configure permissions on " << file_path.value();
706 result = false;
707 }
708
709 if (!delegate_->SetOwnership(file_path, -1, iioservice_gid_.value())) {
710 LOG(ERROR) << "cannot configure ownership on " << file_path.value();
711 result = false;
712 }
713
714 return result;
715}
716
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700717} // namespace mems_setup