synclinkmp.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,458 行 · 第 1/5 页
C
2,458 行
ret += sprintf(buf+ret, "\tASYNC tx:%d rx:%d", info->icount.tx, info->icount.rx); if (info->icount.frame) ret += sprintf(buf+ret, " fe:%d", info->icount.frame); if (info->icount.parity) ret += sprintf(buf+ret, " pe:%d", info->icount.parity); if (info->icount.brk) ret += sprintf(buf+ret, " brk:%d", info->icount.brk); if (info->icount.overrun) ret += sprintf(buf+ret, " oe:%d", info->icount.overrun); } /* Append serial signal status to end */ ret += sprintf(buf+ret, " %s\n", stat_buf+1); ret += sprintf(buf+ret, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", info->tx_active,info->bh_requested,info->bh_running, info->pending_bh); return ret;}/* Called to print information about devices */int read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ int len = 0, l; off_t begin = 0; SLMP_INFO *info; len += sprintf(page, "synclinkmp driver:%s\n", driver_version); info = synclinkmp_device_list; while( info ) { l = line_info(page + len, info); len += l; if (len+begin > off+count) goto done; if (len+begin < off) { begin += len; len = 0; } info = info->next_device; } *eof = 1;done: if (off >= len+begin) return 0; *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off);}/* Return the count of bytes in transmit buffer */static int chars_in_buffer(struct tty_struct *tty){ SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; if (sanity_check(info, tty->name, "chars_in_buffer")) return 0; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s chars_in_buffer()=%d\n", __FILE__, __LINE__, info->device_name, info->tx_count); return info->tx_count;}/* Signal remote device to throttle send data (our receive data) */static void throttle(struct tty_struct * tty){ SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s throttle() entry\n", __FILE__,__LINE__, info->device_name ); if (sanity_check(info, tty->name, "throttle")) return; if (I_IXOFF(tty)) send_xchar(tty, STOP_CHAR(tty)); if (tty->termios->c_cflag & CRTSCTS) { spin_lock_irqsave(&info->lock,flags); info->serial_signals &= ~SerialSignal_RTS; set_signals(info); spin_unlock_irqrestore(&info->lock,flags); }}/* Signal remote device to stop throttling send data (our receive data) */static void unthrottle(struct tty_struct * tty){ SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s unthrottle() entry\n", __FILE__,__LINE__, info->device_name ); if (sanity_check(info, tty->name, "unthrottle")) return; if (I_IXOFF(tty)) { if (info->x_char) info->x_char = 0; else send_xchar(tty, START_CHAR(tty)); } if (tty->termios->c_cflag & CRTSCTS) { spin_lock_irqsave(&info->lock,flags); info->serial_signals |= SerialSignal_RTS; set_signals(info); spin_unlock_irqrestore(&info->lock,flags); }}/* set or clear transmit break condition * break_state -1=set break condition, 0=clear */static void set_break(struct tty_struct *tty, int break_state){ unsigned char RegValue; SLMP_INFO * info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s set_break(%d)\n", __FILE__,__LINE__, info->device_name, break_state); if (sanity_check(info, tty->name, "set_break")) return; spin_lock_irqsave(&info->lock,flags); RegValue = read_reg(info, CTL); if (break_state == -1) RegValue |= BIT3; else RegValue &= ~BIT3; write_reg(info, CTL, RegValue); spin_unlock_irqrestore(&info->lock,flags);}#ifdef CONFIG_HDLC/** * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) * set encoding and frame check sequence (FCS) options * * dev pointer to network device structure * encoding serial encoding setting * parity FCS setting * * returns 0 if success, otherwise error code */static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, unsigned short parity){ SLMP_INFO *info = dev_to_port(dev); unsigned char new_encoding; unsigned short new_crctype; /* return error if TTY interface open */ if (info->count) return -EBUSY; switch (encoding) { case ENCODING_NRZ: new_encoding = HDLC_ENCODING_NRZ; break; case ENCODING_NRZI: new_encoding = HDLC_ENCODING_NRZI_SPACE; break; case ENCODING_FM_MARK: new_encoding = HDLC_ENCODING_BIPHASE_MARK; break; case ENCODING_FM_SPACE: new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break; case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break; default: return -EINVAL; } switch (parity) { case PARITY_NONE: new_crctype = HDLC_CRC_NONE; break; case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break; case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break; default: return -EINVAL; } info->params.encoding = new_encoding; info->params.crc_type = new_crctype;; /* if network interface up, reprogram hardware */ if (info->netcount) program_hw(info); return 0;}/** * called by generic HDLC layer to send frame * * skb socket buffer containing HDLC frame * dev pointer to network device structure * * returns 0 if success, otherwise error code */static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev){ SLMP_INFO *info = dev_to_port(dev); struct net_device_stats *stats = hdlc_stats(dev); unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) printk(KERN_INFO "%s:hdlc_xmit(%s)\n",__FILE__,dev->name); /* stop sending until this frame completes */ netif_stop_queue(dev); /* copy data to device buffers */ info->tx_count = skb->len; tx_load_dma_buffer(info, skb->data, skb->len); /* update network statistics */ stats->tx_packets++; stats->tx_bytes += skb->len; /* done with socket buffer, so free it */ dev_kfree_skb(skb); /* save start time for transmit timeout detection */ dev->trans_start = jiffies; /* start hardware transmitter if necessary */ spin_lock_irqsave(&info->lock,flags); if (!info->tx_active) tx_start(info); spin_unlock_irqrestore(&info->lock,flags); return 0;}/** * called by network layer when interface enabled * claim resources and initialize hardware * * dev pointer to network device structure * * returns 0 if success, otherwise error code */static int hdlcdev_open(struct net_device *dev){ SLMP_INFO *info = dev_to_port(dev); int rc; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name); /* generic HDLC layer open processing */ if ((rc = hdlc_open(dev))) return rc; /* arbitrate between network and tty opens */ spin_lock_irqsave(&info->netlock, flags); if (info->count != 0 || info->netcount != 0) { printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name); spin_unlock_irqrestore(&info->netlock, flags); return -EBUSY; } info->netcount=1; spin_unlock_irqrestore(&info->netlock, flags); /* claim resources and init adapter */ if ((rc = startup(info)) != 0) { spin_lock_irqsave(&info->netlock, flags); info->netcount=0; spin_unlock_irqrestore(&info->netlock, flags); return rc; } /* assert DTR and RTS, apply hardware settings */ info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; program_hw(info); /* enable network layer transmit */ dev->trans_start = jiffies; netif_start_queue(dev); /* inform generic HDLC layer of current DCD status */ spin_lock_irqsave(&info->lock, flags); get_signals(info); spin_unlock_irqrestore(&info->lock, flags); hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, dev); return 0;}/** * called by network layer when interface is disabled * shutdown hardware and release resources * * dev pointer to network device structure * * returns 0 if success, otherwise error code */static int hdlcdev_close(struct net_device *dev){ SLMP_INFO *info = dev_to_port(dev); unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s:hdlcdev_close(%s)\n",__FILE__,dev->name); netif_stop_queue(dev); /* shutdown adapter and release resources */ shutdown(info); hdlc_close(dev); spin_lock_irqsave(&info->netlock, flags); info->netcount=0; spin_unlock_irqrestore(&info->netlock, flags); return 0;}/** * called by network layer to process IOCTL call to network device * * dev pointer to network device structure * ifr pointer to network interface request structure * cmd IOCTL command code * * returns 0 if success, otherwise error code */static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){ const size_t size = sizeof(sync_serial_settings); sync_serial_settings new_line; sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; SLMP_INFO *info = dev_to_port(dev); unsigned int flags; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name); /* return error if TTY interface open */ if (info->count) return -EBUSY; if (cmd != SIOCWANDEV) return hdlc_ioctl(dev, ifr, cmd); switch(ifr->ifr_settings.type) { case IF_GET_IFACE: /* return current sync_serial_settings */ ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; if (ifr->ifr_settings.size < size) { ifr->ifr_settings.size = size; /* data size wanted */ return -ENOBUFS; } flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); switch (flags){ case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break; case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break; case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_TXINT; break; case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break; default: new_line.clock_type = CLOCK_DEFAULT; } new_line.clock_rate = info->params.clock_speed; new_line.loopback = info->params.loopback ? 1:0; if (copy_to_user(line, &new_line, size)) return -EFAULT; return 0; case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */ if(!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&new_line, line, size)) return -EFAULT; switch (new_line.clock_type) { case CLOCK_EXT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break; case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break; case CLOCK_INT: flags = HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG; break; case CLOCK_TXINT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG; break; case CLOCK_DEFAULT: flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); break; default: return -EINVAL; } if (new_line.loopback != 0 && new_line.loopback != 1) return -EINVAL; info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); info->params.flags |= flags; info->params.loopback = new_line.loopback; if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG)) info->params.clock_speed = new_line.clock_rate; else info->params.clock_speed = 0; /* if network interface up, reprogram hardware */ if (info->netcount) program_hw(info); return 0; default: return hdlc_ioctl(dev, ifr, cmd); }}/** * called by network layer when transmit timeout is detected * * dev pointer to network device structure */static void hdlcdev_tx_timeout(struct net_device *dev){ SLMP_INFO *info = dev_to_port(dev); struct net_device_stats *stats = hdlc_stats(dev); unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) printk("hdlcdev_tx_timeout(%s)\n",dev->name); stats->tx_errors++; stats->tx_aborted_errors++; spin_lock_irqsave(&info->lock,flags); tx_stop(info); spin_unlock_irqrestore(&info->lock,flags); netif_wake_queue(dev);}/** * called by device driver when transmit completes * reenable network layer transmit if stopped * * info pointer to device instance information */static void hdlcdev_tx_done(SLMP_INFO *info){ if (netif_queue_stopped(info->netdev)) netif_wake_queue(info->netdev);}/** * called by device driver when frame received * pass frame to network layer * * info pointer to device instance information * buf pointer to buffer contianing frame data * size count of data bytes in buf */static void hdlcdev_rx(SLMP_INFO *info, char *buf, int size){ struct sk_buff *skb = dev_alloc_skb(size); struct net_device *dev = info->netdev; struct net_device_stats *stats = hdlc_stats(dev); if (debug_level >= DEBUG_LEVEL_INFO) printk("hdlcdev_rx(%s)\n",dev->name); if (skb == NULL) { printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", dev->name); stats->rx_dropped++; return; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?