📄 lmc_main.c
字号:
/* * Copyright (c) 1997-2000 LAN Media Corporation (LMC) * All rights reserved. www.lanmedia.com * * This code is written by: * Andrew Stanley-Jones (asj@cban.com) * Rob Braun (bbraun@vix.com), * Michael Graff (explorer@vix.com) and * Matt Thomas (matt@3am-software.com). * * With Help By: * David Boggs * Ron Crane * Alan Cox * * This software may be used and distributed according to the terms * of the GNU General Public License version 2, incorporated herein by reference. * * Driver for the LanMedia LMC5200, LMC5245, LMC1000, LMC1200 cards. * * To control link specific options lmcctl is required. * It can be obtained from ftp.lanmedia.com. * * Linux driver notes: * Linux uses the device struct lmc_private to pass private information * arround. * * The initialization portion of this driver (the lmc_reset() and the * lmc_dec_reset() functions, as well as the led controls and the * lmc_initcsrs() functions. * * The watchdog function runs every second and checks to see if * we still have link, and that the timing source is what we expected * it to be. If link is lost, the interface is marked down, and * we no longer can transmit. * *//* $Id: lmc_main.c,v 1.36 2000/04/11 05:25:25 asj Exp $ */#include <linux/kernel.h>#include <linux/module.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/ptrace.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/in.h>#include <linux/if_arp.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/inet.h>#include <net/syncppp.h>#include <asm/processor.h> /* Processor type for cache alignment. */#include <asm/bitops.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/uaccess.h>//#include <asm/spinlock.h>#define DRIVER_MAJOR_VERSION 1#define DRIVER_MINOR_VERSION 34#define DRIVER_SUB_VERSION 0#define DRIVER_VERSION ((DRIVER_MAJOR_VERSION << 8) + DRIVER_MINOR_VERSION)#include "lmc.h"#include "lmc_var.h"#include "lmc_ioctl.h"#include "lmc_debug.h"#include "lmc_proto.h"static int lmc_first_load = 0;static int LMC_PKT_BUF_SZ = 1542;static struct pci_device_id lmc_pci_tbl[] = { { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST, PCI_VENDOR_ID_LMC, PCI_ANY_ID }, { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST, PCI_ANY_ID, PCI_VENDOR_ID_LMC }, { 0 }};MODULE_DEVICE_TABLE(pci, lmc_pci_tbl);MODULE_LICENSE("GPL");static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev);static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev);static int lmc_rx (struct net_device *dev);static int lmc_open(struct net_device *dev);static int lmc_close(struct net_device *dev);static struct net_device_stats *lmc_get_stats(struct net_device *dev);static irqreturn_t lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs);static int lmc_set_config(struct net_device *dev, struct ifmap *map);static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, size_t csr_size);static void lmc_softreset(lmc_softc_t * const);static void lmc_running_reset(struct net_device *dev);static int lmc_ifdown(struct net_device * const);static void lmc_watchdog(unsigned long data);static void lmc_reset(lmc_softc_t * const sc);static void lmc_dec_reset(lmc_softc_t * const sc);static void lmc_driver_timeout(struct net_device *dev);/* * linux reserves 16 device specific IOCTLs. We call them * LMCIOC* to control various bits of our world. */int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/{ lmc_softc_t *sc; lmc_ctl_t ctl; int ret; u_int16_t regVal; unsigned long flags; struct sppp *sp; ret = -EOPNOTSUPP; sc = dev->priv; lmc_trace(dev, "lmc_ioctl in"); /* * Most functions mess with the structure * Disable interrupts while we do the polling */ spin_lock_irqsave(&sc->lmc_lock, flags); switch (cmd) { /* * Return current driver state. Since we keep this up * To date internally, just copy this out to the user. */ case LMCIOCGINFO: /*fold01*/ if (copy_to_user(ifr->ifr_data, &sc->ictl, sizeof (lmc_ctl_t))) return -EFAULT; ret = 0; break; case LMCIOCSINFO: /*fold01*/ sp = &((struct ppp_device *) dev)->sppp; if (!capable(CAP_NET_ADMIN)) { ret = -EPERM; break; } if(dev->flags & IFF_UP){ ret = -EBUSY; break; } if (copy_from_user(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t))) return -EFAULT; sc->lmc_media->set_status (sc, &ctl); if(ctl.crc_length != sc->ictl.crc_length) { sc->lmc_media->set_crc_length(sc, ctl.crc_length); if (sc->ictl.crc_length == LMC_CTL_CRC_LENGTH_16) sc->TxDescriptControlInit |= LMC_TDES_ADD_CRC_DISABLE; else sc->TxDescriptControlInit &= ~LMC_TDES_ADD_CRC_DISABLE; } if (ctl.keepalive_onoff == LMC_CTL_OFF) sp->pp_flags &= ~PP_KEEPALIVE; /* Turn off */ else sp->pp_flags |= PP_KEEPALIVE; /* Turn on */ ret = 0; break; case LMCIOCIFTYPE: /*fold01*/ { u_int16_t old_type = sc->if_type; u_int16_t new_type; if (!capable(CAP_NET_ADMIN)) { ret = -EPERM; break; } if (copy_from_user(&new_type, ifr->ifr_data, sizeof(u_int16_t))) return -EFAULT; if (new_type == old_type) { ret = 0 ; break; /* no change */ } lmc_proto_close(sc); lmc_proto_detach(sc); sc->if_type = new_type;// lmc_proto_init(sc); lmc_proto_attach(sc); lmc_proto_open(sc); ret = 0 ; break ; } case LMCIOCGETXINFO: /*fold01*/ sc->lmc_xinfo.Magic0 = 0xBEEFCAFE; sc->lmc_xinfo.PciCardType = sc->lmc_cardtype; sc->lmc_xinfo.PciSlotNumber = 0; sc->lmc_xinfo.DriverMajorVersion = DRIVER_MAJOR_VERSION; sc->lmc_xinfo.DriverMinorVersion = DRIVER_MINOR_VERSION; sc->lmc_xinfo.DriverSubVersion = DRIVER_SUB_VERSION; sc->lmc_xinfo.XilinxRevisionNumber = lmc_mii_readreg (sc, 0, 3) & 0xf; sc->lmc_xinfo.MaxFrameSize = LMC_PKT_BUF_SZ; sc->lmc_xinfo.link_status = sc->lmc_media->get_link_status (sc); sc->lmc_xinfo.mii_reg16 = lmc_mii_readreg (sc, 0, 16); sc->lmc_xinfo.Magic1 = 0xDEADBEEF; if (copy_to_user(ifr->ifr_data, &sc->lmc_xinfo, sizeof (struct lmc_xinfo))) return -EFAULT; ret = 0; break; case LMCIOCGETLMCSTATS: /*fold01*/ if (sc->lmc_cardtype == LMC_CARDTYPE_T1){ lmc_mii_writereg (sc, 0, 17, T1FRAMER_FERR_LSB); sc->stats.framingBitErrorCount += lmc_mii_readreg (sc, 0, 18) & 0xff; lmc_mii_writereg (sc, 0, 17, T1FRAMER_FERR_MSB); sc->stats.framingBitErrorCount += (lmc_mii_readreg (sc, 0, 18) & 0xff) << 8; lmc_mii_writereg (sc, 0, 17, T1FRAMER_LCV_LSB); sc->stats.lineCodeViolationCount += lmc_mii_readreg (sc, 0, 18) & 0xff; lmc_mii_writereg (sc, 0, 17, T1FRAMER_LCV_MSB); sc->stats.lineCodeViolationCount += (lmc_mii_readreg (sc, 0, 18) & 0xff) << 8; lmc_mii_writereg (sc, 0, 17, T1FRAMER_AERR); regVal = lmc_mii_readreg (sc, 0, 18) & 0xff; sc->stats.lossOfFrameCount += (regVal & T1FRAMER_LOF_MASK) >> 4; sc->stats.changeOfFrameAlignmentCount += (regVal & T1FRAMER_COFA_MASK) >> 2; sc->stats.severelyErroredFrameCount += regVal & T1FRAMER_SEF_MASK; } if (copy_to_user(ifr->ifr_data, &sc->stats, sizeof (struct lmc_statistics))) return -EFAULT; ret = 0; break; case LMCIOCCLEARLMCSTATS: /*fold01*/ if (!capable(CAP_NET_ADMIN)){ ret = -EPERM; break; } memset (&sc->stats, 0, sizeof (struct lmc_statistics)); sc->stats.check = STATCHECK; sc->stats.version_size = (DRIVER_VERSION << 16) + sizeof (struct lmc_statistics); sc->stats.lmc_cardtype = sc->lmc_cardtype; ret = 0; break; case LMCIOCSETCIRCUIT: /*fold01*/ if (!capable(CAP_NET_ADMIN)){ ret = -EPERM; break; } if(dev->flags & IFF_UP){ ret = -EBUSY; break; } if (copy_from_user(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t))) return -EFAULT; sc->lmc_media->set_circuit_type(sc, ctl.circuit_type); sc->ictl.circuit_type = ctl.circuit_type; ret = 0; break; case LMCIOCRESET: /*fold01*/ if (!capable(CAP_NET_ADMIN)){ ret = -EPERM; break; } /* Reset driver and bring back to current state */ printk (" REG16 before reset +%04x\n", lmc_mii_readreg (sc, 0, 16)); lmc_running_reset (dev); printk (" REG16 after reset +%04x\n", lmc_mii_readreg (sc, 0, 16)); LMC_EVENT_LOG(LMC_EVENT_FORCEDRESET, LMC_CSR_READ (sc, csr_status), lmc_mii_readreg (sc, 0, 16)); ret = 0; break;#ifdef DEBUG case LMCIOCDUMPEVENTLOG: if (copy_to_user(ifr->ifr_data, &lmcEventLogIndex, sizeof (u32))) return -EFAULT; if (copy_to_user(ifr->ifr_data + sizeof (u32), lmcEventLogBuf, sizeof (lmcEventLogBuf))) return -EFAULT; ret = 0; break;#endif /* end ifdef _DBG_EVENTLOG */ case LMCIOCT1CONTROL: /*fold01*/ if (sc->lmc_cardtype != LMC_CARDTYPE_T1){ ret = -EOPNOTSUPP; break; } break; case LMCIOCXILINX: /*fold01*/ { struct lmc_xilinx_control xc; /*fold02*/ if (!capable(CAP_NET_ADMIN)){ ret = -EPERM; break; } /* * Stop the xwitter whlie we restart the hardware */ netif_stop_queue(dev); if (copy_from_user(&xc, ifr->ifr_data, sizeof (struct lmc_xilinx_control))) return -EFAULT; switch(xc.command){ case lmc_xilinx_reset: /*fold02*/ { u16 mii; mii = lmc_mii_readreg (sc, 0, 16); /* * Make all of them 0 and make input */ lmc_gpio_mkinput(sc, 0xff); /* * make the reset output */ lmc_gpio_mkoutput(sc, LMC_GEP_RESET); /* * RESET low to force configuration. This also forces * the transmitter clock to be internal, but we expect to reset * that later anyway. */ sc->lmc_gpio &= ~LMC_GEP_RESET; LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); /* * hold for more than 10 microseconds */ udelay(50); sc->lmc_gpio |= LMC_GEP_RESET; LMC_CSR_WRITE(sc, csr_gp, sc->lmc_gpio); /* * stop driving Xilinx-related signals */ lmc_gpio_mkinput(sc, 0xff); /* Reset the frammer hardware */ sc->lmc_media->set_link_status (sc, 1); sc->lmc_media->set_status (sc, NULL);// lmc_softreset(sc); { int i; for(i = 0; i < 5; i++){ lmc_led_on(sc, LMC_DS3_LED0); mdelay(100); lmc_led_off(sc, LMC_DS3_LED0); lmc_led_on(sc, LMC_DS3_LED1); mdelay(100); lmc_led_off(sc, LMC_DS3_LED1); lmc_led_on(sc, LMC_DS3_LED3); mdelay(100); lmc_led_off(sc, LMC_DS3_LED3); lmc_led_on(sc, LMC_DS3_LED2); mdelay(100); lmc_led_off(sc, LMC_DS3_LED2); } } ret = 0x0; } break; case lmc_xilinx_load_prom: /*fold02*/ { u16 mii; int timeout = 500000; mii = lmc_mii_readreg (sc, 0, 16); /* * Make all of them 0 and make input */ lmc_gpio_mkinput(sc, 0xff); /* * make the reset output */ lmc_gpio_mkoutput(sc, LMC_GEP_DP | LMC_GEP_RESET); /* * RESET low to force configuration. This also forces * the transmitter clock to be internal, but we expect to reset * that later anyway. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -