diff --git a/settings.conf b/settings.conf
index e1243402619184874d84028ee8e529a0390f3196..0b0bd72382e6302ffbbc2f5ce9a20e9c28b26930 100644
--- a/settings.conf
+++ b/settings.conf
@@ -81,7 +81,7 @@ sequence:
   - initcpio
   - users
   - displaymanager
-  - hardwarecfg
+  - mhwdcfg
   - networkcfg
   - hwclock
   - services
diff --git a/src/modules/bootloader/main.py b/src/modules/bootloader/main.py
index e0125ee64e7ac3f20f31255958037b12af21f993..d292de6fda4676cb5426d9993a7f0ae7a3c52d65 100644
--- a/src/modules/bootloader/main.py
+++ b/src/modules/bootloader/main.py
@@ -220,15 +220,14 @@ def install_grub(efi_directory, fw_type):
                                "--force"])
 
         # VFAT is weird, see issue CAL-385
-        efi_directory_firmware = case_insensitive_subdir(efi_directory,
-                                                         ["EFI", "Efi", "efi"])
-        if not efi_directory_firmware:
-            efi_directory_firmware = os.path.join(efi_directory, "EFI")
-
-        efi_boot_directory = case_insensitive_subdir(efi_directory_firmware,
-                                                     ["Boot", "boot", "BOOT"])
-        if not efi_boot_directory:
-            efi_boot_directory = os.path.join(efi_directory_firmware, "boot")
+        efi_directory_firmware = os.path.join(efi_directory, "EFI")
+        if os.path.exists(efi_directory_firmware):
+            efi_directory_firmware = vfat_correct_case(efi_directory, "EFI")
+
+        efi_boot_directory = os.path.join(efi_directory_firmware, "boot")
+        if os.path.exists(efi_boot_directory):
+            efi_boot_directory = vfat_correct_case(efi_directory_firmware, "boot")
+        else:
             check_target_env_call(["mkdir", "-p", efi_boot_directory])
 
         # Workaround for some UEFI firmwares
@@ -251,11 +250,11 @@ def install_grub(efi_directory, fw_type):
                            libcalamares.job.configuration["grubCfg"]])
 
 
-def case_insensitive_subdir(parent, candidate_dirnames):
-    for dirname in candidate_dirnames:
-        if os.path.isdir(os.path.join(parent, dirname)):
-            return os.path.join(parent, dirname)
-    return ""
+def vfat_correct_case(parent, name):
+    for candidate in os.listdir(parent):
+        if name.lower() == candidate.lower():
+            return candidate
+    return os.path.join(parent, name)
 
 
 def prepare_bootloader(fw_type):
diff --git a/src/modules/hardwarecfg/main.py b/src/modules/hardwarecfg/main.py
deleted file mode 100644
index 08c49b3c8ab53829ee46af173c43fc29c81d71d9..0000000000000000000000000000000000000000
--- a/src/modules/hardwarecfg/main.py
+++ /dev/null
@@ -1,119 +0,0 @@
-#!/usr/bin/env python3
-# encoding: utf-8
-# === This file is part of Calamares - <http://github.com/calamares> ===
-#
-#   Copyright 2014, Philip Müller <philm@manjaro.org>
-#
-#   Calamares 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 3 of the License, or
-#   (at your option) any later version.
-#
-#   Calamares 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 Calamares. If not, see <http://www.gnu.org/licenses/>.
-
-import os
-import subprocess
-
-import libcalamares
-
-import shutil
-
-def run():
-    """ Configure the hardware """
-
-    install_path = libcalamares.globalstorage.value( "rootMountPoint" )
-
-    # Copy generated xorg.xonf to target
-    if os.path.exists("/etc/X11/xorg.conf"):
-        shutil.copy2('/etc/X11/xorg.conf',
-             os.path.join(install_path, 'etc/X11/xorg.conf'))
-
-    # TODO: Maybe we can drop this
-    # Configure ALSA
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Master 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Front 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Side 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Surround 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Center 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset LFE 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Headphone 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Speaker 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset PCM 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Line 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset External 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset FM 50% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Master Mono 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Master Digital 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Analog Mix 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Aux 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Aux2 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset PCM Center 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset PCM Front 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset PCM LFE 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset PCM Side 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset PCM Surround 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Playback 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset PCM,1 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset DAC 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset DAC,0 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset DAC,1 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Synth 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset CD 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Wave 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Music 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset AC97 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Analog Front 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset VIA DXS,0 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset VIA DXS,1 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset VIA DXS,2 70% unmute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset VIA DXS,3 70% unmute'])
-
-    # set input levels
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Mic 70% mute'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset IEC958 70% mute'])
-
-    # special stuff
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Master Playback Switch on'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Master Surround on'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset SB Live Analog/Digital Output Jack off'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Audigy Analog/Digital Output Jack off'])
-
-    # special stuff
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Master Playback Switch on'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Master Surround on'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset SB Live Analog/Digital Output Jack off'])
-    libcalamares.utils.target_env_call(['sh', '-c', 'amixer -c 0 sset Audigy Analog/Digital Output Jack off'])
-
-    # Set pulse
-    if os.path.exists("/usr/bin/pulseaudio-ctl"):
-        libcalamares.utils.target_env_call(['pulseaudio-ctl', 'normal'])
-
-    # Save settings
-    libcalamares.utils.target_env_call(['alsactl', '-f', '/etc/asound.state', 'store'])
-
-    if os.path.exists("/opt/livecd"):
-        repo_path="/opt/livecd/pacman-gfx.conf"
-    else:
-        repo_path="/opt/live/pacman-gfx.conf"
-
-    # Install xf86-video driver
-    if os.path.exists(repo_path):
-        # TODO: get mhwd-script path or port it to python
-        mhwd_script_path = '/usr/lib/calamares/modules/hardwarecfg/mhwd.sh'
-        #try:
-        subprocess.check_call(["/usr/bin/bash", mhwd_script_path, install_path])
-
-    # Remove virtualbox driver on real hardware
-    p1 = subprocess.Popen(["mhwd"], stdout=subprocess.PIPE)
-    p2 = subprocess.Popen(["grep", "0300:80ee:beef"], stdin=p1.stdout, stdout=subprocess.PIPE)
-    num_res = p2.communicate()[0]
-    if num_res == "0":
-        libcalamares.utils.target_env_call(['sh', '-c', 'pacman -Rsc --noconfirm $(pacman -Qq | grep virtualbox-guest-modules)'])
-
-    return None
diff --git a/src/modules/hardwarecfg/mhwd.sh b/src/modules/hardwarecfg/mhwd.sh
deleted file mode 100755
index cec0323845cabe86dc6db1567657c6a48eef7e4d..0000000000000000000000000000000000000000
--- a/src/modules/hardwarecfg/mhwd.sh
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/sh
-kernel_cmdline ()
-{
-    for param in $(/bin/cat /proc/cmdline); do
-        case "${param}" in
-            $1=*) echo "${param##*=}"; return 0 ;;
-            $1) return 0 ;;
-            *) continue ;;
-        esac
-    done
-    [ -n "${2}" ] && echo "${2}"
-    return 1
-}
-
-USENONFREE="$(kernel_cmdline nonfree no)"
-VIDEO="$(kernel_cmdline xdriver no)"
-DESTDIR="$1"
-
-REPO_PATH=/opt/live
-[ -d /opt/livecd ] && REPO_PATH=/opt/livecd
-PAC_CONF=${REPO_PATH}/pacman-gfx.conf
-
-echo "MHWD-Driver: ${USENONFREE}"
-echo "MHWD-Video: ${VIDEO}"
-
-mkdir -p ${DESTDIR}${REPO_PATH}
-mount -o bind ${REPO_PATH} ${DESTDIR}${REPO_PATH} > /tmp/mount.pkgs.log
-ls ${DESTDIR}${REPO_PATH} >> /tmp/mount.pkgs.log
-
-# Video driver
-if  [ "${USENONFREE}" == "yes" ] || [ "${USENONFREE}" == "true" ]; then
-	if  [ "${VIDEO}" == "vesa" ]; then
-		chroot ${DESTDIR} mhwd --install pci video-vesa --pmconfig "${PAC_CONF}"
-	else
-		chroot ${DESTDIR} mhwd --auto pci nonfree 0300 --pmconfig "${PAC_CONF}"
-	fi
-else
-	if  [ "${VIDEO}" == "vesa" ]; then
-		chroot ${DESTDIR} mhwd --install pci video-vesa --pmconfig "${PAC_CONF}"
-	else
-		chroot ${DESTDIR} mhwd --auto pci free 0300 --pmconfig "${PAC_CONF}"
-	fi
-fi
-
-# Network driver
-chroot ${DESTDIR} mhwd --auto pci free 0200 --pmconfig "${PAC_CONF}"
-chroot ${DESTDIR} mhwd --auto pci free 0280 --pmconfig "${PAC_CONF}"
-
-umount ${DESTDIR}${REPO_PATH}
-rmdir ${DESTDIR}${REPO_PATH}
diff --git a/src/modules/mhwdcfg/main.py b/src/modules/mhwdcfg/main.py
new file mode 100644
index 0000000000000000000000000000000000000000..4b560ba8d31b265e27ada0410003f72772f8fa8a
--- /dev/null
+++ b/src/modules/mhwdcfg/main.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# === This file is part of Calamares - <http://github.com/calamares> ===
+#
+#   Copyright 2016, Artoo <artoo@manjaro.org>
+#
+#   Calamares 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 3 of the License, or
+#   (at your option) any later version.
+#
+#   Calamares 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 Calamares. If not, see <http://www.gnu.org/licenses/>.
+
+import libcalamares
+
+from libcalamares.utils import target_env_call, debug
+from os.path import join
+from subprocess import call
+
+class MhwdController:
+	def __init__(self):
+		self.__root = libcalamares.globalstorage.value( "rootMountPoint" )
+		self.__bus = libcalamares.job.configuration.get('bus', [])
+		self.__identifier = libcalamares.job.configuration.get('identifier', [])
+		self.__local = libcalamares.job.configuration['local']
+		self.__repo = libcalamares.job.configuration['repo']
+		self._driver = libcalamares.job.configuration['driver']
+
+	@property
+	def driver(self):
+		return self._driver
+
+	@driver.setter
+	def driver(self, value):
+		self._driver = value
+
+	@property
+	def root(self):
+		return self.__root
+
+	@property
+	def local(self):
+		return self.__local
+
+	@property
+	def repo(self):
+		return self.__repo
+
+	@property
+	def identifier(self):
+		return self.__identifier
+
+	@property
+	def bus(self):
+		return self.__bus
+
+	def umount(self, mp):
+		call(["umount", "-l", join(self.root, mp)])
+
+	def mount(self, mp):
+		call(["mount", "-Br", "/" + mp, join(self.root, mp)])
+
+	def configure(self, name, id):
+		cmd = ["mhwd", "-a", str(name), str(self.driver), str(id).zfill(4)]
+		if self.local:
+			self.mount("opt")
+			cmd.extend(["--pmconfig", self.repo])
+
+		self.mount("etc/resolv.conf")
+		target_env_call(cmd)
+
+		if self.local:
+			self.umount("opt")
+		self.umount("etc/resolv.conf")
+
+	def run(self):
+		for b in self.bus:
+			for id in self.identifier['net']:
+					self.configure(b, id)
+			for id in self.identifier['video']:
+					self.configure(b, id)
+
+		return None
+
+def run():
+	""" Configure the hardware """
+
+	mhwd = MhwdController()
+
+	return mhwd.run()
diff --git a/src/modules/mhwdcfg/mhwdcfg.conf b/src/modules/mhwdcfg/mhwdcfg.conf
new file mode 100644
index 0000000000000000000000000000000000000000..18db7fbeabe4c3eb8088244314980af39e6eb325
--- /dev/null
+++ b/src/modules/mhwdcfg/mhwdcfg.conf
@@ -0,0 +1,19 @@
+---
+bus:
+    - pci
+#    - usb
+
+identifier:
+    net:
+      - 200
+      - 280
+    video:
+      - 300
+      - 302
+      - 380
+
+driver: free
+
+local: true
+
+repo: /opt/pacman-mhwd.conf
diff --git a/src/modules/hardwarecfg/module.desc b/src/modules/mhwdcfg/module.desc
similarity index 83%
rename from src/modules/hardwarecfg/module.desc
rename to src/modules/mhwdcfg/module.desc
index 0a05af30fbcb4b536ae373b2882ae1238fe129a7..1e719bb0bdcab6cc665ade18fa920937a552d9ec 100644
--- a/src/modules/hardwarecfg/module.desc
+++ b/src/modules/mhwdcfg/module.desc
@@ -1,6 +1,6 @@
 # Syntax is YAML 1.2
 ---
 type:       "job"
-name:       "hardwarecfg"
+name:       "mhwdcfg"
 interface:  "python"
 script:     "main.py"   #assumed relative to the current directory
diff --git a/src/modules/welcome/WelcomeViewStep.cpp b/src/modules/welcome/WelcomeViewStep.cpp
index ca24254e8733646db33376c72b662d2aa227c6db..3c9d29993625cd060a0cc1fa8ab59ef15774b67b 100644
--- a/src/modules/welcome/WelcomeViewStep.cpp
+++ b/src/modules/welcome/WelcomeViewStep.cpp
@@ -20,6 +20,7 @@
 
 #include "WelcomePage.h"
 #include "checker/RequirementsChecker.h"
+#include "utils/Logger.h"
 
 
 #include <QVariant>
@@ -128,5 +129,8 @@ WelcomeViewStep::setConfigurationMap( const QVariantMap& configurationMap )
     if ( configurationMap.contains( "requirements" ) &&
          configurationMap.value( "requirements" ).type() == QVariant::Map )
         m_requirementsChecker->setConfigurationMap( configurationMap.value( "requirements" ).toMap() );
+    else
+        cDebug() << "WARNING: no valid requirements map found in welcome "
+                    "module configuration.";
 }
 
diff --git a/src/modules/welcome/checker/RequirementsChecker.cpp b/src/modules/welcome/checker/RequirementsChecker.cpp
index 0a7233e3dcae24f8cdcaf9623b27e9cfba2705f9..a8207a87624fe97224ce1d5e54e42f1661ea2060 100644
--- a/src/modules/welcome/checker/RequirementsChecker.cpp
+++ b/src/modules/welcome/checker/RequirementsChecker.cpp
@@ -185,6 +185,7 @@ RequirementsChecker::widget() const
 void
 RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
 {
+    bool incompleteConfiguration = false;
     if ( configurationMap.contains( "requiredStorage" ) &&
          ( configurationMap.value( "requiredStorage" ).type() == QVariant::Double ||
            configurationMap.value( "requiredStorage" ).type() == QVariant::Int ) )
@@ -199,6 +200,7 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
     else
     {
         m_requiredStorageGB = 3.;
+        incompleteConfiguration = true;
     }
 
     if ( configurationMap.contains( "requiredRam" ) &&
@@ -208,11 +210,15 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
         bool ok = false;
         m_requiredRamGB = configurationMap.value( "requiredRam" ).toDouble( &ok );
         if ( !ok )
+        {
             m_requiredRamGB = 1.;
+            incompleteConfiguration = true;
+        }
     }
     else
     {
         m_requiredRamGB = 1.;
+        incompleteConfiguration = true;
     }
 
     if ( configurationMap.contains( "check" ) &&
@@ -221,6 +227,8 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
         m_entriesToCheck.clear();
         m_entriesToCheck.append( configurationMap.value( "check" ).toStringList() );
     }
+    else
+        incompleteConfiguration = true;
 
     if ( configurationMap.contains( "required" ) &&
          configurationMap.value( "required" ).type() == QVariant::List )
@@ -228,6 +236,19 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
         m_entriesToRequire.clear();
         m_entriesToRequire.append( configurationMap.value( "required" ).toStringList() );
     }
+    else
+        incompleteConfiguration = true;
+
+    if ( incompleteConfiguration )
+    {
+        cDebug() << "WARNING: The RequirementsChecker configuration map provided by "
+                    "the welcome module configuration file is incomplete or "
+                    "incorrect.\n"
+                    "Startup will continue for debugging purposes, but one or "
+                    "more checks might not function correctly.\n"
+                    "RequirementsChecker configuration map:\n"
+                 << configurationMap;
+    }
 }