Beispiel #1
0
void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
{
	struct usb_setup_packet *setup = (void *)usb_dc_stm32_state.pcd.Setup;
	struct usb_dc_stm32_ep_state *ep_state;

	LOG_DBG("");

	ep_state = usb_dc_stm32_get_ep_state(EP0_OUT); /* can't fail for ep0 */
	ep_state->read_count = SETUP_SIZE;
	ep_state->read_offset = 0U;
	memcpy(&usb_dc_stm32_state.ep_buf[EP0_IDX],
	       usb_dc_stm32_state.pcd.Setup, ep_state->read_count);

	if (ep_state->cb) {
		ep_state->cb(EP0_OUT, USB_DC_EP_SETUP);

		if (!(setup->wLength == 0U) &&
		    !(REQTYPE_GET_DIR(setup->bmRequestType) ==
		    REQTYPE_DIR_TO_HOST)) {
			usb_dc_ep_start_read(EP0_OUT,
					     usb_dc_stm32_state.ep_buf[EP0_IDX],
					     setup->wLength);
		}
	}
}
Beispiel #2
0
/*************************************************************************
    PreHandleRequest
    ================
    Change data pointer for data out request

    Returns TRUE if the pointer was changed
**************************************************************************/
static BOOL PreHandleRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData)
{
    if ((pSetup->wLength != 0) &&
        (REQTYPE_GET_DIR(pSetup->bmRequestType) == REQTYPE_DIR_TO_DEVICE) &&
        (pSetup->bRequest == REQ_DATA_TRANSFER) &&
        (*piLen <= write_ram_len)) {
            // directly write to the location given by WRITE_TO_RAM
            *ppbData = (U8*) write_ram_adr;
            return TRUE;
    }
    return FALSE;
}
/**
 *	Handles IN/OUT transfers on EP0
 *
 *	@param [in]	bEP		Endpoint address
 *	@param [in]	bEPStat	Endpoint status
 */
void USBHandleControlTransfer(U8 bEP, U8 bEPStat)
{
	int iChunk, iType;

	if (bEP == 0x00) {
		// OUT transfer
		if (bEPStat & EP_STATUS_SETUP) {
			// setup packet, reset request message state machine
			USBHwEPRead(0x00, (U8 *)&Setup, sizeof(Setup));
			DBG("S%x", Setup.bRequest);

			// defaults for data pointer and residue
			iType = REQTYPE_GET_TYPE(Setup.bmRequestType);
			pbData = apbDataStore[iType];
			iResidue = Setup.wLength;
			iLen = Setup.wLength;

			if ((Setup.wLength == 0) ||
				(REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_HOST)) {
				// ask installed handler to process request
				if (!_HandleRequest(&Setup, &iLen, &pbData)) {
					DBG("_HandleRequest1 failed\n");
					StallControlPipe(bEPStat);
					return;
				}
				// send smallest of requested and offered length
				iResidue = MIN(iLen, Setup.wLength);
				// send first part (possibly a zero-length status message)
				DataIn();
			}
		}
		else {		
			if (iResidue > 0) {
				// store data
				iChunk = USBHwEPRead(0x00, pbData, iResidue);
				if (iChunk < 0) {
					StallControlPipe(bEPStat);
					return;
				}
				pbData += iChunk;
				iResidue -= iChunk;
				if (iResidue == 0) {
					// received all, send data to handler
					iType = REQTYPE_GET_TYPE(Setup.bmRequestType);
					pbData = apbDataStore[iType];
					if (!_HandleRequest(&Setup, &iLen, &pbData)) {
						DBG("_HandleRequest2 failed\n");
						StallControlPipe(bEPStat);
						return;
					}
					// send status to host
					DataIn();
				}
			}
			else {
				// absorb zero-length status message
				iChunk = USBHwEPRead(0x00, NULL, 0);
				DBG(iChunk > 0 ? "?" : "");
			}
		}
	}
	else if (bEP == 0x80) {
		// IN transfer
		// send more data if available (possibly a 0-length packet)
		DataIn();
	}
	else {
		ASSERT(FALSE);
	}
}
Beispiel #4
0
void USBCTRL::EPIntHandler(USBHW *u, uint8_t bEP, uint8_t bEPStatus) {
	iprintf("E0x%02X:0x%02X\t", bEP, bEPStatus);
	if (bEP == 0x00) {
		if (bEPStatus & EP_STATUS_SETUP) {
			// defaults for data pointer and residue
			HwEPRead(bEP, (uint8_t *) &Setup, sizeof(Setup));

			uint8_t iType = REQTYPE_GET_TYPE(Setup.bmRequestType);
			pbData = &apbDataStore[iType][0];
			iResidue = Setup.wLength;
			iLen = Setup.wLength;

			if ((Setup.wLength == 0) ||
				(REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_HOST)) {
				switch(REQTYPE_GET_TYPE(Setup.bmRequestType)) {
					case REQTYPE_TYPE_STANDARD: {
// 						iprintf("STDREQ:%02X,%02X,%04X,%04X,%04x\n", Setup.bmRequestType, Setup.bRequest, Setup.wValue, Setup.wIndex, Setup.wLength);
						uint8_t r = 0;
						switch (REQTYPE_GET_RECIP(Setup.bmRequestType)) {
							case REQTYPE_RECIP_DEVICE: {
								iprintf("StdDevReq:Rq=%02x,wV=%02x,wI=%02x,wL=%02x\n", Setup.bRequest, Setup.wValue, Setup.wIndex, Setup.wLength);
								r = HandleStdDeviceReq(&Setup, &iLen, &pbData);
								iprintf("Reply:%d bytes, max this packet: %d\n", iLen, Setup.wLength);
								break;
							}
							case REQTYPE_RECIP_INTERFACE: {
								iprintf("StdIntReq:Rq=%02x,wV=%02x,wI=%02x,wL=%02x\n", Setup.bRequest, Setup.wValue, Setup.wIndex, Setup.wLength);
								r = HandleStdInterfaceReq(&Setup, &iLen, &pbData);
								break;
							}
							case REQTYPE_RECIP_ENDPOINT: {
								iprintf("StdEPReq:Rq=%02x,wV=%02x,wI=%02x,wL=%02x\n", Setup.bRequest, Setup.wValue, Setup.wIndex, Setup.wLength);
								r = HandleStdEndPointReq(&Setup, &iLen, &pbData);
								break;
							}
							case REQTYPE_RECIP_OTHER: {
								iprintf("StdReq?:RqType=%02x;Rq=%02x,wV=%02x,wI=%02x,wL=%02x\n", Setup.bmRequestType, Setup.bRequest, Setup.wValue, Setup.wIndex, Setup.wLength);
								break;
							}
						}
						if (!r) {
							iprintf("STALL!\n");
							HwEPStall(0x80, TRUE);
							return;
						}
						iResidue = iLen;
						if (iResidue > Setup.wLength)
							iResidue = Setup.wLength;

						DataIn();

						return;
					};
				}
			}
			iprintf("Unknown Setup ReqType %d - ignored\n", Setup.bmRequestType);
			iprintf("bRequest: %d (0x%02X), wValue: %d, wIndex: %d (0x%X), wLength: %d\n", Setup.bRequest, Setup.bRequest, Setup.wValue, Setup.wIndex, Setup.wIndex, Setup.wLength);
			iprintf("Dir: %s, ", (REQTYPE_GET_DIR(Setup.bmRequestType)?"Device->Host":"Host->Device"));
			if (REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_DEVICE) {
				iResidue = Setup.wLength;
			}
			else {
				iResidue = 0;
			}
			switch (REQTYPE_GET_TYPE(Setup.bmRequestType)) {
				case REQTYPE_TYPE_STANDARD:
					iprintf("Type: Standard, ");
					break;
				case REQTYPE_TYPE_CLASS:
					iprintf("Type: Class   , ");
					break;
				case REQTYPE_TYPE_VENDOR:
					iprintf("Type: Vendor  , ");
					break;
				default:
					iprintf("Type: Reserved, ");
					break;
			}
			switch (REQTYPE_GET_RECIP(Setup.bmRequestType)) {
				case 0:
					iprintf("Recip: Device\n");
					break;
				case 1:
					iprintf("Recip: Interface 0x%X\n", Setup.wIndex);
					break;
				case 2:
					iprintf("Recip: Endpoint 0x%X\n", Setup.wIndex);
					break;
				case 3:
					iprintf("Recip: Other\n");
					break;
				default:
					iprintf("Recip: unknown\n");
					break;
			}
// 			if (REQTYPE_GET_TYPE(Setup.bmRequestType) == REQTYPE_TYPE_CLASS) {
// 				// find interface
// 				int i;
// 				for (i = 0; descriptors[i] != ((usbdesc_base *) 0); i++) {
// 					if ((descriptors[i]->bDescType == DT_INTERFACE) && (REQTYPE_GET_RECIP(Setup.bmRequestType) == REQTYPE_RECIP_INTERFACE)) {
// 						usbdesc_interface *inf = (usbdesc_interface *) descriptors[i];
// 						if (inf->bInterfaceNumber == Setup.wIndex) {
// 							iprintf("Firing Interface's setup handler: %p\n", inf->setupReceiver);
// 							if (inf->setupReceiver) {
// 								inf->setupReceiver->SetupHandler(u, bEP, &Setup);
// 								break;
// 							}
// 						}
// 					}
// 					if ((descriptors[i]->bDescType == DT_ENDPOINT) && (REQTYPE_GET_RECIP(Setup.bmRequestType) == REQTYPE_RECIP_ENDPOINT)) {
// 						usbdesc_endpoint *ep = (usbdesc_endpoint *) descriptors[i];
// 						if (ep->bEndpointAddress == bEP) {
// 							iprintf("Firing Endpoint's setup handler: %p\n", ep->setupReceiver);
// 							if (ep->setupReceiver)
// 								ep->setupReceiver->SetupHandler(u, bEP, &Setup);
// 						}
// 					}
// 				}
// 			}
		}
		else {
			int iChunk;
			if (iResidue > 0) {
				// store data
				iChunk = HwEPRead(0x00, pbData, iResidue);
				iprintf("G:%db\n", iChunk);
				if (iChunk < 0) {
					HwEPStall(0x80, TRUE);
					return;
				}
				pbData += iChunk;
				iResidue -= iChunk;
				if (iResidue == 0) {
					// received all, send data to handler
					uint8_t iType = REQTYPE_GET_TYPE(Setup.bmRequestType);
					pbData = apbDataStore[iType];
					iprintf("HANDLE 0x%02X with %db\n", iType, iLen);
// 					if (!_HandleRequest(&Setup, &iLen, &pbData)) {
// 						DBG("_HandleRequest2 failed\n");
// 						StallControlPipe(bEPStat);
// 						return;
// 					}
					// send status to host
					DataIn();
				}
			}
			else {
				// absorb zero-length status message
				iChunk = HwEPRead(0x00, NULL, 0);
				iprintf("g%db\n", iChunk);
				// acknowledge
				HwEPWrite(0x80, 0, 0);
// 				DBG(iChunk > 0 ? "?" : "");
			}
		}
		if (REQTYPE_GET_TYPE(Setup.bmRequestType) == REQTYPE_TYPE_CLASS) {
			if ((iResidue == Setup.wLength) || (REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_HOST)) {
				// find interface
				int i;
				for (i = 0; descriptors[i] != ((usbdesc_base *) 0); i++) {
					if ((descriptors[i]->bDescType == DT_INTERFACE) && (REQTYPE_GET_RECIP(Setup.bmRequestType) == REQTYPE_RECIP_INTERFACE)) {
						usbdesc_interface *inf = (usbdesc_interface *) descriptors[i];
						if (inf->bInterfaceNumber == Setup.wIndex) {
							iprintf("Firing Interface's setup handler: %p\n", inf->setupReceiver);
							if (inf->setupReceiver) {
								inf->setupReceiver->SetupHandler(u, bEP, &Setup);
								break;
							}
						}
					}
					if ((descriptors[i]->bDescType == DT_ENDPOINT) && (REQTYPE_GET_RECIP(Setup.bmRequestType) == REQTYPE_RECIP_ENDPOINT)) {
						usbdesc_endpoint *ep = (usbdesc_endpoint *) descriptors[i];
						if (ep->bEndpointAddress == bEP) {
							iprintf("Firing Endpoint's setup handler: %p\n", ep->setupReceiver);
							if (ep->setupReceiver)
								ep->setupReceiver->SetupHandler(u, bEP, &Setup);
						}
					}
				}
			}
		}
	}
	else if (bEP == 0x80) {
		DataIn();
	}
	else {
		int i;
		usbdesc_base *descriptor;
		for (i = 0; i < 32; i++) {
			descriptor = descriptors[i];
			if (descriptor->bDescType == DT_ENDPOINT) {
				usbdesc_endpoint *endpoint = (usbdesc_endpoint *) descriptor;
				if (endpoint->bEndpointAddress == bEP) {
					endpoint->callbackReceiver->EPIntHandler(u, bEP, bEPStatus);
				}
			}
		}
	}
}
Beispiel #5
0
/*************************************************************************
	USBHandleControlTransfer
	========================
		Handles IN/OUT transfers on EP0

**************************************************************************/
void USBHandleControlTransfer(U8 bEP, U8 bEPStat)
{
	int iChunk;

	if (bEP == 0x00) {
		// OUT transfer
		if (bEPStat & EP_STATUS_SETUP) {
			// setup packet, reset request message state machine
			USBHwEPRead(0x00, (U8 *)&Setup, &iLen);
//mmmm			DBG("S%x", Setup.bRequest);

			// defaults for data pointer and residue
			pbData = abControlData;
			iResidue = Setup.wLength;
			iLen = Setup.wLength;

			// ask installed handler to pre process request
			if (!_PreHandleRequest(&Setup, &iLen, &pbData)) {
				// silently ignore non installed handler
			}

			if ((Setup.wLength == 0) ||
				(REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_HOST)) {
				// ask installed handler to process request
				if (!_HandleRequest(&Setup, &iLen, &pbData)) {
					DBG("_HandleRequest1 failed\n");
					StallControlPipe(bEPStat);
					return;
				}
				// send smallest of requested and offered length
				iResidue = MIN(iLen, Setup.wLength);
				// send first part (possibly a zero-length status message)
				DataIn();
			}

			if ((Setup.wLength != 0) &&
                (REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_DEVICE)) {
				if (!_PreHandleRequest(&Setup, &iLen, &pbData)) {
					// this is not a must, might fail
				}
			}
		}
		else {		
			if (iResidue > 0) {
				// store data
				iChunk = 0;
				USBHwEPRead(0x00, pbData, &iChunk);
				pbData += iChunk;
				iResidue -= iChunk;
				if (iResidue == 0) {
					// received all, send data to handler
					// TODO set pointer correctly
					pbData = abControlData;
					if (!_HandleRequest(&Setup, &iLen, &pbData)) {
						StallControlPipe(bEPStat);
						DBG("_HandleRequest2 failed\n");
						return;
					}
					// send status to host
					DataIn();
				}
			}
			else {
				// absorb zero-length status message
				USBHwEPRead(0x00, NULL, &iChunk);
				DBG(iChunk > 0 ? "?" : "");
			}
		}
	}
	else if (bEP == 0x80) {
		// IN transfer
		// send more data if available (possibly a 0-length packet)
		DataIn();
	}
	else {
		ASSERT(FALSE);
	}
}
Beispiel #6
0
/*************************************************************************
    HandleVendorRequest
    ===================
**************************************************************************/
static BOOL HandleVendorRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData)
{
    IAP func_entry;

    func_entry = (IAP) IAP_LOCATION;

    if (pSetup->wIndex != 0) {
        DBG("Invalid idx %X\n", pSetup->wIndex);
        return FALSE;
    }
    if (pSetup->wValue != 0) {
        DBG("Invalid val %X\n", pSetup->wValue);
        return FALSE;
    }

    switch (pSetup->bRequest) {

    // commands
    case REQ_IAP_COMMAND:
        /* fallthrough */
    case REQ_ISP_COMMAND:
        /* fallthrough */
    case REQ_BTL_COMMAND:
        if (pSetup->bRequest == REQ_IAP_COMMAND) func_entry = (IAP) IAP_LOCATION;
        if (pSetup->bRequest == REQ_ISP_COMMAND) func_entry = isp_entry;
        if (pSetup->bRequest == REQ_BTL_COMMAND) func_entry = btl_entry;

        if (REQTYPE_GET_DIR(pSetup->bmRequestType) == REQTYPE_DIR_TO_HOST) {
            // send result
            *ppbData = (U8*) rescmd;
            *piLen = 32; // TODO remove
            if (*piLen != 32) return FALSE;
        }
        else {
            // start command
            if (*piLen != 20) return FALSE;
            memcpy(&rescmd[3], *ppbData, 20);
            func_entry(&rescmd[3], rescmd);
        }
        break;

    // data transfer
    case REQ_DATA_TRANSFER:
        if (REQTYPE_GET_DIR(pSetup->bmRequestType) == REQTYPE_DIR_TO_HOST) {
            // check if data to read
            if (*piLen > read_mem_len) return FALSE;
            *ppbData = (U8*) read_mem_adr;
            read_mem_adr += *piLen;
            read_mem_len -= *piLen;
        }
        else {
            // data is already written, adjust pointers
            if (*piLen > write_ram_len) return FALSE;
            write_ram_adr += *piLen;
            write_ram_len -= *piLen;
        }
        break;

    default:
        DBG("Unhandled vendor\n");
        return FALSE;
    }
    return TRUE;
}
Beispiel #7
0
static bool usb_control_class_handler(void) {
  uint32_t oid;
  uint32_t buflen;
  uint32_t bufptr;

  //printf("control_class_handler!!!");
  ETH_DEV_DBG_INFO("class control request=%d interface=%u len=%u dir=%d\n",usbRequest.request,usbRequest.index,usbRequest.length,REQTYPE_GET_DIR(usbRequest.type));
  DBG("class control request=%d interface=%u len=%u dir=%d\n",usbRequest.request,usbRequest.index,usbRequest.length,REQTYPE_GET_DIR(usbRequest.type));

  if (REQTYPE_GET_DIR(usbRequest.type) == REQTYPE_DIR_TO_HOST) {
    if (rndisResponseReady) {
      //ETH_DEV_DBG_INFO("sending data back to the host, %d bytes\n",rndisResponseLen);
      usbControlTransferPtr = rndisResponse;
      usbControlTransferLen = rndisResponseLen;
      rndisResponseReady = 0;
    } else {
      //ETH_DEV_DBG_INFO("sending NO RESPONE AVAILABLE to the host");
      usbControlTransferPtr = &rndisResponseNotAvailable;
      usbControlTransferLen = 1;
    }
    return TRUE;
  }

  uint32_t type = uint32FromLittleEndian(usbControlTransferPtr);
  uint32_t len  = uint32FromLittleEndian(usbControlTransferPtr+4);
  uint32_t id   = uint32FromLittleEndian(usbControlTransferPtr+8);

  //ETH_DEV_DBG_INFO("RNDIS request type = %x len=%u id=%u\n",type,len,id);
  if (type > 10 || len > 200) {
    ETH_DEV_DBG_INFO("Woopa!!!\n");
    oid    = uint32FromLittleEndian(usbControlTransferPtr+12);
    buflen = uint32FromLittleEndian(usbControlTransferPtr+16);
    bufptr = uint32FromLittleEndian(usbControlTransferPtr+20);
    if (type==4) ETH_DEV_DBG_INFO("QUERY OID=%x infolen=%d infooffset=%d",oid,buflen,bufptr);
    int iii;
    for (iii=0; iii<usbRequest.length; iii++)
      ETH_DEV_DBG_INFO("%02x",usbControlTransferPtr[iii]);
    while (1);
  }

  switch (type) {
  case 0x02: /* REMOTE_NDIS_INITIALIZE_MSG */
    ETH_DEV_DBG_INFO("  INITIALIZE_MSG version=%u.%u max device->host transfer size = %u",
        uint32FromLittleEndian(usbControlTransferPtr+12),
        uint32FromLittleEndian(usbControlTransferPtr+16),
        uint32FromLittleEndian(usbControlTransferPtr+20));


    if (rndisState != RNDIS_UNINITIALIZED) {
      ETH_DEV_DBG_ERROR("INITIALIZE message when we are not in the uninitialized state (state=%d)",rndisState);
      break;
    }
    //int i;
    //for (i=0; i<len; i++) {
    //  ETH_DEV_DBG_INFO("%d %02x",i,usbControlTransferPtr[i]);
    //}

    uint32ToLittleEndian(0x80000002,rndisResponse); /* INITIALIZE_CMPLT */
    uint32ToLittleEndian(52,rndisResponse+4);         /* length */
    uint32ToLittleEndian(id,rndisResponse+8);         /* request id to which we are responding */
    uint32ToLittleEndian(RNDIS_STATUS_SUCCESS,rndisResponse+12); /* status */
    uint32ToLittleEndian(1,rndisResponse+16);          /* version, major */
    uint32ToLittleEndian(0,rndisResponse+20);          /* version, minor */
    uint32ToLittleEndian(1,rndisResponse+24);          /* flags = connectionless */
    uint32ToLittleEndian(0,rndisResponse+28);          /* medium = 802.3 */
    uint32ToLittleEndian(1,rndisResponse+32);          /* max packets per transfer */
    /* the 22 is some voodoo from Linux drivers/gadget */
    uint32ToLittleEndian((11*4+ETHERNET_FRAME_SIZE_MAX+22),rndisResponse+36);  /* max transfer size; rndis header + ethernet packet */
    uint32ToLittleEndian(0,rndisResponse+40);          /* packet alignment for multi-packet transfers */
    uint32ToLittleEndian(0,rndisResponse+44);          /* reserved */
    uint32ToLittleEndian(0,rndisResponse+48);          /* reserved */
    rndisResponseLen   = 52;

    //usbControlTransferPtr = rndisResponse;
    //usbControlTransferLen = 24;

    rndisResponseReady = 1;
    eth_nak_interrupts |= INACK_II;
    usbEnableNAKInterrupts(eth_nak_interrupts);
    //usbEnableNAKInterrupts(INACK_II);

    rndisState = RNDIS_INITIALIZED; /* we should really do this only after sending the response */

    break;
  case 0x03: /* HALT */
    ETH_DEV_DBG_INFO("HALT!?!");

    rndisState = RNDIS_UNINITIALIZED; /* we should really do this only after sending the response */
    break;
  case 0x04: /* REMOTE_NDIS_QUERY_MSG */
    oid    = uint32FromLittleEndian(usbControlTransferPtr+12);
    buflen = uint32FromLittleEndian(usbControlTransferPtr+16);
    bufptr = uint32FromLittleEndian(usbControlTransferPtr+20);

    ETH_DEV_DBG_INFO("QUERY OID=%x infolen=%d infooffset=%d",oid,buflen,bufptr);
    if (buflen > 0) {
      //ETH_DEV_DBG_INFO("parameters???");
      //int iii;
      //for (iii=0; iii<usbRequest.length; iii++)
      //  ETH_DEV_DBG_INFO("%02x",usbControlTransferPtr[iii]);
      //while(1);
    }

    if (buflen+28 != len) {
      ETH_DEV_DBG_INFO("wrong size?");
      int iii;
      for (iii=0; iii<usbRequest.length; iii++)
        ETH_DEV_DBG_INFO("%02x",usbControlTransferPtr[iii]);
      while(1);
    }

    if (buflen>0 && bufptr != 28-8) {
      ETH_DEV_DBG_INFO("wrong offset?");
      int iii;
      for (iii=0; iii<usbRequest.length; iii++)
        ETH_DEV_DBG_INFO("%02x",usbControlTransferPtr[iii]);
      while(1);

    }

    uint32ToLittleEndian(0x80000004,rndisResponse); /* INITIALIZE_CMPLT */
    uint32ToLittleEndian(id,rndisResponse+8);         /* request id to which we are responding */

    rndisResponseLen   = 24;

    uint32_t response_size = 0;
    switch (oid) {

    case OID_GEN_SUPPORTED_LIST:
      rndisResponseLen += sizeof(rndisSupportedOIDs);
      memcpy(rndisResponse + 24, rndisSupportedOIDs, sizeof(rndisSupportedOIDs));
      break;

    case OID_GEN_PHYSICAL_MEDIUM:
      rndisResponseLen += sizeof(uint32_t);
      /* Indicate that the device is a true ethernet link */
      uint32ToLittleEndian(0,rndisResponse+24);

      break;
    case OID_GEN_HARDWARE_STATUS:
      rndisResponseLen += sizeof(uint32_t);
      uint32ToLittleEndian(0 /* ready */,rndisResponse+24);
      break;

    case OID_GEN_MEDIA_SUPPORTED:
    case OID_GEN_MEDIA_IN_USE:
      rndisResponseLen += sizeof(uint32_t);
      uint32ToLittleEndian(REMOTE_NDIS_MEDIUM_802_3,rndisResponse+24);
      break;

    case OID_GEN_VENDOR_ID:
      rndisResponseLen += sizeof(uint32_t);
      /* Vendor ID 0x0xFFFFFF is reserved for vendors who have not purchased a NDIS VID */
      uint32ToLittleEndian(0x00FFFFFF,rndisResponse+24);
      break;

    case OID_GEN_MAXIMUM_TOTAL_SIZE:
      rndisResponseLen += sizeof(uint32_t);
      /* Indicate maximum overall buffer (Ethernet frame and RNDIS header) the adapter can handle */
      uint32ToLittleEndian(11*4 + ETHERNET_FRAME_SIZE_MAX,rndisResponse+24);
      break;

    case OID_GEN_TRANSMIT_BLOCK_SIZE:
    case OID_GEN_RECEIVE_BLOCK_SIZE:
    case OID_GEN_MAXIMUM_FRAME_SIZE:
      rndisResponseLen += sizeof(uint32_t);
      uint32ToLittleEndian(ETHERNET_FRAME_SIZE_MAX,rndisResponse+24);
      //uint32ToLittleEndian(256,rndisResponse+24);
      break;

    //case OID_GEN_TRANSMIT_BLOCK_SIZE:
    //case OID_GEN_RECEIVE_BLOCK_SIZE:
    //  rndisResponseLen += sizeof(uint32_t);
    //  uint32ToLittleEndian(102 /* from contiki */,rndisResponse+24);
    //  break;

    case OID_GEN_VENDOR_DESCRIPTION:
      rndisResponseLen += 16;
      memcpy(rndisResponse+24, "Sivan Toledo\0\0\0\0",16);
      break;

    case OID_GEN_MEDIA_CONNECT_STATUS:
      rndisResponseLen += sizeof(uint32_t);
      uint32ToLittleEndian(REMOTE_NDIS_MEDIA_STATE_CONNECTED,rndisResponse+24);
      break;

    case OID_GEN_LINK_SPEED:
      rndisResponseLen += sizeof(uint32_t);
      /* Indicate 10Mb/s link speed */
      uint32ToLittleEndian(100000,rndisResponse+24);
      //DBG("get link speed");
      break;

    case OID_802_3_PERMANENT_ADDRESS:
    case OID_802_3_CURRENT_ADDRESS:
      rndisResponseLen += 6; // mac address
      memcpy(rndisResponse + 24, "\x22\x33\x44\x55\x66\x77", 6);
      // MAC address reused from some old Meraki Mini
      //memcpy(rndisResponse + 24, "\x00\x18\x0A\x01\xDF\x44", 6);

      break;

    case OID_802_3_MAXIMUM_LIST_SIZE:
      rndisResponseLen += sizeof(uint32_t);
      /* Indicate only one multicast address supported */
      uint32ToLittleEndian(1,rndisResponse+24);
      break;

    case OID_GEN_CURRENT_PACKET_FILTER:
      rndisResponseLen += sizeof(uint32_t);
      uint32ToLittleEndian(rndisCurrentPacketFilter,rndisResponse+24);
      break;

    case OID_GEN_RCV_ERROR:
    case OID_GEN_XMIT_ERROR:
    case OID_GEN_RCV_NO_BUFFER:
    case OID_802_3_MAC_OPTIONS:
    case OID_802_3_RCV_ERROR_ALIGNMENT:
    case OID_802_3_XMIT_ONE_COLLISION:
    case OID_802_3_XMIT_MORE_COLLISIONS:
      rndisResponseLen += sizeof(uint32_t);
      /* Unused statistic OIDs - always return 0 for each */
      uint32ToLittleEndian(0,rndisResponse+24);

      break;
    case OID_GEN_RCV_OK: // received by the interface means we sent the packet to teh host.
      rndisResponseLen += sizeof(uint32_t);
      uint32ToLittleEndian(rndisTxPackets,rndisResponse+24);
      break;
    case OID_GEN_XMIT_OK:
      rndisResponseLen += sizeof(uint32_t);
      uint32ToLittleEndian(rndisRxPackets,rndisResponse+24);
      break;
    case OID_802_3_MULTICAST_LIST:
      rndisResponseLen += sizeof(uint32_t);
      /* from Linux drivers/gadget */
      uint32ToLittleEndian(0xE0000000,rndisResponse+24);
      break;
    default:
      break;
    }

    if (rndisResponseLen == 24) {
      DBG("No response to query!?!");
      DBG("QUERY OID=%x infolen=%d infooffset=%d",oid,buflen,bufptr);
      uint32ToLittleEndian(RNDIS_STATUS_NOT_SUPPORTED,rndisResponse+12); /* status */
      //uint32ToLittleEndian(RNDIS_STATUS_FAILURE,rndisResponse+12); /* status */
      uint32ToLittleEndian(0,rndisResponse+16);         /* buffer length */
      uint32ToLittleEndian(0,rndisResponse+20);         /* buffer ptr */
    } else {
      ETH_DEV_DBG_INFO("response with %d bytes",rndisResponseLen);
      uint32ToLittleEndian(RNDIS_STATUS_SUCCESS,rndisResponse+12); /* status */
      uint32ToLittleEndian(rndisResponseLen-24,rndisResponse+16);         /* buffer length */
      uint32ToLittleEndian(24-8,rndisResponse+20);         /* buffer ptr */
    }
    uint32ToLittleEndian(rndisResponseLen,rndisResponse+4);         /* length */

    // xxx wrong!!!

    rndisResponseReady = 1;
    eth_nak_interrupts |= INACK_II;
    usbEnableNAKInterrupts(eth_nak_interrupts);
    //usbEnableNAKInterrupts(INACK_II);

    break;
  case 0x05: /* REMOTE_NDIS_SET_MSG */
    uint32ToLittleEndian(0x80000005,rndisResponse); /* INITIALIZE_CMPLT */
    uint32ToLittleEndian(16,rndisResponse+4);         /* length */
    uint32ToLittleEndian(id,rndisResponse+8);         /* request id to which we are responding */
    uint32ToLittleEndian(RNDIS_STATUS_SUCCESS,rndisResponse+12); /* status */
    rndisResponseLen   = 16;

    oid    = uint32FromLittleEndian(usbControlTransferPtr+12);
    buflen = uint32FromLittleEndian(usbControlTransferPtr+16);
    bufptr = uint32FromLittleEndian(usbControlTransferPtr+20);
    ETH_DEV_DBG_INFO("SET OID=%x infolen=%d infooffset=%d",oid,buflen,bufptr);
    switch (oid) {
    case OID_GEN_CURRENT_PACKET_FILTER:
      // the 8 byte offset is for the header, which is the first two words in the message
      rndisCurrentPacketFilter = uint32FromLittleEndian(usbControlTransferPtr+8+bufptr);
      ETH_DEV_DBG_INFO("packet filter = %x",rndisCurrentPacketFilter);
      if (rndisCurrentPacketFilter) rndisState = RNDIS_DATA_INITIALIZED;
      else                          rndisState = RNDIS_INITIALIZED;
      break;
    case OID_802_3_MULTICAST_LIST:
      // do nothing
      break;
    default:
      ETH_DEV_DBG_INFO("cannot set this...");
      while(1);
      break;
    }
    rndisResponseReady = 1;
    eth_nak_interrupts |= INACK_II;
    usbEnableNAKInterrupts(eth_nak_interrupts);
    //usbEnableNAKInterrupts(INACK_II);

    break;

  case 0x06: /* RESET */
    ETH_DEV_DBG_INFO("RESET");
    DBG("rndis RESET");
    //while (1); // for testing
    uint32ToLittleEndian(0x80000006,rndisResponse); /* INITIALIZE_CMPLT */
    uint32ToLittleEndian(16,rndisResponse+4);         /* length */
    uint32ToLittleEndian(RNDIS_STATUS_SUCCESS,rndisResponse+8); /* status */
    uint32ToLittleEndian(0,rndisResponse+8); /* addressing reset: no, don't send again */
    rndisResponseLen   = 16;

    rndisResponseReady = 1;
    eth_nak_interrupts |= INACK_II;
    usbEnableNAKInterrupts(eth_nak_interrupts);
    //usbEnableNAKInterrupts(INACK_II);

    rndisReset();

    break;
  case 0x07: /* INDICATE_STATUS */
    // wrong direction; we need to send this to the host...
    ETH_DEV_DBG_INFO("INDICATE STATUS");
    break;
  case 0x08: /* KEEPALIVE */
    ETH_DEV_DBG_INFO("KEEPALIVE");
    uint32ToLittleEndian(0x80000008,rndisResponse); /* INITIALIZE_CMPLT */
    uint32ToLittleEndian(12,rndisResponse+4);         /* length */
    uint32ToLittleEndian(id,rndisResponse+8);         /* request id to which we are responding */

    rndisResponseReady = 1;
    eth_nak_interrupts |= INACK_II;
    usbEnableNAKInterrupts(eth_nak_interrupts);
    break;
  default:
    ETH_DEV_DBG_INFO("class control request=%x interface=%u len=%u dir=%d\n",usbRequest.request,usbRequest.index,usbRequest.length,REQTYPE_GET_DIR(usbRequest.type));
    ETH_DEV_DBG_INFO("RNDIS request type = %x len=%u id=%u\n",type,len,id);
    break;

  }

  return TRUE;
}