Allow psartial transfers and use them for usbserial
This commit is contained in:
parent
824e1447ac
commit
34787305df
10 changed files with 93 additions and 59 deletions
|
@ -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,
|
||||
|
|
|
@ -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++];
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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,10 +335,12 @@ 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++)
|
||||
{
|
||||
|
@ -346,6 +350,8 @@ grub_free_queue (struct grub_uhci *u, grub_uhci_td_t td,
|
|||
if (transfer && (td->linkptr & 1))
|
||||
transfer->last_trans = i;
|
||||
|
||||
*actual += (td->ctrl_status + 1) & 0x7ff;
|
||||
|
||||
/* Unlink the queue. */
|
||||
tdprev = td;
|
||||
td = (grub_uhci_td_t) td->linkptr2;
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue