📄 depca.c
字号:
** card initialized itself correctly.** ** Search the Ethernet address ROM for the signature. Since the ROM address** counter can start at an arbitrary point, the search must include the entire** probe sequence length plus the (length_of_the_signature - 1).** Stop the search IMMEDIATELY after the signature is found so that the** PROM address counter is correctly positioned at the start of the** ethernet address for later read out.*/__initfunc(static intDevicePresent(u_long ioaddr)){ union { struct { u32 a; u32 b; } llsig; char Sig[sizeof(u32) << 1]; } dev; short sigLength=0; s8 data; s16 nicsr; int i, j, status = 0; data = inb(DEPCA_PROM); /* clear counter on DEPCA */ data = inb(DEPCA_PROM); /* read data */ if (data == 0x08) { /* Enable counter on DEPCA */ nicsr = inb(DEPCA_NICSR); nicsr |= AAC; outb(nicsr, DEPCA_NICSR); } dev.llsig.a = ETH_PROM_SIG; dev.llsig.b = ETH_PROM_SIG; sigLength = sizeof(u32) << 1; for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) { data = inb(DEPCA_PROM); if (dev.Sig[j] == data) { /* track signature */ j++; } else { /* lost signature; begin search again */ if (data == dev.Sig[0]) { /* rare case.... */ j=1; } else { j=0; } } } if (j!=sigLength) { status = -ENODEV; /* search failed */ } return status;}/*** The DE100 and DE101 PROM accesses were made non-standard for some bizarre** reason: access the upper half of the PROM with x=0; access the lower half** with x=1.*/__initfunc(static intget_hw_addr(struct device *dev)){ u_long ioaddr = dev->base_addr; int i, k, tmp, status = 0; u_short j, x, chksum; x = (((adapter == de100) || (adapter == de101)) ? 1 : 0); for (i=0,k=0,j=0;j<3;j++) { k <<= 1 ; if (k > 0xffff) k-=0xffff; k += (u_char) (tmp = inb(DEPCA_PROM + x)); dev->dev_addr[i++] = (u_char) tmp; k += (u_short) ((tmp = inb(DEPCA_PROM + x)) << 8); dev->dev_addr[i++] = (u_char) tmp; if (k > 0xffff) k-=0xffff; } if (k == 0xffff) k=0; chksum = (u_char) inb(DEPCA_PROM + x); chksum |= (u_short) (inb(DEPCA_PROM + x) << 8); if (k != chksum) status = -1; return status;}/*** Load a packet into the shared memory*/static int load_packet(struct device *dev, struct sk_buff *skb){ struct depca_private *lp = (struct depca_private *)dev->priv; int i, entry, end, len, status = 0; entry = lp->tx_new; /* Ring around buffer number. */ end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask; if (!(readl(&lp->tx_ring[end].base) & T_OWN)) {/* Enough room? */ /* ** Caution: the write order is important here... don't set up the ** ownership rights until all the other information is in place. */ if (end < entry) { /* wrapped buffer */ len = (lp->txRingMask - entry + 1) * TX_BUFF_SZ; memcpy_toio(lp->tx_memcpy[entry], skb->data, len); memcpy_toio(lp->tx_memcpy[0], skb->data + len, skb->len - len); } else { /* linear buffer */ memcpy_toio(lp->tx_memcpy[entry], skb->data, skb->len); } /* set up the buffer descriptors */ len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; for (i = entry; i != end; i = (++i) & lp->txRingMask) { /* clean out flags */ writel(readl(&lp->tx_ring[i].base) & ~T_FLAGS, &lp->tx_ring[i].base); writew(0x0000, &lp->tx_ring[i].misc); /* clears other error flags */ writew(-TX_BUFF_SZ, &lp->tx_ring[i].length);/* packet length in buffer */ len -= TX_BUFF_SZ; } /* clean out flags */ writel(readl(&lp->tx_ring[end].base) & ~T_FLAGS, &lp->tx_ring[end].base); writew(0x0000, &lp->tx_ring[end].misc); /* clears other error flags */ writew(-len, &lp->tx_ring[end].length); /* packet length in last buff */ /* start of packet */ writel(readl(&lp->tx_ring[entry].base) | T_STP, &lp->tx_ring[entry].base); /* end of packet */ writel(readl(&lp->tx_ring[end].base) | T_ENP, &lp->tx_ring[end].base); for (i=end; i!=entry; --i) { /* ownership of packet */ writel(readl(&lp->tx_ring[i].base) | T_OWN, &lp->tx_ring[i].base); if (i == 0) i=lp->txRingMask+1; } writel(readl(&lp->tx_ring[entry].base) | T_OWN, &lp->tx_ring[entry].base); lp->tx_new = (++end) & lp->txRingMask; /* update current pointers */ } else { status = -1; } return status;}/*** Look for a particular board name in the EISA configuration space*/__initfunc(static intEISA_signature(char *name, s32 eisa_id)){ u_int i; const char *signatures[] = DEPCA_SIGNATURE; char ManCode[DEPCA_STRLEN]; union { s32 ID; char Id[4]; } Eisa; int status = 0; *name = '\0'; Eisa.ID = inl(eisa_id); 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;}static void depca_dbg_open(struct device *dev){ struct depca_private *lp = (struct depca_private *)dev->priv; u_long ioaddr = dev->base_addr; struct depca_init *p = (struct depca_init *)lp->sh_mem; int i; if (depca_debug > 1){ /* Copy the shadow init_block to shared memory */ memcpy_toio((char *)lp->sh_mem,&lp->init_block,sizeof(struct depca_init)); printk("%s: depca open with irq %d\n",dev->name,dev->irq); printk("Descriptor head addresses:\n"); printk("\t0x%lx 0x%lx\n",(u_long)lp->rx_ring, (u_long)lp->tx_ring); printk("Descriptor addresses:\nRX: "); for (i=0;i<lp->rxRingMask;i++){ if (i < 3) { printk("0x%8.8lx ", (long) &lp->rx_ring[i].base); } } printk("...0x%8.8lx\n", (long) &lp->rx_ring[i].base); printk("TX: "); for (i=0;i<lp->txRingMask;i++){ if (i < 3) { printk("0x%8.8lx ", (long) &lp->tx_ring[i].base); } } printk("...0x%8.8lx\n", (long) &lp->tx_ring[i].base); printk("\nDescriptor buffers:\nRX: "); for (i=0;i<lp->rxRingMask;i++){ if (i < 3) { printk("0x%8.8x ", readl(&lp->rx_ring[i].base)); } } printk("...0x%8.8x\n", readl(&lp->rx_ring[i].base)); printk("TX: "); for (i=0;i<lp->txRingMask;i++){ if (i < 3) { printk("0x%8.8x ", readl(&lp->tx_ring[i].base)); } } printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base)); printk("Initialisation block at 0x%8.8lx\n",lp->sh_mem); printk("\tmode: 0x%4.4x\n",readw(&p->mode)); printk("\tphysical address: "); for (i=0;i<ETH_ALEN-1;i++){ printk("%2.2x:",(u_char)readb(&p->phys_addr[i])); } printk("%2.2x\n",(u_char)readb(&p->phys_addr[i])); printk("\tmulticast hash table: "); for (i=0;i<(HASH_TABLE_LEN >> 3)-1;i++){ printk("%2.2x:",(u_char)readb(&p->mcast_table[i])); } printk("%2.2x\n",(u_char)readb(&p->mcast_table[i])); printk("\trx_ring at: 0x%8.8x\n",readl(&p->rx_ring)); printk("\ttx_ring at: 0x%8.8x\n",readl(&p->tx_ring)); printk("dma_buffs: 0x%8.8lx\n",lp->dma_buffs); printk("Ring size:\nRX: %d Log2(rxRingMask): 0x%8.8x\n", (int)lp->rxRingMask + 1, lp->rx_rlen); printk("TX: %d Log2(txRingMask): 0x%8.8x\n", (int)lp->txRingMask + 1, lp->tx_rlen); outw(CSR2,DEPCA_ADDR); printk("CSR2&1: 0x%4.4x",inw(DEPCA_DATA)); outw(CSR1,DEPCA_ADDR); printk("%4.4x\n",inw(DEPCA_DATA)); outw(CSR3,DEPCA_ADDR); printk("CSR3: 0x%4.4x\n",inw(DEPCA_DATA)); } return;}/*** Perform IOCTL call functions here. Some are privileged operations and the** effective uid is checked in those cases.** All multicast IOCTLs will not work here and are for testing purposes only.*/static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd){ struct depca_private *lp = (struct depca_private *)dev->priv; struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_data; int i, status = 0; u_long ioaddr = dev->base_addr; union { u8 addr[(HASH_TABLE_LEN * ETH_ALEN)]; u16 sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1]; u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2]; } tmp; switch(ioc->cmd) { case DEPCA_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 (verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len)) return -EFAULT; copy_to_user(ioc->data, tmp.addr, ioc->len); break; case DEPCA_SET_HWADDR: /* Set the hardware address */ if (!capable(CAP_NET_ADMIN)) return -EPERM; if (verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN)) return -EFAULT; copy_from_user(tmp.addr,ioc->data,ETH_ALEN); for (i=0; i<ETH_ALEN; i++) { dev->dev_addr[i] = tmp.addr[i]; } while(dev->tbusy) barrier(); /* Stop ring access */ test_and_set_bit(0, (void*)&dev->tbusy); while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */ STOP_DEPCA; /* Temporarily stop the depca. */ depca_init_ring(dev); /* Initialize the descriptor rings */ LoadCSRs(dev); /* Reload CSR3 */ InitRestartDepca(dev); /* Resume normal operation. */ dev->tbusy = 0; /* Unlock the TX ring */ break; case DEPCA_SET_PROM: /* Set Promiscuous Mode */ if (!capable(CAP_NET_ADMIN)) return -EPERM; while(dev->tbusy) barrier(); /* Stop ring access */ test_and_set_bit(0, (void*)&dev->tbusy); while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */ STOP_DEPCA; /* Temporarily stop the depca. */ depca_init_ring(dev); /* Initialize the descriptor rings */ lp->init_block.mode |= PROM; /* Set promiscuous mode */ LoadCSRs(dev); /* Reload CSR3 */ InitRestartDepca(dev); /* Resume normal operation. */ dev->tbusy = 0; /* Unlock the TX ring */ break; case DEPCA_CLR_PROM: /* Clear Promiscuous Mode */ if (!capable(CAP_NET_ADMIN)) return -EPERM; while(dev->tbusy) barrier(); /* Stop ring access */ test_and_set_bit(0, (void*)&dev->tbusy); while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */ STOP_DEPCA; /* Temporarily stop the depca. */ depca_init_ring(dev); /* Initialize the descriptor rings */ lp->init_block.mode &= ~PROM; /* Clear promiscuous mode */ LoadCSRs(dev); /* Reload CSR3 */ InitRestartDepca(dev); /* Resume normal operation. */ dev->tbusy = 0; /* Unlock the TX ring */ break; case DEPCA_SAY_BOO: /* Say "Boo!" to the kernel log file */ printk("%s: Boo!\n", dev->name); break; case DEPCA_GET_MCA: /* Get the multicast address table */ ioc->len = (HASH_TABLE_LEN >> 3); if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT; copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len); break; case DEPCA_SET_MCA: /* Set a multicast address */ if (!capable(CAP_NET_ADMIN)) return -EPERM; if (verify_area(VERIFY_READ, ioc->data, ETH_ALEN*ioc->len)) return -EFAULT; copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len); set_multicast_list(dev); break; case DEPCA_CLR_MCA: /* Clear all multicast addresses */ if (!capable(CAP_NET_ADMIN)) return -EPERM; set_multicast_list(dev); break; case DEPCA_MCA_EN: /* Enable pass all multicast addressing */ if (!capable(CAP_NET_ADMIN)) return -EPERM; set_multicast_list(dev); break; case DEPCA_GET_STATS: /* Get the driver statistics */ cli(); ioc->len = sizeof(lp->pktStats); if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) { status = -EFAULT; } else { copy_to_user(ioc->data, &lp->pktStats, ioc->len); } sti(); break; case DEPCA_CLR_STATS: /* Zero out the driver statistics */ if (!capable(CAP_NET_ADMIN)) return -EPERM; cli(); memset(&lp->pktStats, 0, sizeof(lp->pktStats)); sti(); break; case DEPCA_GET_REG: /* Get the DEPCA Registers */ i=0; tmp.sval[i++] = inw(DEPCA_NICSR); outw(CSR0, DEPCA_ADDR); /* status register */ tmp.sval[i++] = inw(DEPCA_DATA); memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init)); ioc->len = i+sizeof(struct depca_init); if (verify_area(VERIFY_WRITE, ioc->data, ioc->len)) return -EFAULT; copy_to_user(ioc->data, tmp.addr, ioc->len); break; default: return -EOPNOTSUPP; } return status;}#ifdef MODULEstatic char devicename[9] = {0,};static struct device thisDepca = { devicename, /* device name is inserted by /linux/drivers/net/net_init.c */ 0, 0, 0, 0, 0x200, 7, /* I/O address, IRQ */ 0, 0, 0, NULL, depca_pro
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -