📄 jsm_neo.c
字号:
/************************************************************************ * Copyright 2003 Digi International (www.digi.com) * * Copyright (C) 2004 IBM Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 * Temple Place - Suite 330, Boston, * MA 02111-1307, USA. * * Contact Information: * Scott H Kilau <Scott_Kilau@digi.com> * Wendy Xiong <wendyx@us.ltcfwd.linux.ibm.com> * ***********************************************************************/#include <linux/delay.h> /* For udelay */#include <linux/serial_reg.h> /* For the various UART offsets */#include <linux/tty.h>#include <linux/pci.h>#include <asm/io.h>#include "jsm.h" /* Driver main header file */static u32 jsm_offset_table[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };/* * This function allows calls to ensure that all outstanding * PCI writes have been completed, by doing a PCI read against * a non-destructive, read-only location on the Neo card. * * In this case, we are reading the DVID (Read-only Device Identification) * value of the Neo card. */static inline void neo_pci_posting_flush(struct jsm_board *bd){ readb(bd->re_map_membase + 0x8D);}static void neo_set_cts_flow_control(struct jsm_channel *ch){ u8 ier, efr; ier = readb(&ch->ch_neo_uart->ier); efr = readb(&ch->ch_neo_uart->efr); jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting CTSFLOW\n"); /* Turn on auto CTS flow control */ ier |= (UART_17158_IER_CTSDSR); efr |= (UART_17158_EFR_ECB | UART_17158_EFR_CTSDSR); /* Turn off auto Xon flow control */ efr &= ~(UART_17158_EFR_IXON); /* Why? Becuz Exar's spec says we have to zero it out before setting it */ writeb(0, &ch->ch_neo_uart->efr); /* Turn on UART enhanced bits */ writeb(efr, &ch->ch_neo_uart->efr); /* Turn on table D, with 8 char hi/low watermarks */ writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr); /* Feed the UART our trigger levels */ writeb(8, &ch->ch_neo_uart->tfifo); ch->ch_t_tlevel = 8; writeb(ier, &ch->ch_neo_uart->ier);}static void neo_set_rts_flow_control(struct jsm_channel *ch){ u8 ier, efr; ier = readb(&ch->ch_neo_uart->ier); efr = readb(&ch->ch_neo_uart->efr); jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting RTSFLOW\n"); /* Turn on auto RTS flow control */ ier |= (UART_17158_IER_RTSDTR); efr |= (UART_17158_EFR_ECB | UART_17158_EFR_RTSDTR); /* Turn off auto Xoff flow control */ ier &= ~(UART_17158_IER_XOFF); efr &= ~(UART_17158_EFR_IXOFF); /* Why? Becuz Exar's spec says we have to zero it out before setting it */ writeb(0, &ch->ch_neo_uart->efr); /* Turn on UART enhanced bits */ writeb(efr, &ch->ch_neo_uart->efr); writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr); ch->ch_r_watermark = 4; writeb(56, &ch->ch_neo_uart->rfifo); ch->ch_r_tlevel = 56; writeb(ier, &ch->ch_neo_uart->ier); /* * From the Neo UART spec sheet: * The auto RTS/DTR function must be started by asserting * RTS/DTR# output pin (MCR bit-0 or 1 to logic 1 after * it is enabled. */ ch->ch_mostat |= (UART_MCR_RTS);}static void neo_set_ixon_flow_control(struct jsm_channel *ch){ u8 ier, efr; ier = readb(&ch->ch_neo_uart->ier); efr = readb(&ch->ch_neo_uart->efr); jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXON FLOW\n"); /* Turn off auto CTS flow control */ ier &= ~(UART_17158_IER_CTSDSR); efr &= ~(UART_17158_EFR_CTSDSR); /* Turn on auto Xon flow control */ efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXON); /* Why? Becuz Exar's spec says we have to zero it out before setting it */ writeb(0, &ch->ch_neo_uart->efr); /* Turn on UART enhanced bits */ writeb(efr, &ch->ch_neo_uart->efr); writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr); ch->ch_r_watermark = 4; writeb(32, &ch->ch_neo_uart->rfifo); ch->ch_r_tlevel = 32; /* Tell UART what start/stop chars it should be looking for */ writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1); writeb(0, &ch->ch_neo_uart->xonchar2); writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1); writeb(0, &ch->ch_neo_uart->xoffchar2); writeb(ier, &ch->ch_neo_uart->ier);}static void neo_set_ixoff_flow_control(struct jsm_channel *ch){ u8 ier, efr; ier = readb(&ch->ch_neo_uart->ier); efr = readb(&ch->ch_neo_uart->efr); jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Setting IXOFF FLOW\n"); /* Turn off auto RTS flow control */ ier &= ~(UART_17158_IER_RTSDTR); efr &= ~(UART_17158_EFR_RTSDTR); /* Turn on auto Xoff flow control */ ier |= (UART_17158_IER_XOFF); efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXOFF); /* Why? Becuz Exar's spec says we have to zero it out before setting it */ writeb(0, &ch->ch_neo_uart->efr); /* Turn on UART enhanced bits */ writeb(efr, &ch->ch_neo_uart->efr); /* Turn on table D, with 8 char hi/low watermarks */ writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr); writeb(8, &ch->ch_neo_uart->tfifo); ch->ch_t_tlevel = 8; /* Tell UART what start/stop chars it should be looking for */ writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1); writeb(0, &ch->ch_neo_uart->xonchar2); writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1); writeb(0, &ch->ch_neo_uart->xoffchar2); writeb(ier, &ch->ch_neo_uart->ier);}static void neo_set_no_input_flow_control(struct jsm_channel *ch){ u8 ier, efr; ier = readb(&ch->ch_neo_uart->ier); efr = readb(&ch->ch_neo_uart->efr); jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Input FLOW\n"); /* Turn off auto RTS flow control */ ier &= ~(UART_17158_IER_RTSDTR); efr &= ~(UART_17158_EFR_RTSDTR); /* Turn off auto Xoff flow control */ ier &= ~(UART_17158_IER_XOFF); if (ch->ch_c_iflag & IXON) efr &= ~(UART_17158_EFR_IXOFF); else efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXOFF); /* Why? Becuz Exar's spec says we have to zero it out before setting it */ writeb(0, &ch->ch_neo_uart->efr); /* Turn on UART enhanced bits */ writeb(efr, &ch->ch_neo_uart->efr); /* Turn on table D, with 8 char hi/low watermarks */ writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr); ch->ch_r_watermark = 0; writeb(16, &ch->ch_neo_uart->tfifo); ch->ch_t_tlevel = 16; writeb(16, &ch->ch_neo_uart->rfifo); ch->ch_r_tlevel = 16; writeb(ier, &ch->ch_neo_uart->ier);}static void neo_set_no_output_flow_control(struct jsm_channel *ch){ u8 ier, efr; ier = readb(&ch->ch_neo_uart->ier); efr = readb(&ch->ch_neo_uart->efr); jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "Unsetting Output FLOW\n"); /* Turn off auto CTS flow control */ ier &= ~(UART_17158_IER_CTSDSR); efr &= ~(UART_17158_EFR_CTSDSR); /* Turn off auto Xon flow control */ if (ch->ch_c_iflag & IXOFF) efr &= ~(UART_17158_EFR_IXON); else efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXON); /* Why? Becuz Exar's spec says we have to zero it out before setting it */ writeb(0, &ch->ch_neo_uart->efr); /* Turn on UART enhanced bits */ writeb(efr, &ch->ch_neo_uart->efr); /* Turn on table D, with 8 char hi/low watermarks */ writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr); ch->ch_r_watermark = 0; writeb(16, &ch->ch_neo_uart->tfifo); ch->ch_t_tlevel = 16; writeb(16, &ch->ch_neo_uart->rfifo); ch->ch_r_tlevel = 16; writeb(ier, &ch->ch_neo_uart->ier);}static inline void neo_set_new_start_stop_chars(struct jsm_channel *ch){ /* if hardware flow control is set, then skip this whole thing */ if (ch->ch_c_cflag & CRTSCTS) return; jsm_printk(PARAM, INFO, &ch->ch_bd->pci_dev, "start\n"); /* Tell UART what start/stop chars it should be looking for */ writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1); writeb(0, &ch->ch_neo_uart->xonchar2); writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1); writeb(0, &ch->ch_neo_uart->xoffchar2);}static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch){ int qleft = 0; u8 linestatus = 0; u8 error_mask = 0; int n = 0; int total = 0; u16 head; u16 tail; if (!ch) return; /* cache head and tail of queue */ head = ch->ch_r_head & RQUEUEMASK; tail = ch->ch_r_tail & RQUEUEMASK; /* Get our cached LSR */ linestatus = ch->ch_cached_lsr; ch->ch_cached_lsr = 0; /* Store how much space we have left in the queue */ if ((qleft = tail - head - 1) < 0) qleft += RQUEUEMASK + 1; /* * If the UART is not in FIFO mode, force the FIFO copy to * NOT be run, by setting total to 0. * * On the other hand, if the UART IS in FIFO mode, then ask * the UART to give us an approximation of data it has RX'ed. */ if (!(ch->ch_flags & CH_FIFO_ENABLED)) total = 0; else { total = readb(&ch->ch_neo_uart->rfifo); /* * EXAR chip bug - RX FIFO COUNT - Fudge factor. * * This resolves a problem/bug with the Exar chip that sometimes * returns a bogus value in the rfifo register. * The count can be any where from 0-3 bytes "off". * Bizarre, but true. */ total -= 3; } /* * Finally, bound the copy to make sure we don't overflow * our own queue... * The byte by byte copy loop below this loop this will * deal with the queue overflow possibility. */ total = min(total, qleft); while (total > 0) { /* * Grab the linestatus register, we need to check * to see if there are any errors in the FIFO. */ linestatus = readb(&ch->ch_neo_uart->lsr); /* * Break out if there is a FIFO error somewhere. * This will allow us to go byte by byte down below, * finding the exact location of the error. */ if (linestatus & UART_17158_RX_FIFO_DATA_ERROR) break; /* Make sure we don't go over the end of our queue */ n = min(((u32) total), (RQUEUESIZE - (u32) head)); /* * Cut down n even further if needed, this is to fix * a problem with memcpy_fromio() with the Neo on the * IBM pSeries platform. * 15 bytes max appears to be the magic number. */ n = min((u32) n, (u32) 12); /* * Since we are grabbing the linestatus register, which * will reset some bits after our read, we need to ensure * we don't miss our TX FIFO emptys. */ if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR)) ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); linestatus = 0; /* Copy data from uart to the queue */ memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, n); /* * Since RX_FIFO_DATA_ERROR was 0, we are guarenteed * that all the data currently in the FIFO is free of * breaks and parity/frame/orun errors. */ memset(ch->ch_equeue + head, 0, n); /* Add to and flip head if needed */ head = (head + n) & RQUEUEMASK; total -= n; qleft -= n; ch->ch_rxcount += n; } /* * Create a mask to determine whether we should * insert the character (if any) into our queue. */ if (ch->ch_c_iflag & IGNBRK) error_mask |= UART_LSR_BI; /* * Now cleanup any leftover bytes still in the UART. * Also deal with any possible queue overflow here as well. */ while (1) { /* * Its possible we have a linestatus from the loop above * this, so we "OR" on any extra bits. */ linestatus |= readb(&ch->ch_neo_uart->lsr); /* * If the chip tells us there is no more data pending to * be read, we can then leave. * But before we do, cache the linestatus, just in case. */ if (!(linestatus & UART_LSR_DR)) { ch->ch_cached_lsr = linestatus; break; } /* No need to store this bit */ linestatus &= ~UART_LSR_DR; /* * Since we are grabbing the linestatus register, which * will reset some bits after our read, we need to ensure * we don't miss our TX FIFO emptys. */ if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR)) { linestatus &= ~(UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR); ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); } /* * Discard character if we are ignoring the error mask. */ if (linestatus & error_mask) { u8 discard; linestatus = 0; memcpy_fromio(&discard, &ch->ch_neo_uart->txrxburst, 1); continue; } /* * If our queue is full, we have no choice but to drop some data. * The assumption is that HWFLOW or SWFLOW should have stopped * things way way before we got to this point. * * I decided that I wanted to ditch the oldest data first, * I hope thats okay with everyone? Yes? Good. */ while (qleft < 1) { jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Queue full, dropping DATA:%x LSR:%x\n", ch->ch_rqueue[tail], ch->ch_equeue[tail]); ch->ch_r_tail = tail = (tail + 1) & RQUEUEMASK; ch->ch_err_overrun++; qleft++; } memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, 1); ch->ch_equeue[head] = (u8) linestatus; jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "DATA/LSR pair: %x %x\n", ch->ch_rqueue[head], ch->ch_equeue[head]); /* Ditch any remaining linestatus value. */ linestatus = 0; /* Add to and flip head if needed */ head = (head + 1) & RQUEUEMASK;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -