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

[cdi-devel] [PATCH] UHCI, USB, MSC



From: Max Reitz <xanclic@xxxxxxxxxxxxxx>

+ UHCI/USB/MSC (MSDs erscheinen als CDI.storage),
  der Schreibsupport ist große Glückssache, Treiber
  nur unter QEMU erfolgreich getestet...

Signed-off-by: Max Reitz <xanclic@xxxxxxxxxxxxxx>
---
 usb/include/msd.h  |  104 +++++++++
 usb/include/uhci.h |  110 ++++++++++
 usb/include/usb.h  |  287 +++++++++++++++++++++++++
 usb/main.c         |  451 +++++++++++++++++++++++++++++++++++++++
 usb/msd.c          |  599 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 usb/uhci.c         |  339 +++++++++++++++++++++++++++++
 6 files changed, 1890 insertions(+), 0 deletions(-)
 create mode 100644 usb/include/msd.h
 create mode 100644 usb/include/uhci.h
 create mode 100644 usb/include/usb.h
 create mode 100644 usb/main.c
 create mode 100644 usb/msd.c
 create mode 100644 usb/uhci.c

diff --git a/usb/include/msd.h b/usb/include/msd.h
new file mode 100644
index 0000000..99c796d
--- /dev/null
+++ b/usb/include/msd.h
@@ -0,0 +1,104 @@
+/******************************************************************************
+ * 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 _CDI__USB__MSD_H
+#define _CDI__USB__MSD_H
+
+#include <stdint.h>
+
+#include "cdi/storage.h"
+
+#include "usb.h"
+
+
+//"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 usb_device *usb_device;
+    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
+
+#endif
diff --git a/usb/include/uhci.h b/usb/include/uhci.h
new file mode 100644
index 0000000..0158bd2
--- /dev/null
+++ b/usb/include/uhci.h
@@ -0,0 +1,110 @@
+/******************************************************************************
+ * 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 _CDI__USB__UHCI_H
+#define _CDI__USB__UHCI_H
+
+#include <stdint.h>
+
+#include "cdi/misc.h"
+#include "cdi/pci.h"
+
+#include "usb.h"
+
+
+#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 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
+
+
+struct uhci
+{
+    struct hci gen_hci;
+    uint16_t pbase;
+    uintptr_t phys_frame_list;
+    uint32_t *frame_list;
+    int root_ports;
+};
+
+struct uhci_qh
+{
+    volatile uint32_t next;
+    volatile uint32_t transfer;
+} __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;
+};
+
+#endif
diff --git a/usb/include/usb.h b/usb/include/usb.h
new file mode 100644
index 0000000..2c435d8
--- /dev/null
+++ b/usb/include/usb.h
@@ -0,0 +1,287 @@
+/******************************************************************************
+ * 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 _CDI__USB__USB_H
+#define _CDI__USB__USB_H
+
+#include <stdint.h>
+
+#include "cdi/misc.h"
+#include "cdi/pci.h"
+
+
+#define PACKET_SETUP 0x2D
+#define PACKET_IN    0x69
+#define PACKET_OUT   0xE1
+
+#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
+
+#define USB_NO_ERROR      0x00
+#define USB_STALLED       0x01
+#define USB_BUFFER_ERROR  0x02
+#define USB_BABBLE        0x04
+#define USB_NAK           0x08
+#define USB_CRC           0x10
+#define USB_TIMEOUT       0x20
+#define USB_BITSTUFF      0x40
+#define USB_TRIVIAL_ERROR 0x80
+
+#define USB_TOD_SETUP          0x0001
+#define USB_TOD_SETUP_DATA_IN  0x0002
+#define USB_TOD_SETUP_DATA_OUT 0x0004
+#define USB_TOD_SETUP_ACK_IN   0x0008
+#define USB_TOD_SETUP_ACK_OUT  0x0010
+#define USB_TOD_COMMAND        0x0020
+#define USB_TOD_DATA_IN        0x0040
+#define USB_TOD_DATA_OUT       0x0080
+#define USB_TOD_STATUS         0x0100
+
+#define USB_TODS_SETUP          0
+#define USB_TODS_SETUP_DATA_IN  1
+#define USB_TODS_SETUP_DATA_OUT 2
+#define USB_TODS_SETUP_ACK_IN   3
+#define USB_TODS_SETUP_ACK_OUT  4
+#define USB_TODS_COMMAND        5
+#define USB_TODS_DATA_IN        6
+#define USB_TODS_DATA_OUT       7
+#define USB_TODS_STATUS         8
+
+
+typedef enum
+{
+    HCI_UHCI,
+    HCI_OHCI,
+    HCI_EHCI
+} hci_type_t;
+
+struct cdi_hci
+{
+    struct cdi_device cdi_device;
+    struct hci *hci;
+};
+
+struct usb_device;
+
+struct hci
+{
+    struct cdi_pci_device *pcidev;
+    hci_type_t type;
+    cdi_list_t (*find_devices)(struct hci *);
+    void (*activate_device)(struct hci *, struct usb_device *);
+    int (*do_packet)(struct hci *, int frame, int type, int device, int endpoint, int low_speed, uintptr_t phys_data, int length, int datatoggle);
+    int (*get_frame)(struct hci *);
+};
+
+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;
+
+struct class_data
+{
+    usb_class_t type;
+};
+
+struct usb_device
+{
+    struct hci *hci;
+    int id;
+    int port;
+    int low_speed;
+    struct device_desc *device;
+    struct config_desc *config;
+    struct interface_desc *interface;
+    struct class_data *classd;
+    int stalled;
+    int locked;
+    int expects;
+};
+
+struct msclass_data
+{
+    struct class_data gen_class;
+    struct endpoint_desc *bulk_ep_in;
+    struct endpoint_desc *bulk_ep_out;
+};
+
+
+#include "uhci.h"
+
+
+#define HCI_STRUCT_SIZE sizeof(struct uhci)
+
+
+int do_packet(struct usb_device *device, int type, int endpoint, uintptr_t phys_data, int length, int datatoggle, int type_of_data);
+void enumerate_hci(struct hci *);
+struct cdi_driver *init_uhcd(void);
+void init_msc_driver(void);
+void register_msd(struct usb_device *usbdev);
+void uhci_init(struct cdi_device *cdi_hci);
+
+#endif
diff --git a/usb/main.c b/usb/main.c
new file mode 100644
index 0000000..c06f15d
--- /dev/null
+++ b/usb/main.c
@@ -0,0 +1,451 @@
+/******************************************************************************
+ * 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/misc.h"
+#include "cdi/pci.h"
+
+#include "usb.h"
+
+#define DEBUG
+
+#ifdef DEBUG
+#include <stdarg.h>
+#define dprintf(fmt, args...) printf("[usb] " fmt, ##args)
+#define _dprintf(fmt, args...) printf(fmt, ##args)
+#else
+static int dprintf(const char *fmt, ...)
+{
+    return 0;
+}
+#define _dprintf(fmt, args...) dprintf(fmt, ##args)
+#endif
+
+static struct usb_device *devices[128];
+static cdi_list_t ehci, ohci, uhci;
+static void (*ccdriver_take_device[0x100])(struct usb_device *);
+static int usb_dev_ids = 1;
+
+static void usb_init(void);
+static void enumerate_hub(struct usb_device *usbdev);
+
+#ifdef CDI_STANDALONE
+int main(void)
+#else
+int init_usb(void)
+#endif
+{
+    cdi_init();
+
+    memset(devices, 0, 128 * sizeof(struct usb_device *));
+
+    usb_init();
+
+    cdi_run_drivers();
+
+    return 0;
+}
+
+static const int next_data_type[9] = {
+    USB_TOD_SETUP_DATA_IN | USB_TOD_SETUP_DATA_OUT | USB_TOD_SETUP_ACK_IN,
+    USB_TOD_SETUP_ACK_OUT,
+    USB_TOD_SETUP_ACK_IN,
+    USB_TOD_SETUP | USB_TOD_COMMAND,
+    USB_TOD_SETUP | USB_TOD_COMMAND,
+    USB_TOD_DATA_IN | USB_TOD_DATA_OUT | USB_TOD_STATUS,
+    USB_TOD_STATUS,
+    USB_TOD_STATUS,
+    USB_TOD_SETUP | USB_TOD_COMMAND
+};
+
+/*static const char *tod_name[9] = {
+    "SETUP",
+    "SETUP DS IN",
+    "SETUP DS OUT",
+    "SETUP ACK IN",
+    "SETUP ACK OUT",
+    "COMMAND",
+    "DATA IN",
+    "DATA OUT",
+    "STATUS"
+};*/
+
+/**
+* Verarbeitet ein USB-Paket.
+*
+* @param device Das USB-Gerät
+* @param type Der Typ des Pakets (PACKET_IN, PACKET_OUT, PACKET_SETUP)
+* @param endpoint Der gewünschte Endpoint (0 bis 15)
+* @param phys_data Die physische Adresse des zu verwendenden Datenpuffers
+* @param length Die Länge des Puffers
+* @param datatoggle Gibt an, ob DATA0 (0) oder DATA1 (1) verwendet werden soll
+* @param type_of_data Typ der Daten (zur Sicherheit, damit es kein doofes STALL gibt)
+*/
+
+int do_packet(struct usb_device *device, int type, int endpoint, uintptr_t phys_data, int length, int datatoggle, int type_of_data)
+{
+    int error;
+    int tod_short;
+
+    if (!(device->expects & type_of_data)) {
+        dprintf("Expected 0x%04X, got 0x%04X...?\n", device->expects, type_of_data);
+        for (;;);
+    }
+    type_of_data >>= 1;
+    for (tod_short = 0; type_of_data; tod_short++) {
+        type_of_data >>= 1;
+    }
+    //dprintf("TOD: %s\n", tod_name[tod_short]);
+    device->expects = next_data_type[tod_short];
+    endpoint &= 0x07;
+    type &= 0xFF;
+    if (device->stalled) //TODO: Irgendwie entstallen, evtl.? oO
+    {
+        dprintf("Zugriff auf stalled-Gerät verweigert.\n");
+        return USB_STALLED;
+    }
+    error = device->hci->do_packet(device->hci,
+                                   (device->hci->get_frame(device->hci) + 3) & 0x3FF,
+                                   type, device->id, endpoint,
+                                   device->low_speed, phys_data, length,
+                                   datatoggle);
+    if (error == USB_STALLED)
+    {
+        printf("[usb] ENDPOINT %i DES GERÄTS %i STALLED!\n", endpoint, device->id);
+        device->stalled = 1;
+    }
+    return error;
+}
+
+static void *do_control(struct usb_device *device, int direction, void *buffer, int length, int rtype, int recipient, int request, int value, int index)
+{
+    void *rbuf;
+    int rval, no_data;
+    struct setup_packet *setup;
+    uintptr_t pbuf, psetup;
+
+    no_data = direction & NO_DATA;
+    if (!no_data && (cdi_alloc_phys_mem(length, &rbuf, (void **)&pbuf) == -1)) {
+        return NULL;
+    }
+    if (cdi_alloc_phys_mem(sizeof(struct setup_packet),
+                           (void **)&setup, (void **)&psetup) == -1) {
+        return NULL;
+    }
+    direction &= 0x80;
+    if ((direction == HOST_TO_DEV) && length && (buffer != NULL)) {
+        memcpy(rbuf, buffer, length);
+    }
+    setup->request_type = direction | (rtype & 0x60) | (recipient & 0x1F);
+    setup->request = request;
+    setup->value = value;
+    setup->index = index;
+    setup->length = length;
+    if (do_packet(device, PACKET_SETUP, 0, psetup, sizeof(struct setup_packet),
+                  0, USB_TOD_SETUP) != USB_NO_ERROR) {
+        return NULL;
+    }
+    cdi_sleep_ms(20);
+    if (no_data)
+    {
+        rval = USB_NO_ERROR;
+        rbuf = (void *)0xFFFFFFFF; //Kein Fehler, aber auch keine Daten
+    }
+    else
+    {
+        if (direction == DEV_TO_HOST) {
+            rval = do_packet(device, PACKET_IN, 0, pbuf, length, 1,
+                             USB_TOD_SETUP_DATA_IN);
+        } else {
+            rval = do_packet(device, PACKET_OUT, 0, pbuf, length, 1,
+                             USB_TOD_SETUP_DATA_OUT);
+        }
+    }
+    if (rval == USB_NO_ERROR)
+    {
+        cdi_sleep_ms(20);
+        if (no_data || (direction == HOST_TO_DEV)) {
+            rval = do_packet(device, PACKET_IN, 0, 0, 0, 1, USB_TOD_SETUP_ACK_IN);
+        } else {
+            rval = do_packet(device, PACKET_OUT, 0, 0, 0, 1, USB_TOD_SETUP_ACK_OUT);
+        }
+    }
+    return (rval == USB_NO_ERROR) ? rbuf : NULL;
+}
+
+static void usb_init(void)
+{
+    struct cdi_pci_device *dev;
+    struct hci *hci;
+    struct cdi_hci *cdi_hci;
+    struct cdi_driver *uhcd;
+    char *dev_name;
+    int i;
+
+    init_msc_driver();
+
+    memset(ccdriver_take_device, 0, sizeof(void (*)(struct usb_device *)) * 0x100);
+    ccdriver_take_device[8] = &register_msd;
+    ccdriver_take_device[9] = &enumerate_hub;
+
+    ehci = cdi_list_create();
+    ohci = cdi_list_create();
+    uhci = cdi_list_create();
+
+    cdi_list_t pci_devices = cdi_list_create();
+    cdi_pci_get_all_devices(pci_devices);
+    for (i = 0; (dev = cdi_list_get(pci_devices, i)) != NULL; i++)
+    {
+        if ((dev->class_id != 0x0C) || (dev->subclass_id != 0x03)) {
+            cdi_pci_device_destroy(dev);
+        } else {
+            switch (dev->interface_id)
+            {
+                case 0x00:
+                    hci = malloc(HCI_STRUCT_SIZE);
+                    hci->pcidev = dev;
+                    hci->type = HCI_UHCI;
+                    cdi_list_push(uhci, hci);
+                    break;
+                case 0x10:
+                    hci = malloc(HCI_STRUCT_SIZE);
+                    hci->pcidev = dev;
+                    hci->type = HCI_OHCI;
+                    cdi_list_push(ohci, hci);
+                    break;
+                case 0x20:
+                    hci = malloc(HCI_STRUCT_SIZE);
+                    hci->pcidev = dev;
+                    hci->type = HCI_EHCI;
+                    cdi_list_push(ehci, hci);
+            }
+        }
+    }
+
+    cdi_list_destroy(pci_devices);
+
+    dprintf("%i EHCIs, %i OHCIs und %i UHCIs gefunden.\n", cdi_list_size(ehci),
+                                                           cdi_list_size(ohci),
+                                                           cdi_list_size(uhci));
+
+    uhcd = init_uhcd();
+
+    for (i = 0; (hci = cdi_list_pop(uhci)) != NULL; i++)
+    {
+        cdi_hci = malloc(sizeof(struct cdi_hci));
+        cdi_hci->cdi_device.type = CDI_UNKNOWN;
+        dev_name = malloc(10);
+        sprintf(dev_name, "uhci%i", i);
+        cdi_hci->cdi_device.name = dev_name;
+        hci->find_devices = NULL;
+        cdi_hci->hci = hci;
+        //cdi_list_push(uhcd->devices, cdi_hci);
+        //^ Das ist zwar sehr schön, geht so aber leider nicht
+        dprintf("%s registriert.\n", dev_name);
+        cdi_hci->cdi_device.driver = uhcd;
+        uhci_init(&cdi_hci->cdi_device);
+    }
+
+    cdi_list_destroy(ehci);
+    cdi_list_destroy(ohci);
+    cdi_list_destroy(uhci);
+}
+
+static void enum_device(struct usb_device *usbdev)
+{
+    struct device_desc *dev_desc;
+    struct config_desc *conf_desc;
+    struct interface_desc *if_desc, *best_if;
+    char *name;
+    void *position;
+    int i, id;
+
+    usbdev->stalled = 0;
+    usbdev->locked = 0;
+    usbdev->expects = USB_TOD_SETUP | USB_TOD_COMMAND;
+    dev_desc = do_control(usbdev, DEV_TO_HOST, NULL, sizeof(*dev_desc),
+                          STD_REQUEST, REC_DEVICE, GET_DESCRIPTOR,
+                          DESC_DEVICE << 8, 0);
+    if (dev_desc == NULL) {
+        return;
+    }
+    usbdev->device = dev_desc;
+    dprintf("0x%04X:0x%04X (%i) -> ", dev_desc->vendor_id, dev_desc->device_id,
+                                      dev_desc->class_id);
+    do_control(usbdev, HOST_TO_DEV | NO_DATA, NULL, 0, STD_REQUEST, REC_DEVICE,
+               SET_ADDRESS, (id = usb_dev_ids++), 0);
+    usbdev->id = id;
+    _dprintf("%i\n", id);
+    if (dev_desc->iManufacturer)
+    {
+        name = do_control(usbdev, DEV_TO_HOST, NULL, 64, STD_REQUEST,
+                          REC_DEVICE, GET_DESCRIPTOR,
+                          (DESC_STRING << 8) | dev_desc->iManufacturer, 0);
+        if (name == NULL) {
+            return;
+        }
+        dprintf(" -> Hersteller: ");
+        for (i = 2; i < name[0]; i += 2) {
+            _dprintf("%c", name[i]);
+        }
+        _dprintf("\n");
+    }
+    if (dev_desc->iProduct)
+    {
+        name = do_control(usbdev, DEV_TO_HOST, NULL, 64, STD_REQUEST,
+                          REC_DEVICE, GET_DESCRIPTOR,
+                          (DESC_STRING << 8) | dev_desc->iProduct, 0);
+        if (name == NULL) {
+            return;
+        }
+        dprintf(" -> Produkt: ");
+        for (i = 2; i < name[0]; i += 2) {
+            _dprintf("%c", name[i]);
+        }
+        _dprintf("\n");
+    }
+    devices[id] = usbdev;
+  //TODO: Man kann doch nicht immer den ersten nehmen...
+    conf_desc = do_control(usbdev, DEV_TO_HOST, NULL,
+                           sizeof(struct config_desc), STD_REQUEST, REC_DEVICE,
+                           GET_DESCRIPTOR, DESC_CONFIGURATION << 8, 0);
+    if (conf_desc == NULL) {
+        return;
+    }
+    conf_desc = do_control(usbdev, DEV_TO_HOST, NULL, conf_desc->total_length,
+                           STD_REQUEST, REC_DEVICE, GET_DESCRIPTOR,
+                           DESC_CONFIGURATION << 8, 0);
+    if (conf_desc == NULL) {
+        return;
+    }
+    usbdev->config = conf_desc;
+    do_control(usbdev, HOST_TO_DEV, NULL, 0, STD_REQUEST, REC_DEVICE,
+               SET_CONFIGURATION, conf_desc->config_value, 0);
+    if (conf_desc->iConfiguration)
+    {
+        name = do_control(usbdev, DEV_TO_HOST, NULL, 64, STD_REQUEST,
+                          REC_DEVICE, GET_DESCRIPTOR,
+                          (DESC_STRING << 8) | conf_desc->iConfiguration, 0);
+        if (name == NULL) {
+            return;
+        }
+        dprintf("Verwende Konfiguration ");
+        for (i = 2; i < name[0]; i += 2) {
+            _dprintf("%c", name[i]);
+        }
+        _dprintf(".\n");
+    }
+    position = conf_desc;
+    position += sizeof(struct config_desc);
+    best_if = position; //Standard-IF
+    for (i = 0; i < conf_desc->num_interfaces; i++)
+    {
+        if_desc = position;
+        if (if_desc->interface_class == 8) //TODO: Mehr Klassencodes natürlich!
+        {
+            best_if = if_desc;
+            break;
+        }
+        position += sizeof(struct interface_desc) + if_desc->num_endpoints * sizeof(struct endpoint_desc);
+    }
+    do_control(usbdev, HOST_TO_DEV, NULL, 0, STD_REQUEST, REC_DEVICE,
+               SET_INTERFACE, best_if->interface_number, 0);
+    usbdev->interface = best_if;
+    if (best_if->iInterface)
+    {
+        name = do_control(usbdev, DEV_TO_HOST, NULL, 64, STD_REQUEST,
+                          REC_DEVICE, GET_DESCRIPTOR,
+                          (DESC_STRING << 8) | best_if->iInterface, 0);
+        if (name == NULL) {
+            return;
+        }
+        dprintf("Verwende Interface ");
+        for (i = 2; i < name[0]; i += 2) {
+            _dprintf("%c", name[i]);
+        }
+        _dprintf(".\n");
+    }
+    dprintf("Konfiguration: %i:%i (%i)\n", conf_desc->config_value,
+                                           best_if->interface_number,
+                                           best_if->interface_class);
+    if (ccdriver_take_device[best_if->interface_class] != NULL) {
+        ccdriver_take_device[best_if->interface_class](usbdev);
+    }
+}
+
+static void enumerate_hub(struct usb_device *usbdev)
+{
+    struct hub_desc *hub_desc;
+    struct 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 = 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 = 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
+        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);
+        //Resetten
+        do_control(usbdev, HOST_TO_DEV, NULL, 0, CLS_REQUEST, REC_OTHER,
+                   SET_FEATURE, PORTF_RESET, i+1);
+        //Reset sollte jetzt eigtl. schon beendet sein
+        //(do_control wartet ja 50 ms)
+        down = malloc(sizeof(struct usb_device));
+        down->hci = usbdev->hci;
+        down->id = 0;
+        down->port = i;
+        down->low_speed = (port_status[0] & PORT_LOWSPEED) && 1;
+        enum_device(down);
+    }
+}
+
+void enumerate_hci(struct hci *hci)
+{
+    struct usb_device *usbdev;
+    cdi_list_t usb_devices;
+
+    if (hci->find_devices != NULL)
+    {
+        usb_devices = hci->find_devices(hci);
+        while ((usbdev = cdi_list_pop(usb_devices)) != NULL)
+        {
+            hci->activate_device(hci, usbdev);
+            cdi_sleep_ms(50);
+            enum_device(usbdev);
+        }
+    }
+}
diff --git a/usb/msd.c b/usb/msd.c
new file mode 100644
index 0000000..11fbd6a
--- /dev/null
+++ b/usb/msd.c
@@ -0,0 +1,599 @@
+/******************************************************************************
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cdi/misc.h"
+#include "cdi/storage.h"
+
+#include "msd.h"
+#include "usb.h"
+
+//DEBUG definieren, um einige Debugmeldungen anzuzeigen
+#define DEBUG
+//FULLDEBUG definieren, um ALLE Debugmeldungen anzuzeigen
+#define FULLDEBUG
+
+#if defined FULLDEBUG && !defined DEBUG
+#define DEBUG
+#endif
+
+#ifdef DEBUG
+#define dprintf(fmt, args...) printf("[usb-msc] " fmt, ##args)
+#define _dprintf(fmt, args...) printf(fmt, ##args)
+#else
+static int dprintf(const char *fmt, ...)
+{
+    return 0;
+}
+#define _dprintf(fmt, args...) dprintf(fmt, ##args)
+#endif
+
+#ifdef FULLDEBUG
+#define fdprintf(fmt, args...) printf("[usb-msc] " fmt, ##args)
+#else
+static int fdprintf(const char *fmt, ...)
+{
+    return 0;
+}
+#endif
+
+static uint32_t cbw_tag = 1;
+
+static const char *driver_name = "usb-msc";
+
+static struct cdi_storage_driver cdi_driver;
+
+static void deinit_msd(struct cdi_device *cdi_msd);
+static void get_partitions(struct cdi_storage_device *cdistrg);
+static void init_msd(struct cdi_device *cdi_msd);
+static void kill_driver(struct cdi_driver *cdi_msc_driver);
+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 int msd_get_capacity(struct usb_device *usbdev, uint32_t *block_size, uint32_t *block_count);
+
+//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
+
+//Das muss definiert werden, um vor einem Befehl zu warten, bis das MSD fertig
+//ist. Theoretisch ist das äußerst sinnvoll, praktisch hängt sich der Treiber
+//bisweilen auf - das sollte allerdings mit dem Timeout gegessen sein
+/**
+#define WAIT_FOR_MSD_READY
+*/
+
+//TODO: Storage bietet eine SCSI-Klasse. Die könnte man durchaus benutzen. xD
+
+void init_msc_driver()
+{
+    struct cdi_driver *stddrv = (struct cdi_driver *)&cdi_driver;
+    stddrv->type = CDI_STORAGE;
+    stddrv->name = driver_name;
+    stddrv->init_device = &init_msd;
+    stddrv->remove_device = &deinit_msd;
+    stddrv->destroy = &kill_driver;
+    cdi_driver.read_blocks = &msd_cdi_read;
+    cdi_driver.write_blocks = &msd_cdi_write;
+    cdi_storage_driver_init(&cdi_driver);
+    cdi_storage_driver_register(&cdi_driver);
+}
+
+void register_msd(struct usb_device *usbdev)
+{
+    struct cdi_storage_device *strgdev;
+    struct cdi_msd *cdimsd;
+    struct msclass_data *msc;
+    struct endpoint_desc *ep_desc;
+    void *address;
+    int i;
+    uint32_t bs, bc;
+    uint64_t size;
+    static int msdnum = 0;
+
+    if (usbdev->interface->interface_protocol != 0x50)
+    {
+       dprintf("Es werden nur bulk-only-Interfaces unterstützt.\n");
+       return;
+    }
+    cdimsd = malloc(sizeof(struct cdi_msd));
+    if (cdimsd == NULL) {
+        return;
+    }
+    cdimsd->usb_device = usbdev;
+    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;
+    }
+    sprintf((char *)strgdev->dev.name, "msd%i", msdnum++);
+    msc = malloc(sizeof(struct msclass_data));
+    if (msc == NULL)
+    {
+        free((void *)strgdev->dev.name);
+        free(strgdev);
+        return;
+    }
+    usbdev->classd = (struct class_data *)msc;
+    msc->bulk_ep_in = NULL;
+    msc->bulk_ep_out = NULL;
+    address = (void *)usbdev->interface + sizeof(struct interface_desc);
+    for (i = 0; i < usbdev->interface->num_endpoints; i++)
+    {
+        ep_desc = address;
+        if ((ep_desc->endpoint_address & 0x80) &&
+            (ep_desc->attributes      == 0x02) &&
+            (msc->bulk_ep_in          == NULL)) { //BULK-IN
+            msc->bulk_ep_in = ep_desc;
+        } else if (!(ep_desc->endpoint_address & 0x80) &&
+                    (ep_desc->attributes      == 0x02) &&
+                    (msc->bulk_ep_out         == NULL)) { //BULK-OUT
+            msc->bulk_ep_out = ep_desc;
+        }
+        address += sizeof(struct endpoint_desc);
+    }
+    if ((msc->bulk_ep_in == NULL) || (msc->bulk_ep_out == NULL))
+    {
+        dprintf("Nicht genügend Endpoints gefunden.\n");
+        return;
+    }
+    if (!msd_get_capacity(usbdev, &bs, &bc))
+    {
+        strgdev->block_size = 0;
+        strgdev->block_count = 0;
+        dprintf("Konnte Größe für %s nicht ermitteln.\n", strgdev->dev.name);
+    }
+    else
+    {
+        strgdev->block_size = bs;
+        strgdev->block_count = bc;
+        size = bs;
+        size *= bc;
+        dprintf("%s: %i * %i B (ca. %i MB).\n", strgdev->dev.name, bc, bs, size >> 20);
+    }
+    cdi_storage_device_init(strgdev);
+    cdi_list_push(cdi_driver.drv.devices, strgdev);
+    get_partitions(strgdev);
+}
+
+static void init_msd(struct cdi_device *cdi_dev)
+{
+    //Hier wird nichts gemacht, da die Partitionen schon in register_msd()
+    //erkannt werden MÜSSEN. Somit läuft die ganze Initialisierung dort ab.
+}
+
+static void kill_driver(struct cdi_driver *cdi_msc_driver)
+{
+    //TODO: Man könnte doch noch irgendwie die Geräte entfernen
+}
+
+static void deinit_msd(struct cdi_device *cdi_msd)
+{
+    //TODO: Und gerade hier...
+}
+
+static int msd_get_capacity(struct usb_device *usbdev, uint32_t *block_size, uint32_t *block_count)
+{
+    struct msclass_data *msc;
+    struct command_block_wrapper *cbw;
+    struct command_status_wrapper *csw;
+    struct msd_capacity *cap;
+    uintptr_t pcbw, pcsw, pcap;
+    uint32_t expected_tag;
+
+    if ((usbdev == NULL) || (block_size == NULL) || (block_count == NULL)) {
+        return 0;
+    }
+    if (cdi_alloc_phys_mem(sizeof(struct command_block_wrapper),
+                           (void **)&cbw, (void **)&pcbw) == -1) {
+        return 0;
+    }
+    if (cdi_alloc_phys_mem(sizeof(struct command_status_wrapper),
+                           (void **)&csw, (void **)&pcsw) == -1) {
+        return 0;
+    }
+    if (cdi_alloc_phys_mem(sizeof(struct msd_capacity),
+                           (void **)&cap, (void **)&pcap) == -1) {
+        return 0;
+    }
+    msc = (struct msclass_data *)usbdev->classd;
+    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 (do_packet(usbdev, PACKET_OUT, msc->bulk_ep_out->endpoint_address, pcbw,
+                  0x1F, 0, USB_TOD_COMMAND) != USB_NO_ERROR) {
+        return 0;
+    }
+    cdi_sleep_ms(20);
+    if (do_packet(usbdev, PACKET_IN, msc->bulk_ep_in->endpoint_address, pcap,
+                  sizeof(struct msd_capacity), 0, USB_TOD_DATA_IN)
+           != USB_NO_ERROR) {
+        return 0;
+    }
+    cdi_sleep_ms(5);
+    if (do_packet(usbdev, PACKET_IN, msc->bulk_ep_in->endpoint_address, pcsw,
+                  0x0D, 0, USB_TOD_STATUS) != USB_NO_ERROR) {
+        return 0;
+    }
+    cdi_sleep_ms(5);
+    if ((csw->csw_signature != CSW_SIGNATURE) ||
+         (csw->csw_tag      !=  expected_tag) ||
+          csw->csw_status) {
+        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 usb_device *usbdev)
+{
+   struct msclass_data *msc;
+   struct command_block_wrapper *cbw;
+   struct command_status_wrapper *csw;
+   uintptr_t pcbw, pcsw;
+   uint32_t expected_tag;
+
+   if (cdi_alloc_phys_mem(sizeof(struct command_block_wrapper),
+                          (void **)&cbw, (void **)&pcbw) == -1) {
+      return 0;
+   }
+   if (cdi_alloc_phys_mem(sizeof(struct command_status_wrapper),
+                          (void **)&csw, (void **)&pcsw) == -1) {
+      return 0;
+   }
+   msc = (struct msclass_data *)usbdev->classd;
+   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 (do_packet(usbdev, PACKET_OUT, msc->bulk_ep_out->endpoint_address, pcbw,
+                 0x1F, 0, USB_TOD_COMMAND) != USB_NO_ERROR) {
+       return 0;
+   }
+   cdi_sleep_ms(7);
+   if (do_packet(usbdev, PACKET_IN, msc->bulk_ep_in->endpoint_address, pcsw,
+                 0x0D, 0, USB_TOD_STATUS) != USB_NO_ERROR) {
+       return 0;
+   }
+   cdi_sleep_ms(4);
+   if ((csw->csw_signature != CSW_SIGNATURE) ||
+       (csw->csw_tag       !=  expected_tag) ||
+        csw->csw_status) {
+      return 0;
+   }
+   return 1;
+}
+#endif
+
+static inline int tsl(volatile int *variable)
+{
+    int rval;
+    rval = *variable;
+    *variable = 1;
+    return rval;
+}
+
+static uint32_t msd_read(struct usb_device *usbdev, uint32_t lba, uint16_t sectors, uintptr_t phys_buffer, size_t length);
+
+static int msd_cdi_read(struct cdi_storage_device *strgdev, uint64_t start, uint64_t count, void *buffer)
+{
+    void *vb;
+    uintptr_t pb;
+    int bs = strgdev->block_size, error;
+#ifdef WAIT_FOR_MSD_READY
+    int j;
+#endif
+    uint32_t i;
+    struct usb_device *usbdev = ((struct cdi_msd *)strgdev)->usb_device;
+
+    fdprintf("read(%i, %i)\n", (int)start, (int)count);
+    start += ((struct cdi_msd *)strgdev)->offset;
+    if (cdi_alloc_phys_mem(bs, &vb, (void **)&pb) == -1)
+    {
+        dprintf("Blockspeicher konnte nicht allociert werden.\n");
+        return -1;
+    }
+    if (!count)
+    {
+        dprintf("Leere Leseanfrage.\n");
+        return 0;
+    }
+    while (tsl(&usbdev->locked))
+    {
+#ifndef CDI_STANDALONE
+        __asm__ __volatile__ ("hlt");
+#endif
+    }
+    for (i = 0; i < count; i++)
+    {
+#ifdef WAIT_FOR_MSD_READY
+        for (j = 0; !msd_ready(usbdev) && (j < 10); j++) {
+            cdi_sleep_ms(20);
+        }
+#endif
+        error = msd_read(usbdev, start + i, 1, pb, bs);
+        if (error != USB_NO_ERROR)
+        {
+            dprintf("Lesefehler 0x%X bei Block %i.\n", error, i);
+            usbdev->locked = 0;
+            return -1;
+        }
+        memcpy(buffer + i*bs, vb, bs);
+    }
+    usbdev->locked = 0;
+    return 0;
+}
+
+static uint32_t msd_read(struct usb_device *usbdev, uint32_t lba, uint16_t sectors, uintptr_t phys_buffer, size_t length)
+{
+    struct msclass_data *msc;
+    struct command_block_wrapper *cbw;
+    struct command_status_wrapper *csw;
+    uintptr_t pcbw, pcsw;
+    uint32_t expected_tag;
+    int error;
+
+    if (cdi_alloc_phys_mem(sizeof(struct command_block_wrapper),
+                           (void **)&cbw, (void **)&pcbw) == -1) {
+        return USB_TRIVIAL_ERROR;
+    }
+    if (cdi_alloc_phys_mem(sizeof(struct command_status_wrapper),
+                           (void **)&csw, (void **)&pcsw) == -1) {
+        return USB_TRIVIAL_ERROR;
+    }
+    if (!phys_buffer || !length) {
+        return USB_TRIVIAL_ERROR;
+    }
+    msc = (struct msclass_data *)usbdev->classd;
+    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 = do_packet(usbdev, PACKET_OUT, msc->bulk_ep_out->endpoint_address,
+                      pcbw, 0x1F, 0, USB_TOD_COMMAND);
+    if (error != USB_NO_ERROR) {
+        return error;
+    }
+    cdi_sleep_ms(20);
+    error = do_packet(usbdev, PACKET_IN, msc->bulk_ep_in->endpoint_address,
+                      phys_buffer, length, 0, USB_TOD_DATA_IN);
+    if (error != USB_NO_ERROR) {
+        return error;
+    }
+    cdi_sleep_ms(5);
+    error = do_packet(usbdev, PACKET_IN, msc->bulk_ep_in->endpoint_address,
+                      pcsw, 0x0D, 0, USB_TOD_STATUS);
+    if (error != USB_NO_ERROR) {
+        return error;
+    }
+    cdi_sleep_ms(4);
+    if ((csw->csw_signature != CSW_SIGNATURE) ||
+        (csw->csw_tag       !=  expected_tag) ||
+         csw->csw_status)
+    {
+        dprintf("0x%08X 0x%08X==0x%08X 0x%02X\n", csw->csw_signature,
+                                                  csw->csw_tag,
+                                                  expected_tag,
+                                                  csw->csw_status);
+        return USB_CRC; //Watt weiß denn ich...
+    }
+    return USB_NO_ERROR;
+}
+
+static uint32_t msd_write(struct usb_device *usbdev, uint32_t lba, uint16_t sectors, uintptr_t phys_buffer, size_t length);
+
+static int msd_cdi_write(struct cdi_storage_device *strgdev, uint64_t start, uint64_t count, void *buffer)
+{
+    void *vb;
+    uintptr_t pb;
+    int bs = strgdev->block_size, error;
+#ifdef WAIT_FOR_MSD_READY
+    int j;
+#endif
+    uint32_t i;
+    struct usb_device *usbdev = ((struct cdi_msd *)strgdev)->usb_device;
+
+    fdprintf("write(%i, %i)\n", (int)start, (int)count);
+    start += ((struct cdi_msd *)strgdev)->offset;
+    if (cdi_alloc_phys_mem(bs, &vb, (void **)&pb) == -1)
+    {
+        dprintf("Blockspeicher zum Schreiben konnte nicht allociert werden.\n");
+        return -1;
+    }
+    while (tsl(&usbdev->locked))
+    {
+#ifndef CDI_STANDALONE
+        __asm__ __volatile__ ("hlt");
+#endif
+    }
+    for (i = 0; i < count; i++)
+    {
+        memcpy(vb, buffer + i*bs, bs);
+#ifdef WAIT_FOR_MSD_READY
+        for (j = 0; !msd_ready(usbdev) && (j < 10); j++) {
+            cdi_sleep_ms(20);
+        }
+#endif
+        error = msd_write(usbdev, start + i, 1, pb, bs);
+        if (error != USB_NO_ERROR)
+        {
+            dprintf("Schreibfehler 0x%X bei Block %i.\n", error, i);
+            usbdev->locked = 0;
+            return -1;
+        }
+    }
+    usbdev->locked = 0;
+    return 0;
+}
+
+static uint32_t msd_write(struct usb_device *usbdev, uint32_t lba, uint16_t sectors, uintptr_t phys_buffer, size_t length)
+{
+    struct msclass_data *msc;
+    struct command_block_wrapper *cbw;
+    struct command_status_wrapper *csw;
+    uintptr_t pcbw, pcsw;
+    uint32_t expected_tag;
+    int error;
+
+    if (cdi_alloc_phys_mem(sizeof(struct command_block_wrapper),
+                           (void **)&cbw, (void **)&pcbw) == -1) {
+        return USB_TRIVIAL_ERROR;
+    }
+    if (cdi_alloc_phys_mem(sizeof(struct command_status_wrapper),
+                           (void **)&csw, (void **)&pcsw) == -1) {
+        return USB_TRIVIAL_ERROR;
+    }
+    if (!phys_buffer || !length) {
+        return USB_TRIVIAL_ERROR;
+    }
+    msc = (struct msclass_data *)usbdev->classd;
+    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 = do_packet(usbdev, PACKET_OUT, msc->bulk_ep_out->endpoint_address,
+                      pcbw, 0x1F, 0, USB_TOD_COMMAND);
+    if (error != USB_NO_ERROR) {
+        return error;
+    }
+    cdi_sleep_ms(20);
+    error = do_packet(usbdev, PACKET_OUT, msc->bulk_ep_out->endpoint_address,
+                      phys_buffer, length, 0, USB_TOD_DATA_OUT);
+    if (error != USB_NO_ERROR) {
+        return error;
+    }
+    cdi_sleep_ms(5);
+    error = do_packet(usbdev, PACKET_IN, msc->bulk_ep_in->endpoint_address,
+                      pcsw, 0x0D, 0, USB_TOD_STATUS);
+    if (error != USB_NO_ERROR) {
+        return error;
+    }
+    cdi_sleep_ms(4);
+    if ((csw->csw_signature != CSW_SIGNATURE) ||
+        (csw->csw_tag       !=  expected_tag) ||
+         csw->csw_status)
+    {
+        dprintf("0x%08X 0x%08X==0x%08X 0x%02X\n", csw->csw_signature,
+                                                  csw->csw_tag,
+                                                  expected_tag,
+                                                  csw->csw_status);
+        return USB_CRC;
+    }
+    return 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) != USB_NO_ERROR) {
+        dprintf("MBR konnte nicht eingelesen werden.\n");
+        return;
+    }
+    if (((uint16_t *)mbr)[255] != 0xAA55) {
+        return;
+    }
+    partition = mbr + 0x1BE;
+    dprintf("Partitionen auf %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 = malloc(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.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;
+            _dprintf(" %s", cdimsd->cdi_device.dev.name);
+            cdi_storage_device_init((struct cdi_storage_device *)cdimsd);
+            cdi_list_push(cdi_driver.drv.devices, cdimsd);
+        }
+    }
+    _dprintf("\n");
+}
diff --git a/usb/uhci.c b/usb/uhci.c
new file mode 100644
index 0000000..c09075c
--- /dev/null
+++ b/usb/uhci.c
@@ -0,0 +1,339 @@
+/******************************************************************************
+ * 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/misc.h"
+#include "cdi/pci.h"
+
+#include "uhci.h"
+#include "usb.h"
+
+#define DEBUG
+
+#ifdef DEBUG
+#include <stdio.h>
+#include <stdarg.h>
+#define dprintf(fmt, args...) printf("[uhci] " fmt, ##args)
+#define _dprintf(fmt, args...) printf(fmt, ##args)
+#else
+static int dprintf(const char *fmt, ...)
+{
+    return 0;
+}
+#define _dprintf(fmt, args...) dprintf(fmt, ##args)
+#endif
+
+static const char *driver_name = "uhci";
+
+static struct cdi_driver cdi_driver;
+static cdi_list_t active_transfers;
+
+static void uhci_handler(struct cdi_device *dev);
+static int enqueue_request(struct hci *gen_hci, int frame, int type, int device, int endpoint, int low_speed, uintptr_t phys_data, int length, int datatoggle);
+static cdi_list_t get_devices(struct hci *gen_hci);
+static void activate_device(struct hci *gen_hci, struct usb_device *device);
+static int get_current_frame(struct hci *gen_hci);
+static void uhci_deinit(struct cdi_device *cdi_hci);
+static void uhci_kill(struct cdi_driver *cdi_hcd);
+
+
+struct cdi_driver *init_uhcd()
+{
+    active_transfers = cdi_list_create();
+    cdi_driver.type = CDI_UNKNOWN;
+    cdi_driver.name = driver_name;
+    cdi_driver.init_device = &uhci_init;
+    cdi_driver.remove_device = &uhci_deinit;
+    cdi_driver.destroy = &uhci_kill;
+    cdi_driver_init(&cdi_driver);
+    cdi_driver_register(&cdi_driver);
+    return &cdi_driver;
+}
+
+static void uhci_kill(struct cdi_driver *cdi_hcd)
+{
+  //TODO: Da geht doch noch was
+}
+
+static void uhci_deinit(struct cdi_device *cdi_hci)
+{
+    cdi_outw(((struct uhci *)((struct cdi_hci *)cdi_hci)->hci)->pbase + UHCI_USBCMD,
+             MAXP); //HC anhalten
+  //TODO: Hier doch auch
+}
+
+void uhci_init(struct cdi_device *cdi_hci)
+{
+    struct hci *gen_hci = ((struct cdi_hci *)cdi_hci)->hci;
+    struct uhci *uhci = (struct uhci *)gen_hci;
+    struct cdi_pci_resource *res;
+    int i, size = 0x14;
+
+    //cdi_pci_alloc_ioports(gen_hci->pcidev);
+    uhci->pbase = 0;
+    for (i = 0; (res = cdi_list_get(gen_hci->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)
+            {
+                dprintf("I/O-Ports konnten nicht reserviert werden.\n");
+                return;
+            }
+            uhci->pbase = res->start;
+            break;
+        }
+    }
+    if (!uhci->pbase)
+    {
+        dprintf("I/O-Basis nicht gefunden!\n");
+        return;
+    }
+    if (cdi_alloc_phys_mem(4096, (void **)&uhci->frame_list,
+                                 (void **)&uhci->phys_frame_list) == -1)
+    {
+        dprintf("Frame List konnte nicht allociert werden!\n");
+        return;
+    }
+    cdi_register_irq(gen_hci->pcidev->irq, &uhci_handler, cdi_hci);
+    uhci->root_ports = (size - 0x10) >> 1;
+    if (uhci->root_ports > 7) { //Laut Linuxkernel ist das so "weird", dass da was nicht stimmen kann...
+        uhci->root_ports = 2;
+    }
+    dprintf("UHC mit I/O 0x%04X (%i Ports) und IRQ %i\n", uhci->pbase, uhci->root_ports, gen_hci->pcidev->irq);
+    for (i = 0; i < 1024; i++) {
+        uhci->frame_list[i] = 1; //Invalid
+    }
+    dprintf("Resetten...\n");
+    //HC zurücksetzen
+    cdi_outw(uhci->pbase + UHCI_USBCMD, MAXP | HCRESET);
+    for (i = 0; (cdi_inw(uhci->pbase + UHCI_USBCMD) & HCRESET) && (i < 50); i++) {
+        cdi_sleep_ms(10);
+    }
+    //Reset auf dem USB treiben
+    cdi_outw(uhci->pbase + UHCI_USBCMD, MAXP | GRESET);
+    for (i = 0; (cdi_inw(uhci->pbase + UHCI_USBCMD) & GRESET) && (i < 50); i++) {
+        cdi_sleep_ms(10);
+    }
+    //Alle Interrupts senden
+    cdi_outw(uhci->pbase + UHCI_USBINTR, 0xF); 
+    //Framelistadresse eintragen
+    cdi_outl(uhci->pbase + UHCI_FRBASEADD, uhci->phys_frame_list);
+    cdi_outw(uhci->pbase + UHCI_FRNUM, 0); //Frame zurücksetzen
+    //Ports abschalten, damit selektiv eingeschaltet werden kann (Enumeration)
+    for (i = 0; i < uhci->root_ports; i++) {
+        cdi_outw(uhci->pbase + UHCI_RPORTS + i*2, RPORT_CSC);
+    }
+    dprintf("  Fertig\n");
+    gen_hci->find_devices = &get_devices;
+    gen_hci->activate_device = &activate_device;
+    gen_hci->do_packet = &enqueue_request;
+    gen_hci->get_frame = &get_current_frame;
+
+    enumerate_hci(gen_hci);
+}
+
+static cdi_list_t get_devices(struct hci *gen_hci)
+{
+    struct uhci *uhci = (struct uhci *)gen_hci;
+    struct usb_device *dev;
+    cdi_list_t dlist = cdi_list_create();
+    int i;
+
+    dprintf("Geräte finden: ");
+    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))
+        {
+            _dprintf("-");
+            continue;
+        }
+        _dprintf("!");
+        dev = malloc(sizeof(struct usb_device));
+        dev->hci = gen_hci;
+        dev->id = 0;
+        dev->port = i;
+        dev->low_speed =
+                (cdi_inw(uhci->pbase + UHCI_RPORTS + 2*i) & RPORT_LOSPD) && 1;
+        cdi_list_push(dlist, dev);
+    }
+    _dprintf("\n");
+    return dlist;
+}
+
+static void activate_device(struct hci *gen_hci, struct usb_device *device)
+{
+    struct uhci *uhci = (struct uhci *)gen_hci;
+
+    dprintf("Gerät an Port %i wird aktiviert.\n", device->port);
+    cdi_outw(uhci->pbase + UHCI_RPORTS + 2 * device->port,
+             RPORT_RESET | RPORT_ENABLE | RPORT_CSC);
+    cdi_sleep_ms(20);
+}
+
+static int get_current_frame(struct hci *gen_hci)
+{
+    return cdi_inw(((struct uhci *)gen_hci)->pbase + UHCI_FRNUM);
+}
+
+static inline int tsl(volatile int *variable)
+{
+    int rval;
+    rval = *variable;
+    *variable = 1;
+    return rval;
+}
+static volatile int locked = 0;
+
+static int enqueue_request(struct hci *gen_hci, int frame, int type, int device, int endpoint, int low_speed, uintptr_t phys_data, int length, int datatoggle)
+{
+    struct uhci *uhci = (struct uhci *)gen_hci;
+    struct uhci_td *td;
+    struct uhci_qh *qh;
+    uintptr_t ptd, pqh;
+    struct transfer *addr;
+
+    if (cdi_alloc_phys_mem(sizeof(struct uhci_td),
+                           (void **)&td, (void **)&ptd) == -1) {
+        return USB_TRIVIAL_ERROR;
+    }
+    if (cdi_alloc_phys_mem(sizeof(struct uhci_qh),
+                           (void **)&qh, (void **)&pqh) == -1) {
+        return USB_TRIVIAL_ERROR;
+    }
+    while (tsl(&locked))
+    {
+#ifndef CDI_STANDALONE
+        __asm__ __volatile__ ("hlt");
+#endif
+    }
+    qh->next = 1; //Invalid
+    qh->transfer = ptd;
+    memset(td, 0, sizeof(struct uhci_td));
+    td->next = 1; //Invalid
+    td->active = 1;
+    td->ioc = 1;
+    td->data_toggle = datatoggle;
+    td->low_speed = low_speed;
+    td->errors = 1;
+    td->pid = type;
+    td->device = device;
+    td->endpoint = endpoint;
+    td->maxlen = length ? length-1 : 0x7FF;
+    td->buffer = phys_data;
+    addr = malloc(sizeof(struct transfer));
+    addr->virt = td;
+    addr->phys = ptd;
+    addr->error = 0xFFFF;
+    cdi_list_push(active_transfers, addr);
+    uhci->frame_list[frame] = pqh | 2;
+#ifdef CDI_STANDALONE
+    /*int cframe = get_current_frame(gen_hci), nframe;
+    nframe = (cframe > frame) ? frame + 1024 : frame; //Überläufe korrigieren
+    //Annähern, wann er wohl fertig ist
+    cdi_sleep_ms(nframe + 30 - get_current_frame(gen_hci));*/
+#else
+    while (!(qh->transfer & 1)) {
+        __asm__ __volatile__ ("hlt");
+    }
+#endif
+    while (addr->error == 0xFFFF)
+    {
+#ifndef CDI_STANDALONE
+        __asm__ __volatile__ ("hlt");
+#endif
+    }
+    uhci->frame_list[frame] = 1;
+    locked = 0;
+    return addr->error;
+}
+
+static void uhci_handler(struct cdi_device *cdi_hci)
+{
+    struct uhci *uhci = (struct uhci *)((struct cdi_hci *)cdi_hci)->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;
+    }
+    if (status & ~0x0001) {
+        dprintf("Unerwarteter IRQ 0x%04X von %s\n", status, cdi_hci->name);
+    }
+    if (status & 0x10)
+    {
+        printf("[uhci] SCHWERWIEGENDER FEHLER - HC WIRD ANGEHALTEN\n");
+        cdi_outw(uhci->pbase + UHCI_USBCMD, MAXP | HCRESET); //FU!
+    }
+    else
+    {
+        for (i = 0; (addr = cdi_list_get(active_transfers, i)) != NULL; i++)
+        {
+            td = addr->virt;
+            if (td->active) {
+                continue;
+            }
+            addr->error = USB_NO_ERROR;
+            cdi_list_remove(active_transfers, i--);
+            if (td->stalled_err)
+            {
+                dprintf("ENDPOINT STALLED\n");
+                addr->error |= USB_STALLED;
+            }
+            if (td->buf_err)
+            {
+                dprintf("Pufferüberlauf oder Underrun\n");
+                addr->error |= USB_BUFFER_ERROR;
+            }
+            if (td->babble)
+            {
+                dprintf("Puh, da war ein Gerät wohl sehr gesprächig: Babble.\n");
+                addr->error |= USB_BABBLE;
+            }
+            if (td->nak)
+            {
+                dprintf("NAK empfangen\n");
+                addr->error |= USB_NAK;
+            }
+            if (td->crc_time_err)
+            {
+                dprintf("CRC-Fehler oder Timeout\n");
+                addr->error |= USB_CRC | USB_TIMEOUT;
+            }
+            if (td->bitstuff_err)
+            {
+                dprintf("Bitstufffehler\n");
+                addr->error |= USB_BITSTUFF;
+            }
+            //TODO: free(td) - dazu wäre eine CDI-Funktion nützlich
+        }
+    }
+    cdi_outw(uhci->pbase + UHCI_USBSTS, status);
+}
-- 
1.6.0.2