/bin/wifi: robustify Quantenna device detection.

Detect Quantenna device without actually executing the QCSAPI and move
detection out of module load time. Instead, check if the qdpc-host
module is loaded and the QCSAPI binaries exist, and memoize the result.

Change-Id: If2ff5d7e7035ca90d23e721f3ad820e5cd229199
diff --git a/wifi/quantenna.py b/wifi/quantenna.py
index bee478f..0bed0c8 100755
--- a/wifi/quantenna.py
+++ b/wifi/quantenna.py
@@ -9,27 +9,23 @@
 import utils
 
 
-# Detect Quantenna device.
-#
-# qcsapi_pcie_static runs on PCIe hosts, e.g. GFRG250.
-# call_qcsapi runs on the LHOST, e.g. GFEX250.
-#
-# When called without arguments, qcsapi_pcie_static checks for a Quantenna
-# device without sending any RPCs. Both programs return 234 only if a Quantenna
-# device is present.
-_QCSAPI = None
-for qcsapi in ['qcsapi_pcie_static', 'call_qcsapi']:
-  with open(os.devnull, 'w') as devnull:
-    try:
-      if subprocess.call([qcsapi], stdout=devnull, stderr=devnull) == 234:
-        _QCSAPI = qcsapi
-        break
-    except OSError:
-      continue
+def _get_qcsapi():
+  """Detect Quantenna device."""
+  if not hasattr(_get_qcsapi, 'qcsapi'):
+    _get_qcsapi.qcsapi = None
+    if (utils.subprocess_quiet(['runnable', 'qcsapi_pcie_static']) == 0 and
+        utils.subprocess_quiet(['modinfo', 'qdpc-host'], no_stdout=True) == 0):
+      # qcsapi_pcie_static runs on PCIe hosts, e.g. GFRG250. qdpc-host is only
+      # loaded if a Quantenna device is present.
+      _get_qcsapi.qcsapi = 'qcsapi_pcie_static'
+    elif utils.subprocess_quiet(['runnable', 'call_qcsapi']) == 0:
+      # call_qcsapi runs on the LHOST, e.g. GFEX250.
+      _get_qcsapi.qcsapi = 'call_qcsapi'
+  return _get_qcsapi.qcsapi
 
 
 def _qcsapi(*args):
-  return subprocess.check_output([_QCSAPI] + list(args))
+  return subprocess.check_output([_get_qcsapi()] + list(args))
 
 
 def _set(mode, opt):
@@ -85,7 +81,7 @@
 
 
 def has_quantenna():
-  return _QCSAPI is not None
+  return _get_qcsapi() is not None
 
 
 def set_wifi(opt):