⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jsm_neo.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/************************************************************************ * 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 + -