Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runtime switching of the USB Mass Storage function #226

Merged
merged 5 commits into from
Dec 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions mtda/console/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,9 @@ def reader(self):
if retries > 0:
print("resetting console to recover from read error "
"({0})...".format(error), file=sys.stderr)
with self.rx_lock:
con.close()
con.open()
con.close()
self.rx_active.wait()
con.open()
error = None
else:
print("failed to reset the console, "
Expand Down
5 changes: 4 additions & 1 deletion mtda/console/serial.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def __init__(self, mtda):
self.rate = 115200
self.opened = False
self.role = 'console'
self.hotplug = False

""" Configure this console from the provided configuration"""
def configure(self, conf, role='console'):
Expand All @@ -50,7 +51,9 @@ def configure_systemd(self, dir):
def probe(self):
self.mtda.debug(3, "console.serial.probe()")

result = os.path.exists(self.port)
result = True
if self.hotplug is False:
result = os.path.exists(self.port)
if result is True:
self.ser = serial.Serial()
self.ser.port = self.port
Expand Down
11 changes: 1 addition & 10 deletions mtda/console/usbf.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class UsbFunctionConsole(SerialConsole):

def __init__(self, mtda):
super().__init__(mtda)
self.hotplug = True
self.port = None
self.rate = 9600
Composite.mtda = mtda
Expand All @@ -36,16 +37,6 @@ def configure(self, conf, role='console'):
def configure_systemd(self, dir):
return None

def probe(self):
self.mtda.debug(3, "console.usbf.probe()")

result = Composite.install()
if result is True:
result = super().probe()

self.mtda.debug(3, "console.usbf.probe(): {}".format(result))
return result


def instantiate(mtda):
return UsbFunctionConsole(mtda)
32 changes: 14 additions & 18 deletions mtda/keyboard/hid.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,11 @@ def configure(self, conf):
def probe(self):
self.mtda.debug(3, "keyboard.hid.probe()")

result = False
result = True
if self.dev is None:
result = False
self.mtda.debug(1, "keyboard.hid.probe(): "
"{} not configured".format(self.dev))
else:
result = Composite.install()
if result is True and os.path.exists(self.dev) is False:
self.mtda.debug(1, "keyboard.hid.probe(): "
"{} not found".format(self.dev))
result = False

self.mtda.debug(3, "keyboard.hid.probe(): {}".format(result))
return result
Expand Down Expand Up @@ -86,17 +81,17 @@ def idle(self):
def press(self, key, mod=0x00, repeat=1):
self.mtda.debug(3, "keyboard.hid.press()")

NULL_CHAR = chr(0)
try:
if self.fd is None:
self.mtda.debug(4, "keyboard.hid.press(): "
"opening {}".format(self.dev))
self.fd = open(self.dev, mode="r+b", buffering=0)
except FileNotFoundError:
self.mtda.debug(0, "keyboard.hid.press(): "
"failed to open {}".format(self.dev))
if os.path.exists(self.dev) is False:
self.mtda.debug(1, "keyboard.hid.press(): "
"{} not found".format(self.dev))
return False

if self.fd is None:
self.mtda.debug(4, "keyboard.hid.press(): "
"opening {}".format(self.dev))
self.fd = open(self.dev, mode="r+b", buffering=0)

NULL_CHAR = chr(0)
result = True
while repeat > 0:
repeat = repeat - 1
Expand Down Expand Up @@ -224,6 +219,7 @@ def tab(self, repeat=1):
def write(self, str):
self.mtda.debug(3, "keyboard.hid.write()")

ret = '\n'
lower_keys = {
'a': 0x04, 'b': 0x05, 'c': 0x06, 'd': 0x07, 'e': 0x08, 'f': 0x09,
'g': 0x0a, 'h': 0x0b, 'i': 0x0c, 'j': 0x0d, 'k': 0x0e, 'l': 0x0f,
Expand All @@ -232,8 +228,8 @@ def write(self, str):
'y': 0x1c, 'z': 0x1d, '1': 0x1e, '2': 0x1f, '3': 0x20, '4': 0x21,
'5': 0x22, '6': 0x23, '7': 0x24, '8': 0x25, '9': 0x26, '0': 0x27,
'!': 0x1e, '@': 0x1f, '#': 0x20, '$': 0x21, '%': 0x22, '^': 0x23,
'&': 0x24, '*': 0x25, '(': 0x26, ')': 0x27, ' ': 0x2c, '-': 0x2d,
'_': 0x2d, '+': 0x2e, '=': 0x2e
'&': 0x24, '*': 0x25, '(': 0x26, ')': 0x27, ret: 0x28, ' ': 0x2c,
'-': 0x2d, '_': 0x2d, '+': 0x2e, '=': 0x2e
}
for k in str:
if k in lower_keys:
Expand Down
39 changes: 38 additions & 1 deletion mtda/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import mtda.video.controller
import mtda.utils
from mtda import __version__
from mtda.support.usb import Composite

try:
www_support = True
Expand Down Expand Up @@ -131,6 +132,33 @@ def command(self, args, session=None):
self.mtda.debug(3, "main.command(): %s" % str(result))
return result

def _composite_start(self):
self.mtda.debug(3, "main._composite_start()")

result = True
storage = self.storage_controller
if storage is not None and storage.variant == 'usbf':
status, _, _ = self.storage_status()
enabled = status == CONSTS.STORAGE.ON_TARGET
self.mtda.debug(3, "main._composite_start(): "
"with storage? {}".format(enabled))
Composite.storage_toggle(enabled)
result = Composite.install()

self.mtda.debug(3, "main._composite_start(): {}".format(result))
return result

def _composite_stop(self):
self.mtda.debug(3, "main._composite_stop()")

result = None
storage = self.storage_controller
if storage is not None and storage.variant == 'usbf':
Composite.remove()

self.mtda.debug(3, "main._composite_stop(): {}".format(result))
return result

def config_set_power_timeout(self, timeout, session=None):
self.mtda.debug(3, "main.config_set_power_timeout()")

Expand Down Expand Up @@ -846,7 +874,14 @@ def _target_on(self, session=None):

result = False
if self.power_locked(session) is False:
result = self.power_controller.on()
# Toggle the mass storage functions of the usbf controller
result = self._composite_start()

# Turn the DUT on
if result is True:
result = self.power_controller.on()

# Resume logging
if result is True:
if self.console_logger is not None:
self.console_logger.resume()
Expand Down Expand Up @@ -922,6 +957,7 @@ def _target_off(self, session=None):
result = True
if self.power_controller is not None:
result = self.power_controller.off()
self._composite_stop()
self._power_event(CONSTS.POWER.OFF)

self.mtda.debug(3, "main._target_off(): {}".format(result))
Expand Down Expand Up @@ -1315,6 +1351,7 @@ def load_storage_config(self, parser):
mod = importlib.import_module("mtda.storage." + variant)
factory = getattr(mod, 'instantiate')
self.storage_controller = factory(self)
self.storage_controller.variant = variant
self._writer = AsyncImageWriter(self, self.storage_controller)
# Configure the storage controller
self.storage_controller.configure(dict(parser.items('storage')))
Expand Down
2 changes: 1 addition & 1 deletion mtda/storage/usbf.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def probe(self):
"device!".format(self.device))
if self.file is not None:
if os.path.exists(self.file) is True:
result = Composite.install()
result = True
else:
self.mtda.debug(1, "storage.usbf.probe(): "
"{} not found!".format(self.file))
Expand Down
76 changes: 57 additions & 19 deletions mtda/support/usb.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,14 @@ class Composite:
_storage = None
_installed = False

functions = []
path = "/sys/kernel/config/usb_gadget/" + product.lower().replace(" ", "_")

def debug(level, msg):
if Composite.mtda is not None:
Composite.mtda.debug(level, msg)

def configure(what, conf):
Composite.debug(3, "composite.configure()")
Composite.debug(3, "composite.configure('{}')".format(what))

with Composite.lock:
result = Composite._configure(what, conf)
Expand All @@ -45,18 +44,18 @@ def configure(what, conf):

def _configure(what, conf):
result = True
if what == 'console':
Composite.functions.append(Composite.console_function)
elif what == 'monitor':
Composite.functions.append(Composite.monitor_function)
elif what == 'keyboard':
Composite.functions.append(Composite.hid_function)
elif what == 'storage':
if 'file' in conf:
Composite._storage = conf['file']
Composite.functions.append(Composite.ms_function)
if what == 'storage' and 'file' in conf:
Composite._storage = conf['file']
if what in Composite.functions:
Composite.functions[what]['configured'] = True
Composite.functions[what]['enabled'] = True
Composite.debug(2, "composite.configure(): "
"{} configured & enabled".format(what))
else:
Composite.debug(1, "composite.configure(): "
"not supported")
result = False

return result

def _enable():
Expand Down Expand Up @@ -86,6 +85,18 @@ def _install():

Composite._remove()

enabled = False
for function in Composite.functions.values():
if function['enabled'] is True:
enabled = True
break

if enabled is False:
# Nothing to install
Composite.debug(2, "composite.install(): "
"no functions were enabled")
return True

atexit.register(Composite.remove)
path = Composite.path
create_dirs(path)
Expand All @@ -106,13 +117,17 @@ def _install():

Composite._create_functions()

if Composite._storage is not None:
if Composite.functions['storage']['enabled'] is True:
lun = path + "/functions/mass_storage.usb0/lun.0/"
file = Composite._storage
write(lun + "cdrom", "0")
write(lun + "ro", "0")
write(lun + "nofua", "0")
write(lun + "file", Composite._storage)
write(lun + "file", file)
Composite.debug(2, "composite.install(): "
"storage device/file: {}".format(file))
Composite._installed = Composite._enable()
return Composite._installed

def remove():
Composite.debug(3, "composite.remove()")
Expand Down Expand Up @@ -145,9 +160,12 @@ def _remove():
Composite._installed = False

def _create_functions():
functions = Composite.functions
for function in functions:
for function in Composite.functions.values():
name = function['name']
if function['configured'] is False:
continue
if function['enabled'] is False:
continue
Composite.debug(2, "composite._create_functions: "
"registering {}".format(name))
path = Composite.path + "/functions/" + name
Expand All @@ -165,8 +183,15 @@ def _create_functions():
if not os.path.exists(config):
os.symlink(path, config, True)

def storage_toggle(enabled):
with Composite.lock:
if Composite.functions['storage']['configured'] is True:
Composite.functions['storage']['enabled'] = enabled

hid_function = {
"name": "hid.usb0",
"configured": False,
"enabled": False,
"protocol": "1",
"subclass": "1",
"report_length": "8",
Expand Down Expand Up @@ -207,15 +232,28 @@ def _create_functions():
}

console_function = {
"name": "acm.GS0"
"name": "acm.GS0",
"configured": False,
"enabled": False
}

monitor_function = {
"name": "acm.GS1"
"name": "acm.GS1",
"configured": False,
"enabled": False
}

ms_function = {
"name": "mass_storage.usb0"
"name": "mass_storage.usb0",
"configured": False,
"enabled": False
}

functions = {
"console": console_function,
"monitor": monitor_function,
"keyboard": hid_function,
"storage": ms_function
}


Expand Down