📄 lan91c111.c
字号:
// Clock Low - output data
_outpw(MII_REG, mii_reg | bits[i]);
// Clock Hi - input data
_outpw(MII_REG, mii_reg | bits[i] | MII_MCLK);
bits[i] |= _inpw(MII_REG) & MII_MDI;
}
// Return to idle state
// Set clock to low, data to low, and output tristated
_outpw(MII_REG, mii_reg);
// Restore original bank select
_outpw(BSR_REG, oldBank);
// Recover input data
phydata = 0;
for (i = 0; i < 16; ++i)
{
phydata <<= 1;
if (bits[input_idx++] & MII_MDI)
phydata |= 0x0001;
}
return (phydata);
}
/******************************************************************************
* IRQ Sub Function: SMC_RCV for the LAN91C111
*
* Purpose:
* There is a packet waiting to be read from 91C111
*
* Actions:
* - Read the status
* - If an error, record it
* - otherwise, read in the packet
*
*****************************************************************************/
static void LAN91C111_rcv(ADI_ETHER_LAN91C111_DATA *dev )
{
int i, chip_id;
unsigned short status;
unsigned short packet_length;
unsigned short *data;
unsigned short *elnth;
unsigned char * ptr;
int ioaddr = dev->base_addr;
status = inw(ioaddr + RX_FRAME_PORT);
if ((status & RX_OK) == 0) {
ADI_G(("why no packet?\n"));
return;
}
packet_length = inw(ioaddr + RX_FRAME_PORT);
/*----------------------*/
/*
status = readword(dev,PP_RxStatus<<1);
if ((status & RX_OK) == 0) {
ADI_G(("why no packet?\n"));
return;
}
packet_length = readword(dev,PP_RxLength<<1);
*/
/*----------------------*/
// store for debug
dev->LAN_state.rpsize = packet_length;
ADI_ETHER_BUFFER *tmp_q_ele;
tmp_q_ele = dev->m_RxEnqueuedHead;
if (tmp_q_ele != NULL) {
elnth = (unsigned short *)tmp_q_ele->Data;
*elnth = (packet_length + 4); // add on 4 bytes for the CRC (even if we dont store it)
tmp_q_ele->ProcessedElementCount = (*elnth+2+tmp_q_ele->ElementWidth-1)/tmp_q_ele->ElementWidth;
}
if ((tmp_q_ele)&&(tmp_q_ele->ProcessedElementCount <= tmp_q_ele->ElementCount))
{
//store packet length
// assign pointer
data = (void *)( ((char *)tmp_q_ele->Data) +2);
}
else
{
ADI_G(("drop it\n"));
return;
}
readblock(dev, (char *)data, packet_length);
ptr = (unsigned char * )data;
ADI_G(("CS8900: received %d byte packet of type %x\n",
packet_length, (ptr[ETH_ALEN+ETH_ALEN] << 8) | ptr[ETH_ALEN+ETH_ALEN+1]));
/* Change the Enqueued head */
dev->m_RxEnqueuedHead = (ADI_ETHER_BUFFER*)tmp_q_ele->pNext;
dev->m_RxEnqueuedCount--;
if (dev->m_RxEnqueuedCount == 0)
dev->m_RxEnqueuedTail = NULL;
/* Add the packet to dequeued list*/
if (dev->m_RxDequeuedCount)
dev->m_RxDequeuedTail->pNext = (ADI_ETHER_BUFFER *)tmp_q_ele;
else
dev->m_RxDequeuedHead = tmp_q_ele;
//No matter what this is also the tail.
dev->m_RxDequeuedTail = tmp_q_ele;
//And tail->next should point to NULL
tmp_q_ele->pNext = NULL;
dev->m_RxDequeuedCount++;
// finally we have to update the status word etc
tmp_q_ele->ProcessedFlag = 1;
tmp_q_ele->StatusWord = 0x3000 + (packet_length+4);
return;
}
/******************************************************************************
* TX IRQ Error Handler Function for SMSC91C111
*
* Purpose: Handle the transmit error message.
* This is only called when an TX error occured because of
* the AUTO_RELEASE mode.
*
* Actions:
* - Save pointer and packet no
* - Get the packet no from the top of the queue
* - check if it's valid ( if not, is this an error??? )
* - read the status word
* - record the error
* - ( resend? Not really, since we don't want old packets around )
* - Restore saved values
*
*****************************************************************************/
static void LAN91C111_tx(ADI_ETHER_LAN91C111_DATA * dev)
{
volatile unsigned char saved_packet;
volatile unsigned char packet_no;
volatile unsigned short tx_status;
// one less packet waiting for me
dev->LAN_state.packets_waiting--;
return;
}
/******************************************************************************
* IRQ Sub Function: smc_phy_interrupt for the LAN91C111
*
* Purpose:
* Handle interrupts relating to PHY register 18.
*
* Actions:
* Log last Phy18 Interrupt Source
*
*****************************************************************************/
static void LAN91C111_phy_interrupt(ADI_ETHER_LAN91C111_DATA * cptr)
{
volatile unsigned short phy18;
while (1)
{
// Read PHY Register 18, Status Output
phy18 = LAN91C111_read_phy_register(PHY_INT_REG);
// Exit if no more changes
if (phy18 == cptr->LAN_state.lastPhy18)
break;
// Update the last phy 18 variable
cptr->LAN_state.lastPhy18 = phy18;
} // end while
}
/******************************************************************************
* LANC91C111: LAN91C111_hardware_send_packet
*
* Purpose:
* This sends the actual packet to the SMC9xxx chip.
*
* - First, see if a pending packet is available.
* this should NOT be called if there is none
* - Find the packet number that the chip allocated
* - Point the data pointers at it in memory
* - Set the length word in the chip's memory
* - Dump the packet to chip memory
* - Check if a last byte is needed ( odd length packet )
* if so, set the control flag right
* - Tell the LAn 91C111 to send it
* - Enable the transmit interrupt, so I know if it failed
* - Free the packet data if I actually sent it.
*
*****************************************************************************/
#pragma section("Merge")
static unsigned char LAN91C111_hardware_send_packet(ADI_ETHER_LAN91C111_DATA * cptr)
{
int i;
unsigned char packet_no;
unsigned short length;
unsigned short *buf;
unsigned short *elnth;
unsigned short lnth_first;
ADI_ETHER_BUFFER *bf = cptr->m_TxEnqueuedHead;
buf = (unsigned short *)(((char *)bf->Data)+2);
// the length is held in the first two bytes of the 'frame', the ElementCount says the number of elements in the first buffer
// get length
elnth = (unsigned short *)bf->Data;
length = *elnth;
writeblock(dev_g, (char *)buf, length);
bf->ProcessedFlag = 1;
bf->ProcessedElementCount = (*elnth+2 + bf->ElementWidth-1)/bf->ElementWidth;
bf->StatusWord = 0x3; // completed and OK
cptr->LAN_state.alloc_success = CS89X0_ALLOC_IDLE;
return LAN91C111_TX_SUCCESS;
}
/******************************************************************************
* LANC91C111: LAN91C111_wait_to_send_packet()
*
* Purpose:
* Attempt to allocate memory for a packet, if chip-memory is not
* available, then tell the card to generate an interrupt when it
* is available.
*****************************************************************************/
#pragma section("Merge")
static unsigned char LAN91C111_wait_to_send_packet(ADI_ETHER_LAN91C111_DATA * cptr)
{
unsigned short length;
unsigned short numPages;
unsigned short time_out;
unsigned short status;
unsigned short *elnth;
elnth = (unsigned short *)cptr->m_TxEnqueuedHead->Data;
length = *elnth;
#if 0
// writereg(dev_g, PP_BusCTL, 0x0);
// writereg(dev_g, PP_BusCTL, readreg(dev_g, PP_BusCTL) | ENABLE_IRQ);
ADI_G(("CS8900: sent out data\n"));
// either way, a packet is waiting now
cptr->LAN_state.packets_waiting++;
//rev > 'F'
writeword(dev_g, TX_CMD_PORT, TX_AFTER_ALL);//TX_AFTER_ALL);//for the revison>F
writeword(dev_g, TX_LEN_PORT, length);
time_out =1; // 7.25
while(time_out)
{
if ((readreg(dev_g, PP_BusST) & READY_FOR_TX_NOW) == 0) {
ADI_G(("TX buf not free\n"));
//return 1;
time_out--;
}
else break;
}
if(!time_out) {
return 1;
}
cptr->LAN_state.alloc_success = 1;
return (LAN91C111_hardware_send_packet(cptr));
#endif
/*********************/
/***********************/
#if 1
//writereg(dev_g, PP_BusCTL, 0x0);
//writereg(dev_g, PP_BusCTL, readreg(dev_g, PP_BusCTL) | ENABLE_IRQ);
ADI_G(("CS8900: sent out data\n"));
// either way, a packet is waiting now
cptr->LAN_state.packets_waiting++;
RETRY_P:
//rev > 'F'
writeword(dev_g, TX_CMD_PORT, TX_NOW);//TX_AFTER_ALL);//TX_AFTER_381//for the revison>F
writeword(dev_g, TX_LEN_PORT, length);
time_out =5000; // 7.25
while(time_out)
{
if ((readreg(dev_g, PP_BusST) & READY_FOR_TX_NOW) == 0) {
ADI_G(("TX buf not free\n"));
//return 1;
time_out--;
}
else break;
}
if(!time_out) {
#if 1
writereg(dev_g, PP_BusCTL, 0x0);
writereg(dev_g, PP_BusCTL, readreg(dev_g, PP_BusCTL) | ENABLE_IRQ); //RETRY
//printf("RETRY\n");
goto RETRY_P;
#endif
// return 1;
}
//printf("%d\n",time_out);
cptr->LAN_state.alloc_success = 1;
return (LAN91C111_hardware_send_packet(cptr));
#endif
/*********************/
#if 0
/////////////////////*error die *************************/
//writereg(dev_g, PP_BusCTL, 0x0);
//writereg(dev_g, PP_BusCTL, readreg(dev_g, PP_BusCTL) | ENABLE_IRQ);
ADI_G(("CS8900: sent out data\n"));
// either way, a packet is waiting now
cptr->LAN_state.packets_waiting++;
//rev > 'F'
if(cptr->LAN_state.alloc_success ==CS89X0_ALLOC_SUCE)
{
printf("directly send\n");
}
if( cptr->LAN_state.alloc_success == CS89X0_ALLOC_IDLE)
{
writeword(dev_g, TX_CMD_PORT, dev_g->send_cmd);//TX_AFTER_ALL);//for the revison>F
writeword(dev_g, TX_LEN_PORT, length);
time_out =1; // 7.25
while(time_out)
{
if ((readreg(dev_g, PP_BusST) & READY_FOR_TX_NOW) == 0) {
ADI_G(("TX buf not free\n"));
//return 1;
time_out--;
}
else break;
}
if(!time_out) {
ADI_G ((" RETRY \n")) ;
cptr->LAN_state.alloc_success = CS89X0_ALLOC_WAIT;
} //RETRY
else cptr->LAN_state.alloc_success = CS89X0_ALLOC_SUCE;
}
if(cptr->LAN_state.alloc_success == CS89X0_ALLOC_WAIT)
{
//ADI_G("RETRY %d\n",length);
return 1;
//smsc_sleep(10);
}
return (LAN91C111_hardware_send_packet(cptr));
#endif/************************/
}
/******************************************************************************
* LAN Interrupt Handler
*****************************************************************************/
int LAN91C111_InterruptHandler(ADI_ETHER_LAN91C111_DATA *dev)
{
/*
* This is the main routine of the driver, to handle the
* net_device when it needs some attention.
* So:
* first, save state of the chipset
* branch off into routines to handle each case,
* and acknowledge each to the interrupt register
* and finally restore state.
*/
volatile unsigned short stat,st;
volatile unsigned short card_status;
volatile unsigned char mask;
volatile unsigned short saved_bank;
volatile unsigned short saved_pointer;
ADI_DCB_RESULT result;
ADI_G(("interrupt +++.\n"));
// read IRQ status register
mask = ISQ_EVENT_MASK;
st = readword(dev, ISQ_PORT);
// read the status flag and mask it
stat= st & mask;
//stat= readword(dev, PP_ISQ)& mask;
//int tst=0;
while (st)
{
//printf("%d\n",tst++);
if (stat == ISQ_RECEIVER_EVENT)
{
ADI_G(("states ISQ_RECEIVER_EVENT\n"));
// store debug
dev->LAN_state.last_IRQ_serviced = IM_RCV_INT;
// Got a packet(s), receive them
LAN91C111_rcv(dev);
if (dev->m_RxDequeuedHead != NULL) {
if (dev->DCBHandle!=NULL) {
result = adi_dcb_Post(dev->DCBHandle,ik_ivg12,dev->DMCallback,dev->DeviceHandle,ADI_ETHER_EVENT_FRAME_RCVD,dev->m_RxDequeuedHead->CallbackParameter);
} else {
/*************************************/
if(dev->m_RxDequeuedHead)
(dev->DMCallback)(dev->DeviceHandle,ADI_ETHER_EVENT_FRAME_RCVD,dev->m_RxDequeuedHead->CallbackParameter);
/************************************/
result = ADI_DCB_RESULT_SUCCESS;
}
if (result == ADI_DCB_RESULT_SUCCESS) {
//## what happens if a packet is received while in the callback
dev->m_RxDequeuedHead = NULL;
dev->m_RxDequeuedTail = NULL;
dev->m_RxDequeuedCount = 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -