⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bluecat_cs8900a.c

📁 嵌入式linux系统CS8900A驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
   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 + -