📄 bluecat_cs8900a.c
字号:
return 0;
}
static int
net_send_packet(struct sk_buff *skb, struct device *dev)
{
interror=0;
//printk("net_send_packet..%d\n", skb->len);
DEBUGNET("cyn: net_send_packet ");
if (dev->tbusy) {
/* If we get here, some higher level has decided we are broken.
There should really be a "kick me" function call instead. */
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < 5)
return 1;
if (net_debug > 0)
printk("%s: transmit timed out, network cable problem?\n",
dev->name);
/* Try to restart the adaptor. */
dev->tbusy=0;
dev->trans_start = jiffies;
error++;
}
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else {
struct net_local *lp = (struct net_local *)dev->priv;
unsigned long flags;
if (net_debug > 3)
printk("%s: sent %d byte packet of type %x\n", dev->name, skb->len,
(skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
#ifdef SET_NET_DEBUG
if ( (skb->data[ETH_ALEN+ETH_ALEN+22] == 8 &&
skb->data[ETH_ALEN+ETH_ALEN+23] == 1) ||
(skb->data[ETH_ALEN+ETH_ALEN+24] == 8 &&
skb->data[ETH_ALEN+ETH_ALEN+25] == 1) ) {
DEBUGNET2("cyn: net_send_packet %d byte, type %x\n", skb->len, (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
printk("cyn: net_send_packet %d byte, type %x\n", skb->len, (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
if ( skb->len > 34 )
printpkt(skb->data+34, skb->len-34);
}
#endif
/* keep the upload from being interrupted, since we
* ask the chip to start transmitting before the
* whole packet has been completely uploaded.
*/
save_flags(flags);
cli();
/* initiate a transmit sequence */
__EIOW(TX_CMD_PORT) = lp->send_cmd;
__EIOW(TX_LEN_PORT) = skb->len;
/* Test to see if the chip has allocated memory for the packet */
if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
/* Gasp! It hasn't. But that shouldn't happen since
* we're waiting for TxOk, so return 1 and requeue this packet.
*/
restore_flags(flags);
return 1;
}
/* Write the contents of the packet */
cs_outs(TX_FRAME_PORT,(unsigned short *)skb->data,(skb->len+1) >>1);
restore_flags(flags);
dev->trans_start = jiffies;
}
dev_kfree_skb (skb);
return 0;
}
/* The typical workload of the driver:
Handle the network interface interrupts. */
static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
struct device *dev = dev_id;
struct net_local *lp;
unsigned int ioaddr, status;
DEBUGNET("cyn: net_interrupt ");
if (dev == NULL) {
printk ("net_interrupt(): irq %d for unknown device.\n", irq);
return;
}
if (dev->interrupt)
printk("%s: Re-entering the interrupt handler.\n", dev->name);
dev->interrupt = 1;
ioaddr = dev->base_addr;
lp = (struct net_local *)dev->priv;
/* we MUST read all the events out of the ISQ, otherwise we'll never
* get interrupted again. As a consequence, we can't have any limit
* on the number of times we loop in the interrupt handler. The
* hardware guarantees that eventually we'll run out of events. Of
* course, if you're on a slow machine, and packets are arriving
* faster than you can read them off, you're screwed. Hasta la
* vista, baby!
*/
while ((status = readword(dev, ISQ_PORT))) {
if (net_debug > 4)printk("%s: event=%04x\n", dev->name, status);
switch(status & ISQ_EVENT_MASK) {
case ISQ_RECEIVER_EVENT:
DEBUGNET("rcv ");
/* Got a packet(s). */
net_rx(dev);
break;
case ISQ_TRANSMITTER_EVENT:
lp->stats.tx_packets++;
dev->tbusy = 0;
mark_bh(NET_BH);/* Inform upper layers. */
if ((status & TX_OK) == 0)
lp->stats.tx_errors++;
if (status & TX_LOST_CRS)
lp->stats.tx_carrier_errors++;
if (status & TX_SQE_ERROR)
lp->stats.tx_heartbeat_errors++;
if (status & TX_LATE_COL)
lp->stats.tx_window_errors++;
if (status & TX_16_COL)
lp->stats.tx_aborted_errors++;
DEBUGNET2("xmit status=0x%x npkt=%d", status, lp->stats.tx_packets);
break;
case ISQ_BUFFER_EVENT:
DEBUGNET("buffer ");
if (status & READY_FOR_TX) {
/* we tried to transmit a packet earlier,
* but inexplicably ran out of buffers.
* That shouldn't happen since we only ever
* load one packet. Shrug. Do the right
* thing anyway.
*/
dev->tbusy = 0;
mark_bh(NET_BH);/* Inform upper layers. */
}
if (status & TX_UNDERRUN) {
if (net_debug > 0)
printk("%s: transmit underrun\n", dev->name);
lp->send_underrun++;
if (lp->send_underrun == 3)
lp->send_cmd = TX_AFTER_381;
else if
(lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL;
#ifdef __bluecat__
/* transmit cycle is done, although
frame wasn't transmitted - this
avoids having to wait for the upper
layers to timeout on us, in the
event of a tx underrun */
dev->tbusy = 0;
mark_bh(NET_BH);/* Inform upper layers. */
#endif
}
break;
case ISQ_RX_MISS_EVENT:
DEBUGNET("miss ");
lp->stats.rx_missed_errors += (status >>6);
break;
case ISQ_TX_COL_EVENT:
DEBUGNET("coll ");
lp->stats.collisions += (status >>6);
break;
}
}
dev->interrupt = 0;
/*
printk(" netintexit...\n");
*/
return;
}
/* We have a good packet(s), get it/them out of the buffers. */
static void
net_rx(struct device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
struct sk_buff *skb;
uint16_t status, length;
status = __EIOW(RX_FRAME_PORT);
length = __EIOW(RX_FRAME_PORT);
DEBUGNET2(" status=0x%x, len=0x%x ", status, length);
if ((status & RX_OK) == 0) {
lp->stats.rx_errors++;
if (status & RX_RUNT)
lp->stats.rx_length_errors++;
if (status & RX_EXTRA_DATA)
lp->stats.rx_length_errors++;
if (status & RX_CRC_ERROR)
if (!(status & (RX_EXTRA_DATA|RX_RUNT)))
/* per str 172 */
lp->stats.rx_crc_errors++;
if (status & RX_DRIBBLE)
lp->stats.rx_frame_errors++;
return;
}
/* Malloc up new buffer. */
#ifdef __bluecat__
skb = alloc_skb(length+2, GFP_ATOMIC);
#else
skb = alloc_skb(length, GFP_ATOMIC);
#endif
if (skb == NULL) {
printk("%s: Memory squeeze, dropping packet.\n", dev->name);
lp->stats.rx_dropped++;
return;
}
skb->len = length;
skb->dev = dev;
#ifdef __bluecat__
skb_reserve(skb, 2);/* Align IP on 16 byte boundaries */
#endif
cs_ins(RX_FRAME_PORT, (unsigned short *)skb->data, length >> 1);
if (length & 1)
skb->data[length-1] = __EIOW(RX_FRAME_PORT);
if (net_debug > 3)
printk("%s: received %d byte packet of type %x\n", dev->name, length,
(skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]);
skb->protocol=eth_type_trans(skb,dev);
#ifdef SET_NET_DEBUG
if ( (skb->data[20] == 8 && skb->data[21] == 1) ||
(skb->data[22] == 8 && skb->data[23] == 1) ) {
DEBUGNET2("cyn: net_rcv len=%d, proto=0x%x\n", skb->len, skb->protocol);
printk("cyn: net_rcv len=%d, proto=0x%x\n", skb->len, skb->protocol);
if ( skb->len > 20 )
printpkt(skb->data+20, skb->len-20);
}
#endif
//fc99 if ( skb->data[ETH_ALEN+ETH_ALEN+1] != 6 )
#ifndef __bluecat__
netif_rx(skb);
#endif
lp->stats.rx_packets++;
lp->stats.rx_bytes+=skb->len;
#ifdef __bluecat__
netif_rx(skb);
#endif
//printk("net_rx %d...\n", skb->len);
return;
}
/* The inverse routine to net_open(). */
static int
net_close(struct device *dev)
{
DEBUGNET("cyn: net_close\n");
writereg(dev, PP_RxCFG, 0);
writereg(dev, PP_TxCFG, 0);
writereg(dev, PP_BufCFG, 0);
writereg(dev, PP_BusCTL, 0);
dev->start = 0;
/* Update the statistics here. */
MOD_DEC_USE_COUNT;
return 0;
}
/* Get the current statistics.This may be called with the card open or
closed. */
static struct net_device_stats *
net_get_stats(struct device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
DEBUGNET("cyn: net_get_stats\n");
cli();
/* Update the statistics from the device registers. */
lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
sti();
return &lp->stats;
}
static void set_multicast_list(struct device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
DEBUGNET("cyn: net_multicast_list\n");
if(dev->flags&IFF_PROMISC)
{
lp->rx_mode = RX_ALL_ACCEPT;
}
else if((dev->flags&IFF_ALLMULTI)||dev->mc_list)
{
/* The multicast-accept list is initialized to accept-all, and we
rely on higher-level filtering for now. */
lp->rx_mode = RX_MULTCAST_ACCEPT;
}
else
lp->rx_mode = 0;
writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode);
/* in promiscuous mode, we accept errored packets,
* so we have to enable interrupts on them also
*/
writereg(dev, PP_RxCFG, lp->curr_rx_cfg |
(lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|
RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0));
}
static int set_mac_address(struct device *dev, void *addr)
{
int i;
DEBUGNET("cyn: set_mac_address\n");
if (dev->start)
return -EBUSY;
printk("%s: Setting MAC address to ", dev->name);
for (i = 0; i < 6; i++)
printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]);
printk(".\n");
/* set the Ethernet address */
for (i=0; i < ETH_ALEN/2; i++)
writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
return 0;
}
static int inline
readreg(struct device *dev, int portno)
{
//fc99 #ifdef SET_NET_DEBUG
#if 1
unsigned shortin;
DEBUGNET1("cyn: readreg port = 0x%x, ", portno);
__EIOW(ADD_PORT) = portno;
in = __EIOW(DATA_PORT);
DEBUGNET1("value = 0x%x\n", in);
//printk("readreg port = 0x%x, value = 0x%x\n", portno, in);
return in;
#else
__EIOW(ADD_PORT) = portno;
return __EIOW(DATA_PORT);
#endif
}
static void inline
writereg(struct device *dev, int portno, int value)
{
DEBUGNET2("cyn: writereg port = 0x%x, value=0x%x\n", portno, value);
__EIOW(ADD_PORT) = portno;
__EIOW(DATA_PORT) = value;
}
static uint16_t inline
readword(struct device *dev, int portno)
{
return __EIOW(portno);
}
static void inline
writeword(struct device *dev, int portno, int value)
{
__EIOW(portno) = value;
}
__initfunc(static int
wait_eeprom_ready(struct device *dev))
{
int timeout = jiffies;
/* check to see if the EEPROM is ready, a timeout is used -
* just in case EEPROM is ready when SI_BUSY in the
* PP_SelfST is clear
*/
while(readreg(dev, PP_SelfST) & SI_BUSY)
if (jiffies - timeout >= 40)
return -1;
return 0;
}
__initfunc(static int
get_eeprom_data(struct device *dev, int off, int len, int *buffer))
{
int i;
if (net_debug > 3)
printk("EEPROM data from %x for %x:\n",off,len);
for (i = 0; i < len; i++) {
if (wait_eeprom_ready(dev) < 0)
return -1;
/* Now send the EEPROM read command and EEPROM location to read */
writereg(dev, PP_EECMD, (off + i) | EEPROM_READ_CMD);
if (wait_eeprom_ready(dev) < 0)
return -1;
buffer[i] = readreg(dev, PP_EEData);
if (net_debug > 3)
printk("%04x ", buffer[i]);
}
if (net_debug > 3)
printk("\n");
return 0;
}
__initfunc(static int
get_eeprom_cksum(int off, int len, int *buffer))
{
int i, cksum;
cksum = 0;
for (i = 0; i < len; i++)
cksum += buffer[i];
cksum &= 0xffff;
if (cksum == 0)
return 0;
return -1;
}
void
cs_ins(int port, uint16_t *to, int len )
{
DEBUGNET1("cyn: cs_ins len=%d\n", len);
while ( len-- ) *to++ = __EIOW(port);
}
void
cs_outs(int port, uint16_t *from, int len )
{
DEBUGNET3("cyn: cs_outs p=0x%x, from=0x%x, len=%d\n", port, from, len);
while ( len-- ) __EIOW(port) = *from++;
}
#ifdef SET_NET_DEBUG
static void
printpkt( unsigned char *bptr, int len )
{
static charhex[]= { '0','1','2','3','4','5','6','7','8',
'9','a','b','c','d','e','f' };
charoutbuf[100];
char*outp = outbuf;
if ( len > 72 )
len = 72;
while ( len-- ) {
*outp++ = hex[(*bptr&0xf0)>>4] ;
*outp++ = hex[*bptr&0x0f] ;
bptr++;
if ( (len%24) == 0 ) {
*outp = 0;
printk("%s\n", outbuf);
outp = outbuf;
} else {
if ( (len%4) == 0 )
*outp++ = ' ';
*outp++ = ' ';
}
}
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -