icom.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,703 行 · 第 1/3 页
C
1,703 行
temp = readl(int_mask_tbl[port].global_int_mask); writel(temp & ~int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask); /* write flush */ readl(int_mask_tbl[port].global_int_mask); } else { dev_err(&icom_port->adapter->pci_dev->dev, "Invalid port assignment\n"); } spin_unlock_irqrestore(&icom_lock, flags); return 0;}static void shutdown(struct icom_port *icom_port){ unsigned long temp; unsigned char cmdReg; unsigned long flags; int port; spin_lock_irqsave(&icom_lock, flags); trace(icom_port, "SHUTDOWN", 0); /* * disable all interrupts */ port = icom_port->port; if (port == 0 || port == 1) int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask; else int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2; if (port < 4) { temp = readl(int_mask_tbl[port].global_int_mask); writel(temp | int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask); /* write flush */ readl(int_mask_tbl[port].global_int_mask); } else { dev_err(&icom_port->adapter->pci_dev->dev, "Invalid port assignment\n"); } spin_unlock_irqrestore(&icom_lock, flags); /* * disable break condition */ cmdReg = readb(&icom_port->dram->CmdReg); if ((cmdReg | CMD_SND_BREAK) == CMD_SND_BREAK) { writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg); }}static int icom_write(struct uart_port *port){ unsigned long data_count; unsigned char cmdReg; unsigned long offset; int temp_tail = port->info->xmit.tail; trace(ICOM_PORT, "WRITE", 0); if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) & SA_FLAGS_READY_TO_XMIT) { trace(ICOM_PORT, "WRITE_FULL", 0); return 0; } data_count = 0; while ((port->info->xmit.head != temp_tail) && (data_count <= XMIT_BUFF_SZ)) { ICOM_PORT->xmit_buf[data_count++] = port->info->xmit.buf[temp_tail]; temp_tail++; temp_tail &= (UART_XMIT_SIZE - 1); } if (data_count) { ICOM_PORT->statStg->xmit[0].flags = cpu_to_le16(SA_FLAGS_READY_TO_XMIT); ICOM_PORT->statStg->xmit[0].leLength = cpu_to_le16(data_count); offset = (unsigned long) &ICOM_PORT->statStg->xmit[0] - (unsigned long) ICOM_PORT->statStg; *ICOM_PORT->xmitRestart = cpu_to_le32(ICOM_PORT->statStg_pci + offset); cmdReg = readb(&ICOM_PORT->dram->CmdReg); writeb(cmdReg | CMD_XMIT_RCV_ENABLE, &ICOM_PORT->dram->CmdReg); writeb(START_XMIT, &ICOM_PORT->dram->StartXmitCmd); trace(ICOM_PORT, "WRITE_START", data_count); /* write flush */ readb(&ICOM_PORT->dram->StartXmitCmd); } return data_count;}static inline void check_modem_status(struct icom_port *icom_port){ static char old_status = 0; char delta_status; unsigned char status; spin_lock(&icom_port->uart_port.lock); /*modem input register */ status = readb(&icom_port->dram->isr); trace(icom_port, "CHECK_MODEM", status); delta_status = status ^ old_status; if (delta_status) { if (delta_status & ICOM_RI) icom_port->uart_port.icount.rng++; if (delta_status & ICOM_DSR) icom_port->uart_port.icount.dsr++; if (delta_status & ICOM_DCD) uart_handle_dcd_change(&icom_port->uart_port, delta_status & ICOM_DCD); if (delta_status & ICOM_CTS) uart_handle_cts_change(&icom_port->uart_port, delta_status & ICOM_CTS); wake_up_interruptible(&icom_port->uart_port.info-> delta_msr_wait); old_status = status; } spin_unlock(&icom_port->uart_port.lock);}static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port){ unsigned short int count; int i; if (port_int_reg & (INT_XMIT_COMPLETED)) { trace(icom_port, "XMIT_COMPLETE", 0); /* clear buffer in use bit */ icom_port->statStg->xmit[0].flags &= cpu_to_le16(~SA_FLAGS_READY_TO_XMIT); count = (unsigned short int) cpu_to_le16(icom_port->statStg->xmit[0].leLength); icom_port->uart_port.icount.tx += count; for (i=0; i<count && !uart_circ_empty(&icom_port->uart_port.info->xmit); i++) { icom_port->uart_port.info->xmit.tail++; icom_port->uart_port.info->xmit.tail &= (UART_XMIT_SIZE - 1); } if (!icom_write(&icom_port->uart_port)) /* activate write queue */ uart_write_wakeup(&icom_port->uart_port); } else trace(icom_port, "XMIT_DISABLED", 0);}static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port){ short int count, rcv_buff; struct tty_struct *tty = icom_port->uart_port.info->tty; unsigned short int status; struct uart_icount *icount; unsigned long offset; trace(icom_port, "RCV_COMPLETE", 0); rcv_buff = icom_port->next_rcv; status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags); while (status & SA_FL_RCV_DONE) { trace(icom_port, "FID_STATUS", status); count = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].leLength); trace(icom_port, "RCV_COUNT", count); if (count > (TTY_FLIPBUF_SIZE - tty->flip.count)) count = TTY_FLIPBUF_SIZE - tty->flip.count; trace(icom_port, "REAL_COUNT", count); offset = cpu_to_le32(icom_port->statStg->rcv[rcv_buff].leBuffer) - icom_port->recv_buf_pci; memcpy(tty->flip.char_buf_ptr,(unsigned char *) ((unsigned long)icom_port->recv_buf + offset), count); if (count > 0) { tty->flip.count += count - 1; tty->flip.char_buf_ptr += count - 1; memset(tty->flip.flag_buf_ptr, 0, count); tty->flip.flag_buf_ptr += count - 1; } icount = &icom_port->uart_port.icount; icount->rx += count; /* Break detect logic */ if ((status & SA_FLAGS_FRAME_ERROR) && (tty->flip.char_buf_ptr[0] == 0x00)) { status &= ~SA_FLAGS_FRAME_ERROR; status |= SA_FLAGS_BREAK_DET; trace(icom_port, "BREAK_DET", 0); } if (status & (SA_FLAGS_BREAK_DET | SA_FLAGS_PARITY_ERROR | SA_FLAGS_FRAME_ERROR | SA_FLAGS_OVERRUN)) { if (status & SA_FLAGS_BREAK_DET) icount->brk++; if (status & SA_FLAGS_PARITY_ERROR) icount->parity++; if (status & SA_FLAGS_FRAME_ERROR) icount->frame++; if (status & SA_FLAGS_OVERRUN) icount->overrun++; /* * Now check to see if character should be * ignored, and mask off conditions which * should be ignored. */ if (status & icom_port->ignore_status_mask) { trace(icom_port, "IGNORE_CHAR", 0); goto ignore_char; } status &= icom_port->read_status_mask; if (status & SA_FLAGS_BREAK_DET) { *tty->flip.flag_buf_ptr = TTY_BREAK; } else if (status & SA_FLAGS_PARITY_ERROR) { trace(icom_port, "PARITY_ERROR", 0); *tty->flip.flag_buf_ptr = TTY_PARITY; } else if (status & SA_FLAGS_FRAME_ERROR) *tty->flip.flag_buf_ptr = TTY_FRAME; if (status & SA_FLAGS_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; } } } tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; tty->flip.count++; ignore_char: icom_port->statStg->rcv[rcv_buff].flags = 0; icom_port->statStg->rcv[rcv_buff].leLength = 0; icom_port->statStg->rcv[rcv_buff].WorkingLength = (unsigned short int) cpu_to_le16(RCV_BUFF_SZ); rcv_buff++; if (rcv_buff == NUM_RBUFFS) rcv_buff = 0; status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags); } icom_port->next_rcv = rcv_buff; tty_flip_buffer_push(tty);}static void process_interrupt(u16 port_int_reg, struct icom_port *icom_port){ spin_lock(&icom_port->uart_port.lock); trace(icom_port, "INTERRUPT", port_int_reg); if (port_int_reg & (INT_XMIT_COMPLETED | INT_XMIT_DISABLED)) xmit_interrupt(port_int_reg, icom_port); if (port_int_reg & INT_RCV_COMPLETED) recv_interrupt(port_int_reg, icom_port); spin_unlock(&icom_port->uart_port.lock);}static irqreturn_t icom_interrupt(int irq, void *dev_id, struct pt_regs *regs){ unsigned long int_reg; u32 adapter_interrupts; u16 port_int_reg; struct icom_adapter *icom_adapter; struct icom_port *icom_port; /* find icom_port for this interrupt */ icom_adapter = (struct icom_adapter *) dev_id; if ((icom_adapter->version | ADAPTER_V2) == ADAPTER_V2) { int_reg = icom_adapter->base_addr + 0x8024; adapter_interrupts = readl((void *) int_reg); if (adapter_interrupts & 0x00003FFF) { /* port 2 interrupt, NOTE: for all ADAPTER_V2, port 2 will be active */ icom_port = &icom_adapter->port_info[2]; port_int_reg = (u16) adapter_interrupts; process_interrupt(port_int_reg, icom_port); check_modem_status(icom_port); } if (adapter_interrupts & 0x3FFF0000) { /* port 3 interrupt */ icom_port = &icom_adapter->port_info[3]; if (icom_port->status == ICOM_PORT_ACTIVE) { port_int_reg = (u16) (adapter_interrupts >> 16); process_interrupt(port_int_reg, icom_port); check_modem_status(icom_port); } } /* Clear out any pending interrupts */ writel(adapter_interrupts, (void *) int_reg); int_reg = icom_adapter->base_addr + 0x8004; } else { int_reg = icom_adapter->base_addr + 0x4004; } adapter_interrupts = readl((void *) int_reg); if (adapter_interrupts & 0x00003FFF) { /* port 0 interrupt, NOTE: for all adapters, port 0 will be active */ icom_port = &icom_adapter->port_info[0]; port_int_reg = (u16) adapter_interrupts; process_interrupt(port_int_reg, icom_port); check_modem_status(icom_port); } if (adapter_interrupts & 0x3FFF0000) { /* port 1 interrupt */ icom_port = &icom_adapter->port_info[1]; if (icom_port->status == ICOM_PORT_ACTIVE) { port_int_reg = (u16) (adapter_interrupts >> 16); process_interrupt(port_int_reg, icom_port); check_modem_status(icom_port); } } /* Clear out any pending interrupts */ writel(adapter_interrupts, (void *) int_reg); /* flush the write */ adapter_interrupts = readl((void *) int_reg); return IRQ_HANDLED;}/* * ------------------------------------------------------------------ * Begin serial-core API * ------------------------------------------------------------------ */static unsigned int icom_tx_empty(struct uart_port *port){ int ret; unsigned long flags; spin_lock_irqsave(&port->lock, flags); if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) & SA_FLAGS_READY_TO_XMIT) ret = TIOCSER_TEMT; else ret = 0; spin_unlock_irqrestore(&port->lock, flags); return ret;}static void icom_set_mctrl(struct uart_port *port, unsigned int mctrl){ unsigned char local_osr; trace(ICOM_PORT, "SET_MODEM", 0); local_osr = readb(&ICOM_PORT->dram->osr); if (mctrl & TIOCM_RTS) { trace(ICOM_PORT, "RAISE_RTS", 0); local_osr |= ICOM_RTS; } else { trace(ICOM_PORT, "LOWER_RTS", 0); local_osr &= ~ICOM_RTS; } if (mctrl & TIOCM_DTR) { trace(ICOM_PORT, "RAISE_DTR", 0); local_osr |= ICOM_DTR; } else { trace(ICOM_PORT, "LOWER_DTR", 0); local_osr &= ~ICOM_DTR; } writeb(local_osr, &ICOM_PORT->dram->osr);}static unsigned int icom_get_mctrl(struct uart_port *port){ unsigned char status; unsigned int result; trace(ICOM_PORT, "GET_MODEM", 0); status = readb(&ICOM_PORT->dram->isr); result = ((status & ICOM_DCD) ? TIOCM_CAR : 0) | ((status & ICOM_RI) ? TIOCM_RNG : 0) | ((status & ICOM_DSR) ? TIOCM_DSR : 0) | ((status & ICOM_CTS) ? TIOCM_CTS : 0); return result;}static void icom_stop_tx(struct uart_port *port, unsigned int tty_stop){ unsigned char cmdReg; if (tty_stop) { trace(ICOM_PORT, "STOP", 0); cmdReg = readb(&ICOM_PORT->dram->CmdReg); writeb(cmdReg | CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg); }}static void icom_start_tx(struct uart_port *port, unsigned int tty_start){ unsigned char cmdReg; trace(ICOM_PORT, "START", 0); cmdReg = readb(&ICOM_PORT->dram->CmdReg); if ((cmdReg & CMD_HOLD_XMIT) == CMD_HOLD_XMIT) writeb(cmdReg & ~CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg); icom_write(port);}static void icom_send_xchar(struct uart_port *port, char ch){ unsigned char xdata; int index; unsigned long flags; trace(ICOM_PORT, "SEND_XCHAR", ch); /* wait .1 sec to send char */ for (index = 0; index < 10; index++) { spin_lock_irqsave(&port->lock, flags); xdata = readb(&ICOM_PORT->dram->xchar); if (xdata == 0x00) { trace(ICOM_PORT, "QUICK_WRITE", 0); writeb(ch, &ICOM_PORT->dram->xchar); /* flush write operation */ xdata = readb(&ICOM_PORT->dram->xchar); spin_unlock_irqrestore(&port->lock, flags); break; } spin_unlock_irqrestore(&port->lock, flags); msleep(10); }}static void icom_stop_rx(struct uart_port *port){ unsigned char cmdReg; cmdReg = readb(&ICOM_PORT->dram->CmdReg); writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);}static void icom_enable_ms(struct uart_port *port){ /* no-op */}static void icom_break(struct uart_port *port, int break_state){ unsigned char cmdReg; unsigned long flags; spin_lock_irqsave(&port->lock, flags); trace(ICOM_PORT, "BREAK", 0); cmdReg = readb(&ICOM_PORT->dram->CmdReg); if (break_state == -1) { writeb(cmdReg | CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg); } else { writeb(cmdReg & ~CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg); } spin_unlock_irqrestore(&port->lock, flags);}static int icom_open(struct uart_port *port){ int retval; kobject_get(&ICOM_PORT->adapter->kobj); retval = startup(ICOM_PORT); if (retval) { kobject_put(&ICOM_PORT->adapter->kobj); trace(ICOM_PORT, "STARTUP_ERROR", 0); return retval; } return 0;}static void icom_close(struct uart_port *port){ unsigned char cmdReg; trace(ICOM_PORT, "CLOSE", 0); /* stop receiver */ cmdReg = readb(&ICOM_PORT->dram->CmdReg); writeb(cmdReg & (unsigned char) ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg); shutdown(ICOM_PORT); kobject_put(&ICOM_PORT->adapter->kobj);}static void icom_set_termios(struct uart_port *port, struct termios *termios, struct termios *old_termios){ int baud; unsigned cflag, iflag; int bits; char new_config2; char new_config3 = 0; char tmp_byte; int index; int rcv_buff, xmit_buff; unsigned long offset; unsigned long flags; spin_lock_irqsave(&port->lock, flags); trace(ICOM_PORT, "CHANGE_SPEED", 0); cflag = termios->c_cflag; iflag = termios->c_iflag; new_config2 = ICOM_ACFG_DRIVE1; /* byte size and parity */ switch (cflag & CSIZE) { case CS5: /* 5 bits/char */ new_config2 |= ICOM_ACFG_5BPC;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?