1# Copyright (c) 2013 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 5import logging, time 6 7from autotest_lib.server import autotest, test 8from autotest_lib.client.common_lib import error 9 10_SUSPEND_TIME = 60 11_SUSPEND_TIMEOUT = 30 12 13class power_USBHotplugInSuspend(test.test): 14 version = 1 15 16 def _switch_usbkey_power(self, on): 17 """ 18 Turn on/off the power to the USB key. 19 20 @param on True to turn on, false otherwise. 21 """ 22 if on: 23 self._host.servo.set('prtctl4_pwren', 'on') 24 else: 25 self._host.servo.set('prtctl4_pwren', 'off') 26 time.sleep(self._host.servo.USB_POWEROFF_DELAY) 27 28 def _get_usb_devices(self): 29 """ 30 Get the USB device attached to the client. 31 32 Parses output from lsusb and returns the set of device IDs. 33 """ 34 try: 35 lines = self._host.run('lsusb').stdout.strip().split('\n') 36 except: 37 raise error.TestError('Failed to get list of USB devices.') 38 devices = set(line.split()[5] for line in lines) 39 logging.info('USB Devices: %s' % (",".join(devices))) 40 return devices 41 42 def _suspend_client(self): 43 """ 44 Start the client test power_KernelSuspend to suspend the client and 45 do not wait for it to finish. 46 """ 47 client_at = autotest.Autotest(self._host) 48 # TODO(scottz): Add server side support to sys_power: crosbug.com/38115 49 client_at.run_test('power_KernelSuspend', background=True, 50 seconds=_SUSPEND_TIME) 51 52 def _suspend_and_hotplug(self, insert): 53 """ 54 Suspend the client and add/remove the USB key. This assumes that a 55 USB key is plugged into the servo and is facing the DUT. 56 57 @param insert True to test insertion during suspend, False to test 58 removal. 59 """ 60 # Initialize the USB key and get the set of USB devices before 61 # suspending. 62 self._switch_usbkey_power(not insert) 63 before_suspend = self._get_usb_devices() 64 65 # Suspend the client and wait for it to go down before powering on/off 66 # the usb key. 67 self._suspend_client() 68 if not self._host.ping_wait_down(_SUSPEND_TIMEOUT): 69 raise error.TestError('Client failed to suspend.') 70 self._switch_usbkey_power(insert) 71 72 # Wait for the client to come back up (suspend time + some slack time). 73 # TODO(beeps): Combine the two timeouts in wait_up after 74 # crbug.com/221785 is resolved. 75 time.sleep(_SUSPEND_TIME) 76 if not self._host.wait_up(self._host.RESUME_TIMEOUT): 77 raise error.TestError('Client failed to resume.') 78 79 # Get the set of devices plugged in and make sure the change was 80 # detected. 81 after_suspend = self._get_usb_devices() 82 diff = after_suspend ^ before_suspend 83 if not diff: 84 raise error.TestFail('No USB changes detected after resuming.') 85 86 # Finally, make sure hotplug still works after resuming by switching 87 # the USB key's power once more. 88 self._switch_usbkey_power(not insert) 89 after_hotplug = self._get_usb_devices() 90 diff = after_hotplug ^ after_suspend 91 if not diff: 92 raise error.TestFail('No USB changes detected after hotplugging.') 93 94 def cleanup(self): 95 """ 96 Reset the USB key to its initial state. 97 """ 98 self._host.servo.switch_usbkey(self._init_usbkey_direction) 99 self._switch_usbkey_power(self._init_usbkey_power == 'on') 100 super(power_USBHotplugInSuspend, self).cleanup() 101 102 def run_once(self, host): 103 """ 104 Tests adding and removing a USB device while the client is suspended. 105 """ 106 self._host = host 107 self._init_usbkey_power = self._host.servo.get('prtctl4_pwren') 108 self._init_usbkey_direction = self._host.servo.get_usbkey_direction() 109 110 # Make sure the USB key is facing the DUT and is actually present. 111 self._host.servo.switch_usbkey('dut') 112 self._switch_usbkey_power(False) 113 before_insert = self._get_usb_devices() 114 self._switch_usbkey_power(True) 115 after_insert = self._get_usb_devices() 116 diff = after_insert - before_insert 117 logging.info('Inserted USB device(s): %s' % (",".join(diff))) 118 if not diff: 119 raise error.TestError('No new USB devices detected. Is a USB key ' 120 'plugged into the servo?') 121 122 logging.info('Testing insertion during suspend.') 123 self._suspend_and_hotplug(True) 124 logging.info('Testing removal during suspend.') 125 self._suspend_and_hotplug(False) 126