📄 smc8xx.c
字号:
/*-------------------------------------------------------------*/
/* NULL out descriptor data pointer and length. */
/*-------------------------------------------------------------*/
ring->address = (void *)0;
ring->length = 0;
/*-------------------------------------------------------------*/
/* Wrap descriptor pointer if bottom of ring. */
/*-------------------------------------------------------------*/
_sync_io();
if (ring == chan->txrg_bottom)
{
ring->status = SMC_TX_WRAP;
ring = chan->txrg_top;
}
else
{
ring->status = 0;
ring++;
}
/*-------------------------------------------------------------*/
/* Handle end of frame transmission. (transmit interrupt) */
/*-------------------------------------------------------------*/
if (status & SMC_TX_INTR)
{
/*---------------------------------------------------------*/
/* Update transmit tail pointer: must be done prior to */
/* call-out *datcnf as this may queue some more data. */
/*---------------------------------------------------------*/
chan->txrg_rd = ring;
/*---------------------------------------------------------*/
/* Update the status of the transmitted frame in the status */
/* field of the buffer descriptor. */
/*---------------------------------------------------------*/
imask = splx(MAX_ILEV);
_sync_io();
mblk = BufListTxRemove(&chan->tx_queue);
(void)splx(imask);
chan->tx_count--;
/*---------------------------------------------------------*/
/* Return the mblock to the data link layer using the */
/* UDataCnf call-out. */
/*---------------------------------------------------------*/
DO_DATACNF(mblk, frameFlag);
/*txstatus = 0; -del by szg *//* Clear txstatus for next frame */
frameFlag = 0; /* Clear status for next frame */
}
}
else
break; /* Not finished sending yet */
}
/*---------------------------------------------------------------------*/
/* Update transmit tail pointer */
/*---------------------------------------------------------------------*/
chan->txrg_rd = ring;
}
/***********************************************************************/
/* error_poll: */
/* Polls SMC register for error events */
/* */
/* INPUTS: */
/* chan pointer to the structure that contains channel */
/* information */
/* */
/***********************************************************************/
static void
error_poll(chan_control *chan)
{
smc_regs *smc_regs; /* ptr to SMC registers */
USHORT status; /* content of an individual register */
ULONG imask;
/*---------------------------------------------------------------------*/
/* Initialize pointer SMC registers */
/*---------------------------------------------------------------------*/
smc_regs = chan->smc_regs;
/*---------------------------------------------------------------------*/
/* Poll Event register for error conditions - increment error counters */
/* and clear non fatal errors. */
/*---------------------------------------------------------------------*/
status = smc_regs->smce;
/*---------------------------------------------------------------------*/
/* Clear all set bits of interest. Bit is cleared by writing a 1 to it */
/*---------------------------------------------------------------------*/
smc_regs->smce = status & ~(SMC_EV_RXBUF | SMC_EV_TXBUF );
if (status & SMC_EV_BRKRCV )
{
/*-------------------------------------------------------------*/
/* A break condition has ended. (received a break) use the */
/* UExcInd call-out to notify the upper layer. */
/* When the break comes from the pROBE console defer until */
/* pROBE wakes up and polls us directly via ioctl(BREAKCHECK). */
/*-------------------------------------------------------------*/
#if BSP_NUM_SER_DRVRS > 1
if ( ( chan->port == SDrvCnfg[ ProbeCon ].pnum ) &&
( SerialFuncs[ SDrvCnfg[ ProbeCon ].dnum ].Init == smc8xx_Init )
)
#else
if ( chan->port == (ProbeCon - 1) )
#endif
serial_break_detected = 1;
else
DO_EXPIND(SIOCBREAKR);
smc_regs->smce = SMC_EV_BRKRCV;
}
if (status & SMC_EV_BUSY)
{
/*-------------------------------------------------------------*/
/* Some characters were discarded because of lack of buffers */
/* Replenish the receive ring and account for those errors. */
/*-------------------------------------------------------------*/
imask = splx(MAX_ILEV);
_sync_io();
replenish_desc(chan);
(void)splx(imask);
chan->stats.buffer_shortage++;
/*--------------------------------------------------------*/
/* Tell upper layer by using the UExcInd call-out. */
/*--------------------------------------------------------*/
DO_EXPIND(SIOCOVERRUN);
smc_regs->smce = SMC_EV_BUSY;
_sync_io();
}
return;
}
/***********************************************************************/
/* allocate_brg: */
/* This routine is used to allocate a baud rate generator.*/
/* If the port currently has a generator assigned it will */
/* free the old one. If the baud rate is not changing, */
/* it will simply return the old generator. */
/* */
/* INPUTS: */
/* port port number */
/* direction receive/transmit */
/* rate baud rate */
/* multiplier rate multiplier */
/* */
/* RETURNS: */
/* baud rate generator used */
/* */
/***********************************************************************/
static int
allocate_brg(UINT chan, UINT rate,UINT multiplier)
{
UINT clkdiv; /* clock divider for the BRG */
ULONG simode;
/*---------------------------------------------------------------------*/
/* Use the most accurate divider, providing it fits */
/* in the 12 bits of the register (DIV < 4096) */
/* Here is some information about the baud rate calculation math: */
/* clkdiv is a composite (prescaled) number of 1xBaud or 16xBaud, */
/* depending on TDCR or RDCR bits being set. */
/* Our check is against the system master clock. */
/* Some ranges are illegal since we must use 1xBaud clocking for NRZ */
/* or NRZI. */
/*---------------------------------------------------------------------*/
clkdiv = (BspCpuClkRate() * 1000000) / (rate * multiplier) - 1;
if(clkdiv >= 4096)
{
clkdiv =(((BspCpuClkRate() * 1000000)/(16 * rate * multiplier) -1) << 1) | 1;
}
else
clkdiv <<= 1;
/*---------------------------------------------------------------------*/
/* reset the selected BRG */
/*---------------------------------------------------------------------*/
R_BRG(chan,AllocBrg[chan]) = RESET_BRG;
/*---------------------------------------------------------------------*/
/* initialize the selected BRG */
/*---------------------------------------------------------------------*/
R_BRG(chan,AllocBrg[chan]) = USE_BRGCLK | EN_BRG_COUNT | clkdiv;
_sync_io();
/*---------------------------------------------------------------------*/
/* attach this BRG to the SMC clock (only 3 bits are first reset) */
/*---------------------------------------------------------------------*/
simode = R_SIMODE(chan);
simode &= ~( 7 << ( 12 + ( SmcNum[chan] * 16 ) ) );
simode |= ( AllocBrg[chan] << ( 12 + (SmcNum[chan] * 16) ) );
R_SIMODE(chan) = simode;
_sync_io();
return( AllocBrg[chan] );
}
/***********************************************************************/
/* issue_command: */
/* This routine will issue a command to the RISC's */
/* Command Register. See the RISC section of the 68360 */
/* manual for timing information on the command */
/* register. By busy-waiting for the chip BEFORE the */
/* command is issued, there is no risk of overlapping */
/* commands. */
/* */
/* INPUTS: */
/* port port number */
/* cmd command */
/* */
/***********************************************************************/
static void issue_command (UINT port, USHORT cmd)
{
/*---------------------------------------------------------------------*/
/* Issue a command. Three things are needed: The command or opcode */
/* (bits 8 - 11) the SEMAPHORE_FLAG bit 0 tells RISC there is a */
/* command to be processed and the Channel Number (CH NUM) bits 4 - */
/* 7. */
/*---------------------------------------------------------------------*/
/* R_CR(port) = cmd | SEMAPHORE_FLAG | CR_SMC( SmcNum[port] );*/
CPM_CMD(cmd|CR_SMC(SmcNum[port]));
_sync_io();
}
/***********************************************************************/
/* disable_interrupts */
/* Disable interrupts from port */
/* */
/* INPUTS: */
/* port logical port number */
/* */
/***********************************************************************/
static void disable_interrupts(UINT port, UINT dcdint)
{
switch( SmcNum[port] )
{
/*-----------------------------------------------------------------*/
/* To disable interrupts for any given SMC the SMC# bit and the */
/* Port C bit that controls CTS needs to be cleared. */
/*-----------------------------------------------------------------*/
case 0:
SPLX(R_CIMR(port) &= ~EN_SMC1;)
break;
case 1:
SPLX(R_CIMR(port) &= ~EN_SMC2;)
break;
#if (BD_HAS_SLAVE == 1)
case 2:
SPLX(R_CIMR(port) &= ~EN_SMC1;)
break;
case 3:
SPLX(R_CIMR(port) &= ~EN_SMC2;)
break;
#endif
}
}
/******************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -