📄 synclink.c
字号:
usc_set_serial_signals( info ); } info->drop_rts_on_tx_done = 0; } if (info->tty->stopped || info->tty->hw_stopped) { usc_stop_transmitter(info); return; } mgsl_bh_queue_put(info, BH_TYPE_TRANSMIT_STATUS, status);} /* end of mgsl_isr_transmit_status() *//* mgsl_isr_io_pin() * * Service an Input/Output pin interrupt. The type of * interrupt is indicated by bits in the MISR * * Arguments: info pointer to device instance data * Return Value: None */void mgsl_isr_io_pin( struct mgsl_struct *info ){ struct mgsl_icount *icount; u16 status = usc_InReg( info, MISR ); if ( debug_level >= DEBUG_LEVEL_ISR ) printk("%s(%d):mgsl_isr_io_pin status=%04X\n", __FILE__,__LINE__,status); usc_ClearIrqPendingBits( info, IO_PIN ); usc_UnlatchIostatusBits( info, status ); if (status & (MISCSTATUS_CTS_LATCHED | MISCSTATUS_DCD_LATCHED | MISCSTATUS_DSR_LATCHED | MISCSTATUS_RI_LATCHED) ) { icount = &info->icount; /* update input line counters */ if (status & MISCSTATUS_RI_LATCHED) icount->rng++; if (status & MISCSTATUS_DSR_LATCHED) icount->dsr++; if (status & MISCSTATUS_DCD_LATCHED) { icount->dcd++;#ifdef CONFIG_HARD_PPS if ((info->flags & ASYNC_HARDPPS_CD) && (status & MISCSTATUS_DCD_LATCHED)) hardpps();#endif } if (status & MISCSTATUS_CTS_LATCHED) icount->cts++; 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..."); info->tty->hw_stopped = 0; usc_start_transmitter(info); mgsl_bh_queue_put( info, BH_TYPE_TRANSMIT_DATA, status ); return; } } else { if (!(status & MISCSTATUS_CTS)) { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("CTS tx stop..."); info->tty->hw_stopped = 1; usc_stop_transmitter(info); } } } } /* 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) mgsl_bh_queue_put(info, BH_TYPE_TRANSMIT_DATA, (unsigned short)(info->xmit_cnt));} /* 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 ) {#if LINUX_VERSION_CODE >= VERSION(2,1,0) tty_flip_buffer_push(tty);#else queue_task(&tty->flip.tqueue, &tq_timer); #endif } } /* end of mgsl_isr_receive_data() *//* 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); /* Post a receive event for BH processing. */ mgsl_bh_queue_put( info, BH_TYPE_RECEIVE_DMA, status ); if ( status & BIT3 ) info->rx_overflow = 1;} /* 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); /* Interrupt overflow. Reset adapter and exit. */// UscReset(info);// break; } } /* Request bottom half processing if there's something * for it to do and the bh is not already running */ if ( info->bh_queue_head && !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; } } mgsl_format_bh_queue(info); 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -