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

[cdi-devel] [PATCH] Multiple packets



From: Max Reitz <max@xxxxxxxxxx>

+ OHCD can send more than one packet at once. Now it is a
  lot faster but unfortunately, you get a lot of STALLs
  that cannot be recovered.
* UHCD takes multiple packets but sends them one by one -
  although that is not very nice.

Signed-off-by: Max Reitz <max@xxxxxxxxxx>
---
 usb/include/usb.h |   12 +++-
 usb/main.c        |   46 +++++-----
 usb/msd.c         |    9 ++-
 usb/ohci.c        |  248 +++++++++++++++++++++++++++++++----------------------
 usb/uhci.c        |   23 +++++-
 5 files changed, 210 insertions(+), 128 deletions(-)

diff --git a/usb/include/usb.h b/usb/include/usb.h
index 5f0f2cc..4b37dc5 100644
--- a/usb/include/usb.h
+++ b/usb/include/usb.h
@@ -169,7 +169,7 @@ struct hci {
       *
       * @return Gibt den Status an (z. B. USB_NO_ERROR für keinen Fehler)
       */
-    int (* do_packet)(struct usb_packet* packet);
+    int (* do_packets)(struct usb_packet* packets, int num_packets);
 
     /**
       * Erstellt eine neue Pipe
@@ -299,6 +299,12 @@ struct msclass_data {
     struct usb_pipe* bulk_out;
 };
 
+enum usb_toggle {
+    TOGGLE_UNSPECIFIC = 0,
+    TOGGLE_0 = 1,
+    TOGGLE_1 = 2
+};
+
 /** Beschreibt ein USB-Paket */
 struct usb_packet {
     /// Die gewuenschte Pipe
@@ -311,6 +317,10 @@ struct usb_packet {
     int length;
     /// Typ der Daten (zur Sicherheit, damit es kein doofes STALL gibt)
     int type_of_data;
+    /// Fehlertyp (oder USB_NO_ERROR)
+    int condition;
+    /// Bestimmtes Data-Toggle benuten
+    enum usb_toggle use_toggle;
 };
 
 /// Beschreibt eine Pipe
diff --git a/usb/main.c b/usb/main.c
index da767cb..4639369 100644
--- a/usb/main.c
+++ b/usb/main.c
@@ -177,6 +177,7 @@ int usb_do_packet(struct usb_packet* packets, int num_packets)
                 out_packets[cur].data = packets[i].data;
                 out_packets[cur].length = MIN(packets[i].length, mps);
                 out_packets[cur].type_of_data = tod;
+                out_packets[cur].condition = USB_NAK;
 
                 packets[i].data += out_packets[cur].length;
                 packets[i].length -= out_packets[cur].length;
@@ -185,28 +186,27 @@ int usb_do_packet(struct usb_packet* packets, int num_packets)
         }
     }
 
-    // Pakete (FIXME: einzeln) senden
-    for (i = 0; i < num_out_packets; i++) {
-        error = USB_NAK;
-        while (error == USB_NAK) {
-            error = device->hci->do_packet(&out_packets[i]);
-            if (error == USB_NAK) {
-                cdi_sleep_ms(5);
+    error = device->hci->do_packets(out_packets, num_out_packets);
+    if (error & USB_STALLED) {
+        printf("[usb] ENDPOINT 0x%02X DES GERÃ?TS %i STALLED!\n",
+            pipe->endpoint->endpoint_address,
+            device->id);
+        do_control(device, HOST_TO_DEV | NO_DATA, NULL, 0, STD_REQUEST,
+            REC_ENDPOINT, CLEAR_FEATURE, 0,
+            pipe->endpoint->endpoint_address);
+    } else if (error & USB_NAK) {
+        // Nicht angenommene Pakete (FIXME: einzeln) senden
+        for (i = 0; i < num_out_packets; i++) {
+            if (!(out_packets[i].condition & USB_NAK)) {
+                continue;
+            }
+            error = USB_NAK;
+            while (error & USB_NAK) {
+                error = device->hci->do_packets(&out_packets[i], 1);
+                if (error & USB_NAK) {
+                    cdi_sleep_ms(5);
+                }
             }
-        }
-        if (error != USB_NO_ERROR) {
-            i--;
-        } else {
-            pipe->data_toggle ^= 1;
-        }
-
-        if (error == USB_STALLED) {
-            printf("[usb] ENDPOINT 0x%02X DES GERÃ?TS %i STALLED!\n",
-                pipe->endpoint->endpoint_address,
-                device->id);
-            do_control(device, HOST_TO_DEV | NO_DATA, NULL, 0, STD_REQUEST,
-                REC_ENDPOINT, CLEAR_FEATURE, 0,
-                pipe->endpoint->endpoint_address);
         }
     }
 
@@ -244,6 +244,7 @@ static void* do_control(struct usb_device* device, int direction, void* buffer,
         .data         = setup,
         .length       = sizeof(*setup),
         .type_of_data = USB_TOD_SETUP,
+        .use_toggle   = TOGGLE_UNSPECIFIC
     };
 
     if (usb_do_packet(&setup_packet, 1)) {
@@ -262,6 +263,7 @@ static void* do_control(struct usb_device* device, int direction, void* buffer,
             .type_of_data =
                 (direction ==
                  DEV_TO_HOST ? USB_TOD_SETUP_DATA_IN : USB_TOD_SETUP_DATA_OUT),
+            .use_toggle   = TOGGLE_UNSPECIFIC
         };
 
         rval = usb_do_packet(&data_packet, 1);
@@ -272,8 +274,8 @@ static void* do_control(struct usb_device* device, int direction, void* buffer,
             .pipe       = device->ep0,
             .data       = NULL,
             .length     = 0,
+            .use_toggle = TOGGLE_1
         };
-        device->ep0->data_toggle = 1;
 
         if (no_data || (direction == HOST_TO_DEV)) {
             ack_packet.type = PACKET_IN;
diff --git a/usb/msd.c b/usb/msd.c
index 4191002..34e6e04 100644
--- a/usb/msd.c
+++ b/usb/msd.c
@@ -34,7 +34,7 @@
 //DEBUG definieren, um einige Debugmeldungen anzuzeigen
 #define DEBUG
 //FULLDEBUG definieren, um ALLE Debugmeldungen anzuzeigen
-#define FULLDEBUG
+//#define FULLDEBUG
 
 #if defined FULLDEBUG && !defined DEBUG
 #define DEBUG
@@ -239,6 +239,7 @@ static int write_cmd(struct usb_device* usbdev, void* src)
         .data         = src,
         .length       = 0x1F,
         .type_of_data = USB_TOD_COMMAND,
+        .use_toggle   = TOGGLE_UNSPECIFIC
     };
 
     return usb_do_packet(&cmd_packet, 1);
@@ -266,6 +267,7 @@ static int read_status(struct usb_device* usbdev, uint32_t expected_tag)
         .data         = csw,
         .length       = 0x0D,
         .type_of_data = USB_TOD_STATUS,
+        .use_toggle   = TOGGLE_UNSPECIFIC
     };
 
     error = usb_do_packet(&status_packet, 1);
@@ -319,6 +321,7 @@ static int msd_get_capacity(struct usb_device* usbdev, uint32_t* block_size,
         .data         = cap,
         .length       = sizeof(*cap),
         .type_of_data = USB_TOD_DATA_IN,
+        .use_toggle   = TOGGLE_UNSPECIFIC
     };
 
     if (usb_do_packet(&in_packet, 1) != USB_NO_ERROR) {
@@ -373,7 +376,7 @@ static inline int tsl(volatile int* variable)
     return rval;
 }
 
-#define MAX_ACCESS_BLOCKS 32
+#define MAX_ACCESS_BLOCKS 4
 
 static uint32_t msd_read(struct usb_device* usbdev, uint32_t lba,
     uint16_t sectors, void* buffer,
@@ -461,6 +464,7 @@ static uint32_t msd_read(struct usb_device* usbdev, uint32_t lba,
         .data         = buffer,
         .length       = length,
         .type_of_data = USB_TOD_DATA_IN,
+        .use_toggle   = TOGGLE_UNSPECIFIC
     };
 
     error = usb_do_packet(&in_packet, 1);
@@ -562,6 +566,7 @@ static uint32_t msd_write(struct usb_device* usbdev, uint32_t lba,
         .data         = buffer,
         .length       = length,
         .type_of_data = USB_TOD_DATA_OUT,
+        .use_toggle   = TOGGLE_UNSPECIFIC
     };
 
     error = usb_do_packet(&out_packet, 1);
diff --git a/usb/ohci.c b/usb/ohci.c
index 9e0a2aa..d95f330 100644
--- a/usb/ohci.c
+++ b/usb/ohci.c
@@ -53,7 +53,7 @@ static void ohci_kill(struct cdi_driver* cdi_hcd);
 static void ohci_deinit(struct cdi_device* cdi_hci);
 void ohci_init(struct cdi_device* cdi_hci);
 static void ohci_handler(struct cdi_device* dev);
-static int ohci_do_packet(struct usb_packet* packet);
+static int ohci_do_packets(struct usb_packet* packet, int num_packets);
 static cdi_list_t get_devices(struct hci* gen_hci);
 static void activate_device(struct usb_device* device);
 static void ohci_reset_device(struct usb_device* device);
@@ -109,7 +109,7 @@ void ohci_init(struct cdi_device* cdi_hci)
         dprintf("Speicher nicht gefunden!\n");
         return;
     }
-    dprintf("Speicher @ 0x%08x\n", (uintptr_t) ohci->memory);
+    dprintf("Speicher @ 0x%08X\n", (uintptr_t) ohci->memory);
     if ((ohci->memory->hc_revision & 0xFF) != 0x10) {
         dprintf(
             "Dieses OHCI könnte inkompatibel mit dem Treiber sein (HCI %i.%i, HCD 1.0)\n",
@@ -134,7 +134,7 @@ void ohci_init(struct cdi_device* cdi_hci)
         return;
     }
 
-    ohci->transfer_pool = mempool_create(32 * (1024 + sizeof(struct ohci_td)),
+    ohci->transfer_pool = mempool_create(56 * (1024 + sizeof(struct ohci_td)),
         1024 + sizeof(struct ohci_td));
     if (ohci->transfer_pool == NULL) {
         dprintf("Transfer-Speicherpool konnte nicht erzeugt werden!\n");
@@ -229,24 +229,33 @@ void ohci_init(struct cdi_device* cdi_hci)
 
     gen_hci->find_devices = &get_devices;
     gen_hci->activate_device = &activate_device;
-    gen_hci->do_packet = &ohci_do_packet;
+    gen_hci->do_packets = &ohci_do_packets;
     gen_hci->add_pipe = &ohci_establish_pipe;
 
     enumerate_hci(gen_hci);
 }
 
-static int ohci_do_packet(struct usb_packet* packet)
+static inline int tsl(volatile int* variable)
+{
+    int rval;
+    rval = *variable;
+    *variable = 1;
+    return rval;
+}
+
+static int ohci_do_packets(struct usb_packet* packets, int num_packets)
 {
     struct ohci_ed_desc* edsc;
     struct ohci_td_desc* tdsc, * otdsc;
-    int i, cond;
-    struct ohci* ohci = (struct ohci*) packet->pipe->device->hci;
-    struct ohci_td* vtd;
-    uintptr_t ptd;
+    int i, j, cond, toggle, done_packets;
+    struct ohci* ohci = (struct ohci*) packets[0].pipe->device->hci;
+    struct ohci_td* vtd[num_packets];
+    uintptr_t ptd[num_packets];
+    static volatile int locked = 0;
 
     for (i = 0; (edsc = cdi_list_get(ohci->ed_list, i)) != NULL; i++) {
-        if ((edsc->function == packet->pipe->device->id) &&
-            (edsc->endpoint == packet->pipe->endpoint->endpoint_address))
+        if ((edsc->function == packets[0].pipe->device->id) &&
+            (edsc->endpoint == packets[0].pipe->endpoint->endpoint_address))
         {
             break;
         }
@@ -254,100 +263,143 @@ static int ohci_do_packet(struct usb_packet* packet)
     if (edsc == NULL) {
         return USB_TIMEOUT; //Genau das würde passieren
     }
-    if (mempool_get(ohci->transfer_pool, (void**) &vtd, &ptd) == -1) {
-        return USB_TRIVIAL_ERROR;
-    }
-    if ((packet->data != NULL) && (packet->type != PACKET_IN)) {
-        memcpy((void*) vtd + sizeof(struct ohci_td), packet->data,
-            packet->length);
-    }
-    vtd->rounding = 1; //Warum nicht
-    switch (packet->type) {
-        case PACKET_SETUP:
-            vtd->direction = OHC_TD_DIR_SETUP;
-            break;
-        case PACKET_IN:
-            vtd->direction = OHC_TD_DIR_IN;
-            break;
-        case PACKET_OUT:
-            vtd->direction = OHC_TD_DIR_OUT;
-            break;
-        default:
-            mempool_put(ohci->transfer_pool, vtd);
-            return USB_TRIVIAL_ERROR; //Hm, passt nicht ganz
-    }
-    vtd->di = 0;
-    vtd->toggle = 0x2 | packet->pipe->data_toggle;
-    vtd->error = 0;
-    vtd->condition = 15;
-    if ((packet->data == NULL) || !packet->length) {
-        vtd->current_buffer_pointer = 0;
-        vtd->buffer_end = 0;
-    } else {
-        vtd->current_buffer_pointer = ptd + sizeof(struct ohci_td);
-        vtd->buffer_end = ptd + sizeof(struct ohci_td) + packet->length - 1;
-    }
-    vtd->next_td = 0;
-    tdsc = malloc(sizeof(*tdsc));
-    if (tdsc == NULL) {
-        mempool_put(ohci->transfer_pool, vtd);
-        return USB_TRIVIAL_ERROR;
-    }
-    tdsc->virt = vtd;
-    tdsc->phys = ptd;
-    tdsc->endpoint = edsc;
-    if (cdi_list_size(edsc->transfers)) {
-        otdsc = cdi_list_get(edsc->transfers, cdi_list_size(
-                edsc->transfers) - 1);
-        otdsc->virt->next_td = ptd;
-    }
-    cdi_list_insert(edsc->transfers, cdi_list_size(edsc->transfers), tdsc);
-    if (!edsc->virt->td_queue_head) {
-        edsc->virt->td_queue_head = ptd;
+    toggle = packets[0].pipe->data_toggle;
+    for (i = 0; i < num_packets; i++) {
+        if (mempool_get(ohci->transfer_pool, (void**) &vtd[i],
+                &ptd[i]) == -1)
+        {
+            return USB_TRIVIAL_ERROR;
+        }
+        if ((packets[i].data != NULL) && (packets[i].type != PACKET_IN)) {
+            memcpy((void*) vtd[i] + sizeof(struct ohci_td), packets[i].data,
+                packets[i].length);
+        }
+        vtd[i]->rounding = 1; //Warum nicht
+        switch (packets[i].type) {
+            case PACKET_SETUP:
+                vtd[i]->direction = OHC_TD_DIR_SETUP;
+                break;
+            case PACKET_IN:
+                vtd[i]->direction = OHC_TD_DIR_IN;
+                break;
+            case PACKET_OUT:
+                vtd[i]->direction = OHC_TD_DIR_OUT;
+                break;
+            default: //Hm, passt nicht ganz
+                for (j = 0; j <= i; j++) {
+                    mempool_put(ohci->transfer_pool, vtd[j]);
+                }
+                return USB_TRIVIAL_ERROR;
+        }
+        vtd[i]->di = 0;
+        if (packets[i].use_toggle == TOGGLE_0) {
+            toggle = 0;
+        } else if (packets[i].use_toggle == TOGGLE_1) {
+            toggle = 1;
+        }
+        vtd[i]->toggle = 0x2 | toggle;
+        toggle ^= 1;
+        vtd[i]->error = 0;
+        vtd[i]->condition = 15;
+        if ((packets[i].data == NULL) || !packets[i].length) {
+            vtd[i]->current_buffer_pointer = 0;
+            vtd[i]->buffer_end = 0;
+        } else {
+            vtd[i]->current_buffer_pointer = ptd[i] + sizeof(struct ohci_td);
+            vtd[i]->buffer_end = ptd[i] + sizeof(struct ohci_td) +
+                                 packets[i].length - 1;
+        }
+        vtd[i]->next_td = 0;
+        tdsc = malloc(sizeof(*tdsc));
+        if (tdsc == NULL) {
+            for (j = 0; j <= i; j++) {
+                mempool_put(ohci->transfer_pool, vtd[j]);
+            }
+            return USB_TRIVIAL_ERROR;
+        }
+        tdsc->virt = vtd[i];
+        tdsc->phys = ptd[i];
+        tdsc->endpoint = edsc;
+
+        while (tsl(&locked)) {
+#ifndef CDI_STANDALONE
+            __asm__ __volatile__ ("hlt");
+#endif
+        }
+        if (cdi_list_size(edsc->transfers)) {
+            otdsc = cdi_list_get(edsc->transfers, 0);
+            otdsc->virt->next_td = ptd[i];
+        }
+        if (!edsc->virt->td_queue_head) {
+            edsc->virt->td_queue_head = ptd[i];
+        }
+        locked = 0;
+
+        cdi_list_push(edsc->transfers, tdsc);
     }
+    packets[0].pipe->data_toggle = toggle;
     if (edsc->type == USB_CONTROL) {
         ohci->memory->hc_command_status |= OHC_CMST_CLF;
     } else if (edsc->type == USB_BULK) {
         ohci->memory->hc_command_status |= OHC_CMST_BLF;
     }
-    while (vtd->condition == 15) {
+    done_packets = 0;
+    cond = USB_NO_ERROR;
+    while (done_packets < num_packets) {
         cdi_sleep_ms(1);
+        for (i = 0; i < num_packets; i++) {
+            if (vtd[i]->condition != 15) {
+                done_packets++;
+                switch (vtd[i]->condition) {
+                    case 0x00:
+                        packets[i].condition = USB_NO_ERROR;
+                        break;
+                    case 0x02:
+                        packets[i].condition = USB_BITSTUFF;
+                        break;
+                    case 0x04:
+                        packets[i].condition = USB_STALLED;
+                        for (j = 0; j < num_packets; j++) {
+                            vtd[j]->condition = 0x04; //Allet, was nicht fertig ist, ist STALLed
+                        }
+                        break;
+                    case 0x05:
+                        packets[i].condition = USB_TIMEOUT;
+                        break;
+                    case 0x08:
+                        packets[i].condition = USB_BABBLE;
+                        break;
+                    case 0x0C:
+                    case 0x0D:
+                        packets[i].condition = USB_BUFFER_ERROR;
+                        break;
+                    default:
+                        packets[i].condition = USB_CRC;
+                        break;
+                }
+                cond |= packets[i].condition;
+                vtd[i]->condition = 15; //Nicht nochmal überprüfen
+            }
+        }
     }
-    cond = vtd->condition;
-    if ((packet->data != NULL) && (packet->type == PACKET_IN)) {
-        memcpy(packet->data, (void*) vtd + sizeof(struct ohci_td),
-            packet->length);
+    for (i = 0; i < num_packets; i++) {
+        if ((packets[i].data != NULL) && (packets[i].type == PACKET_IN)) {
+            memcpy(packets[i].data, (void*) vtd[i] + sizeof(struct ohci_td),
+                packets[i].length);
+        }
+        if (vtd[i]->next_td == 0) {
+            edsc->virt->td_queue_head = 0;
+        }
+        mempool_put(ohci->transfer_pool, vtd[i]);
     }
-    if (vtd->next_td == 0) {
+    if (cond & USB_STALLED) { //Transferliste für diesen Endpoint leeren
         edsc->virt->td_queue_head = 0;
+        while ((tdsc = cdi_list_pop(edsc->transfers)) != NULL) {
+            free(tdsc);
+        }
+        edsc->virt->td_queue_tail = 0; //Weitermachen
     }
-    mempool_put(ohci->transfer_pool, vtd);
-    switch (cond) {
-        case 0x00:
-            return USB_NO_ERROR;
-        case 0x01:
-            return USB_CRC;
-        case 0x02:
-            return USB_BITSTUFF;
-        case 0x03: //Datatoggle-Fehler
-            return USB_CRC;
-        case 0x04:
-            return USB_STALLED;
-        case 0x05:
-            return USB_TIMEOUT;
-        case 0x06: //PID-Fehler
-        case 0x07: //Ebenso
-            return USB_CRC;
-        case 0x08:
-            return USB_BABBLE;
-        case 0x09: //Data underrun
-            return USB_CRC;
-        case 0x0C: //Buffer overrun
-        case 0x0D: //Buffer underrun
-            return USB_BUFFER_ERROR;
-        default: //Ã?hm...
-            return USB_CRC;
-    }
+    return cond;
 }
 
 static cdi_list_t get_devices(struct hci* gen_hci)
@@ -440,13 +492,6 @@ static void ohci_establish_pipe(struct usb_pipe* pipe)
     dsc->transfers = cdi_list_create();
     cdi_list_push(ohci->ed_list, dsc);
 
-    dprintf(
-        "%s-Endpoint %i (Gerät %i) hinzugefügt (%s)\n",
-        iscontrol ? "Control" : "Bulk", ved->endpoint, ved->function,
-        (ved->direction ==
-         OHC_ED_DIR_TD) ? "IN/OUT/SETUP" : ((ved->direction ==
-                                             OHC_ED_DIR_IN) ? "IN" : "OUT"));
-
     if (iscontrol) {
         ohci->memory->hc_control_head_ed = ped;
     } else {
@@ -485,6 +530,7 @@ static void ohci_handler(struct cdi_device* dev)
             {
                 if (tdsc->phys == phys) { //Das ist der fertige Transfer
                     cdi_list_remove(edsc->transfers, j);
+                    free(tdsc);
                     break;
                 }
             }
diff --git a/usb/uhci.c b/usb/uhci.c
index 405a879..bad63bb 100644
--- a/usb/uhci.c
+++ b/usb/uhci.c
@@ -54,7 +54,7 @@ static struct cdi_driver cdi_driver;
 static cdi_list_t active_transfers;
 
 static void uhci_handler(struct cdi_device* dev);
-static int uhci_do_packet(struct usb_packet* packet);
+static int uhci_do_packets(struct usb_packet* packets, int num_packets);
 static cdi_list_t get_devices(struct hci* gen_hci);
 static void activate_device(struct usb_device* device);
 static void uhci_deinit(struct cdi_device* cdi_hci);
@@ -184,7 +184,7 @@ void uhci_init(struct cdi_device* cdi_hci)
     dprintf("  Fertig\n");
     gen_hci->find_devices = &get_devices;
     gen_hci->activate_device = &activate_device;
-    gen_hci->do_packet = &uhci_do_packet;
+    gen_hci->do_packets = &uhci_do_packets;
     gen_hci->add_pipe = &uhci_establish_pipe;
 
     enumerate_hci(gen_hci);
@@ -262,7 +262,13 @@ static int uhci_do_packet(struct usb_packet* packet)
     td.next = 1; //Invalid
     td.active = 1;
     td.ioc = 1;
+    if (packet->use_toggle == TOGGLE_0) {
+        packet->pipe->data_toggle = 0;
+    } else if (packet->use_toggle == TOGGLE_1) {
+        packet->pipe->data_toggle = 1;
+    }
     td.data_toggle = packet->pipe->data_toggle;
+    packet->pipe->data_toggle ^= 1;
     td.low_speed = usbdev->low_speed;
     td.errors = 1;
     td.pid = packet->type;
@@ -330,6 +336,19 @@ static int uhci_do_packet(struct usb_packet* packet)
     return addr.error;
 }
 
+static int uhci_do_packets(struct usb_packet* packet, int num_packets)
+{
+    int i, cond = 0;
+
+    //TODO
+    for (i = 0; i < num_packets; i++) {
+        packet[i].condition = uhci_do_packet(&packet[i]);
+        cond |= packet[i].condition;
+    }
+
+    return cond;
+}
+
 static void uhci_handler(struct cdi_device* cdi_hci)
 {
     struct uhci* uhci = (struct uhci*) ((struct cdi_hci*) cdi_hci)->hci;
-- 
1.6.3.3