svn commit: r266508 - head/sys/dev/usb/controller
Hans Petter Selasky
hselasky at FreeBSD.org
Wed May 21 17:22:41 UTC 2014
Author: hselasky
Date: Wed May 21 17:22:41 2014
New Revision: 266508
URL: http://svnweb.freebsd.org/changeset/base/266508
Log:
Implement interrupt endpoint methods for host mode transfers.
Sponsored by: DARPA, AFRL
Modified:
head/sys/dev/usb/controller/saf1761_otg.c
head/sys/dev/usb/controller/saf1761_otg.h
Modified: head/sys/dev/usb/controller/saf1761_otg.c
==============================================================================
--- head/sys/dev/usb/controller/saf1761_otg.c Wed May 21 17:02:21 2014 (r266507)
+++ head/sys/dev/usb/controller/saf1761_otg.c Wed May 21 17:22:41 2014 (r266508)
@@ -561,13 +561,195 @@ complete:
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_
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 *u
switch (edesc->bmAttributes & UE_XFERTYPE) {
case UE_CONTROL:
case UE_BULK:
+ case UE_INTERRUPT:
ep->methods = &saf1761_otg_non_isoc_methods;
break;
default:
Modified: head/sys/dev/usb/controller/saf1761_otg.h
==============================================================================
--- head/sys/dev/usb/controller/saf1761_otg.h Wed May 21 17:02:21 2014 (r266507)
+++ head/sys/dev/usb/controller/saf1761_otg.h Wed May 21 17:22:41 2014 (r266508)
@@ -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;
More information about the svn-src-head
mailing list