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

[cdi-devel] [PATCH] Double reset on enum, no toggle change on error



From: Max Reitz <max@xxxxxxxxxx>

* Reset is needed two times on device enumeration (before reading the
  first eight bytes of the device descriptor and afterwards).
* DATA0/DATA1 toggle bit may not be changed if an error occured.

Signed-off-by: Max Reitz <max@xxxxxxxxxx>
---
 usb/include/usb.h |    2 +
 usb/main.c        |   37 ++++++++++++++++++++---------
 usb/msd.c         |   66 +++++++++++++++++++++++++---------------------------
 usb/uhci.c        |   17 ++++++++++++-
 4 files changed, 74 insertions(+), 48 deletions(-)

diff --git a/usb/include/usb.h b/usb/include/usb.h
index 0fc6567..9a94b2e 100644
--- a/usb/include/usb.h
+++ b/usb/include/usb.h
@@ -242,6 +242,7 @@ struct class_data {
 
 struct usb_device {
     struct hci* hci;
+    struct usb_device* hub;
     int id;
     int port;
     int low_speed;
@@ -254,6 +255,7 @@ struct usb_device {
     int locked;
     int expects;
     int data_toggle;
+    void (* reset)(struct usb_device* device);
 };
 
 struct msclass_data {
diff --git a/usb/main.c b/usb/main.c
index abfb936..7250092 100644
--- a/usb/main.c
+++ b/usb/main.c
@@ -142,8 +142,12 @@ int usb_do_packet(struct usb_device* device, struct usb_packet* packet)
                 cdi_sleep_ms(5);
             }
         }
-        device->data_toggle ^= 1;
-        send_packet.data += mps;
+        if (error != USB_NO_ERROR) {
+            i -= mps;
+        } else {
+            device->data_toggle ^= 1;
+            send_packet.data += mps;
+        }
         if (error == USB_STALLED) {
             printf("[usb] ENDPOINT %i DES GERÃ?TS %i STALLED!\n",
                 packet->endpoint->endpoint_address,
@@ -167,11 +171,9 @@ static void* do_control(struct usb_device* device, int direction, void* buffer,
 
     no_data = direction & NO_DATA;
     direction &= 0x80;
-
     if ((direction != HOST_TO_DEV) || !length || (buffer == NULL)) {
         buffer = malloc(length);
     }
-
     setup->request_type = direction | (rtype & 0x60) | (recipient & 0x1F);
     setup->request = request;
     setup->value = value;
@@ -192,7 +194,7 @@ static void* do_control(struct usb_device* device, int direction, void* buffer,
 
     if (no_data) {
         rval = USB_NO_ERROR;
-        buffer = (void*) 0xFFFFFFFF;      //Kein Fehler, aber auch keine Daten
+        buffer = (void*) 0xFFFFFFFF;    //Kein Fehler, aber auch keine Daten
     } else {
         struct usb_packet data_packet = {
             .type         = (direction == DEV_TO_HOST ? PACKET_IN : PACKET_OUT),
@@ -225,7 +227,7 @@ static void* do_control(struct usb_device* device, int direction, void* buffer,
 
         rval = usb_do_packet(device, &ack_packet);
     }
-    return (rval == USB_NO_ERROR) ? buffer: NULL;
+    return (rval == USB_NO_ERROR) ? buffer : NULL;
 }
 
 static void usb_init(void)
@@ -325,6 +327,9 @@ static void enum_device(struct usb_device* usbdev)
     usbdev->ep0->max_packet_size = 8;
     usbdev->ep0->interval = 0;
 
+    //Resetten
+    usbdev->reset(usbdev);
+
     //Erste acht Bytes des Device-Descriptors abrufen und die maximale Paketgrö�e von EP0 feststellen
     dev_desc =
         do_control(usbdev, DEV_TO_HOST, NULL, 8, STD_REQUEST, REC_DEVICE,
@@ -336,12 +341,16 @@ static void enum_device(struct usb_device* usbdev)
     }
     usbdev->ep0->max_packet_size = dev_desc->max_packet_size0;
 
+    //Nochmals resetten
+    usbdev->reset(usbdev);
+
     //USB-Adresse zuweisen
     do_control(usbdev, HOST_TO_DEV | NO_DATA, NULL, 0, STD_REQUEST, REC_DEVICE,
         SET_ADDRESS, (id = usb_dev_ids++),
         0);
     usbdev->id = id;
 
+    //Den ganzen Device-Descriptor einlesen
     dev_desc =
         do_control(usbdev, DEV_TO_HOST, NULL, sizeof(*dev_desc), STD_REQUEST,
             REC_DEVICE, GET_DESCRIPTOR, DESC_DEVICE << 8,
@@ -454,6 +463,14 @@ static void enum_device(struct usb_device* usbdev)
     }
 }
 
+static void reset_hub_device(struct usb_device* usbdev)
+{
+    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 usb_device* usbdev)
 {
     struct hub_desc* hub_desc;
@@ -481,17 +498,13 @@ static void enumerate_hub(struct usb_device* usbdev)
             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->hub = usbdev;
         down->id = 0;
         down->port = i;
         down->low_speed = (port_status[0] & PORT_LOWSPEED) && 1;
+        down->reset = &reset_hub_device;
         enum_device(down);
     }
 }
diff --git a/usb/msd.c b/usb/msd.c
index 9d843bf..6fb8a42 100644
--- a/usb/msd.c
+++ b/usb/msd.c
@@ -367,10 +367,12 @@ static inline int tsl(volatile int* variable)
 }
 
 static uint32_t msd_read(struct usb_device* usbdev, uint32_t lba,
-    uint16_t sectors, void* buffer, size_t length);
+    uint16_t sectors, void* buffer,
+    size_t length);
 
 static int msd_cdi_read(struct cdi_storage_device* strgdev, uint64_t start,
-    uint64_t count, void* buffer)
+    uint64_t count,
+    void* buffer)
 {
     int bs = strgdev->block_size, error;
 #ifdef WAIT_FOR_MSD_READY
@@ -394,7 +396,6 @@ static int msd_cdi_read(struct cdi_storage_device* strgdev, uint64_t start,
     for (i = 0; !msd_ready(usbdev) && (i < 10); i++) {
         cdi_sleep_ms(20);
     }
-
 #endif
     error = msd_read(usbdev, start, count, buffer, count * bs);
     if (error != USB_NO_ERROR) {
@@ -407,7 +408,8 @@ static int msd_cdi_read(struct cdi_storage_device* strgdev, uint64_t start,
 }
 
 static uint32_t msd_read(struct usb_device* usbdev, uint32_t lba,
-    uint16_t sectors, void* buffer, size_t length)
+    uint16_t sectors, void* buffer,
+    size_t length)
 {
     struct msclass_data* msc;
     struct command_block_wrapper _cbw;
@@ -415,10 +417,9 @@ static uint32_t msd_read(struct usb_device* usbdev, uint32_t lba,
     uint32_t expected_tag;
     int error;
 
-    if (!buffer || !length) {
+    if ((buffer == NULL) || !length) {
         return USB_TRIVIAL_ERROR;
     }
-
     msc = (struct msclass_data*) usbdev->classd;
     memset(cbw, 0, 0x1F);
     cbw->cbw_signature = CBW_SIGNATURE;
@@ -463,57 +464,59 @@ static uint32_t msd_read(struct usb_device* usbdev, uint32_t lba,
 }
 
 static uint32_t msd_write(struct usb_device* usbdev, uint32_t lba,
-    uint16_t sectors, void* buffer, size_t length);
+    uint16_t sectors, void* buffer,
+    size_t length);
 
 static int msd_cdi_write(struct cdi_storage_device* strgdev, uint64_t start,
-    uint64_t count, void* buffer)
+    uint64_t count,
+    void* buffer)
 {
     int bs = strgdev->block_size, error;
 #ifdef WAIT_FOR_MSD_READY
-    int j;
+    int i;
 #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 (!count) {
+        dprintf("Leere Schreibanfrage.\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);
-        }
-
+    for (i = 0; !msd_ready(usbdev) && (i < 10); i++) {
+        cdi_sleep_ms(20);
+    }
 #endif
-        error = msd_write(usbdev, start + i, 1, buffer + i * bs, bs);
-        if (error != USB_NO_ERROR) {
-            dprintf("Schreibfehler 0x%X bei Block %i.\n", error, i);
-            usbdev->locked = 0;
-            return -1;
-        }
+    error = msd_write(usbdev, start, count, buffer, count * bs);
+    if (error != USB_NO_ERROR) {
+        dprintf("Schreibfehler 0x%X bei Block %i.\n", error, start);
+        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, void* buffer, size_t length)
+    uint16_t sectors, void* buffer,
+    size_t length)
 {
     struct msclass_data* msc;
     struct command_block_wrapper _cbw;
     struct command_block_wrapper* cbw = &_cbw;
     uint32_t expected_tag;
-    int error, i, ep_size;
+    int error;
 
-    if (!buffer || !length) {
+    if ((buffer == NULL) || !length) {
         return USB_TRIVIAL_ERROR;
     }
-
     msc = (struct msclass_data*) usbdev->classd;
     memset(cbw, 0, 0x1F);
     cbw->cbw_signature = CBW_SIGNATURE;
@@ -540,18 +543,13 @@ static uint32_t msd_write(struct usb_device* usbdev, uint32_t lba,
         .type         = PACKET_OUT,
         .endpoint     = msc->bulk_ep_out,
         .data         = buffer,
-        .length       = 0,
+        .length       = length,
         .type_of_data = USB_TOD_DATA_OUT,
     };
 
-    ep_size = msc->bulk_ep_out->max_packet_size;
-    for (i = 0; i < length; i += ep_size) {
-        out_packet.length = (length - i > ep_size) ? ep_size : length - i;
-        error = usb_do_packet(usbdev, &out_packet);
-        if (error != USB_NO_ERROR) {
-            return error;
-        }
-        out_packet.data += ep_size;
+    error = usb_do_packet(usbdev, &out_packet);
+    if (error != USB_NO_ERROR) {
+        return error;
     }
 
     error = read_status(usbdev, expected_tag);
diff --git a/usb/uhci.c b/usb/uhci.c
index 03ad4c6..d302364 100644
--- a/usb/uhci.c
+++ b/usb/uhci.c
@@ -59,6 +59,7 @@ 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);
+static void uhci_reset_device(struct usb_device* device);
 
 
 struct cdi_driver* init_uhcd()
@@ -184,19 +185,29 @@ static cdi_list_t get_devices(struct hci* gen_hci)
         dev->port = i;
         dev->low_speed =
             (cdi_inw(uhci->pbase + UHCI_RPORTS + 2 * i) & RPORT_LOSPD) && 1;
+        dev->reset = &uhci_reset_device;
         cdi_list_push(dlist, dev);
     }
     _dprintf("\n");
     return dlist;
 }
 
+static void uhci_reset_device(struct usb_device* device)
+{
+    struct uhci* uhci = (struct uhci*) device->hci;
+
+    cdi_outw(uhci->pbase + UHCI_RPORTS + 2 * device->port,
+        RPORT_ENABLE | RPORT_RESET | RPORT_CSC);
+    cdi_sleep_ms(20);
+}
+
 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);
+        RPORT_ENABLE | RPORT_CSC);
     cdi_sleep_ms(20);
 }
 
@@ -243,7 +254,9 @@ static int uhci_do_packet(struct usb_device* usbdev, struct usb_packet* packet)
         data = NULL;
         phys_data = 0;
     } else {
-        if (cdi_alloc_phys_mem(packet->length, &data, (void**) &phys_data) == -1) {
+        if (cdi_alloc_phys_mem(packet->length, &data,
+                (void**) &phys_data) == -1)
+        {
             return USB_TRIVIAL_ERROR;
         }
         if (packet->type != PACKET_IN) {
-- 
1.6.3.3