Implement interrupt endpoint methods for host mode transfers.

Sponsored by:	DARPA, AFRL
This commit is contained in:
Hans Petter Selasky 2014-05-21 17:22:41 +00:00
parent 400b4e53bd
commit 8e14e4a03a
2 changed files with 194 additions and 1 deletions

View File

@ -561,13 +561,195 @@ saf1761_host_bulk_data_tx(struct saf1761_otg_softc *sc, struct saf1761_otg_td *t
static uint8_t
saf1761_host_intr_data_rx(struct saf1761_otg_softc *sc, struct saf1761_otg_td *td)
{
uint32_t pdt_addr;
uint32_t temp;
if (td->channel < SOTG_HOST_CHANNEL_MAX) {
uint32_t status;
uint32_t count;
uint8_t got_short;
pdt_addr = SOTG_PDT(td->channel);
saf1761_read_host_memory_4(sc, pdt_addr + SOTG_PDT_DW3, &status, 1);
if (status & SOTG_PDT_DW3_ACTIVE) {
goto busy;
} else if (status & SOTG_PDT_DW3_HALTED) {
td->error_stall = 1;
td->error_any = 1;
goto complete;
}
count = (status & SOTG_PDT_DW3_XFER_COUNT);
got_short = 0;
/* verify the packet byte count */
if (count != td->max_packet_size) {
if (count < td->max_packet_size) {
/* we have a short packet */
td->short_pkt = 1;
got_short = 1;
} else {
/* invalid USB packet */
td->error_any = 1;
goto complete;
}
}
td->toggle ^= 1;
/* verify the packet byte count */
if (count > td->remainder) {
/* invalid USB packet */
td->error_any = 1;
goto complete;
}
saf1761_read_host_memory_4(sc, SOTG_DATA_ADDR(td->channel),
sc->sc_bounce_buffer, (count + 3) / 4);
usbd_copy_in(td->pc, td->offset,
sc->sc_bounce_buffer, count);
td->remainder -= count;
td->offset += count;
saf1761_host_channel_free(sc, td);
/* check if we are complete */
if ((td->remainder == 0) || got_short) {
if (td->short_pkt)
goto complete;
/* else need to receive a zero length packet */
}
}
if (saf1761_host_channel_alloc(sc, td))
goto busy;
/* set toggle, if any */
if (td->set_toggle) {
td->set_toggle = 0;
td->toggle = 1;
}
/* receive one more packet */
pdt_addr = SOTG_PDT(td->channel);
SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW7, 0);
SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW6, 0);
temp = (0xFC << td->uframe) & 0xFF; /* complete split */
SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW5, temp);
temp = (1U << td->uframe); /* start split */
SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW4, temp);
temp = SOTG_PDT_DW3_ACTIVE | (td->toggle << 25) | SOTG_PDT_DW3_CERR;
SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW3, temp);
temp = (SOTG_HC_MEMORY_ADDR(SOTG_DATA_ADDR(td->channel)) << 8) | td->interval;
SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW2, temp);
temp = td->dw1_value | (1 << 10) /* IN-PID */ | (td->ep_index >> 1);
SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW1, temp);
temp = (td->ep_index << 31) | (1 << 29) /* pkt-multiplier */ |
(td->max_packet_size << 18) /* wMaxPacketSize */ |
(td->max_packet_size << 3) /* transfer count */ |
SOTG_PDT_DW0_VALID;
SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW0, temp);
busy:
return (1); /* busy */
complete:
return (0); /* complete */
}
static uint8_t
saf1761_host_intr_data_tx(struct saf1761_otg_softc *sc, struct saf1761_otg_td *td)
{
uint32_t pdt_addr;
uint32_t temp;
uint32_t count;
if (td->channel < SOTG_HOST_CHANNEL_MAX) {
uint32_t status;
pdt_addr = SOTG_PDT(td->channel);
saf1761_read_host_memory_4(sc, pdt_addr + SOTG_PDT_DW3, &status, 1);
if (status & SOTG_PDT_DW3_ACTIVE) {
goto busy;
} else if (status & SOTG_PDT_DW3_HALTED) {
td->error_stall = 1;
td->error_any = 1;
}
saf1761_host_channel_free(sc, td);
/* check remainder */
if (td->remainder == 0) {
if (td->short_pkt)
goto complete;
/* else we need to transmit a short packet */
}
}
if (saf1761_host_channel_alloc(sc, td))
goto busy;
count = td->max_packet_size;
if (td->remainder < count) {
/* we have a short packet */
td->short_pkt = 1;
count = td->remainder;
}
usbd_copy_out(td->pc, td->offset, sc->sc_bounce_buffer, count);
saf1761_write_host_memory_4(sc, SOTG_DATA_ADDR(td->channel),
sc->sc_bounce_buffer, (count + 3) / 4);
/* set toggle, if any */
if (td->set_toggle) {
td->set_toggle = 0;
td->toggle = 1;
}
/* send one more packet */
pdt_addr = SOTG_PDT(td->channel);
SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW7, 0);
SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW6, 0);
temp = (0xFC << td->uframe) & 0xFF; /* complete split */
SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW5, temp);
temp = (1U << td->uframe); /* start split */
SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW4, temp);
temp = SOTG_PDT_DW3_ACTIVE | (td->toggle << 25) | SOTG_PDT_DW3_CERR;
SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW3, temp);
temp = (SOTG_HC_MEMORY_ADDR(SOTG_DATA_ADDR(td->channel)) << 8) | td->interval;
SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW2, temp);
temp = td->dw1_value | (0 << 10) /* OUT-PID */ | (td->ep_index >> 1);
SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW1, temp);
temp = (td->ep_index << 31) | (1 << 29) /* pkt-multiplier */ |
(td->max_packet_size << 18) /* wMaxPacketSize */ |
(count << 3) /* transfer count */ |
SOTG_PDT_DW0_VALID;
SAF1761_WRITE_4(sc, pdt_addr + SOTG_PDT_DW0, temp);
td->offset += count;
td->remainder -= count;
td->toggle ^= 1;
busy:
return (1); /* busy */
complete:
return (0); /* complete */
}
static uint8_t
@ -2692,7 +2874,15 @@ saf1761_otg_xfer_setup(struct usb_setup_params *parm)
td->ep_index = ep_no;
td->ep_type = ep_type;
td->dw1_value = dw1;
td->uframe = 0;
if (ep_type == UE_INTERRUPT) {
if (xfer->interval > 32)
td->interval = 32 / 2;
else
td->interval = xfer->interval / 2;
} else {
td->interval = 0;
}
td->obj_next = last_obj;
last_obj = td;
@ -2739,6 +2929,7 @@ saf1761_otg_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *ede
switch (edesc->bmAttributes & UE_XFERTYPE) {
case UE_CONTROL:
case UE_BULK:
case UE_INTERRUPT:
ep->methods = &saf1761_otg_non_isoc_methods;
break;
default:

View File

@ -70,6 +70,8 @@ struct saf1761_otg_td {
uint8_t ep_index;
uint8_t ep_type;
uint8_t channel;
uint8_t uframe;
uint8_t interval;
uint8_t error_any:1;
uint8_t error_stall:1;
uint8_t alt_next:1;