void usb_eth_tx(uint8_t ep, uint8_t stat) { int len; int i; if (!packet_pending || bytes_to_send == 0) { ETH_DEV_DBG_INFO("usb_eth_tx, send buffer is empty, packet_pending=%d", packet_pending); usbEnableNAKInterrupts(0); return; } len = MIN(bytes_to_send - bytes_sent, MAX_PACKET_SIZE); usbWrite(ep, ((uint8_t*) &send_buffer)+bytes_sent, len); bytes_sent += len; ETH_DEV_DBG_INFO("usb_eth_tx: send %d bytes, frame data sent %d/%d", len, bytes_sent, bytes_to_send); if (bytes_sent >= bytes_to_send) { /* finished sending data */ for (i=0; i< bytes_to_send;i++) { send_buffer[i] = 0; } bytes_to_send = 0; bytes_sent = 0; packet_pending = 0; } }
void network_device_send() { int i; uint16_t len; if (packet_pending) { ETH_DEV_DBG_ERROR("network_device_send: already pending packet, discarding request"); return; } if (uip_len == 0) { ETH_DEV_DBG_ERROR("network_device_send: uip_len == 0"); return; } len = MIN(sizeof(send_buffer), uip_len); vicDisable(INT_CHANNEL_USB); for (i=0; i<len; i++) { send_buffer[i] = uip_buf[i]; } bytes_sent=0; bytes_to_send = len; packet_pending = 1; usbEnableNAKInterrupts(INACK_BI); vicEnable(INT_CHANNEL_USB); }
int usbnet_send(uint8_t* buffer, uint16_t length) { vicDisable(INT_CHANNEL_USB); int success = usbring_post_buffer(&send_ring, buffer, length); vicEnable(INT_CHANNEL_USB); if (success) { eth_nak_interrupts |= INACK_BI; usbEnableNAKInterrupts(eth_nak_interrupts); } return success; }
static void vcomBulkIn(uint8_t EP, uint8_t EPStatus) { int i; if (fifoAvailable(&txfifo) == 0) { usbEnableNAKInterrupts(0); return; } for (i = 0; i < MAX_PACKET_SIZE; i++) if (!fifoGet(&txfifo, &_vcom_buffer[i])) break; if (i > 0) usbWrite(EP, _vcom_buffer, i); }
static void usb_device_status_handler(uint8_t dev_status) { if (dev_status & DEV_STATUS_RESET) { LOG_INFO("USB Bus Reset status=%x\n\n",dev_status); recv_ring_drop = 0; usbring_reset(&recv_ring); usbring_reset(&send_ring); eth_nak_interrupts = 0; if (send_ring.size > 0) { eth_nak_interrupts |= INACK_BI; } usbEnableNAKInterrupts(eth_nak_interrupts); } }
void rndisReset(void) { ETH_DEV_DBG_INFO("rndis reset start"); rndisRxState = RNDIS_RX_IDLE; network_device_init(); //usbClear(USB_EP_OUT | RNDIS_BULK_EP); //usbClear(USB_EP_OUT | RNDIS_NOTIFICATION_EP); ETH_DEV_DBG_INFO("rndis reset end"); eth_nak_interrupts = 0; usbEnableNAKInterrupts(eth_nak_interrupts); }
void usb_rndis_notification(uint8_t ep, uint8_t stat) { if (stat & EP_STATUS_DATA) return; /* next buffer is full, wait */ if (rndisResponseReady) { //ETH_DEV_DBG_INFO("rndis notification: Yes! status=%02x\n",stat); usbWrite(ep, rndisResponseAvailable, 8); } else { //ETH_DEV_DBG_INFO("rndis notification: no... status=%02x\n",stat); } eth_nak_interrupts &= ~INACK_II; usbEnableNAKInterrupts(eth_nak_interrupts); //usbEnableNAKInterrupts(0); return; }
void network_device_send() { int i; uint16_t len; DBG("network device send! (%d bytes)",uip_len); if (uip_len == 0) { ETH_DEV_DBG_ERROR("network_device_send: uip_len == 0"); return; } vicDisable(INT_CHANNEL_USB); uint8_t packet_pending_copy = packet_pending; vicEnable(INT_CHANNEL_USB); if (packet_pending_copy) { ETH_DEV_DBG_ERROR("network_device_send: already pending packet, discarding request"); return; } len = MIN(sizeof(send_buffer), uip_len); for (i=0; i<len; i++) { send_buffer[i] = uip_buf[i]; } vicDisable(INT_CHANNEL_USB); bytes_sent=0; bytes_to_send = len; packet_pending = 1; eth_nak_interrupts |= INACK_BI; usbEnableNAKInterrupts(eth_nak_interrupts); vicEnable(INT_CHANNEL_USB); //ETH_DEV_DBG_ERROR("network_device_send: NACK Interrupts enable on bulk in"); //DBG("leaving network send"); }
void usb_cdc_ecm_tx(uint8_t ep, uint8_t stat) { int len; int i; //printf(" cdc_ecm tx "); if (!stat & EP_STATUS_NACKED) { DBG("tx endpoint interrupt, but not NAK"); return; } if (!packet_pending || bytes_to_send == 0) { ETH_DEV_DBG_INFO("usb_eth_tx, send buffer is empty, packet_pending=%d", packet_pending); eth_nak_interrupts &= ~INACK_BI; usbEnableNAKInterrupts(eth_nak_interrupts); return; } len = MIN(bytes_to_send - bytes_sent, MAX_PACKET_SIZE); usbWrite(ep, ((uint8_t*) &send_buffer)+bytes_sent, len); bytes_sent += len; if (bytes_sent >= bytes_to_send /* we sent all the data */ && len < MAX_PACKET_SIZE) /* and we don't need to send a zero-length termination packet */ { /* finished sending data */ rndisTxPackets++; bytes_to_send = 0; bytes_sent = 0; packet_pending = 0; //eth_nak_interrupts &= ~INACK_BI; //usbEnableNAKInterrupts(eth_nak_interrupts); } }
static void usb_cdc_ecm_tx(uint8_t ep, uint8_t stat) { int len; // Not a NAK interrupt - irrelevant //if (!stat & EP_STATUS_NACKED) { // return; //} // if nothing to send anymore - disable NAK interrupts if (send_ring.size == 0) { eth_nak_interrupts &= ~INACK_BI; usbEnableNAKInterrupts(eth_nak_interrupts); return; } if (stat & EP_STATUS_DATA) { return; } // get first buffer from the ring and send it starting from current point volatile usb_buffer_t* buffer = &send_ring.buffers[send_ring.begin]; // calculate how much bytes are left and limit it with maximal USB packet size len = MIN(buffer->length - buffer->current, MAX_USB_PACKET_SIZE); // send the bytes and update current position inside the buffer usbWrite(ep, buffer->data + buffer->current, len); buffer->current += len; // in case we finished sending the current buffer, // check whether the sent USB packet was shorter than maximal - that's how // we notify the host about end of frame. // If so, free the buffer from the ring (host is already notified) // Otherwise do nothing, so the next time zero length packet will be sent. if (buffer->length == buffer->current && len < MAX_USB_PACKET_SIZE) { usbring_free_buffer(&send_ring); } }
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; }
void usb_rndis_tx(uint8_t ep, uint8_t stat) { int len; int i; //DBG("rndis tx\n"); if (!stat & EP_STATUS_NACKED) { DBG("tx endpoint interrupt, but not NAK"); return; } if (!packet_pending || bytes_to_send == 0) { ETH_DEV_DBG_INFO("usb_eth_tx, send buffer is empty, packet_pending=%d", packet_pending); eth_nak_interrupts &= ~INACK_BI; usbEnableNAKInterrupts(eth_nak_interrupts); return; } if (bytes_sent == 0) { /* prepend rndis header */ memset(rndisPacketHeader,0,44); uint32ToLittleEndian(1,rndisPacketHeader); // type uint32ToLittleEndian(44+bytes_to_send,rndisPacketHeader+4); uint32ToLittleEndian(44-8,rndisPacketHeader+8); // type uint32ToLittleEndian(bytes_to_send,rndisPacketHeader+12); // type /* copy start of frame to buffer */ len = MIN(bytes_to_send, 64-44); memcpy(rndisPacketHeader + 44, send_buffer, len); usbWrite(ep, rndisPacketHeader, 44+len); bytes_sent += len; //DBG("sent header and %d bytes out of %d",len,bytes_to_send); } else { len = MIN(bytes_to_send - bytes_sent, MAX_PACKET_SIZE); usbWrite(ep, ((uint8_t*) &send_buffer)+bytes_sent, len); bytes_sent += len; //DBG("usb_eth_tx: send %d bytes, frame data sent %d/%d", // len, bytes_sent, bytes_to_send); } if (bytes_sent >= bytes_to_send) { /* finished sending data */ //DBG("usb_rndis_tx: send done... (%d bytes)",bytes_to_send); //for (i=0; i< bytes_to_send;i++) { // send_buffer[i] = 0; //} rndisTxPackets++; bytes_to_send = 0; bytes_sent = 0; packet_pending = 0; //eth_nak_interrupts &= ~INACK_BI; //usbEnableNAKInterrupts(eth_nak_interrupts); } }
void vcomPutchar(int c) { vicDisable(INT_CHANNEL_USB); fifoPut(&txfifo, c); usbEnableNAKInterrupts(INACK_BI); vicEnable(INT_CHANNEL_USB); }