📄 sdla.c
字号:
flp = slave->priv; for(i=0;i<CONFIG_DLCI_MAX;i++) { if (!flp->master[i]) break; if (abs(flp->dlci[i]) == *(short *)(master->dev_addr)) return(-EADDRINUSE); } if (i == CONFIG_DLCI_MAX) return(-EMLINK); /* #### Alan: Comments on this ?? */ flp->master[i] = master; flp->dlci[i] = -*(short *)(master->dev_addr); master->mtu = slave->mtu; if (netif_running(slave)) { if (flp->config.station == FRAD_STATION_CPE) sdla_reconfig(slave); else sdla_cmd(slave, SDLA_ADD_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL); } return(0);}int sdla_deassoc(struct net_device *slave, struct net_device *master){ struct frad_local *flp; int i; flp = slave->priv; for(i=0;i<CONFIG_DLCI_MAX;i++) if (flp->master[i] == master) break; if (i == CONFIG_DLCI_MAX) return(-ENODEV); flp->master[i] = NULL; flp->dlci[i] = 0; if (netif_running(slave)) { if (flp->config.station == FRAD_STATION_CPE) sdla_reconfig(slave); else sdla_cmd(slave, SDLA_DELETE_DLCI, 0, 0, master->dev_addr, sizeof(short), NULL, NULL); } return(0);}int sdla_dlci_conf(struct net_device *slave, struct net_device *master, int get){ struct frad_local *flp; struct dlci_local *dlp; int i; short len, ret; flp = slave->priv; for(i=0;i<CONFIG_DLCI_MAX;i++) if (flp->master[i] == master) break; if (i == CONFIG_DLCI_MAX) return(-ENODEV); dlp = master->priv; ret = SDLA_RET_OK; len = sizeof(struct dlci_conf); if (netif_running(slave)) { if (get) ret = sdla_cmd(slave, SDLA_READ_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0, NULL, 0, &dlp->config, &len); else ret = sdla_cmd(slave, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0, &dlp->config, sizeof(struct dlci_conf) - 4 * sizeof(short), NULL, NULL); } return(ret == SDLA_RET_OK ? 0 : -EIO);}/************************** * * now for the Linux driver * **************************//* NOTE: the DLCI driver deals with freeing the SKB!! */static int sdla_transmit(struct sk_buff *skb, struct net_device *dev){ struct frad_local *flp; int ret, addr, accept, i; short size; unsigned long flags; struct buf_entry *pbuf; flp = dev->priv; ret = 0; accept = 1; netif_stop_queue(dev); /* * stupid GateD insists on setting up the multicast router thru us * and we're ill equipped to handle a non Frame Relay packet at this * time! */ accept = 1; switch (dev->type) { case ARPHRD_FRAD: if (skb->dev->type != ARPHRD_DLCI) { printk(KERN_WARNING "%s: Non DLCI device, type %i, tried to send on FRAD module.\n", dev->name, skb->dev->type); accept = 0; } break; default: printk(KERN_WARNING "%s: unknown firmware type 0x%4.4X\n", dev->name, dev->type); accept = 0; break; } if (accept) { /* this is frame specific, but till there's a PPP module, it's the default */ switch (flp->type) { case SDLA_S502A: case SDLA_S502E: ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, skb->data, skb->len, NULL, NULL); break; case SDLA_S508: size = sizeof(addr); ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, NULL, skb->len, &addr, &size); if (ret == SDLA_RET_OK) { spin_lock_irqsave(&sdla_lock, flags); SDLA_WINDOW(dev, addr); pbuf = (void *)(((int) dev->mem_start) + (addr & SDLA_ADDR_MASK)); __sdla_write(dev, pbuf->buf_addr, skb->data, skb->len); SDLA_WINDOW(dev, addr); pbuf->opp_flag = 1; spin_unlock_irqrestore(&sdla_lock, flags); } break; } switch (ret) { case SDLA_RET_OK: flp->stats.tx_packets++; ret = DLCI_RET_OK; break; case SDLA_RET_CIR_OVERFLOW: case SDLA_RET_BUF_OVERSIZE: case SDLA_RET_NO_BUFS: flp->stats.tx_dropped++; ret = DLCI_RET_DROP; break; default: flp->stats.tx_errors++; ret = DLCI_RET_ERR; break; } } netif_wake_queue(dev); for(i=0;i<CONFIG_DLCI_MAX;i++) { if(flp->master[i]!=NULL) netif_wake_queue(flp->master[i]); } return(ret);}static void sdla_receive(struct net_device *dev){ struct net_device *master; struct frad_local *flp; struct dlci_local *dlp; struct sk_buff *skb; struct sdla_cmd *cmd; struct buf_info *pbufi; struct buf_entry *pbuf; unsigned long flags; int i=0, received, success, addr, buf_base, buf_top; short dlci, len, len2, split; flp = dev->priv; success = 1; received = addr = buf_top = buf_base = 0; len = dlci = 0; skb = NULL; master = NULL; cmd = NULL; pbufi = NULL; pbuf = NULL; spin_lock_irqsave(&sdla_lock, flags); switch (flp->type) { case SDLA_S502A: case SDLA_S502E: cmd = (void *) (dev->mem_start + (SDLA_502_RCV_BUF & SDLA_ADDR_MASK)); SDLA_WINDOW(dev, SDLA_502_RCV_BUF); success = cmd->opp_flag; if (!success) break; dlci = cmd->dlci; len = cmd->length; break; case SDLA_S508: pbufi = (void *) (dev->mem_start + (SDLA_508_RXBUF_INFO & SDLA_ADDR_MASK)); SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO); pbuf = (void *) (dev->mem_start + ((pbufi->rse_base + flp->buffer * sizeof(struct buf_entry)) & SDLA_ADDR_MASK)); success = pbuf->opp_flag; if (!success) break; buf_top = pbufi->buf_top; buf_base = pbufi->buf_base; dlci = pbuf->dlci; len = pbuf->length; addr = pbuf->buf_addr; break; } /* common code, find the DLCI and get the SKB */ if (success) { for (i=0;i<CONFIG_DLCI_MAX;i++) if (flp->dlci[i] == dlci) break; if (i == CONFIG_DLCI_MAX) { printk(KERN_NOTICE "%s: Received packet from invalid DLCI %i, ignoring.", dev->name, dlci); flp->stats.rx_errors++; success = 0; } } if (success) { master = flp->master[i]; skb = dev_alloc_skb(len + sizeof(struct frhdr)); if (skb == NULL) { printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); flp->stats.rx_dropped++; success = 0; } else skb_reserve(skb, sizeof(struct frhdr)); } /* pick up the data */ switch (flp->type) { case SDLA_S502A: case SDLA_S502E: if (success) __sdla_read(dev, SDLA_502_RCV_BUF + SDLA_502_DATA_OFS, skb_put(skb,len), len); SDLA_WINDOW(dev, SDLA_502_RCV_BUF); cmd->opp_flag = 0; break; case SDLA_S508: if (success) { /* is this buffer split off the end of the internal ring buffer */ split = addr + len > buf_top + 1 ? len - (buf_top - addr + 1) : 0; len2 = len - split; __sdla_read(dev, addr, skb_put(skb, len2), len2); if (split) __sdla_read(dev, buf_base, skb_put(skb, split), split); } /* increment the buffer we're looking at */ SDLA_WINDOW(dev, SDLA_508_RXBUF_INFO); flp->buffer = (flp->buffer + 1) % pbufi->rse_num; pbuf->opp_flag = 0; break; } if (success) { flp->stats.rx_packets++; dlp = master->priv; (*dlp->receive)(skb, master); } spin_unlock_irqrestore(&sdla_lock, flags);}static irqreturn_t sdla_isr(int irq, void *dev_id, struct pt_regs * regs){ struct net_device *dev; struct frad_local *flp; char byte; dev = dev_id; if (dev == NULL) { printk(KERN_WARNING "sdla_isr(): irq %d for unknown device.\n", irq); return IRQ_NONE; } flp = dev->priv; if (!flp->initialized) { printk(KERN_WARNING "%s: irq %d for uninitialized device.\n", dev->name, irq); return IRQ_NONE; } byte = sdla_byte(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE); switch (byte) { case SDLA_INTR_RX: sdla_receive(dev); break; /* the command will get an error return, which is processed above */ case SDLA_INTR_MODEM: case SDLA_INTR_STATUS: sdla_cmd(dev, SDLA_READ_DLC_STATUS, 0, 0, NULL, 0, NULL, NULL); break; case SDLA_INTR_TX: case SDLA_INTR_COMPLETE: case SDLA_INTR_TIMER: printk(KERN_WARNING "%s: invalid irq flag 0x%02X.\n", dev->name, byte); break; } /* the S502E requires a manual acknowledgement of the interrupt */ if (flp->type == SDLA_S502E) { flp->state &= ~SDLA_S502E_INTACK; outb(flp->state, dev->base_addr + SDLA_REG_CONTROL); flp->state |= SDLA_S502E_INTACK; outb(flp->state, dev->base_addr + SDLA_REG_CONTROL); } /* this clears the byte, informing the Z80 we're done */ byte = 0; sdla_write(dev, flp->type == SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte)); return IRQ_HANDLED;}static void sdla_poll(unsigned long device){ struct net_device *dev; struct frad_local *flp; dev = (struct net_device *) device; flp = dev->priv; if (sdla_byte(dev, SDLA_502_RCV_BUF)) sdla_receive(dev); flp->timer.expires = 1; add_timer(&flp->timer);}static int sdla_close(struct net_device *dev){ struct frad_local *flp; struct intr_info intr; int len, i; short dlcis[CONFIG_DLCI_MAX]; flp = dev->priv; len = 0; for(i=0;i<CONFIG_DLCI_MAX;i++) if (flp->dlci[i]) dlcis[len++] = abs(flp->dlci[i]); len *= 2; if (flp->config.station == FRAD_STATION_NODE) { for(i=0;i<CONFIG_DLCI_MAX;i++) if (flp->dlci[i] > 0) sdla_cmd(dev, SDLA_DEACTIVATE_DLCI, 0, 0, dlcis, len, NULL, NULL); sdla_cmd(dev, SDLA_DELETE_DLCI, 0, 0, &flp->dlci[i], sizeof(flp->dlci[i]), NULL, NULL); } memset(&intr, 0, sizeof(intr)); /* let's start up the reception */ switch(flp->type) { case SDLA_S502A: del_timer(&flp->timer); break; case SDLA_S502E: sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(char) + sizeof(short), NULL, NULL); flp->state &= ~SDLA_S502E_INTACK; outb(flp->state, dev->base_addr + SDLA_REG_CONTROL); break; case SDLA_S507: break; case SDLA_S508: sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(struct intr_info), NULL, NULL); flp->state &= ~SDLA_S508_INTEN; outb(flp->state, dev->base_addr + SDLA_REG_CONTROL); break; } sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL); netif_stop_queue(dev); return(0);}struct conf_data { struct frad_conf config; short dlci[CONFIG_DLCI_MAX];};static int sdla_open(struct net_device *dev){ struct frad_local *flp; struct dlci_local *dlp; struct conf_data data; struct intr_info intr; int len, i; char byte; flp = dev->priv; if (!flp->initialized) return(-EPERM); if (!flp->configured) return(-EPERM); /* time to send in the configuration */ len = 0; for(i=0;i<CONFIG_DLCI_MAX;i++) if (flp->dlci[i]) data.dlci[len++] = abs(flp->dlci[i]); len *= 2; memcpy(&data.config, &flp->config, sizeof(struct frad_conf)); len += sizeof(struct frad_conf); sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL); sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, 0, 0, &data, len, NULL, NULL); if (flp->type == SDLA_S508) flp->buffer = 0; sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL); /* let's start up the reception */ memset(&intr, 0, sizeof(intr)); switch(flp->type) { case SDLA_S502A: flp->timer.expires = 1; add_timer(&flp->timer); break; case SDLA_S502E: flp->state |= SDLA_S502E_ENABLE; outb(flp->state, dev->base_addr + SDLA_REG_CONTROL); flp->state |= SDLA_S502E_INTACK; outb(flp->state, dev->base_addr + SDLA_REG_CONTROL); byte = 0; sdla_write(dev, SDLA_502_IRQ_INTERFACE, &byte, sizeof(byte)); intr.flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM; sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(char) + sizeof(short), NULL, NULL); break; case SDLA_S507: break; case SDLA_S508: flp->state |= SDLA_S508_INTEN; outb(flp->state, dev->base_addr + SDLA_REG_CONTROL); byte = 0; sdla_write(dev, SDLA_508_IRQ_INTERFACE, &byte, sizeof(byte)); intr.flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM; intr.irq = dev->irq; sdla_cmd(dev, SDLA_SET_IRQ_TRIGGER, 0, 0, &intr, sizeof(struct intr_info), NULL, NULL); break; } if (flp->config.station == FRAD_STATION_CPE) { byte = SDLA_ICS_STATUS_ENQ; sdla_cmd(dev, SDLA_ISSUE_IN_CHANNEL_SIGNAL, 0, 0, &byte, sizeof(byte), NULL, NULL); } else { sdla_cmd(dev, SDLA_ADD_DLCI, 0, 0, data.dlci, len - sizeof(struct frad_conf), NULL, NULL); for(i=0;i<CONFIG_DLCI_MAX;i++) if (flp->dlci[i] > 0) sdla_cmd(dev, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], 2*sizeof(flp->dlci[i]), NULL, NULL); } /* configure any specific DLCI settings */ for(i=0;i<CONFIG_DLCI_MAX;i++) if (flp->dlci[i]) { dlp = flp->master[i]->priv; if (dlp->configured) sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0, &dlp->config, sizeof(struct dlci_conf), NULL, NULL); } netif_start_queue(dev); return(0);}static int sdla_config(struct net_device *dev, struct frad_conf __user *conf, int get){ struct frad_local *flp; struct conf_data data; int i; short size; if (dev->type == 0xFFFF) return(-EUNATCH); flp = dev->priv; if (!get) { if (netif_running(dev)) return(-EBUSY); if(copy_from_user(&data.config, conf, sizeof(struct frad_conf))) return -EFAULT; if (data.config.station & ~FRAD_STATION_NODE)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -