[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[tyndur-devel] [PATCH 3/3] USB-Stack



From: Max Reitz <max@xxxxxxxxxx>

+ UHCI-Treiber für Control/Bulk und natürlich die Initialisierung
+ USB-1.x-Treiber für Control/Bulk und Hubs (die auf echter Hardware
  aber noch leichte Probleme bereiten)
+ USB-MSC-Treiber für Bulk-Only und CBI (wobei letzteres noch nicht
  so richtig arbeitet); mit Debugausgaben, damit man sieht, dass auch
  etwas passiert

Signed-off-by: Max Reitz <max@xxxxxxxxxx>
---
 src/modules/usb/include/usb-ddrv.h    |   59 +++++
 src/modules/usb/include/usb-hc.h      |  141 +++++++++++
 src/modules/usb/include/usb-hub.h     |   49 ++++
 src/modules/usb/include/usb-server.h  |  153 ++++++++++++
 src/modules/usb/include/usb-structs.h |  176 +++++++++++++
 src/modules/usb/include/usb-trans.h   |   66 +++++
 src/modules/usb/msd/Makefile.all      |    8 +
 src/modules/usb/msd/init.c            |  197 +++++++++++++++
 src/modules/usb/msd/lostio.c          |  218 ++++++++++++++++
 src/modules/usb/msd/main.c            |   65 +++++
 src/modules/usb/msd/msd-bo.c          |  104 ++++++++
 src/modules/usb/msd/msd-bo.h          |   99 ++++++++
 src/modules/usb/msd/msd-cbi.c         |   86 +++++++
 src/modules/usb/msd/msd-cbi.h         |   71 ++++++
 src/modules/usb/msd/msd.h             |  146 +++++++++++
 src/modules/usb/msd/rpc.c             |   83 ++++++
 src/modules/usb/msd/scsi.c            |  240 ++++++++++++++++++
 src/modules/usb/msd/scsi.h            |  219 ++++++++++++++++
 src/modules/usb/msd/usb-lib.c         |  207 ++++++++++++++++
 src/modules/usb/msd/usb-lib.h         |  124 +++++++++
 src/modules/usb/uhci/Makefile.all     |    8 +
 src/modules/usb/uhci/ctrl.c           |   96 +++++++
 src/modules/usb/uhci/init.c           |  265 ++++++++++++++++++++
 src/modules/usb/uhci/main.c           |   73 ++++++
 src/modules/usb/uhci/rpc.c            |  297 ++++++++++++++++++++++
 src/modules/usb/uhci/trans.c          |  316 +++++++++++++++++++++++
 src/modules/usb/uhci/uhci.h           |  269 ++++++++++++++++++++
 src/modules/usb/usb1/Makefile.all     |    8 +
 src/modules/usb/usb1/detect.c         |  440 +++++++++++++++++++++++++++++++++
 src/modules/usb/usb1/hub.c            |  180 ++++++++++++++
 src/modules/usb/usb1/main.c           |   59 +++++
 src/modules/usb/usb1/rpc.c            |  327 ++++++++++++++++++++++++
 src/modules/usb/usb1/transfer.c       |  123 +++++++++
 src/modules/usb/usb1/usb.h            |  209 ++++++++++++++++
 34 files changed, 5181 insertions(+), 0 deletions(-)
 create mode 100644 src/modules/usb/include/usb-ddrv.h
 create mode 100644 src/modules/usb/include/usb-hc.h
 create mode 100644 src/modules/usb/include/usb-hub.h
 create mode 100644 src/modules/usb/include/usb-server.h
 create mode 100644 src/modules/usb/include/usb-structs.h
 create mode 100644 src/modules/usb/include/usb-trans.h
 create mode 100644 src/modules/usb/msd/Makefile.all
 create mode 100644 src/modules/usb/msd/init.c
 create mode 100644 src/modules/usb/msd/lostio.c
 create mode 100644 src/modules/usb/msd/main.c
 create mode 100644 src/modules/usb/msd/msd-bo.c
 create mode 100644 src/modules/usb/msd/msd-bo.h
 create mode 100644 src/modules/usb/msd/msd-cbi.c
 create mode 100644 src/modules/usb/msd/msd-cbi.h
 create mode 100644 src/modules/usb/msd/msd.h
 create mode 100644 src/modules/usb/msd/rpc.c
 create mode 100644 src/modules/usb/msd/scsi.c
 create mode 100644 src/modules/usb/msd/scsi.h
 create mode 100644 src/modules/usb/msd/usb-lib.c
 create mode 100644 src/modules/usb/msd/usb-lib.h
 create mode 100644 src/modules/usb/uhci/Makefile.all
 create mode 100644 src/modules/usb/uhci/ctrl.c
 create mode 100644 src/modules/usb/uhci/init.c
 create mode 100644 src/modules/usb/uhci/main.c
 create mode 100644 src/modules/usb/uhci/rpc.c
 create mode 100644 src/modules/usb/uhci/trans.c
 create mode 100644 src/modules/usb/uhci/uhci.h
 create mode 100644 src/modules/usb/usb1/Makefile.all
 create mode 100644 src/modules/usb/usb1/detect.c
 create mode 100644 src/modules/usb/usb1/hub.c
 create mode 100644 src/modules/usb/usb1/main.c
 create mode 100644 src/modules/usb/usb1/rpc.c
 create mode 100644 src/modules/usb/usb1/transfer.c
 create mode 100644 src/modules/usb/usb1/usb.h

diff --git a/src/modules/usb/include/usb-ddrv.h b/src/modules/usb/include/usb-ddrv.h
new file mode 100644
index 0000000..d213cd7
--- /dev/null
+++ b/src/modules/usb/include/usb-ddrv.h
@@ -0,0 +1,59 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#ifndef USB_DDRV_H
+#define USB_DDRV_H
+
+#include <stdbool.h>
+
+
+#define RPC_USB_DDRV_PLUG_FNN "USB_DDRV_PLUG"
+
+// Ein Wert ist -1, wenn der Treiber alle Geräte annimmt.
+struct usb_handle_devs {
+    int vendor_id, device_id;
+    int class, subclass, protocol;
+};
+
+// Wird vom USB-Bustreiber an einen Gerätetreiber weitergegeben, wenn ein Gerät
+// gefunden wurde
+struct usb_prov_dev {
+    // Handelt es sich beim Gerät um ein Interface und nicht um ein physisches
+    // Gerät, so ist dies true
+    bool is_interface;
+    // Geräte-ID (vom USB-Bustreiber zu verwenden)
+    void* dev_id;
+    // Interface-ID
+    int interface_id;
+    // Typ des Geräts
+    struct usb_handle_devs type;
+};
+
+#endif
diff --git a/src/modules/usb/include/usb-hc.h b/src/modules/usb/include/usb-hc.h
new file mode 100644
index 0000000..a70598a
--- /dev/null
+++ b/src/modules/usb/include/usb-hc.h
@@ -0,0 +1,141 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#ifndef USB_HC_H
+#define USB_HC_H
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+#include "usb-structs.h"
+#include "usb-trans.h"
+
+// Beschreibt einen USB-Hostcontroller
+struct usb_hc {
+    // Anzahl der Rootports
+    int root_ports;
+    // Für den HCD frei verfügbar
+    void* hcd_avail;
+    // PID des HCD
+    pid_t pid;
+    // USB-Adressenzähler
+    int addr_counter;
+};
+
+// RPC-Funktion für USB-Bustreiber (vorrangig Roothubfunktionen)
+#define RPC_USB_HC_CONTROL_FNN "HC_CONTROL"
+// RPC-Funktion für USB-Bustreiber (vorrangig Transferfunktionen)
+#define RPC_USB_HC_TRANSFER_FNN "HC_TRANSFER"
+
+// PIDs für IN, OUT und SETUP
+#define USB_OUT   0xE1
+#define USB_IN    0x69
+#define USB_SETUP 0x2D
+
+// Roothubfunktionen
+enum usb_hc_ctrl_rt {
+    // Portstatus überprüfen
+    HC_CTRL_SCAN_PORT = 0,
+    // Port deaktivieren
+    HC_CTRL_DSBL_PORT,
+    // Resetsignal treiben
+    HC_CTRL_RESET,
+    // Pipe erstellen
+    HC_CTRL_ADD_PIPE
+};
+
+
+// Allgemeiner HC_CONTROL-Request
+struct usb_hc_ctrl_req {
+    // Funktion
+    enum usb_hc_ctrl_rt type;
+    // Hostcontroller
+    struct usb_hc hc;
+};
+
+// Rootport überprüfen
+struct usb_hc_ctrl_scan {
+    struct usb_hc_ctrl_req req;
+    // Portindex
+    int port;
+};
+
+// Rootport deaktivieren
+struct usb_hc_ctrl_dsbl {
+    struct usb_hc_ctrl_req req;
+    // Portindex
+    int port;
+};
+
+// Resetsignal an einem Rootport treiben
+struct usb_hc_ctrl_rst {
+    struct usb_hc_ctrl_req req;
+    // Portindex
+    int port;
+};
+
+// Pipe hinzufügen
+struct usb_hc_ctrl_appe {
+    struct usb_hc_ctrl_req req;
+    // Informationen zur neuen Pipe
+    struct usb_trans_pipe pipe;
+};
+
+// Allgemeine Transferanfrage
+struct usb_hc_trs {
+    // Funktion
+    enum usb_trans_type type;
+    // Hostcontroller
+    struct usb_hc hc;
+    // Pipe, durch die der Transfer laufen soll
+    struct usb_trans_pipe pipe;
+};
+
+// Controltransfer
+struct usb_hc_trs_ctrl {
+    struct usb_hc_trs trs;
+    // SETUP-Paket
+    struct usb_setup_packet setup;
+    // SHM-Bereich für die Datenphase
+    uint32_t shm;
+};
+
+// Bulktransfer
+struct usb_hc_trs_bulk {
+    struct usb_hc_trs trs;
+    // true zum Empfangen
+    bool receive;
+    // Anzahl der zu übertragenden Bytes
+    size_t length;
+    // SHM-Bereich für die übertragenen Daten
+    uint32_t shm;
+};
+
+#endif
diff --git a/src/modules/usb/include/usb-hub.h b/src/modules/usb/include/usb-hub.h
new file mode 100644
index 0000000..478c2bc
--- /dev/null
+++ b/src/modules/usb/include/usb-hub.h
@@ -0,0 +1,49 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#ifndef USB_HUB_H
+#define USB_HUB_H
+
+// In den unteren acht Bits wird die Geschwindigkeit gespeichert (viel Platz
+// für zukünftige Neuerungen...)
+#define USB_HUB_SPEED      0xFF
+// Low Speed
+#define USB_HUB_LOW_SPEED  (1 << 0)
+// Full Speed
+#define USB_HUB_FULL_SPEED (1 << 1)
+// High Speed
+#define USB_HUB_HIGH_SPEED (1 << 2)
+
+// Gerät angeschlossen
+#define USB_HUB_DEVICE     (1 << 8)
+// Status hat sich seit der letzten Anfrage verändert
+#define USB_HUB_CHANGE     (1 << 9)
+
+#endif
diff --git a/src/modules/usb/include/usb-server.h b/src/modules/usb/include/usb-server.h
new file mode 100644
index 0000000..6a98707
--- /dev/null
+++ b/src/modules/usb/include/usb-server.h
@@ -0,0 +1,153 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#ifndef USB_SERVER_H
+#define USB_SERVER_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "usb-ddrv.h"
+#include "usb-server.h"
+#include "usb-structs.h"
+#include "usb-trans.h"
+
+// Funktion zum Registrieren von Hostcontrollern
+#define RPC_USB_SV_REGHC_FNN "HCD_REG"
+// Funktion zum Registrieren von Gerätetreibern
+#define RPC_USB_SV_REGDD_FNN "DDRV_REG"
+// Funktion zur Steuerung von Geräten (Daten austauschen, etc.)
+#define RPC_USB_SV_DEVCT_FNN "DEV_CTL"
+
+// Beschreibt eine USB-Pipe
+struct usb_pipe {
+    // Da die von normalen Treibern sowieso nicht dereferenziert werden dürfen,
+    // können diese Strukturen auch undefiniert bleiben.
+    // USB-Gerät (nur für den Bustreiber)
+    struct usb_device* dev;
+    // Endpunktdeskriptor (nur für den Bustreiber)
+    struct usb_endpoint_descriptor* ep;
+
+    // Pipe, zur Kommunikation mit dem Hostcontroller
+    struct usb_trans_pipe trs;
+};
+
+// Funktionen für DEV_CTRL (mit Rückgabetypen)
+enum usb_devctrl_reqtype {
+    // Gibt Anzahl der Endpunkte zurück
+    USB_DC_NUM_ENDPOINTS = 0, // int
+    // Gibt die Interface-ID zurück
+    USB_DC_GET_IFC_ID, // int
+    // Gibt den Endpunktdeskriptor zurück
+    USB_DC_GET_ENDPOINT, // response
+    // Gibt eine Pipe zurück (und erstellt sie)
+    USB_DC_GET_PIPE, // response
+    // Entstallt eine Pipe/den Endpunkt
+    USB_DC_CLEAR_HALT, // int
+    // Führt einen Controltransfer durch
+    USB_DC_TRSF_CONTROL, // int
+    // Führt einen Bulktransfer durch
+    USB_DC_TRSF_BULK // int
+};
+
+// Allgemeine Anfrage für DEV_CTRL
+struct usb_devctrl_req {
+    // Typ der Anrage
+    enum usb_devctrl_reqtype type;
+};
+
+// Gibt die Anzahl der Endpunkte zurück
+struct usb_devctrl_gne {
+    struct usb_devctrl_req req;
+    // Abzufragendes USB-Gerät
+    struct usb_prov_dev dev;
+};
+
+// Gibt die Interface-ID zurück
+struct usb_devctrl_gii {
+    struct usb_devctrl_req req;
+    // Abzufrasgendes USB-Gerät
+    struct usb_prov_dev dev;
+};
+
+// Gibt den Endpunktdeskriptor zurück
+struct usb_devctrl_gep {
+    struct usb_devctrl_req req;
+    // USB-Gerät
+    struct usb_prov_dev dev;
+    // Nummer des Endpunkts (nicht die ID)
+    int ep_number;
+};
+
+// Erstellt eine USB-Pipe und gibt sie zurück
+struct usb_devctrl_gpp {
+    struct usb_devctrl_req req;
+    // USB-Gerät
+    struct usb_prov_dev dev;
+    // Nummer des Zielendpunkts
+    int ep_number;
+};
+
+// Entstallt eine Pipe resp. den Endpunkt
+struct usb_devctrl_clh {
+    struct usb_devctrl_req req;
+    // USB-Pipe
+    struct usb_pipe pipe;
+};
+
+// Führt einen Controltransfer durch
+struct usb_devctrl_tct {
+    struct usb_devctrl_req req;
+    // Ist EP0 das Ziel, so muss dev_id auf den Wert aus usb_prov_dev gesetzt
+    // werden, sonst pipe auf die entsprechende USB-Pipe.
+    union {
+        struct usb_pipe pipe;
+        void* dev_id;
+    } dst;
+    // true, wenn durch die Default Control Pipe übertragen werden soll
+    bool ep0;
+    // SETUP-Paket
+    struct usb_setup_packet setup;
+    // SHM-Bereich für die Datenphase
+    uint32_t shm;
+};
+
+// Führt einen Bulktransfer durch
+struct usb_devctrl_tbk {
+    struct usb_devctrl_req req;
+    // USB-Pipe
+    struct usb_pipe pipe;
+    // Anzahl der zu übertragenden Bytes
+    size_t length;
+    // SHM-Bereich für die Daten
+    uint32_t shm;
+};
+
+#endif
diff --git a/src/modules/usb/include/usb-structs.h b/src/modules/usb/include/usb-structs.h
new file mode 100644
index 0000000..f0b5927
--- /dev/null
+++ b/src/modules/usb/include/usb-structs.h
@@ -0,0 +1,176 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#ifndef USB_STRUCTS_H
+#define USB_STRUCTS_H
+
+#include <stdint.h>
+
+#define USB_LOW_SPEED  USB_HUB_LOW_SPEED
+#define USB_FULL_SPEED USB_HUB_FULL_SPEED
+#define USB_HIGH_SPEED USB_HUB_HIGH_SPEED
+
+enum usb_state {
+    USB_ATTACHED = 0,
+    USB_POWERED,
+    USB_DEFAULT,
+    USB_ADDRESS,
+    USB_CONFIGURED,
+    USB_SUSPENDED
+};
+
+struct usb_setup_packet {
+    uint8_t type;
+    uint8_t request;
+    uint16_t value;
+    uint16_t index;
+    uint16_t length;
+} __attribute__((packed));
+
+struct usb_descriptor {
+    uint8_t length;
+    uint8_t desc_type;
+} __attribute__((packed));
+
+
+#define USB_SETUP_OUT     (0 << 7)
+#define USB_SETUP_IN      (1 << 7)
+#define USB_SETUP_REQ_STD (0 << 5)
+#define USB_SETUP_REQ_CLS (1 << 5)
+#define USB_SETUP_REQ_VDR (2 << 5)
+#define USB_SETUP_REC_DEV 0
+#define USB_SETUP_REC_IF  1
+#define USB_SETUP_REC_EP  2
+#define USB_SETUP_REC_OTH 3
+
+enum usb_setup_requst {
+    USB_GET_STATUS = 0,
+    USB_CLEAR_FEATURE = 1,
+    USB_SET_FEATURE = 3,
+    USB_SET_ADDRESS = 5,
+    USB_GET_DESCRIPTOR = 6,
+    USB_SET_DESCRIPTOR = 7,
+    USB_GET_CONFIGURATION = 8,
+    USB_SET_CONFIGURATION = 9,
+    USB_GET_INTERFACE = 10,
+    USB_SET_INTERFACE = 11,
+    USB_SYNC_FRAME = 12
+};
+
+enum usb_features {
+    USB_ENDPOINT_HALT = 0,
+    USB_DEVICE_REMOTE_WAKEUP = 1,
+    USB_TEST_MODE = 2
+};
+
+enum usb_setup_descriptor {
+    USB_DESC_DEVICE = 1 << 8,
+    USB_DESC_CONFIGURATION = 2 << 8,
+    USB_DESC_STRING = 3 << 8,
+    USB_DESC_INTERFACE = 4 << 8,
+    USB_DESC_ENDPOINT = 5 << 8,
+    USB_DESC_DEVICE_QUALIFIER = 6 << 8,
+    USB_DESC_OTHER_SPEED_CONFIGURATION = 7 << 8,
+    USB_DESC_INTERFACE_POWER = 8 << 8,
+
+    USB_DESC_HUB = 41 << 8
+};
+
+struct usb_device_descriptor {
+    struct usb_descriptor desc;
+    uint16_t bcd_usb;
+    uint8_t class, subclass, protocol;
+    uint8_t mps0;
+    uint16_t vendor_id, device_id;
+    uint16_t bcd_device;
+    uint8_t i_manufacturer, i_product, i_serial;
+    uint8_t num_configurations;
+} __attribute__((packed));
+
+struct usb_config_descriptor
+{
+    struct usb_descriptor desc;
+    uint16_t total_length;
+    uint8_t num_interfaces;
+    uint8_t configuration_value;
+    uint8_t i_configuration;
+    unsigned rsvd0         : 5;
+    unsigned remote_wakeup : 1;
+    unsigned self_powered  : 1;
+    unsigned rsvd1         : 1;
+    uint8_t max_power;
+} __attribute__((packed));
+
+struct usb_interface_descriptor
+{
+    struct usb_descriptor desc;
+    uint8_t interface_number;
+    uint8_t alternate_setting;
+    uint8_t num_endpoints;
+    uint8_t class, subclass, protocol;
+    uint8_t i_interface;
+} __attribute__((packed));
+
+#define USB_EP_CONTROL     0
+#define USB_EP_ISOCHRONOUS 1
+#define USB_EP_BULK        2
+#define USB_EP_INTERRUPT   3
+
+struct usb_endpoint_descriptor {
+    struct usb_descriptor desc;
+    unsigned number    : 4;
+    unsigned rsvd1     : 3;
+    unsigned direction : 1;
+    unsigned type  : 2;
+    unsigned sync  : 2;
+    unsigned usage : 2;
+    unsigned rsvd2 : 2;
+    unsigned mps       : 11;
+    unsigned trans_opp : 2;
+    unsigned rsvd3     : 3;
+    uint8_t interval;
+} __attribute__((packed));
+
+struct usb_hub_descriptor {
+    struct usb_descriptor desc;
+    uint8_t nbr_ports;
+    unsigned power_mode : 2;
+    unsigned compound   : 1;
+    unsigned oc_protect : 2;
+    unsigned tt         : 2;
+    unsigned pindicator : 1;
+    uint8_t rsvd;
+    uint8_t pwr_on_2_pwr_good;
+    uint8_t hub_contr_current;
+    // Die folgenden Felder haben eine variable Größe
+} __attribute__((packed));
+
+#endif
+
diff --git a/src/modules/usb/include/usb-trans.h b/src/modules/usb/include/usb-trans.h
new file mode 100644
index 0000000..c5d3a1f
--- /dev/null
+++ b/src/modules/usb/include/usb-trans.h
@@ -0,0 +1,66 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#ifndef USB_TRANS_H
+#define USB_TRANS_H
+
+#include <stdbool.h>
+
+#include "usb-hub.h"
+
+// Übertragunsart
+enum usb_trans_type {
+    USB_TRST_CONTROL     = 0,
+    USB_TRST_ISOCHRONOUS = 1,
+    USB_TRST_BULK        = 2,
+    USB_TRST_INTERRUPT   = 3
+};
+
+// USB-Pipe für die Kommunikation mit dem Hostcontroller
+struct usb_trans_pipe {
+    // USB-Adresse (0 bis 127)
+    int usb_addr;
+    // Endpunkt-ID
+    int ep_id;
+    // MPS des Endpunkts
+    int mps;
+
+    // Typ der Pipe
+    enum usb_trans_type type;
+    // Geschwindigkeit des Geräts
+    int speed;
+
+    // Toggle-Bit
+    int toggle;
+    // true, wenn der Endpunkt gestallt ist
+    bool stalled;
+};
+
+#endif
diff --git a/src/modules/usb/msd/Makefile.all b/src/modules/usb/msd/Makefile.all
new file mode 100644
index 0000000..681ef87
--- /dev/null
+++ b/src/modules/usb/msd/Makefile.all
@@ -0,0 +1,8 @@
+shopt -s extglob
+source $LOST_BUILDMK_ROOT/config.sh
+
+CC=$CC -I../include
+
+echo "LD   $1/modules/usb-msd"
+$LOST_TOOLS_LD $LDSCRIPT -ousb-msd.mod  *.o --start-group $2 --end-group
+$LOST_TOOLS_STRIP -s usb-msd.mod -o $1/modules/usb-msd
diff --git a/src/modules/usb/msd/init.c b/src/modules/usb/msd/init.c
new file mode 100644
index 0000000..aa0d4a6
--- /dev/null
+++ b/src/modules/usb/msd/init.c
@@ -0,0 +1,197 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "msd.h"
+#include "msd-bo.h"
+#include "msd-cbi.h"
+#include "usb-lib.h"
+#include "usb-structs.h"
+#include "usb-trans.h"
+
+void got_bo_msd(struct usb_prov_dev* dev);
+void got_cbi_msd(struct usb_prov_dev* dev);
+
+int got_msd(struct usb_prov_dev* dev)
+{
+    if (dev->type.protocol == 0x50) { // Bulk-only
+        got_bo_msd(dev);
+        return 1;
+    } else if ((dev->type.subclass == 0x04) && !dev->type.protocol) { // UFI/CBI
+        got_cbi_msd(dev);
+        return 1;
+    }
+
+    return 0;
+}
+
+void got_bo_msd(struct usb_prov_dev* dev)
+{
+    int endpoints = usb_get_number_of_endpoints(dev);
+    int ifc_id = usb_get_interface_id(dev);
+    struct usb_endpoint_descriptor* epd = calloc(1, sizeof(*epd));
+    struct usb_endpoint_descriptor* bulk_in = malloc(sizeof(*bulk_in));
+    struct usb_endpoint_descriptor* bulk_out = malloc(sizeof(*bulk_out));
+    int bin = -1, bon = -1;
+
+    int i;
+    for (i = 0; i < endpoints; i++) {
+        usb_get_endpoint_info(dev, i, epd);
+
+        if (epd->type == USB_EP_BULK) {
+            if (epd->direction) {
+                memcpy(bulk_in, epd, sizeof(*epd));
+                bin = i;
+            } else {
+                memcpy(bulk_out, epd, sizeof(*epd));
+                bon = i;
+            }
+        }
+    }
+
+    free(epd);
+
+    if ((bin == -1) || (bon == -1)) {
+        free(bulk_in);
+        free(bulk_out);
+        return;
+    }
+
+    struct usb_pipe* bip = calloc(1, sizeof(*bip));
+    struct usb_pipe* bop = calloc(1, sizeof(*bop));
+
+    usb_create_pipe(dev, bin, bip);
+    usb_create_pipe(dev, bon, bop);
+
+    int max_lun = 0;
+    usb_control_transfer(dev, NULL, &(struct usb_setup_packet){
+            .type = USB_SETUP_IN | USB_SETUP_REQ_CLS | USB_SETUP_REC_IF,
+            .request = 0xFE, // GET MAX LUN
+            .index = ifc_id,
+            .length = 1,
+        }, &max_lun);
+
+    for (i = 0; i <= max_lun; i++) {
+        struct msc_bo_dev* new = calloc(1, sizeof(*new));
+
+        new->gen.lun = i;
+        new->gen.issue_scsi_cmd = &msd_bo_issue_scsi_cmd;
+        new->gen.send = &msd_bo_send;
+        new->gen.recv = &msd_bo_recv;
+
+        new->bulk_in = bulk_in;
+        new->bulk_out = bulk_out;
+
+        new->bip = bip;
+        new->bop = bop;
+
+        provide_msd(&new->gen);
+    }
+}
+
+void got_cbi_msd(struct usb_prov_dev* dev)
+{
+    int endpoints = usb_get_number_of_endpoints(dev);
+    int ifc_id = usb_get_interface_id(dev);
+    struct usb_endpoint_descriptor* epd = calloc(1, sizeof(*epd));
+    struct usb_endpoint_descriptor* bulk_in = malloc(sizeof(*bulk_in));
+    struct usb_endpoint_descriptor* bulk_out = malloc(sizeof(*bulk_out));
+    struct usb_endpoint_descriptor* interrupt = malloc(sizeof(*interrupt));
+    int bin = -1, bon = -1, ien = -1;
+
+    int i;
+    for (i = 0; i < endpoints; i++) {
+        usb_get_endpoint_info(dev, i, epd);
+
+        if (epd->type == USB_EP_BULK) {
+            if (epd->direction) {
+                memcpy(bulk_in, epd, sizeof(*epd));
+                bin = i;
+            } else {
+                memcpy(bulk_out, epd, sizeof(*epd));
+                bon = i;
+            }
+        } else if (epd->type == USB_EP_INTERRUPT) {
+            memcpy(interrupt, epd, sizeof(*epd));
+            ien = i;
+        }
+    }
+
+    free(epd);
+
+    if (dev->type.protocol || (ien == -1)) {
+        free(interrupt);
+        ien = -1;
+    }
+
+    if ((bin == -1) || (bon == -1)) {
+        free(bulk_in);
+        free(bulk_out);
+        return;
+    }
+
+    struct usb_pipe* bip = calloc(1, sizeof(*bip));
+    struct usb_pipe* bop = calloc(1, sizeof(*bop));
+    struct usb_pipe* ip;
+
+    usb_create_pipe(dev, bin, bip);
+    usb_create_pipe(dev, bon, bop);
+
+    if (ien != -1) {
+        ip = calloc(1, sizeof(*ip));
+        usb_create_pipe(dev, ien, ip);
+    }
+
+    struct msc_cbi_dev* new = calloc(1, sizeof(*new));
+
+    new->gen.lun = 0;
+    new->gen.issue_scsi_cmd = &msd_cbi_issue_scsi_cmd;
+    new->gen.send = &msd_cbi_send;
+    new->gen.recv = &msd_cbi_recv;
+
+    new->dev = dev;
+    new->ifc_id = ifc_id;
+
+    new->bulk_in = bulk_in;
+    new->bulk_out = bulk_out;
+
+    new->bip = bip;
+    new->bop = bop;
+
+    if (ien != -1) {
+        new->interrupt = interrupt;
+        new->ip = ip;
+    }
+
+    provide_msd(&new->gen);
+}
diff --git a/src/modules/usb/msd/lostio.c b/src/modules/usb/msd/lostio.c
new file mode 100644
index 0000000..6a2b503
--- /dev/null
+++ b/src/modules/usb/msd/lostio.c
@@ -0,0 +1,218 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <init.h>
+#include <lostio.h>
+
+#include "msd.h"
+
+static size_t msd_read(lostio_filehandle_t* liofh, void* dest,
+    size_t blocksize, size_t blockcount);
+static size_t msd_write(lostio_filehandle_t* liofh, size_t blocksize,
+    size_t blockcount, void* data);
+static int msd_seek(lostio_filehandle_t* liofh, uint64_t offset, int origin);
+
+struct partition {
+    struct msc_gen_dev* dev;
+    uint64_t block_offset;
+    uint64_t blocks;
+};
+
+struct parttbl_entry {
+    uint8_t active;
+    uint8_t chs_start[3];
+    uint8_t type;
+    uint8_t chs_end[3];
+    uint32_t start;
+    uint32_t size;
+} __attribute__((packed));
+
+void init_lostio_interface(void)
+{
+    lostio_init();
+    lostio_type_ramfile_use();
+    lostio_type_directory_use();
+
+    typehandle_t* msds = calloc(1, sizeof(*msds));
+
+    msds->id = 42;
+    msds->read = &msd_read;
+    msds->write = &msd_write;
+    msds->seek = &msd_seek;
+
+    lostio_register_typehandle(msds);
+}
+
+static void detect_partitions(int msd_number, struct msc_gen_dev* dev)
+{
+    uint8_t* bootsec = malloc(512);
+
+    msd_scsi_read(dev, 0, bootsec, 1);
+
+    if (*(uint16_t*)&bootsec[510] != 0xAA55) {
+        free(bootsec);
+        return;
+    }
+
+    struct parttbl_entry* ptbl = (struct parttbl_entry*)&bootsec[446];
+
+    int p;
+    for (p = 0; p < 4; p++) {
+        if (ptbl[p].size) {
+            if ((ptbl[p].type == 0x0F) || (ptbl[p].type == 0x85)) {
+                continue;
+            }
+
+            struct partition* part = calloc(1, sizeof(*part));
+            part->dev = dev;
+            part->block_offset = ptbl[p].start;
+            part->blocks = ptbl[p].size;
+
+            char name[13];
+            sprintf(name, "/msd%i_p%i", msd_number, p);
+
+            vfstree_create_node(name, 42, ptbl[p].size * dev->block_size, part,
+                0);
+        }
+    }
+
+    free(bootsec);
+}
+
+void provide_msd(struct msc_gen_dev* dev)
+{
+    static int msds = 0;
+
+    uint64_t bc, bs;
+    if (!msd_scsi_init(dev, &bc, &bs)) {
+        return;
+    }
+
+    printf("[usb-msd] New SCSI block device, %lli %lli-byte blocks: ", bc, bs);
+    uint64_t fs = bc * bs;
+    if (fs >= 10 << 30) {
+        printf("%lli GB\n", fs >> 30);
+    } else if (fs >= 10 << 20) {
+        printf("%lli MB\n", fs >> 20);
+    } else if (fs >= 10 << 10) {
+        printf("%lli kB\n", fs >> 10);
+    } else {
+        printf("%lli B\n", fs);
+    }
+
+    dev->block_size = bs;
+    dev->blocks = bc;
+
+    char name[10];
+    int num = msds++;
+    sprintf(name, "/msd%i", num);
+
+    struct partition* part = calloc(1, sizeof(*part));
+    part->dev = dev;
+    part->blocks = bc;
+
+    vfstree_create_node(name, 42, fs, part, 0);
+
+    // Bei 2880 Sektoren ist es vermutlich eine Diskette (ja, es gibt noch
+    // andere Diskettenarten als 3,5" HD, aber die sind halt selten), und die
+    // hat keine Partitionen (verhindert das Erkennen scheinbarer Partitionen)
+    if (bc != 2880) {
+        detect_partitions(num, dev);
+    }
+
+    // TODO: Das vielleicht erst irgendwie registrieren, wenn alle Geräte
+    // angekommen sind
+    init_service_register("usb-msd");
+
+    uint16_t* mem = calloc(1, 512);
+    msd_scsi_read(dev, 0, mem, 1);
+}
+
+static size_t msd_read(lostio_filehandle_t* liofh, void* dest,
+    size_t blocksize, size_t blockcount)
+{
+    struct partition* part = liofh->node->data;
+    struct msc_gen_dev* dev = part->dev;
+
+    uint64_t begin = liofh->pos / dev->block_size + part->block_offset;
+
+    // Diese Debuginformationen mögen nervig erscheinen, sind aber sehr
+    // wichtig, da man oft nur so erkennen kann, dass überhaupt etwas
+    // geschieht
+    printf("[usb-msd] read from %lli (%i blocks)\n", begin,
+        (blockcount * blocksize + dev->block_size - 1) / dev->block_size);
+    size_t ret = msd_scsi_read(dev, begin, dest,
+        (blockcount * blocksize + dev->block_size - 1) / dev->block_size);
+    msd_seek(liofh, ret, SEEK_CUR);
+
+    return ret;
+}
+
+static size_t msd_write(lostio_filehandle_t* liofh, size_t blocksize,
+    size_t blockcount, void* data)
+{
+    return 0;
+}
+
+static int msd_seek(lostio_filehandle_t* liofh, uint64_t offset, int origin)
+{
+    struct partition* part = liofh->node->data;
+    struct msc_gen_dev* dev = part->dev;
+    uint64_t new_pos = liofh->pos;
+    uint64_t size = part->blocks * dev->block_size;
+
+    switch (origin)  {
+        case SEEK_SET:
+            new_pos = offset;
+            break;
+        case SEEK_CUR:
+            new_pos += offset;
+            break;
+        case SEEK_END:
+            new_pos = size;
+            break;
+    }
+
+    if (new_pos > size) {
+        return -1;
+    } else if (new_pos == size) {
+        liofh->flags |= LOSTIO_FLAG_EOF;
+    } else {
+        liofh->flags &= ~LOSTIO_FLAG_EOF;
+    }
+
+    liofh->pos = new_pos;
+    return 0;
+}
diff --git a/src/modules/usb/msd/main.c b/src/modules/usb/msd/main.c
new file mode 100644
index 0000000..cebca5c
--- /dev/null
+++ b/src/modules/usb/msd/main.c
@@ -0,0 +1,65 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <init.h>
+#include <rpc.h>
+#include <sleep.h>
+#include <syscall.h>
+
+#include "msd.h"
+
+extern pid_t usb_pid;
+
+int main(void)
+{
+    init_messaging();
+    init_lostio_interface();
+
+    // Warten, damit, falls alle Treiber relativ gleichzeitig gestartet werden
+    // (Boot), dieser Prozess nach usb1 (und möglichst vor uhci) weiterläuft
+    msleep(1000);
+
+    usb_pid = init_service_get("usb1");
+    if (!usb_pid)
+    {
+        fprintf(stderr, "You need to start the usb1 driver first.\n");
+        return 1;
+    }
+
+    init_rpc_interface();
+    register_msddrv();
+
+    for (;;) {
+        wait_for_rpc();
+    }
+}
diff --git a/src/modules/usb/msd/msd-bo.c b/src/modules/usb/msd/msd-bo.c
new file mode 100644
index 0000000..0007b80
--- /dev/null
+++ b/src/modules/usb/msd/msd-bo.c
@@ -0,0 +1,104 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "msd.h"
+#include "msd-bo.h"
+#include "usb-lib.h"
+
+int check_csw(struct msc_bo_dev* dev)
+{
+    struct msd_bo_csw csw;
+
+    int ret = usb_bulk_transfer(dev->bip, &csw, sizeof(csw), true);
+    if (ret) {
+        return ret;
+    }
+
+    // Man könnte wohl noch ein bisschen was überprüfen...
+    // Some checks might be nice...
+    return 0;
+}
+
+int msd_bo_issue_scsi_cmd(struct msc_gen_dev* dev, const void* cmd_buffer,
+    size_t cmd_length, bool receive, size_t req_length)
+{
+    struct msc_bo_dev* bo = (struct msc_bo_dev*)dev;
+
+    if (cmd_length > 16) {
+        cmd_length = 16;
+    }
+
+    struct msd_bo_cbw cbw = {
+        .signature = CBW_SIGNATURE,
+        .data_transfer_length = req_length,
+        .flags = receive ? CBW_IN : CBW_OUT,
+        .lun = dev->lun,
+        .cb_length = cmd_length
+    };
+
+    memcpy(cbw.cb, cmd_buffer, cmd_length);
+
+    int ret = usb_bulk_transfer(bo->bop, &cbw, sizeof(cbw), false);
+    if (ret || req_length) {
+        return ret;
+    }
+
+    return check_csw(bo);
+}
+
+int msd_bo_send(struct msc_gen_dev* dev, const void* buffer, size_t size)
+{
+    struct msc_bo_dev* bo = (struct msc_bo_dev*)dev;
+
+    int ret = usb_bulk_transfer(bo->bop, (void*)buffer, size, false);
+    if (ret) {
+        return ret;
+    }
+
+    return check_csw(bo);
+}
+
+int msd_bo_recv(struct msc_gen_dev* dev, void* buffer, size_t size)
+{
+    struct msc_bo_dev* bo = (struct msc_bo_dev*)dev;
+
+    int ret = usb_bulk_transfer(bo->bip, buffer, size, true);
+    if (ret) {
+        return ret;
+    }
+
+    return check_csw(bo);
+}
diff --git a/src/modules/usb/msd/msd-bo.h b/src/modules/usb/msd/msd-bo.h
new file mode 100644
index 0000000..49451cb
--- /dev/null
+++ b/src/modules/usb/msd/msd-bo.h
@@ -0,0 +1,99 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#ifndef MSD_BO_H
+#define MSD_BO_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "msd.h"
+#include "usb-ddrv.h"
+
+#define CBW_IN  0x80
+#define CBW_OUT 0x00
+
+#define CBW_SIGNATURE 0x43425355 //'USBC' => USB command
+#define CSW_SIGNATURE 0x53425355 //'USBS' => USB status
+
+
+// Beschreibt ein MSC-Bulk-Only-Gerät
+struct msc_bo_dev {
+    // Das MSD an sich
+    struct msc_gen_dev gen;
+
+    // Bulk-Endpunkte
+    struct usb_endpoint_descriptor* bulk_in;
+    struct usb_endpoint_descriptor* bulk_out;
+
+    // Pipes zu diesen Endpunkten
+    struct usb_pipe* bip;
+    struct usb_pipe* bop;
+};
+
+// Command Block Wrapper für BO-MSDs
+struct msd_bo_cbw {
+    // CBW_SIGNATURE
+    uint32_t signature;
+    // Ein Wert, der im CSW wiederholt wird
+    uint32_t tag;
+    // Länge des Datentransfers
+    uint32_t data_transfer_length;
+    // Flags (vorrangig Richtung des Transfers)
+    uint8_t flags;
+    // LUN
+    uint8_t lun;
+    // Länge des Befehls
+    uint8_t cb_length;
+    // SCSI-Befehl
+    uint8_t cb[16];
+} __attribute__((packed));
+
+// Command Status Wrapper für BO-MSDs
+struct msd_bo_csw {
+    // CSW_SIGNATURE
+    uint32_t signature;
+    // Tagwert aus dem CBW
+    uint32_t tag;
+    // Größe der Daten, die erwartet, aber nicht übertragen wurden
+    uint32_t data_residue;
+    // Status
+    uint8_t status;
+} __attribute__((packed));
+
+// Sendet einen SCSI-Befehl
+int msd_bo_issue_scsi_cmd(struct msc_gen_dev* dev, const void* buffer,
+    size_t cmd_length, bool receive, size_t req_length);
+// Sendet Daten an das Gerät
+int msd_bo_send(struct msc_gen_dev* dev, const void* buffer, size_t size);
+// Empfängt Daten vom Gerät
+int msd_bo_recv(struct msc_gen_dev* dev, void* buffer, size_t size);
+
+#endif
diff --git a/src/modules/usb/msd/msd-cbi.c b/src/modules/usb/msd/msd-cbi.c
new file mode 100644
index 0000000..66590fd
--- /dev/null
+++ b/src/modules/usb/msd/msd-cbi.c
@@ -0,0 +1,86 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "msd.h"
+#include "msd-cbi.h"
+#include "usb-lib.h"
+
+int msd_cbi_issue_scsi_cmd(struct msc_gen_dev* dev, const void* cmd_buffer,
+    size_t cmd_length, bool receive, size_t req_length)
+{
+    struct msc_cbi_dev* cbi = (struct msc_cbi_dev*)dev;
+    int8_t cmd[12] = { 0 };
+    struct usb_setup_packet setup = {
+        .type = USB_SETUP_OUT | USB_SETUP_REQ_CLS | USB_SETUP_REC_IF,
+        .request = 0,
+        .value = 0,
+        .index = cbi->ifc_id,
+        .length = sizeof(cmd)
+    };
+
+    if (cmd_length > 12) {
+        cmd_length = 12;
+    }
+
+    memcpy(cmd, cmd_buffer, cmd_length);
+
+    int ret = usb_control_transfer(cbi->dev, NULL, &setup, cmd);
+
+    /*
+    if (ret == -EHOSTDOWN) {
+        // kA, ob das etwas bringt
+        if (receive == true) {
+            usb_clear_halt(cbi->bip);
+        } else {
+            usb_clear_halt(cbi->bop);
+        }
+    }
+    */
+
+    return ret;
+}
+
+int msd_cbi_send(struct msc_gen_dev* dev, const void* buffer, size_t size)
+{
+    struct msc_cbi_dev* cbi = (struct msc_cbi_dev*)dev;
+    return usb_bulk_transfer(cbi->bop, (void*)buffer, size, false);
+}
+
+int msd_cbi_recv(struct msc_gen_dev* dev, void* buffer, size_t size)
+{
+    struct msc_cbi_dev* cbi = (struct msc_cbi_dev*)dev;
+    return usb_bulk_transfer(cbi->bip, buffer, size, true);
+}
diff --git a/src/modules/usb/msd/msd-cbi.h b/src/modules/usb/msd/msd-cbi.h
new file mode 100644
index 0000000..66ff221
--- /dev/null
+++ b/src/modules/usb/msd/msd-cbi.h
@@ -0,0 +1,71 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#ifndef MSD_CBI_H
+#define MSD_CBI_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "msd.h"
+#include "usb-ddrv.h"
+
+// Beschreibt ein MSC-CBI-Gerät
+struct msc_cbi_dev {
+    // Das MSD an sich
+    struct msc_gen_dev gen;
+
+    // Das zugrunde liegende USB-Gerät
+    struct usb_prov_dev* dev;
+    // Die Interface-ID (MSDs sind immer Interfaces)
+    int ifc_id;
+
+    // Alle wichtigen Endpunkte (EP0 ist in dev enthalten), interrupt darf NULL
+    // sein
+    struct usb_endpoint_descriptor* bulk_in;
+    struct usb_endpoint_descriptor* bulk_out;
+    struct usb_endpoint_descriptor* interrupt;
+
+    // Die Pipes zu diesen Endpunkten, ip darf NULL sein
+    struct usb_pipe* bip;
+    struct usb_pipe* bop;
+    struct usb_pipe* ip;
+};
+
+
+// Sendet einen SCSI-Befehl
+int msd_cbi_issue_scsi_cmd(struct msc_gen_dev* dev, const void* buffer,
+    size_t cmd_length, bool receive, size_t req_length);
+// Sendet Daten zum Gerät
+int msd_cbi_send(struct msc_gen_dev* dev, const void* buffer, size_t size);
+// Empfängt Daten vom Gerät
+int msd_cbi_recv(struct msc_gen_dev* dev, void* buffer, size_t size);
+
+#endif
diff --git a/src/modules/usb/msd/msd.h b/src/modules/usb/msd/msd.h
new file mode 100644
index 0000000..892b207
--- /dev/null
+++ b/src/modules/usb/msd/msd.h
@@ -0,0 +1,146 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#ifndef MSD_H
+#define MSD_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "usb-ddrv.h"
+
+// Beschreibt eine LUN eines MSC-Geräts (MSD) im Allgemeinen
+struct msc_gen_dev {
+    // LUN
+    int lun;
+
+    // Größe eines Blocks
+    uint64_t block_size;
+    // Anzahl Blöcke
+    uint64_t blocks;
+
+    /**
+     * Führt einen SCSI-Befehl aus.
+     *
+     * @param dev Zielgerät
+     * @param cmd_buffer Speicherbereich, der den Befehl enthält
+     * @param cmd_length Länge dieses Befehls in Byte
+     * @param receive true, wenn empfangen werden soll
+     * @param req_length Länge der zu übertragenden Daten
+     *
+     * @return 0 bei Erfolg, sonst -errno
+     */
+    int (*issue_scsi_cmd)(struct msc_gen_dev* dev, const void* cmd_buffer,
+        size_t cmd_length, bool receive, size_t req_length);
+
+    /**
+     * Sendet Daten zu einem Gerät.
+     *
+     * @param dev Zielgerät
+     * @param buffer Speicherbereich, der die Daten enthält
+     * @param size Anzahl der zu sendenden Bytes
+     *
+     * @return 0 bei Erfolg, sonst -errno
+     */
+    int (*send)(struct msc_gen_dev* dev, const void* buffer, size_t size);
+
+    /**
+     * Empfängt Daten von einem Gerät.
+     *
+     * @param dev Quellgerät
+     * @param buffer Speicherbereich, in den die Daten gelesen werden sollen
+     * @param size Anzahl der zu empfangenden Bytes
+     *
+     * @return 0 bei Erfolg, sonst -errno
+     */
+    int (*recv)(struct msc_gen_dev* dev, void* buffer, size_t size);
+};
+
+/**
+ * Wird von einem RPC-Handler aufgerufen, sobald ein neues MSD gefunden wurde.
+ *
+ * @param dev Neues Gerät
+ *
+ * @return 1 bei Erfolg, sonst 0
+ */
+int got_msd(struct usb_prov_dev* dev);
+
+/**
+ * Initialisiert das LostIO-Interface.
+ */
+void init_lostio_interface(void);
+
+/**
+ * Initialisiert das RPC-Interface.
+ */
+void init_rpc_interface(void);
+
+/**
+ * Initialisiert ein MSD auf SCSI-Ebene.
+ *
+ * @param dev Das MSD
+ * @param blocks Pointer zu einer Variable, in die die Anzahl der vorhandenen
+ *               Blöcke geschrieben wird
+ * @param bsize Pointer zu einer Variable, in die die Größe eines Blocks
+ *              geschrieben wird
+ *
+ * @return 1 bei Erfolg, sonst 0
+ */
+int msd_scsi_init(struct msc_gen_dev* dev, uint64_t* blocks,
+    uint64_t* bsize);
+
+/**
+ * Liest von einem MSD per SCSI.
+ *
+ * @param dev Das MSD
+ * @param start_lba LBA des ersten zu lesenden Blocks
+ * @param dest Zielspeicherbereich
+ * @param blocks Anzahl der zu lesenden Blöcke
+ *
+ * @return Anzahl der gelesenen Bytes
+ */
+size_t msd_scsi_read(struct msc_gen_dev* dev, uint64_t start_lba, void* dest,
+    uint64_t blocks);
+
+/**
+ * Wird von einer MSD-spezifischen Initialisierungsroutine aufgerufen, um ein
+ * für die SCSI-Initialisierung vorbereitetes MSD bereitzustellen.
+ *
+ * @param dev Das neue Gerät
+ */
+void provide_msd(struct msc_gen_dev* dev);
+
+/**
+ * Registriert diesen Treiber beim USB-Bustreiber.
+ */
+void register_msddrv(void);
+
+#endif
diff --git a/src/modules/usb/msd/rpc.c b/src/modules/usb/msd/rpc.c
new file mode 100644
index 0000000..ae48d68
--- /dev/null
+++ b/src/modules/usb/msd/rpc.c
@@ -0,0 +1,83 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <ports.h>
+#include <rpc.h>
+#include <syscall.h>
+
+#include "msd.h"
+#include "usb-ddrv.h"
+#include "usb-server.h"
+
+extern pid_t usb_pid;
+
+void msd_got_device_handler(pid_t src, uint32_t corr_id, size_t length,
+    void* data)
+{
+    struct usb_prov_dev* pd;
+
+    if (length < sizeof(*pd)) {
+        rpc_send_int_response(src, corr_id, 0);
+        return;
+    }
+
+    pd = malloc(sizeof(*pd));
+    memcpy(pd, data, sizeof(*pd));
+
+    rpc_send_int_response(src, corr_id, got_msd(pd));
+}
+
+void init_rpc_interface(void)
+{
+    register_message_handler(RPC_USB_DDRV_PLUG_FNN, &msd_got_device_handler);
+}
+
+void register_msddrv(void)
+{
+    struct usb_handle_devs hd = {
+        .vendor_id = -1,
+        .device_id = -1,
+        .class = 8, // MSC
+        .subclass = -1,
+        .protocol = -1
+    };
+
+    if (!rpc_get_int(usb_pid, RPC_USB_SV_REGDD_FNN, sizeof(hd), (char*)&hd)) {
+        fprintf(stderr, "Could not register USB MSD driver.\n");
+    }
+}
diff --git a/src/modules/usb/msd/scsi.c b/src/modules/usb/msd/scsi.c
new file mode 100644
index 0000000..5a4e007
--- /dev/null
+++ b/src/modules/usb/msd/scsi.c
@@ -0,0 +1,240 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include "msd.h"
+#include "scsi.h"
+
+const char *dev_type[] =
+{
+    "magnetic disk",
+    "magnetic tape",
+    "printer",
+    "processor",
+    "write-once device",
+    "CD-ROM",
+    "scanner",
+    "optical medium",
+    "medium changer",
+    "communications device",
+    "?",
+    "?",
+    "RAID",
+    "enclosure services device",
+    "magnetic disk (simplified)",
+    "card reader/writer (optical)",
+    "?",
+    "object-based storage",
+    "automation/drive interface",
+    "?",
+    "?",
+    "?",
+    "?",
+    "?",
+    "?",
+    "?",
+    "?",
+    "?",
+    "?",
+    "?",
+    "well known LUN",
+    "?"
+};
+
+static int do_pkt(struct msc_gen_dev* dev, int receive, void* buffer1,
+    size_t length1, void* buffer2, size_t length2)
+{
+    while (dev->issue_scsi_cmd(dev, buffer1, length1, !!(receive == 1),
+        length2))
+    {
+        struct scsi_sense sense;
+        struct scsi_cmd_request_sense req_sense = {
+            .cmd = {
+                .operation = SCSI_REQUEST_SENSE
+            },
+            .alloc_len = sizeof(sense),
+            .lun = dev->lun
+        };
+
+        if (dev->issue_scsi_cmd(dev, &req_sense, sizeof(req_sense), true,
+            sizeof(sense)))
+        {
+            fprintf(stderr, "[usb-msd] Could not request sense\n");
+            return -1;
+        }
+
+        if (dev->recv(dev, &sense, sizeof(sense))) {
+            fprintf(stderr, "[usb-msd] Could not sense\n");
+            return -1;
+        }
+    }
+
+    if (receive == 1) {
+        return dev->recv(dev, buffer2, length2);
+    } else if (!receive) {
+        return dev->send(dev, buffer2, length2);
+    }
+
+    return 0;
+}
+
+int msd_scsi_init(struct msc_gen_dev* dev, uint64_t* blocks, uint64_t* bsize)
+{
+    struct scsi_inq_answer inq_ans;
+    struct scsi_cmd_inquiry inq = {
+        .cmd = {
+            .operation = SCSI_INQUIRY
+        },
+        .alloc_len = htobe16(sizeof(inq_ans)),
+        .lun = dev->lun
+    };
+
+    if (do_pkt(dev, 1, &inq, sizeof(inq), &inq_ans, sizeof(inq_ans))) {
+        return 0;
+    }
+
+    printf("[usb-msd] LUN %i: %s, ", dev->lun, dev_type[inq_ans.dev_type]);
+
+    int last;
+    for (last = (int)sizeof(inq_ans.vendor) - 1; last >= 0; last--) {
+        if (inq_ans.vendor[last] != ' ') {
+            break;
+        }
+    }
+
+    last++;
+
+    int i;
+
+    if (last) {
+        for (i = 0; i < last; i++) {
+            printf("%c", inq_ans.vendor[i]);
+        }
+        printf(" ");
+    }
+
+
+    for (last = (int)sizeof(inq_ans.product) - 1; last >= 0; last--) {
+        if (inq_ans.product[last] != ' ') {
+            break;
+        }
+    }
+
+    last++;
+
+    for (i = 0; i < last; i++) {
+        printf("%c", inq_ans.product[i]);
+    }
+    printf("\n");
+
+    // Erklär mir mal einer, wieso man das braucht
+    // I'd appreciate any explanation why this is required
+    int8_t zero[6] = { 0 };
+    if (do_pkt(dev, -1, &zero, sizeof(zero), NULL, 0)) {
+        return 0;
+    }
+
+    uint32_t cap_ans[2];
+    struct scsi_cmd_read_capacity cap = {
+        .cmd = {
+            .operation = SCSI_READ_CAPACITY
+        }
+    };
+
+    if (do_pkt(dev, 1, &cap, sizeof(cap), &cap_ans, sizeof(cap_ans))) {
+        return 0;
+    }
+
+    *blocks = (uint64_t)betoh32(cap_ans[0]) + 1LL;
+    *bsize = betoh32(cap_ans[1]);
+
+    return 1;
+}
+
+#define SCSI_READ 10
+
+size_t msd_scsi_read(struct msc_gen_dev* dev, uint64_t start_lba, void* dest,
+    uint64_t blocks)
+{
+    #if SCSI_READ == 10
+    struct scsi_cmd_read10 r10 = {
+        .cmd = {
+            .operation = SCSI_READ10
+        },
+        .lun = dev->lun,
+        .lba = htobe32(start_lba),
+        .length = htobe16(blocks)
+    };
+    #elif SCSI_READ == 6
+    struct scsi_cmd_read6 r6 = {
+        .cmd = {
+            .operation = SCSI_READ6
+        },
+        .lun = dev->lun,
+        .lba_lo = htobe16(start_lba),
+        .lba_hi = start_lba >> 16,
+        .length = blocks
+    };
+    #else
+    struct scsi_cmd_read12 r12 = {
+        .cmd = {
+            .operation = SCSI_READ12
+        },
+        .lun = dev->lun,
+        .lba = htobe32(start_lba),
+        .length = htobe32(blocks)
+    };
+    #endif
+
+    #if SCSI_READ == 10
+    if ((start_lba >> 32) || (blocks >> 16)) {
+    #elif SCSI_READ == 6
+    if ((start_lba >> 21) || (blocks >> 8)) {
+    #else
+    if ((start_lba >> 32) || (blocks >> 32)) {
+    #endif
+        return 0;
+    }
+
+    #if SCSI_READ == 10
+    int ret = do_pkt(dev, 1, &r10, sizeof(r10), dest, blocks * dev->block_size);
+    #elif SCSI_READ == 6
+    int ret = do_pkt(dev, 1, &r6, sizeof(r6), dest, blocks * dev->block_size);
+    #else
+    int ret = do_pkt(dev, 1, &r12, sizeof(r12), dest, blocks * dev->block_size);
+    #endif
+
+    if (ret < 0) {
+        return 0;
+    }
+    return blocks * dev->block_size;
+}
diff --git a/src/modules/usb/msd/scsi.h b/src/modules/usb/msd/scsi.h
new file mode 100644
index 0000000..98b88f9
--- /dev/null
+++ b/src/modules/usb/msd/scsi.h
@@ -0,0 +1,219 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#ifndef SCSI_H
+#define SCSI_H
+
+#include <stdint.h>
+#include <arpa/inet.h>
+
+// Funktionen zum Konvertieren von/zu Big Endian
+#define htobe16(val) htons(val)
+#define htobe32(val) htonl(val)
+#define betoh16(val) htobe16(val)
+#define betoh32(val) htobe32(val)
+
+// SCSI-Befehlscodes
+#define SCSI_REQUEST_SENSE 0x03
+#define SCSI_READ6         0x08
+#define SCSI_INQUIRY       0x12
+#define SCSI_READ_CAPACITY 0x25
+#define SCSI_READ10        0x28
+#define SCSI_WRITE10       0x2A
+#define SCSI_READ12        0xA8
+
+// Minimaler SCSI-Befehl
+struct scsi_cmd {
+    // Befehlscode
+    uint8_t operation;
+} __attribute__((packed));
+
+// REQUEST SENSE
+// Gibt Informationen im Fehlerfall zurück.
+struct scsi_cmd_request_sense {
+    struct scsi_cmd cmd;
+    unsigned rsvd1 : 5;
+    // LUN
+    unsigned lun   : 3;
+    uint16_t rsvd2;
+    // Anzahl der Bytes, die der Host zu empfangen bereit ist
+    uint8_t alloc_len;
+    uint8_t control;
+} __attribute__((packed));
+
+// INQUIRY
+// Gibt Informationen zum Gerät zurück.
+struct scsi_cmd_inquiry {
+    struct scsi_cmd cmd;
+    unsigned evpd : 1;
+    unsigned rsvd : 4;
+    // LUN
+    unsigned lun  : 3;
+    uint8_t page;
+    // Anzahl der Bytes, die der Host zu empfangen bereit ist
+    uint16_t alloc_len;
+    uint8_t control;
+} __attribute__((packed));
+
+// READ CAPACITY
+// Gibt die LBA des letzten Blocks zurück sowie die Blockgröße
+struct scsi_cmd_read_capacity {
+    struct scsi_cmd cmd;
+    unsigned reladdr : 1;
+    unsigned rsvd1   : 4;
+    // LUN
+    unsigned lun     : 3;
+    uint32_t lba;
+    uint32_t rsvd2;
+} __attribute__((packed));
+
+// READ6
+// Liest Daten
+struct scsi_cmd_read6 {
+    struct scsi_cmd cmd;
+    // Höherwertiger Teil der LBA
+    unsigned lba_hi : 5;
+    // LUN
+    unsigned lun : 3;
+    // Niederwertiger Teil der LBA
+    uint16_t lba_lo;
+    // Anzahl zu lesende Blöcke
+    uint8_t length;
+    uint8_t control;
+} __attribute__((packed));
+
+// READ10
+// Liest Daten
+struct scsi_cmd_read10 {
+    struct scsi_cmd cmd;
+    unsigned reladdr : 1;
+    unsigned rsvd1   : 2;
+    unsigned fua     : 1;
+    unsigned dpo     : 1;
+    // LUN
+    unsigned lun     : 3;
+    // LBA
+    uint32_t lba;
+    uint8_t rsvd2;
+    // Anzahl zu lesende Blöcke
+    uint16_t length;
+    uint8_t control;
+} __attribute__((packed));
+
+// READ12
+// Liest Daten
+struct scsi_cmd_read12 {
+    struct scsi_cmd cmd;
+    unsigned reladdr : 1;
+    unsigned rsvd1   : 2;
+    unsigned fua     : 1;
+    unsigned dpo     : 1;
+    // LUN
+    unsigned lun     : 3;
+    // LBA
+    uint32_t lba;
+    // Anzahl zu lesende Blöcke
+    uint32_t length;
+    uint16_t rsvd2;
+} __attribute__((packed));
+
+// WRITE10
+// Schreibt Daten
+struct scsi_cmd_write10 {
+    struct scsi_cmd cmd;
+    unsigned reladdr : 1;
+    unsigned rsvd1   : 1;
+    unsigned ebp     : 1;
+    unsigned fua     : 1;
+    unsigned dpo     : 1;
+    // LUN
+    unsigned lun     : 3;
+    // LBA
+    uint32_t lba;
+    uint8_t rsvd2;
+    // Anzahl zu lesende Blöcke
+    uint16_t length;
+    uint8_t control;
+} __attribute__((packed));
+
+// Rückgabestruktur von SCSI SENSE
+struct scsi_sense {
+    unsigned resp_code : 7;
+    unsigned valid     : 1;
+    uint8_t segment;
+    unsigned sense_key : 4;
+    unsigned rsvd1     : 1;
+    unsigned ili       : 1;
+    unsigned eom       : 1;
+    unsigned filemark  : 1;
+    uint32_t information;
+    uint8_t add_sense_length;
+    uint32_t cmd_spec_info;
+    uint8_t add_sense_code;
+    uint8_t add_sense_code_qual;
+    uint8_t field_replacable_unit_code;
+    unsigned sense_key_spec1 : 7;
+    unsigned sksv            : 1;
+    uint8_t sense_key_spec2;
+    uint8_t sense_key_spec3;
+} __attribute__((packed));
+
+// Rückgabestruktur von SCSI INQUIRY
+struct scsi_inq_answer {
+    // Gerätetype
+    unsigned dev_type  : 5;
+    unsigned qualifier : 3;
+    unsigned type_mod : 7;
+    unsigned rmb      : 1;
+    unsigned ansi_version : 3;
+    unsigned ecma_version : 3;
+    unsigned iso_version  : 2;
+    unsigned resp_data_format : 4;
+    unsigned rsvd1            : 2;
+    unsigned trm_iop          : 1;
+    unsigned aec              : 1;
+    uint8_t add_length;
+    uint16_t rsvd2;
+    unsigned soft_rst  : 1;
+    unsigned cmd_queue : 1;
+    unsigned rsvd3     : 1;
+    unsigned linked    : 1;
+    unsigned sync      : 1;
+    unsigned wbus16    : 1;
+    unsigned wbus32    : 1;
+    unsigned rel_adr   : 1;
+    // Herstellername
+    char vendor[8];
+    // Produktname
+    char product[16];
+    uint32_t revision;
+} __attribute__((packed));
+
+#endif
diff --git a/src/modules/usb/msd/usb-lib.c b/src/modules/usb/msd/usb-lib.c
new file mode 100644
index 0000000..fe4eb69
--- /dev/null
+++ b/src/modules/usb/msd/usb-lib.c
@@ -0,0 +1,207 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <rpc.h>
+#include <syscall.h>
+
+#include "usb-ddrv.h"
+#include "usb-server.h"
+#include "usb-structs.h"
+#include "usb-trans.h"
+
+pid_t usb_pid;
+
+int usb_get_number_of_endpoints(struct usb_prov_dev* dev)
+{
+    struct usb_devctrl_gne rq = {
+        .req = {
+            .type = USB_DC_NUM_ENDPOINTS
+        },
+        .dev = *dev
+    };
+
+    return rpc_get_int(usb_pid, RPC_USB_SV_DEVCT_FNN, sizeof(rq), (char*)&rq);
+}
+
+int usb_get_interface_id(struct usb_prov_dev* dev)
+{
+    struct usb_devctrl_gii giid = {
+        .req = {
+            .type = USB_DC_GET_IFC_ID
+        },
+        .dev = *dev
+    };
+
+    return rpc_get_int(usb_pid, RPC_USB_SV_DEVCT_FNN, sizeof(giid),
+        (char*)&giid);
+}
+
+void usb_get_endpoint_info(struct usb_prov_dev* dev, int ep_number,
+    struct usb_endpoint_descriptor* ep_desc)
+{
+    struct usb_devctrl_gep gep = {
+        .req = {
+            .type = USB_DC_GET_ENDPOINT
+        },
+        .dev = *dev,
+        .ep_number = ep_number
+    };
+
+    response_t* r = rpc_get_response(usb_pid, RPC_USB_SV_DEVCT_FNN,
+        sizeof(gep), (char*)&gep);
+
+    memcpy(ep_desc, r->data, sizeof(*ep_desc));
+    free(r->data);
+    free(r);
+}
+
+void usb_create_pipe(struct usb_prov_dev* dev, int ep_number,
+    struct usb_pipe* pipe)
+{
+    struct usb_devctrl_gpp gp = {
+        .req = {
+            .type = USB_DC_GET_PIPE
+        },
+        .dev = *dev,
+        .ep_number = ep_number
+    };
+
+    response_t* r = rpc_get_response(usb_pid, RPC_USB_SV_DEVCT_FNN,
+        sizeof(gp), (char*)&gp);
+
+    memcpy(pipe, r->data, sizeof(*pipe));
+    free(r->data);
+    free(r);
+}
+
+int usb_control_transfer(struct usb_prov_dev* dev, struct usb_pipe* pipe,
+    struct usb_setup_packet* setup, void* buffer)
+{
+    uint32_t shm = 0;
+    void* shm_addr = NULL;
+
+    if (setup->length) {
+        shm = create_shared_memory(setup->length);
+        shm_addr = open_shared_memory(shm);
+
+        if ((buffer != NULL) && !(setup->type & USB_SETUP_IN)) {
+            memcpy(shm_addr, buffer, setup->length);
+        }
+    }
+
+    struct usb_devctrl_tct tctrq = {
+        .req = {
+            .type = USB_DC_TRSF_CONTROL
+        },
+        .setup = *setup,
+        .shm = shm
+    };
+
+    if (pipe != NULL) {
+        tctrq.dst.pipe = *pipe;
+        tctrq.ep0 = false;
+    } else {
+        tctrq.dst.dev_id = dev->dev_id;
+        tctrq.ep0 = true;
+    }
+
+    int ret = rpc_get_int(usb_pid, RPC_USB_SV_DEVCT_FNN, sizeof(tctrq),
+        (char*)&tctrq);
+
+    if (setup->length && (buffer != NULL) && (setup->type & USB_SETUP_IN)) {
+        memcpy(buffer, shm_addr, setup->length);
+    }
+
+    if (shm_addr != NULL) {
+        close_shared_memory(shm);
+    }
+
+    return ret;
+}
+
+int usb_bulk_transfer(struct usb_pipe* pipe, void* buffer, size_t length,
+    bool receive)
+{
+    uint32_t shm = 0;
+    void* shm_addr = NULL;
+
+    if (length) {
+        shm = create_shared_memory(length);
+        shm_addr = open_shared_memory(shm);
+
+        if ((buffer != NULL) && !receive) {
+            memcpy(shm_addr, buffer, length);
+        }
+    }
+
+    struct usb_devctrl_tbk tbkrq = {
+        .req = {
+            .type = USB_DC_TRSF_BULK
+        },
+        .pipe = *pipe,
+        .length = length,
+        .shm = shm
+    };
+
+    int ret = rpc_get_int(usb_pid, RPC_USB_SV_DEVCT_FNN, sizeof(tbkrq),
+        (char*)&tbkrq);
+
+    if (length && (buffer != NULL) && receive) {
+        memcpy(buffer, shm_addr, length);
+    }
+
+    if (shm_addr != NULL) {
+        close_shared_memory(shm);
+    }
+
+    if (ret >= 0) {
+        pipe->trs.toggle = ret;
+        ret = 0;
+    }
+
+    return ret;
+}
+
+void usb_clear_halt(struct usb_pipe* pipe)
+{
+    struct usb_devctrl_clh clh = {
+        .req = {
+            .type = USB_DC_CLEAR_HALT
+        },
+        .pipe = *pipe
+    };
+
+    rpc_get_int(usb_pid, RPC_USB_SV_DEVCT_FNN, sizeof(clh), (char*)&clh);
+}
diff --git a/src/modules/usb/msd/usb-lib.h b/src/modules/usb/msd/usb-lib.h
new file mode 100644
index 0000000..2f7fb9b
--- /dev/null
+++ b/src/modules/usb/msd/usb-lib.h
@@ -0,0 +1,124 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#ifndef USB_LIB_H
+#define USB_LIB_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "usb-ddrv.h"
+#include "usb-server.h"
+#include "usb-structs.h"
+#include "usb-trans.h"
+
+/*
+ * Hinweis: Wenn hier die Rede von einem USB-Gerät ist, so ist ein logisches
+ * USB-Gerät gemeint. Dies kann sowohl ein echtes (physisches) Gerät sein oder
+ * aber auch nur ein Interface dieses Geräts (meistens letzteres, da so gut
+ * wie alle USB-Geräteklassen auf Interfaceebene arbeiten und somit die meisten
+ * physischen USB-Geräte genau ein Interface besitzen).
+ */
+
+/**
+ * Führt einen USB-Bulktransfer durch.
+ *
+ * @param pipe Zu verwendende Pipe
+ * @param buffer Zu bearbeitender Speicherbereich
+ * @param length Länge des Transfers
+ * @param receive true, wenn empfangen werden soll, sonst false.
+ *
+ * @return 0 bei Erfolg, sonst -errno.
+ */
+int usb_bulk_transfer(struct usb_pipe* pipe, void* buffer, size_t length,
+    bool receive);
+
+/**
+ * Entstallt einen Endpunkt.
+ *
+ * @param pipe Eine zum Endpunkt gehörige Pipe.
+ */
+void usb_clear_halt(struct usb_pipe* pipe);
+
+/**
+ * Führt einen USB-Controltransfer durch.
+ *
+ * @param dev Gerät
+ * @param pipe Zu verwendende Pipe oder NULL für die Default Control Pipe
+ * @param setup SETUP-Paket
+ * @param buffer Speicherbereich für die Datenphase
+ *
+ * @return 0 bei Erfolg, sonst -errno.
+ */
+int usb_control_transfer(struct usb_prov_dev* dev, struct usb_pipe* pipe,
+    struct usb_setup_packet* setup, void* buffer);
+
+/**
+ * Erstellt eine USB-Pipe.
+ *
+ * @param dev Zielgerät
+ * @param ep_number Nummer des Zielendpunkts (Nummer innerhalb des Interfaces,
+ *                  nicht ID!)
+ * @param pipe Speicherbereich, in dem die Daten der Pipe abgelegt werden
+ *             sollen.
+ */
+void usb_create_pipe(struct usb_prov_dev* dev, int ep_number,
+    struct usb_pipe* pipe);
+
+/**
+ * Empfängt Informationen zu einem Endpunkt.
+ *
+ * @param dev Gerät
+ * @param ep_number Nummer des Endpunkts
+ * @param ep_desc Pointer zu einem Speicherbereich, der einen Endpoint-
+ *                Descriptor aufnehmen kann.
+ */
+void usb_get_endpoint_info(struct usb_prov_dev* dev, int ep_number,
+    struct usb_endpoint_descriptor* ep_desc);
+
+/**
+ * Gibt die Interface-ID des logischen USB-Geräts zurück.
+ *
+ * @param dev Gerät
+ *
+ * @return Interface-ID
+ */
+int usb_get_interface_id(struct usb_prov_dev* dev);
+
+/**
+ * Gibt die Anzahl an Endpunkten des USB-Geräts zurück.
+ *
+ * @param dev Logisches Gerät
+ *
+ * @return Anzahl Endpunkte
+ */
+int usb_get_number_of_endpoints(struct usb_prov_dev* dev);
+
+#endif
diff --git a/src/modules/usb/uhci/Makefile.all b/src/modules/usb/uhci/Makefile.all
new file mode 100644
index 0000000..d0d0f5c
--- /dev/null
+++ b/src/modules/usb/uhci/Makefile.all
@@ -0,0 +1,8 @@
+shopt -s extglob
+source $LOST_BUILDMK_ROOT/config.sh
+
+CC=$CC -I../include
+
+echo "LD   $1/modules/uhci"
+$LOST_TOOLS_LD $LDSCRIPT -ouhci.mod  *.o --start-group $2 --end-group
+$LOST_TOOLS_STRIP -s uhci.mod -o $1/modules/uhci
diff --git a/src/modules/usb/uhci/ctrl.c b/src/modules/usb/uhci/ctrl.c
new file mode 100644
index 0000000..ad1c3a0
--- /dev/null
+++ b/src/modules/usb/uhci/ctrl.c
@@ -0,0 +1,96 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <ports.h>
+#include <sleep.h>
+
+#include "uhci.h"
+#include "usb-hub.h"
+
+void uhci_reset_port(struct uhci* hc, int port)
+{
+    if (hc == NULL)
+        return;
+
+    outw(hc->iobase + UHCI_RPORTS + port * 2, RPORT_ENABLE | RPORT_RESET | RPORT_CSC);
+    msleep(50);
+    uhci_set_port_status(hc, port, 1);
+    msleep(10);
+}
+
+int uhci_scan_port(struct uhci* hc, int port)
+{
+    int ret;
+
+    if (hc == NULL)
+        return 0;
+
+    uint_fast16_t val = inw(hc->iobase + UHCI_RPORTS + port * 2);
+
+    if (!(val & RPORT_DEVICE)) {
+        ret = 0;
+    } else {
+        ret = USB_HUB_DEVICE;
+        if (val & RPORT_LOSPD) {
+            ret |= USB_HUB_LOW_SPEED;
+        } else {
+            ret |= USB_HUB_FULL_SPEED;
+        }
+
+        if (val & RPORT_CSC) {
+            ret |= USB_HUB_CHANGE;
+            outw(hc->iobase + UHCI_RPORTS + port * 2, (val & RPORT_ENABLE) | RPORT_CSC);
+        }
+    }
+
+    return ret;
+}
+
+void uhci_set_port_status(struct uhci* hc, int port, int status)
+{
+    if (hc == NULL)
+        return;
+
+    int previous = inw(hc->iobase + UHCI_RPORTS + port * 2) & RPORT_ENABLE;
+    outw(hc->iobase + UHCI_RPORTS + port * 2, (status ? RPORT_ENABLE : 0) | RPORT_CSC);
+    msleep(50);
+    if (status && !previous)
+    {
+        outw(hc->iobase + UHCI_RPORTS + port * 2, RPORT_ENABLE | RPORT_RESUME);
+        msleep(20);
+        outw(hc->iobase + UHCI_RPORTS + port * 2, RPORT_ENABLE | RPORT_CSC);
+        msleep(10);
+    }
+}
diff --git a/src/modules/usb/uhci/init.c b/src/modules/usb/uhci/init.c
new file mode 100644
index 0000000..7a4d6f6
--- /dev/null
+++ b/src/modules/usb/uhci/init.c
@@ -0,0 +1,265 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <init.h>
+#include <pci.h>
+#include <ports.h>
+#include <rpc.h>
+#include <sleep.h>
+#include <syscall.h>
+
+#include "uhci.h"
+
+extern pid_t usb_pid, pci_pid;
+
+
+extern struct uhci* uhcis[IRQ_COUNT];
+extern void uhci_irq_handler(uint8_t irq);
+
+static uint16_t pci_inw(struct pci_device* dev, int reg)
+{
+    struct pci_config_space_access csa = {
+        .type = PCI_CSA_READ16,
+        .bus = dev->bus,
+        .device = dev->device,
+        .function = dev->function,
+        .reg = reg
+    };
+
+    return rpc_get_dword(pci_pid, RPC_PCI_CONFIG_SPACE_ACCESS, sizeof(csa),
+        (char*)&csa);
+}
+
+static void pci_outw(struct pci_device* dev, int reg, uint16_t val)
+{
+    struct pci_config_space_access csa = {
+        .type = PCI_CSA_WRITE16,
+        .bus = dev->bus,
+        .device = dev->device,
+        .function = dev->function,
+        .reg = reg,
+        .value = val
+    };
+
+    rpc_get_dword(pci_pid, RPC_PCI_CONFIG_SPACE_ACCESS, sizeof(csa),
+        (char*)&csa);
+}
+
+void init_uhc(struct pci_device* dev, size_t devlen)
+{
+    devlen -= sizeof(*dev);
+    int8_t* data = (int8_t*)(dev + 1);
+
+    struct pci_resource pres;
+    uint16_t iobase = 0, iosize = 0;
+
+    while (devlen >= sizeof(pres)) {
+        memcpy(&pres, data, sizeof(pres));
+
+        devlen -= sizeof(pres);
+        data += sizeof(pres);
+
+        if (pres.type == PCI_RESOURCE_PORT) {
+            iobase = pres.start;
+            iosize = pres.length;
+            break;
+        }
+    }
+
+    if (!iobase) {
+        return;
+    }
+
+    struct uhci* ndev = calloc(1, sizeof(*ndev));
+    ndev->pci = dev;
+    ndev->iobase = iobase;
+    ndev->rh = calloc(1, sizeof(*ndev->rh));
+
+    ndev->rh->ports = (iosize - 0x10) >> 1;
+
+    request_ports(iobase, iosize);
+    uhcis[dev->irq] = ndev;
+    register_intr_handler(TYNDUR_IRQ_OFFSET + dev->irq, &uhci_irq_handler);
+
+    outw(iobase + UHCI_USBCMD, GRESET);
+    msleep(50);
+    outw(iobase + UHCI_USBCMD, 0);
+
+    int i;
+    for (i = 2; i < ndev->rh->ports; i++) {
+        if (!(inw(iobase + UHCI_RPORTS + i*2) & 0x0080) ||
+            (inw(iobase + UHCI_RPORTS + i*2) == 0xFFFF))
+        {
+            // Ungültige Werte für einen Rootport, also ist das hier keiner
+            ndev->rh->ports = i;
+            break;
+        }
+    }
+
+    // Mehr als sieben Rootports sind leicht ungewöhnlich
+    if (ndev->rh->ports > 7) {
+        ndev->rh->ports = 2;
+    }
+
+    int legsup = pci_inw(dev, UHCI_PCI_LEGSUP);
+    int cmd = inw(iobase + UHCI_USBCMD);
+    int intr = inw(iobase + UHCI_USBINTR);
+
+    if ((legsup &
+        ~(UHCI_LEGSUP_STATUS | UHCI_LEGSUP_NO_CHG | UHCI_LEGSUP_PIRQ))  ||
+        (cmd & USB_RUN) || (cmd & CONFIGURE) || !(cmd & GLOB_SUSP_MODE) ||
+        (intr & 0x000F))
+    {
+        // Damit uns nicht die IRQs um die Ohren fliegen
+        outw(iobase + UHCI_USBSTS, 0x3F);
+
+        // Einen Frame abwarten
+        msleep(1);
+
+        // Alle LEGSUP-Statusbits löschen
+        pci_outw(dev, UHCI_PCI_LEGSUP, UHCI_LEGSUP_STATUS);
+
+        // Resetten
+        outw(iobase + UHCI_USBCMD, HCRESET);
+        // Ende des Resets abwarten
+        for (i = 0; (inw(iobase + UHCI_USBCMD) & HCRESET) && (i < 50); i++) {
+            msleep(10);
+        }
+
+        // Interrupts erstmal deaktivieren
+        outw(iobase + UHCI_USBINTR, 0);
+        // Den gesamten HC ebenso
+        outw(iobase + UHCI_USBCMD, 0);
+
+        // Alle Ports "runterfahren"
+        for (i = 0; i < ndev->rh->ports; i++) {
+            outw(iobase + UHCI_RPORTS + i * 2, 0);
+        }
+    }
+
+    ndev->frame_list = mem_allocate(4096, 0);
+    assert(ndev->frame_list);
+    ndev->p_frame_list = (uintptr_t)get_phys_addr(ndev->frame_list);
+    assert(ndev->p_frame_list);
+    ndev->frame_list_lock = 0;
+
+    ndev->queue_head = mem_allocate(sizeof(*ndev->queue_head), 0);
+    assert(ndev->queue_head);
+    ndev->p_queue_head = (uintptr_t)get_phys_addr(ndev->queue_head);
+    assert(ndev->p_queue_head);
+    ndev->queue_head_lock = 0;
+
+    // Alle Pointer auf "invalid" setzen
+    ndev->queue_head->next = 1;
+    ndev->queue_head->transfer = 1;
+    ndev->queue_head->q_first = NULL;
+    ndev->queue_head->q_last = NULL;
+
+    for (i = 0; i < 1024; i++) {
+        ndev->frame_list[i] = ndev->p_queue_head | 2;
+    }
+
+    // Alle 1000 µs ein Frame (Standardwert)
+    outb(iobase + UHCI_SOFMOD, 0x40);
+    // Unsere Frameliste eintragen
+    outl(iobase + UHCI_FRBASEADD, ndev->p_frame_list);
+    // Framenummer zurücksetzen
+    outw(iobase + UHCI_FRNUM, 0);
+
+    // Hier setzen wir das PIRQ-Bit und deaktivieren sämtlichen Legacy Support
+    pci_outw(dev, UHCI_PCI_LEGSUP, UHCI_LEGSUP_PIRQ);
+
+    // HC starten
+    outw(iobase + UHCI_USBCMD, USB_RUN | CONFIGURE | MAXP);
+    // Alle Interrupts aktivieren
+    outw(iobase + UHCI_USBINTR, 0xF);
+
+    // Connect-Status-Change-Bit zurücksetzen
+    for (i = 0; i < ndev->rh->ports; i++) {
+        outw(iobase + UHCI_RPORTS + i * 2, RPORT_CSC);
+    }
+
+    // Resumesignal treiben (egal, obs was bringt)
+    outw(iobase + UHCI_USBCMD, USB_RUN | CONFIGURE | MAXP | FORCE_GRESUME);
+    msleep(20);
+    outw(iobase + UHCI_USBCMD, USB_RUN | CONFIGURE | MAXP);
+    msleep(100);
+
+    register_uhci(ndev);
+}
+
+int check_pci(void)
+{
+    struct init_dev_desc* devs;
+
+    int ret = init_dev_list(&devs);
+    if (ret < 0) {
+        return 0;
+    }
+
+    int got_something = 0;
+
+    int8_t* data = (int8_t*)devs;
+    for (;;) {
+        size_t size;
+
+        if (ret < sizeof(*devs)) {
+            break;
+        }
+
+        devs = (struct init_dev_desc*)data;
+        size = sizeof(*devs) + devs->bus_data_size;
+        if (ret < size) {
+            break;
+        }
+
+        if (devs->type == 10) {
+            struct pci_device* dev = (struct pci_device*)devs->bus_data;
+            if ((dev->class_id == 0x0C) && (dev->subclass_id == 0x03) &&
+                (dev->interface_id == 0x00))
+            {
+                got_something = 1;
+                init_uhc(dev, size);
+            }
+        }
+
+        ret -= size;
+        data += size;
+    }
+
+    return got_something;
+}
diff --git a/src/modules/usb/uhci/main.c b/src/modules/usb/uhci/main.c
new file mode 100644
index 0000000..452f2ad
--- /dev/null
+++ b/src/modules/usb/uhci/main.c
@@ -0,0 +1,73 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <init.h>
+#include <rpc.h>
+#include <sleep.h>
+#include <syscall.h>
+
+#include "uhci.h"
+
+extern pid_t usb_pid, pci_pid;
+
+int main(void)
+{
+    init_messaging();
+
+    // Warten, damit dieser Prozess nach usb1 (und möglichst nach usb-msd)
+    // weiterläuft, sollten diese Treiber gleichzeitig gestartet werden
+    // (z. B. Bootvorgang)
+    msleep(2000);
+
+    usb_pid = init_service_get("usb1");
+    if (!usb_pid) {
+        fprintf(stderr, "You need to start the usb1 driver first.\n");
+        return 1;
+    }
+
+    pci_pid = init_service_get("pci");
+    if (!pci_pid) {
+        fprintf(stderr, "You need to start the pci driver first.\n");
+        return 1;
+    }
+
+    init_rpc_interface();
+
+    if (!check_pci()) {
+        return 0;
+    }
+
+    for (;;) {
+        wait_for_rpc();
+    }
+}
diff --git a/src/modules/usb/uhci/rpc.c b/src/modules/usb/uhci/rpc.c
new file mode 100644
index 0000000..e3f862e
--- /dev/null
+++ b/src/modules/usb/uhci/rpc.c
@@ -0,0 +1,297 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <init.h>
+#include <ports.h>
+#include <rpc.h>
+#include <syscall.h>
+
+#include "uhci.h"
+#include "usb-hc.h"
+#include "usb-server.h"
+
+// #define DEBUG
+// #define SHOW_ERRORS
+
+pid_t usb_pid, pci_pid;
+
+struct uhci* uhcis[IRQ_COUNT] = { NULL };
+
+void uhci_irq_handler(uint8_t irq)
+{
+    if ((irq < TYNDUR_IRQ_OFFSET) || (irq >= TYNDUR_IRQ_OFFSET + IRQ_COUNT)) {
+        return;
+    }
+
+    struct uhci* hc = uhcis[irq - TYNDUR_IRQ_OFFSET];
+
+    int status = inw(hc->iobase + UHCI_USBSTS);
+
+    if (!status) {
+        return;
+    }
+
+    if ((status & 0x10) || (status & 0x08)) {
+        fprintf(stderr, "[uhci] SERIOUS HOST ERROR CONDITION (STS: 0x%02X)\n", status);
+        return;
+    }
+
+    if (status & 0x20) {
+        fprintf(stderr, "[uhci] Erm, wtf. HC halted...\n");
+        return;
+    }
+
+    if (status & ~0x03) {
+        return;
+    }
+
+    struct uhci_td *td, *ntd;
+
+    lock(&hc->queue_head_lock);
+
+    td = (struct uhci_td*)hc->queue_head->q_first;
+
+    while (td != NULL) {
+        /*
+        #ifdef DEBUG
+        printf("Active: %i (next: 0x%08X)\n", td->flags.bits.active, td->next);
+        #endif
+        */
+        if (td->flags.bits.active) {
+            if (td->active_count--) {
+                break;
+            } else {
+                #ifdef DEBUG
+                printf("Active timeout on 0x%08X/0x%08X, QH -> 0x%08X/0x%08X\n",
+                    td, td->ptd, hc->queue_head->q_first,
+                    hc->queue_head->transfer);
+                #endif
+                td->flags.bits.active = 0;
+            }
+        }
+
+        #ifdef DEBUG
+        printf("Finished td %s %i:%i, flags: 0x%08X\n",
+            (td->pid == 0x69) ? "from" : "to", td->addr, td->ep,
+            td->flags.flags);
+        #endif
+
+        if (td->result != NULL) {
+            if (td->flags.bits.spd) {
+                #ifdef SHOW_ERRORS
+                printf("[uhci] Short packet detected\n");
+                #endif
+
+                if (hc->queue_head->transfer == td->ptd) {
+                    hc->queue_head->transfer = td->next;
+                }
+
+                *td->result = EMSGSIZE;
+            } else if ((status == 0x01) && !td->flags.bits.e_stall) {
+                #ifdef DEBUG
+                printf("[uhci] Fine, actual len: %i; max len: %i\n",
+                    td->flags.bits.act_len, td->maxlen);
+                #endif
+                if (((td->flags.bits.act_len + 1) & 0x7FF) < ((td->maxlen + 1) & 0x7FF)) {
+                    *td->result = EMSGSIZE;
+                } else {
+                    *td->result = 0;
+                }
+            } else {
+                td->pipe->toggle = td->toggle;
+                // TODO Weitere Transfers aus der Liste entfernen
+                #ifdef SHOW_ERRORS
+                printf("[uhci] Something failed, errors: %c%c%c%c%c%c\n",
+                    td->flags.bits.e_bitstuff ? 'b' : '-',
+                    td->flags.bits.e_crc_timeout ? 'c' : '-',
+                    td->flags.bits.e_nak ? 'n' : '-',
+                    td->flags.bits.e_babble ? 'q' : '-',
+                    td->flags.bits.e_buffer ? 'f' : '-',
+                    td->flags.bits.e_stall ? 's' : '-');
+                printf("[uhci] Next'll be: 0x%08X/0x%08X\n", td->next,
+                    td->q_next);
+                #endif
+
+                if (hc->queue_head->transfer == td->ptd) {
+                    hc->queue_head->transfer = td->next;
+                }
+
+                if (td->flags.bits.e_stall) {
+                    *td->result = EHOSTDOWN;
+                } else {
+                    *td->result = EAGAIN;
+                }
+            }
+        }
+
+        ntd = td->q_next;
+        if (td->free_on_completion) {
+            mem_free(td, 4096);
+        }
+
+        if (td->next & 1) {
+            td = ntd;
+            break;
+        }
+
+        td = ntd;
+    }
+
+    hc->queue_head->q_first = td;
+    if (td == NULL) {
+        hc->queue_head->q_last = NULL;
+        hc->queue_head->transfer = 1;
+    }
+
+    unlock(&hc->queue_head_lock);
+
+    outw(hc->iobase + UHCI_USBSTS, status);
+}
+
+void uhci_hct_handler(pid_t src, uint32_t corr_id, size_t length, void* data)
+{
+    struct usb_hc_trs* trs = data;
+    void* shm;
+    int result;
+
+    if (length < sizeof(*trs)) {
+        rpc_send_int_response(src, corr_id, -EINVAL);
+        return;
+    }
+
+    switch (trs->type)
+    {
+        case USB_TRST_CONTROL:
+            if (length < sizeof(struct usb_hc_trs_ctrl)) {
+                rpc_send_int_response(src, corr_id, -EINVAL);
+                return;
+            }
+            struct usb_hc_trs_ctrl* ctrl = data;
+
+            shm = open_shared_memory(ctrl->shm);
+            result = uhci_do_control(trs->hc.hcd_avail, &trs->pipe,
+                &ctrl->setup, shm);
+            close_shared_memory(ctrl->shm);
+            rpc_send_int_response(src, corr_id, result);
+            break;
+        case USB_TRST_BULK:
+            if (length < sizeof(struct usb_hc_trs_bulk)) {
+                rpc_send_int_response(src, corr_id, -EINVAL);
+                return;
+            }
+            struct usb_hc_trs_bulk* bulk = data;
+
+            shm = open_shared_memory(bulk->shm);
+            result = uhci_do_bulk(trs->hc.hcd_avail, &trs->pipe,
+                bulk->receive, shm, bulk->length);
+            close_shared_memory(bulk->shm);
+
+            if (!result) {
+                // Irgendwie muss der Status des Bits ja zurück
+                result = trs->pipe.toggle;
+            }
+            rpc_send_int_response(src, corr_id, result);
+            break;
+        default:
+            rpc_send_int_response(src, corr_id, -EINVAL);
+            break;
+    }
+}
+
+void uhci_hcc_handler(pid_t src, uint32_t corr_id, size_t length, void* data)
+{
+    struct usb_hc_ctrl_req* rq = data;
+    struct usb_hc_ctrl_scan* rqsc = data;
+    struct usb_hc_ctrl_dsbl* rqdbl = data;
+    struct usb_hc_ctrl_rst* rqrst = data;
+
+    if (length < sizeof(*rq)) {
+        rpc_send_int_response(src, corr_id, 0);
+        return;
+    }
+
+    switch (rq->type)
+    {
+        case HC_CTRL_SCAN_PORT:
+            if (length < sizeof(*rqsc)) {
+                rpc_send_int_response(src, corr_id, 0);
+                return;
+            }
+            int result = uhci_scan_port(rq->hc.hcd_avail, rqsc->port);
+            rpc_send_int_response(src, corr_id, result);
+            break;
+        case HC_CTRL_DSBL_PORT:
+            if (length < sizeof(*rqdbl)) {
+                rpc_send_int_response(src, corr_id, 0);
+                return;
+            }
+            uhci_set_port_status(rq->hc.hcd_avail, rqdbl->port, 0);
+            rpc_send_int_response(src, corr_id, 1);
+            break;
+        case HC_CTRL_RESET:
+            if (length < sizeof(*rqrst)) {
+                rpc_send_int_response(src, corr_id, 0);
+                return;
+            }
+            uhci_reset_port(rq->hc.hcd_avail, rqrst->port);
+            rpc_send_int_response(src, corr_id, 1);
+            break;
+        case HC_CTRL_ADD_PIPE:
+            rpc_send_int_response(src, corr_id, 1);
+            break;
+        default:
+            rpc_send_int_response(src, corr_id, 0);
+            break;
+    }
+}
+
+void init_rpc_interface(void)
+{
+    register_message_handler(RPC_USB_HC_CONTROL_FNN, &uhci_hcc_handler);
+    register_message_handler(RPC_USB_HC_TRANSFER_FNN, &uhci_hct_handler);
+}
+
+void register_uhci(struct uhci* hc)
+{
+    struct usb_hc rhc = {
+        .root_ports = hc->rh->ports,
+        .hcd_avail = hc
+    };
+
+    if (!rpc_get_int(usb_pid, RPC_USB_SV_REGHC_FNN, sizeof(rhc), (char*)&rhc)) {
+        fprintf(stderr, "Could not register UHCI.\n");
+    }
+}
diff --git a/src/modules/usb/uhci/trans.c b/src/modules/usb/uhci/trans.c
new file mode 100644
index 0000000..b9c82c2
--- /dev/null
+++ b/src/modules/usb/uhci/trans.c
@@ -0,0 +1,316 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <syscall.h>
+
+#include "uhci.h"
+#include "usb-hc.h"
+#include "usb-trans.h"
+
+#define USB_SETUP_OUT (0 << 7)
+#define USB_SETUP_IN  (1 << 7)
+
+int insert_td(struct uhci* hc, uintptr_t ptd, struct uhci_td* td);
+
+int uhci_do_control(struct uhci* hc, struct usb_trans_pipe* pipe,
+            struct usb_setup_packet* setup, void* buffer)
+{
+    if ((pipe->speed != USB_HUB_LOW_SPEED) &&
+        (pipe->speed != USB_HUB_FULL_SPEED))
+    {
+        return -EPROTOTYPE;
+    }
+
+    struct uhci_td* td = mem_allocate(sizeof(*td), 0);
+    assert(td);
+    uintptr_t ptd = (uintptr_t)get_phys_addr(td);
+    assert(ptd);
+
+    volatile int status;
+
+    do {
+        status = EALREADY;
+
+        td->next = 1;
+        if (pipe->speed == USB_HUB_LOW_SPEED) {
+            td->flags.flags = 0x1D800000;
+        } else {
+            td->flags.flags = 0x19800000;
+        }
+        td->pid = USB_SETUP;
+        td->toggle = 0;
+        td->addr = pipe->usb_addr;
+        td->ep = pipe->ep_id;
+
+        td->maxlen = sizeof(*setup) - 1;
+        td->buffer = (uintptr_t)get_phys_addr(setup);
+
+        td->result = &status;
+        td->free_on_completion = 0;
+
+        td->pipe = pipe;
+
+        while (insert_td(hc, ptd, td));
+
+        while (status == EALREADY);
+    } while (status == EAGAIN);
+
+    if (status) {
+        if (status == EHOSTDOWN) {
+            pipe->stalled = 1;
+        }
+
+        mem_free(td, 4096);
+        return -status;
+    }
+
+    pipe->toggle = 1;
+
+    int remaining = setup->length;
+    int direction, done = 0;
+
+    if (setup->type & USB_SETUP_IN) {
+        direction = USB_IN;
+    } else {
+        direction = USB_OUT;
+    }
+
+    while (remaining) {
+        int this_len = (remaining > pipe->mps) ? pipe->mps : remaining;
+
+        remaining -= this_len;
+
+        do {
+            status = EALREADY;
+
+            td->next = 1;
+            if (pipe->speed == USB_HUB_LOW_SPEED) {
+                td->flags.flags = 0x1D800000;
+            } else {
+                td->flags.flags = 0x19800000;
+            }
+            td->pid = direction;
+            td->toggle = pipe->toggle;
+            td->addr = pipe->usb_addr;
+            td->ep = pipe->ep_id;
+
+            td->maxlen = (unsigned int)(this_len - 1) & 0x7FF;
+            td->buffer = (uintptr_t)get_phys_addr((void*)((uintptr_t)buffer + done));
+
+            td->result = &status;
+            td->free_on_completion = 0;
+
+            while (insert_td(hc, ptd, td));
+
+            while (status == EALREADY);
+        } while (status == EAGAIN);
+
+        if (status && (status != EMSGSIZE)) {
+            if (status == EHOSTDOWN) {
+                pipe->stalled = 1;
+            }
+
+            mem_free(td, 4096);
+            return -status;
+        }
+
+        pipe->toggle ^= 1;
+        done += this_len;
+
+        if (status == EMSGSIZE)
+            break;
+    }
+
+    if (direction == USB_IN) {
+        direction = USB_OUT;
+    } else {
+        direction = USB_IN;
+    }
+
+    do {
+        status = EALREADY;
+
+        td->next = 1;
+        if (pipe->speed == USB_HUB_LOW_SPEED) {
+            td->flags.flags = 0x1D800000;
+        } else {
+            td->flags.flags = 0x19800000;
+        }
+        td->pid = direction;
+        td->toggle = 1;
+        td->addr = pipe->usb_addr;
+        td->ep = pipe->ep_id;
+
+        td->maxlen = 0x7FF;
+        td->buffer = 0;
+
+        td->result = &status;
+        td->free_on_completion = 0;
+
+        while (insert_td(hc, ptd, td));
+
+        while (status == EALREADY);
+    } while (status == EAGAIN);
+
+    if (status == EHOSTDOWN) {
+        pipe->stalled = 1;
+    }
+
+    pipe->toggle = 0;
+    mem_free(td, sizeof(*td));
+
+    return -status;
+}
+
+int uhci_do_bulk(struct uhci* hc, struct usb_trans_pipe* pipe, bool receive,
+    void* buffer, size_t length)
+{
+    if ((pipe->speed != USB_HUB_LOW_SPEED) &&
+        (pipe->speed != USB_HUB_FULL_SPEED))
+    {
+        return -EPROTOTYPE;
+    }
+
+    if (!length) {
+        return -EINVAL;
+    }
+
+    // printf("Issuing bulk (%i B expected)\n", length);
+
+    struct uhci_td* td = mem_allocate(sizeof(*td), 0);
+    assert(td);
+    uintptr_t ptd = (uintptr_t)get_phys_addr(td);
+    assert(ptd);
+
+    volatile int res;
+
+    int remaining = length;
+    int done = 0;
+
+    while (remaining) {
+        // printf("%i B to go\n", remaining);
+        int this_len = (remaining > pipe->mps) ? pipe->mps : remaining;
+
+        remaining -= this_len;
+
+        td->next = 1;
+        if (pipe->speed == USB_LOW_SPEED) {
+            td->flags.flags = 0x1D800000;
+        } else {
+            td->flags.flags = 0x19800000;
+        }
+        if (receive) {
+            td->pid = USB_IN;
+        } else {
+            td->pid = USB_OUT;
+        }
+        td->toggle = pipe->toggle;
+        td->addr = pipe->usb_addr;
+        td->ep = pipe->ep_id;
+
+        td->maxlen = (unsigned int)(this_len - 1) & 0x7FF;
+        td->buffer = (uintptr_t)
+            get_phys_addr((void *)((uintptr_t)buffer + done));
+
+        res = EALREADY;
+        td->result = &res;
+        td->free_on_completion = 0;
+        td->pipe = pipe;
+
+        // printf("Inserting TD\n");
+        while (insert_td(hc, ptd, td));
+
+        // printf("Waiting for transmission\n");
+        while (res == EALREADY);
+        // printf("Thru\n");
+
+        if (res == EAGAIN) {
+            remaining += this_len;
+            continue;
+        }
+
+        if (res) {
+            return -res;
+        }
+
+        pipe->toggle ^= 1;
+
+        done += this_len;
+    }
+
+    if (res == EHOSTDOWN) {
+        pipe->stalled = 1;
+    }
+
+    mem_free(td, sizeof(*td));
+
+    return -res;
+}
+
+int insert_td(struct uhci* hc, uintptr_t ptd, struct uhci_td* td)
+{
+    struct uhci_td *last;
+
+    lock(&hc->queue_head_lock);
+
+    td->ptd = ptd;
+    td->q_next = NULL;
+    td->active_count = 10;
+
+    if (hc->queue_head->transfer & 1) {
+        // Insert as first element to be done
+        if (hc->queue_head->q_last != NULL) {
+            hc->queue_head->q_last->q_next = td;
+        } else {
+            hc->queue_head->q_first = td;
+        }
+
+        hc->queue_head->q_last = td;
+        hc->queue_head->transfer = ptd;
+    } else {
+        last = (struct uhci_td*)hc->queue_head->q_last;
+        #ifdef DEBUG
+        printf("[uhci] Will append to 0x%08X (p 0x%08X)\n", last, hc->queue_head->transfer);
+        #endif
+
+        last->q_next = td;
+        hc->queue_head->q_last = td;
+        last->next = ptd | 4;
+    }
+
+    unlock(&hc->queue_head_lock);
+
+    return 0;
+}
diff --git a/src/modules/usb/uhci/uhci.h b/src/modules/usb/uhci/uhci.h
new file mode 100644
index 0000000..c6b758c
--- /dev/null
+++ b/src/modules/usb/uhci/uhci.h
@@ -0,0 +1,269 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#ifndef UHCI_H
+#define UHCI_H
+
+#include <stdint.h>
+#include <lock.h>
+
+#include "usb-hc.h"
+#include "usb-trans.h"
+
+
+#define TYNDUR_IRQ_OFFSET 0x20
+#define IRQ_COUNT         0x10
+
+// Befehlsregister (uint16_t)
+#define UHCI_USBCMD    0x00
+// Statusregister (uint16_t)
+#define UHCI_USBSTS    0x02
+// Interruptregister (uint16_t)
+#define UHCI_USBINTR   0x04
+// Aktuelle Framenummer (uint16_t)
+#define UHCI_FRNUM     0x06
+// Pointer zur Frameliste (uint32_t)
+#define UHCI_FRBASEADD 0x08
+// Bestimmt die genaue Länge eines Frames (uint8_t)
+#define UHCI_SOFMOD    0x0C
+// Array von Informationen über je einen Rootport (je uint16_t)
+#define UHCI_RPORTS    0x10
+
+#define MAXP           (1 << 7)
+#define CONFIGURE      (1 << 6)
+// Resumesignal treiben
+#define FORCE_GRESUME  (1 << 4)
+// Alle Rootports befinden sich im Suspendmodus
+#define GLOB_SUSP_MODE (1 << 3)
+// RESET-Signal wird an allen Rootports getrieben
+#define GRESET         (1 << 2)
+// HC wird zurückgesetzt
+#define HCRESET        (1 << 1)
+// Normaler Ausführungsmodus
+#define USB_RUN        (1 << 0)
+
+// Setzt einen Rootport zurück
+#define RPORT_RESET    (1 << 9)
+// Gibt an, ob ein Low-Speed-Gerät angeschlossen ist
+#define RPORT_LOSPD    (1 << 8)
+// Treibt das Resume-Signal auf dem Bus
+#define RPORT_RESUME   (1 << 6)
+// Schaltet den Rootport ein
+#define RPORT_ENABLE   (1 << 2)
+// Wird gesetzt, wenn ein Gerät angeschlossen oder entfernt wird
+#define RPORT_CSC      (1 << 1)
+// Gibt an, ob ein Gerät angeschlossen ist
+#define RPORT_DEVICE   (1 << 0)
+
+// Das Legacy-Support-Register im PCI-Konfigurationsraum (uint16_t)
+#define UHCI_PCI_LEGSUP 0xC0
+
+// Alle Statusbits, die mittels Schreiben einer 1 gelöscht werden
+#define UHCI_LEGSUP_STATUS 0x8F00
+// Unveränderliche Bits (RO oder reserviert)
+#define UHCI_LEGSUP_NO_CHG 0x5040
+// Interrupt wird als PCI-IRQ ausgeführt
+#define UHCI_LEGSUP_PIRQ   0x2000
+
+
+struct uhci_td {
+    volatile uint32_t next;
+
+    union {
+        volatile uint32_t flags;
+        struct {
+            volatile unsigned act_len : 11;
+            unsigned rsvd1 : 6;
+            volatile unsigned e_bitstuff : 1;
+            volatile unsigned e_crc_timeout : 1;
+            volatile unsigned e_nak : 1;
+            volatile unsigned e_babble : 1;
+            volatile unsigned e_buffer : 1;
+            volatile unsigned e_stall : 1;
+            volatile unsigned active : 1;
+            unsigned ioc : 1;
+            unsigned isochronous : 1;
+            unsigned low_speed : 1;
+            volatile unsigned errors : 2;
+            unsigned spd : 1;
+            unsigned rsvd2 : 2;
+        } __attribute__((packed)) bits;
+    } __attribute__((packed)) flags;
+
+    unsigned pid : 8;
+    unsigned addr : 7;
+    unsigned ep : 4;
+    unsigned toggle : 1;
+    unsigned rsvd : 1;
+    unsigned maxlen : 11;
+
+    uint32_t buffer;
+
+    // Diese Felder sind für den HCD
+
+    // Nächster TD in der Warteschlange
+    struct uhci_td* q_next;
+
+    // Pointer zu einer Variable, die einen errno-Wert aufnimmt
+    volatile int* result;
+
+    // Ist dieses Flag gesetzt, so wird der TD nach Abarbeitung vom IRQ-Handler
+    // automatisch freigegeben
+    int free_on_completion;
+
+    // Physische Adresse
+    uintptr_t ptd;
+
+    // Entsprechende Pipe
+    struct usb_trans_pipe* pipe;
+
+    int active_count;
+} __attribute__((packed));
+
+struct uhci_qh {
+    volatile uint32_t next;
+    volatile uint32_t transfer;
+
+    // Diese Felder sind für den HCD
+
+    // Erster TD in der Warteschlange (oder NULL, wenn keiner)
+    volatile struct uhci_td* q_first;
+
+    // Letzter TD in der Warteschlange (oder NULL, wenn keiner)
+    volatile struct uhci_td* q_last;
+} __attribute__((packed));
+
+// Beschreibt ein UHCI
+struct uhci {
+    // PCI-Geräteinformationen
+    struct pci_device* pci;
+    // Beginn des I/O-Raums
+    uint16_t iobase;
+
+    // Physische Adresse der Framelist
+    uintptr_t p_frame_list;
+    // Virtuelle Adresse der Framelist
+    uint32_t* frame_list;
+    // Lock für den Zugriff auf diese Liste
+    lock_t frame_list_lock;
+
+    // Physische Adresse des (bisher einzigen) QHs
+    uintptr_t p_queue_head;
+    // Virtuelle Adresse des QHs
+    struct uhci_qh* queue_head;
+    // Lock für den Zugriff auf diesen
+    lock_t queue_head_lock;
+
+    // Roothub, der durch das UHCI bereitgestellt wird
+    struct usb_rh* rh;
+};
+
+// Beschreibt einen Roothub (nur für UHCI)
+struct usb_rh {
+    // Anzahl der Rootports
+    int ports;
+};
+
+
+/**
+ * Durchsucht alle verfügbaren PCI-Geräte nach einem UHCI.
+ *
+ * @return 1, wenn ein UHCI gefunden wurde, sonst 0.
+ */
+int check_pci(void);
+
+/**
+ * Initialisiert das RPC-Interface (Handler)
+ */
+void init_rpc_interface(void);
+
+/**
+ * Registriert einen UHCI als HC beim USB-Treiber.
+ *
+ * @param hc Das zu registrierende UHCI
+ */
+void register_uhci(struct uhci* hc);
+
+/**
+ * Führt einen Bulktransfer durch.
+ *
+ * @param hc UHCI
+ * @param pipe Pipe, durch die die Übertragung stattfinden soll
+ * @param receive true, wenn empfangen werden soll, sonst false
+ * @param buffer Zielspeicherbereich
+ * @param length (Angestrebte) Länge des Transfers
+ *
+ * @return 0 bei Erfolg, sonst -errno
+ */
+int uhci_do_bulk(struct uhci* hc, struct usb_trans_pipe* pipe, bool receive,
+    void* buffer, size_t length);
+
+/**
+ * Führt einen Controltransfer durch.
+ *
+ * @param hc UHCI
+ * @param pipe Pipe, durch die die Übertragung stattfinden soll
+ * @param setup SETUP-Paket
+ * @param buffer Speicherbereich, mit dem während der Datenphase gearbeitet
+ *               werden soll.
+ *
+ * @return 0 bei Erfolg, sonst -errno
+ */
+int uhci_do_control(struct uhci* hc, struct usb_trans_pipe* pipe,
+    struct usb_setup_packet* setup, void* buffer);
+
+/**
+ * Treibt das Resetsignal auf einem Port und aktiviert ihn.
+ *
+ * @param hc UHCI
+ * @param port Der Portindex
+ */
+void uhci_reset_port(struct uhci* hc, int port);
+
+/**
+ * Überprüft einen Port.
+ *
+ * @param hc UHCI
+ * @param port Zu überprüfender Port
+ *
+ * @return Status (USB_HUB_...)
+ */
+int uhci_scan_port(struct uhci* hc, int port);
+
+/**
+ * Aktiviert oder deaktiviert einen Port.
+ *
+ * @param hc UHCI
+ * @param port Portindex
+ * @param status 1 zum Aktivieren, 0 zum Deaktivieren
+ */
+void uhci_set_port_status(struct uhci* hc, int port, int status);
+
+#endif
diff --git a/src/modules/usb/usb1/Makefile.all b/src/modules/usb/usb1/Makefile.all
new file mode 100644
index 0000000..a0f9525
--- /dev/null
+++ b/src/modules/usb/usb1/Makefile.all
@@ -0,0 +1,8 @@
+shopt -s extglob
+source $LOST_BUILDMK_ROOT/config.sh
+
+CC=$CC -I../include
+
+echo "LD   $1/modules/usb1"
+$LOST_TOOLS_LD $LDSCRIPT -ousb1.mod  *.o --start-group $2 --end-group
+$LOST_TOOLS_STRIP -s usb1.mod -o $1/modules/usb1
diff --git a/src/modules/usb/usb1/detect.c b/src/modules/usb/usb1/detect.c
new file mode 100644
index 0000000..54ed6d7
--- /dev/null
+++ b/src/modules/usb/usb1/detect.c
@@ -0,0 +1,440 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <collections.h>
+#include <rpc.h>
+#include <syscall.h>
+
+#include "usb.h"
+#include "usb-ddrv.h"
+#include "usb-hc.h"
+#include "usb-hub.h"
+
+extern void usb_found_hub(struct usb_device* dev);
+
+extern list_t* usb_ddrvs;
+extern list_t* unhandled_devs;
+
+static const char* speed_name(int speed)
+{
+    switch (speed) {
+        case USB_LOW_SPEED:
+            return "low speed";
+        case USB_FULL_SPEED:
+            return "full speed";
+        case USB_HIGH_SPEED:
+            return "high speed";
+        default:
+            return "unknown speed";
+    }
+}
+
+static int fits(int is, int want)
+{
+    if (want == -1)
+        return -1;
+    return !!(is == want);
+}
+
+static int provide_to(struct usb_device* dev, int ifc_num,
+    struct usb_interface_descriptor* ifc, struct usb_ddrv* drv)
+{
+    struct usb_prov_dev pd = {
+        .is_interface = (ifc == NULL) ? false : true,
+        .dev_id = dev,
+        .interface_id = ifc_num,
+        .type = {
+            .vendor_id = dev->dev_desc->vendor_id,
+            .device_id = dev->dev_desc->device_id,
+            .class = (ifc == NULL) ? dev->dev_desc->class : ifc->class,
+            .subclass = (ifc == NULL) ? dev->dev_desc->subclass : ifc->subclass,
+            .protocol = (ifc == NULL) ? dev->dev_desc->protocol : ifc->protocol
+        }
+    };
+
+    return rpc_get_int(drv->pid, RPC_USB_DDRV_PLUG_FNN, sizeof(pd), (char*)&pd);
+}
+
+static void dev_is_unhandled(struct usb_device* dev, int ifc_num,
+    struct usb_interface_descriptor* ifc)
+{
+    struct usb_prov_dev* pd = calloc(1, sizeof(*pd));
+
+    pd->is_interface = (ifc == NULL) ? false : true;
+    pd->dev_id = dev;
+    pd->interface_id = ifc_num;
+    pd->type.vendor_id = dev->dev_desc->vendor_id;
+    pd->type.device_id = dev->dev_desc->device_id;
+    pd->type.class = (ifc == NULL) ? dev->dev_desc->class : ifc->class;
+    pd->type.subclass = (ifc == NULL) ? dev->dev_desc->subclass : ifc->subclass;
+    pd->type.protocol = (ifc == NULL) ? dev->dev_desc->protocol : ifc->protocol;
+
+    list_push(unhandled_devs, pd);
+}
+
+#define check(svar, lname) int svar##f = fits(svar, drv->handle.lname); \
+    if (!svar##f) { continue; }
+
+#define provto(check) if (check && provide_to(dev, ifc_num, ifc, drv)) \
+    { break; }
+
+static void provide(struct usb_device* dev, int ifc_num,
+    struct usb_interface_descriptor* ifc)
+{
+    int vid, did, cls, scl, ptc;
+
+    vid = dev->dev_desc->vendor_id;
+    did = dev->dev_desc->device_id;
+    if (ifc == NULL) {
+        cls = dev->dev_desc->class;
+        scl = dev->dev_desc->subclass;
+        ptc = dev->dev_desc->protocol;
+    } else {
+        cls = ifc->class;
+        scl = ifc->subclass;
+        ptc = ifc->protocol;
+    }
+
+    int i, s = list_size(usb_ddrvs);
+    for (i = 0; i < s; i++) {
+        struct usb_ddrv* drv = list_get_element_at(usb_ddrvs, i);
+
+        check(vid, vendor_id)
+        check(did, device_id)
+        check(cls, class)
+        check(scl, subclass)
+        check(ptc, protocol)
+
+        // Wenn jemandem noch eine sinnvolle Kombination einfällt, kann er die
+        // gern hier eintragen.
+        // If anyone knows another combination making sense, he is encouraged
+        // to insert it here.
+        provto(vidf && didf)
+        provto(vidf &&         clsf && sclf && ptcf)
+        provto(                clsf && sclf && ptcf)
+        provto(vidf &&         clsf && sclf)
+        provto(                clsf && sclf)
+        provto(vidf &&         clsf)
+        provto(                clsf)
+    }
+
+    if (i == s) {
+        dev_is_unhandled(dev, ifc_num, ifc);
+    }
+}
+
+void update_ep_trs_info(struct usb_pipe* ep)
+{
+    ep->trs.usb_addr = ep->dev->addr;
+    ep->trs.ep_id = ep->ep->number;
+    ep->trs.mps = ep->ep->mps;
+    ep->trs.type = ep->ep->type;
+    ep->trs.speed = ep->dev->speed;
+}
+
+#define TNC(fnc) if ((ret = fnc)) { \
+    printf("[usb1] err@%i, ret is %i\n" # fnc "\n", __LINE__, ret); return; }
+
+void enumerate_device(struct usb_device* dev)
+{
+    struct usb_hub* hub = dev->parent;
+    int p = dev->hub_port;
+
+    printf("[usb1] Enumerating %s device on port %i of some hub\n", speed_name(dev->speed), dev->hub_port);
+
+    hub->reset_port(hub, p);
+    dev->addr = 0;
+    dev->state = USB_DEFAULT;
+
+    struct usb_pipe* ep0;
+    dev->ep0 = ep0 = calloc(1, sizeof(*ep0));
+
+    ep0->dev = dev;
+    ep0->ep = calloc(1, sizeof(*ep0->ep));
+    ep0->ep->number = 0;
+    ep0->ep->mps = 8;
+    ep0->ep->type = USB_EP_CONTROL;
+
+    update_ep_trs_info(ep0);
+
+    ep0->trs.toggle = 0;
+    ep0->trs.stalled = false;
+
+    if (hub->add_pipe != NULL) {
+        hub->add_pipe(hub, ep0);
+    }
+
+    dev->dev_desc = calloc(1, sizeof(*dev->dev_desc));
+
+    int ret = usb_control_transfer(ep0,
+        USB_SETUP_IN | USB_SETUP_REQ_STD | USB_SETUP_REC_DEV,
+        USB_GET_DESCRIPTOR, USB_DESC_DEVICE | 0, 0, 8, dev->dev_desc);
+
+    printf("[usb1] mps0 is %i B\n", dev->dev_desc->mps0);
+
+    if (ret) {
+        fprintf(stderr, "[usb1] Warning: first transfer returned %i\n", ret);
+    }
+
+    if (!dev->dev_desc->mps0) {
+        return;
+    }
+
+    hub->reset_port(hub, p);
+    ep0->ep->mps = dev->dev_desc->mps0;
+    ep0->trs.stalled = false;
+    update_ep_trs_info(ep0);
+
+    int address = dev->hc->addr_counter++;
+    TNC(usb_control_transfer(ep0,
+        USB_SETUP_OUT | USB_SETUP_REQ_STD | USB_SETUP_REC_DEV, USB_SET_ADDRESS,
+        address, 0, 0, NULL));
+    dev->addr = address;
+    update_ep_trs_info(ep0);
+
+    if (hub->add_pipe != NULL) {
+        hub->add_pipe(hub, dev->ep0);
+    }
+
+    dev->state = USB_ADDRESS;
+
+    TNC(usb_control_transfer(ep0,
+        USB_SETUP_IN | USB_SETUP_REQ_STD | USB_SETUP_REC_DEV,
+        USB_GET_DESCRIPTOR, USB_DESC_DEVICE | 0, 0, sizeof(*dev->dev_desc),
+        dev->dev_desc));
+
+    printf("[usb1] 0x%04X:0x%04X (%i configs)\n", dev->dev_desc->vendor_id,
+        dev->dev_desc->device_id, dev->dev_desc->num_configurations);
+
+    int i;
+
+    if (dev->dev_desc->i_manufacturer) {
+        uint8_t name[255];
+
+        TNC(usb_control_transfer(ep0,
+            USB_SETUP_IN | USB_SETUP_REQ_STD | USB_SETUP_REC_DEV,
+            USB_GET_DESCRIPTOR, USB_DESC_STRING | dev->dev_desc->i_manufacturer,
+            0, 255, name));
+
+        printf("[usb1]  -> Manufacturer: ");
+        for (i = 2; i < name[0]; i += 2) {
+            printf("%c", name[i]);
+        }
+        printf("\n");
+    }
+    if (dev->dev_desc->i_product) {
+        uint8_t name[255];
+
+        TNC(usb_control_transfer(ep0,
+            USB_SETUP_IN | USB_SETUP_REQ_STD | USB_SETUP_REC_DEV,
+            USB_GET_DESCRIPTOR, USB_DESC_STRING | dev->dev_desc->i_product,
+            0, 255, name));
+
+        printf("[usb1]  -> Product: ");
+        for (i = 2; i < name[0]; i += 2) {
+            printf("%c", name[i]);
+        }
+        printf("\n");
+    }
+
+    dev->cfg_desc = calloc(dev->dev_desc->num_configurations, sizeof(*dev->cfg_desc));
+    for (i = 0; i < dev->dev_desc->num_configurations; i++) {
+        uint8_t tmp[9];
+
+        // Erstmal Länge aller Deskriptoren herausfinden
+        TNC(usb_control_transfer(ep0,
+            USB_SETUP_IN | USB_SETUP_REQ_STD | USB_SETUP_REC_DEV,
+            USB_GET_DESCRIPTOR, USB_DESC_CONFIGURATION | i, 0, 9, tmp));
+        dev->cfg_desc[i] = calloc(1, tmp[2] | (tmp[3] << 8));
+        TNC(usb_control_transfer(ep0,
+            USB_SETUP_IN | USB_SETUP_REQ_STD | USB_SETUP_REC_DEV,
+            USB_GET_DESCRIPTOR, USB_DESC_CONFIGURATION | i, 0,
+            tmp[2] | (tmp[3] << 8), dev->cfg_desc[i]));
+    }
+
+    if (dev->dev_desc->class == 9) {
+        usb_found_hub(dev);
+        return;
+    }
+
+    if (dev->dev_desc->class) {
+        provide(dev, 0, NULL);
+    }
+
+    struct usb_config_descriptor* best_cfg = dev->cfg_desc[0];
+
+    int c;
+    for (c = 0; c < dev->dev_desc->num_configurations; c++) {
+        struct usb_config_descriptor* cur_cfg = dev->cfg_desc[c];
+
+        if (cur_cfg->self_powered && !best_cfg->self_powered) {
+            // Wir wollen möglichst Self-powered
+            best_cfg = cur_cfg;
+        } else if (cur_cfg->max_power > best_cfg->max_power) {
+            // Und möglichst hohen Stromverbrauch (FIXME: Das aber nicht immer)
+            best_cfg = cur_cfg;
+        }
+    }
+
+    dev->cur_cfg = best_cfg;
+    usb_set_configuration(dev, best_cfg->configuration_value);
+
+    struct usb_interface_descriptor* cur_ifc = (struct usb_interface_descriptor*)(best_cfg + 1);
+
+    for (i = 0; i < best_cfg->num_interfaces; i++) {
+        if (cur_ifc->class && !cur_ifc->alternate_setting) {
+            provide(dev, i, cur_ifc);
+        }
+
+        cur_ifc = (struct usb_interface_descriptor*)
+            ((struct usb_endpoint_descriptor*)(cur_ifc + 1) +
+            cur_ifc->num_endpoints);
+    }
+}
+
+void scan_hub(struct usb_hub* hub)
+{
+    int p;
+
+    printf("[usb1] Hub with %i ports detected.\n", hub->ports);
+
+    for (p = 0; p < hub->ports; p++) {
+        hub->disable_port(hub, p);
+    }
+
+    for (p = 0; p < hub->ports; p++) {
+        int stat = hub->scan_port(hub, p);
+
+        if (stat & USB_HUB_DEVICE) {
+            struct usb_device* dev = calloc(1, sizeof(*dev));
+
+            dev->parent = hub;
+            dev->hub_port = p;
+
+            if (hub->root_hub) {
+                dev->hc = hub->dev.hc;
+            } else {
+                dev->hc = hub->dev.usb->hc;
+            }
+
+            dev->addr = 0;
+            dev->state = USB_ATTACHED;
+            dev->speed = stat & USB_HUB_SPEED;
+
+            enumerate_device(dev);
+        }
+    }
+}
+
+static void rh_addpipe(struct usb_hub* hub, struct usb_pipe* pipe)
+{
+    struct usb_hc* hc;
+
+    if (hub->root_hub) {
+        hc = hub->dev.hc;
+    } else {
+        hc = hub->dev.usb->hc;
+    }
+
+    struct usb_hc_ctrl_appe appe = {
+        .req = {
+            .type = HC_CTRL_ADD_PIPE,
+            .hc = *hc
+        },
+        .pipe = pipe->trs
+    };
+
+    rpc_get_int(hc->pid, RPC_USB_HC_CONTROL_FNN, sizeof(appe),
+        (char*)&appe);
+}
+
+static void rh_rst(struct usb_hub* hub, int port)
+{
+    struct usb_hc_ctrl_rst rqrst = {
+        .req = {
+            .type = HC_CTRL_RESET,
+            .hc = *hub->dev.hc
+        },
+        .port = port
+    };
+
+    rpc_get_int(hub->dev.hc->pid, RPC_USB_HC_CONTROL_FNN, sizeof(rqrst),
+        (char*)&rqrst);
+}
+
+static int rh_scan(struct usb_hub* hub, int port)
+{
+    struct usb_hc_ctrl_scan rqsc = {
+        .req = {
+            .type = HC_CTRL_SCAN_PORT,
+            .hc = *hub->dev.hc
+        },
+        .port = port
+    };
+
+    return rpc_get_int(hub->dev.hc->pid, RPC_USB_HC_CONTROL_FNN, sizeof(rqsc),
+        (char*)&rqsc);
+}
+
+static void rh_disable(struct usb_hub* hub, int port)
+{
+    struct usb_hc_ctrl_dsbl rqdbl = {
+        .req = {
+            .type = HC_CTRL_DSBL_PORT,
+            .hc = *hub->dev.hc
+        },
+        .port = port
+    };
+
+    rpc_get_int(hub->dev.hc->pid, RPC_USB_HC_CONTROL_FNN, sizeof(rqdbl),
+        (char*)&rqdbl);
+}
+
+void scan_hc(struct usb_hc* hc)
+{
+    struct usb_hub rh = {
+        .dev = {
+            .hc = hc
+        },
+        .root_hub = true,
+        .ports = hc->root_ports,
+        .add_pipe = &rh_addpipe,
+        .disable_port = &rh_disable,
+        .reset_port = &rh_rst,
+        .scan_port = &rh_scan
+    };
+
+    scan_hub(&rh);
+}
diff --git a/src/modules/usb/usb1/hub.c b/src/modules/usb/usb1/hub.c
new file mode 100644
index 0000000..b1d0597
--- /dev/null
+++ b/src/modules/usb/usb1/hub.c
@@ -0,0 +1,180 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <collections.h>
+#include <rpc.h>
+#include <sleep.h>
+
+#include "usb.h"
+#include "usb-hc.h"
+
+static int scan_hub_port(struct usb_hub* hub, int port)
+{
+    uint32_t status;
+
+    usb_control_transfer(hub->dev.usb->ep0,
+        USB_SETUP_IN | USB_SETUP_REQ_CLS | USB_SETUP_REC_OTH, USB_GET_STATUS,
+        0, port + 1, 4, &status);
+
+    if (!(status & (1 << 0))) {
+        return 0;
+    }
+
+    if (status & (1 << 9)) {
+        return USB_HUB_DEVICE | USB_HUB_LOW_SPEED;
+    } else if (status & (1 << 10)) {
+        return USB_HUB_DEVICE | USB_HUB_HIGH_SPEED;
+    } else {
+        return USB_HUB_DEVICE | USB_HUB_FULL_SPEED;
+    }
+}
+
+static void disable_hub_port(struct usb_hub *hub, int port)
+{
+    // Deaktivieren
+    usb_control_transfer(hub->dev.usb->ep0,
+        USB_SETUP_OUT | USB_SETUP_REQ_CLS | USB_SETUP_REC_OTH,
+        USB_CLEAR_FEATURE, 1, port + 1, 0, NULL);
+}
+
+static void reset_hub_port(struct usb_hub* hub, int port)
+{
+    uint32_t cur;
+
+    port++;
+
+    usb_control_transfer(hub->dev.usb->ep0,
+        USB_SETUP_IN | USB_SETUP_REQ_CLS | USB_SETUP_REC_OTH, USB_GET_STATUS,
+        0, port, 4, &cur);
+
+    // Zurücksetzen
+    usb_control_transfer(hub->dev.usb->ep0,
+        USB_SETUP_OUT | USB_SETUP_REQ_CLS | USB_SETUP_REC_OTH,
+        USB_SET_FEATURE, 4, port, 0, NULL);
+
+    msleep(20);
+
+    if (!(cur & (1 << 1)) || (cur & (1 << 2))) {
+        // Vorher deaktiviert oder im Suspendmodus, Resume treiben
+        usb_control_transfer(hub->dev.usb->ep0,
+            USB_SETUP_OUT | USB_SETUP_REQ_CLS | USB_SETUP_REC_OTH,
+            USB_CLEAR_FEATURE, 2, port, 0, NULL);
+        msleep(30);
+    }
+}
+
+void usb_found_hub(struct usb_device* dev)
+{
+    struct usb_config_descriptor* ccfg;
+    struct usb_interface_descriptor* cint;
+    struct usb_hub* hub;
+    struct usb_hub_descriptor* chub;
+    uint8_t chub_buf[256];
+
+    dev->cur_cfg = NULL;
+
+    int c, i;
+
+    for (c = 0; c < dev->dev_desc->num_configurations; c++) {
+        ccfg = dev->cfg_desc[c];
+        cint = (struct usb_interface_descriptor*)(dev->cfg_desc[c] + 1);
+        for (i = 0; i < ccfg->num_interfaces; i++) {
+            if (cint->class == 9) {
+                dev->cur_cfg = ccfg;
+                break;
+            }
+
+            cint = (struct usb_interface_descriptor*)
+                ((struct usb_endpoint_descriptor*)(cint + 1) +
+                cint->num_endpoints);
+        }
+    }
+
+    if (dev->cur_cfg == NULL) {
+        return;
+    }
+
+    usb_set_configuration(dev, dev->cur_cfg->configuration_value);
+
+    hub = calloc(1, sizeof(*hub));
+    if (hub == NULL) {
+        return;
+    }
+
+    hub->dev.usb = dev;
+    hub->root_hub = false;
+
+    usb_control_transfer(dev->ep0,
+        USB_SETUP_IN | USB_SETUP_REQ_CLS | USB_SETUP_REC_DEV,
+        USB_GET_DESCRIPTOR, USB_DESC_HUB, 0, 256, chub_buf);
+
+    chub = (struct usb_hub_descriptor*)chub_buf;
+
+    hub->ports = chub->nbr_ports;
+
+    for (i = 1; i <= hub->ports; i++) {
+        // Strom einschalten
+        usb_control_transfer(dev->ep0,
+            USB_SETUP_OUT | USB_SETUP_REQ_CLS | USB_SETUP_REC_OTH,
+            USB_SET_FEATURE, 8, i, 0, NULL);
+
+        msleep(chub->pwr_on_2_pwr_good * 2);
+    }
+
+    msleep(100);
+
+    for (i = 1; i <= hub->ports; i++) {
+        uint32_t status;
+
+        usb_control_transfer(dev->ep0,
+            USB_SETUP_IN | USB_SETUP_REQ_CLS | USB_SETUP_REC_OTH,
+            USB_GET_STATUS, 0, i, 4, &status);
+
+        if (status & (1 << 1)) {
+            // Port deaktivieren
+            usb_control_transfer(dev->ep0,
+                USB_SETUP_OUT | USB_SETUP_REQ_CLS | USB_SETUP_REC_OTH,
+                USB_CLEAR_FEATURE, 1, i, 0, NULL);
+        }
+    }
+
+    hub->add_pipe = dev->parent->add_pipe;
+    hub->disable_port = &disable_hub_port;
+    hub->reset_port = &reset_hub_port;
+    hub->scan_port = &scan_hub_port;
+
+    scan_hub(hub);
+}
diff --git a/src/modules/usb/usb1/main.c b/src/modules/usb/usb1/main.c
new file mode 100644
index 0000000..a7611ff
--- /dev/null
+++ b/src/modules/usb/usb1/main.c
@@ -0,0 +1,59 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <collections.h>
+#include <init.h>
+#include <rpc.h>
+#include <syscall.h>
+
+#include "usb.h"
+
+extern list_t* usb_hcs;
+extern list_t* usb_ddrvs;
+extern list_t* unhandled_devs;
+
+int main(void)
+{
+    usb_hcs = list_create();
+    usb_ddrvs = list_create();
+    unhandled_devs = list_create();
+
+    init_messaging();
+    register_rpc_interface();
+
+    for (;;) {
+        wait_for_rpc();
+    }
+}
diff --git a/src/modules/usb/usb1/rpc.c b/src/modules/usb/usb1/rpc.c
new file mode 100644
index 0000000..5d55306
--- /dev/null
+++ b/src/modules/usb/usb1/rpc.c
@@ -0,0 +1,327 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <collections.h>
+#include <init.h>
+#include <rpc.h>
+#include <syscall.h>
+
+#include "usb.h"
+#include "usb-ddrv.h"
+#include "usb-hc.h"
+#include "usb-server.h"
+
+list_t* usb_hcs;
+list_t* usb_ddrvs;
+list_t* unhandled_devs;
+
+extern void scan_hc(struct usb_hc* hc);
+
+static void hcd_handler(pid_t src, uint32_t corr_id, size_t length, void* data)
+{
+    struct usb_hc* hc;
+
+    if (length < sizeof(*hc)) {
+        rpc_send_int_response(src, corr_id, 0);
+        return;
+    }
+
+    hc = malloc(sizeof(*hc));
+    memcpy(hc, data, sizeof(*hc));
+
+    hc->pid = src;
+    hc->addr_counter = 1;
+    list_push(usb_hcs, hc);
+
+    scan_hc(hc);
+
+    rpc_send_int_response(src, corr_id, 42);
+}
+
+#define check(name) if ((dev->type.name != hd->name) && (hd->name != -1)) \
+    { continue; }
+
+static void ddrv_handler(pid_t src, uint32_t corr_id, size_t length, void* data)
+{
+    struct usb_handle_devs* hd = data;
+
+    if (length < sizeof(*hd)) {
+        rpc_send_int_response(src, corr_id, 0);
+        return;
+    }
+
+    struct usb_ddrv* drv = calloc(1, sizeof(*drv));
+    drv->pid = src;
+    drv->handle = *hd;
+    list_push(usb_ddrvs, drv);
+
+    int i, s = list_size(unhandled_devs);
+    for (i = 0; i < s; i++) {
+        struct usb_prov_dev* dev = list_get_element_at(unhandled_devs, i);
+
+        check(vendor_id)
+        check(device_id)
+        check(class)
+        check(subclass)
+        check(protocol)
+
+        if (rpc_get_int(src, RPC_USB_DDRV_PLUG_FNN, sizeof(*dev), (char*)dev)) {
+            list_remove(unhandled_devs, i--);
+            s--;
+        }
+    }
+
+    rpc_send_int_response(src, corr_id, 42);
+}
+
+static void devctl_handler(pid_t src, uint32_t corr_id, size_t length,
+    void* data)
+{
+    struct usb_devctrl_req* rq = data;
+
+    if (length < sizeof(*rq)) {
+        rpc_send_int_response(src, corr_id, 0);
+        return;
+    }
+
+    struct usb_device* dev;
+    struct usb_interface_descriptor* ifc;
+    int ifcs, ifc_num, i, ret;
+
+    switch (rq->type) {
+        case USB_DC_NUM_ENDPOINTS:
+            if (length < sizeof(struct usb_devctrl_gne)) {
+                rpc_send_int_response(src, corr_id, 0);
+                return;
+            }
+
+            struct usb_devctrl_gne* ne = data;
+            dev = ne->dev.dev_id;
+            ifc = (struct usb_interface_descriptor*)(dev->cur_cfg + 1);
+
+            ifcs = dev->cur_cfg->num_interfaces;
+            ifc_num = ne->dev.interface_id;
+            if ((ifc_num < 0) || (ifc_num >= ifcs)) {
+                ifc_num = 0;
+            }
+
+            for (i = 0; i < ifcs; i++) {
+                if (i == ifc_num) {
+                    rpc_send_int_response(src, corr_id, ifc->num_endpoints);
+                    return;
+                }
+
+                ifc = (struct usb_interface_descriptor*)
+                    ((struct usb_endpoint_descriptor*)(ifc + 1) +
+                    ifc->num_endpoints);
+            }
+            // Hierhin sollte der Code nie gelangen
+            // Execution should never get here
+            break;
+        case USB_DC_GET_IFC_ID:
+            if (length < sizeof(struct usb_devctrl_gii)) {
+                rpc_send_int_response(src, corr_id, 0);
+                return;
+            }
+
+            struct usb_devctrl_gii* ii = data;
+            dev = ii->dev.dev_id;
+            ifc = (struct usb_interface_descriptor*)(dev->cur_cfg + 1);
+
+            ifcs = dev->cur_cfg->num_interfaces;
+            // Das ist nicht die, die wir suchen
+            // This is not the one we're looking for
+            ifc_num = ne->dev.interface_id;
+            if ((ifc_num < 0) || (ifc_num >= ifcs)) {
+                ifc_num = 0;
+            }
+
+            for (i = 0; i < ifcs; i++) {
+                if (i == ifc_num) {
+                    rpc_send_int_response(src, corr_id, ifc->interface_number);
+                    return;
+                }
+
+                ifc = (struct usb_interface_descriptor*)
+                    ((struct usb_endpoint_descriptor*)(ifc + 1) +
+                    ifc->num_endpoints);
+            }
+            // s. o.
+        case USB_DC_GET_ENDPOINT:
+            if (length < sizeof(struct usb_devctrl_gep)) {
+                // Hm, geht wohl nicht anders (und vertretbar, da dieser Fall
+                // nie auftreten sollte)
+                rpc_send_response(src, corr_id, 0, NULL);
+                return;
+            }
+
+            struct usb_devctrl_gep* ge = data;
+            dev = ge->dev.dev_id;
+            ifc = (struct usb_interface_descriptor*)(dev->cur_cfg + 1);
+
+            ifcs = dev->cur_cfg->num_interfaces;
+            ifc_num = ne->dev.interface_id;
+            if ((ifc_num < 0) || (ifc_num >= ifcs)) {
+                ifc_num = 0;
+            }
+
+            for (i = 0; i < ifcs; i++) {
+                if (i == ifc_num) {
+                    struct usb_endpoint_descriptor* epd =
+                        (struct usb_endpoint_descriptor*)(ifc + 1);
+                    rpc_send_response(src, corr_id, sizeof(*epd),
+                        (char*)&epd[ge->ep_number]);
+                    return;
+                }
+
+                ifc = (struct usb_interface_descriptor*)
+                    ((struct usb_endpoint_descriptor*)(ifc + 1) +
+                    ifc->num_endpoints);
+            }
+            // s. o.
+            break;
+        case USB_DC_GET_PIPE:
+            if (length < sizeof(struct usb_devctrl_gpp)) {
+                // Auch hier wohl nur so möglich
+                rpc_send_response(src, corr_id, 0, NULL);
+                return;
+            }
+
+            struct usb_devctrl_gpp* gp = data;
+            dev = gp->dev.dev_id;
+            ifc = (struct usb_interface_descriptor*)(dev->cur_cfg + 1);
+
+            ifcs = dev->cur_cfg->num_interfaces;
+            ifc_num = ne->dev.interface_id;
+            if ((ifc_num < 0) || (ifc_num >= ifcs)) {
+                ifc_num = 0;
+            }
+
+            for (i = 0; i < ifcs; i++) {
+                if (i == ifc_num) {
+                    if ((gp->ep_number < 0) ||
+                        (gp->ep_number >= ifc->num_endpoints))
+                    {
+                        gp->ep_number = 0;
+                    }
+
+                    struct usb_endpoint_descriptor* epd =
+                        (struct usb_endpoint_descriptor*)(ifc + 1);
+                    epd += gp->ep_number;
+
+                    struct usb_pipe pp = {
+                        .dev = dev,
+                        .ep = epd,
+                        .trs = {
+                            .usb_addr = dev->addr,
+                            .ep_id = epd->number,
+                            .mps = epd->mps,
+                            .type = epd->type,
+                            .speed = dev->speed,
+                            .toggle = 0,
+                            .stalled = false
+                        }
+                    };
+
+                    if (dev->parent->add_pipe != NULL) {
+                        dev->parent->add_pipe(dev->parent, &pp);
+                    }
+
+                    rpc_send_response(src, corr_id, sizeof(pp), (char*)&pp);
+                    return;
+                }
+
+                ifc = (struct usb_interface_descriptor*)
+                    ((struct usb_endpoint_descriptor*)(ifc + 1) +
+                    ifc->num_endpoints);
+            }
+            // s. o.
+            break;
+        case USB_DC_CLEAR_HALT:
+            if (length < sizeof(struct usb_devctrl_clh)) {
+                rpc_send_int_response(src, corr_id, -EINVAL);
+                return;
+            }
+
+            struct usb_devctrl_clh* clrh = data;
+            usb_clear_halt(&clrh->pipe);
+            rpc_send_int_response(src, corr_id, 0);
+            break;
+        case USB_DC_TRSF_CONTROL:
+            if (length < sizeof(struct usb_devctrl_tct)) {
+                rpc_send_int_response(src, corr_id, -EINVAL);
+                return;
+            }
+
+            struct usb_devctrl_tct* tctrq = data;
+            if (tctrq->ep0) {
+                dev = tctrq->dst.dev_id;
+                ret = usb_shm_control_transfer(dev->ep0, tctrq->setup.type,
+                    tctrq->setup.request, tctrq->setup.value,
+                    tctrq->setup.index, tctrq->setup.length, tctrq->shm);
+            } else {
+                ret = usb_shm_control_transfer(&tctrq->dst.pipe,
+                    tctrq->setup.type, tctrq->setup.request, tctrq->setup.value,
+                    tctrq->setup.index, tctrq->setup.length, tctrq->shm);
+            }
+
+            rpc_send_int_response(src, corr_id, ret);
+            break;
+        case USB_DC_TRSF_BULK:
+            if (length < sizeof(struct usb_devctrl_tbk)) {
+                rpc_send_int_response(src, corr_id, -EINVAL);
+                return;
+            }
+
+            struct usb_devctrl_tbk* tbkrq = data;
+            ret = usb_shm_bulk_transfer(&tbkrq->pipe, tbkrq->shm,
+                tbkrq->length);
+
+            // Senden des Togglebitstatus erwünscht
+            rpc_send_int_response(src, corr_id, ret);
+            break;
+    }
+}
+
+void register_rpc_interface(void)
+{
+    register_message_handler(RPC_USB_SV_REGHC_FNN, &hcd_handler);
+    register_message_handler(RPC_USB_SV_REGDD_FNN, &ddrv_handler);
+    register_message_handler(RPC_USB_SV_DEVCT_FNN, &devctl_handler);
+    init_service_register("usb1");
+}
diff --git a/src/modules/usb/usb1/transfer.c b/src/modules/usb/usb1/transfer.c
new file mode 100644
index 0000000..8c96c4d
--- /dev/null
+++ b/src/modules/usb/usb1/transfer.c
@@ -0,0 +1,123 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#include <stddef.h>
+#include <string.h>
+
+#include <rpc.h>
+#include <syscall.h>
+
+#include "usb.h"
+#include "usb-ddrv.h"
+#include "usb-hc.h"
+
+int usb_control_transfer(struct usb_pipe* pipe, int type, int request,
+    int value, int index, int length, void* buffer)
+{
+    uint32_t shm = 0;
+    void *shm_addr = NULL;
+
+    if (length) {
+        shm = create_shared_memory(length);
+        shm_addr = open_shared_memory(shm);
+
+        if ((buffer != NULL) && !(type & USB_SETUP_IN)) {
+            memcpy(shm_addr, buffer, length);
+        }
+    }
+
+    int ret = usb_shm_control_transfer(pipe, type, request, value, index,
+        length, shm);
+
+    if (length && (buffer != NULL) && (type & USB_SETUP_IN)) {
+        memcpy(buffer, shm_addr, length);
+    }
+
+    if (shm_addr != NULL) {
+        close_shared_memory(shm);
+    }
+
+    return ret;
+}
+
+int usb_shm_control_transfer(struct usb_pipe* pipe, int type, int request,
+    int value, int index, int length, uint32_t shm)
+{
+    struct usb_hc_trs_ctrl trs = {
+        .trs = {
+            .type = USB_TRST_CONTROL,
+            .hc = *pipe->dev->hc,
+            .pipe = pipe->trs
+        },
+        .setup = {
+            .type = type,
+            .request = request,
+            .value = value,
+            .index = index,
+            .length = length
+        },
+        .shm = shm
+    };
+
+    return rpc_get_int(pipe->dev->hc->pid, RPC_USB_HC_TRANSFER_FNN,
+        sizeof(trs), (char*)&trs);
+}
+
+int usb_shm_bulk_transfer(struct usb_pipe* pipe, uint32_t shm, size_t length)
+{
+    struct usb_hc_trs_bulk trs = {
+        .trs = {
+            .type = USB_TRST_BULK,
+            .hc = *pipe->dev->hc,
+            .pipe = pipe->trs
+        },
+        .receive = pipe->ep->direction ? true : false,
+        .length = length,
+        .shm = shm
+    };
+
+    return rpc_get_int(pipe->dev->hc->pid, RPC_USB_HC_TRANSFER_FNN,
+        sizeof(trs), (char*)&trs);
+}
+
+void usb_set_configuration(struct usb_device* dev, int config)
+{
+    usb_control_transfer(dev->ep0,
+        USB_SETUP_OUT | USB_SETUP_REQ_STD | USB_SETUP_REC_DEV,
+        USB_SET_CONFIGURATION, config, 0, 0, NULL);
+    dev->state = USB_CONFIGURED;
+}
+
+void usb_clear_halt(struct usb_pipe* pipe)
+{
+    usb_control_transfer(pipe->dev->ep0,
+        USB_SETUP_OUT | USB_SETUP_REQ_STD | USB_SETUP_REC_EP,
+        USB_CLEAR_FEATURE, USB_ENDPOINT_HALT, pipe->ep->number, 0, NULL);
+}
diff --git a/src/modules/usb/usb1/usb.h b/src/modules/usb/usb1/usb.h
new file mode 100644
index 0000000..6efc729
--- /dev/null
+++ b/src/modules/usb/usb1/usb.h
@@ -0,0 +1,209 @@
+/*****************************************************************************
+* Copyright (c) 2009-2010 Max Reitz                                          *
+*                                                                            *
+* THE COKE-WARE LICENSE                                                      *
+*                                                                            *
+* Redistribution  and use  in  source  and  binary  forms,  with or  without *
+* modification,  are permitted  provided that the  following  conditions are *
+* met:                                                                       *
+*                                                                            *
+*   1. Redistributions  of  source code  must  retain  the  above  copyright *
+*      notice, this list of conditions and the following disclaimer.         *
+*   2. Redistribution in  binary form  must reproduce  the  above  copyright *
+*      notice  and either  the full  list  of  conditions and  the following *
+*      disclaimer or a link to both.                                         *
+*   3. If we meet one day and you think this stuff is worth it,  you may buy *
+*      me a coke in return.                                                  *
+*                                                                            *
+* THIS SOFTWARE  IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY *
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO, THE IMPLIED *
+* WARRANTIES  OF MERCHANTABILITY  AND FITNESS  FOR A PARTICULAR PURPOSE  ARE *
+* DISCLAIMED.  IN  NO  EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL *
+* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
+* CAUSED  AND  ON  ANY  THEORY OF  LIABILITY,  WHETHER  IN CONTRACT,  STRICT *
+* LIABILITY,  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
+* OUT OF THE USE  OF THIS  SOFTWARE,  EVEN IF ADVISED OF THE  POSSIBILITY OF *
+* SUCH DAMAGE.                                                               *
+*****************************************************************************/
+
+#ifndef USB_H
+#define USB_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "usb-ddrv.h"
+#include "usb-hc.h"
+#include "usb-hub.h"
+#include "usb-server.h"
+#include "usb-structs.h"
+#include "usb-trans.h"
+
+struct usb_pipe;
+
+// Beschreibt einen Hub (sowohl Roothub als auch einen normalen).
+struct usb_hub {
+    // Da ein Hub immer nur entweder Root- oder normaler Hub sein kann, macht
+    // sich eine Union hier ganz gut.
+    union {
+        struct usb_device* usb;
+        struct usb_hc* hc;
+    } dev;
+    // true, wenn es sich um einen Roothub handelt.
+    bool root_hub;
+    // Anzahl der Ports am Hub.
+    int ports;
+
+    /**
+     * Wird aufgerufen, wenn eine neue Pipe benötigt wird. Ist bereits eine
+     * Pipe zur angegebenen Geräte-/Endpunkt-Kombination vorhanden, so sollte
+     * diese entfernt werden. Der Pointer darf NULL sein, um anzuzeigen, dass
+     * die Funktion nicht benötigt wird. Normale Hubs müssen jedoch dafür
+     * sorgen, dass die vom Hostcontroller (Roothub) bereitgestellte Funktion
+     * aufgerufen wird (es genügt, einfach den Pointer vom übergeordneten Hub
+     * zu kopieren, der Roothub muss dies erkennen können).
+     *
+     * @param hub Der Hub, an dem das Gerät hängt.
+     * @param pipe Die neu hinzuzufügende Pipe.
+     */
+    void (*add_pipe)(struct usb_hub* hub, struct usb_pipe* pipe);
+
+    /**
+     * Deaktiviert einen Port (zum Aktivieren wird reset_port verwendet).
+     *
+     * @param hub Hub mit dem zu deaktivierenden Port.
+     * @param port Zu deaktivierender Port.
+     */
+    void (*disable_port)(struct usb_hub* hub, int port);
+
+    /**
+     * Treibt das Resetsignal auf einem Port und aktiviert ihn. Wenn nötig,
+     * muss außerdem das Resume-Signal getrieben werden, damit nach dem Aufruf
+     * dieser Funktion mit dem Gerät kommuniziert werden kann.
+     *
+     * @param hub Hub, an dem das Gerät hängt.
+     * @param port Port, an dem es hängt.
+     */
+    void (*reset_port)(struct usb_hub* hub, int port);
+
+    /**
+     * Überprüft einen Port und gibt dessen Status zurück.
+     *
+     * @param hub Zu untersuchender Hub.
+     * @param port Entsprechender Port.
+     *
+     * @return Kombination aus den in usb-hub.h mit USB_HUB beginnenden Flags.
+     */
+    int (*scan_port)(struct usb_hub* hub, int port);
+};
+
+// Beschreibt ein USB-Gerät
+struct usb_device {
+    // Hub, an dem es hängt
+    struct usb_hub* parent;
+    // Index des Ports, an dem es sich befindet
+    int hub_port;
+
+    // Zuständiger Hostcontroller
+    struct usb_hc* hc;
+    // Dort eindeutige USB-Adresse
+    int addr;
+
+    // Aktueller Status
+    enum usb_state state;
+    // Aktuelle Geschwindigkeit
+    int speed;
+
+    // Default Control Pipe
+    struct usb_pipe* ep0;
+    // Device-Descriptor
+    struct usb_device_descriptor* dev_desc;
+    // Alle Configuration-Descriptors
+    struct usb_config_descriptor** cfg_desc;
+    // Aktuelle Konfiguration
+    struct usb_config_descriptor* cur_cfg;
+};
+
+// USB-Gerätetreiber
+struct usb_ddrv {
+    // Prozess-ID
+    pid_t pid;
+    // Gibt an, welche Geräte er behandeln kann
+    struct usb_handle_devs handle;
+};
+
+// Bisher nicht behandeltes USB-Gerät (oder Interface)
+struct usb_unhandled {
+    // Das Gerät
+    struct usb_device* dev;
+    // Das Interface
+    struct usb_interface_descriptor* ifc;
+};
+
+
+/**
+ * Initialisiert die RPC-Handler und trägt sich als usb1 bei init ein-
+ */
+void register_rpc_interface(void);
+
+/**
+ * Enumeriert alle Geräte an einem Hub
+ *
+ * @param hub Der Hub
+ */
+void scan_hub(struct usb_hub* hub);
+
+/**
+ * Entstallt einen Endpunkt.
+ *
+ * @param pipe Zum Endpunkt gehörige Pipe
+ */
+void usb_clear_halt(struct usb_pipe* pipe);
+
+/**
+ * Führt einen Controltransfer durch.
+ *
+ * @param pipe Die Pipe
+ * @param type type-Feld des SETUP-Pakets
+ * @param request request-Feld des SETUP-Pakets
+ * @param value value-Feld des SETUP-Pakets
+ * @param index index-Feld des SETUP-Pakets
+ * @param length length-Feld des SETUP-Pakets
+ * @param buffer Speicherbereich, mit dem während der Datenphase gearbeitet
+ *               werden soll.
+ *
+ * @return 0 bei Erfolg, sonst -errno.
+ */
+int usb_control_transfer(struct usb_pipe* pipe, int type, int request,
+    int value, int index, int length, void* buffer);
+
+/**
+ * Führt einen Bulktransfer durch.
+ *
+ * @param pipe Die Pipe für den Transfer
+ * @param shm SHM-Bereich, mit dem gearbeitet werden soll
+ * @param length Länge des Transfers
+ *
+ * @return -errno bei Fehler, sonst neuer Wert des Toggle-Bits.
+ */
+int usb_shm_bulk_transfer(struct usb_pipe* pipe, uint32_t shm, size_t length);
+
+/**
+ * Führt einen Controltransfer durch. Entspricht usb_control_transfer, außer
+ * dass ein SHM-Bereich verwendet wird.
+ */
+int usb_shm_control_transfer(struct usb_pipe* pipe, int type, int request,
+    int value, int index, int length, uint32_t shm);
+
+/**
+ * Setzt die aktuelle Konfiguration eines Geräts.
+ *
+ * @param dev USB-Gerät
+ * @param config ID der neuen Konfiguration
+ */
+void usb_set_configuration(struct usb_device* dev, int config);
+
+#endif
-- 
1.6.4.2