ewrk3.c
字号:
ManCode[0] = (((Eisa.Id[0] >> 2) & 0x1f) + 0x40); ManCode[1] = (((Eisa.Id[1] & 0xe0) >> 5) + ((Eisa.Id[0] & 0x03) << 3) + 0x40); ManCode[2] = (((Eisa.Id[2] >> 4) & 0x0f) + 0x30); ManCode[3] = ((Eisa.Id[2] & 0x0f) + 0x30); ManCode[4] = (((Eisa.Id[3] >> 4) & 0x0f) + 0x30); ManCode[5] = '\0'; for (i = 0; (*signatures[i] != '\0') && (*name == '\0'); i++) { if (strstr(ManCode, signatures[i]) != NULL) { strcpy(name, ManCode); status = 1; } } return status; /* return the device name string */}static void ewrk3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ int fwrev = Read_EEPROM(dev->base_addr, EEPROM_REVLVL); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); sprintf(info->fw_version, "%d", fwrev); strcpy(info->bus_info, "N/A"); info->eedump_len = EEPROM_MAX;}static int ewrk3_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd){ struct ewrk3_private *lp = netdev_priv(dev); unsigned long iobase = dev->base_addr; u8 cr = inb(EWRK3_CR); switch (lp->adapter_name[4]) { case '3': /* DE203 */ ecmd->supported = SUPPORTED_BNC; ecmd->port = PORT_BNC; break; case '4': /* DE204 */ ecmd->supported = SUPPORTED_TP; ecmd->port = PORT_TP; break; case '5': /* DE205 */ ecmd->supported = SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_AUI; ecmd->autoneg = !(cr & CR_APD); /* ** Port is only valid if autoneg is disabled ** and even then we don't know if AUI is jumpered. */ if (!ecmd->autoneg) ecmd->port = (cr & CR_PSEL) ? PORT_BNC : PORT_TP; break; } ecmd->supported |= SUPPORTED_10baseT_Half; ecmd->speed = SPEED_10; ecmd->duplex = DUPLEX_HALF; return 0;}static int ewrk3_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd){ struct ewrk3_private *lp = netdev_priv(dev); unsigned long iobase = dev->base_addr; unsigned long flags; u8 cr; /* DE205 is the only card with anything to set */ if (lp->adapter_name[4] != '5') return -EOPNOTSUPP; /* Sanity-check parameters */ if (ecmd->speed != SPEED_10) return -EINVAL; if (ecmd->port != PORT_TP && ecmd->port != PORT_BNC) return -EINVAL; /* AUI is not software-selectable */ if (ecmd->transceiver != XCVR_INTERNAL) return -EINVAL; if (ecmd->duplex != DUPLEX_HALF) return -EINVAL; if (ecmd->phy_address != 0) return -EINVAL; spin_lock_irqsave(&lp->hw_lock, flags); cr = inb(EWRK3_CR); /* If Autoneg is set, change to Auto Port mode */ /* Otherwise, disable Auto Port and set port explicitly */ if (ecmd->autoneg) { cr &= ~CR_APD; } else { cr |= CR_APD; if (ecmd->port == PORT_TP) cr &= ~CR_PSEL; /* Force TP */ else cr |= CR_PSEL; /* Force BNC */ } /* Commit the changes */ outb(cr, EWRK3_CR); spin_unlock_irqrestore(&lp->hw_lock, flags); return 0;}static u32 ewrk3_get_link(struct net_device *dev){ unsigned long iobase = dev->base_addr; u8 cmr = inb(EWRK3_CMR); /* DE203 has BNC only and link status does not apply */ /* On DE204 this is always valid since TP is the only port. */ /* On DE205 this reflects TP status even if BNC or AUI is selected. */ return !(cmr & CMR_LINK);}static int ewrk3_phys_id(struct net_device *dev, u32 data){ struct ewrk3_private *lp = netdev_priv(dev); unsigned long iobase = dev->base_addr; unsigned long flags; u8 cr; int count; /* Toggle LED 4x per second */ count = data << 2; spin_lock_irqsave(&lp->hw_lock, flags); /* Bail if a PHYS_ID is already in progress */ if (lp->led_mask == 0) { spin_unlock_irqrestore(&lp->hw_lock, flags); return -EBUSY; } /* Prevent ISR from twiddling the LED */ lp->led_mask = 0; while (count--) { /* Toggle the LED */ cr = inb(EWRK3_CR); outb(cr ^ CR_LED, EWRK3_CR); /* Wait a little while */ spin_unlock_irqrestore(&lp->hw_lock, flags); msleep(250); spin_lock_irqsave(&lp->hw_lock, flags); /* Exit if we got a signal */ if (signal_pending(current)) break; } lp->led_mask = CR_LED; cr = inb(EWRK3_CR); outb(cr & ~CR_LED, EWRK3_CR); spin_unlock_irqrestore(&lp->hw_lock, flags); return signal_pending(current) ? -ERESTARTSYS : 0;}static const struct ethtool_ops ethtool_ops_203 = { .get_drvinfo = ewrk3_get_drvinfo, .get_settings = ewrk3_get_settings, .set_settings = ewrk3_set_settings, .phys_id = ewrk3_phys_id,};static const struct ethtool_ops ethtool_ops = { .get_drvinfo = ewrk3_get_drvinfo, .get_settings = ewrk3_get_settings, .set_settings = ewrk3_set_settings, .get_link = ewrk3_get_link, .phys_id = ewrk3_phys_id,};/* ** Perform IOCTL call functions here. Some are privileged operations and the ** effective uid is checked in those cases. */static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ struct ewrk3_private *lp = netdev_priv(dev); struct ewrk3_ioctl *ioc = (struct ewrk3_ioctl *) &rq->ifr_ifru; u_long iobase = dev->base_addr; int i, j, status = 0; u_char csr; unsigned long flags; union ewrk3_addr { u_char addr[HASH_TABLE_LEN * ETH_ALEN]; u_short val[(HASH_TABLE_LEN * ETH_ALEN) >> 1]; }; union ewrk3_addr *tmp; /* All we handle are private IOCTLs */ if (cmd != EWRK3IOCTL) return -EOPNOTSUPP; tmp = kmalloc(sizeof(union ewrk3_addr), GFP_KERNEL); if(tmp==NULL) return -ENOMEM; switch (ioc->cmd) { case EWRK3_GET_HWADDR: /* Get the hardware address */ for (i = 0; i < ETH_ALEN; i++) { tmp->addr[i] = dev->dev_addr[i]; } ioc->len = ETH_ALEN; if (copy_to_user(ioc->data, tmp->addr, ioc->len)) status = -EFAULT; break; case EWRK3_SET_HWADDR: /* Set the hardware address */ if (capable(CAP_NET_ADMIN)) { spin_lock_irqsave(&lp->hw_lock, flags); csr = inb(EWRK3_CSR); csr |= (CSR_TXD | CSR_RXD); outb(csr, EWRK3_CSR); /* Disable the TX and RX */ spin_unlock_irqrestore(&lp->hw_lock, flags); if (copy_from_user(tmp->addr, ioc->data, ETH_ALEN)) { status = -EFAULT; break; } spin_lock_irqsave(&lp->hw_lock, flags); for (i = 0; i < ETH_ALEN; i++) { dev->dev_addr[i] = tmp->addr[i]; outb(tmp->addr[i], EWRK3_PAR0 + i); } csr = inb(EWRK3_CSR); csr &= ~(CSR_TXD | CSR_RXD); /* Enable the TX and RX */ outb(csr, EWRK3_CSR); spin_unlock_irqrestore(&lp->hw_lock, flags); } else { status = -EPERM; } break; case EWRK3_SET_PROM: /* Set Promiscuous Mode */ if (capable(CAP_NET_ADMIN)) { spin_lock_irqsave(&lp->hw_lock, flags); csr = inb(EWRK3_CSR); csr |= CSR_PME; csr &= ~CSR_MCE; outb(csr, EWRK3_CSR); spin_unlock_irqrestore(&lp->hw_lock, flags); } else { status = -EPERM; } break; case EWRK3_CLR_PROM: /* Clear Promiscuous Mode */ if (capable(CAP_NET_ADMIN)) { spin_lock_irqsave(&lp->hw_lock, flags); csr = inb(EWRK3_CSR); csr &= ~CSR_PME; outb(csr, EWRK3_CSR); spin_unlock_irqrestore(&lp->hw_lock, flags); } else { status = -EPERM; } break; case EWRK3_GET_MCA: /* Get the multicast address table */ spin_lock_irqsave(&lp->hw_lock, flags); if (lp->shmem_length == IO_ONLY) { outb(0, EWRK3_IOPR); outw(PAGE0_HTE, EWRK3_PIR1); for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) { tmp->addr[i] = inb(EWRK3_DATA); } } else { outb(0, EWRK3_MPR); memcpy_fromio(tmp->addr, lp->shmem + PAGE0_HTE, (HASH_TABLE_LEN >> 3)); } spin_unlock_irqrestore(&lp->hw_lock, flags); ioc->len = (HASH_TABLE_LEN >> 3); if (copy_to_user(ioc->data, tmp->addr, ioc->len)) status = -EFAULT; break; case EWRK3_SET_MCA: /* Set a multicast address */ if (capable(CAP_NET_ADMIN)) { if (ioc->len > 1024) { status = -EINVAL; break; } if (copy_from_user(tmp->addr, ioc->data, ETH_ALEN * ioc->len)) { status = -EFAULT; break; } set_multicast_list(dev); } else { status = -EPERM; } break; case EWRK3_CLR_MCA: /* Clear all multicast addresses */ if (capable(CAP_NET_ADMIN)) { set_multicast_list(dev); } else { status = -EPERM; } break; case EWRK3_MCA_EN: /* Enable multicast addressing */ if (capable(CAP_NET_ADMIN)) { spin_lock_irqsave(&lp->hw_lock, flags); csr = inb(EWRK3_CSR); csr |= CSR_MCE; csr &= ~CSR_PME; outb(csr, EWRK3_CSR); spin_unlock_irqrestore(&lp->hw_lock, flags); } else { status = -EPERM; } break; case EWRK3_GET_STATS: { /* Get the driver statistics */ struct ewrk3_stats *tmp_stats = kmalloc(sizeof(lp->pktStats), GFP_KERNEL); if (!tmp_stats) { status = -ENOMEM; break; } spin_lock_irqsave(&lp->hw_lock, flags); memcpy(tmp_stats, &lp->pktStats, sizeof(lp->pktStats)); spin_unlock_irqrestore(&lp->hw_lock, flags); ioc->len = sizeof(lp->pktStats); if (copy_to_user(ioc->data, tmp_stats, sizeof(lp->pktStats))) status = -EFAULT; kfree(tmp_stats); break; } case EWRK3_CLR_STATS: /* Zero out the driver statistics */ if (capable(CAP_NET_ADMIN)) { spin_lock_irqsave(&lp->hw_lock, flags); memset(&lp->pktStats, 0, sizeof(lp->pktStats)); spin_unlock_irqrestore(&lp->hw_lock,flags); } else { status = -EPERM; } break; case EWRK3_GET_CSR: /* Get the CSR Register contents */ tmp->addr[0] = inb(EWRK3_CSR); ioc->len = 1; if (copy_to_user(ioc->data, tmp->addr, ioc->len)) status = -EFAULT; break; case EWRK3_SET_CSR: /* Set the CSR Register contents */ if (capable(CAP_NET_ADMIN)) { if (copy_from_user(tmp->addr, ioc->data, 1)) { status = -EFAULT; break; } outb(tmp->addr[0], EWRK3_CSR); } else { status = -EPERM; } break; case EWRK3_GET_EEPROM: /* Get the EEPROM contents */ if (capable(CAP_NET_ADMIN)) { for (i = 0; i < (EEPROM_MAX >> 1); i++) { tmp->val[i] = (short) Read_EEPROM(iobase, i); } i = EEPROM_MAX; tmp->addr[i++] = inb(EWRK3_CMR); /* Config/Management Reg. */ for (j = 0; j < ETH_ALEN; j++) { tmp->addr[i++] = inb(EWRK3_PAR0 + j); } ioc->len = EEPROM_MAX + 1 + ETH_ALEN; if (copy_to_user(ioc->data, tmp->addr, ioc->len)) status = -EFAULT; } else { status = -EPERM; } break; case EWRK3_SET_EEPROM: /* Set the EEPROM contents */ if (capable(CAP_NET_ADMIN)) { if (copy_from_user(tmp->addr, ioc->data, EEPROM_MAX)) { status = -EFAULT; break; } for (i = 0; i < (EEPROM_MAX >> 1); i++) { Write_EEPROM(tmp->val[i], iobase, i); } } else { status = -EPERM; } break; case EWRK3_GET_CMR: /* Get the CMR Register contents */ tmp->addr[0] = inb(EWRK3_CMR); ioc->len = 1; if (copy_to_user(ioc->data, tmp->addr, ioc->len)) status = -EFAULT; break; case EWRK3_SET_TX_CUT_THRU: /* Set TX cut through mode */ if (capable(CAP_NET_ADMIN)) { lp->txc = 1; } else { status = -EPERM; } break; case EWRK3_CLR_TX_CUT_THRU: /* Clear TX cut through mode */ if (capable(CAP_NET_ADMIN)) { lp->txc = 0; } else { status = -EPERM; } break; default: status = -EOPNOTSUPP; } kfree(tmp); return status;}#ifdef MODULEstatic struct net_device *ewrk3_devs[MAX_NUM_EWRK3S];static int ndevs;static int io[MAX_NUM_EWRK3S+1] = { 0x300, 0, };/* '21' below should really be 'MAX_NUM_EWRK3S' */module_param_array(io, int, NULL, 0);module_param_array(irq, int, NULL, 0);MODULE_PARM_DESC(io, "EtherWORKS 3 I/O base address(es)");MODULE_PARM_DESC(irq, "EtherWORKS 3 IRQ number(s)");static __exit void ewrk3_exit_module(void){ int i; for( i=0; i<ndevs; i++ ) { struct net_device *dev = ewrk3_devs[i]; struct ewrk3_private *lp = netdev_priv(dev); ewrk3_devs[i] = NULL; unregister_netdev(dev); release_region(dev->base_addr, EWRK3_TOTAL_SIZE); iounmap(lp->shmem); free_netdev(dev); }}static __init int ewrk3_init_module(void){ int i=0; while( io[i] && irq[i] ) { struct net_device *dev = alloc_etherdev(sizeof(struct ewrk3_private)); if (!dev) break; if (ewrk3_probe1(dev, io[i], irq[i]) != 0) { free_netdev(dev); break; } ewrk3_devs[ndevs++] = dev; i++; } return ndevs ? 0 : -EIO;}/* Hack for breakage in new module stuff */module_exit(ewrk3_exit_module);module_init(ewrk3_init_module);#endif /* MODULE */MODULE_LICENSE("GPL");/* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c ewrk3.c" * * compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c ewrk3.c" * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -