cyclades.c
来自「linux 内核源代码」· C语言 代码 · 共 2,048 行 · 第 1/5 页
C
2,048 行
ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]); switch (cmd) { case C_CM_PR_ERROR: tty_insert_flip_char(tty, 0, TTY_PARITY); info->icount.rx++; special_count++; break; case C_CM_FR_ERROR: tty_insert_flip_char(tty, 0, TTY_FRAME); info->icount.rx++; special_count++; break; case C_CM_RXBRK: tty_insert_flip_char(tty, 0, TTY_BREAK); info->icount.rx++; special_count++; break; case C_CM_MDCD: info->icount.dcd++; delta_count++; if (info->flags & ASYNC_CHECK_CD) { if ((fw_ver > 241 ? ((u_long) param) : readl(&ch_ctrl->rs_status)) & C_RS_DCD) { wake_up_interruptible(&info->open_wait); } else { tty_hangup(info->tty); wake_up_interruptible(&info->open_wait); info->flags &= ~ASYNC_NORMAL_ACTIVE; } } break; case C_CM_MCTS: info->icount.cts++; delta_count++; break; case C_CM_MRI: info->icount.rng++; delta_count++; break; case C_CM_MDSR: info->icount.dsr++; delta_count++; break;#ifdef Z_WAKE case C_CM_IOCTLW: complete(&info->shutdown_wait); break;#endif#ifdef CONFIG_CYZ_INTR case C_CM_RXHIWM: case C_CM_RXNNDT: case C_CM_INTBACK2: /* Reception Interrupt */#ifdef CY_DEBUG_INTERRUPTS printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, " "port %ld\n", info->card, channel);#endif cyz_handle_rx(info, buf_ctrl); break; case C_CM_TXBEMPTY: case C_CM_TXLOWWM: case C_CM_INTBACK: /* Transmission Interrupt */#ifdef CY_DEBUG_INTERRUPTS printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, " "port %ld\n", info->card, channel);#endif cyz_handle_tx(info, buf_ctrl); break;#endif /* CONFIG_CYZ_INTR */ case C_CM_FATAL: /* should do something with this !!! */ break; default: break; } if (delta_count) wake_up_interruptible(&info->delta_msr_wait); if (special_count) tty_schedule_flip(tty); }}#ifdef CONFIG_CYZ_INTRstatic irqreturn_t cyz_interrupt(int irq, void *dev_id){ struct cyclades_card *cinfo = dev_id; if (unlikely(cinfo == NULL)) {#ifdef CY_DEBUG_INTERRUPTS printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",irq);#endif return IRQ_NONE; /* spurious interrupt */ } if (unlikely(!ISZLOADED(*cinfo))) {#ifdef CY_DEBUG_INTERRUPTS printk(KERN_DEBUG "cyz_interrupt: board not yet loaded " "(IRQ%d).\n", irq);#endif return IRQ_NONE; } /* Handle the interrupts */ cyz_handle_cmd(cinfo); return IRQ_HANDLED;} /* cyz_interrupt */static void cyz_rx_restart(unsigned long arg){ struct cyclades_port *info = (struct cyclades_port *)arg; struct cyclades_card *card = info->card; int retval; __u32 channel = info->line - card->first_line; unsigned long flags; spin_lock_irqsave(&card->card_lock, flags); retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L); if (retval != 0) { printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n", info->line, retval); } spin_unlock_irqrestore(&card->card_lock, flags);}#else /* CONFIG_CYZ_INTR */static void cyz_poll(unsigned long arg){ struct cyclades_card *cinfo; struct cyclades_port *info; struct tty_struct *tty; struct FIRM_ID __iomem *firm_id; struct ZFW_CTRL __iomem *zfw_ctrl; struct BOARD_CTRL __iomem *board_ctrl; struct BUF_CTRL __iomem *buf_ctrl; unsigned long expires = jiffies + HZ; unsigned int port, card; for (card = 0; card < NR_CARDS; card++) { cinfo = &cy_card[card]; if (!IS_CYC_Z(*cinfo)) continue; if (!ISZLOADED(*cinfo)) continue; firm_id = cinfo->base_addr + ID_ADDRESS; zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &(zfw_ctrl->board_ctrl); /* Skip first polling cycle to avoid racing conditions with the FW */ if (!cinfo->intr_enabled) { cinfo->nports = (int)readl(&board_ctrl->n_channel); cinfo->intr_enabled = 1; continue; } cyz_handle_cmd(cinfo); for (port = 0; port < cinfo->nports; port++) { info = &cinfo->ports[port]; tty = info->tty; buf_ctrl = &(zfw_ctrl->buf_ctrl[port]); if (!info->throttle) cyz_handle_rx(info, buf_ctrl); cyz_handle_tx(info, buf_ctrl); } /* poll every 'cyz_polling_cycle' period */ expires = jiffies + cyz_polling_cycle; } mod_timer(&cyz_timerlist, expires);} /* cyz_poll */#endif /* CONFIG_CYZ_INTR *//********** End of block of Cyclades-Z specific code *********//***********************************************************//* This is called whenever a port becomes active; interrupts are enabled and DTR & RTS are turned on. */static int startup(struct cyclades_port *info){ struct cyclades_card *card; unsigned long flags; int retval = 0; void __iomem *base_addr; int chip, channel, index; unsigned long page; card = info->card; channel = info->line - card->first_line; page = get_zeroed_page(GFP_KERNEL); if (!page) return -ENOMEM; spin_lock_irqsave(&card->card_lock, flags); if (info->flags & ASYNC_INITIALIZED) { free_page(page); goto errout; } if (!info->type) { if (info->tty) { set_bit(TTY_IO_ERROR, &info->tty->flags); } free_page(page); goto errout; } if (info->xmit_buf) free_page(page); else info->xmit_buf = (unsigned char *)page; spin_unlock_irqrestore(&card->card_lock, flags); set_line_char(info); if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; index = card->bus_index; base_addr = card->base_addr + (cy_chip_offset[chip] << index);#ifdef CY_DEBUG_OPEN printk(KERN_DEBUG "cyc startup card %d, chip %d, channel %d, " "base_addr %p\n", card, chip, channel, base_addr);#endif spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); cy_writeb(base_addr + (CyRTPR << index), (info->default_timeout ? info->default_timeout : 0x02)); /* 10ms rx timeout */ cyy_issue_cmd(base_addr, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR, index); cy_writeb(base_addr + (CyCAR << index), (u_char) channel); cy_writeb(base_addr + (CyMSVR1 << index), CyRTS); cy_writeb(base_addr + (CyMSVR2 << index), CyDTR);#ifdef CY_DEBUG_DTR printk(KERN_DEBUG "cyc:startup raising DTR\n"); printk(KERN_DEBUG " status: 0x%x, 0x%x\n", readb(base_addr + (CyMSVR1 << index)), readb(base_addr + (CyMSVR2 << index)));#endif cy_writeb(base_addr + (CySRER << index), readb(base_addr + (CySRER << index)) | CyRxData); info->flags |= ASYNC_INITIALIZED; if (info->tty) { clear_bit(TTY_IO_ERROR, &info->tty->flags); } info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; info->breakon = info->breakoff = 0; memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); info->idle_stats.in_use = info->idle_stats.recv_idle = info->idle_stats.xmit_idle = jiffies; spin_unlock_irqrestore(&card->card_lock, flags); } else { struct FIRM_ID __iomem *firm_id; struct ZFW_CTRL __iomem *zfw_ctrl; struct BOARD_CTRL __iomem *board_ctrl; struct CH_CTRL __iomem *ch_ctrl; base_addr = card->base_addr; firm_id = base_addr + ID_ADDRESS; if (!ISZLOADED(*card)) { return -ENODEV; } zfw_ctrl = card->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl;#ifdef CY_DEBUG_OPEN printk(KERN_DEBUG "cyc startup Z card %d, channel %d, " "base_addr %p\n", card, channel, base_addr);#endif spin_lock_irqsave(&card->card_lock, flags); cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);#ifdef Z_WAKE#ifdef CONFIG_CYZ_INTR cy_writel(&ch_ctrl[channel].intr_enable, C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM | C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);#else cy_writel(&ch_ctrl[channel].intr_enable, C_IN_IOCTLW | C_IN_MDCD);#endif /* CONFIG_CYZ_INTR */#else#ifdef CONFIG_CYZ_INTR cy_writel(&ch_ctrl[channel].intr_enable, C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM | C_IN_RXNNDT | C_IN_MDCD);#else cy_writel(&ch_ctrl[channel].intr_enable, C_IN_MDCD);#endif /* CONFIG_CYZ_INTR */#endif /* Z_WAKE */ retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L); if (retval != 0) { printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was " "%x\n", info->line, retval); } /* Flush RX buffers before raising DTR and RTS */ retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L); if (retval != 0) { printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was " "%x\n", info->line, retval); } /* set timeout !!! */ /* set RTS and DTR !!! */ cy_writel(&ch_ctrl[channel].rs_control, readl(&ch_ctrl[channel].rs_control) | C_RS_RTS | C_RS_DTR); retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L); if (retval != 0) { printk(KERN_ERR "cyc:startup(3) retval on ttyC%d was " "%x\n", info->line, retval); }#ifdef CY_DEBUG_DTR printk(KERN_DEBUG "cyc:startup raising Z DTR\n");#endif /* enable send, recv, modem !!! */ info->flags |= ASYNC_INITIALIZED; if (info->tty) { clear_bit(TTY_IO_ERROR, &info->tty->flags); } info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; info->breakon = info->breakoff = 0; memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); info->idle_stats.in_use = info->idle_stats.recv_idle = info->idle_stats.xmit_idle = jiffies; spin_unlock_irqrestore(&card->card_lock, flags); }#ifdef CY_DEBUG_OPEN printk(KERN_DEBUG "cyc startup done\n");#endif return 0;errout: spin_unlock_irqrestore(&card->card_lock, flags); return retval;} /* startup */static void start_xmit(struct cyclades_port *info){ struct cyclades_card *card; unsigned long flags; void __iomem *base_addr; int chip, channel, index; card = info->card; channel = info->line - card->first_line; if (!IS_CYC_Z(*card)) { chip = channel >> 2; channel &= 0x03; index = card->bus_index; base_addr = card->base_addr + (cy_chip_offset[chip] << index); spin_lock_irqsave(&card->card_lock, flags); cy_writeb(base_addr + (CyCAR << index), channel); cy_writeb(base_addr + (CySRER << index), readb(base_addr + (CySRER << index)) | CyTxRdy); spin_unlock_irqrestore(&card->card_lock, flags); } else {#ifdef CONFIG_CYZ_INTR int retval; spin_lock_irqsave(&card->card_lock, flags); retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L); if (retval != 0) { printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was " "%x\n", info->line, retval); } spin_unlock_irqrestore(&card->card_lock, flags);#else /* CONFIG_CYZ_INTR */ /* Don't have
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?