📄 synclink_cs.c
字号:
info->bh_running = 1; while((action = bh_action(info)) != 0) { /* Process work item */ if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):bh_handler() work item action=%d\n", __FILE__,__LINE__,action); switch (action) { case BH_RECEIVE: while(rx_get_frame(info)); break; case BH_TRANSMIT: bh_transmit(info); break; case BH_STATUS: bh_status(info); break; default: /* unknown work item ID */ printk("Unknown work item ID=%08X!\n", action); break; } } if (debug_level >= DEBUG_LEVEL_BH) printk( "%s(%d):bh_handler(%s) exit\n", __FILE__,__LINE__,info->device_name);}void bh_transmit(MGSLPC_INFO *info){ struct tty_struct *tty = info->tty; if (debug_level >= DEBUG_LEVEL_BH) printk("bh_transmit() entry on %s\n", info->device_name); if (tty) { if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { if ( debug_level >= DEBUG_LEVEL_BH ) printk( "%s(%d):calling ldisc.write_wakeup on %s\n", __FILE__,__LINE__,info->device_name); (tty->ldisc.write_wakeup)(tty); } wake_up_interruptible(&tty->write_wait); }}void bh_status(MGSLPC_INFO *info){ info->ri_chkcount = 0; info->dsr_chkcount = 0; info->dcd_chkcount = 0; info->cts_chkcount = 0;}/* eom: non-zero = end of frame */ void rx_ready_hdlc(MGSLPC_INFO *info, int eom) { unsigned char data[2]; unsigned char fifo_count, read_count, i; RXBUF *buf = (RXBUF*)(info->rx_buf + (info->rx_put * info->rx_buf_size)); if (debug_level >= DEBUG_LEVEL_ISR) printk("%s(%d):rx_ready_hdlc(eom=%d)\n",__FILE__,__LINE__,eom); if (!info->rx_enabled) return; if (info->rx_frame_count >= info->rx_buf_count) { /* no more free buffers */ issue_command(info, CHA, CMD_RXRESET); info->pending_bh |= BH_RECEIVE; info->rx_overflow = 1; info->icount.buf_overrun++; return; } if (eom) { /* end of frame, get FIFO count from RBCL register */ if (!(fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f))) fifo_count = 32; } else fifo_count = 32; do { if (fifo_count == 1) { read_count = 1; data[0] = read_reg(info, CHA + RXFIFO); } else { read_count = 2; *((unsigned short *) data) = read_reg16(info, CHA + RXFIFO); } fifo_count -= read_count; if (!fifo_count && eom) buf->status = data[--read_count]; for (i = 0; i < read_count; i++) { if (buf->count >= info->max_frame_size) { /* frame too large, reset receiver and reset current buffer */ issue_command(info, CHA, CMD_RXRESET); buf->count = 0; return; } *(buf->data + buf->count) = data[i]; buf->count++; } } while (fifo_count); if (eom) { info->pending_bh |= BH_RECEIVE; info->rx_frame_count++; info->rx_put++; if (info->rx_put >= info->rx_buf_count) info->rx_put = 0; } issue_command(info, CHA, CMD_RXFIFO);}void rx_ready_async(MGSLPC_INFO *info, int tcd) { unsigned char data, status; int fifo_count; struct tty_struct *tty = info->tty; struct mgsl_icount *icount = &info->icount; if (tcd) { /* early termination, get FIFO count from RBCL register */ fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f); /* Zero fifo count could mean 0 or 32 bytes available. * If BIT5 of STAR is set then at least 1 byte is available. */ if (!fifo_count && (read_reg(info,CHA+STAR) & BIT5)) fifo_count = 32; } else fifo_count = 32; /* Flush received async data to receive data buffer. */ while (fifo_count) { data = read_reg(info, CHA + RXFIFO); status = read_reg(info, CHA + RXFIFO); fifo_count -= 2; if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; *tty->flip.char_buf_ptr = data; icount->rx++; *tty->flip.flag_buf_ptr = 0; // 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) *tty->flip.flag_buf_ptr = TTY_PARITY; else if (status & BIT6) *tty->flip.flag_buf_ptr = TTY_FRAME; } tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; tty->flip.count++; } issue_command(info, CHA, CMD_RXFIFO); if (debug_level >= DEBUG_LEVEL_ISR) { printk("%s(%d):rx_ready_async count=%d\n", __FILE__,__LINE__,tty->flip.count); 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 (tty->flip.count) tty_flip_buffer_push(tty);}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_SYNCLINK_SYNCPPP if (info->netcount) mgslpc_sppp_tx_done(info); else #endif { if (info->tty->stopped || info->tty->hw_stopped) { tx_stop(info); return; } info->pending_bh |= BH_TRANSMIT; }}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(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); }}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;}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++;#ifdef CONFIG_SYNCLINK_SYNCPPP if (info->netcount) sppp_reopen(info->netdev);#endif } else info->input_signal_events.dcd_down++; 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 (!(info->flags & (ASYNC_CALLOUT_ACTIVE | ASYNC_CALLOUT_NOHUP))) { if (debug_level >= DEBUG_LEVEL_ISR) printk("doing serial hangup..."); if (info->tty) tty_hangup(info->tty); } } info->pending_bh |= BH_STATUS;}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;}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 void 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; if (!(info->link.state & DEV_CONFIG)) return; 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); queue_task(&info->task, &tq_immediate); mark_bh(IMMEDIATE_BH); info->bh_requested = 1; } spin_unlock(&info->lock);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -