]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Allow psartial transfers and use them for usbserial
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Mon, 19 Jul 2010 06:43:01 +0000 (08:43 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Mon, 19 Jul 2010 06:43:01 +0000 (08:43 +0200)
bus/usb/ohci.c
bus/usb/serial/common.c
bus/usb/serial/ftdi.c
bus/usb/serial/pl2303.c
bus/usb/uhci.c
bus/usb/usbtrans.c
include/grub/serial.h
include/grub/usb.h
include/grub/usbserial.h
include/grub/usbtrans.h

index 73e3e01e8fecabb9f92900e54d2f732eaed7382b..d8abb343acb26de6b21fc132a4b843bbf76060ea 100644 (file)
@@ -654,7 +654,8 @@ grub_ohci_transaction (grub_ohci_td_t td,
 
 static grub_usb_err_t
 grub_ohci_transfer (grub_usb_controller_t dev,
-                   grub_usb_transfer_t transfer, int timeout)
+                   grub_usb_transfer_t transfer, int timeout,
+                   grub_size_t *actual)
 {
   struct grub_ohci *o = (struct grub_ohci *) dev->data;
   grub_ohci_ed_t ed_virt;
@@ -680,6 +681,8 @@ grub_ohci_transfer (grub_usb_controller_t dev,
   int err_unrec = 0;
   grub_uint32_t intstatus;
 
+  *actual = 0;
+
   /* Pre-set target for ED - we need it to find proper ED */
   /* Set the device address.  */
   target = transfer->devaddr;
@@ -1078,12 +1081,14 @@ grub_ohci_transfer (grub_usb_controller_t dev,
 
        case 9:
          /* XXX: Data underrun error.  */
-         err = GRUB_USB_ERR_DATA;
          grub_dprintf ("ohci", "Underrun, failed TD address: %p, index: %d\n",
                        tderr_virt, tderr_virt->tr_index);
-         grub_dprintf ("ohci", "Underrun, number of not transferred bytes: %d\n",
-                       1 + grub_le_to_cpu32 (tderr_virt->buffer_end)
-                         - grub_le_to_cpu32 (tderr_virt->buffer));
+         if (transfer->last_trans == -1)
+           break;
+         *actual = transfer->transactions[transfer->last_trans].size
+           - (grub_le_to_cpu32 (tderr_virt->buffer_end)
+              - grub_le_to_cpu32 (tderr_virt->buffer))
+           + transfer->transactions[transfer->last_trans].preceding;
          break;
 
        case 10:
@@ -1172,12 +1177,12 @@ grub_ohci_transfer (grub_usb_controller_t dev,
         transfer->last_trans = tderr_virt->tr_index;
       else
         transfer->last_trans = -1;
-
     }
+  else
+    *actual = transfer->size;
 
-    /* Set empty ED - set HEAD = TAIL = last (not processed) TD */
-    ed_virt->td_head = grub_cpu_to_le32 ( grub_le_to_cpu32 (
-                                            ed_virt->td_tail) & ~0xf); 
+  /* Set empty ED - set HEAD = TAIL = last (not processed) TD */
+  ed_virt->td_head = grub_cpu_to_le32 (grub_le_to_cpu32 (ed_virt->td_tail) & ~0xf); 
 
   /* At this point always should be:
    * ED has skip bit set and halted or empty or after next SOF,
index 1da1c5bcf6657cb90c50223a0af94b6a55448d5c..6b5b9005903be28d3bf3d105a3e833a78feffdec 100644 (file)
@@ -100,3 +100,26 @@ grub_usbserial_attach (grub_usb_device_t usbdev, int configno, int interfno,
 
   return 1;
 }
+
+int
+grub_usbserial_fetch (struct grub_serial_port *port, grub_size_t header_size)
+{
+  grub_usb_err_t err;
+  grub_size_t actual;
+
+  if (port->bufstart < port->bufend)
+    return port->buf[port->bufstart++];
+
+  err = grub_usb_bulk_read_extended (port->usbdev, port->in_endp->endp_addr,
+                                    sizeof (port->buf), port->buf, 10,
+                                    &actual);
+  if (err != GRUB_USB_ERR_NONE)
+    return -1;
+
+  port->bufstart = header_size;
+  port->bufend = actual;
+  if (port->bufstart >= port->bufend)
+    return -1;
+
+  return port->buf[port->bufstart++];
+}
index a4d88dbae9803bcd917f18acfbfdbfb19fd38b6a..bd1713b27c046d3b04c794ce21a5cf65de377c70 100644 (file)
@@ -111,16 +111,9 @@ real_config (struct grub_serial_port *port)
 static int
 ftdi_hw_fetch (struct grub_serial_port *port)
 {
-  char cc[3];
-  grub_usb_err_t err;
-
   real_config (port);
 
-  err = grub_usb_bulk_read (port->usbdev, port->in_endp->endp_addr, 3, cc);
-  if (err != GRUB_USB_ERR_NONE)
-    return -1;
-
-  return cc[2];
+  return grub_usbserial_fetch (port, 2);
 }
 
 /* Put a character.  */
index e2dcd606e5be788a82275d6cbde34034930b68d7..9e3b9ae7eb948e38e8546878a0eefae6fee3ed10 100644 (file)
@@ -127,26 +127,9 @@ real_config (struct grub_serial_port *port)
 static int
 pl2303_hw_fetch (struct grub_serial_port *port)
 {
-  grub_usb_err_t err;
-
   real_config (port);
 
-  if (port->bufstart < port->bufend)
-    return port->buf[port->bufstart++];
-
-  err = grub_usb_bulk_read_timeout (port->usbdev, port->in_endp->endp_addr,
-                                   sizeof (port->buf), port->buf, 10);
-  if (err != GRUB_USB_ERR_NONE)
-    return -1;
-
-  port->bufstart = 0;
-  /* FIXME: nearly always only one byte is transfered.
-     It happens however that more are transfered.
-     Setting sizeof (port->buf) to 1 leads code to stop reading after
-     such transfer.  */
-  port->bufend = 1;
-
-  return port->buf[port->bufstart++];
+  return grub_usbserial_fetch (port, 0);
 }
 
 /* Put a character.  */
index d211de369cbeb6ca6655d6ec1872e532ced60f17..69fae60fd46ae7725d6720cbdb5560e7e9277450 100644 (file)
@@ -75,8 +75,10 @@ struct grub_uhci_td
      This is GRUB specific.  */
   grub_uint32_t linkptr2;
 
-  /* 3 additional 32 bits words reserved for the Host Controller Driver.  */
-  grub_uint32_t data[3];
+  grub_uint32_t buffer0;
+
+  /* 2 additional 32 bits words reserved for the Host Controller Driver.  */
+  grub_uint32_t data[2];
 } __attribute__ ((packed));
 
 typedef volatile struct grub_uhci_td *grub_uhci_td_t;
@@ -333,9 +335,11 @@ grub_free_td (struct grub_uhci *u, grub_uhci_td_t td)
 
 static void
 grub_free_queue (struct grub_uhci *u, grub_uhci_td_t td,
-                 grub_usb_transfer_t transfer)
+                 grub_usb_transfer_t transfer, grub_size_t *actual)
 {
   int i; /* Index of TD in transfer */
+
+  *actual = 0;
   
   /* Free the TDs in this queue and set last_trans.  */
   for (i=0; td; i++)
@@ -345,6 +349,8 @@ grub_free_queue (struct grub_uhci *u, grub_uhci_td_t td,
       /* Check state of TD and possibly set last_trans */
       if (transfer && (td->linkptr & 1))
         transfer->last_trans = i;
+
+      *actual += (td->ctrl_status + 1) & 0x7ff;
       
       /* Unlink the queue.  */
       tdprev = td;
@@ -430,6 +436,7 @@ grub_uhci_transaction (struct grub_uhci *u, unsigned int endp,
               | (addr << 8) | tf[type]);
 
   td->buffer = data;
+  td->buffer0 = data;
 
   return td;
 }
@@ -437,7 +444,7 @@ grub_uhci_transaction (struct grub_uhci *u, unsigned int endp,
 static grub_usb_err_t
 grub_uhci_transfer (grub_usb_controller_t dev,
                    grub_usb_transfer_t transfer,
-                   int timeout)
+                   int timeout, grub_size_t *actual)
 {
   struct grub_uhci *u = (struct grub_uhci *) dev->data;
   grub_uhci_qh_t qh;
@@ -448,10 +455,12 @@ grub_uhci_transfer (grub_usb_controller_t dev,
   int i;
   grub_uint64_t endtime;
 
+  *actual = 0;
+
   /* Allocate a queue head for the transfer queue.  */
   qh = grub_alloc_qh (u, GRUB_USB_TRANSACTION_TYPE_CONTROL);
   if (! qh)
-    return grub_errno;
+    return GRUB_USB_ERR_INTERNAL;
 
   grub_dprintf ("uhci", "transfer, iobase:%08x\n", u->iobase);
   
@@ -469,7 +478,7 @@ grub_uhci_transfer (grub_usb_controller_t dev,
          td_prev->linkptr = 1;
 
          if (td_first)
-           grub_free_queue (u, td_first, NULL);
+           grub_free_queue (u, td_first, NULL, actual);
 
          return GRUB_USB_ERR_INTERNAL;
        }
@@ -563,7 +572,7 @@ grub_uhci_transfer (grub_usb_controller_t dev,
   /* Place the QH back in the free list and deallocate the associated
      TDs.  */
   qh->elinkptr = 1;
-  grub_free_queue (u, td_first, transfer);
+  grub_free_queue (u, td_first, transfer, actual);
 
   return err;
 }
index 9dfef509f771cc300bc1f04eae28fc45042166df..db2ec097a896db44f5edd6cdcfa907b81b07162f 100644 (file)
@@ -43,6 +43,7 @@ grub_usb_control_msg (grub_usb_device_t dev,
   volatile char *data;
   grub_uint32_t data_addr;
   grub_size_t size = size0;
+  grub_size_t actual;
 
   /* FIXME: avoid allocation any kind of buffer in a first place.  */
   data_chunk = grub_memalign_dma32 (128, size ? : 16);
@@ -132,6 +133,7 @@ grub_usb_control_msg (grub_usb_device_t dev,
       else
        tr->pid = GRUB_USB_TRANSFER_TYPE_OUT;
       tr->data = data_addr + i * max;
+      tr->preceding = i * max;
       size -= max;
     }
 
@@ -145,7 +147,8 @@ grub_usb_control_msg (grub_usb_device_t dev,
 
   transfer->transactions[datablocks + 1].toggle = 1;
 
-  err = dev->controller.dev->transfer (&dev->controller, transfer, 1000);
+  err = dev->controller.dev->transfer (&dev->controller, transfer,
+                                      1000, &actual);
   grub_dprintf ("usb", "control: err=%d\n", err);
 
   grub_free (transfer->transactions);
@@ -162,7 +165,8 @@ grub_usb_control_msg (grub_usb_device_t dev,
 static grub_usb_err_t
 grub_usb_bulk_readwrite (grub_usb_device_t dev,
                         int endpoint, grub_size_t size0, char *data_in,
-                        grub_transfer_type_t type, int timeout)
+                        grub_transfer_type_t type, int timeout,
+                        grub_size_t *actual)
 {
   int i;
   grub_usb_transfer_t transfer;
@@ -240,10 +244,12 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev,
       toggle = toggle ? 0 : 1;
       tr->pid = type;
       tr->data = data_addr + i * max;
+      tr->preceding = i * max;
       size -= tr->size;
     }
 
-  err = dev->controller.dev->transfer (&dev->controller, transfer, timeout);
+  err = dev->controller.dev->transfer (&dev->controller, transfer, timeout,
+                                      actual);
   /* We must remember proper toggle value even if some transactions
    * were not processed - correct value should be inversion of last
    * processed transaction (TD). */
@@ -268,23 +274,34 @@ grub_usb_err_t
 grub_usb_bulk_write (grub_usb_device_t dev,
                     int endpoint, grub_size_t size, char *data)
 {
-  return grub_usb_bulk_readwrite (dev, endpoint, size, data,
-                                 GRUB_USB_TRANSFER_TYPE_OUT, 1000);
+  grub_size_t actual;
+  grub_usb_err_t err;
+
+  err = grub_usb_bulk_readwrite (dev, endpoint, size, data,
+                                GRUB_USB_TRANSFER_TYPE_OUT, 1000, &actual);
+  if (!err && actual != size)
+    err = GRUB_USB_ERR_DATA;
+  return err;
 }
 
 grub_usb_err_t
 grub_usb_bulk_read (grub_usb_device_t dev,
                    int endpoint, grub_size_t size, char *data)
 {
-  return grub_usb_bulk_readwrite (dev, endpoint, size, data,
-                                 GRUB_USB_TRANSFER_TYPE_IN, 1000);
+  grub_size_t actual;
+  grub_usb_err_t err;
+  err = grub_usb_bulk_readwrite (dev, endpoint, size, data,
+                                GRUB_USB_TRANSFER_TYPE_IN, 1000, &actual);
+  if (!err && actual != size)
+    err = GRUB_USB_ERR_DATA;
+  return err;
 }
 
 grub_usb_err_t
-grub_usb_bulk_read_timeout (grub_usb_device_t dev,
-                           int endpoint, grub_size_t size, char *data,
-                           int timeout)
+grub_usb_bulk_read_extended (grub_usb_device_t dev,
+                            int endpoint, grub_size_t size, char *data,
+                            int timeout, grub_size_t *actual)
 {
   return grub_usb_bulk_readwrite (dev, endpoint, size, data,
-                                 GRUB_USB_TRANSFER_TYPE_IN, timeout);
+                                 GRUB_USB_TRANSFER_TYPE_IN, timeout, actual);
 }
index a7d37c7de2ba1e233a701905b5df1f12cc05b0ef..68cec6fdfe68a76b68f57220a8eb244272ed30d6 100644 (file)
@@ -67,8 +67,6 @@ struct grub_serial_port
   struct grub_serial_driver *driver;
   struct grub_serial_config config;
   int configured;
-  char buf[64];
-  int bufstart, bufend;
   /* This should be void *data but since serial is useful as an early console
      when malloc isn't available it's a union.
    */
@@ -80,6 +78,8 @@ struct grub_serial_port
       grub_usb_device_t usbdev;
       int configno;
       int interfno;
+      char buf[64];
+      int bufstart, bufend;
       struct grub_usb_desc_endp *in_endp;
       struct grub_usb_desc_endp *out_endp;
     };
index 0ebb39478ddb7326d1f7fd59d44112934b50ffe0..b2dc77ce43e90ad8123d8144f9de94ef504eaaf7 100644 (file)
@@ -107,7 +107,7 @@ struct grub_usb_controller_dev
 
   grub_usb_err_t (*transfer) (grub_usb_controller_t dev,
                              grub_usb_transfer_t transfer,
-                             int timeout);
+                             int timeout, grub_size_t *actual);
 
   int (*hubports) (grub_usb_controller_t dev);
 
@@ -240,8 +240,8 @@ void grub_usb_poll_devices (void);
 
 void grub_usb_device_attach (grub_usb_device_t dev);
 grub_usb_err_t
-grub_usb_bulk_read_timeout (grub_usb_device_t dev,
-                           int endpoint, grub_size_t size, char *data,
-                           int timeout);
+grub_usb_bulk_read_extended (grub_usb_device_t dev,
+                            int endpoint, grub_size_t size, char *data,
+                            int timeout, grub_size_t *actual);
 
 #endif /* GRUB_USB_H */
index 786eff7fef7ba356cb1d85b7375f67843d8b86c7..74201256e9ae4f0557a4fae9268d77616caa95a8 100644 (file)
@@ -28,4 +28,7 @@ void grub_usbserial_detach (grub_usb_device_t usbdev, int configno,
 int
 grub_usbserial_attach (grub_usb_device_t usbdev, int configno, int interfno,
                       struct grub_serial_driver *driver);
+int
+grub_usbserial_fetch (struct grub_serial_port *port, grub_size_t header_size);
+
 #endif
index e68698c1de2f7bd40dc16872a8dbf1d3ab289e1e..a5bb2e8b2b4ea2b44e3bcb62e814828e4f980e68 100644 (file)
@@ -38,6 +38,7 @@ struct grub_usb_transaction
   int toggle;
   grub_transfer_type_t pid;
   grub_uint32_t data;
+  grub_size_t preceding;
 };
 typedef struct grub_usb_transaction *grub_usb_transaction_t;