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

[cdi-devel] [PATCH 4/5] USB 1.1



From: Max Reitz <max@xxxxxxxxxx>

+ Added USB 1.1 bus driver

Signed-off-by: Max Reitz <max@xxxxxxxxxx>
Signed-off-by: Kevin Wolf <kevin@xxxxxxxxxx>
---
 usb11/control.c             |  252 +++++++++++++++++++++++++++++++++++++++++++
 usb11/include/control.h     |   31 ++++++
 usb11/include/transfer.h    |   38 +++++++
 usb11/include/usb-structs.h |  184 +++++++++++++++++++++++++++++++
 usb11/include/usb11.h       |   41 +++++++
 usb11/main.c                |   58 ++++++++++
 usb11/transfer.c            |  223 ++++++++++++++++++++++++++++++++++++++
 7 files changed, 827 insertions(+), 0 deletions(-)
 create mode 100644 usb11/control.c
 create mode 100644 usb11/include/control.h
 create mode 100644 usb11/include/transfer.h
 create mode 100644 usb11/include/usb-structs.h
 create mode 100644 usb11/include/usb11.h
 create mode 100644 usb11/main.c
 create mode 100644 usb11/transfer.c

diff --git a/usb11/control.c b/usb11/control.c
new file mode 100644
index 0000000..170341d
--- /dev/null
+++ b/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/usb11/include/control.h b/usb11/include/control.h
new file mode 100644
index 0000000..97edefc
--- /dev/null
+++ b/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/usb11/include/transfer.h b/usb11/include/transfer.h
new file mode 100644
index 0000000..3b0f086
--- /dev/null
+++ b/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/usb11/include/usb-structs.h b/usb11/include/usb-structs.h
new file mode 100644
index 0000000..427d0e5
--- /dev/null
+++ b/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/usb11/include/usb11.h b/usb11/include/usb11.h
new file mode 100644
index 0000000..77634e9
--- /dev/null
+++ b/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/usb11/main.c b/usb11/main.c
new file mode 100644
index 0000000..e381062
--- /dev/null
+++ b/usb11/main.c
@@ -0,0 +1,58 @@
+/*****************************************************************************
+* 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,
+        .init          = &init_usb11,
+        .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
+};
+
+CDI_DRIVER(DRIVER_NAME, driver)
+
+int init_usb11()
+{
+    cdi_init();
+
+    cdi_usb_driver_init(&driver);
+
+    return 0;
+}
diff --git a/usb11/transfer.c b/usb11/transfer.c
new file mode 100644
index 0000000..eb4f949
--- /dev/null
+++ b/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.0.2