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

[tyndur-devel] [PATCH 3/3] OHCI, UHCI, USB 1.1, USB-MSD



From: Max Reitz <max@xxxxxxxxxx>

+ OHCI-Treiber
+ UHCI-Treiber
+ USB-1.1-Treiber
+ USB-Massenspeichertreiber
+ Gemeinsame Makefile.all für alle, damit sie in einer Binary
  landen (wie von der aktuellen CDI.usb- bzw. CDI.usb-hcd-Lib
  gefordert)

Signed-off-by: Max Reitz <max@xxxxxxxxxx>
---
 src/modules/cdi/Makefile.all                 |    6 +
 src/modules/cdi/ohci/Makefile.all            |    2 +
 src/modules/cdi/ohci/hcd.c                   |  335 ++++++++++++++++
 src/modules/cdi/ohci/include/ohci-hcd.h      |   39 ++
 src/modules/cdi/ohci/include/ohci-init.h     |   31 ++
 src/modules/cdi/ohci/include/ohci-transfer.h |   30 ++
 src/modules/cdi/ohci/include/ohci.h          |  283 +++++++++++++
 src/modules/cdi/ohci/init.c                  |  249 ++++++++++++
 src/modules/cdi/ohci/main.c                  |   32 ++
 src/modules/cdi/ohci/transfer.c              |   85 ++++
 src/modules/cdi/uhci/Makefile.all            |    2 +
 src/modules/cdi/uhci/hcd.c                   |  215 ++++++++++
 src/modules/cdi/uhci/include/uhci-hcd.h      |   39 ++
 src/modules/cdi/uhci/include/uhci-init.h     |   31 ++
 src/modules/cdi/uhci/include/uhci-transfer.h |   30 ++
 src/modules/cdi/uhci/include/uhci.h          |  138 +++++++
 src/modules/cdi/uhci/init.c                  |  257 ++++++++++++
 src/modules/cdi/uhci/main.c                  |   32 ++
 src/modules/cdi/uhci/transfer.c              |   91 +++++
 src/modules/cdi/usb-msd/Makefile.all         |    2 +
 src/modules/cdi/usb-msd/include/msd.h        |  121 ++++++
 src/modules/cdi/usb-msd/main.c               |   74 ++++
 src/modules/cdi/usb-msd/msd.c                |  555 ++++++++++++++++++++++++++
 src/modules/cdi/usb11/Makefile.all           |    2 +
 src/modules/cdi/usb11/control.c              |  252 ++++++++++++
 src/modules/cdi/usb11/include/control.h      |   31 ++
 src/modules/cdi/usb11/include/transfer.h     |   38 ++
 src/modules/cdi/usb11/include/usb-structs.h  |  184 +++++++++
 src/modules/cdi/usb11/include/usb11.h        |   41 ++
 src/modules/cdi/usb11/main.c                 |   82 ++++
 src/modules/cdi/usb11/transfer.c             |  223 +++++++++++
 31 files changed, 3532 insertions(+), 0 deletions(-)
 create mode 100644 src/modules/cdi/Makefile.all
 create mode 100644 src/modules/cdi/ohci/Makefile.all
 create mode 100644 src/modules/cdi/ohci/hcd.c
 create mode 100644 src/modules/cdi/ohci/include/ohci-hcd.h
 create mode 100644 src/modules/cdi/ohci/include/ohci-init.h
 create mode 100644 src/modules/cdi/ohci/include/ohci-transfer.h
 create mode 100644 src/modules/cdi/ohci/include/ohci.h
 create mode 100644 src/modules/cdi/ohci/init.c
 create mode 100644 src/modules/cdi/ohci/main.c
 create mode 100644 src/modules/cdi/ohci/transfer.c
 create mode 100644 src/modules/cdi/uhci/Makefile.all
 create mode 100644 src/modules/cdi/uhci/hcd.c
 create mode 100644 src/modules/cdi/uhci/include/uhci-hcd.h
 create mode 100644 src/modules/cdi/uhci/include/uhci-init.h
 create mode 100644 src/modules/cdi/uhci/include/uhci-transfer.h
 create mode 100644 src/modules/cdi/uhci/include/uhci.h
 create mode 100644 src/modules/cdi/uhci/init.c
 create mode 100644 src/modules/cdi/uhci/main.c
 create mode 100644 src/modules/cdi/uhci/transfer.c
 create mode 100644 src/modules/cdi/usb-msd/Makefile.all
 create mode 100644 src/modules/cdi/usb-msd/include/msd.h
 create mode 100644 src/modules/cdi/usb-msd/main.c
 create mode 100644 src/modules/cdi/usb-msd/msd.c
 create mode 100644 src/modules/cdi/usb11/Makefile.all
 create mode 100644 src/modules/cdi/usb11/control.c
 create mode 100644 src/modules/cdi/usb11/include/control.h
 create mode 100644 src/modules/cdi/usb11/include/transfer.h
 create mode 100644 src/modules/cdi/usb11/include/usb-structs.h
 create mode 100644 src/modules/cdi/usb11/include/usb11.h
 create mode 100644 src/modules/cdi/usb11/main.c
 create mode 100644 src/modules/cdi/usb11/transfer.c

diff --git a/src/modules/cdi/Makefile.all b/src/modules/cdi/Makefile.all
new file mode 100644
index 0000000..19a4827
--- /dev/null
+++ b/src/modules/cdi/Makefile.all
@@ -0,0 +1,6 @@
+shopt -s extglob
+source $LOST_BUILDMK_ROOT/config.sh
+
+echo "LD   $1/modules/usb"
+$LOST_TOOLS_LD -Ttext=0x40000000 -ousb.mod  usb11/*.o ohci/*.o uhci/*.o usb-msd/*.o --start-group $2 --end-group
+$LOST_TOOLS_STRIP -s usb.mod -o $1/modules/usb
diff --git a/src/modules/cdi/ohci/Makefile.all b/src/modules/cdi/ohci/Makefile.all
new file mode 100644
index 0000000..e027b50
--- /dev/null
+++ b/src/modules/cdi/ohci/Makefile.all
@@ -0,0 +1,2 @@
+shopt -s extglob
+source $LOST_BUILDMK_ROOT/config.sh
diff --git a/src/modules/cdi/ohci/hcd.c b/src/modules/cdi/ohci/hcd.c
new file mode 100644
index 0000000..5cf8630
--- /dev/null
+++ b/src/modules/cdi/ohci/hcd.c
@@ -0,0 +1,335 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <cdi/io.h>
+#include <cdi/lists.h>
+#include <cdi/mempool.h>
+#include <cdi/usb.h>
+#include <cdi/usb-hcd.h>
+
+#include "ohci.h"
+#include "ohci-hcd.h"
+
+static void reset_device(struct cdi_usb_device *device);
+
+static void find_devices(struct cdi_usb_hc *device)
+{
+    struct ohci *ohci = (struct ohci *)device;
+    struct cdi_usb_device *dev;
+    int i;
+
+    d0printf("Scanning root ports\n");
+    for (i = 0; i < ohci->root_ports; i++) {
+        if (!(ohci->memory->hc_rh_port_status[i] & OHC_RP_CCS)) {
+            continue;
+        }
+        dev = calloc(1, sizeof(struct cdi_usb_device));
+        dev->hc = device;
+        dev->id = 0;
+        dev->port = i;
+        dev->speed = (ohci->memory->hc_rh_port_status[i] & OHC_RP_LSDA) ?
+            CDI_USB_LOW_SPEED : CDI_USB_FULL_SPEED;
+        dev->reset = &reset_device;
+        cdi_usb_device_init(dev);
+    }
+}
+
+static void activate_device(struct cdi_usb_device *device)
+{
+    struct ohci *ohci = (struct ohci *)device->hc;
+
+    if (device->hub != NULL) {
+        return;
+    }
+
+    d1printf("Activating device on port %i.\n", device->port);
+    ohci->memory->hc_rh_port_status[device->port] |= OHC_RP_PES;
+    cdi_sleep_ms(20);
+}
+
+static void reset_device(struct cdi_usb_device *device)
+{
+    struct ohci *ohci = (struct ohci *)device->hc;
+
+    if (device->hub != NULL) {
+        return;
+    }
+
+    d1printf("Resetting device on port %i.\n", device->port);
+    ohci->memory->hc_rh_port_status[device->port] |= OHC_RP_PRS;
+    cdi_sleep_ms(20);
+}
+
+static void add_pipe(struct cdi_usb_pipe *pipe)
+{
+    struct ohci *ohci = (struct ohci *)pipe->device->hc;
+    struct ohci_ed *ved;
+    uintptr_t ped;
+    struct ohci_ed_desc *dsc;
+    //TODO Mehr als Control und Bulk
+    int iscontrol = 0;
+
+    if (mempool_get(ohci->ed_pool, (void **)&ved, &ped) == -1) {
+        return;
+    }
+    ved->function = pipe->device->id;
+    ved->endpoint = pipe->endpoint->endpoint_address;
+    if (ved->endpoint == 0) {
+        //EP0
+        ved->direction = OHC_ED_DIR_TD;
+        iscontrol = 1;
+    } else if (pipe->endpoint->endpoint_address & 0x80) {
+        ved->direction = OHC_ED_DIR_IN;
+    } else {
+        ved->direction = OHC_ED_DIR_OUT;
+    }
+    ved->low_speed = !!(pipe->device->speed == CDI_USB_LOW_SPEED);
+    ved->skip = 0;
+    ved->format = 0;
+    ved->mps = pipe->endpoint->max_packet_size;
+    ved->td_queue_tail = 0;
+    ved->td_queue_head = 0;
+    dsc = cdi_list_get(ohci->ed_list, 0);
+    if (dsc == NULL) {
+        ved->next_ed = 0;
+    } else {
+        ved->next_ed = dsc->phys;
+    }
+    dsc = malloc(sizeof(*dsc));
+    if (dsc == NULL) {
+        mempool_put(ohci->ed_pool, ved);
+        return;
+    }
+    dsc->virt = ved;
+    dsc->phys = ped;
+    dsc->function = pipe->device->id;
+    dsc->endpoint = pipe->endpoint->endpoint_address;
+    dsc->type = iscontrol ? USB_CONTROL : USB_BULK;
+    dsc->transfers = cdi_list_create();
+    cdi_list_push(ohci->ed_list, dsc);
+
+    if (iscontrol) {
+        ohci->memory->hc_control_head_ed = ped;
+    } else {
+        ohci->memory->hc_bulk_head_ed = ped;
+    }
+}
+
+static inline int _tsl(volatile int *variable)
+{
+    int rval;
+    rval = *variable;
+    *variable = 1;
+    return rval;
+}
+
+static volatile int locked = 0;
+
+static cdi_usb_status_t do_some_packets(struct cdi_usb_packet *packets,
+    size_t num_packets)
+{
+    struct ohci_ed_desc *edsc;
+    struct ohci_td_desc *tdsc, *otdsc;
+    int i, j, cond, toggle, done_packets;
+    struct ohci *ohci = (struct ohci *)packets[0].pipe->device->hc;
+    struct ohci_td *vtd[num_packets];
+    uintptr_t ptd[num_packets];
+
+    for (i = 0; (edsc = cdi_list_get(ohci->ed_list, i)) != NULL; i++) {
+        if ((edsc->function == packets[0].pipe->device->id) &&
+             (edsc->endpoint == packets[0].pipe->endpoint->endpoint_address))
+        {
+            break;
+        }
+    }
+    if (edsc == NULL) {
+        return CDI_USB_TIMEOUT; //Genau das würde passieren
+    }
+
+    toggle = packets[0].pipe->data_toggle;
+    for (i = 0; i < (int)num_packets; i++) {
+        if (mempool_get(ohci->transfer_pool, (void **)&vtd[i], &ptd[i]) == -1)
+        {
+            return CDI_USB_TRIVIAL_ERROR;
+        }
+        if ((packets[i].data != NULL) &&
+            (packets[i].type != CDI_USB_PACKET_IN))
+        {
+            memcpy((void *)((uintptr_t)vtd[i] + sizeof(struct ohci_td)),
+                    packets[i].data, packets[i].length);
+        }
+        vtd[i]->rounding = 1; //Warum nicht
+        switch (packets[i].type) {
+            case CDI_USB_PACKET_SETUP:
+                vtd[i]->direction = OHC_TD_DIR_SETUP;
+                break;
+            case CDI_USB_PACKET_IN:
+                vtd[i]->direction = OHC_TD_DIR_IN;
+                break;
+            case CDI_USB_PACKET_OUT:
+                vtd[i]->direction = OHC_TD_DIR_OUT;
+                break;
+                default: //Hm, passt nicht ganz
+                    for (j = 0; j <= i; j++) {
+                        mempool_put(ohci->transfer_pool, vtd[j]);
+                    }
+                    return CDI_USB_TRIVIAL_ERROR;
+        }
+        vtd[i]->di = 0;
+        if (packets[i].use_toggle == TOGGLE_0) {
+            toggle = 0;
+        } else if (packets[i].use_toggle == TOGGLE_1) {
+            toggle = 1;
+        }
+        vtd[i]->toggle = 0x2 | toggle;
+        toggle ^= 1;
+        vtd[i]->error = 0;
+        vtd[i]->condition = 15;
+        if ((packets[i].data == NULL) || !packets[i].length) {
+            vtd[i]->current_buffer_pointer = 0;
+            vtd[i]->buffer_end = 0;
+        } else {
+            vtd[i]->current_buffer_pointer = ptd[i] + sizeof(struct ohci_td);
+            vtd[i]->buffer_end = ptd[i] +
+                    sizeof(struct ohci_td) + packets[i].length - 1;
+        }
+        vtd[i]->next_td = 0;
+        tdsc = malloc(sizeof(*tdsc));
+        if (tdsc == NULL) {
+            for (j = 0; j <= i; j++) {
+                mempool_put(ohci->transfer_pool, vtd[j]);
+            }
+            return CDI_USB_TRIVIAL_ERROR;
+        }
+        tdsc->virt = vtd[i];
+        tdsc->phys = ptd[i];
+        tdsc->endpoint = edsc;
+
+        if (cdi_list_size(edsc->transfers)) {
+            otdsc = cdi_list_get(edsc->transfers, 0);
+            otdsc->virt->next_td = ptd[i];
+        }
+        if (!edsc->virt->td_queue_head) {
+            edsc->virt->td_queue_head = ptd[i];
+        }
+
+        cdi_list_push(edsc->transfers, tdsc);
+    }
+    packets[0].pipe->data_toggle = toggle;
+    if (edsc->type == USB_CONTROL) {
+        ohci->memory->hc_command_status |= OHC_CMST_CLF;
+    } else if (edsc->type == USB_BULK) {
+        ohci->memory->hc_command_status |= OHC_CMST_BLF;
+    }
+    done_packets = 0;
+    cond = CDI_USB_NO_ERROR;
+    while (done_packets < (int)num_packets) {
+        cdi_sleep_ms(1);
+        for (i = 0; i < (int)num_packets; i++) {
+            if (vtd[i]->condition != 15) {
+                done_packets++;
+                switch (vtd[i]->condition) {
+                    case 0x00:
+                        packets[i].condition = CDI_USB_NO_ERROR;
+                        break;
+                    case 0x02:
+                        packets[i].condition = CDI_USB_BITSTUFF;
+                        break;
+                    case 0x04:
+                        packets[i].condition = CDI_USB_STALLED;
+                        for (j = 0; j < (int)num_packets; j++) {
+                            //Allet, was nicht fertig ist, ist STALLed
+                            vtd[j]->condition = 0x04;
+                        }
+                        break;
+                    case 0x05:
+                        packets[i].condition = CDI_USB_TIMEOUT;
+                        break;
+                    case 0x08:
+                        packets[i].condition = CDI_USB_BABBLE;
+                        break;
+                    case 0x0C:
+                    case 0x0D:
+                        packets[i].condition = CDI_USB_BUFFER_ERROR;
+                        break;
+                    default:
+                        packets[i].condition = CDI_USB_CRC;
+                        break;
+                }
+                cond |= packets[i].condition;
+                vtd[i]->condition = 15; //Nicht nochmal überprüfen
+            }
+        }
+    }
+    for (i = 0; i < (int)num_packets; i++) {
+        if ((packets[i].data != NULL) &&
+            (packets[i].type == CDI_USB_PACKET_IN))
+        {
+            memcpy(packets[i].data, (void *)((uintptr_t)vtd[i] +
+                    sizeof(struct ohci_td)), packets[i].length);
+        }
+        if (vtd[i]->next_td == 0) {
+            edsc->virt->td_queue_head = 0;
+        }
+        mempool_put(ohci->transfer_pool, vtd[i]);
+    }
+    if (cond & CDI_USB_STALLED) {
+        //Transferliste für diesen Endpoint leeren
+        edsc->virt->td_queue_head = 0;
+        while ((tdsc = cdi_list_pop(edsc->transfers)) != NULL) {
+            free(tdsc);
+        }
+        edsc->virt->td_queue_tail = 0; //Weitermachen
+    }
+    return cond;
+}
+
+static cdi_usb_status_t do_packets(struct cdi_usb_packet *packets,
+    size_t num_packets)
+{
+    int i;
+    cdi_usb_status_t error;
+
+    for (i = 0; i < (int)num_packets; i += 48) {
+        error = do_some_packets(&packets[i],
+            (num_packets - i > 48) ? 48 : (num_packets - i));
+        if (error != CDI_USB_NO_ERROR) {
+            break;
+        }
+    }
+
+    for (; i < (int)num_packets; i++) {
+        packets[i].condition = CDI_USB_NAK;
+    }
+
+    return error;
+}
+
+const struct ohci_functions ohci_functions = {
+    .find_devices = &find_devices,
+    .activate_device = &activate_device,
+    .send_packets = &do_packets,
+    .add_pipe = &add_pipe
+};
diff --git a/src/modules/cdi/ohci/include/ohci-hcd.h b/src/modules/cdi/ohci/include/ohci-hcd.h
new file mode 100644
index 0000000..ccb6345
--- /dev/null
+++ b/src/modules/cdi/ohci/include/ohci-hcd.h
@@ -0,0 +1,39 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#ifndef UHCI_HCD_H
+#define UHCI_HCD_H
+
+#include <cdi/usb.h>
+#include <cdi/usb-hcd.h>
+
+struct ohci_functions {
+    void (*find_devices)(struct cdi_usb_hc *device);
+    void (*activate_device)(struct cdi_usb_device *device);
+    cdi_usb_status_t (*send_packets)(struct cdi_usb_packet *packets,
+        size_t num_packets);
+    void (*add_pipe)(struct cdi_usb_pipe *pipe);
+};
+
+cdi_list_t ohci_find_devices(struct cdi_usb_hc *device);
+
+#endif
diff --git a/src/modules/cdi/ohci/include/ohci-init.h b/src/modules/cdi/ohci/include/ohci-init.h
new file mode 100644
index 0000000..2f19d2c
--- /dev/null
+++ b/src/modules/cdi/ohci/include/ohci-init.h
@@ -0,0 +1,31 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#ifndef OHCI_INIT_H
+#define OHCI_INIT_H
+
+#include "ohci.h"
+
+void find_and_init_ohcis(void);
+void ohci_init(struct cdi_device *dev);
+
+#endif
diff --git a/src/modules/cdi/ohci/include/ohci-transfer.h b/src/modules/cdi/ohci/include/ohci-transfer.h
new file mode 100644
index 0000000..a6dc6be
--- /dev/null
+++ b/src/modules/cdi/ohci/include/ohci-transfer.h
@@ -0,0 +1,30 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#ifndef OHCI_TRANSFER_H
+#define OHCI_TRANSFER_H
+
+#include <cdi/misc.h>
+
+void ohci_handler(struct cdi_device *cdi_hci);
+
+#endif
diff --git a/src/modules/cdi/ohci/include/ohci.h b/src/modules/cdi/ohci/include/ohci.h
new file mode 100644
index 0000000..b06a280
--- /dev/null
+++ b/src/modules/cdi/ohci/include/ohci.h
@@ -0,0 +1,283 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#ifndef OHCI_H
+#define OHCI_H
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <cdi/misc.h>
+#include <cdi/pci.h>
+#include <cdi/usb-hcd.h>
+
+#include "ohci.h"
+
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define d1printf(...) printf("[ohci] " __VA_ARGS__)
+#define _d1printf(...) printf(__VA_ARGS__)
+#else
+#define d1printf(...)
+#define _d1printf(...)
+#endif
+
+#define d0printf(...) printf("[ohci] " __VA_ARGS__)
+#define _d0printf(...) printf(__VA_ARGS__)
+
+
+#define OHC_USB_RESET       0x00000000
+#define OHC_USB_RESUME      0x00000040
+#define OHC_USB_OPERATIONAL 0x00000080
+#define OHC_USB_SUSPEND     0x000000C0
+
+#define OHC_CTRL_CBSR  0x00000003 //Verhältnis zwischen Control und Bulk
+                                 //(cbsr+1 zu 1)
+#define OHC_CTRL_PLE   0x00000004 //Periodische Transfers aktivieren
+#define OHC_CTRL_IE    0x00000008 //Isochronous-Transfers aktivieren
+#define OHC_CTRL_CLE   0x00000010 //Control-Transfers aktivieren
+#define OHC_CTRL_BLE   0x00000020 //Bulk-Transfers aktivieren
+#define OHC_CTRL_HCFS  0x000000C0 //Status des HCs
+#define OHC_CTRL_IR    0x00000100 //Wenn gesetzt, dann werden IRQs zum SMB
+                                  //geleitet
+#define OHC_CTRL_RWC   0x00000200 //Remote wakeup untersetützt
+#define OHC_CTRL_RW    0x00000400 //Remote wakeup aktivieren
+
+#define OHC_CMST_RESET 0x00000001 //Reset
+#define OHC_CMST_CLF   0x00000002 //Control list filled (muss gesetzt werden,
+                                  //wenn ein Eintrag zur Controlliste
+                                  //hinzugefügt wird)
+#define OHC_CMST_BLF   0x00000004 //Bulk list filled (muss gesetzt werden, wenn
+                                  //ein Eintrag zur Bulkliste hinzugefügt wird)
+#define OHC_CMST_OCR   0x00000008 //Ownership change request
+#define OHC_CMST_SOC   0x00030000 //Scheduling overrun count
+
+#define OHC_INT_SO     0x00000001 //Scheduling overrun
+#define OHC_INT_WDH    0x00000002 //Write back done head
+#define OHC_INT_SF     0x00000004 //Start of frame (wird bei SOF gesetzt)
+#define OHC_INT_RD     0x00000008 //Resume detected (wird bei einem von einem
+                                  //Gerät gesendeten Resume gesetzt)
+#define OHC_INT_UE     0x00000010 //Unrecoverable error (wird bei einem HC-
+                                  //Fehler gesetzt, der nichts mit USB zu tun 
+                                  //hat)
+#define OHC_INT_FNO    0x00000020 //Frame number overflow (wird gesetzt, wenn
+                                  //die Framenummer größer als 32767 und
+                                  //umgebrochen wird)
+#define OHC_INT_RHSC   0x00000040 //Root hub status change (wird gesetzt, wenn
+                                  //sich irgendwas am Roothub geändert hat)
+#define OHC_INT_OC     0x40000000 //Ownership change
+#define OHC_INT_MIE    0x80000000 //(De-)Aktiviert Interrupts
+
+#define OHC_RHA_NDP    0x000000FF //Anzahl an Rootports (1 bis 15)
+#define OHC_RHA_PSM    0x00000100 //Gesetzt, wenn man die Stromzufuhr zu
+                                  //einzelnen Ports unabhängig setzen kann
+#define OHC_RHA_NPS    0x00000200 //Gelöscht, wenn man die Stromzufuhr zu
+                                  //einzelnen Ports unabhängig setzen kann
+#define OHC_RHA_DT     0x00000400 //Immer 0, zeigt so an, dass der Roothub kein
+                                  //Compound device ist.
+#define OHC_RHA_OCPM   0x00000800 //Gesetzt, wenn Überspannungen für jeden Port
+                                  //einzeln gemeldet werden
+#define OHC_RHA_NOCP   0x00001000 //Gesetzt, wenn keine Überspannungen erkannt
+                                  //bzw. verhindert werden können
+#define OHC_RHA_POTPGT 0xFF000000 //Power on to power good time (potpgt * 2)
+
+#define OHC_RHS_LPS    0x00000001 //R: 0
+                                  //W: Strom abdrehen
+#define OHC_RHS_OCI    0x00000002 //R: Unspezifische Überspannung
+#define OHC_RHS_DRWE   0x00008000 //R: Irgendwas mit Remote Wakeup Enable
+                                  //W: Das aktivieren
+#define OHC_RHS_LPSC   0x00010000 //R: 0
+                                  //W: Strom andrehen
+#define OHC_RHS_OCIC   0x00020000 //R: Bei Änderungen von OCI gesetzt
+                                  //W: Feld löschen
+#define OHC_RHS_CRWE   0x80000000 //W: Remote Wakeup Enable deaktivieren
+
+#define OHC_RP_CCS     0x00000001 //R: Gerät angeschlossen
+                                  //W: Deaktiviert den Port
+#define OHC_RP_PES     0x00000002 //R: Port aktiviert
+                                  //W: Aktiviert den Port
+#define OHC_RP_PSS     0x00000004 //R: Port schläft
+                                  //W: Schläfert den Port ein
+#define OHC_RP_POCI    0x00000008 //R: Überspannung
+                                  //W: Port aufwecken
+#define OHC_RP_PRS     0x00000010 //R: Reset läuft
+                                  //W: Reset treiben
+#define OHC_RP_PPS     0x00000100 //R: Strom an
+                                  //W: Strom andrehen
+#define OHC_RP_LSDA    0x00000200 //R: Low-Speed-Gerät
+                                  //W: Strom abdrehen
+#define OHC_RP_CSC     0x00010000 //R: Gerät an- oder abgezogen
+                                  //W: Bit löschen
+#define OHC_RP_PESC    0x00020000 //R: Port (de-)aktiviert
+                                  //W: Bit löschen
+#define OHC_RP_PSSC    0x00040000 //R: Port wurde geweckt
+                                  //W: Bit löschen
+#define OHC_RP_OCIC    0x00080000 //R: Überspannungsbit verändert
+                                  //W: Bit löschen
+#define OHC_RP_PRSC    0x00100000 //R: Reset beendet
+                                  //W: Bit löschen
+
+struct ohci_registers
+{
+    uint32_t hc_revision; //Revision
+    volatile uint32_t hc_control;
+    volatile uint32_t hc_command_status;
+    volatile uint32_t hc_interrupt_status;
+    volatile uint32_t hc_interrupt_enable;
+    volatile uint32_t hc_interrupt_disable;
+    uint32_t hc_hcca; //Adresse des HCCA
+    volatile uint32_t hc_period_current_ed; //Adresse des aktuellen
+                                           //Endpointdescriptors der
+                                           //periodischen Transfers
+    uint32_t hc_control_head_ed; //Adresse des ersten Endpointdescriptors der
+                                //Control-Transfers
+    volatile uint32_t hc_control_current_ed; //Adresse des aktuellen
+                                            //Endpointdescriptors der Control-
+                                            //Transfers
+    uint32_t hc_bulk_head_ed; //Adresse des ersten Endpointdescriptors der
+                             //Bulk-Transfers
+    volatile uint32_t hc_bulk_current_ed; //Adresse des aktuellen
+                                         //Endpointdescriptors der Bulk-
+                                         //Transfers
+    volatile uint32_t hc_done_head; //Adresse des zuletzt abgearbeiteten
+                                   //Transferdeskriptors, der der Done-Liste
+                                   //hinzugefügt wurde
+    uint32_t hc_fm_interval; //Gibt die Länge eines Frames und die maximale
+                            //Paketgröße an
+    volatile uint32_t hc_fm_remaining; //Verbleibende Takte des aktuellen
+                                       //Frames
+    volatile uint32_t hc_fm_number; //Nummer des aktuellen Frames
+    uint32_t hc_periodic_start; //10% von HcFmInterval, wenn HcFmInterval
+                                //diesen Wert erreicht, dann haben periodische
+                                //Transfers Vorrang
+    uint32_t hc_ls_threshold; //Besser nicht ändern
+    uint32_t hc_rh_descriptor_a;
+    uint32_t hc_rh_descriptor_b;
+    volatile uint32_t hc_rh_status;
+    volatile uint32_t hc_rh_port_status[];
+} __attribute__((packed));
+
+struct ohci_legsup
+{
+    uint32_t hce_control;
+    uint32_t hce_input;
+    uint32_t hce_output;
+    uint32_t hce_status;
+} __attribute__((packed));
+
+struct ohci_hcca
+{
+    uint32_t interrupt_table[32]; //Zeiger zu Interrupt-EDs
+    uint16_t frame_number; //Die Nummer des aktuellen Frames
+    uint16_t pad; //Wird auf 0 gesetzt, wenn frame_number neu geschrieben wird
+                 //(Ausrichten an DWord-Grenzen vermutlich)
+    uint32_t done_head;
+    uint8_t rsvd[116];
+} __attribute__((packed));
+
+struct ohci
+{
+    struct cdi_usb_hc cdidev;
+    struct cdi_pci_device *pcidev;
+
+    struct ohci_registers *memory;
+    struct ohci_legsup *legsup;
+    int root_ports;
+    struct ohci_hcca *hcca;
+
+    struct mempool *ed_pool;
+    struct mempool *transfer_pool;
+
+    cdi_list_t ed_list;
+};
+
+#define OHC_ED_DIR_TD  0 //Richtung im TD definiert
+#define OHC_ED_DIR_OUT 1
+#define OHC_ED_DIR_IN  2
+
+struct ohci_ed
+{
+    unsigned function : 7; //USB-Adresse des Geräts
+    unsigned endpoint : 4; //Nummer des Endpoints
+    unsigned direction : 2; //Richtung des Transfers
+    unsigned low_speed : 1;
+    unsigned skip : 1;
+    unsigned format : 1; //Bei Isochronous gesetzt
+    unsigned mps : 11; //Maximale Paketgröße
+    unsigned user : 5; //Für uns frei verfügbar
+    uint32_t td_queue_tail; //Letzter TD in der Warteschlange
+    volatile uint32_t td_queue_head; //Nächster TD in der Warteschlange
+    uint32_t next_ed; //Nächster ED
+} __attribute__((packed));
+
+struct ohci_ed_desc
+{
+    struct ohci_ed *virt;
+    uintptr_t phys;
+    int function;
+    int endpoint;
+    cdi_list_t transfers;
+    enum
+    {
+        USB_CONTROL,
+        USB_BULK
+    } type;
+} __attribute__((packed));
+
+#define OHC_TD_DIR_SETUP 0
+#define OHC_TD_DIR_OUT   1
+#define OHC_TD_DIR_IN    2
+
+struct ohci_td
+{
+    unsigned user : 18; //Für uns frei verfügbar
+    unsigned rounding : 1; //Wenn gesetzt, dann sind zu kleine Pakete nicht so
+                          //schlimm
+    unsigned direction : 2; //Richtung/Typ des Transfers (nur gültig, wenn das
+                           //"direction"-Feld im ED 00b oder 11b ist)
+    unsigned di : 3; //Gibt an, wie viele Frames der HC vor Auslösen eines IRQs
+                    //warten soll
+    unsigned toggle : 2; //Datatoggle (00b oder 01b - Wert muss aus dem ED
+                        //ermittelt werden, 10b = DATA0, 11b = DATA1)
+    volatile unsigned error : 2; //Anzahl der aufgetretenen Fehler - bei 11b
+                                //wird der Status im "condition"-Feld
+                                //gespeichert.
+    volatile unsigned condition : 4; //Status
+    volatile uint32_t current_buffer_pointer; //Pointer zu den Daten (bei 0
+                                             //wurden alle Daten übertragen)
+    uint32_t next_td; //Nächster TD
+    uint32_t buffer_end; //Letztes Datenbyte des Puffers
+} __attribute__((packed));
+
+struct ohci_td_desc
+{
+    struct ohci_td *virt;
+    uintptr_t phys;
+    struct ohci_ed_desc *endpoint;
+} __attribute__((packed));
+
+struct cdi_driver *init_ohcd(void);
+void ohci_init(struct cdi_device *cdi_hci);
+
+#endif
diff --git a/src/modules/cdi/ohci/init.c b/src/modules/cdi/ohci/init.c
new file mode 100644
index 0000000..f2c9670
--- /dev/null
+++ b/src/modules/cdi/ohci/init.c
@@ -0,0 +1,249 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cdi/io.h>
+#include <cdi/lists.h>
+#include <cdi/mempool.h>
+#include <cdi/misc.h>
+#include <cdi/pci.h>
+#include <cdi/usb-hcd.h>
+
+#include "ohci.h"
+#include "ohci-hcd.h"
+#include "ohci-init.h"
+#include "ohci-transfer.h"
+
+extern const struct ohci_functions ohci_functions;
+extern int init_ohci(void);
+
+#define DRIVER_NAME "ohcd"
+
+static struct cdi_usb_hcd driver = {
+    .drv = {
+        .type          = CDI_USB_HCD,
+        .name          = DRIVER_NAME,
+        .devices       = NULL,
+        .init_device   = &ohci_init,
+        .remove_device = NULL,
+#ifdef CDI_DRIVER
+        .init          = &init_ohci,
+#endif
+        .destroy       = NULL
+    }
+};
+
+#ifdef CDI_DRIVER
+CDI_DRIVER(DRIVER_NAME, driver)
+#endif
+
+void find_and_init_ohcis(void)
+{
+    struct ohci *hci;
+    char *name;
+    int ohci_counter = 0;
+    struct cdi_pci_device *dev;
+
+    cdi_usb_hcd_init(&driver);
+
+    cdi_list_t pci_devices = cdi_list_create();
+    cdi_pci_get_all_devices(pci_devices);
+    for (int i = 0; (dev = cdi_list_get(pci_devices, i)) != NULL; i++) {
+        if ((dev->class_id != 0x0C) || (dev->subclass_id != 0x03)
+            || (dev->interface_id != 0x10))
+        {
+            cdi_pci_device_destroy(dev);
+        } else {
+            hci = malloc(sizeof(struct ohci));
+            hci->cdidev.dev.type = CDI_USB_HCD;
+            name = malloc(7);
+            sprintf(name, "ohci%i", ohci_counter++);
+            hci->cdidev.dev.name = (const char *)name;
+            hci->cdidev.speed = CDI_USB_LOW_SPEED | CDI_USB_FULL_SPEED;
+            hci->pcidev = dev;
+            cdi_list_push(driver.drv.devices, hci);
+        }
+    }
+
+    cdi_list_destroy(pci_devices);
+
+    driver.find_devices = ohci_functions.find_devices;
+    driver.activate_device = ohci_functions.activate_device;
+    driver.send_packets = ohci_functions.send_packets;
+    driver.add_pipe = ohci_functions.add_pipe;
+
+#ifndef CDI_DRIVER
+    cdi_driver_register((struct cdi_driver*) &driver);
+#endif
+}
+
+void ohci_init(struct cdi_device *dev)
+{
+    struct ohci *ohci = (struct ohci *)dev;
+    struct cdi_pci_resource *res;
+    int i;
+    uintptr_t phys_hcca;
+
+    ohci->memory = NULL;
+    for (i = 0; (res = cdi_list_get(ohci->pcidev->resources, i)) != NULL;
+        i++)
+    {
+        if (res->type == CDI_PCI_MEMORY) {
+            ohci->memory = cdi_alloc_phys_addr(res->length, res->start);
+            if (ohci->memory == NULL) {
+                d0printf("Wasn't able to allocate memory.\n");
+                return;
+            }
+            ohci->legsup = (void *)((uintptr_t)ohci->memory + 0x100);
+            break;
+        }
+    }
+    if (ohci->memory == NULL) {
+        d1printf("Memory not found!\n");
+        return;
+    }
+    d1printf("Memory @ 0x%08X\n", (uintptr_t)ohci->memory);
+    if ((ohci->memory->hc_revision & 0xFF) != 0x10) {
+        d0printf("This OHCI might be incompatible with this driver"
+            "(HCI %i.%i, HCD 1.0)\n", (ohci->memory->hc_revision & 0xF0) >> 4,
+            ohci->memory->hc_revision & 0xF);
+    }
+    if (cdi_alloc_phys_mem(sizeof(*ohci->hcca), (void **)&ohci->hcca,
+        (void **)&phys_hcca) == -1)
+    {
+        d0printf("Wasn't able to allocate HCCA.\n");
+        return;
+    }
+    memset(ohci->hcca, 0, sizeof(*ohci->hcca));
+
+    d1printf("IRQ: %i\n", ohci->pcidev->irq);
+    cdi_register_irq(ohci->pcidev->irq, &ohci_handler, dev);
+
+    ohci->ed_pool = mempool_create(64 * sizeof(struct ohci_ed),
+        sizeof(struct ohci_ed));
+    if (ohci->ed_pool == NULL) {
+        d0printf("Wasn't able to create ED memory pool!\n");
+        return;
+    }
+
+    ohci->transfer_pool = mempool_create(48 * (1024 + sizeof(struct ohci_td)),
+        1024 + sizeof(struct ohci_td));
+    if (ohci->transfer_pool == NULL) {
+        d0printf("Wasn't able to create transfer memory pool!\n");
+        return;
+    }
+
+    ohci->memory->hc_interrupt_disable = OHC_INT_MIE;
+
+    if (ohci->memory->hc_control & OHC_CTRL_IR) {
+        d1printf("Kicking out SMM... ");
+        //Änderung des "Besitzers" beantragen
+        ohci->memory->hc_command_status |= OHC_CMST_OCR;
+        for (i = 0; (ohci->memory->hc_control & OHC_CTRL_IR) && (i < 1000);
+            i++)
+        {
+            cdi_sleep_ms(1);
+        }
+        if (i < 100) {
+            _d1printf("Went fine.\n");
+        } else {
+            _d1printf("Idiot.\n");
+            ohci->memory->hc_control &= ~OHC_CTRL_IR;
+        }
+    } else if ((ohci->memory->hc_control & OHC_CTRL_CBSR) != OHC_USB_RESET) {
+        d1printf("BIOS active\n");
+        if ((ohci->memory->hc_control & OHC_CTRL_CBSR) != OHC_USB_OPERATIONAL)
+        {
+            d1printf("Activating RESUME...\n");
+            ohci->memory->hc_control =
+                (ohci->memory->hc_control & ~OHC_CTRL_CBSR) | OHC_USB_RESUME;
+            cdi_sleep_ms(10);
+        }
+    } else {
+        //Nix, weder BIOS noch SMM
+        cdi_sleep_ms(10); //Reset abwarten
+    }
+
+    if (ohci->legsup->hce_control & 1) {
+        d1printf("USB legacy support activated, but that won't last for"
+            "long...\n");
+    }
+    //Harhar, that's mine now!
+    ohci->legsup->hce_control = 0;
+
+    ohci->memory->hc_command_status |= OHC_CMST_RESET;
+    //Normalerweise sollte man den Wert von hc_fm_interval von vor dem Reset
+    //wiederherstellen, aber ich finde das Schwachsinn. Die Werte sind so in
+    //Ordnung, wie sie jetzt sind.
+
+    cdi_sleep_ms(3); //10 µs für den Reset und 2 ms für Resume
+    if ((ohci->memory->hc_control & OHC_CTRL_CBSR) == OHC_USB_SUSPEND) {
+        //Boah...
+        d1printf("Reset not finished yet...\n");
+        ohci->memory->hc_control =
+            (ohci->memory->hc_control & ~OHC_CTRL_CBSR) | OHC_USB_RESUME;
+        cdi_sleep_ms(10);
+    }
+
+    ohci->memory->hc_interrupt_disable = OHC_INT_MIE;
+
+    ohci->memory->hc_hcca = phys_hcca;
+    ohci->memory->hc_interrupt_status = 0xFFFFFFFF;
+    ohci->memory->hc_interrupt_enable =
+        OHC_INT_SO   | //Scheduling overrun
+        OHC_INT_WDH  | //Write back done head
+        OHC_INT_RD   | //Resume detected
+        OHC_INT_UE   | //Schwerer Fehler
+        OHC_INT_RHSC | //Root hub status change
+        OHC_INT_MIE;
+    //Eigentlich sollte man alle Transfers aktivieren. Aber wir wollen ja noch
+    //gar keine periodischen Transfers...
+    //Periodisches Zeug deaktivieren
+    ohci->memory->hc_control &= ~(OHC_CTRL_PLE | OHC_CTRL_IE);
+    //Control und Bulk aktivieren
+    ohci->memory->hc_control |= OHC_CTRL_CLE | OHC_CTRL_BLE;
+    //Merkwürdigerweise soll das jetzt nicht auf 10 %, sondern auf 90 % gesetzt
+    //werden. Aber das klingt total bescheuert, weil nicht erklärt wird, wann
+    //man es denn auf 10 % setzen soll. Deshalb machen wir das gleich.
+    ohci->memory->hc_periodic_start = 0x4B0;
+
+    d1printf("Activating HC.\n");
+
+    //DO IT, FAGGOT!
+    ohci->memory->hc_control =
+        (ohci->memory->hc_control & ~OHC_CTRL_CBSR) | OHC_USB_OPERATIONAL;
+
+    ohci->memory->hc_rh_status |= OHC_RHS_LPSC; //Strom andrehen
+    ohci->root_ports = ohci->memory->hc_rh_descriptor_a & OHC_RHA_NDP;
+    cdi_sleep_ms((ohci->memory->hc_rh_descriptor_a & OHC_RHA_POTPGT) >> 23);
+
+    d0printf("Found %i root ports.\n", ohci->root_ports);
+
+    for (i = 0; i < ohci->root_ports; i++) {
+        ohci->memory->hc_rh_port_status[i] |= OHC_RP_CCS; //Deaktivieren
+    }
+
+    ohci->ed_list = cdi_list_create();
+}
diff --git a/src/modules/cdi/ohci/main.c b/src/modules/cdi/ohci/main.c
new file mode 100644
index 0000000..323960a
--- /dev/null
+++ b/src/modules/cdi/ohci/main.c
@@ -0,0 +1,32 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#include <cdi/misc.h>
+
+#include "ohci-init.h"
+
+int init_ohci(void)
+{
+    find_and_init_ohcis();
+
+    return 0;
+}
diff --git a/src/modules/cdi/ohci/transfer.c b/src/modules/cdi/ohci/transfer.c
new file mode 100644
index 0000000..24f7c67
--- /dev/null
+++ b/src/modules/cdi/ohci/transfer.c
@@ -0,0 +1,85 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <cdi/io.h>
+#include <cdi/lists.h>
+#include <cdi/misc.h>
+
+#include "ohci.h"
+
+void ohci_handler(struct cdi_device *cdi_hci)
+{
+    struct ohci *ohci = (struct ohci *)cdi_hci;
+    struct ohci_ed_desc *edsc;
+    struct ohci_td_desc *tdsc;
+    uint32_t status, done = 0;
+    int i, j;
+    uintptr_t phys;
+
+    status = ohci->memory->hc_interrupt_status;
+    if (!status) {
+        return; //Wohl nicht für uns
+    }
+
+    if (status & OHC_INT_RHSC) {
+        done |= OHC_INT_RHSC;
+    }
+    if (status & OHC_INT_UE) {
+        d0printf("Fatal HC error.\n");
+        ohci->memory->hc_command_status |= OHC_CMST_RESET;
+        done |= OHC_INT_UE;
+    }
+    if (status & OHC_INT_SF) {
+        //Öhm... Na ja. Manchmal fragt man sich, ob sich der HC so einsam
+        //fühlt, dass er IRQs feuert, obwohl sie deaktiviert sind.
+        done |= OHC_INT_SF;
+    }
+    if (status & OHC_INT_WDH) {
+        //Paket gesendet
+        done |= OHC_INT_WDH;
+        phys = ohci->hcca->done_head;
+        for (i = 0; (edsc = cdi_list_get(ohci->ed_list, i)) != NULL; i++) {
+            for (j = 0; (tdsc = cdi_list_get(edsc->transfers, j)) != NULL; j++)
+            {
+                if (tdsc->phys == phys) {
+                    //Das ist der fertige Transfer
+                    cdi_list_remove(edsc->transfers, j);
+                    free(tdsc);
+                    break;
+                }
+            }
+            if (tdsc != NULL) {
+                //Gefunden
+                break;
+            }
+        }
+    }
+
+    if (status & ~done) {
+        d1printf("Non-handled interrupt: 0x%08X\n", status & ~done);
+    }
+
+    ohci->memory->hc_interrupt_status = status;
+}
diff --git a/src/modules/cdi/uhci/Makefile.all b/src/modules/cdi/uhci/Makefile.all
new file mode 100644
index 0000000..e027b50
--- /dev/null
+++ b/src/modules/cdi/uhci/Makefile.all
@@ -0,0 +1,2 @@
+shopt -s extglob
+source $LOST_BUILDMK_ROOT/config.sh
diff --git a/src/modules/cdi/uhci/hcd.c b/src/modules/cdi/uhci/hcd.c
new file mode 100644
index 0000000..79f7481
--- /dev/null
+++ b/src/modules/cdi/uhci/hcd.c
@@ -0,0 +1,215 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <cdi/io.h>
+#include <cdi/lists.h>
+#include <cdi/mempool.h>
+#include <cdi/usb.h>
+#include <cdi/usb-hcd.h>
+
+#include "uhci.h"
+#include "uhci-hcd.h"
+
+extern cdi_list_t uhci_active_transfers;
+
+static void reset_device(struct cdi_usb_device *device);
+
+static void find_devices(struct cdi_usb_hc *device)
+{
+    struct uhci *uhci = (struct uhci *)device;
+    struct cdi_usb_device *dev;
+    int i;
+
+    d0printf("Scanning root ports\n");
+    cdi_outw(uhci->pbase + UHCI_USBCMD, USB_RUN);
+    for (i = 0; i < uhci->root_ports; i++) {
+        if (!(cdi_inw(uhci->pbase + UHCI_RPORTS + 2 * i) & RPORT_DEVICE)) {
+            continue;
+        }
+        dev = calloc(1, sizeof(struct cdi_usb_device));
+        dev->hc = device;
+        dev->id = 0;
+        dev->port = i;
+        dev->speed = (cdi_inw(uhci->pbase + UHCI_RPORTS + 2 * i) &
+                RPORT_LOSPD) ? CDI_USB_LOW_SPEED : CDI_USB_FULL_SPEED;
+        dev->hub = NULL;
+        dev->reset = &reset_device;
+        cdi_usb_device_init(dev);
+    }
+}
+
+static void activate_device(struct cdi_usb_device *device)
+{
+    struct uhci *uhci = (struct uhci *)device->hc;
+
+    if (device->hub != NULL) {
+        return;
+    }
+
+    d1printf("Activating device on port %i.\n", device->port);
+    cdi_outw(uhci->pbase + UHCI_RPORTS + 2 * device->port,
+             RPORT_ENABLE | RPORT_CSC);
+    cdi_sleep_ms(20);
+}
+
+static void reset_device(struct cdi_usb_device *device)
+{
+    struct uhci *uhci = (struct uhci *)device->hc;
+
+    if (device->hub != NULL) {
+        return;
+    }
+
+    d1printf("Resetting device on port %i.\n", device->port);
+    cdi_outw(uhci->pbase + UHCI_RPORTS + 2 * device->port,
+             RPORT_ENABLE | RPORT_RESET | RPORT_CSC);
+    cdi_sleep_ms(20);
+}
+
+static void add_pipe(struct cdi_usb_pipe *pipe)
+{
+    //Macht nix, weil das bei UHCI nicht nötig ist
+    pipe = NULL; //Aber GCC können wir trotzdem glücklich machen
+}
+
+static inline int _tsl(volatile int *variable)
+{
+    int rval;
+    rval = *variable;
+    *variable = 1;
+    return rval;
+}
+
+static volatile int locked = 0;
+
+static cdi_usb_status_t do_packet(struct cdi_usb_packet *packet)
+{
+    struct cdi_usb_device *usbdev = packet->pipe->device;
+    struct uhci *uhci = (struct uhci *)usbdev->hc;
+    struct uhci_td td;
+    struct transfer addr;
+    int timeout, frame;
+
+    void *buf;
+    uintptr_t pbuf;
+
+    memset(&td, 0, sizeof(td));
+    td.next = 1; //Invalid
+    td.active = 1;
+    td.ioc = 1;
+    if (packet->use_toggle == TOGGLE_0) {
+        packet->pipe->data_toggle = 0;
+    } else if (packet->use_toggle == TOGGLE_1) {
+        packet->pipe->data_toggle = 1;
+    }
+    td.data_toggle = packet->pipe->data_toggle;
+    packet->pipe->data_toggle ^= 1;
+    td.low_speed = !!(usbdev->speed == CDI_USB_LOW_SPEED);
+    td.errors = 1;
+    td.pid = packet->type;
+    td.device = usbdev->id;
+    td.endpoint = packet->pipe->endpoint->endpoint_address & 0x07;
+    td.maxlen = packet->length ? packet->length - 1 : 0x7FF;
+    while (_tsl(&locked));
+    frame = (cdi_inw(uhci->pbase + UHCI_FRNUM) + 5) & 0x3FF;
+    while (!(uhci->queue_heads[frame].transfer & 1)) {
+        frame++;
+        frame &= 0x3FF;
+    }
+
+    if (mempool_get(uhci->buffers, &buf, &pbuf) < 0) {
+        return CDI_USB_TRIVIAL_ERROR;
+    }
+
+    addr.virt = buf;
+    addr.phys = pbuf;
+    addr.error = 0xFFFF;
+
+    buf = (void *)((uintptr_t)buf + sizeof(td));
+    pbuf += sizeof(td);
+
+    if (!packet->length) {
+        td.buffer = 0;
+    } else {
+        td.buffer = pbuf;
+        if (packet->type != CDI_USB_PACKET_IN) {
+            memcpy(buf, packet->data, packet->length);
+        }
+    }
+
+    memcpy(addr.virt, &td, sizeof(td));
+
+
+    if (uhci_active_transfers == NULL) {
+        uhci_active_transfers = cdi_list_create();
+    }
+    uhci->queue_heads[frame].transfer = addr.phys;
+    cdi_list_push(uhci_active_transfers, &addr);
+
+    locked = 0;
+    for (timeout = 0; !(uhci->queue_heads[frame].transfer & 1) &&
+         (timeout < 1000); timeout++)
+    {
+        cdi_sleep_ms(1);
+    }
+    while ((timeout < 1000) && (addr.error == 0xFFFF)) {
+#ifndef CDI_STANDALONE
+        __asm__ __volatile__ ("hlt");
+#endif
+    }
+    if (packet->type == CDI_USB_PACKET_IN) {
+        memcpy(packet->data, buf, packet->length);
+    }
+    if (addr.error == 0xFFFF) {
+        addr.error = CDI_USB_TIMEOUT;
+    }
+
+    mempool_put(uhci->buffers, addr.virt);
+
+    return addr.error;
+}
+
+static cdi_usb_status_t do_packets(struct cdi_usb_packet *packets,
+    size_t num_packets)
+{
+    size_t i;
+    cdi_usb_status_t cond = CDI_USB_NO_ERROR;
+
+    //TODO
+    for (i = 0; (i < num_packets) && !cond; i++) {
+        packets[i].condition = do_packet(&packets[i]);
+        cond |= packets[i].condition;
+    }
+
+    return cond;
+}
+
+
+const struct uhci_functions uhci_functions = {
+    .find_devices = &find_devices,
+    .activate_device = &activate_device,
+    .send_packets = &do_packets,
+    .add_pipe = &add_pipe
+};
diff --git a/src/modules/cdi/uhci/include/uhci-hcd.h b/src/modules/cdi/uhci/include/uhci-hcd.h
new file mode 100644
index 0000000..46e4093
--- /dev/null
+++ b/src/modules/cdi/uhci/include/uhci-hcd.h
@@ -0,0 +1,39 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#ifndef UHCI_HCD_H
+#define UHCI_HCD_H
+
+#include <cdi/usb.h>
+#include <cdi/usb-hcd.h>
+
+struct uhci_functions {
+    void (*find_devices)(struct cdi_usb_hc *device);
+    void (*activate_device)(struct cdi_usb_device *device);
+    cdi_usb_status_t (*send_packets)(struct cdi_usb_packet *packets,
+        size_t num_packets);
+    void (*add_pipe)(struct cdi_usb_pipe *pipe);
+};
+
+cdi_list_t uhci_find_devices(struct cdi_usb_hc *device);
+
+#endif
diff --git a/src/modules/cdi/uhci/include/uhci-init.h b/src/modules/cdi/uhci/include/uhci-init.h
new file mode 100644
index 0000000..7b357bc
--- /dev/null
+++ b/src/modules/cdi/uhci/include/uhci-init.h
@@ -0,0 +1,31 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#ifndef UHCI_INIT_H
+#define UHCI_INIT_H
+
+#include "uhci.h"
+
+void find_and_init_uhcis(void);
+void uhci_init(struct cdi_device *dev);
+
+#endif
diff --git a/src/modules/cdi/uhci/include/uhci-transfer.h b/src/modules/cdi/uhci/include/uhci-transfer.h
new file mode 100644
index 0000000..53b46b0
--- /dev/null
+++ b/src/modules/cdi/uhci/include/uhci-transfer.h
@@ -0,0 +1,30 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#ifndef UHCI_TRANSFER_H
+#define UHCI_TRANSFER_H
+
+#include <cdi/misc.h>
+
+void uhci_handler(struct cdi_device *cdi_hci);
+
+#endif
diff --git a/src/modules/cdi/uhci/include/uhci.h b/src/modules/cdi/uhci/include/uhci.h
new file mode 100644
index 0000000..678b2a1
--- /dev/null
+++ b/src/modules/cdi/uhci/include/uhci.h
@@ -0,0 +1,138 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#ifndef UHCI_H
+#define UHCI_H
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <cdi/mempool.h>
+#include <cdi/misc.h>
+#include <cdi/pci.h>
+#include <cdi/usb-hcd.h>
+
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define d1printf(...) printf("[uhci] " __VA_ARGS__)
+#define _d1printf(...) printf(__VA_ARGS__)
+#else
+#define d1printf(...)
+#define _d1printf(...)
+#endif
+
+#define d0printf(...) printf("[uhci] " __VA_ARGS__)
+#define _d0printf(...) printf(__VA_ARGS__)
+
+
+#define UHCI_USBCMD    0x00 //w
+#define UHCI_USBSTS    0x02 //w
+#define UHCI_USBINTR   0x04 //w
+#define UHCI_FRNUM     0x06 //w
+#define UHCI_FRBASEADD 0x08 //l
+#define UHCI_SOFMOD    0x0C //b
+#define UHCI_RPORTS    0x10
+#define UHCI_PORTSC1   0x10 //w
+#define UHCI_PORTSC2   0x12 //w
+
+#define MAXP           0x0080
+#define CONFIGURE      0x0040
+#define GLOB_SUSP_MODE 0x0008
+#define GRESET         0x0004
+#define HCRESET        0x0002
+#define USB_RUN        0x0001
+
+#define RPORT_RESET    0x0200
+#define RPORT_LOSPD    0x0100 //Low speed device attached
+#define RPORT_ENABLE   0x0004
+#define RPORT_CSC      0x0002 //Connect status change
+#define RPORT_DEVICE   0x0001
+
+//Legacy support
+#define UHCI_PCI_LEGSUP 0xC0 //w
+
+#define UHCI_LEGSUP_STATUS 0x8F00 //Statusbits, die mittels schreiben einer 1
+                                  //gelöscht werden
+#define UHCI_LEGSUP_NO_CHG 0x5040 //Bits, die nicht verändert werden können
+                                  //(RO bzw. reserviert)
+#define UHCI_LEGSUP_PIRQ   0x2000 //Interrupt wird als PCI-IRQ ausgeführt
+
+
+struct uhci_qh {
+    volatile uint32_t next;
+    volatile uint32_t transfer;
+    uint32_t align[2]; //Fürs korrekte Alignment (an 16 Bytes)
+} __attribute__((packed));
+
+struct uhci_td {
+    volatile uint32_t next;
+
+    unsigned trans_len : 11;
+    unsigned rsvd0 : 6;
+    unsigned bitstuff_err : 1;
+    unsigned crc_time_err : 1;
+    unsigned nak : 1;
+    unsigned babble : 1;
+    unsigned buf_err : 1;
+    unsigned stalled_err : 1;
+    unsigned active : 1;
+    unsigned ioc : 1;
+    unsigned isochronous : 1;
+    unsigned low_speed : 1;
+    unsigned errors : 2;
+    unsigned spd : 1;
+    unsigned rsvd1 : 2;
+
+    unsigned pid : 8;
+    unsigned device : 7;
+    unsigned endpoint : 4;
+    unsigned data_toggle : 1;
+    unsigned rsvd2 : 1;
+    unsigned maxlen : 11;
+
+    uint32_t buffer;
+
+    uint32_t user[4];
+} __attribute__((packed));
+
+struct transfer {
+    void *virt;
+    uintptr_t phys;
+    volatile int error;
+};
+
+struct uhci {
+    struct cdi_usb_hc cdidev;
+    struct cdi_pci_device *pcidev;
+    int pbase;
+    uintptr_t phys_frame_list;
+    uint32_t *frame_list;
+    int root_ports;
+    struct uhci_qh *queue_heads;
+    struct uhci_qh *phys_queue_heads;
+
+    struct mempool *buffers;
+};
+
+#endif
diff --git a/src/modules/cdi/uhci/init.c b/src/modules/cdi/uhci/init.c
new file mode 100644
index 0000000..e9f9569
--- /dev/null
+++ b/src/modules/cdi/uhci/init.c
@@ -0,0 +1,257 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <cdi/io.h>
+#include <cdi/lists.h>
+#include <cdi/mempool.h>
+#include <cdi/misc.h>
+#include <cdi/pci.h>
+#include <cdi/usb-hcd.h>
+
+#include "uhci.h"
+#include "uhci-hcd.h"
+#include "uhci-init.h"
+#include "uhci-transfer.h"
+
+extern const struct uhci_functions uhci_functions;
+extern int init_uhci(void);
+
+#define DRIVER_NAME "uhcd"
+
+static struct cdi_usb_hcd driver = {
+    .drv = {
+        .type          = CDI_USB_HCD,
+        .name          = DRIVER_NAME,
+        .devices       = NULL,
+        .init_device   = &uhci_init,
+        .remove_device = NULL,
+#ifdef CDI_DRIVER
+        .init          = &init_uhci,
+#endif
+        .destroy       = NULL
+    }
+};
+
+#ifdef CDI_DRIVER
+CDI_DRIVER(DRIVER_NAME, driver)
+#endif
+
+void find_and_init_uhcis(void)
+{
+    struct uhci *hci;
+    char *name;
+    int uhci_counter = 0;
+    struct cdi_pci_device *dev;
+
+    cdi_usb_hcd_init(&driver);
+
+    cdi_list_t pci_devices = cdi_list_create();
+    cdi_pci_get_all_devices(pci_devices);
+    for (int i = 0; (dev = cdi_list_get(pci_devices, i)) != NULL; i++) {
+        if ((dev->class_id != 0x0C) || (dev->subclass_id != 0x03)
+            || (dev->interface_id != 0x00))
+        {
+            cdi_pci_device_destroy(dev);
+        } else {
+            hci = malloc(sizeof(struct uhci));
+            hci->cdidev.dev.type = CDI_USB_HCD;
+            name = malloc(7);
+            sprintf(name, "uhci%i", uhci_counter++);
+            hci->cdidev.dev.name = (const char *)name;
+            hci->cdidev.speed = CDI_USB_LOW_SPEED | CDI_USB_FULL_SPEED;
+            hci->pcidev = dev;
+            cdi_list_push(driver.drv.devices, hci);
+        }
+    }
+
+    cdi_list_destroy(pci_devices);
+
+    driver.find_devices = uhci_functions.find_devices;
+    driver.activate_device = uhci_functions.activate_device;
+    driver.send_packets = uhci_functions.send_packets;
+    driver.add_pipe = uhci_functions.add_pipe;
+
+#ifndef CDI_DRIVER
+    cdi_driver_register((struct cdi_driver*) &driver);
+#endif
+}
+
+void uhci_init(struct cdi_device *dev)
+{
+    struct uhci *uhci = (struct uhci *)dev;
+    struct cdi_pci_resource *res;
+    int size = 0, request_size, cmd, intr, i;
+#ifdef CDI_PCI_DIRECT_ACCESS
+    int legsup;
+#endif
+
+    d0printf("Trying to init %s at %02x:%02x.%02x...\n", uhci->cdidev.dev.name,
+        uhci->pcidev->bus, uhci->pcidev->dev, uhci->pcidev->function);
+
+    uhci->pbase = 0;
+    for (i = 0; (res = cdi_list_get(uhci->pcidev->resources, i)) != NULL; i++)
+    {
+        if (res->type == CDI_PCI_IOPORTS) {
+            size = res->length ? res->length : 0x14;
+            if (cdi_ioports_alloc(res->start, size) == -1) {
+                d0printf("Cannot allocate I/O ports.\n");
+                return;
+            }
+            uhci->pbase = res->start;
+            break;
+        }
+    }
+    if (!uhci->pbase) {
+        d0printf("No I/O space found.\n");
+        return;
+    }
+    request_size =
+            // Maximale Paketlänge (Full Speed) ist 1023, Alignment außerdem
+            1024 +
+            // Transferdeskriptor
+            sizeof(struct uhci_td);
+
+    uhci->buffers = mempool_create(8192, request_size);
+    if (uhci->buffers == NULL) {
+        d0printf("Cannot create mempool.\n");
+        return;
+    }
+
+    if (cdi_alloc_phys_mem(sizeof(*uhci->queue_heads) * 1024,
+        (void **)&uhci->queue_heads, (void **)&uhci->phys_queue_heads) == -1)
+    {
+        d0printf("Cannot allocate QH memory.\n");
+        return;
+    }
+
+    if (cdi_alloc_phys_mem(4096, (void **)&uhci->frame_list,
+        (void **)&uhci->phys_frame_list) == -1)
+    {
+        d0printf("Cannot allocate frame list.\n");
+        return;
+    }
+
+#ifdef CDI_PCI_DIRECT_ACCESS
+    cdi_pci_config_outw(uhci->pcidev, 4, 0x05);
+#endif
+
+    cdi_register_irq(uhci->pcidev->irq, &uhci_handler, dev);
+    uhci->root_ports = (size - 0x10) >> 1;
+    //Erstmal testen, wie viele wir genau haben...
+    for (i = 2; i < uhci->root_ports; i++) {
+        if (!(cdi_inw(uhci->pbase + UHCI_RPORTS + i * 2) & 0x0080) ||
+              (cdi_inw(uhci->pbase + UHCI_RPORTS + i * 2) == 0xFFFF))
+        {
+            uhci->root_ports = i;
+            break;
+        }
+    }
+    //Mehr als sieben Rootports, klingt lustig
+    if (uhci->root_ports > 7) {
+        uhci->root_ports = 2;
+    }
+
+    d1printf("I/O 0x%04X (%i ports), IRQ %i\n", uhci->pbase, uhci->root_ports,
+        uhci->pcidev->irq);
+
+#ifdef CDI_PCI_DIRECT_ACCESS
+    legsup = cdi_pci_config_inw(uhci->pcidev, UHCI_PCI_LEGSUP);
+#endif
+    cmd = cdi_inw(uhci->pbase + UHCI_USBCMD);
+    intr = cdi_inw(uhci->pbase + UHCI_USBINTR);
+
+#ifdef CDI_PCI_DIRECT_ACCESS
+    //Wenn der HC läuft, das Configurebit gesetzt ist, der nicht runtergefahren
+    //ist oder dieses Interrupt-enable-Bit gesetzt ist, dann war wohl schon
+    //jemand dran.
+    //(oder wenn der Legacy Support aktiviert ist, das heißt, wenn in LEGSUP
+    //irgendein Bit gesetzt ist, dass nicht RO/reserviert oder ein Statusbit
+    //ist)
+    if ((legsup & ~(UHCI_LEGSUP_STATUS | UHCI_LEGSUP_NO_CHG)) ||
+         (cmd & USB_RUN) || !(cmd & CONFIGURE) || !(cmd & GLOB_SUSP_MODE) ||
+         (intr & 0x0002))
+    {
+        //Na, wer hat denn da am HC rumgefummelt. Bööööses BIOS. Oder SMM. Oder
+        //wer auch immer.
+        //Alle LEGSUP-Statusbits löschen
+        cdi_pci_config_outw(uhci->pcidev, UHCI_PCI_LEGSUP,
+                            UHCI_LEGSUP_STATUS);
+#endif
+        //Resetten
+        cdi_outw(uhci->pbase + UHCI_USBCMD, HCRESET);
+        //Warten, bis der Reset beendet ist
+        for (i = 0; (cdi_inw(uhci->pbase + UHCI_USBCMD) & HCRESET) &&
+             (i < 50); i++)
+        {
+            cdi_sleep_ms(10);
+        }
+        if (i == 50) {
+            d1printf("Reset not finished...\n");
+        }
+
+        //Interrupts erstmal deaktivieren
+        cdi_outw(uhci->pbase + UHCI_USBINTR, 0);
+        //Den gesamten HC ebenso
+        cdi_outw(uhci->pbase + UHCI_USBCMD, 0);
+
+        //Alle Ports "runterfahren"
+        for (int port = 0; port < uhci->root_ports; port++) {
+            cdi_outw(uhci->pbase + UHCI_RPORTS + (port * 2), 0);
+        }
+#ifdef CDI_PCI_DIRECT_ACCESS
+    }
+#endif
+
+    for (i = 0; i < 1024; i++) {
+        uhci->queue_heads[i].next = 1; //Invalid
+        uhci->queue_heads[i].transfer = 1; //Invalid
+    }
+    for (i = 0; i < 1024; i++) {
+        uhci->frame_list[i] = (uintptr_t)&uhci->phys_queue_heads[i] | 2;
+    }
+
+    //Standardwert, jede Millisekunde ein Frame
+    cdi_outb(uhci->pbase + UHCI_SOFMOD, 0x40);
+    //Unsere Frameliste eintragen
+    cdi_outl(uhci->pbase + UHCI_FRBASEADD, uhci->phys_frame_list);
+    //Frame zurücksetzen
+    cdi_outw(uhci->pbase + UHCI_FRNUM, 0);
+#ifdef CDI_PCI_DIRECT_ACCESS
+    //Hier setzen wir das PIRQ-Bit und deaktivieren sämtlichen Legacy Support.
+    cdi_pci_config_outw(uhci->pcidev, UHCI_PCI_LEGSUP, UHCI_LEGSUP_PIRQ);
+#else
+    d0printf("Failed to deactivate USB legacy support.\n");
+#endif
+
+    //HC starten
+    cdi_outw(uhci->pbase + UHCI_USBCMD, USB_RUN | CONFIGURE | MAXP);
+    //Alle Interrupts aktivieren
+    cdi_outw(uhci->pbase + UHCI_USBINTR, 0xF);
+
+    //Connect status change löschen
+    for (i = 0; i < uhci->root_ports; i++) {
+        cdi_outw(uhci->pbase + UHCI_RPORTS + i * 2, RPORT_CSC);
+    }
+}
diff --git a/src/modules/cdi/uhci/main.c b/src/modules/cdi/uhci/main.c
new file mode 100644
index 0000000..7047be9
--- /dev/null
+++ b/src/modules/cdi/uhci/main.c
@@ -0,0 +1,32 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#include <cdi/misc.h>
+
+#include "uhci-init.h"
+
+int init_uhci(void)
+{
+    find_and_init_uhcis();
+
+    return 0;
+}
diff --git a/src/modules/cdi/uhci/transfer.c b/src/modules/cdi/uhci/transfer.c
new file mode 100644
index 0000000..33c60bf
--- /dev/null
+++ b/src/modules/cdi/uhci/transfer.c
@@ -0,0 +1,91 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#include <stdio.h>
+
+#include <cdi/io.h>
+#include <cdi/lists.h>
+#include <cdi/misc.h>
+
+#include "uhci.h"
+
+cdi_list_t uhci_active_transfers = NULL;
+
+void uhci_handler(struct cdi_device *cdi_hci)
+{
+    struct uhci *uhci = (struct uhci *)cdi_hci;
+    int status = cdi_inw(uhci->pbase + UHCI_USBSTS), i;
+    struct transfer *addr;
+    struct uhci_td *td;
+
+    if (!status) {
+        //Also, von hier kommt der IRQ nicht.
+        return;
+    }
+    //Ist Bit 0 gesetzt, dann ist das ein normaler IOC (Interrupt on
+    //completion), bei Bit 1 ist ein Fehler aufgetreten, aber das werden wir ja
+    //unten sehen.
+    if (status & ~0x0003) {
+        d1printf("Unerwarteter IRQ 0x%04X von %s\n", status, cdi_hci->name);
+    }
+    if (status & 0x10) {
+        d0printf("SCHWERWIEGENDER FEHLER - HC WIRD ANGEHALTEN\n");
+        cdi_outw(uhci->pbase + UHCI_USBCMD, MAXP | HCRESET); //FU!
+    } else {
+        for (i = 0; (addr = cdi_list_get(uhci_active_transfers, i)) != NULL;
+            i++)
+        {
+            td = addr->virt;
+            if (td->active) {
+                continue;
+            }
+            addr->error = CDI_USB_NO_ERROR;
+            cdi_list_remove(uhci_active_transfers, i--);
+            if (td->stalled_err) {
+                d0printf("ENDPOINT STALLED\n");
+                addr->error |= CDI_USB_STALLED;
+            }
+            if (td->buf_err) {
+                d1printf("Pufferüberlauf oder Underrun\n");
+                addr->error |= CDI_USB_BUFFER_ERROR;
+            }
+            if (td->babble) {
+                d1printf("Da war ein Gerät wohl sehr gesprächig: Babble.\n");
+                addr->error |= CDI_USB_BABBLE;
+            }
+            if (td->nak) {
+                d1printf("NAK empfangen\n");
+                addr->error |= CDI_USB_NAK;
+            }
+            if (td->crc_time_err) {
+                d1printf("CRC-Fehler oder Timeout\n");
+                addr->error |= CDI_USB_CRC | CDI_USB_TIMEOUT;
+            }
+            if (td->bitstuff_err) {
+                d1printf("Bitstufffehler\n");
+                addr->error |= CDI_USB_BITSTUFF;
+            }
+            //TODO: free(td) - dazu wäre eine CDI-Funktion nützlich
+        }
+    }
+    cdi_outw(uhci->pbase + UHCI_USBSTS, status);
+}
diff --git a/src/modules/cdi/usb-msd/Makefile.all b/src/modules/cdi/usb-msd/Makefile.all
new file mode 100644
index 0000000..e027b50
--- /dev/null
+++ b/src/modules/cdi/usb-msd/Makefile.all
@@ -0,0 +1,2 @@
+shopt -s extglob
+source $LOST_BUILDMK_ROOT/config.sh
diff --git a/src/modules/cdi/usb-msd/include/msd.h b/src/modules/cdi/usb-msd/include/msd.h
new file mode 100644
index 0000000..bb6cf51
--- /dev/null
+++ b/src/modules/cdi/usb-msd/include/msd.h
@@ -0,0 +1,121 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#ifndef MSD_H
+#define MSD_H
+
+#include <stdint.h>
+#include <stdio.h>
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define d1printf(...) printf("[usb-msd] " __VA_ARGS__)
+#define _d1printf(...) printf(__VA_ARGS__)
+#else
+#define d1printf(...)
+#define _d1printf(...)
+#endif
+
+#define d0printf(...) printf("[usb-msd] " __VA_ARGS__)
+#define _d0printf(...) printf(__VA_ARGS__)
+
+//"USBC"
+#define CBW_SIGNATURE 0x43425355
+struct command_block_wrapper
+{
+    uint32_t cbw_signature;
+    uint32_t cbw_tag;
+    uint32_t cbw_data_transfer_length;
+    uint8_t cbw_flags;
+    uint8_t cbw_lun;
+    uint8_t cbw_cb_length;
+    uint8_t cbw_cb[16];
+} __attribute__((packed));
+
+//"USBS"
+#define CSW_SIGNATURE 0x53425355
+struct command_status_wrapper
+{
+    uint32_t csw_signature;
+    uint32_t csw_tag;
+    uint32_t csw_data_residue;
+    uint8_t csw_status;
+} __attribute__((packed));
+
+struct msc_sense
+{
+    unsigned error : 7;
+    unsigned valid : 1;
+    uint8_t rsvd0;
+    unsigned sense_key : 4;
+    unsigned rsvd1 : 4;
+    uint32_t information;
+    uint8_t additional_length;
+    uint32_t rsvd2;
+    uint8_t additional_code;
+    uint8_t additional_code_qualifier;
+    uint32_t rsvd;
+} __attribute__((packed));
+
+struct msd_capacity
+{
+    uint32_t last_lba;
+    uint32_t block_length;
+} __attribute__((packed));
+
+struct cdi_msd
+{
+    struct cdi_storage_device cdi_device;
+    struct cdi_usb_device *usb_device;
+    struct cdi_usb_pipe *bulk_in;
+    struct cdi_usb_pipe *bulk_out;
+    uint32_t offset; //Für Partitionen
+};
+
+struct part_table_entry
+{
+    uint8_t active;
+    uint8_t begin_chs[3];
+    uint8_t type;
+    uint8_t end_chs[3];
+    uint32_t start;
+    uint32_t size;
+} __attribute__((packed));
+
+
+#define MSC_CMD_REZERO   0x01
+#define MSC_CMD_SENSE    0x03
+#define MSC_CMD_CAPACITY 0x25
+#define MSC_CMD_READ10   0x28
+#define MSC_CMD_WRITE10  0x2A
+#define MSC_CMD_SEEK     0x2B
+#define MSC_CMD_READ12   0xA8
+#define MSC_CMD_WRITE12  0xAA
+
+int check_msd(struct cdi_usb_device *device);
+int msd_read_blocks(struct cdi_storage_device *device, uint64_t start,
+    uint64_t count, void *buffer);
+int msd_write_blocks(struct cdi_storage_device *device, uint64_t start,
+    uint64_t count, void *buffer);
+
+#endif
diff --git a/src/modules/cdi/usb-msd/main.c b/src/modules/cdi/usb-msd/main.c
new file mode 100644
index 0000000..e414e80
--- /dev/null
+++ b/src/modules/cdi/usb-msd/main.c
@@ -0,0 +1,74 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#include <cdi/misc.h>
+#include <cdi/storage.h>
+#include <cdi/usb.h>
+
+#include "msd.h"
+
+#define DRIVER_NAME "usb-msd"
+
+int init_usbmsd(void);
+
+struct cdi_storage_driver msc_driver = {
+    .drv = {
+        .type          = CDI_STORAGE,
+        .name          = DRIVER_NAME,
+        .devices       = NULL,
+        .init_device   = NULL,
+        .remove_device = NULL,
+#ifdef CDI_DRIVER
+        .init          = &init_usbmsd,
+#endif
+        .destroy       = NULL
+    },
+    .read_blocks       = &msd_read_blocks,
+    .write_blocks      = &msd_write_blocks
+};
+
+#ifdef CDI_DRIVER
+CDI_DRIVER(DRIVER_NAME, msc_driver)
+#endif
+
+static struct cdi_usb_device_pattern msd_pattern = {
+    .vendor_id   = -1,
+    .device_id   = -1,
+    .class_id    = 8,
+    .subclass_id = -1,
+    .protocol_id = -1,
+
+    .take_usb_device = &check_msd
+};
+
+int init_usbmsd()
+{
+    cdi_storage_driver_init(&msc_driver);
+
+#ifndef CDI_DRIVER
+    cdi_storage_driver_register(&msc_driver);
+#endif
+
+    cdi_usb_register_device_pattern(&msd_pattern);
+
+    return 0;
+}
diff --git a/src/modules/cdi/usb-msd/msd.c b/src/modules/cdi/usb-msd/msd.c
new file mode 100644
index 0000000..a53d41f
--- /dev/null
+++ b/src/modules/cdi/usb-msd/msd.c
@@ -0,0 +1,555 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cdi/misc.h>
+#include <cdi/storage.h>
+#include <cdi/usb.h>
+#include <cdi/usb-hcd.h>
+
+#include "msd.h"
+
+//TODO: CDI-Funktion wäre hier sicher nützlich...
+#define CPU_IS_LITTLE_ENDIAN
+
+#define change_endianess_32(_) ((((_) & \
+                                  0xFF000000) >> \
+                                 24) | \
+                                (((_) & \
+                                  0xFF0000) >> \
+                                 8) | \
+                                (((_) & 0xFF00) << 8) | (((_) & 0xFF) << 24))
+#ifdef CPU_IS_LITTLE_ENDIAN
+#define CPU2BE(_) change_endianess_32(_)
+#define CPU2LE(_) (_)
+#define BE2CPU(_) change_endianess_32(_)
+#define LE2CPU(_) (_)
+#else
+#define CPU2BE(_) (_)
+#define CPU2LE(_) change_endianess_32(_)
+#define BE2CPU(_) (_)
+#define LE2CPU(_) change_endianess_32(_)
+#endif
+
+extern struct cdi_storage_driver msc_driver;
+static uint32_t cbw_tag = 1;
+static volatile int i_am_locked = 0;
+
+static int msd_cdi_read(struct cdi_storage_device *strgdev, uint64_t start,
+    uint64_t count, void *buffer);
+static int msd_cdi_write(struct cdi_storage_device *strgdev, uint64_t start,
+    uint64_t count, void *buffer);
+static void get_partitions(struct cdi_storage_device *cdistrg);
+
+int msd_read_blocks(struct cdi_storage_device *device, uint64_t start,
+    uint64_t count, void *buffer)
+{
+    return msd_cdi_read(device, start, count, buffer);
+}
+
+int msd_write_blocks(struct cdi_storage_device *device, uint64_t start,
+    uint64_t count, void *buffer)
+{
+    return msd_cdi_write(device, start, count, buffer);
+}
+
+static int msd_get_capacity(struct cdi_usb_device *usbdev,
+    uint32_t *block_size, uint32_t *block_count);
+
+int check_msd(struct cdi_usb_device *device)
+{
+    struct cdi_storage_device *strgdev;
+    struct cdi_usb_endpoint *ep_desc;
+    struct cdi_msd *cdimsd;
+    struct cdi_usb_hcd *hcd;
+    void *address;
+    int i;
+    uint32_t bs, bc;
+    uint64_t size;
+    static int msdnum = 0;
+
+    //Nur Bulk-Only
+    if (device->protocol_id != 0x50) {
+        return 0;
+    }
+
+    d0printf("MSD detected.\n");
+
+    cdimsd = malloc(sizeof(struct cdi_msd));
+    if (cdimsd == NULL) {
+        return 0;
+    }
+    cdimsd->usb_device = device;
+    cdimsd->offset = 0;
+    strgdev = (struct cdi_storage_device *)cdimsd;
+    strgdev->dev.type = CDI_STORAGE;
+    strgdev->dev.name = malloc(10);
+    if (strgdev->dev.name == NULL) {
+        free(strgdev);
+        return 0;
+    }
+    sprintf((char *)strgdev->dev.name, "usb-msd%i", msdnum++);
+    strgdev->dev.driver = (struct cdi_driver *)&msc_driver;
+    device->driver_data = cdimsd;
+    cdimsd->bulk_in = malloc(sizeof(*cdimsd->bulk_in));
+    cdimsd->bulk_in->device = device;
+    cdimsd->bulk_in->endpoint = NULL;
+    cdimsd->bulk_in->data_toggle = 0;
+    cdimsd->bulk_out = malloc(sizeof(*cdimsd->bulk_out));
+    cdimsd->bulk_out->device = device;
+    cdimsd->bulk_out->endpoint = NULL;
+    cdimsd->bulk_out->data_toggle = 0;
+    address = (void *)((uintptr_t)device->interface_desc +
+        sizeof(struct cdi_usb_interface));
+    for (i = 0; i < device->interface_desc->num_endpoints; i++) {
+        ep_desc = address;
+        if ((ep_desc->endpoint_address & 0x80) &&
+            (ep_desc->attributes == 0x02) &&
+            (cdimsd->bulk_in->endpoint == NULL))
+        {
+            //BULK-IN
+            cdimsd->bulk_in->endpoint = ep_desc;
+        }
+        else if (!(ep_desc->endpoint_address & 0x80) &&
+            (ep_desc->attributes == 0x02) &&
+            (cdimsd->bulk_out->endpoint == NULL))
+        {
+            //BULK-OUT
+            cdimsd->bulk_out->endpoint = ep_desc;
+        }
+        address = (void *)((uintptr_t)address +
+            sizeof(struct cdi_usb_endpoint));
+    }
+    if ((cdimsd->bulk_in->endpoint == NULL) ||
+        (cdimsd->bulk_out->endpoint == NULL))
+    {
+        d0printf("Not enough endpoints found.\n");
+        return 0;
+    }
+    hcd = (struct cdi_usb_hcd *)device->hc->dev.driver;
+    hcd->add_pipe(cdimsd->bulk_in);
+    hcd->add_pipe(cdimsd->bulk_out);
+    if (!msd_get_capacity(device, &bs, &bc)) {
+        strgdev->block_size = 0;
+        strgdev->block_count = 0;
+        d1printf("Wasn't able to determine size of %s.\n", strgdev->dev.name);
+    } else {
+        strgdev->block_size = bs;
+        strgdev->block_count = bc;
+        size = bs;
+        size *= bc;
+        d1printf("%s: %i * %i B (about %d MB).\n", strgdev->dev.name, bc, bs,
+            (int)(size >> 20));
+    }
+    cdi_storage_device_init(strgdev);
+    cdi_list_push(msc_driver.drv.devices, strgdev);
+
+    get_partitions(strgdev);
+
+    return 1;
+}
+
+static int write_cmd(struct cdi_usb_device *usbdev, void *src)
+{
+    struct cdi_msd *cdimsd = usbdev->driver_data;
+    struct cdi_usb_packet cmd_packet = {
+        .pipe         = cdimsd->bulk_out,
+        .type         = CDI_USB_PACKET_OUT,
+        .data         = src,
+        .length       = 0x1F,
+        .use_toggle   = TOGGLE_UNSPECIFIC
+    };
+
+    return usbdev->drv->send_packets(&cmd_packet, 1);
+}
+
+/**
+ * Liest den Status von einem MSD
+ *
+ * @param usbdev Das bewusste Gerät
+ * @param expected_tag Das erwartete Tag
+ *
+ * @return Wenn der Status OK ist USB_NO_ERROR, sonst entsprechender Fehler
+ */
+
+static int read_status(struct cdi_usb_device *usbdev, uint32_t expected_tag)
+{
+    struct cdi_msd *msc = usbdev->driver_data;
+    struct command_status_wrapper _csw;
+    struct command_status_wrapper *csw = &_csw;
+    cdi_usb_status_t error;
+
+    struct cdi_usb_packet status_packet = {
+        .pipe         = msc->bulk_in,
+        .type         = CDI_USB_PACKET_IN,
+        .data         = csw,
+        .length       = 0x0D,
+        .use_toggle   = TOGGLE_UNSPECIFIC
+    };
+
+    error = usbdev->drv->send_packets(&status_packet, 1);
+    if (error != CDI_USB_NO_ERROR) {
+        return error;
+    }
+    if ((csw->csw_signature != CSW_SIGNATURE) ||
+        (csw->csw_tag != expected_tag) || csw->csw_status)
+    {
+        d1printf("0x%08X %i==%i 0x%08X\n", csw->csw_signature, csw->csw_tag,
+            expected_tag, csw->csw_status);
+        return CDI_USB_TRIVIAL_ERROR;
+    }
+
+    return CDI_USB_NO_ERROR;
+}
+
+static int msd_get_capacity(struct cdi_usb_device *usbdev,
+    uint32_t *block_size, uint32_t *block_count)
+{
+    struct cdi_msd *msc;
+    struct command_block_wrapper _cbw;
+    struct command_block_wrapper *cbw = &_cbw;
+    struct msd_capacity _cap;
+    struct msd_capacity *cap = &_cap;
+    uint32_t expected_tag;
+
+    if ((usbdev == NULL) || (block_size == NULL) || (block_count == NULL)) {
+        return 0;
+    }
+
+    msc = usbdev->driver_data;
+    memset(cbw, 0, 0x1F);
+    cbw->cbw_signature = CBW_SIGNATURE;
+    cbw->cbw_tag = (expected_tag = cbw_tag++);
+    cbw->cbw_data_transfer_length = sizeof(struct msd_capacity);
+    cbw->cbw_flags = 0x80; //IN
+    cbw->cbw_lun = 0; //Was weiß ich, wie viele LUNs datt Dingens hat?
+    cbw->cbw_cb_length = 12;
+    cbw->cbw_cb[0] = MSC_CMD_CAPACITY;
+    cbw->cbw_cb[1] = 0; //LUN: 0
+
+    if (write_cmd(usbdev, cbw) != CDI_USB_NO_ERROR) {
+        return 0;
+    }
+
+    struct cdi_usb_packet in_packet = {
+        .pipe         = msc->bulk_in,
+        .type         = CDI_USB_PACKET_IN,
+        .data         = cap,
+        .length       = sizeof(*cap),
+        .use_toggle   = TOGGLE_UNSPECIFIC
+    };
+
+    if (usbdev->drv->send_packets(&in_packet, 1) != CDI_USB_NO_ERROR) {
+        return 0;
+    }
+
+    if (read_status(usbdev, expected_tag) != CDI_USB_NO_ERROR) {
+        return 0;
+    }
+
+    *block_size = BE2CPU(cap->block_length);
+    *block_count = BE2CPU(cap->last_lba) + 1;
+
+    return 1;
+}
+
+#ifdef WAIT_FOR_MSD_READY
+static int msd_ready(struct cdi_usb_device *usbdev)
+{
+    struct msclass_data *msc;
+    struct command_block_wrapper _cbw;
+    struct command_block_wrapper *cbw = &_cbw;
+    uint32_t expected_tag;
+
+    msc = (struct msclass_data *)usbdev->driver_data;
+    memset(cbw, 0, 0x1F);
+    cbw->cbw_signature = CBW_SIGNATURE;
+    cbw->cbw_tag = (expected_tag = cbw_tag++);
+    cbw->cbw_data_transfer_length = 0;
+    cbw->cbw_flags = 0x80; //IN
+    cbw->cbw_lun = 0; //Was weiß ich, wie viele LUNs datt Dingens hat?
+    cbw->cbw_cb_length = 12; //Alles null, also "Test unit ready"
+
+    if (write_cmd(usbdev, cbw) != USB_NO_ERROR) {
+        return 0;
+    }
+
+    if (read_status(usbdev, expected_tag) != USB_NO_ERROR) {
+        return 0;
+    }
+
+    return 1;
+}
+#endif
+
+static inline int _tsl(volatile int *variable)
+{
+    int rval;
+    rval = *variable;
+    *variable = 1;
+    return rval;
+}
+
+#define MAX_ACCESS_BLOCKS 32
+
+static uint32_t msd_read(struct cdi_usb_device *usbdev, uint32_t lba,
+    uint16_t sectors, void *buffer, size_t length);
+
+static int msd_cdi_read(struct cdi_storage_device *strgdev, uint64_t start,
+    uint64_t count, void *buffer)
+{
+    int bs = strgdev->block_size, error;
+#ifdef WAIT_FOR_MSD_READY
+    int i;
+#endif
+    struct cdi_usb_device *usbdev = ((struct cdi_msd *)strgdev)->usb_device;
+    int j, bbs;
+
+    while (_tsl(&i_am_locked));
+
+    d1printf("read(%i, %i)\n", (int)start, (int)count);
+    start += ((struct cdi_msd *)strgdev)->offset;
+
+    if (!count) {
+        d1printf("Empty read request.\n");
+        i_am_locked = 0;
+        return 0;
+    }
+    for (j = 0; j < (int)count; j += MAX_ACCESS_BLOCKS) {
+#ifdef WAIT_FOR_MSD_READY
+        for (i = 0; !msd_ready(usbdev) && (i < 10); i++) {
+            cdi_sleep_ms(20);
+        }
+#endif
+        bbs = (count - j > MAX_ACCESS_BLOCKS) ? MAX_ACCESS_BLOCKS : count - j;
+        error = msd_read(usbdev, start + j, bbs,
+                         (void *)((uintptr_t)buffer + j * bs), bbs * bs);
+        if (error != CDI_USB_NO_ERROR) {
+            d0printf("Read error 0x%X at block %lld.\n", error, start + j);
+            i_am_locked = 0;
+            return -1;
+        }
+    }
+    i_am_locked = 0;
+    return 0;
+}
+
+static uint32_t msd_read(struct cdi_usb_device *usbdev, uint32_t lba,
+    uint16_t sectors, void *buffer, size_t length)
+{
+    struct cdi_msd *msc;
+    struct command_block_wrapper _cbw;
+    struct command_block_wrapper *cbw = &_cbw;
+    uint32_t expected_tag;
+    int error;
+
+    if ((buffer == NULL) || !length) {
+        return CDI_USB_TRIVIAL_ERROR;
+    }
+    msc = usbdev->driver_data;
+    memset(cbw, 0, 0x1F);
+    cbw->cbw_signature = CBW_SIGNATURE;
+    cbw->cbw_tag = (expected_tag = cbw_tag++);
+    cbw->cbw_data_transfer_length = length;
+    cbw->cbw_flags = 0x80; //IN
+    cbw->cbw_lun = 0; //Was weiß ich, wie viele LUNs datt Dingens hat?
+    cbw->cbw_cb_length = 12;
+    cbw->cbw_cb[0] = MSC_CMD_READ10;
+    cbw->cbw_cb[1] = 0; //LUN: 0
+    cbw->cbw_cb[2] = (lba & 0xFF000000) >> 24;
+    cbw->cbw_cb[3] = (lba & 0x00FF0000) >> 16;
+    cbw->cbw_cb[4] = (lba & 0x0000FF00) >> 8;
+    cbw->cbw_cb[5] = lba & 0x000000FF;
+    cbw->cbw_cb[7] = (sectors & 0x0000FF00) >> 8;
+    cbw->cbw_cb[8] = sectors & 0x000000FF;
+
+    error = write_cmd(usbdev, cbw);
+    if (error != CDI_USB_NO_ERROR) {
+        return error;
+    }
+
+    struct cdi_usb_packet in_packet = {
+        .pipe         = msc->bulk_in,
+        .type         = CDI_USB_PACKET_IN,
+        .data         = buffer,
+        .length       = length,
+        .use_toggle   = TOGGLE_UNSPECIFIC
+    };
+
+    error = usbdev->drv->send_packets(&in_packet, 1);
+    if (error != CDI_USB_NO_ERROR) {
+        return error;
+    }
+
+    error = read_status(usbdev, expected_tag);
+    if (error != CDI_USB_NO_ERROR) {
+        return error;
+    }
+
+    return CDI_USB_NO_ERROR;
+}
+
+static uint32_t msd_write(struct cdi_usb_device *usbdev, uint32_t lba,
+    uint16_t sectors, void *buffer, size_t length);
+
+static int msd_cdi_write(struct cdi_storage_device *strgdev, uint64_t start,
+    uint64_t count, void *buffer)
+{
+    int bs = strgdev->block_size, error;
+#ifdef WAIT_FOR_MSD_READY
+    int i;
+#endif
+    struct cdi_usb_device *usbdev = ((struct cdi_msd *)strgdev)->usb_device;
+    int j, bbs;
+
+    while (_tsl(&i_am_locked));
+
+    d1printf("write(%i, %i)\n", (int)start, (int)count);
+    start += ((struct cdi_msd *)strgdev)->offset;
+
+    if (!count) {
+        d1printf("Empty write request.\n");
+        i_am_locked = 0;
+        return 0;
+    }
+    for (j = 0; j < (int)count; j += MAX_ACCESS_BLOCKS) {
+#ifdef WAIT_FOR_MSD_READY
+        for (i = 0; !msd_ready(usbdev) && (i < 10); i++)
+            cdi_sleep_ms(20);
+#endif
+        bbs = (count - j > MAX_ACCESS_BLOCKS) ? MAX_ACCESS_BLOCKS : count - j;
+        error = msd_write(usbdev, start + j, bbs,
+            (void *)((uintptr_t)buffer + j * bs), bbs * bs);
+        if (error != CDI_USB_NO_ERROR) {
+            d0printf("Write error 0x%X at block %lld.\n", error, start + j);
+            i_am_locked = 0;
+            return -1;
+        }
+    }
+    i_am_locked = 0;
+    return 0;
+}
+
+static uint32_t msd_write(struct cdi_usb_device *usbdev, uint32_t lba,
+    uint16_t sectors, void *buffer, size_t length)
+{
+    struct cdi_msd *msc;
+    struct command_block_wrapper _cbw;
+    struct command_block_wrapper* cbw = &_cbw;
+    uint32_t expected_tag;
+    int error;
+
+    if ((buffer == NULL) || !length) {
+        return CDI_USB_TRIVIAL_ERROR;
+    }
+    msc = usbdev->driver_data;
+    memset(cbw, 0, 0x1F);
+    cbw->cbw_signature = CBW_SIGNATURE;
+    cbw->cbw_tag = (expected_tag = cbw_tag++);
+    cbw->cbw_data_transfer_length = length;
+    cbw->cbw_flags = 0x00; //OUT
+    cbw->cbw_lun = 0; //Was weiß ich, wie viele LUNs datt Dingens hat?
+    cbw->cbw_cb_length = 12;
+    cbw->cbw_cb[0] = MSC_CMD_WRITE10;
+    cbw->cbw_cb[1] = 0; //LUN: 0
+    cbw->cbw_cb[2] = (lba & 0xFF000000) >> 24;
+    cbw->cbw_cb[3] = (lba & 0x00FF0000) >> 16;
+    cbw->cbw_cb[4] = (lba & 0x0000FF00) >> 8;
+    cbw->cbw_cb[5] = lba & 0x000000FF;
+    cbw->cbw_cb[7] = (sectors & 0x0000FF00) >> 8;
+    cbw->cbw_cb[8] = sectors & 0x000000FF;
+
+    error = write_cmd(usbdev, cbw);
+    if (error != CDI_USB_NO_ERROR) {
+        return error;
+    }
+
+    struct cdi_usb_packet out_packet = {
+        .pipe         = msc->bulk_out,
+        .type         = CDI_USB_PACKET_OUT,
+        .data         = buffer,
+        .length       = length,
+        .use_toggle   = TOGGLE_UNSPECIFIC
+    };
+
+    error = usbdev->drv->send_packets(&out_packet, 1);
+    if (error != CDI_USB_NO_ERROR) {
+        return error;
+    }
+
+    error = read_status(usbdev, expected_tag);
+    if (error != CDI_USB_NO_ERROR) {
+        return error;
+    }
+
+    return CDI_USB_NO_ERROR;
+}
+
+static void get_partitions(struct cdi_storage_device *cdistrg)
+{
+    void *mbr;
+    struct part_table_entry *partition;
+    struct cdi_msd *cdimsd, *base_cdimsd = (struct cdi_msd *)cdistrg;
+    int i, j = 0;
+
+    mbr = malloc(512);
+    if (msd_cdi_read(cdistrg, 0, 1, mbr) != CDI_USB_NO_ERROR)
+    {
+        d1printf("Couldn't read MBR.\n");
+        return;
+    }
+    if (((uint16_t *)mbr)[255] != 0xAA55)
+        return;
+    partition = (void *)((uintptr_t)mbr + 0x1BE);
+    d1printf("Partitions on %s:", cdistrg->dev.name);
+    for (i = 0; i < 4; i++)
+    {
+        if (partition[i].type && partition[i].size &&
+            (partition[i].start + partition[i].size <= cdistrg->block_count))
+        {
+            cdimsd = calloc(1, sizeof(struct cdi_msd));
+            if (cdimsd == NULL) {
+                break;
+            }
+            cdimsd->offset = partition[i].start;
+            cdimsd->usb_device = base_cdimsd->usb_device;
+            cdimsd->cdi_device.dev.type = CDI_STORAGE;
+            cdimsd->cdi_device.dev.driver = (struct cdi_driver *)&msc_driver;
+            cdimsd->cdi_device.dev.name = malloc(14);
+            if (cdimsd->cdi_device.dev.name == NULL) {
+                free(cdimsd);
+                break;
+            }
+            sprintf((char *)cdimsd->cdi_device.dev.name, "%sp%i",
+                     cdistrg->dev.name, j++);
+            cdimsd->cdi_device.block_size = base_cdimsd->cdi_device.block_size;
+            cdimsd->cdi_device.block_count = partition[i].size;
+            _d1printf(" %s", cdimsd->cdi_device.dev.name);
+            cdi_storage_device_init((struct cdi_storage_device *)cdimsd);
+            cdi_list_push(msc_driver.drv.devices, cdimsd);
+        }
+    }
+    _d1printf("\n");
+}
diff --git a/src/modules/cdi/usb11/Makefile.all b/src/modules/cdi/usb11/Makefile.all
new file mode 100644
index 0000000..e027b50
--- /dev/null
+++ b/src/modules/cdi/usb11/Makefile.all
@@ -0,0 +1,2 @@
+shopt -s extglob
+source $LOST_BUILDMK_ROOT/config.sh
diff --git a/src/modules/cdi/usb11/control.c b/src/modules/cdi/usb11/control.c
new file mode 100644
index 0000000..170341d
--- /dev/null
+++ b/src/modules/cdi/usb11/control.c
@@ -0,0 +1,252 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#include <stdlib.h>
+
+#include <cdi/lists.h>
+#include <cdi/misc.h>
+#include <cdi/usb.h>
+
+#include "usb11.h"
+#include "usb-structs.h"
+#include "transfer.h"
+
+static int usb_dev_ids = 1;
+
+static void enumerate_hub(struct cdi_usb_device *usbdev);
+
+static int usb11_real_enumerate(struct cdi_usb_device *device)
+{
+    struct endpoint_desc *ep0;
+    struct device_desc *dev_desc;
+    struct cdi_usb_hcd *hcd;
+    int id;
+    char *name;
+    void *position;
+    struct config_desc *conf_desc;
+    struct interface_desc *if_desc, *best_if;
+
+    hcd = (struct cdi_usb_hcd *)device->hc->dev.driver;
+
+    //EP0 initialisieren
+    device->ep0 = malloc(sizeof(*device->ep0));
+    device->ep0->endpoint = malloc(sizeof(struct endpoint_desc));
+    ep0 = (struct endpoint_desc *)device->ep0->endpoint;
+    ep0->length = sizeof(struct endpoint_desc);
+    ep0->descriptor_type = DESC_ENDPOINT;
+    ep0->endpoint_address = 0;
+    ep0->attributes = 0;
+    ep0->max_packet_size = 8;
+    ep0->interval = 0;
+    device->ep0->device = device;
+    device->ep0->data_toggle = 0;
+
+    //Zurücksetzen
+    device->reset(device);
+
+    //Pipe erzeugen
+    hcd->add_pipe(device->ep0);
+
+    //Erste acht Bytes des Device-Descriptors abrufen und die maximale
+    //Paketgröße von EP0 feststellen
+    dev_desc = usb11_do_control(device, DEV_TO_HOST, NULL, 8, STD_REQUEST,
+        REC_DEVICE, GET_DESCRIPTOR, DESC_DEVICE << 8, 0);
+    if (dev_desc == NULL) {
+        return 0;
+    }
+    ep0->max_packet_size = dev_desc->max_packet_size0;
+
+    //Nochmals zurücksetzen
+    device->reset(device);
+
+    //USB-Adresse zuweisen
+    usb11_do_control(device, HOST_TO_DEV | NO_DATA, NULL, 0, STD_REQUEST,
+        REC_DEVICE, SET_ADDRESS, (id = usb_dev_ids++), 0);
+    device->id = id;
+    if (usb_dev_ids >= 128) {
+        d0printf("Warning: USB device ID overflow.\n");
+        usb_dev_ids = 1;
+    }
+
+    //So, jetzt haben wir eine Adresse, da gibts auch eine neue Pipe
+    hcd->add_pipe(device->ep0);
+
+    //Den ganzen Device-Descriptor einlesen
+    dev_desc = usb11_do_control(device, DEV_TO_HOST, NULL, sizeof(*dev_desc),
+        STD_REQUEST, REC_DEVICE, GET_DESCRIPTOR, DESC_DEVICE << 8, 0);
+    device->device_desc = dev_desc;
+    device->vendor_id = dev_desc->vendor_id;
+    device->device_id = dev_desc->device_id;
+
+    if (dev_desc->iManufacturer) {
+        name = usb11_do_control(device, DEV_TO_HOST, NULL, 64, STD_REQUEST,
+            REC_DEVICE, GET_DESCRIPTOR,
+            (DESC_STRING << 8) | dev_desc->iManufacturer, 0);
+        if (name == NULL) {
+            return 0;
+        }
+        d1printf(" -> Manufacturer: ");
+        for (int i = 2; i < name[0]; i += 2) {
+            _d1printf("%c", name[i]);
+        }
+        _d1printf("\n");
+    }
+    if (dev_desc->iProduct) {
+        name = usb11_do_control(device, DEV_TO_HOST, NULL, 64, STD_REQUEST,
+            REC_DEVICE, GET_DESCRIPTOR,
+            (DESC_STRING << 8) | dev_desc->iProduct, 0);
+        if (name == NULL) {
+            return 0;
+        }
+        d1printf(" -> Product: ");
+        for (int i = 2; i < name[0]; i += 2) {
+            _d1printf("%c", name[i]);
+        }
+        _d1printf("\n");
+    }
+    //TODO: Man kann doch nicht immer den ersten nehmen...
+    conf_desc = usb11_do_control(device, DEV_TO_HOST, NULL,
+        sizeof(struct config_desc), STD_REQUEST, REC_DEVICE, GET_DESCRIPTOR,
+        DESC_CONFIGURATION << 8, 0);
+    if (conf_desc == NULL) {
+        return 0;
+    }
+    conf_desc = usb11_do_control(device, DEV_TO_HOST, NULL,
+        conf_desc->total_length, STD_REQUEST, REC_DEVICE, GET_DESCRIPTOR,
+        DESC_CONFIGURATION << 8, 0);
+    if (conf_desc == NULL) {
+        return 0;
+    }
+    device->config_desc = conf_desc;
+    usb11_do_control(device, HOST_TO_DEV, NULL, 0, STD_REQUEST, REC_DEVICE,
+        SET_CONFIGURATION, conf_desc->config_value, 0);
+    if (conf_desc->iConfiguration) {
+        name = usb11_do_control(device, DEV_TO_HOST, NULL, 64, STD_REQUEST,
+            REC_DEVICE, GET_DESCRIPTOR,
+            (DESC_STRING << 8) | conf_desc->iConfiguration, 0);
+        if (name == NULL) {
+            return 0;
+        }
+        d1printf("Using configuration ");
+        for (int i = 2; i < name[0]; i += 2) {
+            _d1printf("%c", name[i]);
+        }
+        _d1printf(".\n");
+    }
+    position = conf_desc;
+    position = (void *)((uintptr_t)position + sizeof(struct config_desc));
+    best_if = position; //Standard-IF
+    for (int i = 0; i < conf_desc->num_interfaces; i++) {
+        if_desc = position;
+        //TODO MSD ist zwar hübsch. Aber andere auch ;-)
+        if (if_desc->interface_class == 8) {
+            best_if = if_desc;
+            break;
+        }
+        position = (void *)((uintptr_t)position +
+            sizeof(struct interface_desc) +
+            if_desc->num_endpoints * sizeof(struct endpoint_desc));
+    }
+    usb11_do_control(device, HOST_TO_DEV, NULL, 0, STD_REQUEST, REC_DEVICE,
+        SET_INTERFACE, best_if->interface_number, 0);
+    device->interface_desc = (void *)best_if;
+    if (best_if->iInterface) {
+        name = usb11_do_control(device, DEV_TO_HOST, NULL, 64, STD_REQUEST,
+            REC_DEVICE, GET_DESCRIPTOR,
+            (DESC_STRING << 8) | best_if->iInterface, 0);
+        if (name == NULL) {
+            return 0;
+        }
+        d1printf("Using interface ");
+        for (int i = 2; i < name[0]; i += 2) {
+            _d1printf("%c", name[i]);
+        }
+        _d1printf(".\n");
+    }
+    d1printf("Configuration: %i:%i (%i)\n", conf_desc->config_value,
+        best_if->interface_number, best_if->interface_class);
+
+    if (!dev_desc->class_id) { //Composite Device
+        device->class_id = best_if->interface_class;
+        device->subclass_id = best_if->interface_subclass;
+        device->protocol_id = best_if->interface_protocol;
+    } else {
+        device->class_id = dev_desc->class_id;
+        device->subclass_id = dev_desc->subclass_id;
+        device->protocol_id = dev_desc->protocol_id;
+    }
+
+    if (best_if->interface_class == USBDC_HUB) {
+        enumerate_hub(device);
+    }
+
+    return 1;
+}
+
+void usb11_enumerate(struct cdi_usb_device *device)
+{
+    if (!usb11_real_enumerate(device)) {
+        free(device->ep0->endpoint);
+        free(device->ep0);
+    }
+}
+
+static void reset_hub_device(struct cdi_usb_device *usbdev)
+{
+    usb11_do_control(usbdev->hub, HOST_TO_DEV, NULL, 0, CLS_REQUEST, REC_OTHER,
+        SET_FEATURE, PORTF_RESET, usbdev->port + 1);
+    cdi_sleep_ms(20);
+}
+
+static void enumerate_hub(struct cdi_usb_device *usbdev)
+{
+    struct hub_desc *hub_desc;
+    struct cdi_usb_device *down;
+    uint16_t *port_status;
+    int i;
+
+    //Mehr als 8 Ports sollte es nicht geben, die Größe des Deskriptors wird
+    //daher wohl nicht größer als sizeof()+16 werden
+    hub_desc = usb11_do_control(usbdev, DEV_TO_HOST, NULL,
+        sizeof(*hub_desc) + 16, CLS_REQUEST, REC_DEVICE, GET_DESCRIPTOR,
+        DESC_DEVICE << 8, 0);
+    for (i = 0; i < hub_desc->nbr_ports; i++) {
+        port_status = usb11_do_control(usbdev, DEV_TO_HOST, NULL, 4,
+            CLS_REQUEST,REC_OTHER, GET_STATUS, 0, i + 1);
+        if (!(port_status[0] & PORT_DEVICE)) {
+            continue;
+        }
+        //Strom an
+        usb11_do_control(usbdev, HOST_TO_DEV, NULL, 0, CLS_REQUEST, REC_OTHER,
+            SET_FEATURE, PORTF_POWER, i + 1);
+        cdi_sleep_ms(hub_desc->pwron2pwrgood * 2);
+        down = malloc(sizeof(struct cdi_usb_device));
+        down->hc = usbdev->hc;
+        down->hub = usbdev;
+        down->id = 0;
+        down->port = i;
+        down->speed = (port_status[0] & PORT_LOWSPEED) ?
+            CDI_USB_LOW_SPEED : CDI_USB_FULL_SPEED;
+        down->reset = &reset_hub_device;
+        cdi_usb_device_init(down);
+    }
+}
diff --git a/src/modules/cdi/usb11/include/control.h b/src/modules/cdi/usb11/include/control.h
new file mode 100644
index 0000000..97edefc
--- /dev/null
+++ b/src/modules/cdi/usb11/include/control.h
@@ -0,0 +1,31 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#ifndef CONTROL_H
+#define CONTROL_H
+
+#include <cdi/lists.h>
+#include <cdi/usb.h>
+
+void usb11_enumerate(struct cdi_usb_device *device);
+
+#endif
diff --git a/src/modules/cdi/usb11/include/transfer.h b/src/modules/cdi/usb11/include/transfer.h
new file mode 100644
index 0000000..3b0f086
--- /dev/null
+++ b/src/modules/cdi/usb11/include/transfer.h
@@ -0,0 +1,38 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#ifndef TRANSFER_H
+#define TRANSFER_H
+
+#include <stddef.h>
+
+#include <cdi/usb.h>
+
+void *usb11_do_control(struct cdi_usb_device *device, int direction,
+    void *buffer, int length, int rtype, int recipient, int request, int value,
+    int index);
+void *usb11_export_control(struct cdi_usb_device *device,
+    struct cdi_usb_control_transfer *transfer);
+cdi_usb_status_t usb11_send_packets(struct cdi_usb_packet *packets,
+    size_t num_packets);
+
+#endif
diff --git a/src/modules/cdi/usb11/include/usb-structs.h b/src/modules/cdi/usb11/include/usb-structs.h
new file mode 100644
index 0000000..427d0e5
--- /dev/null
+++ b/src/modules/cdi/usb11/include/usb-structs.h
@@ -0,0 +1,184 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#ifndef USB_STRUCTS_H
+#define USB_STRUCTS_H
+
+#include <stdint.h>
+
+
+#define NO_DATA                        0x01
+#define DEV_TO_HOST                    0x80
+#define HOST_TO_DEV                    0x00
+#define STD_REQUEST                    0x00
+#define CLS_REQUEST                    0x20
+#define VEN_REQUEST                    0x40
+#define REC_DEVICE                     0x00
+#define REC_INTERFACE                  0x01
+#define REC_ENDPOINT                   0x02
+#define REC_OTHER                      0x03
+
+#define GET_STATUS                     0
+#define CLEAR_FEATURE                  1
+#define SET_FEATURE                    3
+#define SET_ADDRESS                    5
+#define GET_DESCRIPTOR                 6
+#define SET_DESCRIPTOR                 7
+#define GET_CONFIGURATION              8
+#define SET_CONFIGURATION              9
+#define GET_INTERFACE                  10
+#define SET_INTERFACE                  11
+#define SYNC_FRAME                     12
+
+#define PORT_DEVICE                    0x0001
+#define PORT_ENABLED                   0x0002
+#define PORT_SUSPENDED                 0x0004
+#define PORT_OVERCURRENT               0x0008
+#define PORT_RESET                     0x0010
+#define PORT_POWER                     0x0100
+#define PORT_LOWSPEED                  0x0200
+#define PORT_HIGHSPEED                 0x0400
+#define PORT_TEST                      0x0800
+#define PORT_INDICATOR                 0x1000
+
+#define PORTF_CONNECTION               0
+#define PORTF_ENABLE                   1
+#define PORTF_SUSPEND                  2
+#define PORTF_OVERCURRENT              3
+#define PORTF_RESET                    4
+#define PORTF_POWER                    8
+#define PORTF_LOWSPEED                 9
+#define PORTF_HIGHSPEED                10
+#define PORTF_C_CONNECTION             16
+#define PORTF_C_ENABLE                 17
+#define PORTF_C_SUSPEND                18
+#define PORTF_C_OVERCURRENT            19
+#define PORTF_C_RESET                  20
+#define PORTF_TEST                     21
+#define PORTF_INDICATOR                22
+
+#define DESC_DEVICE                    1
+#define DESC_CONFIGURATION             2
+#define DESC_STRING                    3
+#define DESC_INTERFACE                 4
+#define DESC_ENDPOINT                  5
+#define DESC_DEVICE_QUALIFIER          6
+#define DESC_OTHER_SPEED_CONFIGURATION 7
+#define DESC_INTERFACE_POWER           8
+
+
+struct setup_packet
+{
+    uint8_t request_type;
+    uint8_t request;
+    uint16_t value;
+    uint16_t index;
+    uint16_t length;
+} __attribute__((packed));
+
+struct device_desc
+{
+    uint8_t length;
+    uint8_t descriptor_type;
+    uint16_t bcdUSB;
+    uint8_t class_id;
+    uint8_t subclass_id;
+    uint8_t protocol_id;
+    uint8_t max_packet_size0;
+    uint16_t vendor_id;
+    uint16_t device_id;
+    uint16_t bcdDevice;
+    uint8_t iManufacturer;
+    uint8_t iProduct;
+    uint8_t iSerialNumber;
+    uint8_t num_configurations;
+} __attribute__((packed));
+
+struct config_desc
+{
+    uint8_t length;
+    uint8_t descriptor_type;
+    uint16_t total_length;
+    uint8_t num_interfaces;
+    uint8_t config_value;
+    uint8_t iConfiguration;
+    uint8_t attributes;
+    uint8_t max_power;
+} __attribute__((packed));
+
+struct interface_desc
+{
+    uint8_t length;
+    uint8_t descriptor_type;
+    uint8_t interface_number;
+    uint8_t alternate_setting;
+    uint8_t num_endpoints;
+    uint8_t interface_class;
+    uint8_t interface_subclass;
+    uint8_t interface_protocol;
+    uint8_t iInterface;
+} __attribute__((packed));
+
+struct endpoint_desc
+{
+    uint8_t length;
+    uint8_t descriptor_type;
+    uint8_t endpoint_address;
+    uint8_t attributes;
+    uint16_t max_packet_size;
+    uint8_t interval;
+} __attribute__((packed));
+
+struct hub_desc
+{
+    uint8_t length;
+    uint8_t descriptor_type;
+    uint8_t nbr_ports;
+    uint16_t hub_characteristics;
+    uint8_t pwron2pwrgood;
+    uint8_t hub_contr_current;
+} __attribute__((packed));
+
+typedef enum
+{
+    USBDC_COMPOSITE = 0x00,
+    USBDC_AUDIO = 0x01,
+    USBDC_COMM_CDC = 0x02,
+    USBDC_HID = 0x03,
+    USBDC_PID = 0x05,
+    USBDC_IMAGE = 0x06,
+    USBDC_PRINTER = 0x07,
+    USBDC_MSC = 0x08,
+    USBDC_HUB = 0x09,
+    USBDC_CDC_DATA = 0x0A,
+    USBDC_CHIP = 0x0B,
+    USBDC_SECURITY = 0x0D,
+    USBDC_VIDEO = 0x0E,
+    USBDC_HEALTH = 0x0F,
+    USBDC_DIAGNOSIS = 0xDC,
+    USBDC_WIRELESS = 0xE0,
+    USBDC_MISC = 0xEF,
+    USBDC_SOFT_SPEC = 0xFE,
+    USBDC_VENDOR_SPEC = 0xFF
+} usb_class_t;
+
+#endif
diff --git a/src/modules/cdi/usb11/include/usb11.h b/src/modules/cdi/usb11/include/usb11.h
new file mode 100644
index 0000000..77634e9
--- /dev/null
+++ b/src/modules/cdi/usb11/include/usb11.h
@@ -0,0 +1,41 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#ifndef USB11_H
+#define USB11_H
+
+#include <stdio.h>
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define d1printf(...) printf("[usb 1.1] " __VA_ARGS__)
+#define _d1printf(...) printf(__VA_ARGS__)
+#else
+#define d1printf(...)
+#define _d1printf(...)
+#endif
+
+#define d0printf(...) printf("[usb 1.1] " __VA_ARGS__)
+#define _d0printf(...) printf(__VA_ARGS__)
+
+#endif
diff --git a/src/modules/cdi/usb11/main.c b/src/modules/cdi/usb11/main.c
new file mode 100644
index 0000000..5594209
--- /dev/null
+++ b/src/modules/cdi/usb11/main.c
@@ -0,0 +1,82 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#include <cdi/misc.h>
+#include <cdi/usb.h>
+
+#include "control.h"
+#include "transfer.h"
+
+#define DRIVER_NAME "USB 1.1"
+
+int init_usb11(void);
+
+static struct cdi_usb_driver driver = {
+    .drv = {
+        .type          = CDI_USB,
+        .name          = DRIVER_NAME,
+        .devices       = NULL,
+        .init_device   = NULL,
+        .remove_device = NULL,
+#ifdef CDI_DRIVER
+        .init          = &init_usb11,
+#endif
+        .destroy       = NULL
+    },
+    .speeds            = CDI_USB_LOW_SPEED | CDI_USB_FULL_SPEED,
+    .enumerate_device  = &usb11_enumerate,
+    .send_packets      = &usb11_send_packets,
+    .do_control        = &usb11_export_control
+};
+
+#ifdef CDI_DRIVER
+CDI_DRIVER(DRIVER_NAME, driver)
+#else
+extern int init_ohci(void);
+extern int init_uhci(void);
+extern int init_usbmsd(void);
+#endif
+
+#if defined CDI_STANDALONE && !defined CDI_DRIVER
+int main(void)
+#else
+int init_usb11()
+#endif
+{
+#ifndef CDI_DRIVER
+    cdi_init();
+#endif
+
+    cdi_usb_driver_init(&driver);
+
+#if defined CDI_STANDALONE && !defined CDI_DRIVER
+    init_uhci();
+    init_ohci();
+    init_usbmsd();
+
+    cdi_usb_driver_register(&driver);
+
+    cdi_run_drivers();
+#endif
+
+    return 0;
+}
diff --git a/src/modules/cdi/usb11/transfer.c b/src/modules/cdi/usb11/transfer.c
new file mode 100644
index 0000000..1ea8dff
--- /dev/null
+++ b/src/modules/cdi/usb11/transfer.c
@@ -0,0 +1,223 @@
+/*****************************************************************************
+* Copyright (c) 2009 Max Reitz                                               *
+*                                                                            *
+* Permission is hereby granted,  free of charge,  to any  person obtaining a *
+* copy of this software and associated documentation files (the "Software"), *
+* to deal in the Software without restriction,  including without limitation *
+* the rights to use,  copy, modify, merge, publish,  distribute, sublicense, *
+* and/or sell copies  of the  Software,  and to permit  persons to whom  the *
+* Software is furnished to do so, subject to the following conditions:       *
+*                                                                            *
+* The above copyright notice and this permission notice shall be included in *
+* all copies or substantial portions of the Software.                        *
+*                                                                            *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+* IMPLIED, INCLUDING  BUT NOT  LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+* FITNESS FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT.  IN NO EVENT SHALL *
+* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+* LIABILITY,  WHETHER IN AN ACTION OF CONTRACT,  TORT OR OTHERWISE,  ARISING *
+* FROM,  OUT OF  OR IN CONNECTION  WITH THE  SOFTWARE  OR THE  USE OR  OTHER *
+* DEALINGS IN THE SOFTWARE.                                                  *
+*****************************************************************************/
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <cdi/usb.h>
+
+#include "transfer.h"
+#include "usb11.h"
+#include "usb-structs.h"
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+/**
+ * Verarbeitet USB-Pakete.
+ *
+ * @param packet Die Paketliste
+ * @param num_packets Anzahl der Pakete
+ *
+ * @return Status
+ */
+
+cdi_usb_status_t usb11_send_packets(struct cdi_usb_packet *packets,
+    size_t num_packets)
+{
+    cdi_usb_status_t error = CDI_USB_NAK;
+    int i = 0, mps;
+    int num_out_packets;
+    struct cdi_usb_pipe *pipe;
+    struct cdi_usb_device *device;
+    struct cdi_usb_packet *out_packets;
+    struct endpoint_desc *ep;
+    struct cdi_usb_hcd *hcd;
+
+    if (num_packets < 1) {
+        return CDI_USB_TRIVIAL_ERROR;
+    }
+
+    // Alle Pakete muessen dieselbe Pipe benutzen
+    pipe = packets[0].pipe;
+    for (i = 1; i < (int)num_packets; i++) {
+        if (packets[i].pipe != pipe) {
+            return CDI_USB_TRIVIAL_ERROR;
+        }
+    }
+
+    device = pipe->device;
+    hcd = (struct cdi_usb_hcd *)device->hc->dev.driver;
+    ep = (struct endpoint_desc *)pipe->endpoint;
+
+    // Pruefen, wie viele Pakete wir draus machen muessen
+    mps = ep->max_packet_size;
+    num_out_packets = 0;
+    for (i = 0; i < (int)num_packets; i++) {
+        int num = (packets[i].length + mps - 1) / mps;
+        if (num > 0) {
+            num_out_packets += num;
+        } else {
+            // Pakete ohne Daten wollen auch gesendet werden
+            num_out_packets++;
+        }
+    }
+
+    // Ggf. Pakete kopieren und splitten
+    if (num_out_packets == (int)num_packets) {
+        out_packets = packets;
+    } else {
+        int j;
+        int cur = 0;
+
+        out_packets = calloc(num_out_packets, sizeof(*out_packets));
+        for (i = 0; i < (int)num_packets; i++) {
+            int num = (packets[i].length + mps - 1) / mps;
+            if (num == 0) {
+                num = 1;
+            }
+
+            for (j = 0; j < num; j++) {
+                out_packets[cur].pipe = pipe;
+                out_packets[cur].type = packets[i].type;
+                out_packets[cur].data = packets[i].data;
+                out_packets[cur].length = MIN((int)packets[i].length, mps);
+                out_packets[cur].condition = CDI_USB_NAK;
+
+                packets[i].data = (void *)((uintptr_t)packets[i].data +
+                        out_packets[cur].length);
+                packets[i].length -= out_packets[cur].length;
+                cur++;
+            }
+        }
+    }
+
+    error = hcd->send_packets(out_packets, num_out_packets);
+    if (error & CDI_USB_STALLED) {
+        d0printf("ENDPOINT 0x%02X OF DEVICE %i STALLED!\n",
+            ep->endpoint_address, device->id);
+        usb11_do_control(device, HOST_TO_DEV | NO_DATA, NULL, 0, STD_REQUEST,
+            REC_ENDPOINT, CLEAR_FEATURE, 0, ep->endpoint_address);
+    } else if (error & CDI_USB_NAK) {
+        // Nicht angenommene Pakete (FIXME: einzeln) senden
+        for (i = 0; i < num_out_packets; i++) {
+            if (!(out_packets[i].condition & CDI_USB_NAK)) {
+                continue;
+            }
+            error = CDI_USB_NAK;
+            while (error & CDI_USB_NAK) {
+                error = hcd->send_packets(&out_packets[i], 1);
+                if (error & CDI_USB_NAK) {
+                    cdi_sleep_ms(5);
+                }
+            }
+        }
+    }
+
+    if (out_packets != packets) {
+        free(out_packets);
+    }
+
+    return error;
+}
+
+void *usb11_do_control(struct cdi_usb_device *device, int direction,
+    void *buffer, int length, int rtype, int recipient, int request, int value,
+    int index)
+{
+    int no_data, alloced_here = 0;
+    cdi_usb_status_t rval;
+    struct setup_packet _setup;
+    struct setup_packet *setup = &_setup;
+
+    no_data = direction & NO_DATA;
+    direction &= 0x80;
+
+    setup->request_type = direction | (rtype & 0x60) | (recipient & 0x1F);
+    setup->request = request;
+    setup->value = value;
+    setup->index = index;
+    setup->length = length;
+
+    struct cdi_usb_packet setup_packet = {
+        .pipe         = device->ep0,
+        .type         = CDI_USB_PACKET_SETUP,
+        .data         = setup,
+        .length       = sizeof(*setup),
+        .use_toggle   = TOGGLE_UNSPECIFIC
+    };
+
+    if (usb11_send_packets(&setup_packet, 1)) {
+        return NULL;
+    }
+
+    if (no_data) {
+        rval = CDI_USB_NO_ERROR;
+        buffer = (void *)0xFFFFFFFF; //Kein Fehler, aber auch keine Daten
+    } else {
+        if ((direction != HOST_TO_DEV) || (length && (buffer == NULL))) {
+            buffer = malloc(length);
+            alloced_here = 1;
+        }
+
+        struct cdi_usb_packet data_packet = {
+            .pipe         = device->ep0,
+            .type         = (direction == DEV_TO_HOST ?
+                CDI_USB_PACKET_IN : CDI_USB_PACKET_OUT),
+            .data         = buffer,
+            .length       = length,
+            .use_toggle   = TOGGLE_UNSPECIFIC
+        };
+
+        rval = usb11_send_packets(&data_packet, 1);
+    }
+
+    if (rval == CDI_USB_NO_ERROR) {
+        struct cdi_usb_packet ack_packet = {
+            .pipe       = device->ep0,
+            .data       = NULL,
+            .length     = 0,
+            .use_toggle = TOGGLE_1
+        };
+
+        if (no_data || (direction == HOST_TO_DEV)) {
+            ack_packet.type = CDI_USB_PACKET_IN;
+        } else {
+            ack_packet.type = CDI_USB_PACKET_OUT;
+        }
+
+        rval = usb11_send_packets(&ack_packet, 1);
+    }
+
+    if ((rval != CDI_USB_NO_ERROR) && alloced_here) {
+        free(buffer);
+    }
+
+    return (rval == CDI_USB_NO_ERROR) ? buffer : NULL;
+}
+
+void *usb11_export_control(struct cdi_usb_device *device,
+    struct cdi_usb_control_transfer *transfer)
+{
+    return usb11_do_control(device, transfer->direction, transfer->buffer,
+        transfer->length, transfer->rtype, transfer->recipient,
+        transfer->request, transfer->value, transfer->index);
+}
-- 
1.6.4.2