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