Example #1
0
static int handle_submit(usb_t *self, data_hdr_t *hdr)
{
    submit_req_t req;
    urb_t *urb;
    urb_t small_urb;

    if (self->recv(&req, sizeof(req)) != sizeof(req))
        return 0;

    if (be32toh(req.length) >= 0x80000000)
        return 0;

    if (be32toh(hdr->direction) == DIR_OUT)
        urb = malloc(sizeof(urb_t) + be32toh(req.length));
    else
        urb = &small_urb;
    if (urb == NULL)
        return 0;

    urb->devid = be32toh(hdr->devid);
    urb->seqnum = be32toh(hdr->seqnum);
    urb->direction = be32toh(hdr->direction);
    urb->endpoint = be32toh(hdr->endpoint);
    urb->flags = be32toh(req.flags);
    urb->length = be32toh(req.length);
    urb->interval = be32toh(req.interval);
    memcpy(urb->setup, req.setup, sizeof(urb->setup));
    if (urb->direction == DIR_OUT && self->recv(urb->data, urb->length) != urb->length)
    {
        free(urb);
        return 0;
    }

    if (urb->endpoint == 0)
        return handle_ep0(self, urb);
    else
        return msc_handle_urb(self, urb);
}
Example #2
0
/**
 * This interrupt indicates that an IN EP has a pending Interrupt.
 * The sequence for handling the IN EP interrupt is shown below:
 * -#	Read the Device All Endpoint Interrupt register
 * -#	Repeat the following for each IN EP interrupt bit set (from
 *   	LSB to MSB).
 * -#	Read the Device Endpoint Interrupt (DIEPINTn) register
 * -#	If "Transfer Complete" call the request complete function
 * -#	If "Endpoint Disabled" complete the EP disable procedure.
 * -#	If "AHB Error Interrupt" log error
 * -#	If "Time-out Handshake" log error
 * -#	If "IN Token Received when TxFIFO Empty" write packet to Tx
 *   	FIFO.
 * -#	If "IN Token EP Mismatch" (disable, this is handled by EP
 *   	Mismatch Interrupt)
 */
static int32_t dwc_otg_pcd_handle_in_ep_intr(void)
{
#define CLEAR_IN_EP_INTR(__epnum,__intr) \
do { \
        diepint_data_t diepint = { 0 }; \
	diepint.b.__intr = 1; \
	dwc_write_reg32(DWC_REG_IN_EP_INTR(__epnum), \
			diepint.d32); \
} while (0)

        diepint_data_t diepint = { 0 };
//        depctl_data_t diepctl = { 0 };
        uint32_t ep_intr;
        uint32_t epnum = 0;
        gintmsk_data_t intr_mask = {0};
        gintsts_data_t gintsts;

	 DBG( "dwc_otg_pcd_handle_in_ep_intr()\n" );

	/* Read in the device interrupt bits */
        ep_intr = (dwc_read_reg32(DWC_REG_DAINT) &
                dwc_read_reg32( DWC_REG_DAINTMSK));
        ep_intr =( (ep_intr & 0xffff) );


	/* Clear the INEPINT in GINTSTS */
	/* Clear all the interrupt bits for all IN endpoints in DAINT */
	gintsts.d32 = 0;
	gintsts.b.inepint = 1;
	dwc_write_reg32 (DWC_REG_GINTSTS, gintsts.d32);
	dwc_write_reg32(DWC_REG_DAINT, 0xFFFF );
	flush_cpu_cache();

	/* Service the Device IN interrupts for each endpoint */
        while ( ep_intr ) {
                if (ep_intr&0x1) {

                        diepint.d32 = (dwc_read_reg32( DWC_REG_IN_EP_INTR(epnum)) &
									dwc_read_reg32(DWC_REG_DAINTMSK));
                        /* Transfer complete */
                        if ( diepint.b.xfercompl ) {


                                /* Disable the NP Tx FIFO Empty
                                 * Interrrupt */
                                intr_mask.b.nptxfempty = 1;
                                dwc_modify_reg32( DWC_REG_GINTMSK, intr_mask.d32, 0);

                                /* Clear the bit in DIEPINTn for this interrupt */
                                CLEAR_IN_EP_INTR(epnum,xfercompl);

                                /* Complete the transfer */
					if (epnum == 0) {
						handle_ep0( 0 );
					} else {
						complete_ep( epnum,1 );
					}
                        }
                        /* Endpoint disable  */
                        if ( diepint.b.epdisabled ) {
                                handle_in_ep_disable_intr( epnum );

                                /* Clear the bit in DIEPINTn for this interrupt */
                                CLEAR_IN_EP_INTR(epnum,epdisabled);
                        }
                        /* AHB Error */
                        if ( diepint.b.ahberr ) {
				/* Clear the bit in DIEPINTn for this interrupt */
				CLEAR_IN_EP_INTR(epnum,ahberr);
                        }
                        /* TimeOUT Handshake (non-ISOC IN EPs) */
                        if ( diepint.b.timeout ) {
                                handle_in_ep_timeout_intr( epnum );

				CLEAR_IN_EP_INTR(epnum,timeout);
                        }
                        /** IN Token received with TxF Empty */
                        if (diepint.b.intktxfemp) {
                                DWN_MSG("diepint.b.intktxfemp\n");
#if 0
                                if (!ep->stopped && epnum != 0) {
                                        diepmsk_data_t diepmsk = { 0};
                                        diepmsk.b.intktxfemp = 1;
                                        dwc_modify_reg32( &dev_if->dev_global_regs->diepmsk, diepmsk.d32, 0 );
                                        start_next_request(ep);
                                }
#endif
				CLEAR_IN_EP_INTR(epnum,intktxfemp);
                        }
                        /** IN Token Received with EP mismatch */
                        if (diepint.b.intknepmis) {
                                DWN_MSG("intknepmis ep%d\n", epnum);
                                CLEAR_IN_EP_INTR(epnum,intknepmis);
                        }
                        /** IN Endpoint NAK Effective */
                        if (diepint.b.inepnakeff) {
				CLEAR_IN_EP_INTR(epnum,inepnakeff);
                        }
                }
                epnum++;
                ep_intr >>=1;
        }

        return 1;

#undef CLEAR_IN_EP_INTR
}
Example #3
0
static void dcd_soft_intr(void *arg)
{
    td243fc_rev2_softc_t *sc = (td243fc_rev2_softc_t *)arg;
    juint32_t sys_intr, ep_intr;
    juint32_t fc_cmd;

    DBG_V(DSLAVE_DCD, ("DCD: dcd_soft_intr\n"));

    jspinlock_lock(sc->sc_lock);
    {
        sys_intr = sc->sys_intr;
        ep_intr = sc->ep_intr; 
        fc_cmd = sc->fc_cmd;
        sc->sys_intr = sc->ep_intr = sc->fc_cmd = 0;
    }
    jspinlock_unlock(sc->sc_lock);
    
    sys_intr &= sc->sys_intr_mask;
    ep_intr &= sc->ep_intr_mask;

    /* Acknowledge the interuppts */
    WRITE4(TD243FC_SYSTEM_INT_STATUS_REG, sys_intr);

    /* HSU Addition */
    /* Handle EP interrupts first. Fix for the case where OUT EP interrupt and 
       subsequent RESET interrupt are handled together. So the OUT EP interrupt 
       has to be handled first. The opposite case was not observed. */
    if (sys_intr & TD243FC_DONEREG)
    {
        juint_t i;

        sc->add_to_list = TRUE;

        /* Handle interrupts on EP0 (IN and OUT interrupts) */
        if (ep_intr & (TD243FC_EP_BIT(0, 0) | TD243FC_EP_BIT(0, 1)))
            handle_ep0(sc, ep_intr);

        /* Handle interrupts on endpoints other than EP0 */
        for (i = 2; i < TD243FC_EP_NUM * 2; i++)
        {
            if (ep_intr & (1<<i))
                handle_epn(sc, i);
        }

        /* Clear interrupts of handled EPs */
        WRITE4(TD243FC_EP_DONE_STATUS_REG, ep_intr);
        sc->add_to_list = FALSE;
        if (sc->ep_ready)
        {
            WRITE4(TD243FC_EP_READY_REG, sc->ep_ready);
            sc->ep_ready = 0;
        }
    }
    /* HSU End */

    if ((sys_intr & TD243FC_BUSRST) && (fc_cmd & TD243FC_RESETDET))
    {
      DBG_V(DSLAVE_DCD, ("DCD: Bus reset detected\n"));

      handle_reset(sc);

      /* Since we enable interrupts other then BUSRST only in handle_reset,
      * no need to handle other interrupts together with BUSRST */
      goto Exit;
    }

    if ((sys_intr & TD243FC_RESUME) && (fc_cmd & TD243FC_RSMINPROG))
    {
      if (sc->is_suspend)
      {
        DBG_V(DSLAVE_DCD, ("DCD: RESUME detected\n"));
        core_resume(sc->core_ctx);
        sc->is_suspend = 0;
        sc->sys_intr_mask  &= ~TD243FC_RESUME;
        sc->sys_intr_mask  |= TD243FC_SUSP;
        WRITE4(TD243FC_SYSTEM_INT_ENABLE_REG, sc->sys_intr_mask);
      }
    }

    if ((sys_intr & TD243FC_SUSP) && (fc_cmd & TD243FC_SUSPDET))
    {
      if (!sc->is_suspend)
      {
        DBG_V(DSLAVE_DCD, ("DCD: SUSPEND detected\n"));
        core_suspend(sc->core_ctx);
        sc->is_suspend = 1;
        sc->sys_intr_mask  &= ~TD243FC_SUSP;
        sc->sys_intr_mask  |= TD243FC_RESUME;
        WRITE4(TD243FC_SYSTEM_INT_ENABLE_REG, sc->sys_intr_mask);
        SET4(TD243FC_COMMAND_REG, TD243FC_SUSPDET);
      }
    }

    /* HSU Addition */

    /* Moved handling of TD243FC_DONEREG interrupt from here to the beginning 
       of the function */

    /* HSU End */
    WRITE4(TD243FC_SYSTEM_INT_ENABLE_REG, sc->sys_intr_mask);
Exit:
    /* Ack & Enable device controller global interrupt */
    SET4(TD243FC_CHIP_INT_ENABLE_REG, TD243FC_INTF);
    DBG_V(DSLAVE_DCD, ("DCD: dcd_soft_intr finished\n\n\n"));
}
Example #4
0
/**
 * This interrupt indicates that an OUT EP has a pending Interrupt.
 * The sequence for handling the OUT EP interrupt is shown below:
 * -#	Read the Device All Endpoint Interrupt register
 * -#	Repeat the following for each OUT EP interrupt bit set (from
 *   	LSB to MSB).
 * -#	Read the Device Endpoint Interrupt (DOEPINTn) register
 * -#	If "Transfer Complete" call the request complete function
 * -#	If "Endpoint Disabled" complete the EP disable procedure.
 * -#	If "AHB Error Interrupt" log error
 * -#	If "Setup Phase Done" process Setup Packet (See Standard USB
 *   	Command Processing)
 */
static int32_t dwc_otg_pcd_handle_out_ep_intr(void)
{
#define CLEAR_OUT_EP_INTR(__epnum,__intr) \
do { \
        doepint_data_t doepint = { 0 }; \
	doepint.b.__intr = 1; \
	dwc_write_reg32(DWC_REG_OUT_EP_INTR(__epnum), \
			doepint.d32); \
} while (0)

        uint32_t ep_intr;
        doepint_data_t doepint = { 0 };
        uint32_t epnum = 0;
//	 uint32_t epnum_trans = 0;
        gintsts_data_t gintsts;

        DBG( "dwc_otg_pcd_handle_out_ep_intr()\n" );

	/* Read in the device interrupt bits */
        ep_intr = (dwc_read_reg32(DWC_REG_DAINT) &
                dwc_read_reg32( DWC_REG_DAINTMSK));
        ep_intr =( (ep_intr & 0xffff0000) >> 16);

	/* Clear the OUTEPINT in GINTSTS */
	gintsts.d32 = 0;
	gintsts.b.outepintr = 1;
	dwc_write_reg32 (DWC_REG_GINTSTS, gintsts.d32);
	dwc_write_reg32(DWC_REG_DAINT, 0xFFFF0000 );

        while ( ep_intr ) {
            if (ep_intr&0x1) {
                    doepint.d32 = (dwc_read_reg32( DWC_REG_OUT_EP_INTR(epnum)) &
						dwc_read_reg32(DWC_REG_DOEPMSK));

                    /* Transfer complete */
			if ( doepint.b.xfercompl ) {
				DBG("EP%d OUT Xfer Complete\n", epnum);

				/* Clear the bit in DOEPINTn for this interrupt */
				CLEAR_OUT_EP_INTR(epnum,xfercompl);

				if (epnum == 0) {
					handle_ep0( 0 );
				} else {
					complete_ep( epnum,0 );
				}
                    }
                    /* Endpoint disable  */
                    if ( doepint.b.epdisabled ) {
                            DBG("EP%d OUT disabled\n", epnum);
				/* Clear the bit in DOEPINTn for this interrupt */
				CLEAR_OUT_EP_INTR(epnum,epdisabled);
                    }
                    /* AHB Error */
                    if ( doepint.b.ahberr ) {
                            DBG("EP%d OUT AHB Error\n", epnum);
				CLEAR_OUT_EP_INTR(epnum,ahberr);
                    }
                    /* Setup Phase Done (contorl EPs) */
                    if ( doepint.b.setup ) {
                            handle_ep0( 0 );
				CLEAR_OUT_EP_INTR(epnum,setup);
                    }
            }
		epnum++;
		ep_intr >>=1;
        }

        return 1;

#undef CLEAR_OUT_EP_INTR
}