=== added file 'lava_dispatcher/actions/lava_lmp.py'
--- lava_dispatcher/actions/lava_lmp.py	1970-01-01 00:00:00 +0000
+++ lava_dispatcher/actions/lava_lmp.py	2013-08-08 13:55:13 +0000
@@ -0,0 +1,230 @@
+# Copyright (C) 2013 Linaro Limited
+#
+# Author: Dave Pigott <dave.pigott@linaro.org>
+#
+# This file is part of LAVA Dispatcher.
+#
+# LAVA Dispatcher is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# LAVA Dispatcher is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along
+# with this program; if not, see <http://www.gnu.org/licenses>.
+
+import serial
+import json
+import logging
+from serial import (
+    serialutil
+)
+from lava_dispatcher.errors import (
+    CriticalError,
+)
+
+class LAVALmpDeviceSerial(object):
+    def __init__(self, serialno, board_type):
+        device_map = {
+            "sdmux": "0a",
+            "sata": "19",
+            "lsgpio": "09",
+            "hdmi": "0c",
+            "usb": "04"
+        }
+        self.serialno = "LL" + device_map[board_type] + serialno.zfill(12)
+        logging.debug("LMP Serial #: %s" % self.serialno)
+        self.lmpType = "org.linaro.lmp." + board_type
+        self.board_type = board_type
+        try:
+            self.port = serial.Serial("/dev/serial/by-id/usb-Linaro_Ltd_LavaLMP_" + self.serialno + "-if00", timeout=1)
+        except serial.serialutil.SerialException as e:
+            logging.error("LMP: Error opening {0:s}: {1:s}".format(self.serialno, e))
+            raise
+        self.START_FRAME = '\x02'
+        self.END_FRAME = '\x04'
+        self.sendFrame('{"schema":"org.linaro.lmp.info"}')
+        message = self.getResponse("board")
+        if message['serial'] != self.serialno:
+            raise CriticalError("Lmp %s not connected" % serial)
+
+    def sendCommand(self, mode, selection):
+        message = '{"schema":"' + self.lmpType + '",' + \
+            '"serial":"' + self.serialno + '",' + \
+            '"modes":[{"name":"' + mode + '",' + \
+            '"option":"' + selection + '"}]}'
+        self.sendFrame(message)
+        device_in_mode = False
+        while not device_in_mode:
+            try:
+                response = self.getFrame()
+            except ValueError as e:
+                logging.warning("LMP Frame read error: %s" % e)
+                continue
+            else:
+                for i in response["report"]:
+                    if i["name"] == "modes":
+                        modes = dict(i)
+                        for j in modes["modes"]:
+                            state = dict(j)
+                            if state["name"] == mode and state["mode"] == selection:
+                                logging.debug("LMP %s: %s now in mode %s" % (self.board_type, mode, selection))
+                                device_in_mode = True
+
+    def sendFrame(self, command):
+        logging.debug("LMP: Sending %s" % command)
+        payload = self.START_FRAME + command + self.END_FRAME
+        self.port.write(payload)
+
+    def getResponse(self, schema):
+        got_schema = False
+
+        result = self.getFrame()
+
+        while not got_schema:
+            if result['schema'] == "org.linaro.lmp." + schema:
+                got_schema = True
+            else:
+                result = self.getFrame()
+
+        return result
+
+    def getFrame(self):
+        char = self.port.read()
+
+        while char != self.START_FRAME:
+            char = self.port.read()
+
+        response = ""
+
+        while char != self.END_FRAME:
+            char = self.port.read()
+            if char != self.END_FRAME:
+                response += char
+
+        logging.debug("LMP: Got %s" % response)
+
+        return json.loads(response)
+
+    def close(self):
+        self.port.close()
+
+
+class LAVALmpSDMux(LAVALmpDeviceSerial):
+    def __init__(self, serialno):
+        super(LAVALmpSDMux, self).__init__(serialno, "sdmux")
+
+    def dutDisconnect(self):
+        self.sendCommand("dut", "disconnect")
+
+    def dutuSDA(self):
+        self.sendCommand("dut", "uSDA")
+
+    def dutuSDB(self):
+        self.sendCommand("dut", "uSDB")
+
+    def hostDisconnect(self):
+        self.sendCommand("host", "disconnect")
+
+    def hostuSDA(self):
+        self.sendCommand("host", "uSDA")
+
+    def hostuSDB(self):
+        self.sendCommand("host", "uSDB")
+
+    def dutPowerShortForOff(self):
+        self.sendCommand("dut-power", "short-for-off")
+
+    def dutPowerShortForOn(self):
+        self.sendCommand("dut-power", "short-for-on")
+
+
+def lmpSdmux_dutDisconnect(serial):
+    sdmux = LAVALmpSDMux(serial)
+    sdmux.dutDisconnect()
+    sdmux.close()
+
+
+def lmpSdmux_dutuSDA(serial):
+    sdmux = LAVALmpSDMux(serial)
+    sdmux.dutuSDA()
+    sdmux.close()
+
+
+def lmpSdmux_hostDisconnect(serial):
+    sdmux = LAVALmpSDMux(serial)
+    sdmux.hostDisconnect()
+    sdmux.close()
+
+
+def lmpSdmux_hostuSDA(serial):
+    sdmux = LAVALmpSDMux(serial)
+    sdmux.hostuSDA()
+    sdmux.close()
+
+
+class LAVALmpEthSata(LAVALmpDeviceSerial):
+    def __init__(self, serialno):
+        super(LAVALmpEthSata, self).__init__(serialno, "sata")
+
+    def dutDisconnect(self):
+        self.sendCommand("sata", "disconnect")
+
+    def dutPassthru(self):
+        self.sendCommand("sata", "passthru")
+
+
+class LAVALmpLsgpio(LAVALmpDeviceSerial):
+    def __init__(self, serialno):
+        super(LAVALmpLsgpio, self).__init__(serialno, "lsgpio")
+
+    def audioDisconnect(self):
+        self.sendCommand("audio", "disconnect")
+
+    def audioPassthru(self):
+        self.sendCommand("audio", "passthru")
+
+    def aDirIn(self):
+        self.sendCommand("a-dir", "in")
+
+    def aDirOut(self):
+        self.sendCommand("a-dir", "out")
+
+    def bDirIn(self):
+        self.sendCommand("b-dir", "in")
+
+    def bDirOut(self):
+        self.sendCommand("b-dir", "out")
+
+
+class LAVALmpHdmi(LAVALmpDeviceSerial):
+    def __init__(self, serialno):
+        super(LAVALmpHdmi, self).__init__(serialno, "hdmi")
+
+    def hdmiDisconnect(self):
+        self.sendCommand("hdmi", "disconnect")
+
+    def hdmiPassthru(self):
+        self.sendCommand("hdmi", "passthru")
+
+    def hdmiFake(self):
+        self.sendCommand("hdmi", "fake")
+
+
+class LAVALmpUsb(LAVALmpDeviceSerial):
+    def __init__(self, serialno):
+        super(LAVALmpUsb, self).__init__(serialno, "usb")
+
+    def usbDevice(self):
+        self.sendCommand("usb", "device")
+
+    def usbHost(self):
+        self.sendCommand("usb", "host")
+
+    def usbDisconnect(self):
+        self.sendCommand("usb", "disconnect")

=== modified file 'lava_dispatcher/config.py'
--- lava_dispatcher/config.py	2013-07-22 21:18:32 +0000
+++ lava_dispatcher/config.py	2013-08-08 13:55:13 +0000
@@ -80,6 +80,7 @@
     testboot_offset = schema.IntOption(fatal=True)
     # see doc/sdmux.rst for details
     sdmux_id = schema.StringOption()
+    sdmux_usb_id = schema.StringOption()
     sdmux_version = schema.StringOption(default="unknown")
 
     simulator_version_command = schema.StringOption()

=== added file 'lava_dispatcher/default-config/lava-dispatcher/devices/beaglebone-black-01.conf'
--- lava_dispatcher/default-config/lava-dispatcher/devices/beaglebone-black-01.conf	1970-01-01 00:00:00 +0000
+++ lava_dispatcher/default-config/lava-dispatcher/devices/beaglebone-black-01.conf	2013-08-08 13:55:13 +0000
@@ -0,0 +1,11 @@
+device_type = beaglebone-black
+hostname = beaglebone-black-01
+client_type = sdmux
+
+sdmux_id = 13060055
+sdmux_usb_id = 1-1
+sdmux_version = LAVA-Lmp-Rev3a
+
+connection_command = telnet localhost 7001
+power_on_cmd = echo "Please power on the device"
+power_off_cmd = echo "Please power the device down"

=== modified file 'lava_dispatcher/device/sdmux.py'
--- lava_dispatcher/device/sdmux.py	2013-07-16 16:04:07 +0000
+++ lava_dispatcher/device/sdmux.py	2013-08-08 13:55:13 +0000
@@ -1,6 +1,7 @@
-# Copyright (C) 2012 Linaro Limited
+# Copyright (C) 2012-2013 Linaro Limited
 #
 # Author: Andy Doan <andy.doan@linaro.org>
+#         Dave Pigott <dave.pigott@linaro.org>
 #
 # This file is part of LAVA Dispatcher.
 #
@@ -21,6 +22,7 @@
 import contextlib
 import logging
 import os
+import glob
 import subprocess
 import time
 
@@ -43,6 +45,12 @@
     ensure_directory,
     extract_targz,
 )
+from lava_dispatcher.actions.lava_lmp import (
+    lmpSdmux_dutDisconnect,
+    lmpSdmux_dutuSDA,
+    lmpSdmux_hostDisconnect,
+    lmpSdmux_hostuSDA
+)
 
 
 def _flush_files(mntdir):
@@ -64,26 +72,19 @@
     This adds support for the "sd mux" device. An SD-MUX device is a piece of
     hardware that allows the host and target to both connect to the same SD
     card. The control of the SD card can then be toggled between the target
-    and host via software. The schematics and pictures of this device can be
-    found at:
-      http://people.linaro.org/~doanac/sdmux/
-
-    Documentation for setting this up is located under doc/sdmux.rst.
-
-    NOTE: please read doc/sdmux.rst about kernel versions
-    """
+    and host via software.
+"""
 
     def __init__(self, context, config):
         super(SDMuxTarget, self).__init__(context, config)
 
         self.proc = None
 
+        if not config.sdmux_usb_id:
+            raise CriticalError('Device config requires "sdmux_usb_id"')
+
         if not config.sdmux_id:
             raise CriticalError('Device config requires "sdmux_id"')
-        if not config.power_on_cmd:
-            raise CriticalError('Device config requires "power_on_cmd"')
-        if not config.power_off_cmd:
-            raise CriticalError('Device config requires "power_off_cmd"')
 
         if config.pre_connect_command:
             self.context.run_command(config.pre_connect_command)
@@ -119,26 +120,25 @@
         self._write_image(img)
 
     def _as_chunks(self, fname, bsize):
-        with open(fname, 'r') as fd:
+        with open(fname, 'rb') as fd:
             while True:
                 data = fd.read(bsize)
                 if not data:
                     break
                 yield data
+            fd.close()
 
     def _write_image(self, image):
+        lmpSdmux_dutDisconnect(self.config.sdmux_id)
+        lmpSdmux_hostuSDA(self.config.sdmux_id)
+
         with self.mux_device() as device:
             logging.info("dd'ing image to device (%s)", device)
-            with open(device, 'w') as of:
-                written = 0
-                size = os.path.getsize(image)
-                # 4M chunks work well for SD cards
-                for chunk in self._as_chunks(image, 4 << 20):
-                    of.write(chunk)
-                    written += len(chunk)
-                    if written % (20 * (4 << 20)) == 0:  # only log every 80MB
-                        logging.info("wrote %d of %d bytes", written, size)
-                logging.info('closing %s, could take a while...', device)
+            dd_cmd = 'dd if=%s of=%s bs=4096 conv=fsync' % (image, device)
+            dd_proc = subprocess.Popen(dd_cmd, shell=True)
+            dd_proc.wait()
+
+        lmpSdmux_hostDisconnect(self.config.sdmux_id)
 
     @contextlib.contextmanager
     def mux_device(self):
@@ -153,23 +153,32 @@
         the USB device connect to the sdmux will be powered off so that the
         target will be able to safely access it.
         """
-        muxid = self.config.sdmux_id
-        source_dir = os.path.abspath(os.path.dirname(__file__))
-        muxscript = os.path.join(source_dir, 'sdmux.sh')
 
-        self.power_off(self.proc)
         self.proc = None
 
-        try:
-            deventry = subprocess.check_output([muxscript, '-d', muxid, 'on'])
-            deventry = deventry.strip()
+        syspath = "/sys/bus/usb/devices/" + self.config.sdmux_usb_id + \
+            "/" + self.config.sdmux_usb_id + \
+            "*/host*/target*/*:0:0:0/block/*"
+
+        retrycount = 0
+
+        while retrycount < 20:
+            device_list = glob.glob(syspath)
+            deventry = ""
+            for device in device_list:
+                deventry = os.path.join("/dev/", os.path.basename(device))
+            if deventry != "":
+                break
+            time.sleep(1)
+            retrycount += 1
+
+        if deventry != "":
             logging.info('returning sdmux device as: %s', deventry)
+            os.system("umount /media/rootfs")
+            os.system("umount /media/boot")
             yield deventry
-        except subprocess.CalledProcessError:
+        else:
             raise CriticalError('Unable to access sdmux device')
-        finally:
-            logging.info('powering off sdmux')
-            self.context.run_command([muxscript, '-d', muxid, 'off'], failok=False)
 
     @contextlib.contextmanager
     def file_system(self, partition, directory):
@@ -219,10 +228,14 @@
     def power_off(self, proc):
         super(SDMuxTarget, self).power_off(proc)
         self.context.run_command(self.config.power_off_cmd)
+        lmpSdmux_dutDisconnect(self.config.sdmux_id)
 
     def power_on(self):
         self.proc = connect_to_serial(self.context)
 
+        lmpSdmux_hostDisconnect(self.config.sdmux_id)
+        lmpSdmux_dutuSDA(self.config.sdmux_id)
+
         logging.info('powering on')
         self.context.run_command(self.config.power_on_cmd)
 

=== modified file 'setup.py'
--- setup.py	2013-07-17 09:16:24 +0000
+++ setup.py	2013-08-08 13:55:13 +0000
@@ -53,6 +53,7 @@
         "configglue",
         "PyYAML",
         'versiontools >= 1.8',
+        "pyserial",
     ],
     setup_requires=[
         'versiontools >= 1.8',

