📄 cyclades.c
字号:
cy_readb(base_addr+(CySRER<<index)) & ~CyTxRdy); goto txdone; } if (info->tty->stopped || info->tty->hw_stopped){ cy_writeb((u_long)base_addr+(CySRER<<index), cy_readb(base_addr+(CySRER<<index)) & ~CyTxRdy); goto txdone; } /* Because the Embedded Transmit Commands have been enabled, we must check to see if the escape character, NULL, is being sent. If it is, we must ensure that there is room for it to be doubled in the output stream. Therefore we no longer advance the pointer when the character is fetched, but rather wait until after the check for a NULL output character. This is necessary because there may not be room for the two chars needed to send a NULL.) */ outch = info->xmit_buf[info->xmit_tail]; if( outch ){ info->xmit_cnt--; info->xmit_tail = (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); cy_writeb((u_long)base_addr+(CyTDR<<index), outch); info->icount.tx++; }else{ if(char_count > 1){ info->xmit_cnt--; info->xmit_tail = (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1); cy_writeb((u_long)base_addr+(CyTDR<<index), outch); cy_writeb((u_long)base_addr+(CyTDR<<index), 0); info->icount.tx++; char_count--; }else{ } } } txdone: if (info->xmit_cnt < WAKEUP_CHARS) { cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); } txend: /* end of service */ cy_writeb((u_long)base_addr+(CyTIR<<index), (save_xir & 0x3f)); cy_writeb((u_long)base_addr+(CyCAR<<index), (save_car)); spin_unlock(&cinfo->card_lock); } if (status & CySRModem) { /* modem interrupt */ /* determine the channel & change to that context */ spin_lock(&cinfo->card_lock); save_xir = (u_char) cy_readb(base_addr+(CyMIR<<index)); channel = (u_short ) (save_xir & CyIRChannel); info = &cy_port[channel + chip * 4 + cinfo->first_line]; info->last_active = jiffies; save_car = cy_readb(base_addr+(CyCAR<<index)); cy_writeb((u_long)base_addr+(CyCAR<<index), save_xir); mdm_change = cy_readb(base_addr+(CyMISR<<index)); mdm_status = cy_readb(base_addr+(CyMSVR1<<index)); if(info->tty == 0){/* no place for data, ignore it*/ ; }else{ if (mdm_change & CyANY_DELTA) { /* For statistics only */ if (mdm_change & CyDCD) info->icount.dcd++; if (mdm_change & CyCTS) info->icount.cts++; if (mdm_change & CyDSR) info->icount.dsr++; if (mdm_change & CyRI) info->icount.rng++; cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP); } if((mdm_change & CyDCD) && (info->flags & ASYNC_CHECK_CD)){ if(mdm_status & CyDCD){ cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP); }else if(!((info->flags & ASYNC_CALLOUT_ACTIVE) &&(info->flags & ASYNC_CALLOUT_NOHUP))){ cy_sched_event(info, Cy_EVENT_HANGUP); } } if((mdm_change & CyCTS) && (info->flags & ASYNC_CTS_FLOW)){ if(info->tty->hw_stopped){ if(mdm_status & CyCTS){ /* cy_start isn't used because... !!! */ info->tty->hw_stopped = 0; cy_writeb((u_long)base_addr+(CySRER<<index), cy_readb(base_addr+(CySRER<<index)) | CyTxRdy); cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); } }else{ if(!(mdm_status & CyCTS)){ /* cy_stop isn't used because ... !!! */ info->tty->hw_stopped = 1; cy_writeb((u_long)base_addr+(CySRER<<index), cy_readb(base_addr+(CySRER<<index)) & ~CyTxRdy); } } } if(mdm_change & CyDSR){ } if(mdm_change & CyRI){ } } /* end of service */ cy_writeb((u_long)base_addr+(CyMIR<<index), (save_xir & 0x3f)); cy_writeb((u_long)base_addr+(CyCAR<<index), save_car); spin_unlock(&cinfo->card_lock); } } /* end while status != 0 */ } /* end loop for chips... */ } while(had_work); /* clear interrupts */ spin_lock(&cinfo->card_lock); cy_writeb((u_long)card_base_addr + (Cy_ClrIntr<<index), 0); /* Cy_ClrIntr is 0x1800 */ spin_unlock(&cinfo->card_lock);} /* cyy_interrupt *//***********************************************************//********* End of block of Cyclom-Y specific code **********//******** Start of block of Cyclades-Z specific code *********//***********************************************************/static intcyz_fetch_msg( struct cyclades_card *cinfo, uclong *channel, ucchar *cmd, uclong *param){ struct FIRM_ID *firm_id; struct ZFW_CTRL *zfw_ctrl; struct BOARD_CTRL *board_ctrl; unsigned long loc_doorbell; firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); if (!ISZLOADED(*cinfo)){ return (-1); } zfw_ctrl = (struct ZFW_CTRL *) (cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); board_ctrl = &zfw_ctrl->board_ctrl; loc_doorbell = cy_readl(&((struct RUNTIME_9060 *) (cinfo->ctl_addr))->loc_doorbell); if (loc_doorbell){ *cmd = (char)(0xff & loc_doorbell); *channel = cy_readl(&board_ctrl->fwcmd_channel); *param = (uclong)cy_readl(&board_ctrl->fwcmd_param); cy_writel(&((struct RUNTIME_9060 *)(cinfo->ctl_addr))->loc_doorbell, 0xffffffff); return 1; } return 0;} /* cyz_fetch_msg */static intcyz_issue_cmd( struct cyclades_card *cinfo, uclong channel, ucchar cmd, uclong param){ struct FIRM_ID *firm_id; struct ZFW_CTRL *zfw_ctrl; struct BOARD_CTRL *board_ctrl; volatile uclong *pci_doorbell; int index; firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); if (!ISZLOADED(*cinfo)){ return (-1); } zfw_ctrl = (struct ZFW_CTRL *) (cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff)); board_ctrl = &zfw_ctrl->board_ctrl; index = 0; pci_doorbell = (uclong *)(&((struct RUNTIME_9060 *) (cinfo->ctl_addr))->pci_doorbell); while( (cy_readl(pci_doorbell) & 0xff) != 0){ if (index++ == 1000){ return((int)(cy_readl(pci_doorbell) & 0xff)); } udelay(50L); } cy_writel((u_long)&board_ctrl->hcmd_channel, channel); cy_writel((u_long)&board_ctrl->hcmd_param , param); cy_writel((u_long)pci_doorbell, (long)cmd); return(0);} /* cyz_issue_cmd */static voidcyz_handle_rx(struct cyclades_port *info, volatile struct CH_CTRL *ch_ctrl, volatile struct BUF_CTRL *buf_ctrl){ struct cyclades_card *cinfo = &cy_card[info->card]; struct tty_struct *tty = info->tty; volatile int char_count;#ifdef BLOCKMOVE int small_count;#else char data;#endif volatile uclong rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr; rx_get = new_rx_get = cy_readl(&buf_ctrl->rx_get); rx_put = cy_readl(&buf_ctrl->rx_put); rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize); rx_bufaddr = cy_readl(&buf_ctrl->rx_bufaddr); if (rx_put >= rx_get) char_count = rx_put - rx_get; else char_count = rx_put - rx_get + rx_bufsize; if ( char_count ) { info->last_active = jiffies; info->jiffies[1] = jiffies;#ifdef CY_ENABLE_MONITORING info->mon.int_count++; info->mon.char_count += char_count; if (char_count > info->mon.char_max) info->mon.char_max = char_count; info->mon.char_last = char_count;#endif if(tty == 0){ /* flush received characters */ new_rx_get = (new_rx_get + char_count) & (rx_bufsize - 1); info->rflush_count++; }else{#ifdef BLOCKMOVE /* we'd like to use memcpy(t, f, n) and memset(s, c, count) for performance, but because of buffer boundaries, there may be several steps to the operation */ while(0 < (small_count = min_t(unsigned int, (rx_bufsize - new_rx_get), min_t(unsigned int, (TTY_FLIPBUF_SIZE - tty->flip.count), char_count)) )) { memcpy_fromio(tty->flip.char_buf_ptr, (char *)(cinfo->base_addr + rx_bufaddr + new_rx_get), small_count); tty->flip.char_buf_ptr += small_count; memset(tty->flip.flag_buf_ptr, TTY_NORMAL, small_count); tty->flip.flag_buf_ptr += small_count; new_rx_get = (new_rx_get + small_count) & (rx_bufsize - 1); char_count -= small_count; info->icount.rx += small_count; info->idle_stats.recv_bytes += small_count; tty->flip.count += small_count; }#else while(char_count--){ if (tty->flip.count >= TTY_FLIPBUF_SIZE){ break; } data = cy_readb(cinfo->base_addr + rx_bufaddr + new_rx_get); new_rx_get = (new_rx_get + 1) & (rx_bufsize - 1); tty->flip.count++; *tty->flip.flag_buf_ptr++ = TTY_NORMAL; *tty->flip.char_buf_ptr++ = data; info->idle_stats.recv_bytes++; info->icount.rx++; }#endif#ifdef CONFIG_CYZ_INTR /* Recalculate the number of chars in the RX buffer and issue a cmd in case it's higher than the RX high water mark */ rx_put = cy_readl(&buf_ctrl->rx_put); if (rx_put >= rx_get) char_count = rx_put - rx_get; else char_count = rx_put - rx_get + rx_bufsize; if(char_count >= cy_readl(&buf_ctrl->rx_threshold)) { cy_sched_event(info, Cy_EVENT_Z_RX_FULL); }#endif info->idle_stats.recv_idle = jiffies; queue_task(&tty->flip.tqueue, &tq_timer); } /* Update rx_get */ cy_writel(&buf_ctrl->rx_get, new_rx_get); }}static voidcyz_handle_tx(struct cyclades_port *info, volatile struct CH_CTRL *ch_ctrl, volatile struct BUF_CTRL *buf_ctrl){ struct cyclades_card *cinfo = &cy_card[info->card]; struct tty_struct *tty = info->tty; char data; volatile int char_count;#ifdef BLOCKMOVE int small_count;#endif volatile uclong tx_put, tx_get, tx_bufsize, tx_bufaddr; if (info->xmit_cnt <= 0) /* Nothing to transmit */ return; tx_get = cy_readl(&buf_ctrl->tx_get); tx_put = cy_readl(&buf_ctrl->tx_put); tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize); tx_bufaddr = cy_readl(&buf_ctrl->tx_bufaddr); if (tx_put >= tx_get) char_count = tx_get - tx_put - 1 + tx_bufsize; else char_count = tx_get - tx_put - 1; if ( char_count ) { if( tty == 0 ){ goto ztxdone; } if(info->x_char) { /* send special char */ data = info->x_char; cy_writeb((cinfo->base_addr + tx_bufaddr + tx_put), d
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -