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
|
static grub_usb_err_t
|
||||||
grub_ohci_transfer (grub_usb_controller_t dev,
|
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;
|
struct grub_ohci *o = (struct grub_ohci *) dev->data;
|
||||||
grub_ohci_ed_t ed_virt;
|
grub_ohci_ed_t ed_virt;
|
||||||
|
@ -680,6 +681,8 @@ grub_ohci_transfer (grub_usb_controller_t dev,
|
||||||
int err_unrec = 0;
|
int err_unrec = 0;
|
||||||
grub_uint32_t intstatus;
|
grub_uint32_t intstatus;
|
||||||
|
|
||||||
|
*actual = 0;
|
||||||
|
|
||||||
/* Pre-set target for ED - we need it to find proper ED */
|
/* Pre-set target for ED - we need it to find proper ED */
|
||||||
/* Set the device address. */
|
/* Set the device address. */
|
||||||
target = transfer->devaddr;
|
target = transfer->devaddr;
|
||||||
|
@ -1078,12 +1081,14 @@ grub_ohci_transfer (grub_usb_controller_t dev,
|
||||||
|
|
||||||
case 9:
|
case 9:
|
||||||
/* XXX: Data underrun error. */
|
/* XXX: Data underrun error. */
|
||||||
err = GRUB_USB_ERR_DATA;
|
|
||||||
grub_dprintf ("ohci", "Underrun, failed TD address: %p, index: %d\n",
|
grub_dprintf ("ohci", "Underrun, failed TD address: %p, index: %d\n",
|
||||||
tderr_virt, tderr_virt->tr_index);
|
tderr_virt, tderr_virt->tr_index);
|
||||||
grub_dprintf ("ohci", "Underrun, number of not transferred bytes: %d\n",
|
if (transfer->last_trans == -1)
|
||||||
1 + grub_le_to_cpu32 (tderr_virt->buffer_end)
|
break;
|
||||||
- grub_le_to_cpu32 (tderr_virt->buffer));
|
*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;
|
break;
|
||||||
|
|
||||||
case 10:
|
case 10:
|
||||||
|
@ -1172,12 +1177,12 @@ grub_ohci_transfer (grub_usb_controller_t dev,
|
||||||
transfer->last_trans = tderr_virt->tr_index;
|
transfer->last_trans = tderr_virt->tr_index;
|
||||||
else
|
else
|
||||||
transfer->last_trans = -1;
|
transfer->last_trans = -1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
*actual = transfer->size;
|
||||||
|
|
||||||
/* Set empty ED - set HEAD = TAIL = last (not processed) TD */
|
/* 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_head = grub_cpu_to_le32 (grub_le_to_cpu32 (ed_virt->td_tail) & ~0xf);
|
||||||
ed_virt->td_tail) & ~0xf);
|
|
||||||
|
|
||||||
/* At this point always should be:
|
/* At this point always should be:
|
||||||
* ED has skip bit set and halted or empty or after next SOF,
|
* 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;
|
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
|
static int
|
||||||
ftdi_hw_fetch (struct grub_serial_port *port)
|
ftdi_hw_fetch (struct grub_serial_port *port)
|
||||||
{
|
{
|
||||||
char cc[3];
|
|
||||||
grub_usb_err_t err;
|
|
||||||
|
|
||||||
real_config (port);
|
real_config (port);
|
||||||
|
|
||||||
err = grub_usb_bulk_read (port->usbdev, port->in_endp->endp_addr, 3, cc);
|
return grub_usbserial_fetch (port, 2);
|
||||||
if (err != GRUB_USB_ERR_NONE)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return cc[2];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Put a character. */
|
/* Put a character. */
|
||||||
|
|
|
@ -127,26 +127,9 @@ real_config (struct grub_serial_port *port)
|
||||||
static int
|
static int
|
||||||
pl2303_hw_fetch (struct grub_serial_port *port)
|
pl2303_hw_fetch (struct grub_serial_port *port)
|
||||||
{
|
{
|
||||||
grub_usb_err_t err;
|
|
||||||
|
|
||||||
real_config (port);
|
real_config (port);
|
||||||
|
|
||||||
if (port->bufstart < port->bufend)
|
return grub_usbserial_fetch (port, 0);
|
||||||
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++];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Put a character. */
|
/* Put a character. */
|
||||||
|
|
|
@ -75,8 +75,10 @@ struct grub_uhci_td
|
||||||
This is GRUB specific. */
|
This is GRUB specific. */
|
||||||
grub_uint32_t linkptr2;
|
grub_uint32_t linkptr2;
|
||||||
|
|
||||||
/* 3 additional 32 bits words reserved for the Host Controller Driver. */
|
grub_uint32_t buffer0;
|
||||||
grub_uint32_t data[3];
|
|
||||||
|
/* 2 additional 32 bits words reserved for the Host Controller Driver. */
|
||||||
|
grub_uint32_t data[2];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
typedef volatile struct grub_uhci_td *grub_uhci_td_t;
|
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
|
static void
|
||||||
grub_free_queue (struct grub_uhci *u, grub_uhci_td_t td,
|
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 */
|
int i; /* Index of TD in transfer */
|
||||||
|
|
||||||
|
*actual = 0;
|
||||||
|
|
||||||
/* Free the TDs in this queue and set last_trans. */
|
/* Free the TDs in this queue and set last_trans. */
|
||||||
for (i=0; td; i++)
|
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))
|
if (transfer && (td->linkptr & 1))
|
||||||
transfer->last_trans = i;
|
transfer->last_trans = i;
|
||||||
|
|
||||||
|
*actual += (td->ctrl_status + 1) & 0x7ff;
|
||||||
|
|
||||||
/* Unlink the queue. */
|
/* Unlink the queue. */
|
||||||
tdprev = td;
|
tdprev = td;
|
||||||
td = (grub_uhci_td_t) td->linkptr2;
|
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]);
|
| (addr << 8) | tf[type]);
|
||||||
|
|
||||||
td->buffer = data;
|
td->buffer = data;
|
||||||
|
td->buffer0 = data;
|
||||||
|
|
||||||
return td;
|
return td;
|
||||||
}
|
}
|
||||||
|
@ -437,7 +444,7 @@ grub_uhci_transaction (struct grub_uhci *u, unsigned int endp,
|
||||||
static grub_usb_err_t
|
static grub_usb_err_t
|
||||||
grub_uhci_transfer (grub_usb_controller_t dev,
|
grub_uhci_transfer (grub_usb_controller_t dev,
|
||||||
grub_usb_transfer_t transfer,
|
grub_usb_transfer_t transfer,
|
||||||
int timeout)
|
int timeout, grub_size_t *actual)
|
||||||
{
|
{
|
||||||
struct grub_uhci *u = (struct grub_uhci *) dev->data;
|
struct grub_uhci *u = (struct grub_uhci *) dev->data;
|
||||||
grub_uhci_qh_t qh;
|
grub_uhci_qh_t qh;
|
||||||
|
@ -448,10 +455,12 @@ grub_uhci_transfer (grub_usb_controller_t dev,
|
||||||
int i;
|
int i;
|
||||||
grub_uint64_t endtime;
|
grub_uint64_t endtime;
|
||||||
|
|
||||||
|
*actual = 0;
|
||||||
|
|
||||||
/* Allocate a queue head for the transfer queue. */
|
/* Allocate a queue head for the transfer queue. */
|
||||||
qh = grub_alloc_qh (u, GRUB_USB_TRANSACTION_TYPE_CONTROL);
|
qh = grub_alloc_qh (u, GRUB_USB_TRANSACTION_TYPE_CONTROL);
|
||||||
if (! qh)
|
if (! qh)
|
||||||
return grub_errno;
|
return GRUB_USB_ERR_INTERNAL;
|
||||||
|
|
||||||
grub_dprintf ("uhci", "transfer, iobase:%08x\n", u->iobase);
|
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;
|
td_prev->linkptr = 1;
|
||||||
|
|
||||||
if (td_first)
|
if (td_first)
|
||||||
grub_free_queue (u, td_first, NULL);
|
grub_free_queue (u, td_first, NULL, actual);
|
||||||
|
|
||||||
return GRUB_USB_ERR_INTERNAL;
|
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
|
/* Place the QH back in the free list and deallocate the associated
|
||||||
TDs. */
|
TDs. */
|
||||||
qh->elinkptr = 1;
|
qh->elinkptr = 1;
|
||||||
grub_free_queue (u, td_first, transfer);
|
grub_free_queue (u, td_first, transfer, actual);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ grub_usb_control_msg (grub_usb_device_t dev,
|
||||||
volatile char *data;
|
volatile char *data;
|
||||||
grub_uint32_t data_addr;
|
grub_uint32_t data_addr;
|
||||||
grub_size_t size = size0;
|
grub_size_t size = size0;
|
||||||
|
grub_size_t actual;
|
||||||
|
|
||||||
/* FIXME: avoid allocation any kind of buffer in a first place. */
|
/* FIXME: avoid allocation any kind of buffer in a first place. */
|
||||||
data_chunk = grub_memalign_dma32 (128, size ? : 16);
|
data_chunk = grub_memalign_dma32 (128, size ? : 16);
|
||||||
|
@ -132,6 +133,7 @@ grub_usb_control_msg (grub_usb_device_t dev,
|
||||||
else
|
else
|
||||||
tr->pid = GRUB_USB_TRANSFER_TYPE_OUT;
|
tr->pid = GRUB_USB_TRANSFER_TYPE_OUT;
|
||||||
tr->data = data_addr + i * max;
|
tr->data = data_addr + i * max;
|
||||||
|
tr->preceding = i * max;
|
||||||
size -= max;
|
size -= max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +147,8 @@ grub_usb_control_msg (grub_usb_device_t dev,
|
||||||
|
|
||||||
transfer->transactions[datablocks + 1].toggle = 1;
|
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_dprintf ("usb", "control: err=%d\n", err);
|
||||||
|
|
||||||
grub_free (transfer->transactions);
|
grub_free (transfer->transactions);
|
||||||
|
@ -162,7 +165,8 @@ grub_usb_control_msg (grub_usb_device_t dev,
|
||||||
static grub_usb_err_t
|
static grub_usb_err_t
|
||||||
grub_usb_bulk_readwrite (grub_usb_device_t dev,
|
grub_usb_bulk_readwrite (grub_usb_device_t dev,
|
||||||
int endpoint, grub_size_t size0, char *data_in,
|
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;
|
int i;
|
||||||
grub_usb_transfer_t transfer;
|
grub_usb_transfer_t transfer;
|
||||||
|
@ -240,10 +244,12 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev,
|
||||||
toggle = toggle ? 0 : 1;
|
toggle = toggle ? 0 : 1;
|
||||||
tr->pid = type;
|
tr->pid = type;
|
||||||
tr->data = data_addr + i * max;
|
tr->data = data_addr + i * max;
|
||||||
|
tr->preceding = i * max;
|
||||||
size -= tr->size;
|
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
|
/* We must remember proper toggle value even if some transactions
|
||||||
* were not processed - correct value should be inversion of last
|
* were not processed - correct value should be inversion of last
|
||||||
* processed transaction (TD). */
|
* processed transaction (TD). */
|
||||||
|
@ -268,23 +274,34 @@ grub_usb_err_t
|
||||||
grub_usb_bulk_write (grub_usb_device_t dev,
|
grub_usb_bulk_write (grub_usb_device_t dev,
|
||||||
int endpoint, grub_size_t size, char *data)
|
int endpoint, grub_size_t size, char *data)
|
||||||
{
|
{
|
||||||
return grub_usb_bulk_readwrite (dev, endpoint, size, data,
|
grub_size_t actual;
|
||||||
GRUB_USB_TRANSFER_TYPE_OUT, 1000);
|
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_err_t
|
||||||
grub_usb_bulk_read (grub_usb_device_t dev,
|
grub_usb_bulk_read (grub_usb_device_t dev,
|
||||||
int endpoint, grub_size_t size, char *data)
|
int endpoint, grub_size_t size, char *data)
|
||||||
{
|
{
|
||||||
return grub_usb_bulk_readwrite (dev, endpoint, size, data,
|
grub_size_t actual;
|
||||||
GRUB_USB_TRANSFER_TYPE_IN, 1000);
|
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_err_t
|
||||||
grub_usb_bulk_read_timeout (grub_usb_device_t dev,
|
grub_usb_bulk_read_extended (grub_usb_device_t dev,
|
||||||
int endpoint, grub_size_t size, char *data,
|
int endpoint, grub_size_t size, char *data,
|
||||||
int timeout)
|
int timeout, grub_size_t *actual)
|
||||||
{
|
{
|
||||||
return grub_usb_bulk_readwrite (dev, endpoint, size, data,
|
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_driver *driver;
|
||||||
struct grub_serial_config config;
|
struct grub_serial_config config;
|
||||||
int configured;
|
int configured;
|
||||||
char buf[64];
|
|
||||||
int bufstart, bufend;
|
|
||||||
/* This should be void *data but since serial is useful as an early console
|
/* This should be void *data but since serial is useful as an early console
|
||||||
when malloc isn't available it's a union.
|
when malloc isn't available it's a union.
|
||||||
*/
|
*/
|
||||||
|
@ -80,6 +78,8 @@ struct grub_serial_port
|
||||||
grub_usb_device_t usbdev;
|
grub_usb_device_t usbdev;
|
||||||
int configno;
|
int configno;
|
||||||
int interfno;
|
int interfno;
|
||||||
|
char buf[64];
|
||||||
|
int bufstart, bufend;
|
||||||
struct grub_usb_desc_endp *in_endp;
|
struct grub_usb_desc_endp *in_endp;
|
||||||
struct grub_usb_desc_endp *out_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_err_t (*transfer) (grub_usb_controller_t dev,
|
||||||
grub_usb_transfer_t transfer,
|
grub_usb_transfer_t transfer,
|
||||||
int timeout);
|
int timeout, grub_size_t *actual);
|
||||||
|
|
||||||
int (*hubports) (grub_usb_controller_t dev);
|
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);
|
void grub_usb_device_attach (grub_usb_device_t dev);
|
||||||
grub_usb_err_t
|
grub_usb_err_t
|
||||||
grub_usb_bulk_read_timeout (grub_usb_device_t dev,
|
grub_usb_bulk_read_extended (grub_usb_device_t dev,
|
||||||
int endpoint, grub_size_t size, char *data,
|
int endpoint, grub_size_t size, char *data,
|
||||||
int timeout);
|
int timeout, grub_size_t *actual);
|
||||||
|
|
||||||
#endif /* GRUB_USB_H */
|
#endif /* GRUB_USB_H */
|
||||||
|
|
|
@ -28,4 +28,7 @@ void grub_usbserial_detach (grub_usb_device_t usbdev, int configno,
|
||||||
int
|
int
|
||||||
grub_usbserial_attach (grub_usb_device_t usbdev, int configno, int interfno,
|
grub_usbserial_attach (grub_usb_device_t usbdev, int configno, int interfno,
|
||||||
struct grub_serial_driver *driver);
|
struct grub_serial_driver *driver);
|
||||||
|
int
|
||||||
|
grub_usbserial_fetch (struct grub_serial_port *port, grub_size_t header_size);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -38,6 +38,7 @@ struct grub_usb_transaction
|
||||||
int toggle;
|
int toggle;
|
||||||
grub_transfer_type_t pid;
|
grub_transfer_type_t pid;
|
||||||
grub_uint32_t data;
|
grub_uint32_t data;
|
||||||
|
grub_size_t preceding;
|
||||||
};
|
};
|
||||||
typedef struct grub_usb_transaction *grub_usb_transaction_t;
|
typedef struct grub_usb_transaction *grub_usb_transaction_t;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue