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;
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to