📄 synclink_cs.c
字号:
data = read_reg(info, CHA + RXFIFO); status = read_reg(info, CHA + RXFIFO); fifo_count -= 2; icount->rx++; flag = TTY_NORMAL; // if no frameing/crc error then save data // BIT7:parity error // BIT6:framing error if (status & (BIT7 + BIT6)) { if (status & BIT7) icount->parity++; else icount->frame++; /* discard char if tty control flags say so */ if (status & info->ignore_status_mask) continue; status &= info->read_status_mask; if (status & BIT7) flag = TTY_PARITY; else if (status & BIT6) flag = TTY_FRAME; } work += tty_insert_flip_char(tty, data, flag); } issue_command(info, CHA, CMD_RXFIFO); if (debug_level >= DEBUG_LEVEL_ISR) { printk("%s(%d):rx_ready_async", __FILE__,__LINE__); printk("%s(%d):rx=%d brk=%d parity=%d frame=%d overrun=%d\n", __FILE__,__LINE__,icount->rx,icount->brk, icount->parity,icount->frame,icount->overrun); } if (work) tty_flip_buffer_push(tty);}static void tx_done(MGSLPC_INFO *info){ if (!info->tx_active) return; info->tx_active = 0; info->tx_aborting = 0; if (info->params.mode == MGSL_MODE_ASYNC) return; info->tx_count = info->tx_put = info->tx_get = 0; del_timer(&info->tx_timer); if (info->drop_rts_on_tx_done) { get_signals(info); if (info->serial_signals & SerialSignal_RTS) { info->serial_signals &= ~SerialSignal_RTS; set_signals(info); } info->drop_rts_on_tx_done = 0; }#ifdef CONFIG_HDLC if (info->netcount) hdlcdev_tx_done(info); else #endif { if (info->tty->stopped || info->tty->hw_stopped) { tx_stop(info); return; } info->pending_bh |= BH_TRANSMIT; }}static void tx_ready(MGSLPC_INFO *info){ unsigned char fifo_count = 32; int c; if (debug_level >= DEBUG_LEVEL_ISR) printk("%s(%d):tx_ready(%s)\n", __FILE__,__LINE__,info->device_name); if (info->params.mode == MGSL_MODE_HDLC) { if (!info->tx_active) return; } else { if (info->tty->stopped || info->tty->hw_stopped) { tx_stop(info); return; } if (!info->tx_count) info->tx_active = 0; } if (!info->tx_count) return; while (info->tx_count && fifo_count) { c = min(2, min_t(int, fifo_count, min(info->tx_count, TXBUFSIZE - info->tx_get))); if (c == 1) { write_reg(info, CHA + TXFIFO, *(info->tx_buf + info->tx_get)); } else { write_reg16(info, CHA + TXFIFO, *((unsigned short*)(info->tx_buf + info->tx_get))); } info->tx_count -= c; info->tx_get = (info->tx_get + c) & (TXBUFSIZE - 1); fifo_count -= c; } if (info->params.mode == MGSL_MODE_ASYNC) { if (info->tx_count < WAKEUP_CHARS) info->pending_bh |= BH_TRANSMIT; issue_command(info, CHA, CMD_TXFIFO); } else { if (info->tx_count) issue_command(info, CHA, CMD_TXFIFO); else issue_command(info, CHA, CMD_TXFIFO + CMD_TXEOM); }}static void cts_change(MGSLPC_INFO *info){ get_signals(info); if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) irq_disable(info, CHB, IRQ_CTS); info->icount.cts++; if (info->serial_signals & SerialSignal_CTS) info->input_signal_events.cts_up++; else info->input_signal_events.cts_down++; wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); if (info->flags & ASYNC_CTS_FLOW) { if (info->tty->hw_stopped) { if (info->serial_signals & SerialSignal_CTS) { if (debug_level >= DEBUG_LEVEL_ISR) printk("CTS tx start..."); if (info->tty) info->tty->hw_stopped = 0; tx_start(info); info->pending_bh |= BH_TRANSMIT; return; } } else { if (!(info->serial_signals & SerialSignal_CTS)) { if (debug_level >= DEBUG_LEVEL_ISR) printk("CTS tx stop..."); if (info->tty) info->tty->hw_stopped = 1; tx_stop(info); } } } info->pending_bh |= BH_STATUS;}static void dcd_change(MGSLPC_INFO *info){ get_signals(info); if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) irq_disable(info, CHB, IRQ_DCD); info->icount.dcd++; if (info->serial_signals & SerialSignal_DCD) { info->input_signal_events.dcd_up++; } else info->input_signal_events.dcd_down++;#ifdef CONFIG_HDLC if (info->netcount) hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, info->netdev);#endif wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); if (info->flags & ASYNC_CHECK_CD) { if (debug_level >= DEBUG_LEVEL_ISR) printk("%s CD now %s...", info->device_name, (info->serial_signals & SerialSignal_DCD) ? "on" : "off"); if (info->serial_signals & SerialSignal_DCD) wake_up_interruptible(&info->open_wait); else { if (debug_level >= DEBUG_LEVEL_ISR) printk("doing serial hangup..."); if (info->tty) tty_hangup(info->tty); } } info->pending_bh |= BH_STATUS;}static void dsr_change(MGSLPC_INFO *info){ get_signals(info); if ((info->dsr_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) port_irq_disable(info, PVR_DSR); info->icount.dsr++; if (info->serial_signals & SerialSignal_DSR) info->input_signal_events.dsr_up++; else info->input_signal_events.dsr_down++; wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); info->pending_bh |= BH_STATUS;}static void ri_change(MGSLPC_INFO *info){ get_signals(info); if ((info->ri_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) port_irq_disable(info, PVR_RI); info->icount.rng++; if (info->serial_signals & SerialSignal_RI) info->input_signal_events.ri_up++; else info->input_signal_events.ri_down++; wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); info->pending_bh |= BH_STATUS;}/* Interrupt service routine entry point. * * Arguments: * * irq interrupt number that caused interrupt * dev_id device ID supplied during interrupt registration * regs interrupted processor context */static irqreturn_t mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs){ MGSLPC_INFO * info = (MGSLPC_INFO *)dev_id; unsigned short isr; unsigned char gis, pis; int count=0; if (debug_level >= DEBUG_LEVEL_ISR) printk("mgslpc_isr(%d) entry.\n", irq); if (!info) return IRQ_NONE; if (!(info->p_dev->_locked)) return IRQ_HANDLED; spin_lock(&info->lock); while ((gis = read_reg(info, CHA + GIS))) { if (debug_level >= DEBUG_LEVEL_ISR) printk("mgslpc_isr %s gis=%04X\n", info->device_name,gis); if ((gis & 0x70) || count > 1000) { printk("synclink_cs:hardware failed or ejected\n"); break; } count++; if (gis & (BIT1 + BIT0)) { isr = read_reg16(info, CHB + ISR); if (isr & IRQ_DCD) dcd_change(info); if (isr & IRQ_CTS) cts_change(info); } if (gis & (BIT3 + BIT2)) { isr = read_reg16(info, CHA + ISR); if (isr & IRQ_TIMER) { info->irq_occurred = 1; irq_disable(info, CHA, IRQ_TIMER); } /* receive IRQs */ if (isr & IRQ_EXITHUNT) { info->icount.exithunt++; wake_up_interruptible(&info->event_wait_q); } if (isr & IRQ_BREAK_ON) { info->icount.brk++; if (info->flags & ASYNC_SAK) do_SAK(info->tty); } if (isr & IRQ_RXTIME) { issue_command(info, CHA, CMD_RXFIFO_READ); } if (isr & (IRQ_RXEOM + IRQ_RXFIFO)) { if (info->params.mode == MGSL_MODE_HDLC) rx_ready_hdlc(info, isr & IRQ_RXEOM); else rx_ready_async(info, isr & IRQ_RXEOM); } /* transmit IRQs */ if (isr & IRQ_UNDERRUN) { if (info->tx_aborting) info->icount.txabort++; else info->icount.txunder++; tx_done(info); } else if (isr & IRQ_ALLSENT) { info->icount.txok++; tx_done(info); } else if (isr & IRQ_TXFIFO) tx_ready(info); } if (gis & BIT7) { pis = read_reg(info, CHA + PIS); if (pis & BIT1) dsr_change(info); if (pis & BIT2) ri_change(info); } } /* Request bottom half processing if there's something * for it to do and the bh is not already running */ if (info->pending_bh && !info->bh_running && !info->bh_requested) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):%s queueing bh task.\n", __FILE__,__LINE__,info->device_name); schedule_work(&info->task); info->bh_requested = 1; } spin_unlock(&info->lock); if (debug_level >= DEBUG_LEVEL_ISR) printk("%s(%d):mgslpc_isr(%d)exit.\n", __FILE__,__LINE__,irq); return IRQ_HANDLED;}/* Initialize and start device. */static int startup(MGSLPC_INFO * info){ int retval = 0; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):startup(%s)\n",__FILE__,__LINE__,info->device_name); if (info->flags & ASYNC_INITIALIZED) return 0; if (!info->tx_buf) { /* allocate a page of memory for a transmit buffer */ info->tx_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); if (!info->tx_buf) { printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n", __FILE__,__LINE__,info->device_name); return -ENOMEM; } } info->pending_bh = 0; memset(&info->icount, 0, sizeof(info->icount)); init_timer(&info->tx_timer); info->tx_timer.data = (unsigned long)info; info->tx_timer.function = tx_timeout; /* Allocate and claim adapter resources */ retval = claim_resources(info); /* perform existance check and diagnostics */ if ( !retval ) retval = adapter_test(info); if ( retval ) { if (capable(CAP_SYS_ADMIN) && info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); release_resources(info); return retval; } /* program hardware for current parameters */ mgslpc_change_params(info); if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); info->flags |= ASYNC_INITIALIZED; return 0;}/* Called by mgslpc_close() and mgslpc_hangup() to shutdown hardware */static void shutdown(MGSLPC_INFO * info){ unsigned long flags; if (!(info->flags & ASYNC_INITIALIZED)) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgslpc_shutdown(%s)\n", __FILE__,__LINE__, info->device_name ); /* clear status wait queue because status changes */ /* can't happen after shutting down the hardware */ wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); del_timer(&info->tx_timer); if (info->tx_buf) { free_page((unsigned long) info->tx_buf); info->tx_buf = NULL; } spin_lock_irqsave(&info->lock,flags); rx_stop(info); tx_stop(info); /* TODO:disable interrupts instead of reset to preserve signal states */ reset_device(info); if (!info->tty || info->tty->termios->c_cflag & HUPCL) { info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); set_signals(info); } spin_unlock_irqrestore(&info->lock,flags); release_resources(info); if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); info->flags &= ~ASYNC_INITIALIZED;}static void mgslpc_program_hw(MGSLPC_INFO *info){ unsigned long flags; spin_lock_irqsave(&info->lock,flags); rx_stop(info); tx_stop(info); info->tx_count = info->tx_put = info->tx_get = 0; if (info->params.mode == MGSL_MODE_HDLC || info->netcount) hdlc_mode(info); else async_mode(info); set_signals(info); info->dcd_chkcount = 0; info->cts_chkcount = 0; info->ri_chkcount = 0; info->dsr_chkcount = 0; irq_enable(info, CHB, IRQ_DCD | IRQ_CTS); port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI); get_signals(info); if (info->netcount || info->tty->termios->c_cflag & CREAD) rx_start(info); spin_unlock_irqrestore(&info->lock,flags);}/* Reconfigure adapter based on new parameters */static void mgslpc_change_params(MGSLPC_INFO *info){ unsigned cflag; int bits_per_char; if (!info->tty || !info->tty->termios) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgslpc_change_params(%s)\n", __FILE__,__LINE__, info->device_name ); cflag = info->tty->termios->c_cflag;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -