📄 8253xnet.c
字号:
/* -*- linux-c -*- *//* * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * **/#include <linux/module.h>#include <linux/kernel.h>#include <linux/pci.h>#include <linux/stddef.h>#include <linux/string.h>#include <linux/sockios.h>#include <asm/io.h>#include <asm/byteorder.h>#include <asm/pgtable.h>#include <linux/skbuff.h>#include <linux/if_arp.h>#include <linux/fs.h>#include <linux/sched.h>#include <asm/uaccess.h>#include <linux/version.h>#include <linux/etherdevice.h>#include "Reg9050.h"#include "8253xctl.h"#include "ring.h"#include "8253x.h"#include "crc32dcl.h" /* turns network packet into a pseudoethernet */ /* frame -- does ethernet stuff that 8253x does */ /* not do -- makes minimum 64 bytes add crc, etc*/int sab8253xn_write2(struct sk_buff *skb, struct net_device *dev){ size_t cnt; unsigned int flags; SAB_PORT *priv = (SAB_PORT*) dev->priv; struct sk_buff *substitute;#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) if(dev->tbusy != 0) /* something of an error */ { ++(priv->Counters.tx_drops); dev_kfree_skb_any(skb); return -EBUSY; /* only during release */ }#endif if(priv->active2.transmit == NULL) { return -ENOMEM; } DEBUGPRINT((KERN_ALERT "sab8253x: sending IP packet(bytes):\n")); DEBUGPRINT((KERN_ALERT "sab8253x: start address is %p.\n", skb->data)); cnt = skb->tail - skb->data; cnt = MIN(cnt, sab8253xn_rbufsize); if(cnt < ETH_ZLEN) { if((skb->end - skb->data) >= ETH_ZLEN) { skb->tail = (skb->data + ETH_ZLEN); cnt = ETH_ZLEN; } else { substitute = dev_alloc_skb(ETH_ZLEN); if(substitute == NULL) { dev_kfree_skb_any(skb); return 0; } substitute->tail = (substitute->data + ETH_ZLEN); memcpy(substitute->data, skb->data, cnt); cnt = ETH_ZLEN; dev_kfree_skb_any(skb); skb = substitute; } } save_flags(flags); cli(); if((priv->active2.transmit->Count & OWNER) == OWN_SAB) { ++(priv->Counters.tx_drops);#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) dev->tbusy = 1;#else netif_stop_queue (dev);#endif priv->tx_full = 1; restore_flags(flags); return 1; } restore_flags(flags);#ifndef FREEINTERRUPT if(priv->active2.transmit->HostVaddr != NULL) { register RING_DESCRIPTOR *freeme; freeme = priv->active2.transmit; do { skb_unlink((struct sk_buff*)freeme->HostVaddr); dev_kfree_skb_any((struct sk_buff*)freeme->HostVaddr); freeme->HostVaddr = NULL; freeme = (RING_DESCRIPTOR*) freeme->VNext; } while(((freeme->Count & OWNER) != OWN_SAB) && (freeme->HostVaddr != NULL)); }#endif dev->trans_start = jiffies; skb_queue_head(priv->sab8253xbuflist, skb); priv->active2.transmit->HostVaddr = skb; priv->active2.transmit->sendcrc = 1; priv->active2.transmit->crcindex = 0; priv->active2.transmit->crc = fn_calc_memory_crc32(skb->data, cnt); priv->active2.transmit->Count = (OWN_SAB|cnt); /* must be this order */ priv->active2.transmit = (RING_DESCRIPTOR*) priv->active2.transmit->VNext; priv->Counters.transmitbytes += cnt; sab8253x_start_txS(priv); return 0;} /* packetizes the received character */ /* stream */static void sab8253x_receive_charsN(struct sab_port *port, union sab8253x_irq_status *stat){ unsigned char buf[32]; int free_fifo = 0; int reset_fifo = 0; int msg_done = 0; int msg_bad = 0; int count = 0; int total_size = 0; int rstatus = 0; struct sk_buff *skb; /* Read number of BYTES (Character + Status) available. */ if((stat->images[ISR1_IDX] & SAB82532_ISR1_RDO) || (stat->images[ISR0_IDX] & SAB82532_ISR0_RFO) ) { ++msg_bad; ++free_fifo; ++reset_fifo; } else { if (stat->images[ISR0_IDX] & SAB82532_ISR0_RPF) { count = port->recv_fifo_size; ++free_fifo; } if (stat->images[ISR0_IDX] & SAB82532_ISR0_RME) { count = READB(port,rbcl); count &= (port->recv_fifo_size - 1); ++msg_done; ++free_fifo; total_size = READB(port, rbch); if(total_size & SAB82532_RBCH_OV) { msg_bad++; } rstatus = READB(port, rsta); if((rstatus & SAB82532_RSTA_VFR) == 0) { msg_bad++; } if(rstatus & SAB82532_RSTA_RDO) { msg_bad++; } if((rstatus & SAB82532_RSTA_CRC) == 0) { msg_bad++; } if(rstatus & SAB82532_RSTA_RAB) { msg_bad++; } } } /* Read the FIFO. */ (*port->readfifo)(port, buf, count); /* Issue Receive Message Complete command. */ if (free_fifo) { sab8253x_cec_wait(port); WRITEB(port, cmdr, SAB82532_CMDR_RMC); } if(reset_fifo) { sab8253x_cec_wait(port); WRITEB(port, cmdr, SAB82532_CMDR_RHR); } if(port->active2.receive == NULL) { return; } if(msg_bad) { ++(port->Counters.rx_drops); port->active2.receive->HostVaddr->tail = port->active2.receive->HostVaddr->data; /* clear the buffer */ port->active2.receive->Count = sab8253xn_rbufsize|OWN_SAB; return; } memcpy(port->active2.receive->HostVaddr->tail, buf, count); port->active2.receive->HostVaddr->tail += count; if(msg_done) { port->active2.receive->Count = (port->active2.receive->HostVaddr->tail - port->active2.receive->HostVaddr->data); if((port->active2.receive->Count < (ETH_ZLEN+4+3)) || /* 4 is the CRC32 size 3 bytes from the SAB part */ (skb = dev_alloc_skb(sab8253xn_rbufsize), skb == NULL)) { ++(port->Counters.rx_drops); port->active2.receive->HostVaddr->tail = port->active2.receive->HostVaddr->data; /* clear the buffer */ port->active2.receive->Count = sab8253xn_rbufsize|OWN_SAB; } else { port->active2.receive->Count -= 3; port->active2.receive->HostVaddr->len = port->active2.receive->Count; port->active2.receive->HostVaddr->pkt_type = PACKET_HOST; port->active2.receive->HostVaddr->dev = port->dev; port->active2.receive->HostVaddr->protocol = eth_type_trans(port->active2.receive->HostVaddr, port->dev); port->active2.receive->HostVaddr->tail -= 3; ++(port->Counters.receivepacket); port->Counters.receivebytes += port->active2.receive->Count; skb_unlink(port->active2.receive->HostVaddr); netif_rx(port->active2.receive->HostVaddr); skb_queue_head(port->sab8253xbuflist, skb); port->active2.receive->HostVaddr = skb; port->active2.receive->Count = sab8253xn_rbufsize|OWN_SAB; } }}static void sab8253x_check_statusN(struct sab_port *port, union sab8253x_irq_status *stat){ int modem_change = 0; mctlsig_t *sig; if (stat->images[ISR0_IDX] & SAB82532_ISR0_RFO) { port->icount.buf_overrun++; } /* Checking DCD */ sig = &port->dcd; if (stat->images[sig->irq] & sig->irqmask) { sig->val = ISON(port,dcd); port->icount.dcd++; modem_change++; } /* Checking CTS */ sig = &port->cts; if (stat->images[sig->irq] & sig->irqmask) { sig->val = ISON(port,cts); port->icount.cts++; modem_change++; } /* Checking DSR */ sig = &port->dsr; if (stat->images[sig->irq] & sig->irqmask) { sig->val = ISON(port,dsr); port->icount.dsr++; modem_change++; } if (modem_change) { wake_up_interruptible(&port->delta_msr_wait); } sig = &port->dcd; if ((port->flags & FLAG8253X_CHECK_CD) && (stat->images[sig->irq] & sig->irqmask)) { if (sig->val) { netif_carrier_on(port->dev); } else if (!((port->flags & FLAG8253X_CALLOUT_ACTIVE) && (port->flags & FLAG8253X_CALLOUT_NOHUP))) { netif_carrier_off(port->dev); } }#if 0 /* need to think about CTS/RTS stuff for a network driver */ sig = &port->cts; if (port->flags & FLAG8253X_CTS_FLOW) { /* not setting this yet */ if (port->tty->hw_stopped) { if (sig->val) { port->tty->hw_stopped = 0; sab8253x_sched_event(port, RS_EVENT_WRITE_WAKEUP); port->interrupt_mask1 &= ~(SAB82532_IMR1_XPR); WRITEB(port, imr1, port->interrupt_mask1); sab8253x_start_txS(port); } } else { if (!(sig->val)) { port->tty->hw_stopped = 1; } } }#endif}static void Sab8253xCollectStats(struct net_device *dev){ struct net_device_stats *statsp = &((SAB_PORT*) dev->priv)->stats;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -