void SMSC9218_RX_ISR()
{       
    DWORD RxStatus, packet_len, dw;
    DWORD numPacketReceived;
    DWORD RxFFCountDW;
    DCU msg;
    unsigned char* recv_packet;
    unsigned long temp;
    int tries = 0;

    dw = RX_FIFO_INF;
    numPacketReceived = (dw & 0x00FF0000) >> 16;

    while(numPacketReceived)
    {
        tries = 0;
        RxStatus = RX_STS_FIFO_PORT;
        packet_len = (RxStatus & 0x3FFF0000) >> 16;

        if (!(RxStatus & RX_STS_ERROR) && 
            !(((RxStatus & RX_STS_LEN_ERROR) == RX_STS_LEN_ERROR) && 
            ((RxStatus & RX_STS_FRAME_TYPE) == 0)))
        {   
            do
            {
                msg = os_alloc_packet_input(packet_len - 2, DRIVER_ALLOC);
                if(!msg)
                    for(int i = 0; i < 500; i++);       //delay
            }while(!msg && tries++ < 50);
                    
            if(msg)
            {
                unsigned long *rxbpl    = (unsigned long *) RX_BUFFER;
                unsigned char *rx_ptr   = (unsigned char *) RX_BUFFER;
                int ndx;
                    
                for (ndx = ((packet_len + 2 + 3) >> 2); ndx > 0; ndx--)
                {
                    temp = RX_DATA_FIFO_PORT;
                    *rxbpl++ = BIT_EDIANDW(temp);
                }

                recv_packet = (unsigned char*)DCUTODATA(msg);
                msg->length = packet_len - 2;
                memcpy(recv_packet, rx_ptr + 2, packet_len - 2);
                rtp_net_invoke_input(iface, msg, msg->length);              
            }
            else
            {
                // Read off and discard the packet.
                RxFFCountDW = (packet_len + 2 + 3) >> 2;
                SMSC9218_RX_Fast_Forward(RxFFCountDW);
            }
        }
        else
        {
示例#2
0
void davicom_interrupt(int minor_no)
{
dword status;
PDAVICOM_SOFTC softc;
PDESCRIPTOR pdesc;
DCU msg;
int pkt_len;

    softc = off_to_davicom_softc(minor_no);
    if (!softc)
        return;

     status = READ_CR(DC_STATUS_ISR_CR5);
     WRITE_CR(DC_STATUS_ISR_CR5, status);

     status &= DC_STATUS_MASK;  /* keep only bits we are interested in */

     if (status & DC_ISR_RX_DONE)
         while (1)
         {
            pdesc = softc->rx_desc + softc->this_rx;
            if (pdesc->buffer == 0)
               break;
            if (pdesc->status & OWN_BIT)
               break;
            if ((pdesc->status & (ES_BIT|PLE_BIT|AE_BIT)) == 0) /* no error */
            {
                pkt_len = (pdesc->status >> 16) & 2047;
                msg = softc->rx_dcus[softc->this_rx];

                /* set up length of packet; MUST be set to actual size      */
                /* not including crc etc even if allocated a larger         */
                /* packet above                                             */
                DCUTOPACKET(msg)->length = pkt_len;

                softc->stats.packets_in++;
                softc->stats.bytes_in += pkt_len;

                /* signal IP layer that a packet is on its exchange'      */
                /* send packet from ring buffer                           */
                ks_invoke_input(softc->iface, msg);

                /* replace current DCU from ring buffer just passed to      */
                /* IP task with a new DCU                                   */
                softc->rx_dcus[softc->this_rx] = msg = os_alloc_packet_input(CFG_MAX_PACKETSIZE+4, DRIVER_ALLOC);
                if (msg)
                   pdesc->buffer = (dword) DCUTODATA(msg);
                else
                {
                   pdesc->buffer = 0; /* out of buffers */
                   DEBUG_ERROR("davicom_interrupt: out of DCUs", NOVAR, 0, 0);
                }
            }
            else /* error receive, discard */
            {
int SH7619_EDMAC_xmit(PIFACE pi, DCU msg)
{
	RTP_UINT16              length = 0;
	EmacTDescriptor *pTxTd;
	char* send_packet;
	UINT16  count;
	long    flag = FP1;
	UINT16  size = length;

	GLOBAL_LOCK(encIrq);

	if (!pi)
	{
		return (-1);
	}   

	length = msg->length;

	if (length > (ETHERSIZE+4))
	{
		RTP_DEBUG_ERROR("xmit - length is too large, truncated", NOVAR, 0, 0);
		length = ETHERSIZE+4;         /* what a terriable hack! */
	}

	send_packet = (char*)DCUTODATA(msg);

	for( count = 0 ; length > 0 ; length -= count )
	{  
    	// Pointers to the current TxTd
    	pTxTd = *(txTd.td + txTd.head);
		while( (count = Send_Packet(pTxTd, send_packet, length)) < 0 );
		if( count == length )
		{
			flag |= FP0;
		}
		pTxTd->status = (pTxTd->status & DL) | flag | ACT;
		flag = 0;

		// Driver manage the ring buffer
		CIRC_INC(txTd.head, TX_BUFFERS)

		send_packet += count;
	}

	// Now start to transmit if it is not already done
	if( EDTRR0 == 0x00000000 )
	{
		EDTRR0 = 0x00000001;
	}

	return (0);
}
示例#4
0
void timeout(void * vsc)
{
   PDAVICOM_SOFTC softc = vsc;

   if (softc->OutOfBuffers)
   {
      int i;

      softc->OutOfBuffers = 0;

      for (i=0; i<DC_RX_RING_SIZE; i++)
      {
         PDESCRIPTOR pdesc = softc->rx_desc + i;

         if (pdesc->buffer == 0)
         {
            DCU msg;

            softc->rx_dcus[i] = msg = os_alloc_packet_input(CFG_MAX_PACKETSIZE+4, DRIVER_ALLOC);
            if (msg)
            {
               pdesc->buffer = (dword) DCUTODATA(msg);
               pdesc->status = OWN_BIT;
#if DEBUG_DAVICOM
               DEBUG_ERROR("davicom_timeout: added new receive DCU", NOVAR, 0, 0);
#endif
            }
            else
            {
#if DEBUG_DAVICOM
               DEBUG_ERROR("davicom_timeout: out of DCUs", NOVAR, 0, 0);
#endif
            }
         }
      }

      /* get receiver going again   */
#if DEBUG_DAVICOM
      DEBUG_ERROR("davicom_timeout: restart receiver stalled at ", EBS_INT1, softc->this_rx, 0);
#endif
      softc->this_rx = 0;
      WRITE_CR(DC_RX_BASE_ADDR_CR3, (dword)(softc->rx_desc));
      WRITE_CR(DC_RX_START_CR2, 0xFFFFFFFF);
   }
   ebs_start_timer(&softc->timer);
}
/* ********************************************************************
   Transmit. a packet over the packet driver interface.
   
   This routine is called when a packet needs sending. The packet contains a
   full ethernet frame to be transmitted. The length of the packet is 
   provided.
  
   Returns 0 if successful or errno if unsuccessful
  
   ********************************************************************     */
int loop_xmit(PIFACE pi, DCU msg)    
{
    NATIVE_PROFILE_HAL_DRIVERS_ETHERNET();
    DCU lb_msg;
    int length;
    PIPPKT pip;
    PIFACE pi_send;
    RTP_BOOL is_802_2;
    
#if (DEBUG_LOOP)
    static int cnt = 0;
    static DCU msg1, msg2, msg3 = 0;

	if (msg != 0)
	{
		if (cnt == 0)
		{
			msg1 = msg;
			cnt++;
			/*  return xmit done     */
			return(REPORT_XMIT_MORE);			
		}
		if (cnt == 1)
		{
			msg2 = msg;
			cnt++;
			/*  return xmit done     */
			return(REPORT_XMIT_MORE);	
		}
		if (cnt == 2)
		{
			msg3 = msg;
			cnt++;
			/*  return xmit done     */
			return(REPORT_XMIT_MORE);	
		}
	}
	if (cnt == 3 || msg == 0)
	{
		cnt = -1;
		if (msg1)
			loop_xmit(pi, msg1);
		if (msg2)
			loop_xmit(pi, msg2);
		if (msg3)
			loop_xmit(pi, msg3);
		cnt = 0;
		msg1 = msg2 = msg3 = 0;
		if (msg == 0)
			return(0);
	}
#endif

  length = msg->length;
  
#if (DEBUG_LOOP)
    DEBUG_ERROR("loop_xmit: packet,len = ", DINT2, DCUTODATA(msg), length);
    DEBUG_ERROR("loop_xmit: PACKET = ", PKT, DCUTODATA(msg), length);
#endif

	

    /* allocate DCU for msg; 
       For non loopback case, msg will be queued and freed when
       sent out only if PKT_FLAG_KEEP is not set.
       But for loopback, copy of msg will not go thru the output queue, but
       will go straight to IP list which will free it
       after interpreting it.  Therefore, copy it to
       a new allocated DCU and the new DCU will be freed after
       it is processed on the input side.  The origional DCU
	   will be freed according to dcu_flags.  The origional DCU
	   is on the output list, therefore, it will signal according
	   to the flags in the origional DCU, therefore, signal flag
	   does not have to be set in the new DCU.
	   IN OTHER WORDS, the packet could have been allocated by the
	   application who would be the only task which should free the
	   packet and the IP task will always free an incoming packet when
	   done, therefore, allocate a new one
       NOTE: the new packet has flags 0, i.e. do not keep, do not signal
    // NOTE: netwrite() will call tc_release_message for the origional packet
             which will signal and free it if requested
           
    */
    
    lb_msg = os_alloc_packet(length, DRIVER_ALLOC); 

    if (!lb_msg)
    {
        RTP_DEBUG_LOG("loop_xmit - os_alloc_packet failed", LEVEL_3, NOVAR, 0, 0);
        return(ENOPKTS);
    }

    /* copy msg to lbmsg which was just allocated 
       (set flags to no keep, no signal)
	 */
	COPY_DCU_FLAGS(lb_msg, msg)

#if (DEBUG_LOOP)
	DEBUG_ERROR("loop_xmit: new pkt = ", PKT, DCUTODATA(lb_msg), length);
	DEBUG_ERROR("           addr = ", DINT1, DCUTODATA(lb_msg), 0);
	DEBUG_ERROR("           length = ", EBS_INT1, length, 0);
#endif

	/* set up phoney dest addr to make sure it is not broadcast; 
	    this is done so icmp will not drop the packet
	 */
	SETUP_LL_HDR_DEST(pi, lb_msg, phony_addr)

	// determine if need 802.2 (SNAP,LLC) header
	is_802_2 = RTP_FALSE;
#if (INCLUDE_802_2)
{
    NATIVE_PROFILE_HAL_DRIVERS_ETHERNET();
	is_802_2 = (RTP_BOOL)(SEND_802_2_PI(pi));
}

#endif

	DCUSETUPPTRS(lb_msg, is_802_2)			

	pip = DCUTOIPPKT(lb_msg);
	pi_send = tc_get_local_pi(pip->ip_dest);
	if (!pi_send)
	{
#if (DEBUG_LOOP)
		DEBUG_ERROR("loop_xmit: pi_send is null", NOVAR, 0, 0);
#endif
		pi_send = pi;
	}

    /* send packet to ip exchange 
       NOTE: interface number is put in DCU by ip tasks
     */
    
    OS_SNDX_IP_EXCHG(pi_send, lb_msg);
    
    rtp_thrd_interrupt_continuation(pi->ctrl.index);
    
    RTP_DEBUG_LOG("loop_xmit - sent lb to ip ex", LEVEL_3, NOVAR, 0, 0);

    /* update statistics */
    loop_packets_out    += 1;
    loop_bytes_out      += length;
    loop_packets_in     += 1;
    loop_bytes_in       += length;

#if 0
    /* TBD
	   signal IP layer that send is done this is exactly 
	   ks_invoke_output except ks_invoke_output needs
	   to work from an interrupt service routine
	 */
	 
	/* Disable interrupts   */
	rtp_irq_disable();			
	pi_send->xmit_done_counter++;
	/* enable interrupts    */
    rtp_irq_enable();			
	OS_SET_IP_SIGNAL(pi_send);
    return (0);
#else
    return(REPORT_XMIT_DONE);            // return xmit done
#endif
    
}
void SH7619_EDMAC_recv(PIFACE pi)
{
	DCU               	msg;
	RTP_UINT16         	FrameLength = 0;
	long 				leng;
	UINT16             	BufferLength;
	UINT32  			tmpIdx = rxTd.idx;
	char*				recv_packet;
	int					tries = 100;
	BOOL				recv_error = FALSE;
	BOOL				mem_error = FALSE;
	EmacTDescriptor 	*pRxTd;
	BOOL isFrame = FALSE;
	
	GLOBAL_LOCK(encIrq);

	pRxTd = *(rxTd.td + rxTd.idx);

	while ((pRxTd->status & ACT) != 0 && tries-- > 0)
	{
		for(int i = 0; i < 500; i++);
	}

	if(tries <= 0)
	{
		//while ((pRxTd->status & ACT) != 0 && tries++ < RX_BUFFERS)
		//{
		//	CIRC_INC(rxTd.idx, RX_BUFFERS);
		//	pRxTd = *(rxTd.td + rxTd.idx);
		//}
		//tmpIdx = rxTd.idx;
		return;
	}

	while ((pRxTd->status & ACT) == 0)
	{
		leng = pRxTd->RDL;
		// A start of frame has been received
		if((pRxTd->status & FP1) != 0) 
		{
			// Skip previous fragment
			while (tmpIdx != rxTd.idx)
			{
				pRxTd = *(rxTd.td + rxTd.idx);
				pRxTd->status |= ACT;
				CIRC_INC(rxTd.idx, RX_BUFFERS);
			}

			FrameLength = 0;

			// Start to gather buffers in a frame
			isFrame = TRUE;
		}

		// Increment the pointer
		CIRC_INC(tmpIdx, RX_BUFFERS);

		if(isFrame)
		{
			if (tmpIdx == rxTd.idx) 
			{
				hal_printf("Receive buffer is too small for the current frame!\r\n");
				do
				{
					//FrameLength += pRxTd->RDL;
					pRxTd = *(rxTd.td + rxTd.idx);
					pRxTd->status |= ACT;
					CIRC_INC(rxTd.idx, RX_BUFFERS);
				} while(tmpIdx != rxTd.idx);
			}

			if((pRxTd->status & FE) != 0) 
			{
				recv_error = TRUE;
			}

			FrameLength += leng;

			// An end of frame has been received
			if((pRxTd->status & FP0) != 0)
			{
				tries = 0;

				if(recv_error == FALSE)
				{				
					do
					{
						msg = os_alloc_packet_input(FrameLength, DRIVER_ALLOC);
						if(!msg)
							for(int i = 0; i < 5000; i++);		//delay
					}while(!msg && tries++ < 50);

					if (msg)
					{
						recv_packet = (char*)DCUTODATA(msg);
						msg->length = FrameLength;
					}
					else
					{
						mem_error = TRUE;
					}
				}
				else
				{
					mem_error = TRUE;
				}

				BufferLength = EMAC_RX_UNITSIZE;
				// Get all the data
				while (rxTd.idx != tmpIdx)
				{                   
					pRxTd = *(rxTd.td + rxTd.idx);

					if(mem_error == FALSE)
					{
						if(BufferLength >= FrameLength)
						{
							memcpy(recv_packet, (void*)(pRxTd->TRBA), FrameLength);
						}
						else
						{
							memcpy(recv_packet, (void*)(pRxTd->TRBA), BufferLength);
							FrameLength -= BufferLength;
							recv_packet += BufferLength;
						}
					}

					pRxTd->status |= ACT;
					CIRC_INC(rxTd.idx, RX_BUFFERS);
				}
                
				// signal IP layer that a packet is on its exchange
				if(mem_error == FALSE)
					rtp_net_invoke_input(pi, msg, msg->length);

				// Prepare for the next Frame
				isFrame = FALSE;
				recv_error = FALSE;
				mem_error = FALSE;
			}
		}// if(isFrame) ends
		else
		{
			pRxTd->status |= ACT;
			rxTd.idx = tmpIdx;		   
		}

		// Process the next buffer
		pRxTd = *(rxTd.td + tmpIdx);
	}
}
示例#7
0
RTIP_BOOLEAN davicom_open(PIFACE pi)
{
PDAVICOM_SOFTC softc;
int  i;
unsigned short w;
PFBYTE p;

    if (davicom_softc[pi->minor_number] == NULL)
    {
       p = ks_malloc(sizeof(*softc)+16-1-4, PACKET_POOL_MALLOC, DRV_MALLOC);

       /* make sure on 16 byte boundary first         */
       while (((dword)p) & 15)
           p++;

       davicom_softc[pi->minor_number] = (PDAVICOM_SOFTC) p;
    }
    softc = iface_to_davicom_softc(pi);
    if (!softc)
    {
        set_errno(ENUMDEVICE);
        return (FALSE);
    }
    tc_memset((PFBYTE)softc, 0, sizeof(*softc));

    /* Set up the private data structure so that it points to the global interface      */
    /* structure. (address is needed later when returning packets)                      */
    softc->iface = pi;
    pi->driver_stats.ether_stats = (PETHER_STATS)&(softc->stats);

    /* ************************************************************     */
#if (CFG_DAVICOM_PCI)
    /* read/write suitable values for the PCI configuration registers     */
    if (!davicom_pci_init(pi, softc))
    {
        DEBUG_ERROR("davicom_open: PCI register configuration failed", NOVAR, 0, 0);
        set_errno(EPROBEFAIL);      /* ??check for a PCI init failed error code?? */
        return(FALSE);
    }
#endif /* CFG_DAVICOM_PCI */

    /* ************************************************************      */
    /* reset the Davicom chip                                            */
    WRITE_CR(DC_SCR_CR0, DC_SCR_SW_RESET);

    /* wait at least 32 PCI clock cycles     */
    ks_sleep(2);

    /* ************************************************************      */
    /* read local Ethernet address from EEPROM                           */
    w = davicom_read_srom_word( softc, 10 );    /* was 20 */
    pi->addr.my_hw_addr[0] = (unsigned char) w;
    pi->addr.my_hw_addr[1] = (unsigned char) (w >> 8);
    w = davicom_read_srom_word( softc, 11 );    /* was 22 */
    pi->addr.my_hw_addr[2] = (unsigned char) w;
    pi->addr.my_hw_addr[3] = (unsigned char) (w >> 8);
    w = davicom_read_srom_word( softc, 12 );    /* was 24 */
    pi->addr.my_hw_addr[4] = (unsigned char) w;
    pi->addr.my_hw_addr[5] = (unsigned char) (w >> 8);
#if (DEBUG_DAVICOM)
    DEBUG_ERROR("ETHERNET ADDRESS: ", ETHERADDR, pi->addr.my_hw_addr, 0);
#endif
    /* ************************************************************      */
    /* create the Tx descriptors                                         */
    for (i=0; i < DC_TX_RING_SIZE; i++)
       softc->tx_desc[i].nxt_desc = (dword) (softc->tx_desc + ((i+1) & DC_TX_RING_MASK));

    /* create the Rx descriptors      */
    for (i=0; i < DC_RX_RING_SIZE; i++)
    {
        softc->rx_dcus[i] = os_alloc_packet_input(CFG_MAX_PACKETSIZE+4, DRIVER_ALLOC);
        if (!softc->rx_dcus[i])
        {
            DEBUG_ERROR("davicom_init: out of DCUs", NOVAR, 0, 0);
            return(set_errno(ENOPKTS));
        }

        softc->rx_desc[i].buffer = (dword) DCUTODATA(softc->rx_dcus[i]);
        softc->rx_desc[i].ctrl_flags = (CFG_MAX_PACKETSIZE+4) | (1<<24);

        softc->rx_desc[i].nxt_desc = (dword) (softc->rx_desc + ((i+1) & DC_RX_RING_MASK));
        softc->rx_desc[i].status = OWN_BIT;
    }

    /* write CR3 and CR4 to provide the starting address of each descriptor      */
    /* list                                                                      */
    WRITE_CR(DC_RX_BASE_ADDR_CR3, (dword)(softc->rx_desc));
    WRITE_CR(DC_TX_BASE_ADDR_CR4, (dword)(softc->tx_desc));

    /* ************************************************************      */
    /* Write CR0 to set global host bus operation parameters             */
    WRITE_CR( DC_SCR_CR0, 0 );

    /* ************************************************************      */
    /* hook the interrupt based up PCI values read                       */
    ks_hook_interrupt(softc->dav_irq, (PFVOID) pi, 
                      (RTIPINTFN_POINTER)davicom_interrupt,
                      (RTIPINTFN_POINTER)davicom_pre_interrupt,
                      pi->minor_number);

    /* ************************************************************      */
    /* write CR7 to mask causes of unnecessary interrupt                 */
    WRITE_CR(DC_ISR_MASK_CR7, 
        /* normal     */
        DC_IMR_NISE   |         /* Normal interrupt enable */
        DC_IMR_RXCIE  |         /* Receive complete interrupt */
/*      DC_IMR_TXDUE  |       */  /* Transmit buffer unavailable enabled */
        DC_IMR_TXCIE  |         /* Transmit complete interrupt enable */

        /* abnormal     */
        DC_IMR_AISE   |         /* Abnormal interrupt enable */
        DC_IMR_RXDUE  |         /* Receive buffer unavailable */
        DC_IMR_TXFUE);          /* Transmit fifo underrun enabled */

#define DC_STATUS_MASK (DC_ISR_RX_DONE  | DC_ISR_TX_DONE | DC_ISR_ABNORMAL | DC_ISR_TX_UNDERRUN | DC_ISR_RX_NOBUF)

#if (DEBUG_DAVICOM)
   DEBUG_ERROR("davicom_init: start rcv and xmit", NOVAR, 0, 0);
#endif

    /* ************************************************************
     * write CR6 to set global parameters and start both receive and transmit
     * processes; start receive
     * DC_MODE_TX_SC - start transmitter
     * DC_MODE_RX_RC - start receiver
     * DC_MODE_PAM - receive multicasts
     * DC_MODE_1_PKT
    */
    WRITE_CR(DC_MODE_CR6, (1<<26) |
       DC_MODE_SFT_XMIT | /* wait with transmit until all data is in fifo (disable threshold) */
       DC_MODE_1_PKT |    /* only one packet in transmit fifo */
       (3<<14)       |    /* max threshohld */
       DC_MODE_TX_SC |    /* start transmit */
/*     DC_MODE_PAM |      // receive multicasts   */
       DC_MODE_RX_RC |    /* start receive */
       0);

    /* ************************************************************     */

    softc->timer.func = timeout;   /* routine to execute every second */
    softc->timer.arg = softc;
    ebs_set_timer(&softc->timer, 1, TRUE);
    ebs_start_timer(&softc->timer);

    return(TRUE);
}
示例#8
0
文件: R8139.C 项目: Strongc/DC_source
/* Transmit Routine. The 8139 device requires that the packet data is 32 bit aligned.
   It is assumed here that the DCU's were aligned, no checking will be done here. */
int r8139_xmit(PIFACE pi, DCU msg)    /*__fn__*/
{
    IOADDRESS io_address;
    PR8139_SOFTC sc;
    int   length;
    int this_tx;
#if (INCLUDE_XMIT_QUE)
    int nxt_tx;
#endif
    dword status;

    sc = iface_to_r8139_softc(pi);
    if (!sc)
        return(ENUMDEVICE);

    io_address = sc->ia_iobase;

    if (msg)
    {
        length = DCUTOPACKET(msg)->length;
        if (length < ETHER_MIN_LEN)
            length = ETHER_MIN_LEN;
        if (length > ETHERSIZE)
        {
            DEBUG_ERROR("xmit - length is too large", NOVAR, 0, 0);
            length = ETHERSIZE;         /* what a terriable hack! */
        }

#if (INCLUDE_XMIT_QUE)
        /* if we are starting a new block of transfers save the first one   */
        /* disable transmitter                                              */
        if (sc->first_tx == -1)
        {
#if (DISABLE_TX)
            R8139_OUTBYTE(io_address + CR_COMMAND,CR_RXENA);
#endif
            sc->first_tx = this_tx;
        }
        sc->num_tx++;
#endif

        /* get current discriptor and update descriptor pointer   */
        this_tx = sc->this_tx++;
        this_tx &= TX_RING_MASK;  /* Wrap to zero if must */
        sc->this_tx &= TX_RING_MASK;  /* Wrap to zero if must */

        sc->tx_dcus[this_tx] = msg;

        /* check that we own the descriptor otherwise return error  */
        status = R8139_INDWORD(io_address + TXSD0 + (this_tx<<2));
        if (!(status & TXSTAT_OWN))
        {
            DEBUG_ERROR("TX Descriptor not owned ", DINT2 , this_tx, status);
            return(EOUTPUTFULL);
        }

        /* write the packet address to the descriptor   */
        R8139_OUTDWORD(io_address + TXADD0 +(this_tx<<2),
                       kvtop((PFBYTE)DCUTODATA(msg)));

        /* write the length to the descriptor   */
        R8139_OUTDWORD(io_address + TXSD0 +(this_tx<<2),
                       sc->tx_flag | length);


#if (DEBUG_R8139_XMIT_QUE)
        DEBUG_ERROR("rs189_xmit: msg, this_tx", DINT2, msg, this_tx);
#endif

        /*    */
#if (INCLUDE_XMIT_QUE)
        /* get next descriptor (already calculated above)   */
        nxt_tx = sc->this_tx;
        + 1;

        /* see if we can fit any more packets in the ring buffer   */
        status = R8139_INDWORD(io_address + TXSD0 + (nxt_tx<<2));
        if ( (status & TXSTAT_OWN) && (sc->num_tx <= TX_RING_SIZE) )
        {
#if (DEBUG_R8139_XMIT_QUE)
            DEBUG_ERROR("r8139_xmit: we can queue more: nxt_tx", EBS_INT1,
                        nxt_tx, 0);
#endif
            return(REPORT_XMIT_MORE);
        }
#if (DEBUG_R8139_XMIT_QUE)
        else
        {
            DEBUG_ERROR("r8139_xmit: we can NOT queue more: nxt_tx", EBS_INT1,
                        nxt_tx, 0);
        }
#endif
#endif      /* INCLUDE_XMIT_QUE */
    }       /* if msg */

    /* start xmit   */
#if (DEBUG_R8139_XMIT_QUE)
    DEBUG_ERROR("r8139_xmit: start xmit", NOVAR, 0, 0);
#endif

#if (INCLUDE_XMIT_QUE)
    sc->first_tx = -1;

#    if (DISABLE_TX)
    /* Enable Tx/Rx before setting tx configs   */
    R8139_OUTBYTE(io_address + CR_COMMAND,CR_RXENA|CR_TXENA);
    set_up_xmit(sc);
#    endif
#endif

    return(0);
}