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;
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;
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:
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,
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++];
+}
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. */
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. */
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;
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++)
/* 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;
| (addr << 8) | tf[type]);
td->buffer = data;
+ td->buffer0 = data;
return td;
}
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;
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);
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;
}
/* 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;
}
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);
else
tr->pid = GRUB_USB_TRANSFER_TYPE_OUT;
tr->data = data_addr + i * max;
+ tr->preceding = i * max;
size -= max;
}
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);
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;
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). */
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);
}
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.
*/
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;
};
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);
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 */
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
int toggle;
grub_transfer_type_t pid;
grub_uint32_t data;
+ grub_size_t preceding;
};
typedef struct grub_usb_transaction *grub_usb_transaction_t;