xref: /OK3568_Linux_fs/kernel/drivers/tty/serial/jsm/jsm_cls.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright 2003 Digi International (www.digi.com)
4*4882a593Smuzhiyun  *	Scott H Kilau <Scott_Kilau at digi dot com>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  *	NOTE TO LINUX KERNEL HACKERS:  DO NOT REFORMAT THIS CODE!
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *	This is shared code between Digi's CVS archive and the
9*4882a593Smuzhiyun  *	Linux Kernel sources.
10*4882a593Smuzhiyun  *	Changing the source just for reformatting needlessly breaks
11*4882a593Smuzhiyun  *	our CVS diff history.
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  *	Send any bug fixes/changes to:  Eng.Linux at digi dot com.
14*4882a593Smuzhiyun  *	Thank you.
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  */
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <linux/delay.h>	/* For udelay */
19*4882a593Smuzhiyun #include <linux/io.h>		/* For read[bwl]/write[bwl] */
20*4882a593Smuzhiyun #include <linux/serial.h>	/* For struct async_serial */
21*4882a593Smuzhiyun #include <linux/serial_reg.h>	/* For the various UART offsets */
22*4882a593Smuzhiyun #include <linux/pci.h>
23*4882a593Smuzhiyun #include <linux/tty.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #include "jsm.h"	/* Driver main header file */
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun static struct {
28*4882a593Smuzhiyun 	unsigned int rate;
29*4882a593Smuzhiyun 	unsigned int cflag;
30*4882a593Smuzhiyun } baud_rates[] = {
31*4882a593Smuzhiyun 	{ 921600, B921600 },
32*4882a593Smuzhiyun 	{ 460800, B460800 },
33*4882a593Smuzhiyun 	{ 230400, B230400 },
34*4882a593Smuzhiyun 	{ 115200, B115200 },
35*4882a593Smuzhiyun 	{  57600, B57600  },
36*4882a593Smuzhiyun 	{  38400, B38400  },
37*4882a593Smuzhiyun 	{  19200, B19200  },
38*4882a593Smuzhiyun 	{   9600, B9600   },
39*4882a593Smuzhiyun 	{   4800, B4800   },
40*4882a593Smuzhiyun 	{   2400, B2400   },
41*4882a593Smuzhiyun 	{   1200, B1200   },
42*4882a593Smuzhiyun 	{    600, B600    },
43*4882a593Smuzhiyun 	{    300, B300    },
44*4882a593Smuzhiyun 	{    200, B200    },
45*4882a593Smuzhiyun 	{    150, B150    },
46*4882a593Smuzhiyun 	{    134, B134    },
47*4882a593Smuzhiyun 	{    110, B110    },
48*4882a593Smuzhiyun 	{     75, B75     },
49*4882a593Smuzhiyun 	{     50, B50     },
50*4882a593Smuzhiyun };
51*4882a593Smuzhiyun 
cls_set_cts_flow_control(struct jsm_channel * ch)52*4882a593Smuzhiyun static void cls_set_cts_flow_control(struct jsm_channel *ch)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun 	u8 lcrb = readb(&ch->ch_cls_uart->lcr);
55*4882a593Smuzhiyun 	u8 ier = readb(&ch->ch_cls_uart->ier);
56*4882a593Smuzhiyun 	u8 isr_fcr = 0;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	/*
59*4882a593Smuzhiyun 	 * The Enhanced Register Set may only be accessed when
60*4882a593Smuzhiyun 	 * the Line Control Register is set to 0xBFh.
61*4882a593Smuzhiyun 	 */
62*4882a593Smuzhiyun 	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	/* Turn on CTS flow control, turn off IXON flow control */
67*4882a593Smuzhiyun 	isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_CTSDSR);
68*4882a593Smuzhiyun 	isr_fcr &= ~(UART_EXAR654_EFR_IXON);
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	/* Write old LCR value back out, which turns enhanced access off */
73*4882a593Smuzhiyun 	writeb(lcrb, &ch->ch_cls_uart->lcr);
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	/*
76*4882a593Smuzhiyun 	 * Enable interrupts for CTS flow, turn off interrupts for
77*4882a593Smuzhiyun 	 * received XOFF chars
78*4882a593Smuzhiyun 	 */
79*4882a593Smuzhiyun 	ier |= (UART_EXAR654_IER_CTSDSR);
80*4882a593Smuzhiyun 	ier &= ~(UART_EXAR654_IER_XOFF);
81*4882a593Smuzhiyun 	writeb(ier, &ch->ch_cls_uart->ier);
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	/* Set the usual FIFO values */
84*4882a593Smuzhiyun 	writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 |
87*4882a593Smuzhiyun 		UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
88*4882a593Smuzhiyun 		&ch->ch_cls_uart->isr_fcr);
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	ch->ch_t_tlevel = 16;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun 
cls_set_ixon_flow_control(struct jsm_channel * ch)93*4882a593Smuzhiyun static void cls_set_ixon_flow_control(struct jsm_channel *ch)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun 	u8 lcrb = readb(&ch->ch_cls_uart->lcr);
96*4882a593Smuzhiyun 	u8 ier = readb(&ch->ch_cls_uart->ier);
97*4882a593Smuzhiyun 	u8 isr_fcr = 0;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	/*
100*4882a593Smuzhiyun 	 * The Enhanced Register Set may only be accessed when
101*4882a593Smuzhiyun 	 * the Line Control Register is set to 0xBFh.
102*4882a593Smuzhiyun 	 */
103*4882a593Smuzhiyun 	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	/* Turn on IXON flow control, turn off CTS flow control */
108*4882a593Smuzhiyun 	isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXON);
109*4882a593Smuzhiyun 	isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR);
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	/* Now set our current start/stop chars while in enhanced mode */
114*4882a593Smuzhiyun 	writeb(ch->ch_startc, &ch->ch_cls_uart->mcr);
115*4882a593Smuzhiyun 	writeb(0, &ch->ch_cls_uart->lsr);
116*4882a593Smuzhiyun 	writeb(ch->ch_stopc, &ch->ch_cls_uart->msr);
117*4882a593Smuzhiyun 	writeb(0, &ch->ch_cls_uart->spr);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	/* Write old LCR value back out, which turns enhanced access off */
120*4882a593Smuzhiyun 	writeb(lcrb, &ch->ch_cls_uart->lcr);
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	/*
123*4882a593Smuzhiyun 	 * Disable interrupts for CTS flow, turn on interrupts for
124*4882a593Smuzhiyun 	 * received XOFF chars
125*4882a593Smuzhiyun 	 */
126*4882a593Smuzhiyun 	ier &= ~(UART_EXAR654_IER_CTSDSR);
127*4882a593Smuzhiyun 	ier |= (UART_EXAR654_IER_XOFF);
128*4882a593Smuzhiyun 	writeb(ier, &ch->ch_cls_uart->ier);
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	/* Set the usual FIFO values */
131*4882a593Smuzhiyun 	writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
134*4882a593Smuzhiyun 		UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
135*4882a593Smuzhiyun 		&ch->ch_cls_uart->isr_fcr);
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun 
cls_set_no_output_flow_control(struct jsm_channel * ch)138*4882a593Smuzhiyun static void cls_set_no_output_flow_control(struct jsm_channel *ch)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	u8 lcrb = readb(&ch->ch_cls_uart->lcr);
141*4882a593Smuzhiyun 	u8 ier = readb(&ch->ch_cls_uart->ier);
142*4882a593Smuzhiyun 	u8 isr_fcr = 0;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	/*
145*4882a593Smuzhiyun 	 * The Enhanced Register Set may only be accessed when
146*4882a593Smuzhiyun 	 * the Line Control Register is set to 0xBFh.
147*4882a593Smuzhiyun 	 */
148*4882a593Smuzhiyun 	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	/* Turn off IXON flow control, turn off CTS flow control */
153*4882a593Smuzhiyun 	isr_fcr |= (UART_EXAR654_EFR_ECB);
154*4882a593Smuzhiyun 	isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR | UART_EXAR654_EFR_IXON);
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	/* Write old LCR value back out, which turns enhanced access off */
159*4882a593Smuzhiyun 	writeb(lcrb, &ch->ch_cls_uart->lcr);
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	/*
162*4882a593Smuzhiyun 	 * Disable interrupts for CTS flow, turn off interrupts for
163*4882a593Smuzhiyun 	 * received XOFF chars
164*4882a593Smuzhiyun 	 */
165*4882a593Smuzhiyun 	ier &= ~(UART_EXAR654_IER_CTSDSR);
166*4882a593Smuzhiyun 	ier &= ~(UART_EXAR654_IER_XOFF);
167*4882a593Smuzhiyun 	writeb(ier, &ch->ch_cls_uart->ier);
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	/* Set the usual FIFO values */
170*4882a593Smuzhiyun 	writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
173*4882a593Smuzhiyun 		UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
174*4882a593Smuzhiyun 		&ch->ch_cls_uart->isr_fcr);
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	ch->ch_r_watermark = 0;
177*4882a593Smuzhiyun 	ch->ch_t_tlevel = 16;
178*4882a593Smuzhiyun 	ch->ch_r_tlevel = 16;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
cls_set_rts_flow_control(struct jsm_channel * ch)181*4882a593Smuzhiyun static void cls_set_rts_flow_control(struct jsm_channel *ch)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	u8 lcrb = readb(&ch->ch_cls_uart->lcr);
184*4882a593Smuzhiyun 	u8 ier = readb(&ch->ch_cls_uart->ier);
185*4882a593Smuzhiyun 	u8 isr_fcr = 0;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	/*
188*4882a593Smuzhiyun 	 * The Enhanced Register Set may only be accessed when
189*4882a593Smuzhiyun 	 * the Line Control Register is set to 0xBFh.
190*4882a593Smuzhiyun 	 */
191*4882a593Smuzhiyun 	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	/* Turn on RTS flow control, turn off IXOFF flow control */
196*4882a593Smuzhiyun 	isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_RTSDTR);
197*4882a593Smuzhiyun 	isr_fcr &= ~(UART_EXAR654_EFR_IXOFF);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	/* Write old LCR value back out, which turns enhanced access off */
202*4882a593Smuzhiyun 	writeb(lcrb, &ch->ch_cls_uart->lcr);
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	/* Enable interrupts for RTS flow */
205*4882a593Smuzhiyun 	ier |= (UART_EXAR654_IER_RTSDTR);
206*4882a593Smuzhiyun 	writeb(ier, &ch->ch_cls_uart->ier);
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	/* Set the usual FIFO values */
209*4882a593Smuzhiyun 	writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 |
212*4882a593Smuzhiyun 		UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
213*4882a593Smuzhiyun 		&ch->ch_cls_uart->isr_fcr);
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	ch->ch_r_watermark = 4;
216*4882a593Smuzhiyun 	ch->ch_r_tlevel = 8;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun 
cls_set_ixoff_flow_control(struct jsm_channel * ch)219*4882a593Smuzhiyun static void cls_set_ixoff_flow_control(struct jsm_channel *ch)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun 	u8 lcrb = readb(&ch->ch_cls_uart->lcr);
222*4882a593Smuzhiyun 	u8 ier = readb(&ch->ch_cls_uart->ier);
223*4882a593Smuzhiyun 	u8 isr_fcr = 0;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	/*
226*4882a593Smuzhiyun 	 * The Enhanced Register Set may only be accessed when
227*4882a593Smuzhiyun 	 * the Line Control Register is set to 0xBFh.
228*4882a593Smuzhiyun 	 */
229*4882a593Smuzhiyun 	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	/* Turn on IXOFF flow control, turn off RTS flow control */
234*4882a593Smuzhiyun 	isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXOFF);
235*4882a593Smuzhiyun 	isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR);
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	/* Now set our current start/stop chars while in enhanced mode */
240*4882a593Smuzhiyun 	writeb(ch->ch_startc, &ch->ch_cls_uart->mcr);
241*4882a593Smuzhiyun 	writeb(0, &ch->ch_cls_uart->lsr);
242*4882a593Smuzhiyun 	writeb(ch->ch_stopc, &ch->ch_cls_uart->msr);
243*4882a593Smuzhiyun 	writeb(0, &ch->ch_cls_uart->spr);
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	/* Write old LCR value back out, which turns enhanced access off */
246*4882a593Smuzhiyun 	writeb(lcrb, &ch->ch_cls_uart->lcr);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	/* Disable interrupts for RTS flow */
249*4882a593Smuzhiyun 	ier &= ~(UART_EXAR654_IER_RTSDTR);
250*4882a593Smuzhiyun 	writeb(ier, &ch->ch_cls_uart->ier);
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	/* Set the usual FIFO values */
253*4882a593Smuzhiyun 	writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
256*4882a593Smuzhiyun 		UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
257*4882a593Smuzhiyun 		&ch->ch_cls_uart->isr_fcr);
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun 
cls_set_no_input_flow_control(struct jsm_channel * ch)260*4882a593Smuzhiyun static void cls_set_no_input_flow_control(struct jsm_channel *ch)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun 	u8 lcrb = readb(&ch->ch_cls_uart->lcr);
263*4882a593Smuzhiyun 	u8 ier = readb(&ch->ch_cls_uart->ier);
264*4882a593Smuzhiyun 	u8 isr_fcr = 0;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	/*
267*4882a593Smuzhiyun 	 * The Enhanced Register Set may only be accessed when
268*4882a593Smuzhiyun 	 * the Line Control Register is set to 0xBFh.
269*4882a593Smuzhiyun 	 */
270*4882a593Smuzhiyun 	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	/* Turn off IXOFF flow control, turn off RTS flow control */
275*4882a593Smuzhiyun 	isr_fcr |= (UART_EXAR654_EFR_ECB);
276*4882a593Smuzhiyun 	isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR | UART_EXAR654_EFR_IXOFF);
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	/* Write old LCR value back out, which turns enhanced access off */
281*4882a593Smuzhiyun 	writeb(lcrb, &ch->ch_cls_uart->lcr);
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	/* Disable interrupts for RTS flow */
284*4882a593Smuzhiyun 	ier &= ~(UART_EXAR654_IER_RTSDTR);
285*4882a593Smuzhiyun 	writeb(ier, &ch->ch_cls_uart->ier);
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	/* Set the usual FIFO values */
288*4882a593Smuzhiyun 	writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
291*4882a593Smuzhiyun 		UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
292*4882a593Smuzhiyun 		&ch->ch_cls_uart->isr_fcr);
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	ch->ch_t_tlevel = 16;
295*4882a593Smuzhiyun 	ch->ch_r_tlevel = 16;
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun /*
299*4882a593Smuzhiyun  * cls_clear_break.
300*4882a593Smuzhiyun  * Determines whether its time to shut off break condition.
301*4882a593Smuzhiyun  *
302*4882a593Smuzhiyun  * No locks are assumed to be held when calling this function.
303*4882a593Smuzhiyun  * channel lock is held and released in this function.
304*4882a593Smuzhiyun  */
cls_clear_break(struct jsm_channel * ch)305*4882a593Smuzhiyun static void cls_clear_break(struct jsm_channel *ch)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun 	unsigned long lock_flags;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	spin_lock_irqsave(&ch->ch_lock, lock_flags);
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	/* Turn break off, and unset some variables */
312*4882a593Smuzhiyun 	if (ch->ch_flags & CH_BREAK_SENDING) {
313*4882a593Smuzhiyun 		u8 temp = readb(&ch->ch_cls_uart->lcr);
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 		writeb((temp & ~UART_LCR_SBC), &ch->ch_cls_uart->lcr);
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 		ch->ch_flags &= ~(CH_BREAK_SENDING);
318*4882a593Smuzhiyun 		jsm_dbg(IOCTL, &ch->ch_bd->pci_dev,
319*4882a593Smuzhiyun 			"clear break Finishing UART_LCR_SBC! finished: %lx\n",
320*4882a593Smuzhiyun 			jiffies);
321*4882a593Smuzhiyun 	}
322*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun 
cls_disable_receiver(struct jsm_channel * ch)325*4882a593Smuzhiyun static void cls_disable_receiver(struct jsm_channel *ch)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun 	u8 tmp = readb(&ch->ch_cls_uart->ier);
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	tmp &= ~(UART_IER_RDI);
330*4882a593Smuzhiyun 	writeb(tmp, &ch->ch_cls_uart->ier);
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun 
cls_enable_receiver(struct jsm_channel * ch)333*4882a593Smuzhiyun static void cls_enable_receiver(struct jsm_channel *ch)
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun 	u8 tmp = readb(&ch->ch_cls_uart->ier);
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	tmp |= (UART_IER_RDI);
338*4882a593Smuzhiyun 	writeb(tmp, &ch->ch_cls_uart->ier);
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun /* Make the UART raise any of the output signals we want up */
cls_assert_modem_signals(struct jsm_channel * ch)342*4882a593Smuzhiyun static void cls_assert_modem_signals(struct jsm_channel *ch)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun 	if (!ch)
345*4882a593Smuzhiyun 		return;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	writeb(ch->ch_mostat, &ch->ch_cls_uart->mcr);
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun 
cls_copy_data_from_uart_to_queue(struct jsm_channel * ch)350*4882a593Smuzhiyun static void cls_copy_data_from_uart_to_queue(struct jsm_channel *ch)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun 	int qleft = 0;
353*4882a593Smuzhiyun 	u8 linestatus = 0;
354*4882a593Smuzhiyun 	u8 error_mask = 0;
355*4882a593Smuzhiyun 	u16 head;
356*4882a593Smuzhiyun 	u16 tail;
357*4882a593Smuzhiyun 	unsigned long flags;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	if (!ch)
360*4882a593Smuzhiyun 		return;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	spin_lock_irqsave(&ch->ch_lock, flags);
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	/* cache head and tail of queue */
365*4882a593Smuzhiyun 	head = ch->ch_r_head & RQUEUEMASK;
366*4882a593Smuzhiyun 	tail = ch->ch_r_tail & RQUEUEMASK;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	/* Get our cached LSR */
369*4882a593Smuzhiyun 	linestatus = ch->ch_cached_lsr;
370*4882a593Smuzhiyun 	ch->ch_cached_lsr = 0;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	/* Store how much space we have left in the queue */
373*4882a593Smuzhiyun 	qleft = tail - head - 1;
374*4882a593Smuzhiyun 	if (qleft < 0)
375*4882a593Smuzhiyun 		qleft += RQUEUEMASK + 1;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	/*
378*4882a593Smuzhiyun 	 * Create a mask to determine whether we should
379*4882a593Smuzhiyun 	 * insert the character (if any) into our queue.
380*4882a593Smuzhiyun 	 */
381*4882a593Smuzhiyun 	if (ch->ch_c_iflag & IGNBRK)
382*4882a593Smuzhiyun 		error_mask |= UART_LSR_BI;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	while (1) {
385*4882a593Smuzhiyun 		/*
386*4882a593Smuzhiyun 		 * Grab the linestatus register, we need to
387*4882a593Smuzhiyun 		 * check to see if there is any data to read
388*4882a593Smuzhiyun 		 */
389*4882a593Smuzhiyun 		linestatus = readb(&ch->ch_cls_uart->lsr);
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 		/* Break out if there is no data to fetch */
392*4882a593Smuzhiyun 		if (!(linestatus & UART_LSR_DR))
393*4882a593Smuzhiyun 			break;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 		/*
396*4882a593Smuzhiyun 		 * Discard character if we are ignoring the error mask
397*4882a593Smuzhiyun 		 * which in this case is the break signal.
398*4882a593Smuzhiyun 		 */
399*4882a593Smuzhiyun 		if (linestatus & error_mask)  {
400*4882a593Smuzhiyun 			u8 discard;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 			linestatus = 0;
403*4882a593Smuzhiyun 			discard = readb(&ch->ch_cls_uart->txrx);
404*4882a593Smuzhiyun 			continue;
405*4882a593Smuzhiyun 		}
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 		/*
408*4882a593Smuzhiyun 		 * If our queue is full, we have no choice but to drop some
409*4882a593Smuzhiyun 		 * data. The assumption is that HWFLOW or SWFLOW should have
410*4882a593Smuzhiyun 		 * stopped things way way before we got to this point.
411*4882a593Smuzhiyun 		 *
412*4882a593Smuzhiyun 		 * I decided that I wanted to ditch the oldest data first,
413*4882a593Smuzhiyun 		 * I hope thats okay with everyone? Yes? Good.
414*4882a593Smuzhiyun 		 */
415*4882a593Smuzhiyun 		while (qleft < 1) {
416*4882a593Smuzhiyun 			tail = (tail + 1) & RQUEUEMASK;
417*4882a593Smuzhiyun 			ch->ch_r_tail = tail;
418*4882a593Smuzhiyun 			ch->ch_err_overrun++;
419*4882a593Smuzhiyun 			qleft++;
420*4882a593Smuzhiyun 		}
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 		ch->ch_equeue[head] = linestatus & (UART_LSR_BI | UART_LSR_PE
423*4882a593Smuzhiyun 								 | UART_LSR_FE);
424*4882a593Smuzhiyun 		ch->ch_rqueue[head] = readb(&ch->ch_cls_uart->txrx);
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 		qleft--;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 		if (ch->ch_equeue[head] & UART_LSR_PE)
429*4882a593Smuzhiyun 			ch->ch_err_parity++;
430*4882a593Smuzhiyun 		if (ch->ch_equeue[head] & UART_LSR_BI)
431*4882a593Smuzhiyun 			ch->ch_err_break++;
432*4882a593Smuzhiyun 		if (ch->ch_equeue[head] & UART_LSR_FE)
433*4882a593Smuzhiyun 			ch->ch_err_frame++;
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 		/* Add to, and flip head if needed */
436*4882a593Smuzhiyun 		head = (head + 1) & RQUEUEMASK;
437*4882a593Smuzhiyun 		ch->ch_rxcount++;
438*4882a593Smuzhiyun 	}
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	/*
441*4882a593Smuzhiyun 	 * Write new final heads to channel structure.
442*4882a593Smuzhiyun 	 */
443*4882a593Smuzhiyun 	ch->ch_r_head = head & RQUEUEMASK;
444*4882a593Smuzhiyun 	ch->ch_e_head = head & EQUEUEMASK;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ch->ch_lock, flags);
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun 
cls_copy_data_from_queue_to_uart(struct jsm_channel * ch)449*4882a593Smuzhiyun static void cls_copy_data_from_queue_to_uart(struct jsm_channel *ch)
450*4882a593Smuzhiyun {
451*4882a593Smuzhiyun 	u16 tail;
452*4882a593Smuzhiyun 	int n;
453*4882a593Smuzhiyun 	int qlen;
454*4882a593Smuzhiyun 	u32 len_written = 0;
455*4882a593Smuzhiyun 	struct circ_buf *circ;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	if (!ch)
458*4882a593Smuzhiyun 		return;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	circ = &ch->uart_port.state->xmit;
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	/* No data to write to the UART */
463*4882a593Smuzhiyun 	if (uart_circ_empty(circ))
464*4882a593Smuzhiyun 		return;
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	/* If port is "stopped", don't send any data to the UART */
467*4882a593Smuzhiyun 	if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_BREAK_SENDING))
468*4882a593Smuzhiyun 		return;
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	/* We have to do it this way, because of the EXAR TXFIFO count bug. */
471*4882a593Smuzhiyun 	if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM)))
472*4882a593Smuzhiyun 		return;
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	n = 32;
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	/* cache tail of queue */
477*4882a593Smuzhiyun 	tail = circ->tail & (UART_XMIT_SIZE - 1);
478*4882a593Smuzhiyun 	qlen = uart_circ_chars_pending(circ);
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	/* Find minimum of the FIFO space, versus queue length */
481*4882a593Smuzhiyun 	n = min(n, qlen);
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	while (n > 0) {
484*4882a593Smuzhiyun 		writeb(circ->buf[tail], &ch->ch_cls_uart->txrx);
485*4882a593Smuzhiyun 		tail = (tail + 1) & (UART_XMIT_SIZE - 1);
486*4882a593Smuzhiyun 		n--;
487*4882a593Smuzhiyun 		ch->ch_txcount++;
488*4882a593Smuzhiyun 		len_written++;
489*4882a593Smuzhiyun 	}
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	/* Update the final tail */
492*4882a593Smuzhiyun 	circ->tail = tail & (UART_XMIT_SIZE - 1);
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	if (len_written > ch->ch_t_tlevel)
495*4882a593Smuzhiyun 		ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 	if (uart_circ_empty(circ))
498*4882a593Smuzhiyun 		uart_write_wakeup(&ch->uart_port);
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun 
cls_parse_modem(struct jsm_channel * ch,u8 signals)501*4882a593Smuzhiyun static void cls_parse_modem(struct jsm_channel *ch, u8 signals)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun 	u8 msignals = signals;
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	jsm_dbg(MSIGS, &ch->ch_bd->pci_dev,
506*4882a593Smuzhiyun 		"neo_parse_modem: port: %d msignals: %x\n",
507*4882a593Smuzhiyun 		ch->ch_portnum, msignals);
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	/*
510*4882a593Smuzhiyun 	 * Scrub off lower bits.
511*4882a593Smuzhiyun 	 * They signify delta's, which I don't care about
512*4882a593Smuzhiyun 	 * Keep DDCD and DDSR though
513*4882a593Smuzhiyun 	 */
514*4882a593Smuzhiyun 	msignals &= 0xf8;
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	if (msignals & UART_MSR_DDCD)
517*4882a593Smuzhiyun 		uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD);
518*4882a593Smuzhiyun 	if (msignals & UART_MSR_DDSR)
519*4882a593Smuzhiyun 		uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_CTS);
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	if (msignals & UART_MSR_DCD)
522*4882a593Smuzhiyun 		ch->ch_mistat |= UART_MSR_DCD;
523*4882a593Smuzhiyun 	else
524*4882a593Smuzhiyun 		ch->ch_mistat &= ~UART_MSR_DCD;
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	if (msignals & UART_MSR_DSR)
527*4882a593Smuzhiyun 		ch->ch_mistat |= UART_MSR_DSR;
528*4882a593Smuzhiyun 	else
529*4882a593Smuzhiyun 		ch->ch_mistat &= ~UART_MSR_DSR;
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	if (msignals & UART_MSR_RI)
532*4882a593Smuzhiyun 		ch->ch_mistat |= UART_MSR_RI;
533*4882a593Smuzhiyun 	else
534*4882a593Smuzhiyun 		ch->ch_mistat &= ~UART_MSR_RI;
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	if (msignals & UART_MSR_CTS)
537*4882a593Smuzhiyun 		ch->ch_mistat |= UART_MSR_CTS;
538*4882a593Smuzhiyun 	else
539*4882a593Smuzhiyun 		ch->ch_mistat &= ~UART_MSR_CTS;
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	jsm_dbg(MSIGS, &ch->ch_bd->pci_dev,
542*4882a593Smuzhiyun 		"Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n",
543*4882a593Smuzhiyun 		ch->ch_portnum,
544*4882a593Smuzhiyun 		!!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR),
545*4882a593Smuzhiyun 		!!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS),
546*4882a593Smuzhiyun 		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_CTS),
547*4882a593Smuzhiyun 		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DSR),
548*4882a593Smuzhiyun 		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_RI),
549*4882a593Smuzhiyun 		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DCD));
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun /* Parse the ISR register for the specific port */
cls_parse_isr(struct jsm_board * brd,uint port)553*4882a593Smuzhiyun static inline void cls_parse_isr(struct jsm_board *brd, uint port)
554*4882a593Smuzhiyun {
555*4882a593Smuzhiyun 	struct jsm_channel *ch;
556*4882a593Smuzhiyun 	u8 isr = 0;
557*4882a593Smuzhiyun 	unsigned long flags;
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun 	/*
560*4882a593Smuzhiyun 	 * No need to verify board pointer, it was already
561*4882a593Smuzhiyun 	 * verified in the interrupt routine.
562*4882a593Smuzhiyun 	 */
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	if (port >= brd->nasync)
565*4882a593Smuzhiyun 		return;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	ch = brd->channels[port];
568*4882a593Smuzhiyun 	if (!ch)
569*4882a593Smuzhiyun 		return;
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	/* Here we try to figure out what caused the interrupt to happen */
572*4882a593Smuzhiyun 	while (1) {
573*4882a593Smuzhiyun 		isr = readb(&ch->ch_cls_uart->isr_fcr);
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 		/* Bail if no pending interrupt on port */
576*4882a593Smuzhiyun 		if (isr & UART_IIR_NO_INT)
577*4882a593Smuzhiyun 			break;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 		/* Receive Interrupt pending */
580*4882a593Smuzhiyun 		if (isr & (UART_IIR_RDI | UART_IIR_RDI_TIMEOUT)) {
581*4882a593Smuzhiyun 			/* Read data from uart -> queue */
582*4882a593Smuzhiyun 			cls_copy_data_from_uart_to_queue(ch);
583*4882a593Smuzhiyun 			jsm_check_queue_flow_control(ch);
584*4882a593Smuzhiyun 		}
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 		/* Transmit Hold register empty pending */
587*4882a593Smuzhiyun 		if (isr & UART_IIR_THRI) {
588*4882a593Smuzhiyun 			/* Transfer data (if any) from Write Queue -> UART. */
589*4882a593Smuzhiyun 			spin_lock_irqsave(&ch->ch_lock, flags);
590*4882a593Smuzhiyun 			ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
591*4882a593Smuzhiyun 			spin_unlock_irqrestore(&ch->ch_lock, flags);
592*4882a593Smuzhiyun 			cls_copy_data_from_queue_to_uart(ch);
593*4882a593Smuzhiyun 		}
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 		/*
596*4882a593Smuzhiyun 		 * CTS/RTS change of state:
597*4882a593Smuzhiyun 		 * Don't need to do anything, the cls_parse_modem
598*4882a593Smuzhiyun 		 * below will grab the updated modem signals.
599*4882a593Smuzhiyun 		 */
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 		/* Parse any modem signal changes */
602*4882a593Smuzhiyun 		cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr));
603*4882a593Smuzhiyun 	}
604*4882a593Smuzhiyun }
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun /* Channel lock MUST be held before calling this function! */
cls_flush_uart_write(struct jsm_channel * ch)607*4882a593Smuzhiyun static void cls_flush_uart_write(struct jsm_channel *ch)
608*4882a593Smuzhiyun {
609*4882a593Smuzhiyun 	u8 tmp = 0;
610*4882a593Smuzhiyun 	u8 i = 0;
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 	if (!ch)
613*4882a593Smuzhiyun 		return;
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT),
616*4882a593Smuzhiyun 						&ch->ch_cls_uart->isr_fcr);
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	for (i = 0; i < 10; i++) {
619*4882a593Smuzhiyun 		/* Check to see if the UART feels it completely flushed FIFO */
620*4882a593Smuzhiyun 		tmp = readb(&ch->ch_cls_uart->isr_fcr);
621*4882a593Smuzhiyun 		if (tmp & UART_FCR_CLEAR_XMIT) {
622*4882a593Smuzhiyun 			jsm_dbg(IOCTL, &ch->ch_bd->pci_dev,
623*4882a593Smuzhiyun 				"Still flushing TX UART... i: %d\n", i);
624*4882a593Smuzhiyun 			udelay(10);
625*4882a593Smuzhiyun 		} else
626*4882a593Smuzhiyun 			break;
627*4882a593Smuzhiyun 	}
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun /* Channel lock MUST be held before calling this function! */
cls_flush_uart_read(struct jsm_channel * ch)633*4882a593Smuzhiyun static void cls_flush_uart_read(struct jsm_channel *ch)
634*4882a593Smuzhiyun {
635*4882a593Smuzhiyun 	if (!ch)
636*4882a593Smuzhiyun 		return;
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	/*
639*4882a593Smuzhiyun 	 * For complete POSIX compatibility, we should be purging the
640*4882a593Smuzhiyun 	 * read FIFO in the UART here.
641*4882a593Smuzhiyun 	 *
642*4882a593Smuzhiyun 	 * However, clearing the read FIFO (UART_FCR_CLEAR_RCVR) also
643*4882a593Smuzhiyun 	 * incorrectly flushes write data as well as just basically trashing the
644*4882a593Smuzhiyun 	 * FIFO.
645*4882a593Smuzhiyun 	 *
646*4882a593Smuzhiyun 	 * Presumably, this is a bug in this UART.
647*4882a593Smuzhiyun 	 */
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun 	udelay(10);
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun 
cls_send_start_character(struct jsm_channel * ch)652*4882a593Smuzhiyun static void cls_send_start_character(struct jsm_channel *ch)
653*4882a593Smuzhiyun {
654*4882a593Smuzhiyun 	if (!ch)
655*4882a593Smuzhiyun 		return;
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	if (ch->ch_startc != __DISABLED_CHAR) {
658*4882a593Smuzhiyun 		ch->ch_xon_sends++;
659*4882a593Smuzhiyun 		writeb(ch->ch_startc, &ch->ch_cls_uart->txrx);
660*4882a593Smuzhiyun 	}
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun 
cls_send_stop_character(struct jsm_channel * ch)663*4882a593Smuzhiyun static void cls_send_stop_character(struct jsm_channel *ch)
664*4882a593Smuzhiyun {
665*4882a593Smuzhiyun 	if (!ch)
666*4882a593Smuzhiyun 		return;
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	if (ch->ch_stopc != __DISABLED_CHAR) {
669*4882a593Smuzhiyun 		ch->ch_xoff_sends++;
670*4882a593Smuzhiyun 		writeb(ch->ch_stopc, &ch->ch_cls_uart->txrx);
671*4882a593Smuzhiyun 	}
672*4882a593Smuzhiyun }
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun /*
675*4882a593Smuzhiyun  * cls_param()
676*4882a593Smuzhiyun  * Send any/all changes to the line to the UART.
677*4882a593Smuzhiyun  */
cls_param(struct jsm_channel * ch)678*4882a593Smuzhiyun static void cls_param(struct jsm_channel *ch)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun 	u8 lcr = 0;
681*4882a593Smuzhiyun 	u8 uart_lcr = 0;
682*4882a593Smuzhiyun 	u8 ier = 0;
683*4882a593Smuzhiyun 	u32 baud = 9600;
684*4882a593Smuzhiyun 	int quot = 0;
685*4882a593Smuzhiyun 	struct jsm_board *bd;
686*4882a593Smuzhiyun 	int i;
687*4882a593Smuzhiyun 	unsigned int cflag;
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 	bd = ch->ch_bd;
690*4882a593Smuzhiyun 	if (!bd)
691*4882a593Smuzhiyun 		return;
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 	/*
694*4882a593Smuzhiyun 	 * If baud rate is zero, flush queues, and set mval to drop DTR.
695*4882a593Smuzhiyun 	 */
696*4882a593Smuzhiyun 	if ((ch->ch_c_cflag & (CBAUD)) == 0) {
697*4882a593Smuzhiyun 		ch->ch_r_head = 0;
698*4882a593Smuzhiyun 		ch->ch_r_tail = 0;
699*4882a593Smuzhiyun 		ch->ch_e_head = 0;
700*4882a593Smuzhiyun 		ch->ch_e_tail = 0;
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 		cls_flush_uart_write(ch);
703*4882a593Smuzhiyun 		cls_flush_uart_read(ch);
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 		/* The baudrate is B0 so all modem lines are to be dropped. */
706*4882a593Smuzhiyun 		ch->ch_flags |= (CH_BAUD0);
707*4882a593Smuzhiyun 		ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
708*4882a593Smuzhiyun 		cls_assert_modem_signals(ch);
709*4882a593Smuzhiyun 		return;
710*4882a593Smuzhiyun 	}
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	cflag = C_BAUD(ch->uart_port.state->port.tty);
713*4882a593Smuzhiyun 	baud = 9600;
714*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(baud_rates); i++) {
715*4882a593Smuzhiyun 		if (baud_rates[i].cflag == cflag) {
716*4882a593Smuzhiyun 			baud = baud_rates[i].rate;
717*4882a593Smuzhiyun 			break;
718*4882a593Smuzhiyun 		}
719*4882a593Smuzhiyun 	}
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun 	if (ch->ch_flags & CH_BAUD0)
722*4882a593Smuzhiyun 		ch->ch_flags &= ~(CH_BAUD0);
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	if (ch->ch_c_cflag & PARENB)
725*4882a593Smuzhiyun 		lcr |= UART_LCR_PARITY;
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	if (!(ch->ch_c_cflag & PARODD))
728*4882a593Smuzhiyun 		lcr |= UART_LCR_EPAR;
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun 	/*
731*4882a593Smuzhiyun 	 * Not all platforms support mark/space parity,
732*4882a593Smuzhiyun 	 * so this will hide behind an ifdef.
733*4882a593Smuzhiyun 	 */
734*4882a593Smuzhiyun #ifdef CMSPAR
735*4882a593Smuzhiyun 	if (ch->ch_c_cflag & CMSPAR)
736*4882a593Smuzhiyun 		lcr |= UART_LCR_SPAR;
737*4882a593Smuzhiyun #endif
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 	if (ch->ch_c_cflag & CSTOPB)
740*4882a593Smuzhiyun 		lcr |= UART_LCR_STOP;
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	switch (ch->ch_c_cflag & CSIZE) {
743*4882a593Smuzhiyun 	case CS5:
744*4882a593Smuzhiyun 		lcr |= UART_LCR_WLEN5;
745*4882a593Smuzhiyun 		break;
746*4882a593Smuzhiyun 	case CS6:
747*4882a593Smuzhiyun 		lcr |= UART_LCR_WLEN6;
748*4882a593Smuzhiyun 		break;
749*4882a593Smuzhiyun 	case CS7:
750*4882a593Smuzhiyun 		lcr |= UART_LCR_WLEN7;
751*4882a593Smuzhiyun 		break;
752*4882a593Smuzhiyun 	case CS8:
753*4882a593Smuzhiyun 	default:
754*4882a593Smuzhiyun 		lcr |= UART_LCR_WLEN8;
755*4882a593Smuzhiyun 		break;
756*4882a593Smuzhiyun 	}
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun 	ier = readb(&ch->ch_cls_uart->ier);
759*4882a593Smuzhiyun 	uart_lcr = readb(&ch->ch_cls_uart->lcr);
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 	quot = ch->ch_bd->bd_dividend / baud;
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 	if (quot != 0) {
764*4882a593Smuzhiyun 		writeb(UART_LCR_DLAB, &ch->ch_cls_uart->lcr);
765*4882a593Smuzhiyun 		writeb((quot & 0xff), &ch->ch_cls_uart->txrx);
766*4882a593Smuzhiyun 		writeb((quot >> 8), &ch->ch_cls_uart->ier);
767*4882a593Smuzhiyun 		writeb(lcr, &ch->ch_cls_uart->lcr);
768*4882a593Smuzhiyun 	}
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 	if (uart_lcr != lcr)
771*4882a593Smuzhiyun 		writeb(lcr, &ch->ch_cls_uart->lcr);
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	if (ch->ch_c_cflag & CREAD)
774*4882a593Smuzhiyun 		ier |= (UART_IER_RDI | UART_IER_RLSI);
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 	ier |= (UART_IER_THRI | UART_IER_MSI);
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 	writeb(ier, &ch->ch_cls_uart->ier);
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	if (ch->ch_c_cflag & CRTSCTS)
781*4882a593Smuzhiyun 		cls_set_cts_flow_control(ch);
782*4882a593Smuzhiyun 	else if (ch->ch_c_iflag & IXON) {
783*4882a593Smuzhiyun 		/*
784*4882a593Smuzhiyun 		 * If start/stop is set to disable,
785*4882a593Smuzhiyun 		 * then we should disable flow control.
786*4882a593Smuzhiyun 		 */
787*4882a593Smuzhiyun 		if ((ch->ch_startc == __DISABLED_CHAR) ||
788*4882a593Smuzhiyun 			(ch->ch_stopc == __DISABLED_CHAR))
789*4882a593Smuzhiyun 			cls_set_no_output_flow_control(ch);
790*4882a593Smuzhiyun 		else
791*4882a593Smuzhiyun 			cls_set_ixon_flow_control(ch);
792*4882a593Smuzhiyun 	} else
793*4882a593Smuzhiyun 		cls_set_no_output_flow_control(ch);
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun 	if (ch->ch_c_cflag & CRTSCTS)
796*4882a593Smuzhiyun 		cls_set_rts_flow_control(ch);
797*4882a593Smuzhiyun 	else if (ch->ch_c_iflag & IXOFF) {
798*4882a593Smuzhiyun 		/*
799*4882a593Smuzhiyun 		 * If start/stop is set to disable,
800*4882a593Smuzhiyun 		 * then we should disable flow control.
801*4882a593Smuzhiyun 		 */
802*4882a593Smuzhiyun 		if ((ch->ch_startc == __DISABLED_CHAR) ||
803*4882a593Smuzhiyun 			(ch->ch_stopc == __DISABLED_CHAR))
804*4882a593Smuzhiyun 			cls_set_no_input_flow_control(ch);
805*4882a593Smuzhiyun 		else
806*4882a593Smuzhiyun 			cls_set_ixoff_flow_control(ch);
807*4882a593Smuzhiyun 	} else
808*4882a593Smuzhiyun 		cls_set_no_input_flow_control(ch);
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 	cls_assert_modem_signals(ch);
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun 	/* get current status of the modem signals now */
813*4882a593Smuzhiyun 	cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr));
814*4882a593Smuzhiyun }
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun /*
817*4882a593Smuzhiyun  * cls_intr()
818*4882a593Smuzhiyun  *
819*4882a593Smuzhiyun  * Classic specific interrupt handler.
820*4882a593Smuzhiyun  */
cls_intr(int irq,void * voidbrd)821*4882a593Smuzhiyun static irqreturn_t cls_intr(int irq, void *voidbrd)
822*4882a593Smuzhiyun {
823*4882a593Smuzhiyun 	struct jsm_board *brd = voidbrd;
824*4882a593Smuzhiyun 	unsigned long lock_flags;
825*4882a593Smuzhiyun 	unsigned char uart_poll;
826*4882a593Smuzhiyun 	uint i = 0;
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 	/* Lock out the slow poller from running on this board. */
829*4882a593Smuzhiyun 	spin_lock_irqsave(&brd->bd_intr_lock, lock_flags);
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun 	/*
832*4882a593Smuzhiyun 	 * Check the board's global interrupt offset to see if we
833*4882a593Smuzhiyun 	 * acctually do have an interrupt pending on us.
834*4882a593Smuzhiyun 	 */
835*4882a593Smuzhiyun 	uart_poll = readb(brd->re_map_membase + UART_CLASSIC_POLL_ADDR_OFFSET);
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 	jsm_dbg(INTR, &brd->pci_dev, "%s:%d uart_poll: %x\n",
838*4882a593Smuzhiyun 		__FILE__, __LINE__, uart_poll);
839*4882a593Smuzhiyun 
840*4882a593Smuzhiyun 	if (!uart_poll) {
841*4882a593Smuzhiyun 		jsm_dbg(INTR, &brd->pci_dev,
842*4882a593Smuzhiyun 			"Kernel interrupted to me, but no pending interrupts...\n");
843*4882a593Smuzhiyun 		spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
844*4882a593Smuzhiyun 		return IRQ_NONE;
845*4882a593Smuzhiyun 	}
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 	/* At this point, we have at least SOMETHING to service, dig further. */
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun 	/* Parse each port to find out what caused the interrupt */
850*4882a593Smuzhiyun 	for (i = 0; i < brd->nasync; i++)
851*4882a593Smuzhiyun 		cls_parse_isr(brd, i);
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun 	spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun 	return IRQ_HANDLED;
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun /* Inits UART */
cls_uart_init(struct jsm_channel * ch)859*4882a593Smuzhiyun static void cls_uart_init(struct jsm_channel *ch)
860*4882a593Smuzhiyun {
861*4882a593Smuzhiyun 	unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
862*4882a593Smuzhiyun 	unsigned char isr_fcr = 0;
863*4882a593Smuzhiyun 
864*4882a593Smuzhiyun 	writeb(0, &ch->ch_cls_uart->ier);
865*4882a593Smuzhiyun 
866*4882a593Smuzhiyun 	/*
867*4882a593Smuzhiyun 	 * The Enhanced Register Set may only be accessed when
868*4882a593Smuzhiyun 	 * the Line Control Register is set to 0xBFh.
869*4882a593Smuzhiyun 	 */
870*4882a593Smuzhiyun 	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
871*4882a593Smuzhiyun 
872*4882a593Smuzhiyun 	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun 	/* Turn on Enhanced/Extended controls */
875*4882a593Smuzhiyun 	isr_fcr |= (UART_EXAR654_EFR_ECB);
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun 	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
878*4882a593Smuzhiyun 
879*4882a593Smuzhiyun 	/* Write old LCR value back out, which turns enhanced access off */
880*4882a593Smuzhiyun 	writeb(lcrb, &ch->ch_cls_uart->lcr);
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun 	/* Clear out UART and FIFO */
883*4882a593Smuzhiyun 	readb(&ch->ch_cls_uart->txrx);
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun 	writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT),
886*4882a593Smuzhiyun 						 &ch->ch_cls_uart->isr_fcr);
887*4882a593Smuzhiyun 	udelay(10);
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun 	ch->ch_flags |= (CH_FIFO_ENABLED | CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
890*4882a593Smuzhiyun 
891*4882a593Smuzhiyun 	readb(&ch->ch_cls_uart->lsr);
892*4882a593Smuzhiyun 	readb(&ch->ch_cls_uart->msr);
893*4882a593Smuzhiyun }
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun /*
896*4882a593Smuzhiyun  * Turns off UART.
897*4882a593Smuzhiyun  */
cls_uart_off(struct jsm_channel * ch)898*4882a593Smuzhiyun static void cls_uart_off(struct jsm_channel *ch)
899*4882a593Smuzhiyun {
900*4882a593Smuzhiyun 	/* Stop all interrupts from accurring. */
901*4882a593Smuzhiyun 	writeb(0, &ch->ch_cls_uart->ier);
902*4882a593Smuzhiyun }
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun /*
905*4882a593Smuzhiyun  * cls_get_uarts_bytes_left.
906*4882a593Smuzhiyun  * Returns 0 is nothing left in the FIFO, returns 1 otherwise.
907*4882a593Smuzhiyun  *
908*4882a593Smuzhiyun  * The channel lock MUST be held by the calling function.
909*4882a593Smuzhiyun  */
cls_get_uart_bytes_left(struct jsm_channel * ch)910*4882a593Smuzhiyun static u32 cls_get_uart_bytes_left(struct jsm_channel *ch)
911*4882a593Smuzhiyun {
912*4882a593Smuzhiyun 	u8 left = 0;
913*4882a593Smuzhiyun 	u8 lsr = readb(&ch->ch_cls_uart->lsr);
914*4882a593Smuzhiyun 
915*4882a593Smuzhiyun 	/* Determine whether the Transmitter is empty or not */
916*4882a593Smuzhiyun 	if (!(lsr & UART_LSR_TEMT))
917*4882a593Smuzhiyun 		left = 1;
918*4882a593Smuzhiyun 	else {
919*4882a593Smuzhiyun 		ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
920*4882a593Smuzhiyun 		left = 0;
921*4882a593Smuzhiyun 	}
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun 	return left;
924*4882a593Smuzhiyun }
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun /*
927*4882a593Smuzhiyun  * cls_send_break.
928*4882a593Smuzhiyun  * Starts sending a break thru the UART.
929*4882a593Smuzhiyun  *
930*4882a593Smuzhiyun  * The channel lock MUST be held by the calling function.
931*4882a593Smuzhiyun  */
cls_send_break(struct jsm_channel * ch)932*4882a593Smuzhiyun static void cls_send_break(struct jsm_channel *ch)
933*4882a593Smuzhiyun {
934*4882a593Smuzhiyun 	/* Tell the UART to start sending the break */
935*4882a593Smuzhiyun 	if (!(ch->ch_flags & CH_BREAK_SENDING)) {
936*4882a593Smuzhiyun 		u8 temp = readb(&ch->ch_cls_uart->lcr);
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun 		writeb((temp | UART_LCR_SBC), &ch->ch_cls_uart->lcr);
939*4882a593Smuzhiyun 		ch->ch_flags |= (CH_BREAK_SENDING);
940*4882a593Smuzhiyun 	}
941*4882a593Smuzhiyun }
942*4882a593Smuzhiyun 
943*4882a593Smuzhiyun /*
944*4882a593Smuzhiyun  * cls_send_immediate_char.
945*4882a593Smuzhiyun  * Sends a specific character as soon as possible to the UART,
946*4882a593Smuzhiyun  * jumping over any bytes that might be in the write queue.
947*4882a593Smuzhiyun  *
948*4882a593Smuzhiyun  * The channel lock MUST be held by the calling function.
949*4882a593Smuzhiyun  */
cls_send_immediate_char(struct jsm_channel * ch,unsigned char c)950*4882a593Smuzhiyun static void cls_send_immediate_char(struct jsm_channel *ch, unsigned char c)
951*4882a593Smuzhiyun {
952*4882a593Smuzhiyun 	writeb(c, &ch->ch_cls_uart->txrx);
953*4882a593Smuzhiyun }
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun struct board_ops jsm_cls_ops = {
956*4882a593Smuzhiyun 	.intr =				cls_intr,
957*4882a593Smuzhiyun 	.uart_init =			cls_uart_init,
958*4882a593Smuzhiyun 	.uart_off =			cls_uart_off,
959*4882a593Smuzhiyun 	.param =			cls_param,
960*4882a593Smuzhiyun 	.assert_modem_signals =		cls_assert_modem_signals,
961*4882a593Smuzhiyun 	.flush_uart_write =		cls_flush_uart_write,
962*4882a593Smuzhiyun 	.flush_uart_read =		cls_flush_uart_read,
963*4882a593Smuzhiyun 	.disable_receiver =		cls_disable_receiver,
964*4882a593Smuzhiyun 	.enable_receiver =		cls_enable_receiver,
965*4882a593Smuzhiyun 	.send_break =			cls_send_break,
966*4882a593Smuzhiyun 	.clear_break =			cls_clear_break,
967*4882a593Smuzhiyun 	.send_start_character =		cls_send_start_character,
968*4882a593Smuzhiyun 	.send_stop_character =		cls_send_stop_character,
969*4882a593Smuzhiyun 	.copy_data_from_queue_to_uart = cls_copy_data_from_queue_to_uart,
970*4882a593Smuzhiyun 	.get_uart_bytes_left =		cls_get_uart_bytes_left,
971*4882a593Smuzhiyun 	.send_immediate_char =		cls_send_immediate_char
972*4882a593Smuzhiyun };
973*4882a593Smuzhiyun 
974