📄 if_snnew.c
字号:
#endif
ifp->if_softc = sc;
ifp->if_unit = is->id_unit;
ifp->if_name = "sn";
ifp->if_mtu = ETHERMTU;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
ifp->if_init = sninit;
ifp->if_output = ether_output;
ifp->if_start = snstart;
ifp->if_ioctl = snioctl;
ifp->if_watchdog = snwatchdog;
ifp->if_type = IFT_ETHER;
ifp->if_addrlen = ETHER_ADDR_LEN;
ifp->if_hdrlen = ETHER_HDR_LEN;
ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
ifp->if_timer = 0;
if_attach(ifp);
/*
* Fill the hardware address into ifa_addr if we find an AF_LINK entry.
* We need to do this so bpf's can get the hardware addr of this card.
* netstat likes this too!
*/
ifa = ifp->if_addrlist;
while ((ifa != 0) && (ifa->ifa_addr != 0) &&
(ifa->ifa_addr->sa_family != AF_LINK))
ifa = ifa->ifa_next;
if ((ifa != 0) && (ifa->ifa_addr != 0)) {
sdl = (struct sockaddr_dl *) ifa->ifa_addr;
sdl->sdl_type = IFT_ETHER;
sdl->sdl_alen = ETHER_ADDR_LEN;
sdl->sdl_slen = 0;
bcopy((char *)sc->arpcom.ac_enaddr, (char *)LLADDR(sdl), ETHER_ADDR_LEN);
}
snstop();
return 1;
}
/*
* Reset and initialize the chip
*/
void
sninit(void *dummy)
{
register struct sn_softc *sc = &sn_softc0;
register struct ifnet *ifp = &sc->arpcom.ac_if;
int s;
volatile unsigned int j;
unsigned short i, ret;
#if defined(ORG)
unsigned short flags, mask;
#else
unsigned short flags;
unsigned char mask;
#endif
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
volatile unsigned short tmp_reg;
#endif
s = splimp();
/* This resets the registers mostly to defaults, but doesn't
* affect EEPROM. After the reset cycle, we pause briefly
* for the chip to be happy.
*/
SMC_SELECT_BANK( 0 );
outw( BASE + RECV_CONTROL_REG_W, RCR_SOFTRESET );
for (j=0;j<WAIT_UNIT;j++); /* BUSY wait */
/* Terminate soft reset and disable transmit functionality */
outw( BASE + RECV_CONTROL_REG_W, 0x0000 );
SMC_DELAY( );
SMC_DELAY( );
#if defined(_MIC_M32192_) || defined(_MIC_M32104_)
/* Set NO_WAIT bit */
SMC_SELECT_BANK( 1 );
i = inw( BASE + CONFIG_REG_W );
outw( BASE + CONFIG_REG_W, i|CR_NOW_WAIT_ST );
#endif
/* Disable receive functionality */
SMC_SELECT_BANK( 0 );
outw( BASE + TXMIT_CONTROL_REG_W, 0x0000 );
/* Set the control register to automatically release
* succesfully transmitted packets (making the best
* use out of our limited memory) and to enable the EPH
* interrupt on certain TX errors.
*/
SMC_SELECT_BANK( 1 );
i = inw( BASE + CONTROL_REG_W );
outw( BASE + CONTROL_REG_W, ( i|CTR_AUTO_RELEASE ));
/* Reset the MMU and wait for it to be un-busy.
*/
SMC_SELECT_BANK( 2 );
outw( BASE + MMU_CMD_REG_W, MMUCR_RESET );
while ( inw( BASE + MMU_CMD_REG_W ) & MMUCR_BUSY ) /*NOTHING*/ ;
/* Disable all interrupts
*/
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
/* cannot access with byte length */
outw( BASE + INTR_MASK_REG_W, 0x0000 );
#else
outb( BASE + INTR_MASK_REG_B, 0x00 );
#endif
/* Set the receiver filter. We want receive enabled and auto
* strip of CRC from received packet. If we are promiscuous
* then set that bit too. We just get all multicast packets
* even if we only want them from particular groups. This may
* be changed at some future point.
*/
SMC_SELECT_BANK( 0 );
flags = RCR_ENABLE | RCR_STRIP_CRC | RCR_ALMUL;
if (ifp->if_flags & IFF_PROMISC)
flags |= RCR_PROMISC;
outw( BASE + RECV_CONTROL_REG_W, flags );
/* Set the transmitter control. We want it enabled.
*/
flags = TCR_ENABLE;
#if !defined(SW_PAD)
/* I (GB) have been unlucky getting this to work.
*/
flags |= TCR_PAD_ENABLE;
#endif
#if !defined(OLD)
/* set Switched Full Duplex mode */
flags |= TCR_SWFDUP;
#endif
outw( BASE + TXMIT_CONTROL_REG_W, flags );
/* Now, enable interrupts
*/
SMC_SELECT_BANK( 2 );
mask = IM_EPH_INT |
IM_RX_OVRN_INT |
IM_RCV_INT |
#if defined(LAN91C111)
IM_MDINT |
#endif
IM_TX_INT;
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
/* cannot access with byte length */
tmp_reg = (u_short)(mask << 8);
outw( BASE + INTR_MASK_REG_W, tmp_reg );
#else
outb( BASE + INTR_MASK_REG_B, mask );
#endif
sc->intr_mask = mask;
sc->pages_wanted = -1;
/* Mark the interface running but not active.
*/
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
/* Initialize PHY chip */
ret = phy_init();
/* Attempt to push out any waiting packets.
*/
snstart(ifp);
splx(s);
}
void
snstart(struct ifnet *ifp)
{
register struct sn_softc *sc = &sn_softc0;
register u_int len;
register struct mbuf *m;
struct mbuf *top;
int s, pad;
#if defined(ORG)
int mask;
#else
u_char mask;
#endif
u_short length;
u_short numPages;
u_char packet_no;
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
volatile unsigned short tmp_reg, ptr_reg;
#endif
int time_out;
s = splimp();
if (sc->arpcom.ac_if.if_flags & IFF_OACTIVE) {
splx(s);
return;
}
if (sc->pages_wanted != -1) {
splx(s);
#ifdef PRINTON
printf("sn%d: snstart() while memory allocation pending\n",
ifp->if_unit);
#endif
return;
}
startagain:
/* Sneak a peek at the next packet
*/
m = sc->arpcom.ac_if.if_snd.ifq_head;
if (m == 0) {
splx(s);
return;
}
/* Compute the frame length and set pad to give an overall
* even number of bytes. Below we assume that the packet
* length is even.
*/
for (len = 0, top = m; m; m = m->m_next)
len += m->m_len;
pad = (len & 1);
/*
* We drop packets that are too large. Perhaps we should truncate
* them instead?
*/
if (len + pad > ETHER_MAX_LEN) {
#ifdef PRINTON
printf("sn%d: large packet discarded (A)\n", ifp->if_unit);
#endif
++sc->arpcom.ac_if.if_oerrors;
IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
m_freem(m); /* splimp and splx call */
goto readcheck;
}
#ifdef SW_PAD
/* If HW padding is not turned on, then pad to
* ETHER_MIN_LEN.
*/
if (len < ETHER_MIN_LEN)
pad = ETHER_MIN_LEN - len;
#endif
length = pad + len;
#if defined(LAN91C111)
/* the size of "page" is 2048 byte */
numPages = (length + 6) >> 11;
#else
/*
* The MMU wants the number of pages to be the number of 256 byte
* 'pages', minus 1 (A packet can't ever have 0 pages.
* We also include space for the status word, byte count and
* control bytes in the allocation request.
*/
numPages = (length + 6) >> 8;
#endif
/* Now, try to allocate the memory
*/
SMC_SELECT_BANK( 2 );
outw( BASE + MMU_CMD_REG_W, MMUCR_ALLOC | numPages );
/* Wait a short amount of time to see if the allocation request
* completes. Otherwise, I enable the interrupt and wait for
* completion asyncronously.
*/
time_out = MEMORY_WAIT_TIME;
do {
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
/* cannot access with byte length */
tmp_reg = inw( BASE + INTR_STAT_REG_W );
if ( (u_char)(tmp_reg & 0x00FF) & IM_ALLOC_INT ) {
break;
}
#else
if ( inb( BASE + INTR_STAT_REG_B ) & IM_ALLOC_INT ) {
break;
}
#endif
} while ( --time_out );
if ( !time_out ) {
/* No memory now. Oh well, wait until the chip finds
* memory later. Remember how many pages we were asking
* for and enable the allocation completion interrupt.
* Also set a watchdog in case we miss the interrupt.
* We mark the interface active since there is no point
* in attempting an snstart() until after the memory is
* available.
*/
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
/* cannot access with byte length */
tmp_reg = inw( BASE + INTR_MASK_REG_W );
mask = (u_char)(tmp_reg >> 8) | IM_ALLOC_INT;
tmp_reg = (u_short)(mask << 8);
outw( BASE + INTR_MASK_REG_W, tmp_reg );
#else
mask = inb( BASE + INTR_MASK_REG_B ) | IM_ALLOC_INT;
outb( BASE + INTR_MASK_REG_B, mask );
#endif
sc->intr_mask = mask;
sc->arpcom.ac_if.if_timer = 1;
sc->arpcom.ac_if.if_flags |= IFF_OACTIVE;
sc->pages_wanted = numPages;
splx(s);
return;
}
/* The memory allocation completed. Check the results.
*/
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
/* cannot access with byte length */
tmp_reg = inw( BASE + ALLOC_RESULT_REG_W );
packet_no = (u_char)(tmp_reg << 8);
#else
packet_no = inb( BASE + ALLOC_RESULT_REG_B );
#endif
if ( packet_no & ARR_FAILED ) {
#ifdef PRINTON
printf("sn%d: Memory allocation failed\n", ifp->if_unit);
#endif
goto startagain;
}
/* We have a packet number, so tell the card to use it.
*/
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
/* cannot access with byte length */
tmp_reg = (u_short)packet_no & 0x00FF;
outw( BASE + PACKET_NUM_REG_W, tmp_reg );
#else
outb( BASE + PACKET_NUM_REG_B, packet_no );
#endif
/* Point to the beginning of the packet
*/
outw( BASE + POINTER_REG_W, PTR_AUTOINC | 0x0000 );
/* Send the packet length (+6 for status, length and control byte)
* and the status word (set to zeros)
*/
outw( BASE + DATA_REG_W, 0 );
#ifdef CHECK_PRO
outw( BASE + DATA_REG_W, 0x0042 );
#else
#if defined(OLD)
outb( BASE + DATA_REG_B, (length + 6) & 0xFF );
outb( BASE + DATA_REG_B, (length + 6) >> 8 );
#else
outw( BASE + DATA_REG_W, (length + 6) );
#endif
#endif /* CHECK_PRO */
/***********************************
Set Data:
b15 b0
+------------------------------+
0 |Status Word (=0) |
+------------------------------+
2 |(length+6)/256 |(length+6)%256|
+------------------------------+
4 |Data Area |
+------------------------------+
| |
+------------------------------+
2046 |Control Byte | Last Data Byte if odd.
max +------------------------------+
**********************************/
/* Get the packet from the kernel. This will include the
* Ethernet frame header, MAC Addresses etc.
*/
IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
#ifdef CHECK_PRO
outw( BASE + DATA_REG_W, 0xFFFF ); /* dst MAC addr */
outw( BASE + DATA_REG_W, 0xFFFF );
outw( BASE + DATA_REG_W, 0xFFFF );
outw( BASE + DATA_REG_W, 0x0000 ); /* src MAC addr */
outw( BASE + DATA_REG_W, 0x6BE1 );
outw( BASE + DATA_REG_W, 0xDE39 );
outw( BASE + DATA_REG_W, 0x0608 ); /* frame type */
outw( BASE + DATA_REG_W, 0x0100 ); /* H/W type */
outw( BASE + DATA_REG_W, 0x0008 ); /* proto type */
outw( BASE + DATA_REG_W, 0x0406 ); /* addr size */
outw( BASE + DATA_REG_W, 0x0100 ); /* operation */
outw( BASE + DATA_REG_W, 0x0000 ); /* src MAC addr */
outw( BASE + DATA_REG_W, 0x6BE1 );
outw( BASE + DATA_REG_W, 0xDE39 );
outw( BASE + DATA_REG_W, 0x4A0A ); /* src IP addr */
outw( BASE + DATA_REG_W, 0x6401 ); /* 10.74.1.100 */
outw( BASE + DATA_REG_W, 0x0000 ); /* dst MAC addr */
outw( BASE + DATA_REG_W, 0x0000 );
outw( BASE + DATA_REG_W, 0x0000 );
outw( BASE + DATA_REG_W, 0x4A0A ); /* dst IP addr */
outw( BASE + DATA_REG_W, 0x2501 ); /* 10.74.1.37 */
outw( BASE + DATA_REG_W, 0x6820 ); /* others */
outw( BASE + DATA_REG_W, 0x6E61 );
outw( BASE + DATA_REG_W, 0x6C64 );
outw( BASE + DATA_REG_W, 0x6465 );
outw( BASE + DATA_REG_W, 0x6300 );
outw( BASE + DATA_REG_W, 0x656B );
outw( BASE + DATA_REG_W, 0x2074 );
outw( BASE + DATA_REG_W, 0x666F );
outw( BASE + DATA_REG_W, 0x6C20 );
outw( BASE + DATA_REG_W, 0x0000 );
#else /* CHECK_PRO */
/* Push out the data to the card.
*/
for (top = m; m != 0; m = m->m_next) {
if ( (int)mtod(m, caddr_t) & 1) {
/* Odd begin address
*/
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
ptr_reg = inw (BASE + POINTER_REG_W);
/* cannot access with byte length */
tmp_reg = (unsigned short)*(mtod(m, caddr_t)) & 0x00FF;
outw(BASE + DATA_REG_W, tmp_reg);
/* roll back the pointer */
outw(BASE + POINTER_REG_W, ptr_reg + 1);
#else
outb(BASE + DATA_REG_B, *(mtod(m, caddr_t)));
#endif
#ifdef DEBUG
tm_putstring("snstart1.\n");
#endif
/* Push out words.
*/
outsw(BASE + DATA_REG_W,
(unsigned short *)(mtod(m, caddr_t)+1), (m->m_len-1)/ 2);
/* Push out remaining byte.
*/
if ((m->m_len-1) & 1) {
#if defined(_STD_SH7727_) || defined(_MIC_SH7145_)
ptr_reg = inw (BASE + POINTER_REG_W);
/* cannot access with byte length */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -