📄 synclink.c
字号:
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_CHECK_CD) && (status & MISCSTATUS_DCD_LATCHED) ) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s CD now %s...", info->device_name, (status & MISCSTATUS_DCD) ? "on" : "off"); if (status & MISCSTATUS_DCD) wake_up_interruptible(&info->open_wait); else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && (info->flags & ASYNC_CALLOUT_NOHUP))) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("doing serial hangup..."); if (info->tty) tty_hangup(info->tty); } } if ( (info->flags & ASYNC_CTS_FLOW) && (status & MISCSTATUS_CTS_LATCHED) ) { if (info->tty->hw_stopped) { if (status & MISCSTATUS_CTS) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("CTS tx start..."); if (info->tty) info->tty->hw_stopped = 0; usc_start_transmitter(info); info->pending_bh |= BH_TRANSMIT; return; } } else { if (!(status & MISCSTATUS_CTS)) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("CTS tx stop..."); if (info->tty) info->tty->hw_stopped = 1; usc_stop_transmitter(info); } } } } info->pending_bh |= BH_STATUS; /* for diagnostics set IRQ flag */ if ( status & MISCSTATUS_TXC_LATCHED ){ usc_OutReg( info, SICR, (unsigned short)(usc_InReg(info,SICR) & ~(SICR_TXC_ACTIVE+SICR_TXC_INACTIVE)) ); usc_UnlatchIostatusBits( info, MISCSTATUS_TXC_LATCHED ); info->irq_occurred = 1; }} /* end of mgsl_isr_io_pin() *//* mgsl_isr_transmit_data() * * Service a transmit data interrupt (async mode only). * * Arguments: info pointer to device instance data * Return Value: None */void mgsl_isr_transmit_data( struct mgsl_struct *info ){ if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):mgsl_isr_transmit_data xmit_cnt=%d\n", __FILE__,__LINE__,info->xmit_cnt); usc_ClearIrqPendingBits( info, TRANSMIT_DATA ); if (info->tty->stopped || info->tty->hw_stopped) { usc_stop_transmitter(info); return; } if ( info->xmit_cnt ) usc_load_txfifo( info ); else info->tx_active = 0; if (info->xmit_cnt < WAKEUP_CHARS) info->pending_bh |= BH_TRANSMIT;} /* end of mgsl_isr_transmit_data() *//* mgsl_isr_receive_data() * * Service a receive data interrupt. This occurs * when operating in asynchronous interrupt transfer mode. * The receive data FIFO is flushed to the receive data buffers. * * Arguments: info pointer to device instance data * Return Value: None */void mgsl_isr_receive_data( struct mgsl_struct *info ){ int Fifocount; u16 status; unsigned char DataByte; struct tty_struct *tty = info->tty; struct mgsl_icount *icount = &info->icount; if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):mgsl_isr_receive_data\n", __FILE__,__LINE__); usc_ClearIrqPendingBits( info, RECEIVE_DATA ); /* select FIFO status for RICR readback */ usc_RCmd( info, RCmd_SelectRicrRxFifostatus ); /* clear the Wordstatus bit so that status readback */ /* only reflects the status of this byte */ usc_OutReg( info, RICR+LSBONLY, (u16)(usc_InReg(info, RICR+LSBONLY) & ~BIT3 )); /* flush the receive FIFO */ while( (Fifocount = (usc_InReg(info,RICR) >> 8)) ) { /* read one byte from RxFIFO */ outw( (inw(info->io_base + CCAR) & 0x0780) | (RDR+LSBONLY), info->io_base + CCAR ); DataByte = inb( info->io_base + CCAR ); /* get the status of the received byte */ status = usc_InReg(info, RCSR); if ( status & (RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR + RXSTATUS_OVERRUN + RXSTATUS_BREAK_RECEIVED) ) usc_UnlatchRxstatusBits(info,RXSTATUS_ALL); if (tty->flip.count >= TTY_FLIPBUF_SIZE) continue; *tty->flip.char_buf_ptr = DataByte; icount->rx++; *tty->flip.flag_buf_ptr = 0; if ( status & (RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR + RXSTATUS_OVERRUN + RXSTATUS_BREAK_RECEIVED) ) { printk("rxerr=%04X\n",status); /* update error statistics */ if ( status & RXSTATUS_BREAK_RECEIVED ) { status &= ~(RXSTATUS_FRAMING_ERROR + RXSTATUS_PARITY_ERROR); icount->brk++; } else if (status & RXSTATUS_PARITY_ERROR) icount->parity++; else if (status & RXSTATUS_FRAMING_ERROR) icount->frame++; else if (status & RXSTATUS_OVERRUN) { /* must issue purge fifo cmd before */ /* 16C32 accepts more receive chars */ usc_RTCmd(info,RTCmd_PurgeRxFifo); icount->overrun++; } /* discard char if tty control flags say so */ if (status & info->ignore_status_mask) continue; status &= info->read_status_mask; if (status & RXSTATUS_BREAK_RECEIVED) { *tty->flip.flag_buf_ptr = TTY_BREAK; if (info->flags & ASYNC_SAK) do_SAK(tty); } else if (status & RXSTATUS_PARITY_ERROR) *tty->flip.flag_buf_ptr = TTY_PARITY; else if (status & RXSTATUS_FRAMING_ERROR) *tty->flip.flag_buf_ptr = TTY_FRAME; if (status & RXSTATUS_OVERRUN) { /* Overrun is special, since it's * reported immediately, and doesn't * affect the current character */ if (tty->flip.count < TTY_FLIPBUF_SIZE) { tty->flip.count++; tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; *tty->flip.flag_buf_ptr = TTY_OVERRUN; } } } /* end of if (error) */ tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; tty->flip.count++; } if ( debug_level >= DEBUG_LEVEL_ISR ) { printk("%s(%d):mgsl_isr_receive_data flip 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);}/* mgsl_isr_misc() * * Service a miscellaneos interrupt source. * * Arguments: info pointer to device extension (instance data) * Return Value: None */void mgsl_isr_misc( struct mgsl_struct *info ){ u16 status = usc_InReg( info, MISR ); if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):mgsl_isr_misc status=%04X\n", __FILE__,__LINE__,status); usc_ClearIrqPendingBits( info, MISC ); usc_UnlatchMiscstatusBits( info, status );} /* end of mgsl_isr_misc() *//* mgsl_isr_null() * * Services undefined interrupt vectors from the * USC. (hence this function SHOULD never be called) * * Arguments: info pointer to device extension (instance data) * Return Value: None */void mgsl_isr_null( struct mgsl_struct *info ){} /* end of mgsl_isr_null() *//* mgsl_isr_receive_dma() * * Service a receive DMA channel interrupt. * For this driver there are two sources of receive DMA interrupts * as identified in the Receive DMA mode Register (RDMR): * * BIT3 EOA/EOL End of List, all receive buffers in receive * buffer list have been filled (no more free buffers * available). The DMA controller has shut down. * * BIT2 EOB End of Buffer. This interrupt occurs when a receive * DMA buffer is terminated in response to completion * of a good frame or a frame with errors. The status * of the frame is stored in the buffer entry in the * list of receive buffer entries. * * Arguments: info pointer to device instance data * Return Value: None */void mgsl_isr_receive_dma( struct mgsl_struct *info ){ u16 status; /* clear interrupt pending and IUS bit for Rx DMA IRQ */ usc_OutDmaReg( info, CDIR, BIT9+BIT1 ); /* Read the receive DMA status to identify interrupt type. */ /* This also clears the status bits. */ status = usc_InDmaReg( info, RDMR ); if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):mgsl_isr_receive_dma(%s) status=%04X\n", __FILE__,__LINE__,info->device_name,status); info->pending_bh |= BH_RECEIVE; if ( status & BIT3 ) { info->rx_overflow = 1; info->icount.buf_overrun++; }} /* end of mgsl_isr_receive_dma() *//* mgsl_interrupt() * * Interrupt service routine entry point. * * Arguments: * * irq interrupt number that caused interrupt * dev_id device ID supplied during interrupt registration * regs interrupted processor context * * Return Value: None */static void mgsl_interrupt(int irq, void *dev_id, struct pt_regs * regs){ struct mgsl_struct * info; u16 UscVector; u16 DmaVector; if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):mgsl_interrupt(%d)entry.\n", __FILE__,__LINE__,irq); info = (struct mgsl_struct *)dev_id; if (!info) return; spin_lock(&info->irq_spinlock); for(;;) { /* Read the interrupt vectors from hardware. */ UscVector = usc_InReg(info, IVR) >> 9; DmaVector = usc_InDmaReg(info, DIVR); if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):%s UscVector=%08X DmaVector=%08X\n", __FILE__,__LINE__,info->device_name,UscVector,DmaVector); if ( !UscVector && !DmaVector ) break; /* Dispatch interrupt vector */ if ( UscVector ) (*UscIsrTable[UscVector])(info); else mgsl_isr_receive_dma(info); if ( info->isr_overflow ) { printk(KERN_ERR"%s(%d):%s isr overflow irq=%d\n", __FILE__,__LINE__,info->device_name, irq); usc_DisableMasterIrqBit(info); usc_DisableDmaInterrupts(info,DICR_MASTER); break; } } /* 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->irq_spinlock); if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):mgsl_interrupt(%d)exit.\n", __FILE__,__LINE__,irq);} /* end of mgsl_interrupt() *//* startup() * * Initialize and start device. * * Arguments: info pointer to device instance data * Return Value: 0 if success, otherwise error code */static int startup(struct mgsl_struct * info){ int retval = 0; if ( debug_level >= DEBUG_LEVEL_INFO ) printk("%s(%d):mgsl_startup(%s)\n",__FILE__,__LINE__,info->device_name); if (info->flags & ASYNC_INITIALIZED) return 0; if (!info->xmit_buf) { /* allocate a page of memory for a transmit buffer */ info->xmit_buf = (unsigned char *)get_free_page(GFP_KERNEL); if (!info->xmit_buf) { printk(KERN_ERR"%s(%d):%s can't allocate transmit buffer\n", __FILE__,__LINE__,info->device_name); return -ENOMEM; } } info->pending_bh = 0; init_timer(&info->tx_timer); info->tx_timer.data = (unsigned long)info; info->tx_timer.function = mgsl_tx_timeout; /* Allocate and claim adapter resources */ retval = mgsl_claim_resources(info); /* perform existance check and diagnostics */ if ( !retval ) retval = mgsl_adapter_test(info); if ( retval ) { if (capable(CAP_SYS_ADMIN) && info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); mgsl_release_resources(info); return retval; } /* program hardware for current parameters */ mgsl_change_params(info); if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); info->flags |= ASYNC_INITIALIZED; return 0; } /* end of startup() *//* shutdown() * * Called by mgsl_close() and mgsl_hangup() to shutdown hardware * * Arguments: info pointer to device instance data * Return Value: None */static void shutdown(struct mgsl_struct * info){ unsigned long flags; if (!(info->flags & ASYNC_INITIALIZED)) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_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->xmit_buf) { free_page((unsigned long) info->xmit_buf); info->xmit_buf = 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -