blob: 7145bbbf42742e8134d196d380d1a25eef4e49e0 [file] [log] [blame]
Gilad Arnold1ebd8132012-03-05 10:19:29 -08001// Copyright (c) 2012 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
5#include "gpio_handler.h"
6
Gilad Arnold4d740eb2012-05-15 08:48:13 -07007#include <base/memory/scoped_ptr.h>
Gilad Arnold1ebd8132012-03-05 10:19:29 -08008#include <base/string_util.h>
Gilad Arnold4d740eb2012-05-15 08:48:13 -07009#include <base/stringprintf.h>
Gilad Arnold1ebd8132012-03-05 10:19:29 -080010
Gilad Arnold4d740eb2012-05-15 08:48:13 -070011#include "update_engine/file_descriptor.h"
Gilad Arnold1ebd8132012-03-05 10:19:29 -080012
Gilad Arnold4d740eb2012-05-15 08:48:13 -070013using base::Time;
14using base::TimeDelta;
Gilad Arnold1ebd8132012-03-05 10:19:29 -080015using std::string;
16
Gilad Arnold4d740eb2012-05-15 08:48:13 -070017using namespace chromeos_update_engine;
18
Gilad Arnold1ebd8132012-03-05 10:19:29 -080019namespace chromeos_update_engine {
20
Gilad Arnold4d740eb2012-05-15 08:48:13 -070021const char* StandardGpioHandler::gpio_dirs_[kGpioDirMax] = {
22 "in", // kGpioDirIn
23 "out", // kGpioDirOut
Gilad Arnold1ebd8132012-03-05 10:19:29 -080024};
25
Gilad Arnold4d740eb2012-05-15 08:48:13 -070026const char* StandardGpioHandler::gpio_vals_[kGpioValMax] = {
27 "1", // kGpioValUp
28 "0", // kGpioValDown
Gilad Arnold1ebd8132012-03-05 10:19:29 -080029};
Gilad Arnold1ebd8132012-03-05 10:19:29 -080030
Gilad Arnold4d740eb2012-05-15 08:48:13 -070031const StandardGpioHandler::GpioDef
32StandardGpioHandler::gpio_defs_[kGpioIdMax] = {
Gilad Arnold6eccc532012-05-17 15:44:22 -070033 { "dutflaga", "ID_GPIO_DUTFLAGA" }, // kGpioIdDutflaga
34 { "dutflagb", "ID_GPIO_DUTFLAGB" }, // kGpioIdDutflagb
Gilad Arnold4d740eb2012-05-15 08:48:13 -070035};
36
37unsigned StandardGpioHandler::num_instances_ = 0;
38
39
40StandardGpioHandler::StandardGpioHandler(UdevInterface* udev_iface,
Gilad Arnold6eccc532012-05-17 15:44:22 -070041 FileDescriptor* fd,
42 bool is_defer_discovery,
43 bool is_cache_test_mode)
Gilad Arnold4d740eb2012-05-15 08:48:13 -070044 : udev_iface_(udev_iface),
Gilad Arnold6eccc532012-05-17 15:44:22 -070045 fd_(fd),
46 is_cache_test_mode_(is_cache_test_mode),
Gilad Arnold4d740eb2012-05-15 08:48:13 -070047 is_discovery_attempted_(false) {
Gilad Arnold6eccc532012-05-17 15:44:22 -070048 CHECK(udev_iface && fd);
Gilad Arnold4d740eb2012-05-15 08:48:13 -070049
50 // Ensure there's only one instance of this class.
51 CHECK_EQ(num_instances_, static_cast<unsigned>(0));
52 num_instances_++;
53
Gilad Arnold6eccc532012-05-17 15:44:22 -070054 // Reset test signal flags.
55 ResetTestModeSignalingFlags();
56
Gilad Arnold4d740eb2012-05-15 08:48:13 -070057 // If GPIO discovery not deferred, do it.
58 if (!(is_defer_discovery || DiscoverGpios())) {
59 LOG(WARNING) << "GPIO discovery failed";
60 }
61}
62
63StandardGpioHandler::~StandardGpioHandler() {
64 num_instances_--;
65}
66
Gilad Arnold4d740eb2012-05-15 08:48:13 -070067bool StandardGpioHandler::IsTestModeSignaled() {
68 // Attempt GPIO discovery.
69 if (!DiscoverGpios()) {
70 LOG(WARNING) << "GPIO discovery failed";
71 }
72
Gilad Arnold6eccc532012-05-17 15:44:22 -070073 // Force a check if so requested.
74 if (!is_cache_test_mode_)
75 ResetTestModeSignalingFlags();
76
77 bool is_returning_cached = !is_first_check_; // for logging purposes
78 if (is_first_check_) {
79 is_first_check_ = false;
80 DoTestModeSignalingProtocol();
81 }
82
83 LOG(INFO) << "result: " << (is_test_mode_ ? "test" : "normal") << " mode"
84 << (is_returning_cached ? " (cached)" : "")
85 << (is_handshake_completed_ ? "" : " (default)");
86 return is_test_mode_;
Gilad Arnold4d740eb2012-05-15 08:48:13 -070087}
88
Gilad Arnold6eccc532012-05-17 15:44:22 -070089
Gilad Arnold4d740eb2012-05-15 08:48:13 -070090bool StandardGpioHandler::GpioChipUdevEnumHelper::SetupEnumFilters(
91 udev_enumerate* udev_enum) {
92 CHECK(udev_enum);
93
94 return !(gpio_handler_->udev_iface_->EnumerateAddMatchSubsystem(
95 udev_enum, "gpio") ||
96 gpio_handler_->udev_iface_->EnumerateAddMatchSysname(
97 udev_enum, "gpiochip*"));
98}
99
100bool StandardGpioHandler::GpioChipUdevEnumHelper::ProcessDev(udev_device* dev) {
101 CHECK(dev);
102
103 // Ensure we did not encounter more than one chip.
104 if (num_gpio_chips_++) {
105 LOG(ERROR) << "enumerated multiple GPIO chips";
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800106 return false;
107 }
108
Gilad Arnold4d740eb2012-05-15 08:48:13 -0700109 // Obtain GPIO descriptors.
110 for (int id = 0; id < kGpioIdMax; id++) {
111 const GpioDef* gpio_def = &gpio_defs_[id];
112 const char* descriptor =
113 gpio_handler_->udev_iface_->DeviceGetPropertyValue(
114 dev, gpio_def->udev_property);
115 if (!descriptor) {
116 LOG(ERROR) << "could not obtain " << gpio_def->name
117 << " descriptor using property " << gpio_def->udev_property;
118 return false;
119 }
120 gpio_handler_->gpios_[id].descriptor = descriptor;
121 }
122
123 return true;
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800124}
125
Gilad Arnold4d740eb2012-05-15 08:48:13 -0700126bool StandardGpioHandler::GpioChipUdevEnumHelper::Finalize() {
127 if (num_gpio_chips_ != 1) {
128 LOG(ERROR) << "could not enumerate a GPIO chip";
129 return false;
130 }
131 return true;
132}
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800133
Gilad Arnold4d740eb2012-05-15 08:48:13 -0700134bool StandardGpioHandler::GpioUdevEnumHelper::SetupEnumFilters(
135 udev_enumerate* udev_enum) {
136 CHECK(udev_enum);
137 const string gpio_pattern =
138 string("*").append(gpio_handler_->gpios_[id_].descriptor);
139 return !(
140 gpio_handler_->udev_iface_->EnumerateAddMatchSubsystem(
141 udev_enum, "gpio") ||
142 gpio_handler_->udev_iface_->EnumerateAddMatchSysname(
143 udev_enum, gpio_pattern.c_str()));
144}
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800145
Gilad Arnold4d740eb2012-05-15 08:48:13 -0700146bool StandardGpioHandler::GpioUdevEnumHelper::ProcessDev(udev_device* dev) {
147 CHECK(dev);
148
149 // Ensure we did not encounter more than one GPIO device.
150 if (num_gpios_++) {
151 LOG(ERROR) << "enumerated multiple GPIO devices for a given descriptor";
152 return false;
153 }
154
155 // Obtain GPIO device sysfs path.
156 const char* dev_path = gpio_handler_->udev_iface_->DeviceGetSyspath(dev);
157 if (!dev_path) {
158 LOG(ERROR) << "failed to obtain device syspath for GPIO "
159 << gpio_defs_[id_].name;
160 return false;
161 }
162 gpio_handler_->gpios_[id_].dev_path = dev_path;
163
164 LOG(INFO) << "obtained device syspath: " << gpio_defs_[id_].name << " -> "
165 << gpio_handler_->gpios_[id_].dev_path;
166 return true;
167}
168
169bool StandardGpioHandler::GpioUdevEnumHelper::Finalize() {
170 if (num_gpios_ != 1) {
171 LOG(ERROR) << "could not enumerate GPIO device " << gpio_defs_[id_].name;
172 return false;
173 }
174 return true;
175}
176
Gilad Arnold6eccc532012-05-17 15:44:22 -0700177StandardGpioHandler::GpioDirResetter::GpioDirResetter(
178 StandardGpioHandler* handler, GpioId id, GpioDir dir) :
179 do_reset_(false), handler_(handler), id_(id), dir_(dir) {
180 CHECK(handler);
181 CHECK_GE(id, 0);
182 CHECK_LT(id, kGpioIdMax);
183 CHECK_GE(dir, 0);
184 CHECK_LT(dir, kGpioDirMax);
185}
186
187StandardGpioHandler::GpioDirResetter::~GpioDirResetter() {
188 if (do_reset_ && !handler_->SetGpioDirection(id_, dir_)) {
189 LOG(WARNING) << "failed to reset direction of " << gpio_defs_[id_].name
190 << " to " << gpio_dirs_[dir_];
191 }
192}
193
Gilad Arnold4d740eb2012-05-15 08:48:13 -0700194
195bool StandardGpioHandler::InitUdevEnum(struct udev* udev,
196 UdevEnumHelper* enum_helper) {
197 // Obtain a udev enumerate object.
198 struct udev_enumerate* udev_enum;
199 if (!(udev_enum = udev_iface_->EnumerateNew(udev))) {
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800200 LOG(ERROR) << "failed to obtain udev enumerate context";
201 return false;
202 }
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800203
Gilad Arnold4d740eb2012-05-15 08:48:13 -0700204 // Assign enumerate object to closer.
205 scoped_ptr<UdevInterface::UdevEnumerateCloser>
206 udev_enum_closer(udev_iface_->NewUdevEnumerateCloser(&udev_enum));
207
208 // Setup enumeration filters.
209 if (!enum_helper->SetupEnumFilters(udev_enum)) {
210 LOG(ERROR) << "failed to setup udev enumerate filters";
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800211 return false;
212 }
213
Gilad Arnold4d740eb2012-05-15 08:48:13 -0700214 // Scan for matching devices.
215 if (udev_iface_->EnumerateScanDevices(udev_enum)) {
216 LOG(ERROR) << "udev enumerate scan failed";
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800217 return false;
218 }
219
Gilad Arnold4d740eb2012-05-15 08:48:13 -0700220 // Iterate over matching devices.
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800221 struct udev_list_entry* list_entry;
Gilad Arnold4d740eb2012-05-15 08:48:13 -0700222 for (list_entry = udev_iface_->EnumerateGetListEntry(udev_enum);
223 list_entry; list_entry = udev_iface_->ListEntryGetNext(list_entry)) {
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800224 // Obtain device name.
Gilad Arnold4d740eb2012-05-15 08:48:13 -0700225 const char* dev_path = udev_iface_->ListEntryGetName(list_entry);
226 if (!dev_path) {
227 LOG(ERROR) << "enumerated device has a null name string";
228 return false;
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800229 }
230
231 // Obtain device object.
Gilad Arnold4d740eb2012-05-15 08:48:13 -0700232 struct udev_device* dev = udev_iface_->DeviceNewFromSyspath(udev, dev_path);
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800233 if (!dev) {
Gilad Arnold4d740eb2012-05-15 08:48:13 -0700234 LOG(ERROR) << "obtained a null device object for enumerated device";
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800235 return false;
236 }
Gilad Arnold4d740eb2012-05-15 08:48:13 -0700237 scoped_ptr<UdevInterface::UdevDeviceCloser>
238 dev_closer(udev_iface_->NewUdevDeviceCloser(&dev));
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800239
Gilad Arnold4d740eb2012-05-15 08:48:13 -0700240 if (!enum_helper->ProcessDev(dev))
241 return false;
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800242 }
243
Gilad Arnold4d740eb2012-05-15 08:48:13 -0700244 // Make sure postconditions were met.
245 return enum_helper->Finalize();
246}
247
Gilad Arnold6eccc532012-05-17 15:44:22 -0700248void StandardGpioHandler::ResetTestModeSignalingFlags() {
249 is_first_check_ = true;
250 is_handshake_completed_ = false;
251 is_test_mode_ = false;
252}
253
Gilad Arnold4d740eb2012-05-15 08:48:13 -0700254bool StandardGpioHandler::DiscoverGpios() {
255 if (is_discovery_attempted_)
256 return true;
257
258 is_discovery_attempted_ = true;
259
260 // Obtain libudev instance and attach to a dedicated closer.
261 struct udev* udev;
262 if (!(udev = udev_iface_->New())) {
263 LOG(ERROR) << "failed to obtain libudev instance";
264 return false;
265 }
266 scoped_ptr<UdevInterface::UdevCloser>
267 udev_closer(udev_iface_->NewUdevCloser(&udev));
268
269 // Enumerate GPIO chips, scanning for GPIO descriptors.
270 GpioChipUdevEnumHelper chip_enum_helper(this);
271 if (!InitUdevEnum(udev, &chip_enum_helper)) {
272 LOG(ERROR) << "enumeration error, aborting GPIO discovery";
273 return false;
274 }
275
276 // Obtain device names for all discovered GPIOs, reusing the udev instance.
277 for (int id = 0; id < kGpioIdMax; id++) {
278 GpioUdevEnumHelper gpio_enum_helper(this, static_cast<GpioId>(id));
279 if (!InitUdevEnum(udev, &gpio_enum_helper)) {
280 LOG(ERROR) << "enumeration error, aborting GPIO discovery";
281 return false;
282 }
283 }
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800284
285 return true;
286}
287
Gilad Arnold4d740eb2012-05-15 08:48:13 -0700288bool StandardGpioHandler::GetGpioDevName(StandardGpioHandler::GpioId id,
289 string* dev_path_p) {
290 CHECK(id >= 0 && id < kGpioIdMax && dev_path_p);
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800291
Gilad Arnold4d740eb2012-05-15 08:48:13 -0700292 *dev_path_p = gpios_[id].dev_path;
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800293 return true;
294}
295
Gilad Arnold6eccc532012-05-17 15:44:22 -0700296bool StandardGpioHandler::OpenGpioFd(StandardGpioHandler::GpioId id,
297 const char* dev_name,
298 bool is_write) {
299 CHECK(id >= 0 && id < kGpioIdMax && dev_name);
300 string file_name = StringPrintf("%s/%s", gpios_[id].dev_path.c_str(),
301 dev_name);
302 if (!fd_->Open(file_name.c_str(), (is_write ? O_WRONLY : O_RDONLY))) {
303 const string err_str = StringPrintf("failed to open %s (%s) for %s",
304 file_name.c_str(), gpio_defs_[id].name,
305 (is_write ? "writing" : "reading"));
306 if (fd_->IsSettingErrno()) {
307 PLOG(ERROR) << err_str;
308 } else {
309 LOG(ERROR) << err_str;
310 }
311 return false;
312 }
313 return true;
314}
315
316bool StandardGpioHandler::SetGpio(StandardGpioHandler::GpioId id,
317 const char* dev_name, const char* entries[],
318 const int num_entries, int index) {
319 CHECK_GE(id, 0);
320 CHECK_LT(id, kGpioIdMax);
321 CHECK(dev_name);
322 CHECK(entries);
323 CHECK_GT(num_entries, 0);
324 CHECK_GE(index, 0);
325 CHECK_LT(index, num_entries);
326
327 // Open device for writing.
328 if (!OpenGpioFd(id, dev_name, true))
329 return false;
330 ScopedFileDescriptorCloser dev_fd_closer(fd_);
331
332 // Write a string corresponding to the requested output index to the GPIO
333 // device, appending a newline.
334 string output_str = entries[index];
335 output_str += '\n';
336 ssize_t write_len = fd_->Write(output_str.c_str(), output_str.length());
337 if (write_len != static_cast<ssize_t>(output_str.length())) {
338 if (write_len < 0) {
339 const string err_str = "failed to write to GPIO";
340 if (fd_->IsSettingErrno()) {
341 PLOG(ERROR) << err_str;
342 } else {
343 LOG(ERROR) << err_str;
344 }
345 } else {
346 LOG(ERROR) << "wrong number of bytes written (" << write_len
347 << " instead of " << output_str.length() << ")";
348 }
349 return false;
350 }
351
352 // Close the device explicitly, returning the close result.
353 return fd_->Close();
354}
355
356bool StandardGpioHandler::GetGpio(StandardGpioHandler::GpioId id,
357 const char* dev_name, const char* entries[],
358 const int num_entries, int* index_p) {
359 CHECK_GE(id, 0);
360 CHECK_LT(id, kGpioIdMax);
361 CHECK(dev_name);
362 CHECK(entries);
363 CHECK_GT(num_entries, 0);
364 CHECK(index_p);
365
366 // Open device for reading.
367 if (!OpenGpioFd(id, dev_name, false))
368 return false;
369 ScopedFileDescriptorCloser dev_fd_closer(fd_);
370
371 // Read the GPIO device. We attempt to read more than the max number of
372 // characters expected followed by a newline, to ensure that we've indeed read
373 // all the data available on the device.
374 size_t max_entry_len = 0;
375 for (int i = 0; i < num_entries; i++) {
376 size_t entry_len = strlen(entries[i]);
377 if (entry_len > max_entry_len)
378 max_entry_len = entry_len;
379 }
380 max_entry_len++; // account for trailing newline
381 size_t buf_len = max_entry_len + 1; // room for excess char / null terminator
382 char buf[buf_len];
383 memset(buf, 0, buf_len);
384 ssize_t read_len = fd_->Read(buf, buf_len);
385 if (read_len < 0 || read_len > static_cast<ssize_t>(max_entry_len)) {
386 if (read_len < 0) {
387 const string err_str = "failed to read GPIO";
388 if (fd_->IsSettingErrno()) {
389 PLOG(ERROR) << err_str;
390 } else {
391 LOG(ERROR) << err_str;
392 }
393 } else {
394 LOG(ERROR) << "read too many bytes (" << read_len << ")";
395 }
396 return false;
397 }
398
399 // Remove trailing newline.
400 read_len--;
401 if (buf[read_len] != '\n') {
402 LOG(ERROR) << "read value missing trailing newline";
403 return false;
404 }
405 buf[read_len] = '\0';
406
407 // Identify and write GPIO status.
408 for (int i = 0; i < num_entries; i++)
409 if (!strcmp(entries[i], buf)) {
410 *index_p = i;
411 // Close the device explicitly, returning the close result.
412 return fd_->Close();
413 }
414
415 // Oops, unidentified reading...
416 LOG(ERROR) << "read unexpected value from GPIO (`" << buf << "')";
417 return false;
418}
419
420bool StandardGpioHandler::SetGpioDirection(StandardGpioHandler::GpioId id,
421 StandardGpioHandler::GpioDir dir) {
422 return SetGpio(id, "direction", gpio_dirs_, kGpioDirMax, dir);
423}
424
425bool StandardGpioHandler::GetGpioDirection(
426 StandardGpioHandler::GpioId id,
427 StandardGpioHandler::GpioDir* direction_p) {
428 return GetGpio(id, "direction", gpio_dirs_, kGpioDirMax,
429 reinterpret_cast<int*>(direction_p));
430}
431
432bool StandardGpioHandler::SetGpioValue(StandardGpioHandler::GpioId id,
433 StandardGpioHandler::GpioVal value,
434 bool is_check_direction) {
435 // If so instructed, ensure that the GPIO is indeed in the output direction
436 // before attempting to write to it.
437 if (is_check_direction) {
438 GpioDir dir;
439 if (!(GetGpioDirection(id, &dir) && dir == kGpioDirOut)) {
440 LOG(ERROR) << "couldn't verify that GPIO is in the output direction "
441 "prior to reading from it";
442 return false;
443 }
444 }
445
446 return SetGpio(id, "value", gpio_vals_, kGpioValMax, value);
447}
448
449bool StandardGpioHandler::GetGpioValue(StandardGpioHandler::GpioId id,
450 StandardGpioHandler::GpioVal* value_p,
451 bool is_check_direction) {
452 // If so instructed, ensure that the GPIO is indeed in the input direction
453 // before attempting to read from it.
454 if (is_check_direction) {
455 GpioDir dir;
456 if (!(GetGpioDirection(id, &dir) && dir == kGpioDirIn)) {
457 LOG(ERROR) << "couldn't verify that GPIO is in the input direction "
458 "prior to reading from it";
459 return false;
460 }
461 }
462
463 return GetGpio(id, "value", gpio_vals_, kGpioValMax,
464 reinterpret_cast<int*>(value_p));
465}
466
467bool StandardGpioHandler::DoTestModeSignalingProtocol() {
468 // The test mode signaling protocol is designed to provide a robust indication
469 // that a Chrome OS device is physically connected to a servo board in a lab
470 // setting. It is making very few assumptions about the soundness of the
471 // hardware, firmware and kernel driver implementation of the GPIO mechanism.
472 // In general, it is performing a three-way handshake between servo and the
473 // Chrome OS client, based on changes in the GPIO value readings. The
474 // client-side implementation does the following:
475 //
476 // 1. Check for an initial signal (0) on the input GPIO (dut_flaga).
477 //
478 // 2. Flip the signal (1 -> 0) on the output GPIO (dut_flagb).
479 //
480 // 3. Check for a flipped signal (1) on the input GPIO.
481 //
482 // TODO(garnold) the current implementation is based on sysfs access to GPIOs.
483 // We will likely change this to using a specialized in-kernel driver
484 // implementation, which would give us better performance and security
485 // guarantees.
486
487 LOG(INFO) << "attempting GPIO handshake";
488
489 const char* dutflaga_name = gpio_defs_[kGpioIdDutflaga].name;
490 const char* dutflagb_name = gpio_defs_[kGpioIdDutflagb].name;
491
492 // Flip GPIO direction, set it to "in".
493 // TODO(garnold) changing the GPIO direction back and forth is necessary for
494 // overcoming a firmware/kernel issue which causes the device to be in the
495 // "out" state whereas the kernel thinks it is in the "in" state. This should
496 // be abandoned once the firmware and/or kernel driver have been fixed.
497 // Details here: http://code.google.com/p/chromium-os/issues/detail?id=27680
498 if (!(SetGpioDirection(kGpioIdDutflaga, kGpioDirOut) &&
499 SetGpioDirection(kGpioIdDutflaga, kGpioDirIn))) {
500 LOG(ERROR) << "failed to flip direction of input GPIO " << dutflaga_name;
501 return false;
502 }
503
504 // Peek input GPIO state.
505 GpioVal dutflaga_gpio_value;
506 if (!GetGpioValue(kGpioIdDutflaga, &dutflaga_gpio_value, true)) {
507 LOG(ERROR) << "failed to read input GPIO " << dutflaga_name;
508 return false;
509 }
510
511 // If initial handshake signal not received, abort.
512 if (dutflaga_gpio_value != kGpioValDown) {
513 LOG(INFO) << "input GPIO " << dutflaga_name
514 << " unset, terminating handshake";
515 is_handshake_completed_ = true;
516 return true;
517 }
518
519 // Initialize output GPIO to a default state.
520 // TODO(garnold) a similar workaround for possible driver/firmware glitches,
521 // we insist on flipping the direction of the GPIO prior to assuming it is in
522 // the "out" direction.
523 GpioDirResetter dutflagb_dir_resetter(this, kGpioIdDutflagb, kGpioDirIn);
524 if (!(SetGpioDirection(kGpioIdDutflagb, kGpioDirIn) &&
525 dutflagb_dir_resetter.set_do_reset(
526 SetGpioDirection(kGpioIdDutflagb, kGpioDirOut)) &&
527 SetGpioValue(kGpioIdDutflagb, kGpioValUp, false))) {
528 LOG(ERROR) << "failed to initialize output GPIO " << dutflagb_name;
529 return false;
530 }
531
532 // Wait, giving the receiving end enough time to sense the fall.
533 sleep(kServoOutputResponseWaitInSecs);
534
535 // Flip the output signal.
536 if (!SetGpioValue(kGpioIdDutflagb, kGpioValDown, false)) {
537 LOG(ERROR) << "failed to flip output GPIO " << dutflagb_name;
538 return false;
539 }
540
541 // Look for flipped input GPIO value, up to a preset timeout.
542 Time expires =
543 Time::Now() + TimeDelta::FromSeconds(kServoInputResponseTimeoutInSecs);
544 TimeDelta delay =
545 TimeDelta::FromMicroseconds(1000000 / kServoInputNumChecksPerSec);
546 bool is_first_response_check = true;
547 bool is_error = false;
548 while (Time::Now() < expires) {
549 if (is_first_response_check)
550 is_first_response_check = false;
551 else
552 usleep(delay.InMicroseconds());
553
554 // Read input GPIO.
555 if (!GetGpioValue(kGpioIdDutflaga, &dutflaga_gpio_value, true)) {
556 LOG(ERROR) << "failed to read input GPIO " << dutflaga_name;
557 is_error = true;
558 break;
559 }
560
561 // If dutflaga is now up (flipped), we got our signal!
562 if (dutflaga_gpio_value == kGpioValUp) {
563 is_test_mode_ = true;
564 break;
565 }
566 }
567
568 if (!is_error) {
569 if (is_test_mode_) {
570 is_handshake_completed_ = true;
571 LOG(INFO) << "GPIO handshake completed, test mode signaled";
572 } else {
573 LOG(INFO) << "timed out waiting for input GPIO " << dutflaga_name
574 << " to flip, terminating handshake";
575 }
576 }
577
578 return is_handshake_completed_;
579}
580
Gilad Arnold1ebd8132012-03-05 10:19:29 -0800581} // namespace chromeos_update_engine