📄 farsync.c
字号:
return -EINVAL; } switch (sync.clock_type) { case CLOCK_EXT: FST_WRB(card, portConfig[i].internalClock, EXTCLK); break; case CLOCK_INT: FST_WRB(card, portConfig[i].internalClock, INTCLK); break; default: return -EINVAL; } FST_WRL(card, portConfig[i].lineSpeed, sync.clock_rate); return 0;}static intfst_get_iface(struct fst_card_info *card, struct fst_port_info *port, struct ifreq *ifr){ sync_serial_settings sync; int i; /* First check what line type is set, we'll default to reporting X.21 * if nothing is set as IF_IFACE_SYNC_SERIAL implies it can't be * changed */ switch (port->hwif) { case E1: ifr->ifr_settings.type = IF_IFACE_E1; break; case T1: ifr->ifr_settings.type = IF_IFACE_T1; break; case V35: ifr->ifr_settings.type = IF_IFACE_V35; break; case V24: ifr->ifr_settings.type = IF_IFACE_V24; break; case X21D: ifr->ifr_settings.type = IF_IFACE_X21D; break; case X21: default: ifr->ifr_settings.type = IF_IFACE_X21; break; } if (ifr->ifr_settings.size == 0) { return 0; /* only type requested */ } if (ifr->ifr_settings.size < sizeof (sync)) { return -ENOMEM; } i = port->index; sync.clock_rate = FST_RDL(card, portConfig[i].lineSpeed); /* Lucky card and linux use same encoding here */ sync.clock_type = FST_RDB(card, portConfig[i].internalClock) == INTCLK ? CLOCK_INT : CLOCK_EXT; sync.loopback = 0; if (copy_to_user(ifr->ifr_settings.ifs_ifsu.sync, &sync, sizeof (sync))) { return -EFAULT; } ifr->ifr_settings.size = sizeof (sync); return 0;}static intfst_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){ struct fst_card_info *card; struct fst_port_info *port; struct fstioc_write wrthdr; struct fstioc_info info; unsigned long flags; dbg(DBG_IOCTL, "ioctl: %x, %p\n", cmd, ifr->ifr_data); port = dev_to_port(dev); card = port->card; if (!capable(CAP_NET_ADMIN)) return -EPERM; switch (cmd) { case FSTCPURESET: fst_cpureset(card); card->state = FST_RESET; return 0; case FSTCPURELEASE: fst_cpurelease(card); card->state = FST_STARTING; return 0; case FSTWRITE: /* Code write (download) */ /* First copy in the header with the length and offset of data * to write */ if (ifr->ifr_data == NULL) { return -EINVAL; } if (copy_from_user(&wrthdr, ifr->ifr_data, sizeof (struct fstioc_write))) { return -EFAULT; } /* Sanity check the parameters. We don't support partial writes * when going over the top */ if (wrthdr.size > FST_MEMSIZE || wrthdr.offset > FST_MEMSIZE || wrthdr.size + wrthdr.offset > FST_MEMSIZE) { return -ENXIO; } /* Now copy the data to the card. * This will probably break on some architectures. * I'll fix it when I have something to test on. */ if (copy_from_user(card->mem + wrthdr.offset, ifr->ifr_data + sizeof (struct fstioc_write), wrthdr.size)) { return -EFAULT; } /* Writes to the memory of a card in the reset state constitute * a download */ if (card->state == FST_RESET) { card->state = FST_DOWNLOAD; } return 0; case FSTGETCONF: /* If card has just been started check the shared memory config * version and marker */ if (card->state == FST_STARTING) { check_started_ok(card); /* If everything checked out enable card interrupts */ if (card->state == FST_RUNNING) { spin_lock_irqsave(&card->card_lock, flags); fst_enable_intr(card); FST_WRB(card, interruptHandshake, 0xEE); spin_unlock_irqrestore(&card->card_lock, flags); } } if (ifr->ifr_data == NULL) { return -EINVAL; } gather_conf_info(card, port, &info); if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) { return -EFAULT; } return 0; case FSTSETCONF: /* * Most of the settings have been moved to the generic ioctls * this just covers debug and board ident now */ if (card->state != FST_RUNNING) { printk_err ("Attempt to configure card %d in non-running state (%d)\n", card->card_no, card->state); return -EIO; } if (copy_from_user(&info, ifr->ifr_data, sizeof (info))) { return -EFAULT; } return set_conf_from_info(card, port, &info); case SIOCWANDEV: switch (ifr->ifr_settings.type) { case IF_GET_IFACE: return fst_get_iface(card, port, ifr); case IF_IFACE_SYNC_SERIAL: case IF_IFACE_V35: case IF_IFACE_V24: case IF_IFACE_X21: case IF_IFACE_X21D: case IF_IFACE_T1: case IF_IFACE_E1: return fst_set_iface(card, port, ifr); case IF_PROTO_RAW: port->mode = FST_RAW; return 0; case IF_GET_PROTO: if (port->mode == FST_RAW) { ifr->ifr_settings.type = IF_PROTO_RAW; return 0; } return hdlc_ioctl(dev, ifr, cmd); default: port->mode = FST_GEN_HDLC; dbg(DBG_IOCTL, "Passing this type to hdlc %x\n", ifr->ifr_settings.type); return hdlc_ioctl(dev, ifr, cmd); } default: /* Not one of ours. Pass through to HDLC package */ return hdlc_ioctl(dev, ifr, cmd); }}static voidfst_openport(struct fst_port_info *port){ int signals; int txq_length; /* Only init things if card is actually running. This allows open to * succeed for downloads etc. */ if (port->card->state == FST_RUNNING) { if (port->run) { dbg(DBG_OPEN, "open: found port already running\n"); fst_issue_cmd(port, STOPPORT); port->run = 0; } fst_rx_config(port); fst_tx_config(port); fst_op_raise(port, OPSTS_RTS | OPSTS_DTR); fst_issue_cmd(port, STARTPORT); port->run = 1; signals = FST_RDL(port->card, v24DebouncedSts[port->index]); if (signals & (((port->hwif == X21) || (port->hwif == X21D)) ? IPSTS_INDICATE : IPSTS_DCD)) netif_carrier_on(port_to_dev(port)); else netif_carrier_off(port_to_dev(port)); txq_length = port->txqe - port->txqs; port->txqe = 0; port->txqs = 0; }}static voidfst_closeport(struct fst_port_info *port){ if (port->card->state == FST_RUNNING) { if (port->run) { port->run = 0; fst_op_lower(port, OPSTS_RTS | OPSTS_DTR); fst_issue_cmd(port, STOPPORT); } else { dbg(DBG_OPEN, "close: port not running\n"); } }}static intfst_open(struct net_device *dev){ int err; struct fst_port_info *port; port = dev_to_port(dev); if (!try_module_get(THIS_MODULE)) return -EBUSY; if (port->mode != FST_RAW) { err = hdlc_open(dev); if (err) return err; } fst_openport(port); netif_wake_queue(dev); return 0;}static intfst_close(struct net_device *dev){ struct fst_port_info *port; struct fst_card_info *card; unsigned char tx_dma_done; unsigned char rx_dma_done; port = dev_to_port(dev); card = port->card; tx_dma_done = inb(card->pci_conf + DMACSR1); rx_dma_done = inb(card->pci_conf + DMACSR0); dbg(DBG_OPEN, "Port Close: tx_dma_in_progress = %d (%x) rx_dma_in_progress = %d (%x)\n", card->dmatx_in_progress, tx_dma_done, card->dmarx_in_progress, rx_dma_done); netif_stop_queue(dev); fst_closeport(dev_to_port(dev)); if (port->mode != FST_RAW) { hdlc_close(dev); } module_put(THIS_MODULE); return 0;}static intfst_attach(struct net_device *dev, unsigned short encoding, unsigned short parity){ /* * Setting currently fixed in FarSync card so we check and forget */ if (encoding != ENCODING_NRZ || parity != PARITY_CRC16_PR1_CCITT) return -EINVAL; return 0;}static voidfst_tx_timeout(struct net_device *dev){ struct fst_port_info *port; struct fst_card_info *card; struct net_device_stats *stats = hdlc_stats(dev); port = dev_to_port(dev); card = port->card; stats->tx_errors++; stats->tx_aborted_errors++; dbg(DBG_ASS, "Tx timeout card %d port %d\n", card->card_no, port->index); fst_issue_cmd(port, ABORTTX); dev->trans_start = jiffies; netif_wake_queue(dev); port->start = 0;}static intfst_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct fst_card_info *card; struct fst_port_info *port; struct net_device_stats *stats = hdlc_stats(dev); unsigned long flags; int txq_length; port = dev_to_port(dev); card = port->card; dbg(DBG_TX, "fst_start_xmit: length = %d\n", skb->len); /* Drop packet with error if we don't have carrier */ if (!netif_carrier_ok(dev)) { dev_kfree_skb(skb); stats->tx_errors++; stats->tx_carrier_errors++; dbg(DBG_ASS, "Tried to transmit but no carrier on card %d port %d\n", card->card_no, port->index); return 0; } /* Drop it if it's too big! MTU failure ? */ if (skb->len > LEN_TX_BUFFER) { dbg(DBG_ASS, "Packet too large %d vs %d\n", skb->len, LEN_TX_BUFFER); dev_kfree_skb(skb); stats->tx_errors++; return 0; } /* * We are always going to queue the packet * so that the bottom half is the only place we tx from * Check there is room in the port txq */ spin_lock_irqsave(&card->card_lock, flags); if ((txq_length = port->txqe - port->txqs) < 0) { /* * This is the case where the next free has wrapped but the * last used hasn't */ txq_length = txq_length + FST_TXQ_DEPTH; } spin_unlock_irqrestore(&card->card_lock, flags); if (txq_length > fst_txq_high) { /* * We have got enough buffers in the pipeline. Ask the network * layer to stop sending frames down */ netif_stop_queue(dev); port->start = 1; /* I'm using this to signal stop sent up */ } if (txq_length == FST_TXQ_DEPTH - 1) { /* * This shouldn't have happened but such is life */ dev_kfree_skb(skb); stats->tx_errors++; dbg(DBG_ASS, "Tx queue overflow card %d port %d\n", card->card_no, port->index); return 0; } /* * queue the buffer */ spin_lock_irqsave(&card->card_lock, flags); port->txq[port->txqe] = skb; port->txqe++; if (port->txqe == FST_TXQ_DEPTH) port->txqe = 0; spin_unlock_irqrestore(&card->card_lock, flags); /* Scehdule the bottom half which now does transmit processing */ fst_q_work_item(&fst_work_txq, card->card_no); tasklet_schedule(&fst_tx_task); return 0;}/* * Card setup having checked hardware resources. * Should be pretty bizarre if we get an error here (kernel memory * exhaustion is one possibility). If we do see a problem we report it * via a printk and leave the corresponding interface and all that follow * disabled. */static char *type_strings[] __devinitdata = { "no hardware", /* Should never be seen */ "FarSync T2P", "FarSync T4P", "FarSync T1U", "FarSync T2U", "FarSync T4U", "FarSync TE1"};static void __devinitfst_init_card(struct fst_card_info *card){ int i; int err; /* We're working on a number of ports based on the card ID. If the * firmware detects something different later (should never happen) * we'll have to revise it in some way then. */ for (i = 0; i < card->nports; i++) { err = register_hdlc_device(card->ports[i].dev); if (err < 0) { int j; printk_err ("Cannot register HDLC device for port %d" " (errno %d)\n", i, -err ); for (j = i; j < card->nports; j++) { free_netdev(card->ports[j].dev); card->ports[j].dev = NULL; } card->nports = i; break; } } printk_info("
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -