示例#1
0
/**
 *  \brief Process successfully sent packets
 *  \param gmacd Pointer to GMAC Driver instance.
 */
static void _gmacd_tx_complete_handler(struct _gmacd* gmacd, uint8_t queue)
{
	Gmac* gmac = gmacd->gmac;
	struct _gmacd_queue* q = &gmacd->queues[queue];
	struct _gmac_desc *desc;
	gmacd_callback_t callback;
	uint32_t tsr;

	//printf("<TX>\r\n");

	/* Clear status */
	tsr = gmac_get_tx_status(gmac);
	gmac_clear_tx_status(gmac, tsr);

	while (!RING_EMPTY(q->tx_head, q->tx_tail)) {
		desc = &q->tx_desc[q->tx_tail];

		/* Exit if frame has not been sent yet:
		 * On TX completion, the GMAC set the USED bit only into the
		 * very first buffer descriptor of the sent frame.
		 * Otherwise it updates this descriptor with status error bits.
		 * This is the descriptor writeback.
		 */
		if ((desc->status & GMAC_TX_STATUS_USED) == 0)
			break;

		/* Process all buffers of the current transmitted frame */
		while ((desc->status & GMAC_TX_STATUS_LASTBUF) == 0) {
			RING_INC(q->tx_tail, q->tx_size);
			desc = &q->tx_desc[q->tx_tail];
		}

		/* Notify upper layer that a frame has been sent */
		if (q->tx_callbacks) {
			callback = q->tx_callbacks[q->tx_tail];
			if (callback)
				callback(queue, tsr);
		}

		/* Go to next frame */
		RING_INC(q->tx_tail, q->tx_size);
	}

	/* If a wakeup callback has been set, notify upper layer that it can
	   send more packets now */
	if (q->tx_wakeup_callback) {
		if (RING_SPACE(q->tx_head, q->tx_tail, q->tx_size) >=
				q->tx_wakeup_threshold) {
			q->tx_wakeup_callback(queue);
		}
	}
}
示例#2
0
uint16_t network_device_read() {
  uint16_t ret = 0;
  int i;
  packet_t *packet = 0;
  //if (xxx) DBG("device read");

  vicDisable(INT_CHANNEL_USB);
  if (!RING_IS_EMPTY(receive_ring_head, receive_ring_tail, RECEIVE_RING_SIZE)) {
    packet = &receive_ring[receive_ring_head];
    if (packet->size == 0) packet = 0;
  }
  vicEnable(INT_CHANNEL_USB);

  if (packet) {
    /* we got ip packet, copy it and notify uip framework */
    //ETH_DEV_DBG_INFO("Got a packet!");
    DBG("Got a packet! (%d bytes)",packet->size);
    packet = &receive_ring[receive_ring_head];
    for (i=0; i<packet->size; i++) {
      uip_buf[i] = packet->data[i];
      //packet->data[i] = 0;
    }
    ret = packet->size;
    packet->size = 0;

    vicDisable(INT_CHANNEL_USB);
    RING_INC(receive_ring_head, RECEIVE_RING_SIZE);
    vicEnable(INT_CHANNEL_USB);
  }
  return ret;
}
示例#3
0
void usb_cdc_ecm_rx(uint8_t ep, uint8_t stat) {
  int len;
  int ip_length;
  int i;
  uint16_t eth_hdr_type;

  //printf("cdc ecm rx ep-state=%x state=%d transferred=%d",stat,rndisRxState,rndisRxTransferCount);

  switch (rndisRxState) {
  case RNDIS_RX_IDLE:
    rndisRxTransferCount = 0;
    rndisRxPacketSize    = 0; /* it may increase later */
    /* hopefully, it follows the header immediately... */

    if (receive_packet == 0) {
      if (RING_IS_FULL(receive_ring_head, receive_ring_tail, RECEIVE_RING_SIZE)) {
        rndisRxState = RNDIS_RX_DROP;
        DBG("usb_eth_rx: receive ring is full, head=%d, tail=%d",receive_ring_head, receive_ring_tail);
        len = usbRead(ep, NULL, 64);
      } else {
        rndisRxState = RNDIS_RX_RECV;

        receive_packet = &receive_ring[receive_ring_tail];
        packet_init(receive_packet);

        len = usbRead(ep, receive_packet->data , 64);
        rndisRxTransferCount += len;
      }
    }
    break;

  case RNDIS_RX_DROP:
    len = usbRead(ep, NULL, 64);
    //ETH_DEV_DBG_INFO("rndis rx read %d bytes more in drop state",len);
    if (len >= 0) rndisRxTransferCount += len;
    break;

  case RNDIS_RX_RECV:
    len = usbRead(ep, (receive_packet->data) + rndisRxTransferCount, 64 /* maybe we need to limit this */);

    if (len >= 0) rndisRxTransferCount += len;
    break;
  }

  if (len < 64) { /* a short packet terminates the Ethernet frame */
    rndisRxPackets++;
    DBG("cdc ecm rx done with a packet (%d bytes)",rndisRxTransferCount);
    //for (i=0; i<rndisRxPacketSize; i++) DBG("%d %02x",i,(receive_packet->data)[i]);
    //if (rndisRxPacketSize==54) while(1);
    if (rndisRxState == RNDIS_RX_RECV) {
      receive_packet->size = rndisRxTransferCount;
      receive_packet = 0;
      RING_INC(receive_ring_tail, RECEIVE_RING_SIZE);
    }
    rndisRxState = RNDIS_RX_IDLE;
  }
}
示例#4
0
static void unix_add_to_history(zchar *str)
{

    if (*history_next != NULL)
	free( *history_next);
    *history_next = (char *)malloc(strlen((char *)str) + 1);
    strcpy( *history_next, (char *)str);
    RING_INC( history_next, history_buffer, history_end);
    history_view = history_next; /* Reset user frame after each line */
}
示例#5
0
uint16_t network_device_read()
{
  uint16_t ret = 0;
  int i;
  packet_t *packet;
  if (!RING_IS_EMPTY(receive_ring_head, receive_ring_tail, RECEIVE_RING_SIZE)) {
    /* we got ip packet, copy it and notify uip framework */
    packet = &receive_ring[receive_ring_head];
    for (i=0; i<packet->transferred; i++) {
      uip_buf[i] = packet->data[i];
      packet->data[i] = 0;
    }
    ret = packet->transferred;
    packet->transferred = 0;
    RING_INC(receive_ring_head, RECEIVE_RING_SIZE);
  }
  return ret;
}
示例#6
0
/*
 * unix_history_forward
 *
 * Opposite of unix_history_back, and works in the same way.
 */
static int unix_history_forward(zchar *str, int searchlen, int maxlen)
{
    char **prev = history_view;

    do {
	RING_INC( history_view, history_buffer, history_end);
	if ((history_view == history_next)
	    || (*history_view == NULL)) {

	    os_beep(BEEP_HIGH);
	    history_view = prev;
	    return 0;
	}
    } while (strlen( *history_view) > maxlen
	     || (searchlen != 0 && strncmp( (char *)str, *history_view, searchlen)));
    strcpy((char *)str + searchlen, *history_view + searchlen);
    return 1;
}
示例#7
0
void usb_eth_rx(uint8_t ep, uint8_t stat)
{
  int len;
  int ip_length;
  uint16_t eth_hdr_type;

  if (receive_packet == 0) {
    if (RING_IS_FULL(receive_ring_head, receive_ring_tail, RECEIVE_RING_SIZE)) {
      ETH_DEV_DBG_ERROR("usb_eth_rx: receive ring is full, head=%d, tail=%d",
                        receive_ring_head, receive_ring_tail);
      return;
    }
    receive_packet = &receive_ring[receive_ring_tail];
    packet_init(receive_packet);
  }

  if (receive_packet->transferred < PACKET_SIZE) {
    len = usbRead(ep,
                  &receive_packet->data[0] + receive_packet->transferred,
                  PACKET_SIZE - receive_packet->transferred);
  }
  else {
    /* discard the bytes */
    len = usbRead(ep, 0, 0);
  }
  receive_packet->transferred += len;
  
  ETH_DEV_DBG_INFO("usb_eth_rx: read %d bytes, head=%d, tail=%d",
                   len,
                   receive_ring_head,
                   receive_ring_tail);

  if (receive_packet->transferred < UIP_LLH_LEN) {
    /* ethernet header was not received yet got some garbage which we need
     to ignore */
    ETH_DEV_DBG_ERROR("got part of packet with %d bytes", receive_packet->transferred);
    receive_packet->transferred = 0;
    return;
  }

  if (receive_packet->size == 0) {
    eth_hdr_type = (receive_packet->data[0xc] << 8) | receive_packet->data[0xd];
  
    if (eth_hdr_type == UIP_ETHTYPE_IP) {
      ip_length = receive_packet->data[0x10]*0xff + receive_packet->data[0x11];
      receive_packet->size = ip_length + UIP_LLH_LEN;
    }
    else if (eth_hdr_type == UIP_ETHTYPE_ARP) {
      receive_packet->size = receive_packet->transferred;
    }
    else {
      ETH_DEV_DBG_ERROR("Unknown ethernet frame 0x%x", eth_hdr_type);
      receive_packet->size = receive_packet->transferred;
    }
  }

  if (receive_packet->transferred >= receive_packet->size) {
    if (receive_packet->transferred >= receive_packet->size) {
      if (receive_packet->transferred >= PACKET_SIZE) {
        ETH_DEV_DBG_ERROR("Discarding packet of size %d", receive_packet->transferred);
        packet_init(receive_packet);
        receive_packet = 0;
      }
      else {
        ETH_DEV_DBG_INFO("Received packet of size %d", receive_packet->transferred);
        receive_packet = 0;
        RING_INC(receive_ring_tail, RECEIVE_RING_SIZE);
      }
    }
  }
}
示例#8
0
void usb_rndis_rx(uint8_t ep, uint8_t stat) {
  int len;
  int ip_length;
  int i;
  uint16_t eth_hdr_type;

  if (!(stat & EP_STATUS_DATA)) {
    ETH_DEV_DBG_ERROR("rndis rx, no data...");
    return;
  }

  //DBG("rndis rx ep-state=%x state=%d packetsize=%d transferred=%d",stat,rndisRxState,rndisRxPacketSize,rndisRxTransferCount);

  switch (rndisRxState) {
  case RNDIS_RX_IDLE:
  //if (rndisRxState == RNDIS_RX_IDLE) {
    len = usbRead(ep, rndisPacketHeader, 64);
    if (len==1 && rndisPacketHeader[0] == 0) {
      DBG("single byte USB packet (this is normal for rndis");
      return;
    }

    if (len < 44) {
      ETH_DEV_DBG_ERROR("Whoops, USB packet length shorter than RNDIS message header (only %d bytes)",len);
      return;
    }

    uint32_t type     = uint32FromLittleEndian(rndisPacketHeader);
    uint32_t rndislen = uint32FromLittleEndian(rndisPacketHeader+4);
    uint32_t dataoff  = uint32FromLittleEndian(rndisPacketHeader+8);
    uint32_t datalen  = uint32FromLittleEndian(rndisPacketHeader+12);
    uint32_t ooboff   = uint32FromLittleEndian(rndisPacketHeader+16);
    uint32_t ooblen   = uint32FromLittleEndian(rndisPacketHeader+20);
    uint32_t numoob   = uint32FromLittleEndian(rndisPacketHeader+24);
    uint32_t perpacket_infooff = uint32FromLittleEndian(rndisPacketHeader+28);
    uint32_t perpacket_infolen = uint32FromLittleEndian(rndisPacketHeader+32);

    //DBG("rndis rx type=%x len=%d dataoff=%d datalen=%d ooblen=%d numoob=%d perpacket_infooff=%d perpacket_infolen=%d",
    //    type,len,dataoff,datalen,ooblen,numoob,perpacket_infooff,perpacket_infolen);

    if (type != 1) while(1);

    rndisRxTransferCount = 0;
    rndisRxPacketSize    = datalen;
    /* hopefully, it follows the header immediately... */

    if (receive_packet == 0) {
      if (RING_IS_FULL(receive_ring_head, receive_ring_tail, RECEIVE_RING_SIZE)) {
        DBG("usb_eth_rx: receive ring is full, head=%d, tail=%d",receive_ring_head, receive_ring_tail);
        rndisRxState = RNDIS_RX_DROP;
        for (i=0; i<(len-44); i++) {
           rndisRxTransferCount++;
        }
      } else {
        rndisRxState = RNDIS_RX_RECV;
        receive_packet = &receive_ring[receive_ring_tail];
        packet_init(receive_packet);

        for (i=0; i<(len-44); i++) {
          (receive_packet->data)[ rndisRxTransferCount ] = rndisPacketHeader[44+i];
           rndisRxTransferCount++;
        }
      }
    }
    break;

  case RNDIS_RX_DROP:
  //if (rndisRxState == RNDIS_RX_DROP) {
    len = usbRead(ep, NULL, rndisRxPacketSize - rndisRxTransferCount);
    //ETH_DEV_DBG_INFO("rndis rx read %d bytes more in drop state",len);

    if (len >= 0)
      rndisRxTransferCount += len;
    break;
//  }

  case RNDIS_RX_RECV:
  //if (rndisRxState == RNDIS_RX_RECV) {
    //DBG("rndis rx recv read from endpoint");
    len = usbRead(ep, (receive_packet->data) + rndisRxTransferCount, rndisRxPacketSize - rndisRxTransferCount);
    //DBG("rndis rx read %d bytes more in recv state",len);

    if (len >= 0)
      rndisRxTransferCount += len;
    break;
  }

  if (rndisRxTransferCount == rndisRxPacketSize) {
    rndisRxPackets++;
    DBG("rndis rx done with a packet (%d bytes)",rndisRxPacketSize);
    //for (i=0; i<rndisRxPacketSize; i++) DBG("%d %02x",i,(receive_packet->data)[i]);
    //if (rndisRxPacketSize==54) while(1);
    if (rndisRxState == RNDIS_RX_RECV) {
      receive_packet->size = rndisRxPacketSize;
      receive_packet = 0;
      RING_INC(receive_ring_tail, RECEIVE_RING_SIZE);
      xxx = 1;
    }
    rndisRxState = RNDIS_RX_IDLE;
  }

}
示例#9
0
/**
 * \brief Receive a packet with GMAC.
 * If not enough buffer for the packet, the remaining data is lost but right
 * frame length is returned.
 *  \param gmacd Pointer to GMAC Driver instance.
 *  \param pFrame           Buffer to store the frame
 *  \param frameSize        Size of the frame
 *  \param pRcvSize         Received size
 *  \return                 OK, no data, or frame too small
 */
uint8_t gmacd_poll(struct _gmacd* gmacd, uint8_t queue,
	uint8_t* buffer, uint32_t buffer_size, uint32_t* recv_size)
{
	struct _gmacd_queue* q = &gmacd->queues[queue];
	struct _gmac_desc *desc;
	uint32_t idx;
	uint32_t cur_frame_size = 0;
	uint8_t *cur_frame = 0;

	if (!buffer)
		return GMACD_PARAM;

	/* Set the default return value */
	*recv_size = 0;

	/* Process RX descriptors */
	idx = q->rx_head;
	desc = &q->rx_desc[idx];
	while (desc->addr & GMAC_RX_ADDR_OWN) {
		/* A start of frame has been received, discard previous fragments */
		if (desc->status & GMAC_RX_STATUS_SOF) {
			/* Skip previous fragment */
			while (idx != q->rx_head) {
				desc = &q->rx_desc[q->rx_head];
				desc->addr &= ~GMAC_RX_ADDR_OWN;
				RING_INC(q->rx_head, q->rx_size);
			}
			cur_frame = buffer;
			cur_frame_size = 0;
		}

		/* Increment the index */
		RING_INC(idx, q->rx_size);

		/* Copy data in the frame buffer */
		if (cur_frame) {
			if (idx == q->rx_head) {
				trace_info("no EOF (buffers probably too small)\r\n");

				do {
					desc = &q->rx_desc[q->rx_head];
					desc->addr &= ~GMAC_RX_ADDR_OWN;
					RING_INC(q->rx_head, q->rx_size);
				} while (idx != q->rx_head);
				return GMACD_RX_NULL;
			}

			/* Copy the buffer into the application frame */
			uint32_t length = GMAC_RX_UNITSIZE;
			if ((cur_frame_size + length) > buffer_size) {
				length = buffer_size - cur_frame_size;
			}

			uint32_t addr = desc->addr & GMAC_RX_ADDR_MASK;
			l2cc_invalidate_region(addr, addr + length);
			memcpy(cur_frame, (void*)addr, length);
			cur_frame += length;
			cur_frame_size += length;

			/* An end of frame has been received, return the data */
			if (desc->status & GMAC_RX_STATUS_EOF) {
				/* Frame size from the GMAC */
				*recv_size = desc->status & GMAC_RX_STATUS_LENGTH_MASK;

				/* Application frame buffer is too small all
				 * data have not been copied */
				if (cur_frame_size < *recv_size) {
					return GMACD_SIZE_TOO_SMALL;
				}

				/* All data have been copied in the application
				 * frame buffer => release descriptors */
				while (q->rx_head != idx) {
					desc = &q->rx_desc[q->rx_head];
					desc->addr &= ~GMAC_RX_ADDR_OWN;
					RING_INC(q->rx_head, q->rx_size);
				}

				return GMACD_OK;
			}
		}

		/* SOF has not been detected, skip the fragment */
		else {
			desc->addr &= ~GMAC_RX_ADDR_OWN;
			q->rx_head = idx;
		}

		/* Process the next buffer */
		desc = &q->rx_desc[idx];
	}
	return GMACD_RX_NULL;
}
示例#10
0
/**
 *  \brief Reset TX queue when errors are detected
 *  \param gmacd Pointer to GMAC Driver instance.
 */
static void _gmacd_tx_error_handler(struct _gmacd* gmacd, uint8_t queue)
{
	Gmac *gmac = gmacd->gmac;
	struct _gmacd_queue* q = &gmacd->queues[queue];
	struct _gmac_desc* desc;
	gmacd_callback_t callback;
	uint32_t tsr;

	printf("<TXERR>\r\n");

	/* Clear TXEN bit into the Network Configuration Register:
	 * this is a workaround to recover from TX lockups that
	 * occur on sama5d4 gmac (r1p24f2) when using  scatter-gather.
	 * This issue has never been seen on sama5d4 gmac (r1p31).
	 */
	gmac_transmit_enable(gmac, false);

	/* The following step should be optional since this function is called
	 * directly by the IRQ handler. Indeed, according to Cadence
	 * documentation, the transmission is halted on errors such as
	 * too many retries or transmit under run.
	 * However it would become mandatory if the call of this function
	 * were scheduled as a task by the IRQ handler (this is how Linux
	 * driver works). Then this function might compete with GMACD_Send().
	 *
	 * Setting bit 10, tx_halt, of the Network Control Register is not enough:
	 * We should wait for bit 3, tx_go, of the Transmit Status Register to
	 * be cleared at transmit completion if a frame is being transmitted.
	 */
	gmac_halt_transmission(gmac);
	while (gmac_get_tx_status(gmac) & GMAC_TSR_TXGO);

	/* Treat frames in TX queue including the ones that caused the error. */
	while (!RING_EMPTY(q->tx_head, q->tx_tail)) {
		int tx_completed = 0;
		desc = &q->tx_desc[q->tx_tail];

		/* Check USED bit on the very first buffer descriptor to validate
		 * TX completion.
		 */
		if (desc->status & GMAC_TX_STATUS_USED)
			tx_completed = 1;

		/* Go to the last buffer descriptor of the frame */
		while ((desc->status & GMAC_TX_STATUS_LASTBUF) == 0) {
			RING_INC(q->tx_tail, q->tx_size);
			desc = &q->tx_desc[q->tx_tail];
		}

		/* Notify upper layer that a frame status */
		// TODO: which error to notify?
		if (q->tx_callbacks) {
			callback = q->tx_callbacks[q->tx_tail];
			if (callback)
				callback(queue, tx_completed ? GMAC_TSR_TXCOMP : 0);
		}

		/* Go to next frame */
		RING_INC(q->tx_tail, q->tx_size);
	}

	/* Reset TX queue */
	_gmacd_reset_tx(gmacd, queue);

	/* Clear status */
	tsr = gmac_get_tx_status(gmac);
	gmac_clear_tx_status(gmac, tsr);

	/* Now we are ready to start transmission again */
	gmac_transmit_enable(gmac, true);
	if (q->tx_wakeup_callback)
		q->tx_wakeup_callback(queue);
}