18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2003 Digi International (www.digi.com)
48c2ecf20Sopenharmony_ci *	Scott H Kilau <Scott_Kilau at digi dot com>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci *	NOTE TO LINUX KERNEL HACKERS:  DO NOT REFORMAT THIS CODE!
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci *	This is shared code between Digi's CVS archive and the
98c2ecf20Sopenharmony_ci *	Linux Kernel sources.
108c2ecf20Sopenharmony_ci *	Changing the source just for reformatting needlessly breaks
118c2ecf20Sopenharmony_ci *	our CVS diff history.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci *	Send any bug fixes/changes to:  Eng.Linux at digi dot com.
148c2ecf20Sopenharmony_ci *	Thank you.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/delay.h>	/* For udelay */
198c2ecf20Sopenharmony_ci#include <linux/io.h>		/* For read[bwl]/write[bwl] */
208c2ecf20Sopenharmony_ci#include <linux/serial.h>	/* For struct async_serial */
218c2ecf20Sopenharmony_ci#include <linux/serial_reg.h>	/* For the various UART offsets */
228c2ecf20Sopenharmony_ci#include <linux/pci.h>
238c2ecf20Sopenharmony_ci#include <linux/tty.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include "jsm.h"	/* Driver main header file */
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic struct {
288c2ecf20Sopenharmony_ci	unsigned int rate;
298c2ecf20Sopenharmony_ci	unsigned int cflag;
308c2ecf20Sopenharmony_ci} baud_rates[] = {
318c2ecf20Sopenharmony_ci	{ 921600, B921600 },
328c2ecf20Sopenharmony_ci	{ 460800, B460800 },
338c2ecf20Sopenharmony_ci	{ 230400, B230400 },
348c2ecf20Sopenharmony_ci	{ 115200, B115200 },
358c2ecf20Sopenharmony_ci	{  57600, B57600  },
368c2ecf20Sopenharmony_ci	{  38400, B38400  },
378c2ecf20Sopenharmony_ci	{  19200, B19200  },
388c2ecf20Sopenharmony_ci	{   9600, B9600   },
398c2ecf20Sopenharmony_ci	{   4800, B4800   },
408c2ecf20Sopenharmony_ci	{   2400, B2400   },
418c2ecf20Sopenharmony_ci	{   1200, B1200   },
428c2ecf20Sopenharmony_ci	{    600, B600    },
438c2ecf20Sopenharmony_ci	{    300, B300    },
448c2ecf20Sopenharmony_ci	{    200, B200    },
458c2ecf20Sopenharmony_ci	{    150, B150    },
468c2ecf20Sopenharmony_ci	{    134, B134    },
478c2ecf20Sopenharmony_ci	{    110, B110    },
488c2ecf20Sopenharmony_ci	{     75, B75     },
498c2ecf20Sopenharmony_ci	{     50, B50     },
508c2ecf20Sopenharmony_ci};
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic void cls_set_cts_flow_control(struct jsm_channel *ch)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	u8 lcrb = readb(&ch->ch_cls_uart->lcr);
558c2ecf20Sopenharmony_ci	u8 ier = readb(&ch->ch_cls_uart->ier);
568c2ecf20Sopenharmony_ci	u8 isr_fcr = 0;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	/*
598c2ecf20Sopenharmony_ci	 * The Enhanced Register Set may only be accessed when
608c2ecf20Sopenharmony_ci	 * the Line Control Register is set to 0xBFh.
618c2ecf20Sopenharmony_ci	 */
628c2ecf20Sopenharmony_ci	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	/* Turn on CTS flow control, turn off IXON flow control */
678c2ecf20Sopenharmony_ci	isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_CTSDSR);
688c2ecf20Sopenharmony_ci	isr_fcr &= ~(UART_EXAR654_EFR_IXON);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	/* Write old LCR value back out, which turns enhanced access off */
738c2ecf20Sopenharmony_ci	writeb(lcrb, &ch->ch_cls_uart->lcr);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	/*
768c2ecf20Sopenharmony_ci	 * Enable interrupts for CTS flow, turn off interrupts for
778c2ecf20Sopenharmony_ci	 * received XOFF chars
788c2ecf20Sopenharmony_ci	 */
798c2ecf20Sopenharmony_ci	ier |= (UART_EXAR654_IER_CTSDSR);
808c2ecf20Sopenharmony_ci	ier &= ~(UART_EXAR654_IER_XOFF);
818c2ecf20Sopenharmony_ci	writeb(ier, &ch->ch_cls_uart->ier);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	/* Set the usual FIFO values */
848c2ecf20Sopenharmony_ci	writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 |
878c2ecf20Sopenharmony_ci		UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
888c2ecf20Sopenharmony_ci		&ch->ch_cls_uart->isr_fcr);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	ch->ch_t_tlevel = 16;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic void cls_set_ixon_flow_control(struct jsm_channel *ch)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	u8 lcrb = readb(&ch->ch_cls_uart->lcr);
968c2ecf20Sopenharmony_ci	u8 ier = readb(&ch->ch_cls_uart->ier);
978c2ecf20Sopenharmony_ci	u8 isr_fcr = 0;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	/*
1008c2ecf20Sopenharmony_ci	 * The Enhanced Register Set may only be accessed when
1018c2ecf20Sopenharmony_ci	 * the Line Control Register is set to 0xBFh.
1028c2ecf20Sopenharmony_ci	 */
1038c2ecf20Sopenharmony_ci	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	/* Turn on IXON flow control, turn off CTS flow control */
1088c2ecf20Sopenharmony_ci	isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXON);
1098c2ecf20Sopenharmony_ci	isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	/* Now set our current start/stop chars while in enhanced mode */
1148c2ecf20Sopenharmony_ci	writeb(ch->ch_startc, &ch->ch_cls_uart->mcr);
1158c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_cls_uart->lsr);
1168c2ecf20Sopenharmony_ci	writeb(ch->ch_stopc, &ch->ch_cls_uart->msr);
1178c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_cls_uart->spr);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	/* Write old LCR value back out, which turns enhanced access off */
1208c2ecf20Sopenharmony_ci	writeb(lcrb, &ch->ch_cls_uart->lcr);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	/*
1238c2ecf20Sopenharmony_ci	 * Disable interrupts for CTS flow, turn on interrupts for
1248c2ecf20Sopenharmony_ci	 * received XOFF chars
1258c2ecf20Sopenharmony_ci	 */
1268c2ecf20Sopenharmony_ci	ier &= ~(UART_EXAR654_IER_CTSDSR);
1278c2ecf20Sopenharmony_ci	ier |= (UART_EXAR654_IER_XOFF);
1288c2ecf20Sopenharmony_ci	writeb(ier, &ch->ch_cls_uart->ier);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	/* Set the usual FIFO values */
1318c2ecf20Sopenharmony_ci	writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
1348c2ecf20Sopenharmony_ci		UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
1358c2ecf20Sopenharmony_ci		&ch->ch_cls_uart->isr_fcr);
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic void cls_set_no_output_flow_control(struct jsm_channel *ch)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	u8 lcrb = readb(&ch->ch_cls_uart->lcr);
1418c2ecf20Sopenharmony_ci	u8 ier = readb(&ch->ch_cls_uart->ier);
1428c2ecf20Sopenharmony_ci	u8 isr_fcr = 0;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	/*
1458c2ecf20Sopenharmony_ci	 * The Enhanced Register Set may only be accessed when
1468c2ecf20Sopenharmony_ci	 * the Line Control Register is set to 0xBFh.
1478c2ecf20Sopenharmony_ci	 */
1488c2ecf20Sopenharmony_ci	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	/* Turn off IXON flow control, turn off CTS flow control */
1538c2ecf20Sopenharmony_ci	isr_fcr |= (UART_EXAR654_EFR_ECB);
1548c2ecf20Sopenharmony_ci	isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR | UART_EXAR654_EFR_IXON);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	/* Write old LCR value back out, which turns enhanced access off */
1598c2ecf20Sopenharmony_ci	writeb(lcrb, &ch->ch_cls_uart->lcr);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	/*
1628c2ecf20Sopenharmony_ci	 * Disable interrupts for CTS flow, turn off interrupts for
1638c2ecf20Sopenharmony_ci	 * received XOFF chars
1648c2ecf20Sopenharmony_ci	 */
1658c2ecf20Sopenharmony_ci	ier &= ~(UART_EXAR654_IER_CTSDSR);
1668c2ecf20Sopenharmony_ci	ier &= ~(UART_EXAR654_IER_XOFF);
1678c2ecf20Sopenharmony_ci	writeb(ier, &ch->ch_cls_uart->ier);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	/* Set the usual FIFO values */
1708c2ecf20Sopenharmony_ci	writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
1738c2ecf20Sopenharmony_ci		UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
1748c2ecf20Sopenharmony_ci		&ch->ch_cls_uart->isr_fcr);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	ch->ch_r_watermark = 0;
1778c2ecf20Sopenharmony_ci	ch->ch_t_tlevel = 16;
1788c2ecf20Sopenharmony_ci	ch->ch_r_tlevel = 16;
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic void cls_set_rts_flow_control(struct jsm_channel *ch)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	u8 lcrb = readb(&ch->ch_cls_uart->lcr);
1848c2ecf20Sopenharmony_ci	u8 ier = readb(&ch->ch_cls_uart->ier);
1858c2ecf20Sopenharmony_ci	u8 isr_fcr = 0;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	/*
1888c2ecf20Sopenharmony_ci	 * The Enhanced Register Set may only be accessed when
1898c2ecf20Sopenharmony_ci	 * the Line Control Register is set to 0xBFh.
1908c2ecf20Sopenharmony_ci	 */
1918c2ecf20Sopenharmony_ci	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	/* Turn on RTS flow control, turn off IXOFF flow control */
1968c2ecf20Sopenharmony_ci	isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_RTSDTR);
1978c2ecf20Sopenharmony_ci	isr_fcr &= ~(UART_EXAR654_EFR_IXOFF);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	/* Write old LCR value back out, which turns enhanced access off */
2028c2ecf20Sopenharmony_ci	writeb(lcrb, &ch->ch_cls_uart->lcr);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	/* Enable interrupts for RTS flow */
2058c2ecf20Sopenharmony_ci	ier |= (UART_EXAR654_IER_RTSDTR);
2068c2ecf20Sopenharmony_ci	writeb(ier, &ch->ch_cls_uart->ier);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	/* Set the usual FIFO values */
2098c2ecf20Sopenharmony_ci	writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 |
2128c2ecf20Sopenharmony_ci		UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
2138c2ecf20Sopenharmony_ci		&ch->ch_cls_uart->isr_fcr);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	ch->ch_r_watermark = 4;
2168c2ecf20Sopenharmony_ci	ch->ch_r_tlevel = 8;
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic void cls_set_ixoff_flow_control(struct jsm_channel *ch)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	u8 lcrb = readb(&ch->ch_cls_uart->lcr);
2228c2ecf20Sopenharmony_ci	u8 ier = readb(&ch->ch_cls_uart->ier);
2238c2ecf20Sopenharmony_ci	u8 isr_fcr = 0;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	/*
2268c2ecf20Sopenharmony_ci	 * The Enhanced Register Set may only be accessed when
2278c2ecf20Sopenharmony_ci	 * the Line Control Register is set to 0xBFh.
2288c2ecf20Sopenharmony_ci	 */
2298c2ecf20Sopenharmony_ci	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	/* Turn on IXOFF flow control, turn off RTS flow control */
2348c2ecf20Sopenharmony_ci	isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXOFF);
2358c2ecf20Sopenharmony_ci	isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	/* Now set our current start/stop chars while in enhanced mode */
2408c2ecf20Sopenharmony_ci	writeb(ch->ch_startc, &ch->ch_cls_uart->mcr);
2418c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_cls_uart->lsr);
2428c2ecf20Sopenharmony_ci	writeb(ch->ch_stopc, &ch->ch_cls_uart->msr);
2438c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_cls_uart->spr);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	/* Write old LCR value back out, which turns enhanced access off */
2468c2ecf20Sopenharmony_ci	writeb(lcrb, &ch->ch_cls_uart->lcr);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	/* Disable interrupts for RTS flow */
2498c2ecf20Sopenharmony_ci	ier &= ~(UART_EXAR654_IER_RTSDTR);
2508c2ecf20Sopenharmony_ci	writeb(ier, &ch->ch_cls_uart->ier);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	/* Set the usual FIFO values */
2538c2ecf20Sopenharmony_ci	writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
2568c2ecf20Sopenharmony_ci		UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
2578c2ecf20Sopenharmony_ci		&ch->ch_cls_uart->isr_fcr);
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic void cls_set_no_input_flow_control(struct jsm_channel *ch)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	u8 lcrb = readb(&ch->ch_cls_uart->lcr);
2638c2ecf20Sopenharmony_ci	u8 ier = readb(&ch->ch_cls_uart->ier);
2648c2ecf20Sopenharmony_ci	u8 isr_fcr = 0;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	/*
2678c2ecf20Sopenharmony_ci	 * The Enhanced Register Set may only be accessed when
2688c2ecf20Sopenharmony_ci	 * the Line Control Register is set to 0xBFh.
2698c2ecf20Sopenharmony_ci	 */
2708c2ecf20Sopenharmony_ci	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	/* Turn off IXOFF flow control, turn off RTS flow control */
2758c2ecf20Sopenharmony_ci	isr_fcr |= (UART_EXAR654_EFR_ECB);
2768c2ecf20Sopenharmony_ci	isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR | UART_EXAR654_EFR_IXOFF);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	/* Write old LCR value back out, which turns enhanced access off */
2818c2ecf20Sopenharmony_ci	writeb(lcrb, &ch->ch_cls_uart->lcr);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	/* Disable interrupts for RTS flow */
2848c2ecf20Sopenharmony_ci	ier &= ~(UART_EXAR654_IER_RTSDTR);
2858c2ecf20Sopenharmony_ci	writeb(ier, &ch->ch_cls_uart->ier);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	/* Set the usual FIFO values */
2888c2ecf20Sopenharmony_ci	writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
2918c2ecf20Sopenharmony_ci		UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
2928c2ecf20Sopenharmony_ci		&ch->ch_cls_uart->isr_fcr);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	ch->ch_t_tlevel = 16;
2958c2ecf20Sopenharmony_ci	ch->ch_r_tlevel = 16;
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci/*
2998c2ecf20Sopenharmony_ci * cls_clear_break.
3008c2ecf20Sopenharmony_ci * Determines whether its time to shut off break condition.
3018c2ecf20Sopenharmony_ci *
3028c2ecf20Sopenharmony_ci * No locks are assumed to be held when calling this function.
3038c2ecf20Sopenharmony_ci * channel lock is held and released in this function.
3048c2ecf20Sopenharmony_ci */
3058c2ecf20Sopenharmony_cistatic void cls_clear_break(struct jsm_channel *ch)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	unsigned long lock_flags;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ch->ch_lock, lock_flags);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	/* Turn break off, and unset some variables */
3128c2ecf20Sopenharmony_ci	if (ch->ch_flags & CH_BREAK_SENDING) {
3138c2ecf20Sopenharmony_ci		u8 temp = readb(&ch->ch_cls_uart->lcr);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci		writeb((temp & ~UART_LCR_SBC), &ch->ch_cls_uart->lcr);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		ch->ch_flags &= ~(CH_BREAK_SENDING);
3188c2ecf20Sopenharmony_ci		jsm_dbg(IOCTL, &ch->ch_bd->pci_dev,
3198c2ecf20Sopenharmony_ci			"clear break Finishing UART_LCR_SBC! finished: %lx\n",
3208c2ecf20Sopenharmony_ci			jiffies);
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistatic void cls_disable_receiver(struct jsm_channel *ch)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	u8 tmp = readb(&ch->ch_cls_uart->ier);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	tmp &= ~(UART_IER_RDI);
3308c2ecf20Sopenharmony_ci	writeb(tmp, &ch->ch_cls_uart->ier);
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic void cls_enable_receiver(struct jsm_channel *ch)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	u8 tmp = readb(&ch->ch_cls_uart->ier);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	tmp |= (UART_IER_RDI);
3388c2ecf20Sopenharmony_ci	writeb(tmp, &ch->ch_cls_uart->ier);
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci/* Make the UART raise any of the output signals we want up */
3428c2ecf20Sopenharmony_cistatic void cls_assert_modem_signals(struct jsm_channel *ch)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	if (!ch)
3458c2ecf20Sopenharmony_ci		return;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	writeb(ch->ch_mostat, &ch->ch_cls_uart->mcr);
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_cistatic void cls_copy_data_from_uart_to_queue(struct jsm_channel *ch)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	int qleft = 0;
3538c2ecf20Sopenharmony_ci	u8 linestatus = 0;
3548c2ecf20Sopenharmony_ci	u8 error_mask = 0;
3558c2ecf20Sopenharmony_ci	u16 head;
3568c2ecf20Sopenharmony_ci	u16 tail;
3578c2ecf20Sopenharmony_ci	unsigned long flags;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	if (!ch)
3608c2ecf20Sopenharmony_ci		return;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ch->ch_lock, flags);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	/* cache head and tail of queue */
3658c2ecf20Sopenharmony_ci	head = ch->ch_r_head & RQUEUEMASK;
3668c2ecf20Sopenharmony_ci	tail = ch->ch_r_tail & RQUEUEMASK;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	/* Get our cached LSR */
3698c2ecf20Sopenharmony_ci	linestatus = ch->ch_cached_lsr;
3708c2ecf20Sopenharmony_ci	ch->ch_cached_lsr = 0;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	/* Store how much space we have left in the queue */
3738c2ecf20Sopenharmony_ci	qleft = tail - head - 1;
3748c2ecf20Sopenharmony_ci	if (qleft < 0)
3758c2ecf20Sopenharmony_ci		qleft += RQUEUEMASK + 1;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	/*
3788c2ecf20Sopenharmony_ci	 * Create a mask to determine whether we should
3798c2ecf20Sopenharmony_ci	 * insert the character (if any) into our queue.
3808c2ecf20Sopenharmony_ci	 */
3818c2ecf20Sopenharmony_ci	if (ch->ch_c_iflag & IGNBRK)
3828c2ecf20Sopenharmony_ci		error_mask |= UART_LSR_BI;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	while (1) {
3858c2ecf20Sopenharmony_ci		/*
3868c2ecf20Sopenharmony_ci		 * Grab the linestatus register, we need to
3878c2ecf20Sopenharmony_ci		 * check to see if there is any data to read
3888c2ecf20Sopenharmony_ci		 */
3898c2ecf20Sopenharmony_ci		linestatus = readb(&ch->ch_cls_uart->lsr);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci		/* Break out if there is no data to fetch */
3928c2ecf20Sopenharmony_ci		if (!(linestatus & UART_LSR_DR))
3938c2ecf20Sopenharmony_ci			break;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci		/*
3968c2ecf20Sopenharmony_ci		 * Discard character if we are ignoring the error mask
3978c2ecf20Sopenharmony_ci		 * which in this case is the break signal.
3988c2ecf20Sopenharmony_ci		 */
3998c2ecf20Sopenharmony_ci		if (linestatus & error_mask)  {
4008c2ecf20Sopenharmony_ci			u8 discard;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci			linestatus = 0;
4038c2ecf20Sopenharmony_ci			discard = readb(&ch->ch_cls_uart->txrx);
4048c2ecf20Sopenharmony_ci			continue;
4058c2ecf20Sopenharmony_ci		}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci		/*
4088c2ecf20Sopenharmony_ci		 * If our queue is full, we have no choice but to drop some
4098c2ecf20Sopenharmony_ci		 * data. The assumption is that HWFLOW or SWFLOW should have
4108c2ecf20Sopenharmony_ci		 * stopped things way way before we got to this point.
4118c2ecf20Sopenharmony_ci		 *
4128c2ecf20Sopenharmony_ci		 * I decided that I wanted to ditch the oldest data first,
4138c2ecf20Sopenharmony_ci		 * I hope thats okay with everyone? Yes? Good.
4148c2ecf20Sopenharmony_ci		 */
4158c2ecf20Sopenharmony_ci		while (qleft < 1) {
4168c2ecf20Sopenharmony_ci			tail = (tail + 1) & RQUEUEMASK;
4178c2ecf20Sopenharmony_ci			ch->ch_r_tail = tail;
4188c2ecf20Sopenharmony_ci			ch->ch_err_overrun++;
4198c2ecf20Sopenharmony_ci			qleft++;
4208c2ecf20Sopenharmony_ci		}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci		ch->ch_equeue[head] = linestatus & (UART_LSR_BI | UART_LSR_PE
4238c2ecf20Sopenharmony_ci								 | UART_LSR_FE);
4248c2ecf20Sopenharmony_ci		ch->ch_rqueue[head] = readb(&ch->ch_cls_uart->txrx);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci		qleft--;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci		if (ch->ch_equeue[head] & UART_LSR_PE)
4298c2ecf20Sopenharmony_ci			ch->ch_err_parity++;
4308c2ecf20Sopenharmony_ci		if (ch->ch_equeue[head] & UART_LSR_BI)
4318c2ecf20Sopenharmony_ci			ch->ch_err_break++;
4328c2ecf20Sopenharmony_ci		if (ch->ch_equeue[head] & UART_LSR_FE)
4338c2ecf20Sopenharmony_ci			ch->ch_err_frame++;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci		/* Add to, and flip head if needed */
4368c2ecf20Sopenharmony_ci		head = (head + 1) & RQUEUEMASK;
4378c2ecf20Sopenharmony_ci		ch->ch_rxcount++;
4388c2ecf20Sopenharmony_ci	}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	/*
4418c2ecf20Sopenharmony_ci	 * Write new final heads to channel structure.
4428c2ecf20Sopenharmony_ci	 */
4438c2ecf20Sopenharmony_ci	ch->ch_r_head = head & RQUEUEMASK;
4448c2ecf20Sopenharmony_ci	ch->ch_e_head = head & EQUEUEMASK;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ch->ch_lock, flags);
4478c2ecf20Sopenharmony_ci}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_cistatic void cls_copy_data_from_queue_to_uart(struct jsm_channel *ch)
4508c2ecf20Sopenharmony_ci{
4518c2ecf20Sopenharmony_ci	u16 tail;
4528c2ecf20Sopenharmony_ci	int n;
4538c2ecf20Sopenharmony_ci	int qlen;
4548c2ecf20Sopenharmony_ci	u32 len_written = 0;
4558c2ecf20Sopenharmony_ci	struct circ_buf *circ;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	if (!ch)
4588c2ecf20Sopenharmony_ci		return;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	circ = &ch->uart_port.state->xmit;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	/* No data to write to the UART */
4638c2ecf20Sopenharmony_ci	if (uart_circ_empty(circ))
4648c2ecf20Sopenharmony_ci		return;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	/* If port is "stopped", don't send any data to the UART */
4678c2ecf20Sopenharmony_ci	if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_BREAK_SENDING))
4688c2ecf20Sopenharmony_ci		return;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	/* We have to do it this way, because of the EXAR TXFIFO count bug. */
4718c2ecf20Sopenharmony_ci	if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM)))
4728c2ecf20Sopenharmony_ci		return;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	n = 32;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	/* cache tail of queue */
4778c2ecf20Sopenharmony_ci	tail = circ->tail & (UART_XMIT_SIZE - 1);
4788c2ecf20Sopenharmony_ci	qlen = uart_circ_chars_pending(circ);
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	/* Find minimum of the FIFO space, versus queue length */
4818c2ecf20Sopenharmony_ci	n = min(n, qlen);
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	while (n > 0) {
4848c2ecf20Sopenharmony_ci		writeb(circ->buf[tail], &ch->ch_cls_uart->txrx);
4858c2ecf20Sopenharmony_ci		tail = (tail + 1) & (UART_XMIT_SIZE - 1);
4868c2ecf20Sopenharmony_ci		n--;
4878c2ecf20Sopenharmony_ci		ch->ch_txcount++;
4888c2ecf20Sopenharmony_ci		len_written++;
4898c2ecf20Sopenharmony_ci	}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	/* Update the final tail */
4928c2ecf20Sopenharmony_ci	circ->tail = tail & (UART_XMIT_SIZE - 1);
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	if (len_written > ch->ch_t_tlevel)
4958c2ecf20Sopenharmony_ci		ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	if (uart_circ_empty(circ))
4988c2ecf20Sopenharmony_ci		uart_write_wakeup(&ch->uart_port);
4998c2ecf20Sopenharmony_ci}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_cistatic void cls_parse_modem(struct jsm_channel *ch, u8 signals)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	u8 msignals = signals;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	jsm_dbg(MSIGS, &ch->ch_bd->pci_dev,
5068c2ecf20Sopenharmony_ci		"neo_parse_modem: port: %d msignals: %x\n",
5078c2ecf20Sopenharmony_ci		ch->ch_portnum, msignals);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	/*
5108c2ecf20Sopenharmony_ci	 * Scrub off lower bits.
5118c2ecf20Sopenharmony_ci	 * They signify delta's, which I don't care about
5128c2ecf20Sopenharmony_ci	 * Keep DDCD and DDSR though
5138c2ecf20Sopenharmony_ci	 */
5148c2ecf20Sopenharmony_ci	msignals &= 0xf8;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	if (msignals & UART_MSR_DDCD)
5178c2ecf20Sopenharmony_ci		uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD);
5188c2ecf20Sopenharmony_ci	if (msignals & UART_MSR_DDSR)
5198c2ecf20Sopenharmony_ci		uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_CTS);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	if (msignals & UART_MSR_DCD)
5228c2ecf20Sopenharmony_ci		ch->ch_mistat |= UART_MSR_DCD;
5238c2ecf20Sopenharmony_ci	else
5248c2ecf20Sopenharmony_ci		ch->ch_mistat &= ~UART_MSR_DCD;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	if (msignals & UART_MSR_DSR)
5278c2ecf20Sopenharmony_ci		ch->ch_mistat |= UART_MSR_DSR;
5288c2ecf20Sopenharmony_ci	else
5298c2ecf20Sopenharmony_ci		ch->ch_mistat &= ~UART_MSR_DSR;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	if (msignals & UART_MSR_RI)
5328c2ecf20Sopenharmony_ci		ch->ch_mistat |= UART_MSR_RI;
5338c2ecf20Sopenharmony_ci	else
5348c2ecf20Sopenharmony_ci		ch->ch_mistat &= ~UART_MSR_RI;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	if (msignals & UART_MSR_CTS)
5378c2ecf20Sopenharmony_ci		ch->ch_mistat |= UART_MSR_CTS;
5388c2ecf20Sopenharmony_ci	else
5398c2ecf20Sopenharmony_ci		ch->ch_mistat &= ~UART_MSR_CTS;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	jsm_dbg(MSIGS, &ch->ch_bd->pci_dev,
5428c2ecf20Sopenharmony_ci		"Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n",
5438c2ecf20Sopenharmony_ci		ch->ch_portnum,
5448c2ecf20Sopenharmony_ci		!!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR),
5458c2ecf20Sopenharmony_ci		!!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS),
5468c2ecf20Sopenharmony_ci		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_CTS),
5478c2ecf20Sopenharmony_ci		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DSR),
5488c2ecf20Sopenharmony_ci		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_RI),
5498c2ecf20Sopenharmony_ci		!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DCD));
5508c2ecf20Sopenharmony_ci}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci/* Parse the ISR register for the specific port */
5538c2ecf20Sopenharmony_cistatic inline void cls_parse_isr(struct jsm_board *brd, uint port)
5548c2ecf20Sopenharmony_ci{
5558c2ecf20Sopenharmony_ci	struct jsm_channel *ch;
5568c2ecf20Sopenharmony_ci	u8 isr = 0;
5578c2ecf20Sopenharmony_ci	unsigned long flags;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	/*
5608c2ecf20Sopenharmony_ci	 * No need to verify board pointer, it was already
5618c2ecf20Sopenharmony_ci	 * verified in the interrupt routine.
5628c2ecf20Sopenharmony_ci	 */
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	if (port >= brd->nasync)
5658c2ecf20Sopenharmony_ci		return;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	ch = brd->channels[port];
5688c2ecf20Sopenharmony_ci	if (!ch)
5698c2ecf20Sopenharmony_ci		return;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	/* Here we try to figure out what caused the interrupt to happen */
5728c2ecf20Sopenharmony_ci	while (1) {
5738c2ecf20Sopenharmony_ci		isr = readb(&ch->ch_cls_uart->isr_fcr);
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci		/* Bail if no pending interrupt on port */
5768c2ecf20Sopenharmony_ci		if (isr & UART_IIR_NO_INT)
5778c2ecf20Sopenharmony_ci			break;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci		/* Receive Interrupt pending */
5808c2ecf20Sopenharmony_ci		if (isr & (UART_IIR_RDI | UART_IIR_RDI_TIMEOUT)) {
5818c2ecf20Sopenharmony_ci			/* Read data from uart -> queue */
5828c2ecf20Sopenharmony_ci			cls_copy_data_from_uart_to_queue(ch);
5838c2ecf20Sopenharmony_ci			jsm_check_queue_flow_control(ch);
5848c2ecf20Sopenharmony_ci		}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci		/* Transmit Hold register empty pending */
5878c2ecf20Sopenharmony_ci		if (isr & UART_IIR_THRI) {
5888c2ecf20Sopenharmony_ci			/* Transfer data (if any) from Write Queue -> UART. */
5898c2ecf20Sopenharmony_ci			spin_lock_irqsave(&ch->ch_lock, flags);
5908c2ecf20Sopenharmony_ci			ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
5918c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&ch->ch_lock, flags);
5928c2ecf20Sopenharmony_ci			cls_copy_data_from_queue_to_uart(ch);
5938c2ecf20Sopenharmony_ci		}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci		/*
5968c2ecf20Sopenharmony_ci		 * CTS/RTS change of state:
5978c2ecf20Sopenharmony_ci		 * Don't need to do anything, the cls_parse_modem
5988c2ecf20Sopenharmony_ci		 * below will grab the updated modem signals.
5998c2ecf20Sopenharmony_ci		 */
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci		/* Parse any modem signal changes */
6028c2ecf20Sopenharmony_ci		cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr));
6038c2ecf20Sopenharmony_ci	}
6048c2ecf20Sopenharmony_ci}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci/* Channel lock MUST be held before calling this function! */
6078c2ecf20Sopenharmony_cistatic void cls_flush_uart_write(struct jsm_channel *ch)
6088c2ecf20Sopenharmony_ci{
6098c2ecf20Sopenharmony_ci	u8 tmp = 0;
6108c2ecf20Sopenharmony_ci	u8 i = 0;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	if (!ch)
6138c2ecf20Sopenharmony_ci		return;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT),
6168c2ecf20Sopenharmony_ci						&ch->ch_cls_uart->isr_fcr);
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	for (i = 0; i < 10; i++) {
6198c2ecf20Sopenharmony_ci		/* Check to see if the UART feels it completely flushed FIFO */
6208c2ecf20Sopenharmony_ci		tmp = readb(&ch->ch_cls_uart->isr_fcr);
6218c2ecf20Sopenharmony_ci		if (tmp & UART_FCR_CLEAR_XMIT) {
6228c2ecf20Sopenharmony_ci			jsm_dbg(IOCTL, &ch->ch_bd->pci_dev,
6238c2ecf20Sopenharmony_ci				"Still flushing TX UART... i: %d\n", i);
6248c2ecf20Sopenharmony_ci			udelay(10);
6258c2ecf20Sopenharmony_ci		} else
6268c2ecf20Sopenharmony_ci			break;
6278c2ecf20Sopenharmony_ci	}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
6308c2ecf20Sopenharmony_ci}
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci/* Channel lock MUST be held before calling this function! */
6338c2ecf20Sopenharmony_cistatic void cls_flush_uart_read(struct jsm_channel *ch)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	if (!ch)
6368c2ecf20Sopenharmony_ci		return;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	/*
6398c2ecf20Sopenharmony_ci	 * For complete POSIX compatibility, we should be purging the
6408c2ecf20Sopenharmony_ci	 * read FIFO in the UART here.
6418c2ecf20Sopenharmony_ci	 *
6428c2ecf20Sopenharmony_ci	 * However, clearing the read FIFO (UART_FCR_CLEAR_RCVR) also
6438c2ecf20Sopenharmony_ci	 * incorrectly flushes write data as well as just basically trashing the
6448c2ecf20Sopenharmony_ci	 * FIFO.
6458c2ecf20Sopenharmony_ci	 *
6468c2ecf20Sopenharmony_ci	 * Presumably, this is a bug in this UART.
6478c2ecf20Sopenharmony_ci	 */
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	udelay(10);
6508c2ecf20Sopenharmony_ci}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_cistatic void cls_send_start_character(struct jsm_channel *ch)
6538c2ecf20Sopenharmony_ci{
6548c2ecf20Sopenharmony_ci	if (!ch)
6558c2ecf20Sopenharmony_ci		return;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	if (ch->ch_startc != __DISABLED_CHAR) {
6588c2ecf20Sopenharmony_ci		ch->ch_xon_sends++;
6598c2ecf20Sopenharmony_ci		writeb(ch->ch_startc, &ch->ch_cls_uart->txrx);
6608c2ecf20Sopenharmony_ci	}
6618c2ecf20Sopenharmony_ci}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_cistatic void cls_send_stop_character(struct jsm_channel *ch)
6648c2ecf20Sopenharmony_ci{
6658c2ecf20Sopenharmony_ci	if (!ch)
6668c2ecf20Sopenharmony_ci		return;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	if (ch->ch_stopc != __DISABLED_CHAR) {
6698c2ecf20Sopenharmony_ci		ch->ch_xoff_sends++;
6708c2ecf20Sopenharmony_ci		writeb(ch->ch_stopc, &ch->ch_cls_uart->txrx);
6718c2ecf20Sopenharmony_ci	}
6728c2ecf20Sopenharmony_ci}
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci/*
6758c2ecf20Sopenharmony_ci * cls_param()
6768c2ecf20Sopenharmony_ci * Send any/all changes to the line to the UART.
6778c2ecf20Sopenharmony_ci */
6788c2ecf20Sopenharmony_cistatic void cls_param(struct jsm_channel *ch)
6798c2ecf20Sopenharmony_ci{
6808c2ecf20Sopenharmony_ci	u8 lcr = 0;
6818c2ecf20Sopenharmony_ci	u8 uart_lcr = 0;
6828c2ecf20Sopenharmony_ci	u8 ier = 0;
6838c2ecf20Sopenharmony_ci	u32 baud = 9600;
6848c2ecf20Sopenharmony_ci	int quot = 0;
6858c2ecf20Sopenharmony_ci	struct jsm_board *bd;
6868c2ecf20Sopenharmony_ci	int i;
6878c2ecf20Sopenharmony_ci	unsigned int cflag;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	bd = ch->ch_bd;
6908c2ecf20Sopenharmony_ci	if (!bd)
6918c2ecf20Sopenharmony_ci		return;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	/*
6948c2ecf20Sopenharmony_ci	 * If baud rate is zero, flush queues, and set mval to drop DTR.
6958c2ecf20Sopenharmony_ci	 */
6968c2ecf20Sopenharmony_ci	if ((ch->ch_c_cflag & (CBAUD)) == 0) {
6978c2ecf20Sopenharmony_ci		ch->ch_r_head = 0;
6988c2ecf20Sopenharmony_ci		ch->ch_r_tail = 0;
6998c2ecf20Sopenharmony_ci		ch->ch_e_head = 0;
7008c2ecf20Sopenharmony_ci		ch->ch_e_tail = 0;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci		cls_flush_uart_write(ch);
7038c2ecf20Sopenharmony_ci		cls_flush_uart_read(ch);
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci		/* The baudrate is B0 so all modem lines are to be dropped. */
7068c2ecf20Sopenharmony_ci		ch->ch_flags |= (CH_BAUD0);
7078c2ecf20Sopenharmony_ci		ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
7088c2ecf20Sopenharmony_ci		cls_assert_modem_signals(ch);
7098c2ecf20Sopenharmony_ci		return;
7108c2ecf20Sopenharmony_ci	}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	cflag = C_BAUD(ch->uart_port.state->port.tty);
7138c2ecf20Sopenharmony_ci	baud = 9600;
7148c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(baud_rates); i++) {
7158c2ecf20Sopenharmony_ci		if (baud_rates[i].cflag == cflag) {
7168c2ecf20Sopenharmony_ci			baud = baud_rates[i].rate;
7178c2ecf20Sopenharmony_ci			break;
7188c2ecf20Sopenharmony_ci		}
7198c2ecf20Sopenharmony_ci	}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	if (ch->ch_flags & CH_BAUD0)
7228c2ecf20Sopenharmony_ci		ch->ch_flags &= ~(CH_BAUD0);
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	if (ch->ch_c_cflag & PARENB)
7258c2ecf20Sopenharmony_ci		lcr |= UART_LCR_PARITY;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	if (!(ch->ch_c_cflag & PARODD))
7288c2ecf20Sopenharmony_ci		lcr |= UART_LCR_EPAR;
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	/*
7318c2ecf20Sopenharmony_ci	 * Not all platforms support mark/space parity,
7328c2ecf20Sopenharmony_ci	 * so this will hide behind an ifdef.
7338c2ecf20Sopenharmony_ci	 */
7348c2ecf20Sopenharmony_ci#ifdef CMSPAR
7358c2ecf20Sopenharmony_ci	if (ch->ch_c_cflag & CMSPAR)
7368c2ecf20Sopenharmony_ci		lcr |= UART_LCR_SPAR;
7378c2ecf20Sopenharmony_ci#endif
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	if (ch->ch_c_cflag & CSTOPB)
7408c2ecf20Sopenharmony_ci		lcr |= UART_LCR_STOP;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	switch (ch->ch_c_cflag & CSIZE) {
7438c2ecf20Sopenharmony_ci	case CS5:
7448c2ecf20Sopenharmony_ci		lcr |= UART_LCR_WLEN5;
7458c2ecf20Sopenharmony_ci		break;
7468c2ecf20Sopenharmony_ci	case CS6:
7478c2ecf20Sopenharmony_ci		lcr |= UART_LCR_WLEN6;
7488c2ecf20Sopenharmony_ci		break;
7498c2ecf20Sopenharmony_ci	case CS7:
7508c2ecf20Sopenharmony_ci		lcr |= UART_LCR_WLEN7;
7518c2ecf20Sopenharmony_ci		break;
7528c2ecf20Sopenharmony_ci	case CS8:
7538c2ecf20Sopenharmony_ci	default:
7548c2ecf20Sopenharmony_ci		lcr |= UART_LCR_WLEN8;
7558c2ecf20Sopenharmony_ci		break;
7568c2ecf20Sopenharmony_ci	}
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	ier = readb(&ch->ch_cls_uart->ier);
7598c2ecf20Sopenharmony_ci	uart_lcr = readb(&ch->ch_cls_uart->lcr);
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	quot = ch->ch_bd->bd_dividend / baud;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	if (quot != 0) {
7648c2ecf20Sopenharmony_ci		writeb(UART_LCR_DLAB, &ch->ch_cls_uart->lcr);
7658c2ecf20Sopenharmony_ci		writeb((quot & 0xff), &ch->ch_cls_uart->txrx);
7668c2ecf20Sopenharmony_ci		writeb((quot >> 8), &ch->ch_cls_uart->ier);
7678c2ecf20Sopenharmony_ci		writeb(lcr, &ch->ch_cls_uart->lcr);
7688c2ecf20Sopenharmony_ci	}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	if (uart_lcr != lcr)
7718c2ecf20Sopenharmony_ci		writeb(lcr, &ch->ch_cls_uart->lcr);
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	if (ch->ch_c_cflag & CREAD)
7748c2ecf20Sopenharmony_ci		ier |= (UART_IER_RDI | UART_IER_RLSI);
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	ier |= (UART_IER_THRI | UART_IER_MSI);
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	writeb(ier, &ch->ch_cls_uart->ier);
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	if (ch->ch_c_cflag & CRTSCTS)
7818c2ecf20Sopenharmony_ci		cls_set_cts_flow_control(ch);
7828c2ecf20Sopenharmony_ci	else if (ch->ch_c_iflag & IXON) {
7838c2ecf20Sopenharmony_ci		/*
7848c2ecf20Sopenharmony_ci		 * If start/stop is set to disable,
7858c2ecf20Sopenharmony_ci		 * then we should disable flow control.
7868c2ecf20Sopenharmony_ci		 */
7878c2ecf20Sopenharmony_ci		if ((ch->ch_startc == __DISABLED_CHAR) ||
7888c2ecf20Sopenharmony_ci			(ch->ch_stopc == __DISABLED_CHAR))
7898c2ecf20Sopenharmony_ci			cls_set_no_output_flow_control(ch);
7908c2ecf20Sopenharmony_ci		else
7918c2ecf20Sopenharmony_ci			cls_set_ixon_flow_control(ch);
7928c2ecf20Sopenharmony_ci	} else
7938c2ecf20Sopenharmony_ci		cls_set_no_output_flow_control(ch);
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	if (ch->ch_c_cflag & CRTSCTS)
7968c2ecf20Sopenharmony_ci		cls_set_rts_flow_control(ch);
7978c2ecf20Sopenharmony_ci	else if (ch->ch_c_iflag & IXOFF) {
7988c2ecf20Sopenharmony_ci		/*
7998c2ecf20Sopenharmony_ci		 * If start/stop is set to disable,
8008c2ecf20Sopenharmony_ci		 * then we should disable flow control.
8018c2ecf20Sopenharmony_ci		 */
8028c2ecf20Sopenharmony_ci		if ((ch->ch_startc == __DISABLED_CHAR) ||
8038c2ecf20Sopenharmony_ci			(ch->ch_stopc == __DISABLED_CHAR))
8048c2ecf20Sopenharmony_ci			cls_set_no_input_flow_control(ch);
8058c2ecf20Sopenharmony_ci		else
8068c2ecf20Sopenharmony_ci			cls_set_ixoff_flow_control(ch);
8078c2ecf20Sopenharmony_ci	} else
8088c2ecf20Sopenharmony_ci		cls_set_no_input_flow_control(ch);
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	cls_assert_modem_signals(ch);
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	/* get current status of the modem signals now */
8138c2ecf20Sopenharmony_ci	cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr));
8148c2ecf20Sopenharmony_ci}
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci/*
8178c2ecf20Sopenharmony_ci * cls_intr()
8188c2ecf20Sopenharmony_ci *
8198c2ecf20Sopenharmony_ci * Classic specific interrupt handler.
8208c2ecf20Sopenharmony_ci */
8218c2ecf20Sopenharmony_cistatic irqreturn_t cls_intr(int irq, void *voidbrd)
8228c2ecf20Sopenharmony_ci{
8238c2ecf20Sopenharmony_ci	struct jsm_board *brd = voidbrd;
8248c2ecf20Sopenharmony_ci	unsigned long lock_flags;
8258c2ecf20Sopenharmony_ci	unsigned char uart_poll;
8268c2ecf20Sopenharmony_ci	uint i = 0;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	/* Lock out the slow poller from running on this board. */
8298c2ecf20Sopenharmony_ci	spin_lock_irqsave(&brd->bd_intr_lock, lock_flags);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	/*
8328c2ecf20Sopenharmony_ci	 * Check the board's global interrupt offset to see if we
8338c2ecf20Sopenharmony_ci	 * acctually do have an interrupt pending on us.
8348c2ecf20Sopenharmony_ci	 */
8358c2ecf20Sopenharmony_ci	uart_poll = readb(brd->re_map_membase + UART_CLASSIC_POLL_ADDR_OFFSET);
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	jsm_dbg(INTR, &brd->pci_dev, "%s:%d uart_poll: %x\n",
8388c2ecf20Sopenharmony_ci		__FILE__, __LINE__, uart_poll);
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	if (!uart_poll) {
8418c2ecf20Sopenharmony_ci		jsm_dbg(INTR, &brd->pci_dev,
8428c2ecf20Sopenharmony_ci			"Kernel interrupted to me, but no pending interrupts...\n");
8438c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
8448c2ecf20Sopenharmony_ci		return IRQ_NONE;
8458c2ecf20Sopenharmony_ci	}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	/* At this point, we have at least SOMETHING to service, dig further. */
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	/* Parse each port to find out what caused the interrupt */
8508c2ecf20Sopenharmony_ci	for (i = 0; i < brd->nasync; i++)
8518c2ecf20Sopenharmony_ci		cls_parse_isr(brd, i);
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
8568c2ecf20Sopenharmony_ci}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci/* Inits UART */
8598c2ecf20Sopenharmony_cistatic void cls_uart_init(struct jsm_channel *ch)
8608c2ecf20Sopenharmony_ci{
8618c2ecf20Sopenharmony_ci	unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
8628c2ecf20Sopenharmony_ci	unsigned char isr_fcr = 0;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_cls_uart->ier);
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	/*
8678c2ecf20Sopenharmony_ci	 * The Enhanced Register Set may only be accessed when
8688c2ecf20Sopenharmony_ci	 * the Line Control Register is set to 0xBFh.
8698c2ecf20Sopenharmony_ci	 */
8708c2ecf20Sopenharmony_ci	writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	/* Turn on Enhanced/Extended controls */
8758c2ecf20Sopenharmony_ci	isr_fcr |= (UART_EXAR654_EFR_ECB);
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	/* Write old LCR value back out, which turns enhanced access off */
8808c2ecf20Sopenharmony_ci	writeb(lcrb, &ch->ch_cls_uart->lcr);
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	/* Clear out UART and FIFO */
8838c2ecf20Sopenharmony_ci	readb(&ch->ch_cls_uart->txrx);
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT),
8868c2ecf20Sopenharmony_ci						 &ch->ch_cls_uart->isr_fcr);
8878c2ecf20Sopenharmony_ci	udelay(10);
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	ch->ch_flags |= (CH_FIFO_ENABLED | CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	readb(&ch->ch_cls_uart->lsr);
8928c2ecf20Sopenharmony_ci	readb(&ch->ch_cls_uart->msr);
8938c2ecf20Sopenharmony_ci}
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci/*
8968c2ecf20Sopenharmony_ci * Turns off UART.
8978c2ecf20Sopenharmony_ci */
8988c2ecf20Sopenharmony_cistatic void cls_uart_off(struct jsm_channel *ch)
8998c2ecf20Sopenharmony_ci{
9008c2ecf20Sopenharmony_ci	/* Stop all interrupts from accurring. */
9018c2ecf20Sopenharmony_ci	writeb(0, &ch->ch_cls_uart->ier);
9028c2ecf20Sopenharmony_ci}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci/*
9058c2ecf20Sopenharmony_ci * cls_get_uarts_bytes_left.
9068c2ecf20Sopenharmony_ci * Returns 0 is nothing left in the FIFO, returns 1 otherwise.
9078c2ecf20Sopenharmony_ci *
9088c2ecf20Sopenharmony_ci * The channel lock MUST be held by the calling function.
9098c2ecf20Sopenharmony_ci */
9108c2ecf20Sopenharmony_cistatic u32 cls_get_uart_bytes_left(struct jsm_channel *ch)
9118c2ecf20Sopenharmony_ci{
9128c2ecf20Sopenharmony_ci	u8 left = 0;
9138c2ecf20Sopenharmony_ci	u8 lsr = readb(&ch->ch_cls_uart->lsr);
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	/* Determine whether the Transmitter is empty or not */
9168c2ecf20Sopenharmony_ci	if (!(lsr & UART_LSR_TEMT))
9178c2ecf20Sopenharmony_ci		left = 1;
9188c2ecf20Sopenharmony_ci	else {
9198c2ecf20Sopenharmony_ci		ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
9208c2ecf20Sopenharmony_ci		left = 0;
9218c2ecf20Sopenharmony_ci	}
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	return left;
9248c2ecf20Sopenharmony_ci}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci/*
9278c2ecf20Sopenharmony_ci * cls_send_break.
9288c2ecf20Sopenharmony_ci * Starts sending a break thru the UART.
9298c2ecf20Sopenharmony_ci *
9308c2ecf20Sopenharmony_ci * The channel lock MUST be held by the calling function.
9318c2ecf20Sopenharmony_ci */
9328c2ecf20Sopenharmony_cistatic void cls_send_break(struct jsm_channel *ch)
9338c2ecf20Sopenharmony_ci{
9348c2ecf20Sopenharmony_ci	/* Tell the UART to start sending the break */
9358c2ecf20Sopenharmony_ci	if (!(ch->ch_flags & CH_BREAK_SENDING)) {
9368c2ecf20Sopenharmony_ci		u8 temp = readb(&ch->ch_cls_uart->lcr);
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci		writeb((temp | UART_LCR_SBC), &ch->ch_cls_uart->lcr);
9398c2ecf20Sopenharmony_ci		ch->ch_flags |= (CH_BREAK_SENDING);
9408c2ecf20Sopenharmony_ci	}
9418c2ecf20Sopenharmony_ci}
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci/*
9448c2ecf20Sopenharmony_ci * cls_send_immediate_char.
9458c2ecf20Sopenharmony_ci * Sends a specific character as soon as possible to the UART,
9468c2ecf20Sopenharmony_ci * jumping over any bytes that might be in the write queue.
9478c2ecf20Sopenharmony_ci *
9488c2ecf20Sopenharmony_ci * The channel lock MUST be held by the calling function.
9498c2ecf20Sopenharmony_ci */
9508c2ecf20Sopenharmony_cistatic void cls_send_immediate_char(struct jsm_channel *ch, unsigned char c)
9518c2ecf20Sopenharmony_ci{
9528c2ecf20Sopenharmony_ci	writeb(c, &ch->ch_cls_uart->txrx);
9538c2ecf20Sopenharmony_ci}
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_cistruct board_ops jsm_cls_ops = {
9568c2ecf20Sopenharmony_ci	.intr =				cls_intr,
9578c2ecf20Sopenharmony_ci	.uart_init =			cls_uart_init,
9588c2ecf20Sopenharmony_ci	.uart_off =			cls_uart_off,
9598c2ecf20Sopenharmony_ci	.param =			cls_param,
9608c2ecf20Sopenharmony_ci	.assert_modem_signals =		cls_assert_modem_signals,
9618c2ecf20Sopenharmony_ci	.flush_uart_write =		cls_flush_uart_write,
9628c2ecf20Sopenharmony_ci	.flush_uart_read =		cls_flush_uart_read,
9638c2ecf20Sopenharmony_ci	.disable_receiver =		cls_disable_receiver,
9648c2ecf20Sopenharmony_ci	.enable_receiver =		cls_enable_receiver,
9658c2ecf20Sopenharmony_ci	.send_break =			cls_send_break,
9668c2ecf20Sopenharmony_ci	.clear_break =			cls_clear_break,
9678c2ecf20Sopenharmony_ci	.send_start_character =		cls_send_start_character,
9688c2ecf20Sopenharmony_ci	.send_stop_character =		cls_send_stop_character,
9698c2ecf20Sopenharmony_ci	.copy_data_from_queue_to_uart = cls_copy_data_from_queue_to_uart,
9708c2ecf20Sopenharmony_ci	.get_uart_bytes_left =		cls_get_uart_bytes_left,
9718c2ecf20Sopenharmony_ci	.send_immediate_char =		cls_send_immediate_char
9728c2ecf20Sopenharmony_ci};
9738c2ecf20Sopenharmony_ci
974