• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import collections
2import logging
3
4
5PortId = collections.namedtuple('PortId', ['bus', 'port_number'])
6
7# Mapping from bus ID and port number to the GPIO Index.
8# We know of no way to detect this through tools, why the board
9# specific setup is hard coded here.
10_PORT_ID_TO_GPIO_INDEX_DICT = {
11    'guado': {
12        # On Guados, there are three gpios that control usb port power:
13        PortId(bus=1, port_number=2): 218,  # Front left USB 2
14        PortId(bus=2, port_number=1): 218,  # Front left USB 3
15        PortId(bus=1, port_number=3): 219,  # Front right USB 2
16        PortId(bus=2, port_number=2): 219,  # Front right USB 3
17        # Back ports (same GPIO is used for both ports)
18        PortId(bus=1, port_number=5): 209,  # Back upper USB 2
19        PortId(bus=2, port_number=3): 209,  # Back upper USB 3
20        PortId(bus=1, port_number=6): 209,  # Back lower USB 2
21        PortId(bus=2, port_number=4): 209,  # Back lower USB 3
22    },
23    # On Fizz, there are in total 5 usb ports and per port usb power
24    # is controlled by EC with user space command:
25    # ectool gpioset USBx_ENABLE 0/1 (x from 1 to 5).
26    'fizz': {
27        # USB 2 bus.
28        PortId(bus=1, port_number=3): 4,    # Front right USB 2
29        PortId(bus=1, port_number=4): 5,    # Front left USB 2
30        PortId(bus=1, port_number=5): 1,    # Back left USB 2
31        PortId(bus=1, port_number=6): 2,    # Back middle USB 2
32        PortId(bus=1, port_number=2): 3,    # Back right USB 2
33        # USB 3 bus.
34        PortId(bus=2, port_number=3): 4,    # Front right USB 3
35        PortId(bus=2, port_number=4): 5,    # Front left USB 3
36        PortId(bus=2, port_number=5): 1,    # Back left USB 3
37        PortId(bus=2, port_number=6): 2,    # Back middle USB 3
38        PortId(bus=2, port_number=2): 3,    # Back right USB 3
39    }
40}
41
42
43def _get_gpio_index(board, port_id):
44    return _PORT_ID_TO_GPIO_INDEX_DICT[board][port_id]
45
46
47class UsbPortManager(object):
48    """
49    Manages USB ports.
50
51    Can for example power cycle them.
52    """
53    def __init__(self, host):
54        """
55        Initializes with a host.
56
57        @param host a Host object.
58        """
59        self._host = host
60
61    def set_port_power(self, port_ids, power_on):
62        """
63        Turns on or off power to the USB port for peripheral devices.
64
65        @param port_ids Iterable of PortId instances (i.e. bus, port_number
66            tuples) to set power for.
67        @param power_on If true, turns power on. If false, turns power off.
68        """
69        for port_id in port_ids:
70            gpio_index = _get_gpio_index(self._get_board(), port_id)
71            self._set_gpio_power(self._get_board(), gpio_index, power_on)
72
73    def _get_board(self):
74        # host.get_board() adds 'board: ' in front of the board name
75        return self._host.get_board().split(':')[1].strip()
76
77    def _set_gpio_power_guado(self, gpio_index, power_on):
78        """
79        Turns on or off the power for a specific GPIO on board Guado.
80
81        @param gpio_idx The index of the gpio to set the power for.
82        @param power_on If True, powers on the GPIO. If False, powers it off.
83        """
84        gpio_path = '/sys/class/gpio/gpio{}'.format(gpio_index)
85        did_export = False
86        if not self._host.path_exists(gpio_path):
87            did_export = True
88            self._run('echo {} > /sys/class/gpio/export'.format(
89                    gpio_index))
90        try:
91            self._run('echo out > {}/direction'.format(gpio_path))
92            value_string = '1' if power_on else '0'
93            self._run('echo {} > {}/value'.format(
94                    value_string, gpio_path))
95        finally:
96            if did_export:
97                self._run('echo {} > /sys/class/gpio/unexport'.format(
98                        gpio_index))
99
100    def _set_gpio_power_fizz(self, gpio_idx, power_on):
101        """
102        Turns on or off the power for a specific GPIO on board Fizz.
103
104        @param gpio_idx The index of the gpio to set the power for.
105        @param power_on If True, powers on the GPIO. If False, powers it off.
106        """
107        value_string = '1' if power_on else '0'
108        cmd = 'ectool gpioset USB{}_ENABLE {}'.format(gpio_idx,
109              value_string)
110        self._run(cmd)
111
112    def _set_gpio_power(self, board, gpio_index, power_on):
113        """
114        Turns on or off the power for a specific GPIO.
115
116        @param board Board type. Currently support: Guado, Fizz.
117        @param gpio_idx The index of the gpio to set the power for.
118        @param power_on If True, powers on the GPIO. If False, powers it off.
119        """
120        if board == 'guado':
121            self._set_gpio_power_guado(gpio_index, power_on)
122        elif board == 'fizz':
123            self._set_gpio_power_fizz(gpio_index, power_on)
124        else:
125            raise ValueError('Unsupported board type {}.'.format(board))
126
127    def _run(self, command):
128        logging.debug('Running: "%s"', command)
129        res = self._host.run(command)
130        logging.debug('Result: "%s"', res)
131
132