📄 scc.c
字号:
grp1 = scc->kiss.group; for (k = 0; k < (Nchips * 2); k++) { scc2 = &SCC_Info[k]; grp2 = scc2->kiss.group; if (scc2 == scc || !(scc2->dev && grp2)) continue; if ((grp1 & 0x3f) == (grp2 & 0x3f)) { if ( (grp1 & TXGROUP) && (scc2->wreg[R5] & RTS) ) return 1; if ( (grp1 & RXGROUP) && scc2->dcd ) return 1; } } return 0;}/* DWAIT and SLOTTIME expired * * fulldup == 0: DCD is active or Rand > P-persistence: start t_busy timer * else key trx and start txdelay * fulldup == 1: key trx and start txdelay * fulldup == 2: mintime expired, reset status or key trx and start txdelay */static void t_dwait(unsigned long channel){ struct scc_channel *scc = (struct scc_channel *) channel; if (scc->stat.tx_state == TXS_WAIT) /* maxkeyup or idle timeout */ { if (skb_queue_len(&scc->tx_queue) == 0) /* nothing to send */ { scc->stat.tx_state = TXS_IDLE; netif_wake_queue(scc->dev); /* t_maxkeyup locked it. */ return; } scc->stat.tx_state = TXS_BUSY; } if (scc->kiss.fulldup == KISS_DUPLEX_HALF) { Rand = Rand * 17 + 31; if (scc->dcd || (scc->kiss.persist) < Rand || (scc->kiss.group && is_grouped(scc)) ) { scc_start_defer(scc); scc_start_tx_timer(scc, t_dwait, scc->kiss.slottime); return ; } } if ( !(scc->wreg[R5] & RTS) ) { scc_key_trx(scc, TX_ON); scc_start_tx_timer(scc, t_txdelay, scc->kiss.txdelay); } else { scc_start_tx_timer(scc, t_txdelay, 0); }}/* TXDELAY expired * * kick transmission by a fake scc_txint(scc), start 'maxkeyup' watchdog. */static void t_txdelay(unsigned long channel){ struct scc_channel *scc = (struct scc_channel *) channel; scc_start_maxkeyup(scc); if (scc->tx_buff == NULL) { disable_irq(scc->irq); scc_txint(scc); enable_irq(scc->irq); }} /* TAILTIME expired * * switch off transmitter. If we were stopped by Maxkeyup restart * transmission after 'mintime' seconds */static void t_tail(unsigned long channel){ struct scc_channel *scc = (struct scc_channel *) channel; unsigned long flags; save_flags(flags); cli(); del_timer(&scc->tx_wdog); scc_key_trx(scc, TX_OFF); restore_flags(flags); if (scc->stat.tx_state == TXS_TIMEOUT) /* we had a timeout? */ { scc->stat.tx_state = TXS_WAIT; if (scc->kiss.mintime != TIMER_OFF) /* try it again */ scc_start_tx_timer(scc, t_dwait, scc->kiss.mintime*100); else scc_start_tx_timer(scc, t_dwait, 0); return; } scc->stat.tx_state = TXS_IDLE; netif_wake_queue(scc->dev);}/* BUSY timeout * * throw away send buffers if DCD remains active too long. */static void t_busy(unsigned long channel){ struct scc_channel *scc = (struct scc_channel *) channel; del_timer(&scc->tx_t); netif_stop_queue(scc->dev); /* don't pile on the wabbit! */ scc_discard_buffers(scc); scc->stat.txerrs++; scc->stat.tx_state = TXS_IDLE; netif_wake_queue(scc->dev); }/* MAXKEYUP timeout * * this is our watchdog. */static void t_maxkeyup(unsigned long channel){ struct scc_channel *scc = (struct scc_channel *) channel; unsigned long flags; save_flags(flags); cli(); /* * let things settle down before we start to * accept new data. */ netif_stop_queue(scc->dev); scc_discard_buffers(scc); del_timer(&scc->tx_t); cl(scc, R1, TxINT_ENAB); /* force an ABORT, but don't */ cl(scc, R15, TxUIE); /* count it. */ OutReg(scc->ctrl, R0, RES_Tx_P); restore_flags(flags); scc->stat.txerrs++; scc->stat.tx_state = TXS_TIMEOUT; scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime);}/* IDLE timeout * * in fulldup mode 2 it keys down the transmitter after 'idle' seconds * of inactivity. We will not restart transmission before 'mintime' * expires. */static void t_idle(unsigned long channel){ struct scc_channel *scc = (struct scc_channel *) channel; del_timer(&scc->tx_wdog); scc_key_trx(scc, TX_OFF); if (scc->kiss.mintime != TIMER_OFF) scc_start_tx_timer(scc, t_dwait, scc->kiss.mintime*100); scc->stat.tx_state = TXS_WAIT;}static void scc_init_timer(struct scc_channel *scc){ unsigned long flags; save_flags(flags); cli(); scc->stat.tx_state = TXS_IDLE; restore_flags(flags);}/* ******************************************************************** *//* * Set/get L1 parameters * *//* ******************************************************************** *//* * this will set the "hardware" parameters through KISS commands or ioctl() */#define CAST(x) (unsigned long)(x)static unsigned int scc_set_param(struct scc_channel *scc, unsigned int cmd, unsigned int arg){ switch (cmd) { case PARAM_TXDELAY: scc->kiss.txdelay=arg; break; case PARAM_PERSIST: scc->kiss.persist=arg; break; case PARAM_SLOTTIME: scc->kiss.slottime=arg; break; case PARAM_TXTAIL: scc->kiss.tailtime=arg; break; case PARAM_FULLDUP: scc->kiss.fulldup=arg; break; case PARAM_DTR: break; /* does someone need this? */ case PARAM_GROUP: scc->kiss.group=arg; break; case PARAM_IDLE: scc->kiss.idletime=arg; break; case PARAM_MIN: scc->kiss.mintime=arg; break; case PARAM_MAXKEY: scc->kiss.maxkeyup=arg; break; case PARAM_WAIT: scc->kiss.waittime=arg; break; case PARAM_MAXDEFER: scc->kiss.maxdefer=arg; break; case PARAM_TX: scc->kiss.tx_inhibit=arg; break; case PARAM_SOFTDCD: scc->kiss.softdcd=arg; if (arg) { or(scc, R15, SYNCIE); cl(scc, R15, DCDIE); start_hunt(scc); } else { or(scc, R15, DCDIE); cl(scc, R15, SYNCIE); } break; case PARAM_SPEED: if (arg < 256) scc->modem.speed=arg*100; else scc->modem.speed=arg; if (scc->stat.tx_state == 0) /* only switch baudrate on rx... ;-) */ set_speed(scc); break; case PARAM_RTS: if ( !(scc->wreg[R5] & RTS) ) { if (arg != TX_OFF) scc_key_trx(scc, TX_ON); scc_start_tx_timer(scc, t_txdelay, scc->kiss.txdelay); } else { if (arg == TX_OFF) { scc->stat.tx_state = TXS_BUSY; scc_start_tx_timer(scc, t_tail, scc->kiss.tailtime); } } break; case PARAM_HWEVENT: scc_notify(scc, scc->dcd? HWEV_DCD_ON:HWEV_DCD_OFF); break; default: return -EINVAL; } return 0;} static unsigned long scc_get_param(struct scc_channel *scc, unsigned int cmd){ switch (cmd) { case PARAM_TXDELAY: return CAST(scc->kiss.txdelay); case PARAM_PERSIST: return CAST(scc->kiss.persist); case PARAM_SLOTTIME: return CAST(scc->kiss.slottime); case PARAM_TXTAIL: return CAST(scc->kiss.tailtime); case PARAM_FULLDUP: return CAST(scc->kiss.fulldup); case PARAM_SOFTDCD: return CAST(scc->kiss.softdcd); case PARAM_DTR: return CAST((scc->wreg[R5] & DTR)? 1:0); case PARAM_RTS: return CAST((scc->wreg[R5] & RTS)? 1:0); case PARAM_SPEED: return CAST(scc->modem.speed); case PARAM_GROUP: return CAST(scc->kiss.group); case PARAM_IDLE: return CAST(scc->kiss.idletime); case PARAM_MIN: return CAST(scc->kiss.mintime); case PARAM_MAXKEY: return CAST(scc->kiss.maxkeyup); case PARAM_WAIT: return CAST(scc->kiss.waittime); case PARAM_MAXDEFER: return CAST(scc->kiss.maxdefer); case PARAM_TX: return CAST(scc->kiss.tx_inhibit); default: return NO_SUCH_PARAM; }}#undef CAST/* ******************************************************************* *//* * Send calibration pattern * *//* ******************************************************************* */static void scc_stop_calibrate(unsigned long channel){ struct scc_channel *scc = (struct scc_channel *) channel; unsigned long flags; save_flags(flags); cli(); del_timer(&scc->tx_wdog); scc_key_trx(scc, TX_OFF); wr(scc, R6, 0); wr(scc, R7, FLAG); Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */ Outb(scc->ctrl,RES_EXT_INT); netif_wake_queue(scc->dev); restore_flags(flags);}static voidscc_start_calibrate(struct scc_channel *scc, int duration, unsigned char pattern){ unsigned long flags; save_flags(flags); cli(); netif_stop_queue(scc->dev); scc_discard_buffers(scc); del_timer(&scc->tx_wdog); scc->tx_wdog.data = (unsigned long) scc; scc->tx_wdog.function = scc_stop_calibrate; scc->tx_wdog.expires = jiffies + HZ*duration; add_timer(&scc->tx_wdog); /* This doesn't seem to work. Why not? */ wr(scc, R6, 0); wr(scc, R7, pattern); /* * Don't know if this works. * Damn, where is my Z8530 programming manual...? */ Outb(scc->ctrl,RES_EXT_INT); /* reset ext/status interrupts */ Outb(scc->ctrl,RES_EXT_INT); scc_key_trx(scc, TX_ON); restore_flags(flags);}/* ******************************************************************* *//* * Init channel structures, special HW, etc... * *//* ******************************************************************* *//* * Reset the Z8530s and setup special hardware */static void z8530_init(void){ struct scc_channel *scc; int chip, k; unsigned long flags; char *flag; printk(KERN_INFO "Init Z8530 driver: %u channels, IRQ", Nchips*2); flag=" "; for (k = 0; k < NR_IRQS; k++) if (Ivec[k].used) { printk("%s%d", flag, k); flag=","; } printk("\n"); /* reset and pre-init all chips in the system */ for (chip = 0; chip < Nchips; chip++) { scc=&SCC_Info[2*chip]; if (!scc->ctrl) continue; /* Special SCC cards */ if(scc->brand & EAGLE) /* this is an EAGLE card */ Outb(scc->special,0x08); /* enable interrupt on the board */ if(scc->brand & (PC100 | PRIMUS)) /* this is a PC100/PRIMUS card */ Outb(scc->special,scc->option); /* set the MODEM mode (0x22) */ /* Reset and pre-init Z8530 */ save_flags(flags); cli(); Outb(scc->ctrl, 0); OutReg(scc->ctrl,R9,FHWRES); /* force hardware reset */ udelay(100); /* give it 'a bit' more time than required */ wr(scc, R2, chip*16); /* interrupt vector */ wr(scc, R9, VIS); /* vector includes status */ restore_flags(flags); } Driver_Initialized = 1;}/* * Allocate device structure, err, instance, and register driver */static int scc_net_setup(struct scc_channel *scc, unsigned char *name, int addev){ struct net_device *dev; if (dev_get(name)) { printk(KERN_INFO "Z8530drv: device %s already exists.\n", name); return -EEXIST; } if ((scc->dev = (struct net_device *) kmalloc(sizeof(struct net_device), GFP_KERNEL)) == NULL) return -ENOMEM; dev = scc->dev; memset(dev, 0, sizeof(struct net_device)); strcpy(dev->name, name); dev->priv = (void *) scc; dev->init = scc_net_init; if ((addev? register_netdevice(dev) : register_netdev(dev)) != 0) { kfree(dev); return -EIO; } SET_MODULE_OWNER(dev); return 0;}/* ******************************************************************** *//* * Network driver methods * *//* ******************************************************************** */static unsigned char ax25_bcast[AX25_ADDR_LEN] ={'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};static unsigned char ax25_nocall[AX25_ADDR_LEN] ={'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};/* ----> Initialize device <----- */static int scc_net_init(struct net_device *dev){ dev->tx_queue_len = 16; /* should be enough... */ dev->open = scc_net_open; dev->stop = scc_net_close; dev->hard_start_xmit = scc_net_tx; dev->hard_header = ax25_encapsulate; dev->rebuild_header = ax25_rebuild_header; dev->set_mac_address = scc_net_set_mac_address; dev->get_stats = scc_net_get_stats; dev->do_ioctl = scc_net_ioctl; dev->tx_timeout = NULL; memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN); dev->flags = 0; dev->type = ARPHRD_AX25; dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; dev->mtu = AX25_DEF_PACLEN; dev->addr_len = AX25_ADDR_LEN; return 0;}/* ----> open network device <---- */static int scc_net_open(struct net_device *dev){ struct scc_channel *scc = (struct scc_channel *) dev->priv; if (!scc->init) return -EINVAL; scc->tx_buff = NULL; skb_queue_head_init(&scc->tx_queue); init_channel(scc); netif_start_queue(dev); return 0;}/* ----> close network device <---- */static int scc_net_close(struct net_device *dev){ struct scc_channel *scc = (struct scc_channel *) dev->priv; unsigned long flags; netif_stop_queue(dev); save_flags(flags); cli(); Outb(scc->ctrl,0); /* Make sure pointer is written */ wr(scc,R1,0); /* disable interrupts */ wr(scc,R3,0); del_timer(&scc->tx_t); del_timer(&scc->tx_wdog); restore_flags(flags);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -