servod: support parity on servo_micro

Add uart_parity controls and drv support
for servo_micro.

BUG=b:37513705
TEST=set parity on servo micro

Change-Id: I02fae2bc587d84e2cc0aad36cb2c8479d5b1b69b
Reviewed-on: https://chromium-review.googlesource.com/564306
Commit-Ready: Nick Sanders <nsanders@chromium.org>
Tested-by: Nick Sanders <nsanders@chromium.org>
Reviewed-by: Nicolas Boichat <drinkcat@chromium.org>
diff --git a/servo/data/servo_micro.xml b/servo/data/servo_micro.xml
index 9dbf8c3..3cf98a9 100644
--- a/servo/data/servo_micro.xml
+++ b/servo/data/servo_micro.xml
@@ -259,6 +259,14 @@
     </params>
   </control>
   <control>
+    <name>uart3_parity</name>
+    <alias>usbpd_uart_parity</alias>
+    <doc>Parity for uart console</doc>
+    <params drv="uart" subtype="props" line_prop="parity"
+    interface="1" map="uart_parity"></params>
+  </control>
+
+  <control>
     <name>uart2_pty</name>
     <alias>cpu_uart_pty</alias>
     <doc>UART console. USART3: PB10/PB11 - Servo header UART2</doc>
@@ -266,6 +274,14 @@
     </params>
   </control>
   <control>
+    <name>uart2_parity</name>
+    <alias>cpu_uart_parity</alias>
+    <doc>Parity for uart console</doc>
+    <params drv="uart" subtype="props" line_prop="parity"
+    interface="8" map="uart_parity"></params>
+  </control>
+
+  <control>
     <name>uart1_pty</name>
     <alias>raw_ec_uart_pty</alias>
     <doc>UART console. USART2: PA2/PA3 - Servo header UART1</doc>
@@ -273,6 +289,14 @@
     </params>
   </control>
   <control>
+    <name>uart1_parity</name>
+    <alias>ec_uart_parity</alias>
+    <doc>Parity for uart console</doc>
+    <params drv="uart" subtype="props" line_prop="parity"
+    interface="7" map="uart_parity"></params>
+  </control>
+
+  <control>
     <name>raw_servo_console_pty</name>
     <doc>Servo's stm32 console.</doc>
     <params cmd="get" subtype="pty" interface="3" drv="uart">
diff --git a/servo/stm32uart.py b/servo/stm32uart.py
index 65c07ff..0bbdf80 100644
--- a/servo/stm32uart.py
+++ b/servo/stm32uart.py
@@ -36,6 +36,8 @@
 
 class Suart(uart.Uart):
   """Provide interface to stm32 serial usb endpoint."""
+  USB_USART_SET_PARITY = 1
+
   def __init__(self, vendor=0x18d1, product=0x501a, interface=0,
                serialname=None, ftdi_context=None):
     """Suart contstructor.
@@ -57,6 +59,7 @@
     self._logger.debug('')
     self._logger.debug('Suart opening %04x:%04x, intf %d, sn: %s' % (
         vendor, product, interface, serialname))
+    self._props = {}
 
     self._susb = stm32usb.Susb(vendor=vendor, product=product,
         interface=interface, serialname=serialname, logger=self._logger)
@@ -174,10 +177,12 @@
           2: 2 stop bits
     """
     self._logger.debug('')
-    return {'baudrate': 115200,
-            'bits': 8,
-            'parity': 0,
-            'sbits': 1}
+    if not self._props:
+      self._props = {'baudrate': 115200,
+                     'bits': 8,
+                     'parity': 0,
+                     'sbits': 1}
+    return self._props.copy()
 
 
   def set_uart_props(self, line_props):
@@ -198,14 +203,18 @@
           2: 2 stop bits
 
     Raises:
-      SuartError: If requested line properties are not the default.
+      SuartError: If requested line properties are not possible.
     """
     self._logger.debug('')
     curr_props = self.get_uart_props()
     for prop in line_props:
       if line_props[prop] != curr_props[prop]:
-        raise SuartError("Line property %s cannot be set from %s to %s" % (
-            prop, curr_props[prop], line_props[prop]))
+        if prop == 'parity' and line_props[prop] in [0, 1, 2]:
+          self._susb.control(self.USB_USART_SET_PARITY, line_props[prop])
+        else:
+          raise SuartError("Line property %s cannot be set from %s to %s" % (
+              prop, curr_props[prop], line_props[prop]))
+    self._props = line_props.copy()
     return True
 
 
diff --git a/servo/stm32usb.py b/servo/stm32usb.py
index 8e108f7..db73d2f 100755
--- a/servo/stm32usb.py
+++ b/servo/stm32usb.py
@@ -97,6 +97,7 @@
       dev.set_configuration()
     except usb.core.USBError:
       pass
+    self._dev = dev
 
     # Get an endpoint instance.
     cfg = dev.get_active_configuration()
@@ -120,6 +121,26 @@
 
     self._logger.debug("Set up stm32 usb")
 
+  def control(self, request, value):
+    """Send control transfer.
+
+    Args:
+      request: the request type to send, bmRequestType
+      data: the data to send, wValue
+
+    Returns:
+      boolean success/fail
+    """
+    # usb_setup_packet: ec/include/usb_descriptor.h:231
+    reqtype = (usb.util.CTRL_OUT |
+               usb.util.CTRL_TYPE_VENDOR |
+               usb.util.CTRL_RECIPIENT_INTERFACE)
+    ret = self._dev.ctrl_transfer(bmRequestType = reqtype,
+                                  bRequest = request,
+                                  wIndex = self._interface,
+                                  wValue = value)
+    return True
+
   def __del__(self):
     """Sgpio destructor."""
     self._logger.debug("Close")