Date: Wed, 21 May 2014 17:22:41 +0000 (UTC) From: Hans Petter Selasky <hselasky@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r266508 - head/sys/dev/usb/controller Message-ID: <201405211722.s4LHMfCp016032@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201405211722.s4LHMfCp016032>