📄 jsm_neo.c
字号:
ch->ch_flags |= (CH_BAUD0); ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR); neo_assert_modem_signals(ch); ch->ch_old_baud = 0; return; } else if (ch->ch_custom_speed) { baud = ch->ch_custom_speed; if (ch->ch_flags & CH_BAUD0) ch->ch_flags &= ~(CH_BAUD0); } else { int iindex = 0; int jindex = 0; const u64 bauds[4][16] = { { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400 }, { 0, 57600, 115200, 230400, 460800, 150, 200, 921600, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400 }, { 0, 57600, 76800, 115200, 131657, 153600, 230400, 460800, 921600, 1200, 1800, 2400, 4800, 9600, 19200, 38400 }, { 0, 57600, 115200, 230400, 460800, 150, 200, 921600, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400 } }; baud = C_BAUD(ch->uart_port.info->tty) & 0xff; if (ch->ch_c_cflag & CBAUDEX) iindex = 1; jindex = baud; if ((iindex >= 0) && (iindex < 4) && (jindex >= 0) && (jindex < 16)) baud = bauds[iindex][jindex]; else { jsm_printk(IOCTL, DEBUG, &ch->ch_bd->pci_dev, "baud indices were out of range (%d)(%d)", iindex, jindex); baud = 0; } if (baud == 0) baud = 9600; if (ch->ch_flags & CH_BAUD0) ch->ch_flags &= ~(CH_BAUD0); } if (ch->ch_c_cflag & PARENB) lcr |= UART_LCR_PARITY; if (!(ch->ch_c_cflag & PARODD)) lcr |= UART_LCR_EPAR; /* * Not all platforms support mark/space parity, * so this will hide behind an ifdef. */#ifdef CMSPAR if (ch->ch_c_cflag & CMSPAR) lcr |= UART_LCR_SPAR;#endif if (ch->ch_c_cflag & CSTOPB) lcr |= UART_LCR_STOP; switch (ch->ch_c_cflag & CSIZE) { case CS5: lcr |= UART_LCR_WLEN5; break; case CS6: lcr |= UART_LCR_WLEN6; break; case CS7: lcr |= UART_LCR_WLEN7; break; case CS8: default: lcr |= UART_LCR_WLEN8; break; } ier = readb(&ch->ch_neo_uart->ier); uart_lcr = readb(&ch->ch_neo_uart->lcr); if (baud == 0) baud = 9600; quot = ch->ch_bd->bd_dividend / baud; if (quot != 0) { ch->ch_old_baud = baud; writeb(UART_LCR_DLAB, &ch->ch_neo_uart->lcr); writeb((quot & 0xff), &ch->ch_neo_uart->txrx); writeb((quot >> 8), &ch->ch_neo_uart->ier); writeb(lcr, &ch->ch_neo_uart->lcr); } if (uart_lcr != lcr) writeb(lcr, &ch->ch_neo_uart->lcr); if (ch->ch_c_cflag & CREAD) ier |= (UART_IER_RDI | UART_IER_RLSI); ier |= (UART_IER_THRI | UART_IER_MSI); writeb(ier, &ch->ch_neo_uart->ier); /* Set new start/stop chars */ neo_set_new_start_stop_chars(ch); if (ch->ch_c_cflag & CRTSCTS) neo_set_cts_flow_control(ch); else if (ch->ch_c_iflag & IXON) { /* If start/stop is set to disable, then we should disable flow control */ if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR)) neo_set_no_output_flow_control(ch); else neo_set_ixon_flow_control(ch); } else neo_set_no_output_flow_control(ch); if (ch->ch_c_cflag & CRTSCTS) neo_set_rts_flow_control(ch); else if (ch->ch_c_iflag & IXOFF) { /* If start/stop is set to disable, then we should disable flow control */ if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR)) neo_set_no_input_flow_control(ch); else neo_set_ixoff_flow_control(ch); } else neo_set_no_input_flow_control(ch); /* * Adjust the RX FIFO Trigger level if baud is less than 9600. * Not exactly elegant, but this is needed because of the Exar chip's * delay on firing off the RX FIFO interrupt on slower baud rates. */ if (baud < 9600) { writeb(1, &ch->ch_neo_uart->rfifo); ch->ch_r_tlevel = 1; } neo_assert_modem_signals(ch); /* Get current status of the modem signals now */ neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr)); return;}/* * jsm_neo_intr() * * Neo specific interrupt handler. */static irqreturn_t neo_intr(int irq, void *voidbrd, struct pt_regs *regs){ struct jsm_board *brd = (struct jsm_board *) voidbrd; struct jsm_channel *ch; int port = 0; int type = 0; int current_port; u32 tmp; u32 uart_poll; unsigned long lock_flags; unsigned long lock_flags2; int outofloop_count = 0; brd->intr_count++; /* Lock out the slow poller from running on this board. */ spin_lock_irqsave(&brd->bd_intr_lock, lock_flags); /* * Read in "extended" IRQ information from the 32bit Neo register. * Bits 0-7: What port triggered the interrupt. * Bits 8-31: Each 3bits indicate what type of interrupt occurred. */ uart_poll = readl(brd->re_map_membase + UART_17158_POLL_ADDR_OFFSET); jsm_printk(INTR, INFO, &brd->pci_dev, "%s:%d uart_poll: %x\n", __FILE__, __LINE__, uart_poll); if (!uart_poll) { jsm_printk(INTR, INFO, &brd->pci_dev, "Kernel interrupted to me, but no pending interrupts...\n"); spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags); return IRQ_NONE; } /* At this point, we have at least SOMETHING to service, dig further... */ current_port = 0; /* Loop on each port */ while (((uart_poll & 0xff) != 0) && (outofloop_count < 0xff)){ tmp = uart_poll; outofloop_count++; /* Check current port to see if it has interrupt pending */ if ((tmp & jsm_offset_table[current_port]) != 0) { port = current_port; type = tmp >> (8 + (port * 3)); type &= 0x7; } else { current_port++; continue; } jsm_printk(INTR, INFO, &brd->pci_dev, "%s:%d port: %x type: %x\n", __FILE__, __LINE__, port, type); /* Remove this port + type from uart_poll */ uart_poll &= ~(jsm_offset_table[port]); if (!type) { /* If no type, just ignore it, and move onto next port */ jsm_printk(INTR, ERR, &brd->pci_dev, "Interrupt with no type! port: %d\n", port); continue; } /* Switch on type of interrupt we have */ switch (type) { case UART_17158_RXRDY_TIMEOUT: /* * RXRDY Time-out is cleared by reading data in the * RX FIFO until it falls below the trigger level. */ /* Verify the port is in range. */ if (port > brd->nasync) continue; ch = brd->channels[port]; neo_copy_data_from_uart_to_queue(ch); /* Call our tty layer to enforce queue flow control if needed. */ spin_lock_irqsave(&ch->ch_lock, lock_flags2); jsm_check_queue_flow_control(ch); spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); continue; case UART_17158_RX_LINE_STATUS: /* * RXRDY and RX LINE Status (logic OR of LSR[4:1]) */ neo_parse_lsr(brd, port); continue; case UART_17158_TXRDY: /* * TXRDY interrupt clears after reading ISR register for the UART channel. */ /* * Yes, this is odd... * Why would I check EVERY possibility of type of * interrupt, when we know its TXRDY??? * Becuz for some reason, even tho we got triggered for TXRDY, * it seems to be occassionally wrong. Instead of TX, which * it should be, I was getting things like RXDY too. Weird. */ neo_parse_isr(brd, port); continue; case UART_17158_MSR: /* * MSR or flow control was seen. */ neo_parse_isr(brd, port); continue; default: /* * The UART triggered us with a bogus interrupt type. * It appears the Exar chip, when REALLY bogged down, will throw * these once and awhile. * Its harmless, just ignore it and move on. */ jsm_printk(INTR, ERR, &brd->pci_dev, "%s:%d Unknown Interrupt type: %x\n", __FILE__, __LINE__, type); continue; } } spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags); jsm_printk(INTR, INFO, &brd->pci_dev, "finish.\n"); return IRQ_HANDLED;}/* * Neo specific way of turning off the receiver. * Used as a way to enforce queue flow control when in * hardware flow control mode. */static void neo_disable_receiver(struct jsm_channel *ch){ u8 tmp = readb(&ch->ch_neo_uart->ier); tmp &= ~(UART_IER_RDI); writeb(tmp, &ch->ch_neo_uart->ier); /* flush write operation */ neo_pci_posting_flush(ch->ch_bd);}/* * Neo specific way of turning on the receiver. * Used as a way to un-enforce queue flow control when in * hardware flow control mode. */static void neo_enable_receiver(struct jsm_channel *ch){ u8 tmp = readb(&ch->ch_neo_uart->ier); tmp |= (UART_IER_RDI); writeb(tmp, &ch->ch_neo_uart->ier); /* flush write operation */ neo_pci_posting_flush(ch->ch_bd);}static void neo_send_start_character(struct jsm_channel *ch){ if (!ch) return; if (ch->ch_startc != __DISABLED_CHAR) { ch->ch_xon_sends++; writeb(ch->ch_startc, &ch->ch_neo_uart->txrx); /* flush write operation */ neo_pci_posting_flush(ch->ch_bd); }}static void neo_send_stop_character(struct jsm_channel *ch){ if (!ch) return; if (ch->ch_stopc != __DISABLED_CHAR) { ch->ch_xoff_sends++; writeb(ch->ch_stopc, &ch->ch_neo_uart->txrx); /* flush write operation */ neo_pci_posting_flush(ch->ch_bd); }}/* * neo_uart_init */static void neo_uart_init(struct jsm_channel *ch){ writeb(0, &ch->ch_neo_uart->ier); writeb(0, &ch->ch_neo_uart->efr); writeb(UART_EFR_ECB, &ch->ch_neo_uart->efr); /* Clear out UART and FIFO */ readb(&ch->ch_neo_uart->txrx); writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr); readb(&ch->ch_neo_uart->lsr); readb(&ch->ch_neo_uart->msr); ch->ch_flags |= CH_FIFO_ENABLED; /* Assert any signals we want up */ writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr);}/* * Make the UART completely turn off. */static void neo_uart_off(struct jsm_channel *ch){ /* Turn off UART enhanced bits */ writeb(0, &ch->ch_neo_uart->efr); /* Stop all interrupts from occurring. */ writeb(0, &ch->ch_neo_uart->ier);}static u32 neo_get_uart_bytes_left(struct jsm_channel *ch){ u8 left = 0; u8 lsr = readb(&ch->ch_neo_uart->lsr); /* We must cache the LSR as some of the bits get reset once read... */ ch->ch_cached_lsr |= lsr; /* Determine whether the Transmitter is empty or not */ if (!(lsr & UART_LSR_TEMT)) left = 1; else { ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); left = 0; } return left;}/* Channel lock MUST be held by the calling function! */static void neo_send_break(struct jsm_channel *ch){ /* * Set the time we should stop sending the break. * If we are already sending a break, toss away the existing * time to stop, and use this new value instead. */ /* Tell the UART to start sending the break */ if (!(ch->ch_flags & CH_BREAK_SENDING)) { u8 temp = readb(&ch->ch_neo_uart->lcr); writeb((temp | UART_LCR_SBC), &ch->ch_neo_uart->lcr); ch->ch_flags |= (CH_BREAK_SENDING); /* flush write operation */ neo_pci_posting_flush(ch->ch_bd); }}/* * neo_send_immediate_char. * * Sends a specific character as soon as possible to the UART, * jumping over any bytes that might be in the write queue. * * The channel lock MUST be held by the calling function. */static void neo_send_immediate_char(struct jsm_channel *ch, unsigned char c){ if (!ch) return; writeb(c, &ch->ch_neo_uart->txrx); /* flush write operation */ neo_pci_posting_flush(ch->ch_bd);}struct board_ops jsm_neo_ops = { .intr = neo_intr, .uart_init = neo_uart_init, .uart_off = neo_uart_off, .param = neo_param, .assert_modem_signals = neo_assert_modem_signals, .flush_uart_write = neo_flush_uart_write, .flush_uart_read = neo_flush_uart_read, .disable_receiver = neo_disable_receiver, .enable_receiver = neo_enable_receiver, .send_break = neo_send_break, .clear_break = neo_clear_break, .send_start_character = neo_send_start_character, .send_stop_character = neo_send_stop_character, .copy_data_from_queue_to_uart = neo_copy_data_from_queue_to_uart, .get_uart_bytes_left = neo_get_uart_bytes_left, .send_immediate_char = neo_send_immediate_char};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -