📄 cops.c
字号:
if(board==DAYNA) printk("%s: %s at %#3x, using IRQ %d, in Dayna mode.\n", dev->name, cardname, ioaddr, dev->irq); if(board==TANGENT) { if(dev->irq) printk("%s: %s at %#3x, IRQ %d, in Tangent mode\n", dev->name, cardname, ioaddr, dev->irq); else printk("%s: %s at %#3x, using polled IO, in Tangent mode.\n", dev->name, cardname, ioaddr); } return 0;err_out: release_region(ioaddr, COPS_IO_EXTENT); return retval;}static int __init cops_irq (int ioaddr, int board){ /* * This does not use the IRQ to determine where the IRQ is. We just * assume that when we get a correct status response that it's the IRQ. * This really just verifies the IO port but since we only have access * to such a small number of IRQs (5, 4, 3) this is not bad. * This will probably not work for more than one card. */ int irqaddr=0; int i, x, status; if(board==DAYNA) { outb(0, ioaddr+DAYNA_RESET); inb(ioaddr+DAYNA_RESET); mdelay(333); } if(board==TANGENT) { inb(ioaddr); outb(0, ioaddr); outb(0, ioaddr+TANG_RESET); } for(i=0; cops_irqlist[i] !=0; i++) { irqaddr = cops_irqlist[i]; for(x = 0xFFFF; x>0; x --) /* wait for response */ { if(board==DAYNA) { status = (inb(ioaddr+DAYNA_CARD_STATUS)&3); if(status == 1) return irqaddr; } if(board==TANGENT) { if((inb(ioaddr+TANG_CARD_STATUS)& TANG_TX_READY) !=0) return irqaddr; } } } return 0; /* no IRQ found */}/* * Open/initialize the board. This is called (in the current kernel) * sometime after booting when the 'ifconfig' program is run. */static int cops_open(struct net_device *dev){ struct cops_local *lp = netdev_priv(dev); if(dev->irq==0) { /* * I don't know if the Dayna-style boards support polled * operation. For now, only allow it for Tangent. */ if(lp->board==TANGENT) /* Poll 20 times per second */ { init_timer(&cops_timer); cops_timer.function = cops_poll; cops_timer.data = (unsigned long)dev; cops_timer.expires = jiffies + HZ/20; add_timer(&cops_timer); } else { printk(KERN_WARNING "%s: No irq line set\n", dev->name); return -EAGAIN; } } cops_jumpstart(dev); /* Start the card up. */ netif_start_queue(dev); return 0;}/* * This allows for a dynamic start/restart of the entire card. */static int cops_jumpstart(struct net_device *dev){ struct cops_local *lp = netdev_priv(dev); /* * Once the card has the firmware loaded and has acquired * the nodeid, if it is reset it will lose it all. */ cops_reset(dev,1); /* Need to reset card before load firmware. */ cops_load(dev); /* Load the firmware. */ /* * If atalkd already gave us a nodeid we will use that * one again, else we wait for atalkd to give us a nodeid * in cops_ioctl. This may cause a problem if someone steals * our nodeid while we are resetting. */ if(lp->nodeid == 1) cops_nodeid(dev,lp->node_acquire); return 0;}static void tangent_wait_reset(int ioaddr){ int timeout=0; while(timeout++ < 5 && (inb(ioaddr+TANG_CARD_STATUS)&TANG_TX_READY)==0) mdelay(1); /* Wait 1 second */}/* * Reset the LocalTalk board. */static void cops_reset(struct net_device *dev, int sleep){ struct cops_local *lp = netdev_priv(dev); int ioaddr=dev->base_addr; if(lp->board==TANGENT) { inb(ioaddr); /* Clear request latch. */ outb(0,ioaddr); /* Clear the TANG_TX_READY flop. */ outb(0, ioaddr+TANG_RESET); /* Reset the adapter. */ tangent_wait_reset(ioaddr); outb(0, ioaddr+TANG_CLEAR_INT); } if(lp->board==DAYNA) { outb(0, ioaddr+DAYNA_RESET); /* Assert the reset port */ inb(ioaddr+DAYNA_RESET); /* Clear the reset */ if(sleep) { long snap=jiffies; /* Let card finish initializing, about 1/3 second */ while(jiffies-snap<HZ/3) schedule(); } else mdelay(333); } netif_wake_queue(dev); return;}static void cops_load (struct net_device *dev){ struct ifreq ifr; struct ltfirmware *ltf= (struct ltfirmware *)&ifr.ifr_ifru; struct cops_local *lp = netdev_priv(dev); int ioaddr=dev->base_addr; int length, i = 0; strcpy(ifr.ifr_name,"lt0"); /* Get card's firmware code and do some checks on it. */#ifdef CONFIG_COPS_DAYNA if(lp->board==DAYNA) { ltf->length=sizeof(ffdrv_code); ltf->data=ffdrv_code; } else#endif #ifdef CONFIG_COPS_TANGENT if(lp->board==TANGENT) { ltf->length=sizeof(ltdrv_code); ltf->data=ltdrv_code; } else#endif { printk(KERN_INFO "%s; unsupported board type.\n", dev->name); return; } /* Check to make sure firmware is correct length. */ if(lp->board==DAYNA && ltf->length!=5983) { printk(KERN_WARNING "%s: Firmware is not length of FFDRV.BIN.\n", dev->name); return; } if(lp->board==TANGENT && ltf->length!=2501) { printk(KERN_WARNING "%s: Firmware is not length of DRVCODE.BIN.\n", dev->name); return; } if(lp->board==DAYNA) { /* * We must wait for a status response * with the DAYNA board. */ while(++i<65536) { if((inb(ioaddr+DAYNA_CARD_STATUS)&3)==1) break; } if(i==65536) return; } /* * Upload the firmware and kick. Byte-by-byte works nicely here. */ i=0; length = ltf->length; while(length--) { outb(ltf->data[i], ioaddr); i++; } if(cops_debug > 1) printk("%s: Uploaded firmware - %d bytes of %d bytes.\n", dev->name, i, ltf->length); if(lp->board==DAYNA) /* Tell Dayna to run the firmware code. */ outb(1, ioaddr+DAYNA_INT_CARD); else /* Tell Tang to run the firmware code. */ inb(ioaddr); if(lp->board==TANGENT) { tangent_wait_reset(ioaddr); inb(ioaddr); /* Clear initial ready signal. */ } return;}/* * Get the LocalTalk Nodeid from the card. We can suggest * any nodeid 1-254. The card will try and get that exact * address else we can specify 0 as the nodeid and the card * will autoprobe for a nodeid. */static int cops_nodeid (struct net_device *dev, int nodeid){ struct cops_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; if(lp->board == DAYNA) { /* Empty any pending adapter responses. */ while((inb(ioaddr+DAYNA_CARD_STATUS)&DAYNA_TX_READY)==0) { outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupts. */ if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST) cops_rx(dev); /* Kick any packets waiting. */ schedule(); } outb(2, ioaddr); /* Output command packet length as 2. */ outb(0, ioaddr); outb(LAP_INIT, ioaddr); /* Send LAP_INIT command byte. */ outb(nodeid, ioaddr); /* Suggest node address. */ } if(lp->board == TANGENT) { /* Empty any pending adapter responses. */ while(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY) { outb(0, ioaddr+COPS_CLEAR_INT); /* Clear interrupt. */ cops_rx(dev); /* Kick out packets waiting. */ schedule(); } /* Not sure what Tangent does if nodeid picked is used. */ if(nodeid == 0) /* Seed. */ nodeid = jiffies&0xFF; /* Get a random try */ outb(2, ioaddr); /* Command length LSB */ outb(0, ioaddr); /* Command length MSB */ outb(LAP_INIT, ioaddr); /* Send LAP_INIT byte */ outb(nodeid, ioaddr); /* LAP address hint. */ outb(0xFF, ioaddr); /* Int. level to use */ } lp->node_acquire=0; /* Set nodeid holder to 0. */ while(lp->node_acquire==0) /* Get *True* nodeid finally. */ { outb(0, ioaddr+COPS_CLEAR_INT); /* Clear any interrupt. */ if(lp->board == DAYNA) { if((inb(ioaddr+DAYNA_CARD_STATUS)&0x03)==DAYNA_RX_REQUEST) cops_rx(dev); /* Grab the nodeid put in lp->node_acquire. */ } if(lp->board == TANGENT) { if(inb(ioaddr+TANG_CARD_STATUS)&TANG_RX_READY) cops_rx(dev); /* Grab the nodeid put in lp->node_acquire. */ } schedule(); } if(cops_debug > 1) printk(KERN_DEBUG "%s: Node ID %d has been acquired.\n", dev->name, lp->node_acquire); lp->nodeid=1; /* Set got nodeid to 1. */ return 0;}/* * Poll the Tangent type cards to see if we have work. */ static void cops_poll(unsigned long ltdev){ int ioaddr, status; int boguscount = 0; struct net_device *dev = (struct net_device *)ltdev; del_timer(&cops_timer); if(dev == NULL) return; /* We've been downed */ ioaddr = dev->base_addr; do { status=inb(ioaddr+TANG_CARD_STATUS); if(status & TANG_RX_READY) cops_rx(dev);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -