瀏覽代碼

usb: Double-buffered IN pipes.

Keir Fraser 5 年之前
父節點
當前提交
8df3305ac3
共有 3 個文件被更改,包括 53 次插入24 次删除
  1. 3 3
      src/floppy.c
  2. 1 1
      src/usb/cdc_acm.c
  3. 49 20
      src/usb/hw_f1.c

+ 3 - 3
src/floppy.c

@@ -893,9 +893,9 @@ void floppy_process(void)
         floppy_motor(FALSE);
         drive_deselect();
         auto_off.armed = FALSE;
-        gpio_write_pin(gpioa, 0, LOW);
-        delay_ms(100); /* XXX */
-        gpio_write_pin(gpioa, 0, HIGH);
+        //gpio_write_pin(gpioa, 0, LOW);
+        //delay_ms(100); /* force disconnect */
+        //gpio_write_pin(gpioa, 0, HIGH);
     }
 
     switch (floppy_state) {

+ 1 - 1
src/usb/cdc_acm.c

@@ -97,7 +97,7 @@ bool_t cdc_acm_set_configuration(void)
     /* Bulk Pipe (H->D) */
     usb_configure_ep(0x02, USB_EP_TYPE_BULK, 2*USB_FS_MPS);
     /* Bulk Pipe (D->H) */
-    usb_configure_ep(0x83, USB_EP_TYPE_BULK, USB_FS_MPS);
+    usb_configure_ep(0x83, USB_EP_TYPE_BULK, 2*USB_FS_MPS);
 
     floppy_configured();
 

+ 49 - 20
src/usb/hw_f1.c

@@ -122,26 +122,46 @@ void usb_read(uint8_t ep, void *buf, uint32_t len)
 
 void usb_write(uint8_t ep, const void *buf, uint32_t len)
 {
-    unsigned int i, base = (uint16_t)usb_bufd[ep].addr_tx >> 1;
-    uint16_t epr;
+    unsigned int i, base;
+    uint16_t epr = usb->epr[ep];
     const uint16_t *p = buf;
+    volatile struct usb_bufd *bd = &usb_bufd[ep];
+
+    if (epr & USB_EPR_EP_KIND_DBL_BUF) {
+        if (epr & 0x4000) {
+            base = bd->addr_1;
+            bd->count_1 = len;
+        } else {
+            base = bd->addr_0;
+            bd->count_0 = len;
+        }
+        /* If HW is pointing at same buffer as us, we have space for two
+         * packets, and do not need to clear tx_ready. */
+        if ((epr ^ (epr>>8)) & 0x40)
+            eps[ep].tx_ready = FALSE;
+    } else {
+        base = bd->addr_tx;
+        bd->count_tx = len;
+        eps[ep].tx_ready = FALSE;
+    }
+    base = (uint16_t)base >> 1;
 
     for (i = 0; i < len/2; i++)
         usb_buf[base + i] = *p++;
     if (len&1)
         usb_buf[base + i] = *(const uint8_t *)p;
 
-    usb_bufd[ep].count_tx = len;
-
-    /* Set status NAK->VALID. */
-    epr = usb->epr[ep];
-    epr &= 0x073f;
-    epr |= 0x8080;
-    epr ^= USB_EPR_STAT_TX(USB_STAT_VALID);
+    if (epr & USB_EPR_EP_KIND_DBL_BUF) {
+        /* Toggle SW_BUF. Status remains VALID at all times. */
+        epr &= 0x070f; /* preserve rw & t fields */
+        epr |= 0xc080; /* preserve rc_w0 fields, toggle SW_BUF */
+    } else {
+        /* Set status NAK->VALID. */
+        epr &= 0x073f; /* preserve rw & t fields (except STAT_TX) */
+        epr |= 0x8080; /* preserve rc_w0 fields */
+        epr ^= USB_EPR_STAT_TX(USB_STAT_VALID); /* modify STAT_TX */
+    }
     usb->epr[ep] = epr;
-
-    /* Await next CTR_TX notification. */
-    eps[ep].tx_ready = FALSE;
 }
 
 static void usb_write_ep0(void)
@@ -193,27 +213,36 @@ void usb_configure_ep(uint8_t ep, uint8_t type, uint32_t size)
 
     dbl_buf = (size > USB_FS_MPS);
     if (dbl_buf) {
+        ASSERT(ep != 0);
         ASSERT(type == USB_EP_TYPE_BULK);
         ASSERT(size == 2*USB_FS_MPS);
         new_epr |= USB_EPR_EP_KIND_DBL_BUF;
+        bd->addr_0 = buf_end;
+        bd->addr_1 = buf_end + size/2;
+        buf_end += size;
     }
 
     if (in || (ep == 0)) {
-        bd->addr_tx = buf_end;
-        buf_end += size;
-        bd->count_tx = 0;
-        /* TX: Clears data toggle and sets status to NAK. */
-        new_epr |= (old_epr & 0x0070) ^ USB_EPR_STAT_TX(USB_STAT_NAK);
+        if (dbl_buf) {
+            bd->count_0 = bd->count_1 = 0;
+            /* TX: Clears SW_BUF. */
+            new_epr |= old_epr & 0x4000;
+            /* TX: Clears data toggle and sets status to VALID. */
+            new_epr |= (old_epr & 0x0070) ^ USB_EPR_STAT_TX(USB_STAT_VALID);
+        } else {
+            bd->addr_tx = buf_end;
+            buf_end += size;
+            bd->count_tx = 0;
+            /* TX: Clears data toggle and sets status to NAK. */
+            new_epr |= (old_epr & 0x0070) ^ USB_EPR_STAT_TX(USB_STAT_NAK);
+        }
         /* IN Endpoint is immediately ready to transmit. */
         eps[ep].tx_ready = TRUE;
     }
 
     if (!in) {
         if (dbl_buf) {
-            bd->addr_0 = buf_end;
-            bd->addr_1 = buf_end + size/2;
             bd->count_0 = bd->count_1 = 0x8400; /* USB_FS_MPS = 64 bytes */
-            buf_end += size;
             /* RX: Clears SW_BUF. */
             new_epr |= old_epr & 0x0040;
         } else {