18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/************************************************************************ 38c2ecf20Sopenharmony_ci * Copyright 2003 Digi International (www.digi.com) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2004 IBM Corporation. All rights reserved. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Contact Information: 88c2ecf20Sopenharmony_ci * Scott H Kilau <Scott_Kilau@digi.com> 98c2ecf20Sopenharmony_ci * Wendy Xiong <wendyx@us.ibm.com> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci ***********************************************************************/ 128c2ecf20Sopenharmony_ci#include <linux/delay.h> /* For udelay */ 138c2ecf20Sopenharmony_ci#include <linux/serial_reg.h> /* For the various UART offsets */ 148c2ecf20Sopenharmony_ci#include <linux/tty.h> 158c2ecf20Sopenharmony_ci#include <linux/pci.h> 168c2ecf20Sopenharmony_ci#include <asm/io.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "jsm.h" /* Driver main header file */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic u32 jsm_offset_table[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* 238c2ecf20Sopenharmony_ci * This function allows calls to ensure that all outstanding 248c2ecf20Sopenharmony_ci * PCI writes have been completed, by doing a PCI read against 258c2ecf20Sopenharmony_ci * a non-destructive, read-only location on the Neo card. 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * In this case, we are reading the DVID (Read-only Device Identification) 288c2ecf20Sopenharmony_ci * value of the Neo card. 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_cistatic inline void neo_pci_posting_flush(struct jsm_board *bd) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci readb(bd->re_map_membase + 0x8D); 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic void neo_set_cts_flow_control(struct jsm_channel *ch) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci u8 ier, efr; 388c2ecf20Sopenharmony_ci ier = readb(&ch->ch_neo_uart->ier); 398c2ecf20Sopenharmony_ci efr = readb(&ch->ch_neo_uart->efr); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Setting CTSFLOW\n"); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci /* Turn on auto CTS flow control */ 448c2ecf20Sopenharmony_ci ier |= (UART_17158_IER_CTSDSR); 458c2ecf20Sopenharmony_ci efr |= (UART_17158_EFR_ECB | UART_17158_EFR_CTSDSR); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci /* Turn off auto Xon flow control */ 488c2ecf20Sopenharmony_ci efr &= ~(UART_17158_EFR_IXON); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci /* Why? Becuz Exar's spec says we have to zero it out before setting it */ 518c2ecf20Sopenharmony_ci writeb(0, &ch->ch_neo_uart->efr); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci /* Turn on UART enhanced bits */ 548c2ecf20Sopenharmony_ci writeb(efr, &ch->ch_neo_uart->efr); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci /* Turn on table D, with 8 char hi/low watermarks */ 578c2ecf20Sopenharmony_ci writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci /* Feed the UART our trigger levels */ 608c2ecf20Sopenharmony_ci writeb(8, &ch->ch_neo_uart->tfifo); 618c2ecf20Sopenharmony_ci ch->ch_t_tlevel = 8; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci writeb(ier, &ch->ch_neo_uart->ier); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic void neo_set_rts_flow_control(struct jsm_channel *ch) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci u8 ier, efr; 698c2ecf20Sopenharmony_ci ier = readb(&ch->ch_neo_uart->ier); 708c2ecf20Sopenharmony_ci efr = readb(&ch->ch_neo_uart->efr); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Setting RTSFLOW\n"); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* Turn on auto RTS flow control */ 758c2ecf20Sopenharmony_ci ier |= (UART_17158_IER_RTSDTR); 768c2ecf20Sopenharmony_ci efr |= (UART_17158_EFR_ECB | UART_17158_EFR_RTSDTR); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* Turn off auto Xoff flow control */ 798c2ecf20Sopenharmony_ci ier &= ~(UART_17158_IER_XOFF); 808c2ecf20Sopenharmony_ci efr &= ~(UART_17158_EFR_IXOFF); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* Why? Becuz Exar's spec says we have to zero it out before setting it */ 838c2ecf20Sopenharmony_ci writeb(0, &ch->ch_neo_uart->efr); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* Turn on UART enhanced bits */ 868c2ecf20Sopenharmony_ci writeb(efr, &ch->ch_neo_uart->efr); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_4DELAY), &ch->ch_neo_uart->fctr); 898c2ecf20Sopenharmony_ci ch->ch_r_watermark = 4; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci writeb(56, &ch->ch_neo_uart->rfifo); 928c2ecf20Sopenharmony_ci ch->ch_r_tlevel = 56; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci writeb(ier, &ch->ch_neo_uart->ier); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* 978c2ecf20Sopenharmony_ci * From the Neo UART spec sheet: 988c2ecf20Sopenharmony_ci * The auto RTS/DTR function must be started by asserting 998c2ecf20Sopenharmony_ci * RTS/DTR# output pin (MCR bit-0 or 1 to logic 1 after 1008c2ecf20Sopenharmony_ci * it is enabled. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ci ch->ch_mostat |= (UART_MCR_RTS); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic void neo_set_ixon_flow_control(struct jsm_channel *ch) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci u8 ier, efr; 1098c2ecf20Sopenharmony_ci ier = readb(&ch->ch_neo_uart->ier); 1108c2ecf20Sopenharmony_ci efr = readb(&ch->ch_neo_uart->efr); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Setting IXON FLOW\n"); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* Turn off auto CTS flow control */ 1158c2ecf20Sopenharmony_ci ier &= ~(UART_17158_IER_CTSDSR); 1168c2ecf20Sopenharmony_ci efr &= ~(UART_17158_EFR_CTSDSR); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* Turn on auto Xon flow control */ 1198c2ecf20Sopenharmony_ci efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXON); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* Why? Becuz Exar's spec says we have to zero it out before setting it */ 1228c2ecf20Sopenharmony_ci writeb(0, &ch->ch_neo_uart->efr); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* Turn on UART enhanced bits */ 1258c2ecf20Sopenharmony_ci writeb(efr, &ch->ch_neo_uart->efr); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr); 1288c2ecf20Sopenharmony_ci ch->ch_r_watermark = 4; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci writeb(32, &ch->ch_neo_uart->rfifo); 1318c2ecf20Sopenharmony_ci ch->ch_r_tlevel = 32; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* Tell UART what start/stop chars it should be looking for */ 1348c2ecf20Sopenharmony_ci writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1); 1358c2ecf20Sopenharmony_ci writeb(0, &ch->ch_neo_uart->xonchar2); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1); 1388c2ecf20Sopenharmony_ci writeb(0, &ch->ch_neo_uart->xoffchar2); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci writeb(ier, &ch->ch_neo_uart->ier); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic void neo_set_ixoff_flow_control(struct jsm_channel *ch) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci u8 ier, efr; 1468c2ecf20Sopenharmony_ci ier = readb(&ch->ch_neo_uart->ier); 1478c2ecf20Sopenharmony_ci efr = readb(&ch->ch_neo_uart->efr); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Setting IXOFF FLOW\n"); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* Turn off auto RTS flow control */ 1528c2ecf20Sopenharmony_ci ier &= ~(UART_17158_IER_RTSDTR); 1538c2ecf20Sopenharmony_ci efr &= ~(UART_17158_EFR_RTSDTR); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* Turn on auto Xoff flow control */ 1568c2ecf20Sopenharmony_ci ier |= (UART_17158_IER_XOFF); 1578c2ecf20Sopenharmony_ci efr |= (UART_17158_EFR_ECB | UART_17158_EFR_IXOFF); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* Why? Becuz Exar's spec says we have to zero it out before setting it */ 1608c2ecf20Sopenharmony_ci writeb(0, &ch->ch_neo_uart->efr); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* Turn on UART enhanced bits */ 1638c2ecf20Sopenharmony_ci writeb(efr, &ch->ch_neo_uart->efr); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* Turn on table D, with 8 char hi/low watermarks */ 1668c2ecf20Sopenharmony_ci writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci writeb(8, &ch->ch_neo_uart->tfifo); 1698c2ecf20Sopenharmony_ci ch->ch_t_tlevel = 8; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* Tell UART what start/stop chars it should be looking for */ 1728c2ecf20Sopenharmony_ci writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1); 1738c2ecf20Sopenharmony_ci writeb(0, &ch->ch_neo_uart->xonchar2); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1); 1768c2ecf20Sopenharmony_ci writeb(0, &ch->ch_neo_uart->xoffchar2); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci writeb(ier, &ch->ch_neo_uart->ier); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic void neo_set_no_input_flow_control(struct jsm_channel *ch) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci u8 ier, efr; 1848c2ecf20Sopenharmony_ci ier = readb(&ch->ch_neo_uart->ier); 1858c2ecf20Sopenharmony_ci efr = readb(&ch->ch_neo_uart->efr); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Unsetting Input FLOW\n"); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* Turn off auto RTS flow control */ 1908c2ecf20Sopenharmony_ci ier &= ~(UART_17158_IER_RTSDTR); 1918c2ecf20Sopenharmony_ci efr &= ~(UART_17158_EFR_RTSDTR); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* Turn off auto Xoff flow control */ 1948c2ecf20Sopenharmony_ci ier &= ~(UART_17158_IER_XOFF); 1958c2ecf20Sopenharmony_ci if (ch->ch_c_iflag & IXON) 1968c2ecf20Sopenharmony_ci efr &= ~(UART_17158_EFR_IXOFF); 1978c2ecf20Sopenharmony_ci else 1988c2ecf20Sopenharmony_ci efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXOFF); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* Why? Becuz Exar's spec says we have to zero it out before setting it */ 2018c2ecf20Sopenharmony_ci writeb(0, &ch->ch_neo_uart->efr); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* Turn on UART enhanced bits */ 2048c2ecf20Sopenharmony_ci writeb(efr, &ch->ch_neo_uart->efr); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* Turn on table D, with 8 char hi/low watermarks */ 2078c2ecf20Sopenharmony_ci writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci ch->ch_r_watermark = 0; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci writeb(16, &ch->ch_neo_uart->tfifo); 2128c2ecf20Sopenharmony_ci ch->ch_t_tlevel = 16; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci writeb(16, &ch->ch_neo_uart->rfifo); 2158c2ecf20Sopenharmony_ci ch->ch_r_tlevel = 16; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci writeb(ier, &ch->ch_neo_uart->ier); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic void neo_set_no_output_flow_control(struct jsm_channel *ch) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci u8 ier, efr; 2238c2ecf20Sopenharmony_ci ier = readb(&ch->ch_neo_uart->ier); 2248c2ecf20Sopenharmony_ci efr = readb(&ch->ch_neo_uart->efr); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "Unsetting Output FLOW\n"); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* Turn off auto CTS flow control */ 2298c2ecf20Sopenharmony_ci ier &= ~(UART_17158_IER_CTSDSR); 2308c2ecf20Sopenharmony_ci efr &= ~(UART_17158_EFR_CTSDSR); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* Turn off auto Xon flow control */ 2338c2ecf20Sopenharmony_ci if (ch->ch_c_iflag & IXOFF) 2348c2ecf20Sopenharmony_ci efr &= ~(UART_17158_EFR_IXON); 2358c2ecf20Sopenharmony_ci else 2368c2ecf20Sopenharmony_ci efr &= ~(UART_17158_EFR_ECB | UART_17158_EFR_IXON); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* Why? Becuz Exar's spec says we have to zero it out before setting it */ 2398c2ecf20Sopenharmony_ci writeb(0, &ch->ch_neo_uart->efr); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* Turn on UART enhanced bits */ 2428c2ecf20Sopenharmony_ci writeb(efr, &ch->ch_neo_uart->efr); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* Turn on table D, with 8 char hi/low watermarks */ 2458c2ecf20Sopenharmony_ci writeb((UART_17158_FCTR_TRGD | UART_17158_FCTR_RTS_8DELAY), &ch->ch_neo_uart->fctr); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci ch->ch_r_watermark = 0; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci writeb(16, &ch->ch_neo_uart->tfifo); 2508c2ecf20Sopenharmony_ci ch->ch_t_tlevel = 16; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci writeb(16, &ch->ch_neo_uart->rfifo); 2538c2ecf20Sopenharmony_ci ch->ch_r_tlevel = 16; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci writeb(ier, &ch->ch_neo_uart->ier); 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic inline void neo_set_new_start_stop_chars(struct jsm_channel *ch) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* if hardware flow control is set, then skip this whole thing */ 2628c2ecf20Sopenharmony_ci if (ch->ch_c_cflag & CRTSCTS) 2638c2ecf20Sopenharmony_ci return; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci jsm_dbg(PARAM, &ch->ch_bd->pci_dev, "start\n"); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* Tell UART what start/stop chars it should be looking for */ 2688c2ecf20Sopenharmony_ci writeb(ch->ch_startc, &ch->ch_neo_uart->xonchar1); 2698c2ecf20Sopenharmony_ci writeb(0, &ch->ch_neo_uart->xonchar2); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci writeb(ch->ch_stopc, &ch->ch_neo_uart->xoffchar1); 2728c2ecf20Sopenharmony_ci writeb(0, &ch->ch_neo_uart->xoffchar2); 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci int qleft = 0; 2788c2ecf20Sopenharmony_ci u8 linestatus = 0; 2798c2ecf20Sopenharmony_ci u8 error_mask = 0; 2808c2ecf20Sopenharmony_ci int n = 0; 2818c2ecf20Sopenharmony_ci int total = 0; 2828c2ecf20Sopenharmony_ci u16 head; 2838c2ecf20Sopenharmony_ci u16 tail; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* cache head and tail of queue */ 2868c2ecf20Sopenharmony_ci head = ch->ch_r_head & RQUEUEMASK; 2878c2ecf20Sopenharmony_ci tail = ch->ch_r_tail & RQUEUEMASK; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* Get our cached LSR */ 2908c2ecf20Sopenharmony_ci linestatus = ch->ch_cached_lsr; 2918c2ecf20Sopenharmony_ci ch->ch_cached_lsr = 0; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* Store how much space we have left in the queue */ 2948c2ecf20Sopenharmony_ci if ((qleft = tail - head - 1) < 0) 2958c2ecf20Sopenharmony_ci qleft += RQUEUEMASK + 1; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* 2988c2ecf20Sopenharmony_ci * If the UART is not in FIFO mode, force the FIFO copy to 2998c2ecf20Sopenharmony_ci * NOT be run, by setting total to 0. 3008c2ecf20Sopenharmony_ci * 3018c2ecf20Sopenharmony_ci * On the other hand, if the UART IS in FIFO mode, then ask 3028c2ecf20Sopenharmony_ci * the UART to give us an approximation of data it has RX'ed. 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_ci if (!(ch->ch_flags & CH_FIFO_ENABLED)) 3058c2ecf20Sopenharmony_ci total = 0; 3068c2ecf20Sopenharmony_ci else { 3078c2ecf20Sopenharmony_ci total = readb(&ch->ch_neo_uart->rfifo); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /* 3108c2ecf20Sopenharmony_ci * EXAR chip bug - RX FIFO COUNT - Fudge factor. 3118c2ecf20Sopenharmony_ci * 3128c2ecf20Sopenharmony_ci * This resolves a problem/bug with the Exar chip that sometimes 3138c2ecf20Sopenharmony_ci * returns a bogus value in the rfifo register. 3148c2ecf20Sopenharmony_ci * The count can be any where from 0-3 bytes "off". 3158c2ecf20Sopenharmony_ci * Bizarre, but true. 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_ci total -= 3; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* 3218c2ecf20Sopenharmony_ci * Finally, bound the copy to make sure we don't overflow 3228c2ecf20Sopenharmony_ci * our own queue... 3238c2ecf20Sopenharmony_ci * The byte by byte copy loop below this loop this will 3248c2ecf20Sopenharmony_ci * deal with the queue overflow possibility. 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_ci total = min(total, qleft); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci while (total > 0) { 3298c2ecf20Sopenharmony_ci /* 3308c2ecf20Sopenharmony_ci * Grab the linestatus register, we need to check 3318c2ecf20Sopenharmony_ci * to see if there are any errors in the FIFO. 3328c2ecf20Sopenharmony_ci */ 3338c2ecf20Sopenharmony_ci linestatus = readb(&ch->ch_neo_uart->lsr); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* 3368c2ecf20Sopenharmony_ci * Break out if there is a FIFO error somewhere. 3378c2ecf20Sopenharmony_ci * This will allow us to go byte by byte down below, 3388c2ecf20Sopenharmony_ci * finding the exact location of the error. 3398c2ecf20Sopenharmony_ci */ 3408c2ecf20Sopenharmony_ci if (linestatus & UART_17158_RX_FIFO_DATA_ERROR) 3418c2ecf20Sopenharmony_ci break; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* Make sure we don't go over the end of our queue */ 3448c2ecf20Sopenharmony_ci n = min(((u32) total), (RQUEUESIZE - (u32) head)); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* 3478c2ecf20Sopenharmony_ci * Cut down n even further if needed, this is to fix 3488c2ecf20Sopenharmony_ci * a problem with memcpy_fromio() with the Neo on the 3498c2ecf20Sopenharmony_ci * IBM pSeries platform. 3508c2ecf20Sopenharmony_ci * 15 bytes max appears to be the magic number. 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_ci n = min((u32) n, (u32) 12); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* 3558c2ecf20Sopenharmony_ci * Since we are grabbing the linestatus register, which 3568c2ecf20Sopenharmony_ci * will reset some bits after our read, we need to ensure 3578c2ecf20Sopenharmony_ci * we don't miss our TX FIFO emptys. 3588c2ecf20Sopenharmony_ci */ 3598c2ecf20Sopenharmony_ci if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR)) 3608c2ecf20Sopenharmony_ci ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci linestatus = 0; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci /* Copy data from uart to the queue */ 3658c2ecf20Sopenharmony_ci memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, n); 3668c2ecf20Sopenharmony_ci /* 3678c2ecf20Sopenharmony_ci * Since RX_FIFO_DATA_ERROR was 0, we are guaranteed 3688c2ecf20Sopenharmony_ci * that all the data currently in the FIFO is free of 3698c2ecf20Sopenharmony_ci * breaks and parity/frame/orun errors. 3708c2ecf20Sopenharmony_ci */ 3718c2ecf20Sopenharmony_ci memset(ch->ch_equeue + head, 0, n); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci /* Add to and flip head if needed */ 3748c2ecf20Sopenharmony_ci head = (head + n) & RQUEUEMASK; 3758c2ecf20Sopenharmony_ci total -= n; 3768c2ecf20Sopenharmony_ci qleft -= n; 3778c2ecf20Sopenharmony_ci ch->ch_rxcount += n; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* 3818c2ecf20Sopenharmony_ci * Create a mask to determine whether we should 3828c2ecf20Sopenharmony_ci * insert the character (if any) into our queue. 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_ci if (ch->ch_c_iflag & IGNBRK) 3858c2ecf20Sopenharmony_ci error_mask |= UART_LSR_BI; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* 3888c2ecf20Sopenharmony_ci * Now cleanup any leftover bytes still in the UART. 3898c2ecf20Sopenharmony_ci * Also deal with any possible queue overflow here as well. 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_ci while (1) { 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* 3948c2ecf20Sopenharmony_ci * Its possible we have a linestatus from the loop above 3958c2ecf20Sopenharmony_ci * this, so we "OR" on any extra bits. 3968c2ecf20Sopenharmony_ci */ 3978c2ecf20Sopenharmony_ci linestatus |= readb(&ch->ch_neo_uart->lsr); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* 4008c2ecf20Sopenharmony_ci * If the chip tells us there is no more data pending to 4018c2ecf20Sopenharmony_ci * be read, we can then leave. 4028c2ecf20Sopenharmony_ci * But before we do, cache the linestatus, just in case. 4038c2ecf20Sopenharmony_ci */ 4048c2ecf20Sopenharmony_ci if (!(linestatus & UART_LSR_DR)) { 4058c2ecf20Sopenharmony_ci ch->ch_cached_lsr = linestatus; 4068c2ecf20Sopenharmony_ci break; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci /* No need to store this bit */ 4108c2ecf20Sopenharmony_ci linestatus &= ~UART_LSR_DR; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* 4138c2ecf20Sopenharmony_ci * Since we are grabbing the linestatus register, which 4148c2ecf20Sopenharmony_ci * will reset some bits after our read, we need to ensure 4158c2ecf20Sopenharmony_ci * we don't miss our TX FIFO emptys. 4168c2ecf20Sopenharmony_ci */ 4178c2ecf20Sopenharmony_ci if (linestatus & (UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR)) { 4188c2ecf20Sopenharmony_ci linestatus &= ~(UART_LSR_THRE | UART_17158_TX_AND_FIFO_CLR); 4198c2ecf20Sopenharmony_ci ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* 4238c2ecf20Sopenharmony_ci * Discard character if we are ignoring the error mask. 4248c2ecf20Sopenharmony_ci */ 4258c2ecf20Sopenharmony_ci if (linestatus & error_mask) { 4268c2ecf20Sopenharmony_ci u8 discard; 4278c2ecf20Sopenharmony_ci linestatus = 0; 4288c2ecf20Sopenharmony_ci memcpy_fromio(&discard, &ch->ch_neo_uart->txrxburst, 1); 4298c2ecf20Sopenharmony_ci continue; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci /* 4338c2ecf20Sopenharmony_ci * If our queue is full, we have no choice but to drop some data. 4348c2ecf20Sopenharmony_ci * The assumption is that HWFLOW or SWFLOW should have stopped 4358c2ecf20Sopenharmony_ci * things way way before we got to this point. 4368c2ecf20Sopenharmony_ci * 4378c2ecf20Sopenharmony_ci * I decided that I wanted to ditch the oldest data first, 4388c2ecf20Sopenharmony_ci * I hope thats okay with everyone? Yes? Good. 4398c2ecf20Sopenharmony_ci */ 4408c2ecf20Sopenharmony_ci while (qleft < 1) { 4418c2ecf20Sopenharmony_ci jsm_dbg(READ, &ch->ch_bd->pci_dev, 4428c2ecf20Sopenharmony_ci "Queue full, dropping DATA:%x LSR:%x\n", 4438c2ecf20Sopenharmony_ci ch->ch_rqueue[tail], ch->ch_equeue[tail]); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci ch->ch_r_tail = tail = (tail + 1) & RQUEUEMASK; 4468c2ecf20Sopenharmony_ci ch->ch_err_overrun++; 4478c2ecf20Sopenharmony_ci qleft++; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, 1); 4518c2ecf20Sopenharmony_ci ch->ch_equeue[head] = (u8) linestatus; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci jsm_dbg(READ, &ch->ch_bd->pci_dev, "DATA/LSR pair: %x %x\n", 4548c2ecf20Sopenharmony_ci ch->ch_rqueue[head], ch->ch_equeue[head]); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* Ditch any remaining linestatus value. */ 4578c2ecf20Sopenharmony_ci linestatus = 0; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* Add to and flip head if needed */ 4608c2ecf20Sopenharmony_ci head = (head + 1) & RQUEUEMASK; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci qleft--; 4638c2ecf20Sopenharmony_ci ch->ch_rxcount++; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* 4678c2ecf20Sopenharmony_ci * Write new final heads to channel structure. 4688c2ecf20Sopenharmony_ci */ 4698c2ecf20Sopenharmony_ci ch->ch_r_head = head & RQUEUEMASK; 4708c2ecf20Sopenharmony_ci ch->ch_e_head = head & EQUEUEMASK; 4718c2ecf20Sopenharmony_ci jsm_input(ch); 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cistatic void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci u16 head; 4778c2ecf20Sopenharmony_ci u16 tail; 4788c2ecf20Sopenharmony_ci int n; 4798c2ecf20Sopenharmony_ci int s; 4808c2ecf20Sopenharmony_ci int qlen; 4818c2ecf20Sopenharmony_ci u32 len_written = 0; 4828c2ecf20Sopenharmony_ci struct circ_buf *circ; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci if (!ch) 4858c2ecf20Sopenharmony_ci return; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci circ = &ch->uart_port.state->xmit; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* No data to write to the UART */ 4908c2ecf20Sopenharmony_ci if (uart_circ_empty(circ)) 4918c2ecf20Sopenharmony_ci return; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* If port is "stopped", don't send any data to the UART */ 4948c2ecf20Sopenharmony_ci if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_BREAK_SENDING)) 4958c2ecf20Sopenharmony_ci return; 4968c2ecf20Sopenharmony_ci /* 4978c2ecf20Sopenharmony_ci * If FIFOs are disabled. Send data directly to txrx register 4988c2ecf20Sopenharmony_ci */ 4998c2ecf20Sopenharmony_ci if (!(ch->ch_flags & CH_FIFO_ENABLED)) { 5008c2ecf20Sopenharmony_ci u8 lsrbits = readb(&ch->ch_neo_uart->lsr); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci ch->ch_cached_lsr |= lsrbits; 5038c2ecf20Sopenharmony_ci if (ch->ch_cached_lsr & UART_LSR_THRE) { 5048c2ecf20Sopenharmony_ci ch->ch_cached_lsr &= ~(UART_LSR_THRE); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci writeb(circ->buf[circ->tail], &ch->ch_neo_uart->txrx); 5078c2ecf20Sopenharmony_ci jsm_dbg(WRITE, &ch->ch_bd->pci_dev, 5088c2ecf20Sopenharmony_ci "Tx data: %x\n", circ->buf[circ->tail]); 5098c2ecf20Sopenharmony_ci circ->tail = (circ->tail + 1) & (UART_XMIT_SIZE - 1); 5108c2ecf20Sopenharmony_ci ch->ch_txcount++; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci return; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci /* 5168c2ecf20Sopenharmony_ci * We have to do it this way, because of the EXAR TXFIFO count bug. 5178c2ecf20Sopenharmony_ci */ 5188c2ecf20Sopenharmony_ci if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM))) 5198c2ecf20Sopenharmony_ci return; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci /* cache head and tail of queue */ 5248c2ecf20Sopenharmony_ci head = circ->head & (UART_XMIT_SIZE - 1); 5258c2ecf20Sopenharmony_ci tail = circ->tail & (UART_XMIT_SIZE - 1); 5268c2ecf20Sopenharmony_ci qlen = uart_circ_chars_pending(circ); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* Find minimum of the FIFO space, versus queue length */ 5298c2ecf20Sopenharmony_ci n = min(n, qlen); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci while (n > 0) { 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail; 5348c2ecf20Sopenharmony_ci s = min(s, n); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci if (s <= 0) 5378c2ecf20Sopenharmony_ci break; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci memcpy_toio(&ch->ch_neo_uart->txrxburst, circ->buf + tail, s); 5408c2ecf20Sopenharmony_ci /* Add and flip queue if needed */ 5418c2ecf20Sopenharmony_ci tail = (tail + s) & (UART_XMIT_SIZE - 1); 5428c2ecf20Sopenharmony_ci n -= s; 5438c2ecf20Sopenharmony_ci ch->ch_txcount += s; 5448c2ecf20Sopenharmony_ci len_written += s; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci /* Update the final tail */ 5488c2ecf20Sopenharmony_ci circ->tail = tail & (UART_XMIT_SIZE - 1); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci if (len_written >= ch->ch_t_tlevel) 5518c2ecf20Sopenharmony_ci ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci if (uart_circ_empty(circ)) 5548c2ecf20Sopenharmony_ci uart_write_wakeup(&ch->uart_port); 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic void neo_parse_modem(struct jsm_channel *ch, u8 signals) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci u8 msignals = signals; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci jsm_dbg(MSIGS, &ch->ch_bd->pci_dev, 5628c2ecf20Sopenharmony_ci "neo_parse_modem: port: %d msignals: %x\n", 5638c2ecf20Sopenharmony_ci ch->ch_portnum, msignals); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* Scrub off lower bits. They signify delta's, which I don't care about */ 5668c2ecf20Sopenharmony_ci /* Keep DDCD and DDSR though */ 5678c2ecf20Sopenharmony_ci msignals &= 0xf8; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if (msignals & UART_MSR_DDCD) 5708c2ecf20Sopenharmony_ci uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD); 5718c2ecf20Sopenharmony_ci if (msignals & UART_MSR_DDSR) 5728c2ecf20Sopenharmony_ci uart_handle_cts_change(&ch->uart_port, msignals & UART_MSR_CTS); 5738c2ecf20Sopenharmony_ci if (msignals & UART_MSR_DCD) 5748c2ecf20Sopenharmony_ci ch->ch_mistat |= UART_MSR_DCD; 5758c2ecf20Sopenharmony_ci else 5768c2ecf20Sopenharmony_ci ch->ch_mistat &= ~UART_MSR_DCD; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (msignals & UART_MSR_DSR) 5798c2ecf20Sopenharmony_ci ch->ch_mistat |= UART_MSR_DSR; 5808c2ecf20Sopenharmony_ci else 5818c2ecf20Sopenharmony_ci ch->ch_mistat &= ~UART_MSR_DSR; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (msignals & UART_MSR_RI) 5848c2ecf20Sopenharmony_ci ch->ch_mistat |= UART_MSR_RI; 5858c2ecf20Sopenharmony_ci else 5868c2ecf20Sopenharmony_ci ch->ch_mistat &= ~UART_MSR_RI; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (msignals & UART_MSR_CTS) 5898c2ecf20Sopenharmony_ci ch->ch_mistat |= UART_MSR_CTS; 5908c2ecf20Sopenharmony_ci else 5918c2ecf20Sopenharmony_ci ch->ch_mistat &= ~UART_MSR_CTS; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci jsm_dbg(MSIGS, &ch->ch_bd->pci_dev, 5948c2ecf20Sopenharmony_ci "Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n", 5958c2ecf20Sopenharmony_ci ch->ch_portnum, 5968c2ecf20Sopenharmony_ci !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR), 5978c2ecf20Sopenharmony_ci !!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS), 5988c2ecf20Sopenharmony_ci !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_CTS), 5998c2ecf20Sopenharmony_ci !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DSR), 6008c2ecf20Sopenharmony_ci !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_RI), 6018c2ecf20Sopenharmony_ci !!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DCD)); 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci/* Make the UART raise any of the output signals we want up */ 6058c2ecf20Sopenharmony_cistatic void neo_assert_modem_signals(struct jsm_channel *ch) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci if (!ch) 6088c2ecf20Sopenharmony_ci return; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci /* flush write operation */ 6138c2ecf20Sopenharmony_ci neo_pci_posting_flush(ch->ch_bd); 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci/* 6178c2ecf20Sopenharmony_ci * Flush the WRITE FIFO on the Neo. 6188c2ecf20Sopenharmony_ci * 6198c2ecf20Sopenharmony_ci * NOTE: Channel lock MUST be held before calling this function! 6208c2ecf20Sopenharmony_ci */ 6218c2ecf20Sopenharmony_cistatic void neo_flush_uart_write(struct jsm_channel *ch) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci u8 tmp = 0; 6248c2ecf20Sopenharmony_ci int i = 0; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (!ch) 6278c2ecf20Sopenharmony_ci return; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci /* Check to see if the UART feels it completely flushed the FIFO. */ 6348c2ecf20Sopenharmony_ci tmp = readb(&ch->ch_neo_uart->isr_fcr); 6358c2ecf20Sopenharmony_ci if (tmp & UART_FCR_CLEAR_XMIT) { 6368c2ecf20Sopenharmony_ci jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, 6378c2ecf20Sopenharmony_ci "Still flushing TX UART... i: %d\n", i); 6388c2ecf20Sopenharmony_ci udelay(10); 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci else 6418c2ecf20Sopenharmony_ci break; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci/* 6498c2ecf20Sopenharmony_ci * Flush the READ FIFO on the Neo. 6508c2ecf20Sopenharmony_ci * 6518c2ecf20Sopenharmony_ci * NOTE: Channel lock MUST be held before calling this function! 6528c2ecf20Sopenharmony_ci */ 6538c2ecf20Sopenharmony_cistatic void neo_flush_uart_read(struct jsm_channel *ch) 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci u8 tmp = 0; 6568c2ecf20Sopenharmony_ci int i = 0; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci if (!ch) 6598c2ecf20Sopenharmony_ci return; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR), &ch->ch_neo_uart->isr_fcr); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* Check to see if the UART feels it completely flushed the FIFO. */ 6668c2ecf20Sopenharmony_ci tmp = readb(&ch->ch_neo_uart->isr_fcr); 6678c2ecf20Sopenharmony_ci if (tmp & 2) { 6688c2ecf20Sopenharmony_ci jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, 6698c2ecf20Sopenharmony_ci "Still flushing RX UART... i: %d\n", i); 6708c2ecf20Sopenharmony_ci udelay(10); 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci else 6738c2ecf20Sopenharmony_ci break; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci/* 6788c2ecf20Sopenharmony_ci * No locks are assumed to be held when calling this function. 6798c2ecf20Sopenharmony_ci */ 6808c2ecf20Sopenharmony_cistatic void neo_clear_break(struct jsm_channel *ch) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci unsigned long lock_flags; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci spin_lock_irqsave(&ch->ch_lock, lock_flags); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci /* Turn break off, and unset some variables */ 6878c2ecf20Sopenharmony_ci if (ch->ch_flags & CH_BREAK_SENDING) { 6888c2ecf20Sopenharmony_ci u8 temp = readb(&ch->ch_neo_uart->lcr); 6898c2ecf20Sopenharmony_ci writeb((temp & ~UART_LCR_SBC), &ch->ch_neo_uart->lcr); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci ch->ch_flags &= ~(CH_BREAK_SENDING); 6928c2ecf20Sopenharmony_ci jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, 6938c2ecf20Sopenharmony_ci "clear break Finishing UART_LCR_SBC! finished: %lx\n", 6948c2ecf20Sopenharmony_ci jiffies); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci /* flush write operation */ 6978c2ecf20Sopenharmony_ci neo_pci_posting_flush(ch->ch_bd); 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ch->ch_lock, lock_flags); 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci/* 7038c2ecf20Sopenharmony_ci * Parse the ISR register. 7048c2ecf20Sopenharmony_ci */ 7058c2ecf20Sopenharmony_cistatic void neo_parse_isr(struct jsm_board *brd, u32 port) 7068c2ecf20Sopenharmony_ci{ 7078c2ecf20Sopenharmony_ci struct jsm_channel *ch; 7088c2ecf20Sopenharmony_ci u8 isr; 7098c2ecf20Sopenharmony_ci u8 cause; 7108c2ecf20Sopenharmony_ci unsigned long lock_flags; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (!brd) 7138c2ecf20Sopenharmony_ci return; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci if (port >= brd->maxports) 7168c2ecf20Sopenharmony_ci return; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci ch = brd->channels[port]; 7198c2ecf20Sopenharmony_ci if (!ch) 7208c2ecf20Sopenharmony_ci return; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci /* Here we try to figure out what caused the interrupt to happen */ 7238c2ecf20Sopenharmony_ci while (1) { 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci isr = readb(&ch->ch_neo_uart->isr_fcr); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* Bail if no pending interrupt */ 7288c2ecf20Sopenharmony_ci if (isr & UART_IIR_NO_INT) 7298c2ecf20Sopenharmony_ci break; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* 7328c2ecf20Sopenharmony_ci * Yank off the upper 2 bits, which just show that the FIFO's are enabled. 7338c2ecf20Sopenharmony_ci */ 7348c2ecf20Sopenharmony_ci isr &= ~(UART_17158_IIR_FIFO_ENABLED); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci jsm_dbg(INTR, &ch->ch_bd->pci_dev, "%s:%d isr: %x\n", 7378c2ecf20Sopenharmony_ci __FILE__, __LINE__, isr); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (isr & (UART_17158_IIR_RDI_TIMEOUT | UART_IIR_RDI)) { 7408c2ecf20Sopenharmony_ci /* Read data from uart -> queue */ 7418c2ecf20Sopenharmony_ci neo_copy_data_from_uart_to_queue(ch); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci /* Call our tty layer to enforce queue flow control if needed. */ 7448c2ecf20Sopenharmony_ci spin_lock_irqsave(&ch->ch_lock, lock_flags); 7458c2ecf20Sopenharmony_ci jsm_check_queue_flow_control(ch); 7468c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ch->ch_lock, lock_flags); 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci if (isr & UART_IIR_THRI) { 7508c2ecf20Sopenharmony_ci /* Transfer data (if any) from Write Queue -> UART. */ 7518c2ecf20Sopenharmony_ci spin_lock_irqsave(&ch->ch_lock, lock_flags); 7528c2ecf20Sopenharmony_ci ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); 7538c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ch->ch_lock, lock_flags); 7548c2ecf20Sopenharmony_ci neo_copy_data_from_queue_to_uart(ch); 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci if (isr & UART_17158_IIR_XONXOFF) { 7588c2ecf20Sopenharmony_ci cause = readb(&ch->ch_neo_uart->xoffchar1); 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci jsm_dbg(INTR, &ch->ch_bd->pci_dev, 7618c2ecf20Sopenharmony_ci "Port %d. Got ISR_XONXOFF: cause:%x\n", 7628c2ecf20Sopenharmony_ci port, cause); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci /* 7658c2ecf20Sopenharmony_ci * Since the UART detected either an XON or 7668c2ecf20Sopenharmony_ci * XOFF match, we need to figure out which 7678c2ecf20Sopenharmony_ci * one it was, so we can suspend or resume data flow. 7688c2ecf20Sopenharmony_ci */ 7698c2ecf20Sopenharmony_ci spin_lock_irqsave(&ch->ch_lock, lock_flags); 7708c2ecf20Sopenharmony_ci if (cause == UART_17158_XON_DETECT) { 7718c2ecf20Sopenharmony_ci /* Is output stopped right now, if so, resume it */ 7728c2ecf20Sopenharmony_ci if (brd->channels[port]->ch_flags & CH_STOP) { 7738c2ecf20Sopenharmony_ci ch->ch_flags &= ~(CH_STOP); 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci jsm_dbg(INTR, &ch->ch_bd->pci_dev, 7768c2ecf20Sopenharmony_ci "Port %d. XON detected in incoming data\n", 7778c2ecf20Sopenharmony_ci port); 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci else if (cause == UART_17158_XOFF_DETECT) { 7808c2ecf20Sopenharmony_ci if (!(brd->channels[port]->ch_flags & CH_STOP)) { 7818c2ecf20Sopenharmony_ci ch->ch_flags |= CH_STOP; 7828c2ecf20Sopenharmony_ci jsm_dbg(INTR, &ch->ch_bd->pci_dev, 7838c2ecf20Sopenharmony_ci "Setting CH_STOP\n"); 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci jsm_dbg(INTR, &ch->ch_bd->pci_dev, 7868c2ecf20Sopenharmony_ci "Port: %d. XOFF detected in incoming data\n", 7878c2ecf20Sopenharmony_ci port); 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ch->ch_lock, lock_flags); 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (isr & UART_17158_IIR_HWFLOW_STATE_CHANGE) { 7938c2ecf20Sopenharmony_ci /* 7948c2ecf20Sopenharmony_ci * If we get here, this means the hardware is doing auto flow control. 7958c2ecf20Sopenharmony_ci * Check to see whether RTS/DTR or CTS/DSR caused this interrupt. 7968c2ecf20Sopenharmony_ci */ 7978c2ecf20Sopenharmony_ci cause = readb(&ch->ch_neo_uart->mcr); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci /* Which pin is doing auto flow? RTS or DTR? */ 8008c2ecf20Sopenharmony_ci spin_lock_irqsave(&ch->ch_lock, lock_flags); 8018c2ecf20Sopenharmony_ci if ((cause & 0x4) == 0) { 8028c2ecf20Sopenharmony_ci if (cause & UART_MCR_RTS) 8038c2ecf20Sopenharmony_ci ch->ch_mostat |= UART_MCR_RTS; 8048c2ecf20Sopenharmony_ci else 8058c2ecf20Sopenharmony_ci ch->ch_mostat &= ~(UART_MCR_RTS); 8068c2ecf20Sopenharmony_ci } else { 8078c2ecf20Sopenharmony_ci if (cause & UART_MCR_DTR) 8088c2ecf20Sopenharmony_ci ch->ch_mostat |= UART_MCR_DTR; 8098c2ecf20Sopenharmony_ci else 8108c2ecf20Sopenharmony_ci ch->ch_mostat &= ~(UART_MCR_DTR); 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ch->ch_lock, lock_flags); 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci /* Parse any modem signal changes */ 8168c2ecf20Sopenharmony_ci jsm_dbg(INTR, &ch->ch_bd->pci_dev, 8178c2ecf20Sopenharmony_ci "MOD_STAT: sending to parse_modem_sigs\n"); 8188c2ecf20Sopenharmony_ci spin_lock_irqsave(&ch->uart_port.lock, lock_flags); 8198c2ecf20Sopenharmony_ci neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr)); 8208c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ch->uart_port.lock, lock_flags); 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci} 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_cistatic inline void neo_parse_lsr(struct jsm_board *brd, u32 port) 8258c2ecf20Sopenharmony_ci{ 8268c2ecf20Sopenharmony_ci struct jsm_channel *ch; 8278c2ecf20Sopenharmony_ci int linestatus; 8288c2ecf20Sopenharmony_ci unsigned long lock_flags; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (!brd) 8318c2ecf20Sopenharmony_ci return; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci if (port >= brd->maxports) 8348c2ecf20Sopenharmony_ci return; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci ch = brd->channels[port]; 8378c2ecf20Sopenharmony_ci if (!ch) 8388c2ecf20Sopenharmony_ci return; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci linestatus = readb(&ch->ch_neo_uart->lsr); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci jsm_dbg(INTR, &ch->ch_bd->pci_dev, "%s:%d port: %d linestatus: %x\n", 8438c2ecf20Sopenharmony_ci __FILE__, __LINE__, port, linestatus); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci ch->ch_cached_lsr |= linestatus; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (ch->ch_cached_lsr & UART_LSR_DR) { 8488c2ecf20Sopenharmony_ci /* Read data from uart -> queue */ 8498c2ecf20Sopenharmony_ci neo_copy_data_from_uart_to_queue(ch); 8508c2ecf20Sopenharmony_ci spin_lock_irqsave(&ch->ch_lock, lock_flags); 8518c2ecf20Sopenharmony_ci jsm_check_queue_flow_control(ch); 8528c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ch->ch_lock, lock_flags); 8538c2ecf20Sopenharmony_ci } 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci /* 8568c2ecf20Sopenharmony_ci * This is a special flag. It indicates that at least 1 8578c2ecf20Sopenharmony_ci * RX error (parity, framing, or break) has happened. 8588c2ecf20Sopenharmony_ci * Mark this in our struct, which will tell me that I have 8598c2ecf20Sopenharmony_ci *to do the special RX+LSR read for this FIFO load. 8608c2ecf20Sopenharmony_ci */ 8618c2ecf20Sopenharmony_ci if (linestatus & UART_17158_RX_FIFO_DATA_ERROR) 8628c2ecf20Sopenharmony_ci jsm_dbg(INTR, &ch->ch_bd->pci_dev, 8638c2ecf20Sopenharmony_ci "%s:%d Port: %d Got an RX error, need to parse LSR\n", 8648c2ecf20Sopenharmony_ci __FILE__, __LINE__, port); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci /* 8678c2ecf20Sopenharmony_ci * The next 3 tests should *NOT* happen, as the above test 8688c2ecf20Sopenharmony_ci * should encapsulate all 3... At least, thats what Exar says. 8698c2ecf20Sopenharmony_ci */ 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci if (linestatus & UART_LSR_PE) { 8728c2ecf20Sopenharmony_ci ch->ch_err_parity++; 8738c2ecf20Sopenharmony_ci jsm_dbg(INTR, &ch->ch_bd->pci_dev, "%s:%d Port: %d. PAR ERR!\n", 8748c2ecf20Sopenharmony_ci __FILE__, __LINE__, port); 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci if (linestatus & UART_LSR_FE) { 8788c2ecf20Sopenharmony_ci ch->ch_err_frame++; 8798c2ecf20Sopenharmony_ci jsm_dbg(INTR, &ch->ch_bd->pci_dev, "%s:%d Port: %d. FRM ERR!\n", 8808c2ecf20Sopenharmony_ci __FILE__, __LINE__, port); 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (linestatus & UART_LSR_BI) { 8848c2ecf20Sopenharmony_ci ch->ch_err_break++; 8858c2ecf20Sopenharmony_ci jsm_dbg(INTR, &ch->ch_bd->pci_dev, 8868c2ecf20Sopenharmony_ci "%s:%d Port: %d. BRK INTR!\n", 8878c2ecf20Sopenharmony_ci __FILE__, __LINE__, port); 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci if (linestatus & UART_LSR_OE) { 8918c2ecf20Sopenharmony_ci /* 8928c2ecf20Sopenharmony_ci * Rx Oruns. Exar says that an orun will NOT corrupt 8938c2ecf20Sopenharmony_ci * the FIFO. It will just replace the holding register 8948c2ecf20Sopenharmony_ci * with this new data byte. So basically just ignore this. 8958c2ecf20Sopenharmony_ci * Probably we should eventually have an orun stat in our driver... 8968c2ecf20Sopenharmony_ci */ 8978c2ecf20Sopenharmony_ci ch->ch_err_overrun++; 8988c2ecf20Sopenharmony_ci jsm_dbg(INTR, &ch->ch_bd->pci_dev, 8998c2ecf20Sopenharmony_ci "%s:%d Port: %d. Rx Overrun!\n", 9008c2ecf20Sopenharmony_ci __FILE__, __LINE__, port); 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci if (linestatus & UART_LSR_THRE) { 9048c2ecf20Sopenharmony_ci spin_lock_irqsave(&ch->ch_lock, lock_flags); 9058c2ecf20Sopenharmony_ci ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); 9068c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ch->ch_lock, lock_flags); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci /* Transfer data (if any) from Write Queue -> UART. */ 9098c2ecf20Sopenharmony_ci neo_copy_data_from_queue_to_uart(ch); 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci else if (linestatus & UART_17158_TX_AND_FIFO_CLR) { 9128c2ecf20Sopenharmony_ci spin_lock_irqsave(&ch->ch_lock, lock_flags); 9138c2ecf20Sopenharmony_ci ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); 9148c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ch->ch_lock, lock_flags); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci /* Transfer data (if any) from Write Queue -> UART. */ 9178c2ecf20Sopenharmony_ci neo_copy_data_from_queue_to_uart(ch); 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci/* 9228c2ecf20Sopenharmony_ci * neo_param() 9238c2ecf20Sopenharmony_ci * Send any/all changes to the line to the UART. 9248c2ecf20Sopenharmony_ci */ 9258c2ecf20Sopenharmony_cistatic void neo_param(struct jsm_channel *ch) 9268c2ecf20Sopenharmony_ci{ 9278c2ecf20Sopenharmony_ci u8 lcr = 0; 9288c2ecf20Sopenharmony_ci u8 uart_lcr, ier; 9298c2ecf20Sopenharmony_ci u32 baud; 9308c2ecf20Sopenharmony_ci int quot; 9318c2ecf20Sopenharmony_ci struct jsm_board *bd; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci bd = ch->ch_bd; 9348c2ecf20Sopenharmony_ci if (!bd) 9358c2ecf20Sopenharmony_ci return; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci /* 9388c2ecf20Sopenharmony_ci * If baud rate is zero, flush queues, and set mval to drop DTR. 9398c2ecf20Sopenharmony_ci */ 9408c2ecf20Sopenharmony_ci if ((ch->ch_c_cflag & (CBAUD)) == 0) { 9418c2ecf20Sopenharmony_ci ch->ch_r_head = ch->ch_r_tail = 0; 9428c2ecf20Sopenharmony_ci ch->ch_e_head = ch->ch_e_tail = 0; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci neo_flush_uart_write(ch); 9458c2ecf20Sopenharmony_ci neo_flush_uart_read(ch); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci ch->ch_flags |= (CH_BAUD0); 9488c2ecf20Sopenharmony_ci ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR); 9498c2ecf20Sopenharmony_ci neo_assert_modem_signals(ch); 9508c2ecf20Sopenharmony_ci return; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci } else { 9538c2ecf20Sopenharmony_ci int i; 9548c2ecf20Sopenharmony_ci unsigned int cflag; 9558c2ecf20Sopenharmony_ci static struct { 9568c2ecf20Sopenharmony_ci unsigned int rate; 9578c2ecf20Sopenharmony_ci unsigned int cflag; 9588c2ecf20Sopenharmony_ci } baud_rates[] = { 9598c2ecf20Sopenharmony_ci { 921600, B921600 }, 9608c2ecf20Sopenharmony_ci { 460800, B460800 }, 9618c2ecf20Sopenharmony_ci { 230400, B230400 }, 9628c2ecf20Sopenharmony_ci { 115200, B115200 }, 9638c2ecf20Sopenharmony_ci { 57600, B57600 }, 9648c2ecf20Sopenharmony_ci { 38400, B38400 }, 9658c2ecf20Sopenharmony_ci { 19200, B19200 }, 9668c2ecf20Sopenharmony_ci { 9600, B9600 }, 9678c2ecf20Sopenharmony_ci { 4800, B4800 }, 9688c2ecf20Sopenharmony_ci { 2400, B2400 }, 9698c2ecf20Sopenharmony_ci { 1200, B1200 }, 9708c2ecf20Sopenharmony_ci { 600, B600 }, 9718c2ecf20Sopenharmony_ci { 300, B300 }, 9728c2ecf20Sopenharmony_ci { 200, B200 }, 9738c2ecf20Sopenharmony_ci { 150, B150 }, 9748c2ecf20Sopenharmony_ci { 134, B134 }, 9758c2ecf20Sopenharmony_ci { 110, B110 }, 9768c2ecf20Sopenharmony_ci { 75, B75 }, 9778c2ecf20Sopenharmony_ci { 50, B50 }, 9788c2ecf20Sopenharmony_ci }; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci cflag = C_BAUD(ch->uart_port.state->port.tty); 9818c2ecf20Sopenharmony_ci baud = 9600; 9828c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(baud_rates); i++) { 9838c2ecf20Sopenharmony_ci if (baud_rates[i].cflag == cflag) { 9848c2ecf20Sopenharmony_ci baud = baud_rates[i].rate; 9858c2ecf20Sopenharmony_ci break; 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (ch->ch_flags & CH_BAUD0) 9908c2ecf20Sopenharmony_ci ch->ch_flags &= ~(CH_BAUD0); 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci if (ch->ch_c_cflag & PARENB) 9948c2ecf20Sopenharmony_ci lcr |= UART_LCR_PARITY; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (!(ch->ch_c_cflag & PARODD)) 9978c2ecf20Sopenharmony_ci lcr |= UART_LCR_EPAR; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci /* 10008c2ecf20Sopenharmony_ci * Not all platforms support mark/space parity, 10018c2ecf20Sopenharmony_ci * so this will hide behind an ifdef. 10028c2ecf20Sopenharmony_ci */ 10038c2ecf20Sopenharmony_ci#ifdef CMSPAR 10048c2ecf20Sopenharmony_ci if (ch->ch_c_cflag & CMSPAR) 10058c2ecf20Sopenharmony_ci lcr |= UART_LCR_SPAR; 10068c2ecf20Sopenharmony_ci#endif 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci if (ch->ch_c_cflag & CSTOPB) 10098c2ecf20Sopenharmony_ci lcr |= UART_LCR_STOP; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci switch (ch->ch_c_cflag & CSIZE) { 10128c2ecf20Sopenharmony_ci case CS5: 10138c2ecf20Sopenharmony_ci lcr |= UART_LCR_WLEN5; 10148c2ecf20Sopenharmony_ci break; 10158c2ecf20Sopenharmony_ci case CS6: 10168c2ecf20Sopenharmony_ci lcr |= UART_LCR_WLEN6; 10178c2ecf20Sopenharmony_ci break; 10188c2ecf20Sopenharmony_ci case CS7: 10198c2ecf20Sopenharmony_ci lcr |= UART_LCR_WLEN7; 10208c2ecf20Sopenharmony_ci break; 10218c2ecf20Sopenharmony_ci case CS8: 10228c2ecf20Sopenharmony_ci default: 10238c2ecf20Sopenharmony_ci lcr |= UART_LCR_WLEN8; 10248c2ecf20Sopenharmony_ci break; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci ier = readb(&ch->ch_neo_uart->ier); 10288c2ecf20Sopenharmony_ci uart_lcr = readb(&ch->ch_neo_uart->lcr); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci quot = ch->ch_bd->bd_dividend / baud; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci if (quot != 0) { 10338c2ecf20Sopenharmony_ci writeb(UART_LCR_DLAB, &ch->ch_neo_uart->lcr); 10348c2ecf20Sopenharmony_ci writeb((quot & 0xff), &ch->ch_neo_uart->txrx); 10358c2ecf20Sopenharmony_ci writeb((quot >> 8), &ch->ch_neo_uart->ier); 10368c2ecf20Sopenharmony_ci writeb(lcr, &ch->ch_neo_uart->lcr); 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci if (uart_lcr != lcr) 10408c2ecf20Sopenharmony_ci writeb(lcr, &ch->ch_neo_uart->lcr); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci if (ch->ch_c_cflag & CREAD) 10438c2ecf20Sopenharmony_ci ier |= (UART_IER_RDI | UART_IER_RLSI); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci ier |= (UART_IER_THRI | UART_IER_MSI); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci writeb(ier, &ch->ch_neo_uart->ier); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci /* Set new start/stop chars */ 10508c2ecf20Sopenharmony_ci neo_set_new_start_stop_chars(ch); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci if (ch->ch_c_cflag & CRTSCTS) 10538c2ecf20Sopenharmony_ci neo_set_cts_flow_control(ch); 10548c2ecf20Sopenharmony_ci else if (ch->ch_c_iflag & IXON) { 10558c2ecf20Sopenharmony_ci /* If start/stop is set to disable, then we should disable flow control */ 10568c2ecf20Sopenharmony_ci if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR)) 10578c2ecf20Sopenharmony_ci neo_set_no_output_flow_control(ch); 10588c2ecf20Sopenharmony_ci else 10598c2ecf20Sopenharmony_ci neo_set_ixon_flow_control(ch); 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci else 10628c2ecf20Sopenharmony_ci neo_set_no_output_flow_control(ch); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci if (ch->ch_c_cflag & CRTSCTS) 10658c2ecf20Sopenharmony_ci neo_set_rts_flow_control(ch); 10668c2ecf20Sopenharmony_ci else if (ch->ch_c_iflag & IXOFF) { 10678c2ecf20Sopenharmony_ci /* If start/stop is set to disable, then we should disable flow control */ 10688c2ecf20Sopenharmony_ci if ((ch->ch_startc == __DISABLED_CHAR) || (ch->ch_stopc == __DISABLED_CHAR)) 10698c2ecf20Sopenharmony_ci neo_set_no_input_flow_control(ch); 10708c2ecf20Sopenharmony_ci else 10718c2ecf20Sopenharmony_ci neo_set_ixoff_flow_control(ch); 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci else 10748c2ecf20Sopenharmony_ci neo_set_no_input_flow_control(ch); 10758c2ecf20Sopenharmony_ci /* 10768c2ecf20Sopenharmony_ci * Adjust the RX FIFO Trigger level if baud is less than 9600. 10778c2ecf20Sopenharmony_ci * Not exactly elegant, but this is needed because of the Exar chip's 10788c2ecf20Sopenharmony_ci * delay on firing off the RX FIFO interrupt on slower baud rates. 10798c2ecf20Sopenharmony_ci */ 10808c2ecf20Sopenharmony_ci if (baud < 9600) { 10818c2ecf20Sopenharmony_ci writeb(1, &ch->ch_neo_uart->rfifo); 10828c2ecf20Sopenharmony_ci ch->ch_r_tlevel = 1; 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci neo_assert_modem_signals(ch); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci /* Get current status of the modem signals now */ 10888c2ecf20Sopenharmony_ci neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr)); 10898c2ecf20Sopenharmony_ci return; 10908c2ecf20Sopenharmony_ci} 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci/* 10938c2ecf20Sopenharmony_ci * jsm_neo_intr() 10948c2ecf20Sopenharmony_ci * 10958c2ecf20Sopenharmony_ci * Neo specific interrupt handler. 10968c2ecf20Sopenharmony_ci */ 10978c2ecf20Sopenharmony_cistatic irqreturn_t neo_intr(int irq, void *voidbrd) 10988c2ecf20Sopenharmony_ci{ 10998c2ecf20Sopenharmony_ci struct jsm_board *brd = voidbrd; 11008c2ecf20Sopenharmony_ci struct jsm_channel *ch; 11018c2ecf20Sopenharmony_ci int port = 0; 11028c2ecf20Sopenharmony_ci int type = 0; 11038c2ecf20Sopenharmony_ci int current_port; 11048c2ecf20Sopenharmony_ci u32 tmp; 11058c2ecf20Sopenharmony_ci u32 uart_poll; 11068c2ecf20Sopenharmony_ci unsigned long lock_flags; 11078c2ecf20Sopenharmony_ci unsigned long lock_flags2; 11088c2ecf20Sopenharmony_ci int outofloop_count = 0; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci /* Lock out the slow poller from running on this board. */ 11118c2ecf20Sopenharmony_ci spin_lock_irqsave(&brd->bd_intr_lock, lock_flags); 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci /* 11148c2ecf20Sopenharmony_ci * Read in "extended" IRQ information from the 32bit Neo register. 11158c2ecf20Sopenharmony_ci * Bits 0-7: What port triggered the interrupt. 11168c2ecf20Sopenharmony_ci * Bits 8-31: Each 3bits indicate what type of interrupt occurred. 11178c2ecf20Sopenharmony_ci */ 11188c2ecf20Sopenharmony_ci uart_poll = readl(brd->re_map_membase + UART_17158_POLL_ADDR_OFFSET); 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci jsm_dbg(INTR, &brd->pci_dev, "%s:%d uart_poll: %x\n", 11218c2ecf20Sopenharmony_ci __FILE__, __LINE__, uart_poll); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci if (!uart_poll) { 11248c2ecf20Sopenharmony_ci jsm_dbg(INTR, &brd->pci_dev, 11258c2ecf20Sopenharmony_ci "Kernel interrupted to me, but no pending interrupts...\n"); 11268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags); 11278c2ecf20Sopenharmony_ci return IRQ_NONE; 11288c2ecf20Sopenharmony_ci } 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci /* At this point, we have at least SOMETHING to service, dig further... */ 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci current_port = 0; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci /* Loop on each port */ 11358c2ecf20Sopenharmony_ci while (((uart_poll & 0xff) != 0) && (outofloop_count < 0xff)){ 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci tmp = uart_poll; 11388c2ecf20Sopenharmony_ci outofloop_count++; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci /* Check current port to see if it has interrupt pending */ 11418c2ecf20Sopenharmony_ci if ((tmp & jsm_offset_table[current_port]) != 0) { 11428c2ecf20Sopenharmony_ci port = current_port; 11438c2ecf20Sopenharmony_ci type = tmp >> (8 + (port * 3)); 11448c2ecf20Sopenharmony_ci type &= 0x7; 11458c2ecf20Sopenharmony_ci } else { 11468c2ecf20Sopenharmony_ci current_port++; 11478c2ecf20Sopenharmony_ci continue; 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci jsm_dbg(INTR, &brd->pci_dev, "%s:%d port: %x type: %x\n", 11518c2ecf20Sopenharmony_ci __FILE__, __LINE__, port, type); 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci /* Remove this port + type from uart_poll */ 11548c2ecf20Sopenharmony_ci uart_poll &= ~(jsm_offset_table[port]); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci if (!type) { 11578c2ecf20Sopenharmony_ci /* If no type, just ignore it, and move onto next port */ 11588c2ecf20Sopenharmony_ci jsm_dbg(INTR, &brd->pci_dev, 11598c2ecf20Sopenharmony_ci "Interrupt with no type! port: %d\n", port); 11608c2ecf20Sopenharmony_ci continue; 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci /* Switch on type of interrupt we have */ 11648c2ecf20Sopenharmony_ci switch (type) { 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci case UART_17158_RXRDY_TIMEOUT: 11678c2ecf20Sopenharmony_ci /* 11688c2ecf20Sopenharmony_ci * RXRDY Time-out is cleared by reading data in the 11698c2ecf20Sopenharmony_ci * RX FIFO until it falls below the trigger level. 11708c2ecf20Sopenharmony_ci */ 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci /* Verify the port is in range. */ 11738c2ecf20Sopenharmony_ci if (port >= brd->nasync) 11748c2ecf20Sopenharmony_ci continue; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci ch = brd->channels[port]; 11778c2ecf20Sopenharmony_ci if (!ch) 11788c2ecf20Sopenharmony_ci continue; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci neo_copy_data_from_uart_to_queue(ch); 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci /* Call our tty layer to enforce queue flow control if needed. */ 11838c2ecf20Sopenharmony_ci spin_lock_irqsave(&ch->ch_lock, lock_flags2); 11848c2ecf20Sopenharmony_ci jsm_check_queue_flow_control(ch); 11858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci continue; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci case UART_17158_RX_LINE_STATUS: 11908c2ecf20Sopenharmony_ci /* 11918c2ecf20Sopenharmony_ci * RXRDY and RX LINE Status (logic OR of LSR[4:1]) 11928c2ecf20Sopenharmony_ci */ 11938c2ecf20Sopenharmony_ci neo_parse_lsr(brd, port); 11948c2ecf20Sopenharmony_ci continue; 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci case UART_17158_TXRDY: 11978c2ecf20Sopenharmony_ci /* 11988c2ecf20Sopenharmony_ci * TXRDY interrupt clears after reading ISR register for the UART channel. 11998c2ecf20Sopenharmony_ci */ 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci /* 12028c2ecf20Sopenharmony_ci * Yes, this is odd... 12038c2ecf20Sopenharmony_ci * Why would I check EVERY possibility of type of 12048c2ecf20Sopenharmony_ci * interrupt, when we know its TXRDY??? 12058c2ecf20Sopenharmony_ci * Becuz for some reason, even tho we got triggered for TXRDY, 12068c2ecf20Sopenharmony_ci * it seems to be occasionally wrong. Instead of TX, which 12078c2ecf20Sopenharmony_ci * it should be, I was getting things like RXDY too. Weird. 12088c2ecf20Sopenharmony_ci */ 12098c2ecf20Sopenharmony_ci neo_parse_isr(brd, port); 12108c2ecf20Sopenharmony_ci continue; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci case UART_17158_MSR: 12138c2ecf20Sopenharmony_ci /* 12148c2ecf20Sopenharmony_ci * MSR or flow control was seen. 12158c2ecf20Sopenharmony_ci */ 12168c2ecf20Sopenharmony_ci neo_parse_isr(brd, port); 12178c2ecf20Sopenharmony_ci continue; 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci default: 12208c2ecf20Sopenharmony_ci /* 12218c2ecf20Sopenharmony_ci * The UART triggered us with a bogus interrupt type. 12228c2ecf20Sopenharmony_ci * It appears the Exar chip, when REALLY bogged down, will throw 12238c2ecf20Sopenharmony_ci * these once and awhile. 12248c2ecf20Sopenharmony_ci * Its harmless, just ignore it and move on. 12258c2ecf20Sopenharmony_ci */ 12268c2ecf20Sopenharmony_ci jsm_dbg(INTR, &brd->pci_dev, 12278c2ecf20Sopenharmony_ci "%s:%d Unknown Interrupt type: %x\n", 12288c2ecf20Sopenharmony_ci __FILE__, __LINE__, type); 12298c2ecf20Sopenharmony_ci continue; 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci jsm_dbg(INTR, &brd->pci_dev, "finish\n"); 12368c2ecf20Sopenharmony_ci return IRQ_HANDLED; 12378c2ecf20Sopenharmony_ci} 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci/* 12408c2ecf20Sopenharmony_ci * Neo specific way of turning off the receiver. 12418c2ecf20Sopenharmony_ci * Used as a way to enforce queue flow control when in 12428c2ecf20Sopenharmony_ci * hardware flow control mode. 12438c2ecf20Sopenharmony_ci */ 12448c2ecf20Sopenharmony_cistatic void neo_disable_receiver(struct jsm_channel *ch) 12458c2ecf20Sopenharmony_ci{ 12468c2ecf20Sopenharmony_ci u8 tmp = readb(&ch->ch_neo_uart->ier); 12478c2ecf20Sopenharmony_ci tmp &= ~(UART_IER_RDI); 12488c2ecf20Sopenharmony_ci writeb(tmp, &ch->ch_neo_uart->ier); 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci /* flush write operation */ 12518c2ecf20Sopenharmony_ci neo_pci_posting_flush(ch->ch_bd); 12528c2ecf20Sopenharmony_ci} 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci/* 12568c2ecf20Sopenharmony_ci * Neo specific way of turning on the receiver. 12578c2ecf20Sopenharmony_ci * Used as a way to un-enforce queue flow control when in 12588c2ecf20Sopenharmony_ci * hardware flow control mode. 12598c2ecf20Sopenharmony_ci */ 12608c2ecf20Sopenharmony_cistatic void neo_enable_receiver(struct jsm_channel *ch) 12618c2ecf20Sopenharmony_ci{ 12628c2ecf20Sopenharmony_ci u8 tmp = readb(&ch->ch_neo_uart->ier); 12638c2ecf20Sopenharmony_ci tmp |= (UART_IER_RDI); 12648c2ecf20Sopenharmony_ci writeb(tmp, &ch->ch_neo_uart->ier); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci /* flush write operation */ 12678c2ecf20Sopenharmony_ci neo_pci_posting_flush(ch->ch_bd); 12688c2ecf20Sopenharmony_ci} 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_cistatic void neo_send_start_character(struct jsm_channel *ch) 12718c2ecf20Sopenharmony_ci{ 12728c2ecf20Sopenharmony_ci if (!ch) 12738c2ecf20Sopenharmony_ci return; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci if (ch->ch_startc != __DISABLED_CHAR) { 12768c2ecf20Sopenharmony_ci ch->ch_xon_sends++; 12778c2ecf20Sopenharmony_ci writeb(ch->ch_startc, &ch->ch_neo_uart->txrx); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci /* flush write operation */ 12808c2ecf20Sopenharmony_ci neo_pci_posting_flush(ch->ch_bd); 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci} 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_cistatic void neo_send_stop_character(struct jsm_channel *ch) 12858c2ecf20Sopenharmony_ci{ 12868c2ecf20Sopenharmony_ci if (!ch) 12878c2ecf20Sopenharmony_ci return; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci if (ch->ch_stopc != __DISABLED_CHAR) { 12908c2ecf20Sopenharmony_ci ch->ch_xoff_sends++; 12918c2ecf20Sopenharmony_ci writeb(ch->ch_stopc, &ch->ch_neo_uart->txrx); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci /* flush write operation */ 12948c2ecf20Sopenharmony_ci neo_pci_posting_flush(ch->ch_bd); 12958c2ecf20Sopenharmony_ci } 12968c2ecf20Sopenharmony_ci} 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci/* 12998c2ecf20Sopenharmony_ci * neo_uart_init 13008c2ecf20Sopenharmony_ci */ 13018c2ecf20Sopenharmony_cistatic void neo_uart_init(struct jsm_channel *ch) 13028c2ecf20Sopenharmony_ci{ 13038c2ecf20Sopenharmony_ci writeb(0, &ch->ch_neo_uart->ier); 13048c2ecf20Sopenharmony_ci writeb(0, &ch->ch_neo_uart->efr); 13058c2ecf20Sopenharmony_ci writeb(UART_EFR_ECB, &ch->ch_neo_uart->efr); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci /* Clear out UART and FIFO */ 13088c2ecf20Sopenharmony_ci readb(&ch->ch_neo_uart->txrx); 13098c2ecf20Sopenharmony_ci writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT), &ch->ch_neo_uart->isr_fcr); 13108c2ecf20Sopenharmony_ci readb(&ch->ch_neo_uart->lsr); 13118c2ecf20Sopenharmony_ci readb(&ch->ch_neo_uart->msr); 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci ch->ch_flags |= CH_FIFO_ENABLED; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci /* Assert any signals we want up */ 13168c2ecf20Sopenharmony_ci writeb(ch->ch_mostat, &ch->ch_neo_uart->mcr); 13178c2ecf20Sopenharmony_ci} 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci/* 13208c2ecf20Sopenharmony_ci * Make the UART completely turn off. 13218c2ecf20Sopenharmony_ci */ 13228c2ecf20Sopenharmony_cistatic void neo_uart_off(struct jsm_channel *ch) 13238c2ecf20Sopenharmony_ci{ 13248c2ecf20Sopenharmony_ci /* Turn off UART enhanced bits */ 13258c2ecf20Sopenharmony_ci writeb(0, &ch->ch_neo_uart->efr); 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci /* Stop all interrupts from occurring. */ 13288c2ecf20Sopenharmony_ci writeb(0, &ch->ch_neo_uart->ier); 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_cistatic u32 neo_get_uart_bytes_left(struct jsm_channel *ch) 13328c2ecf20Sopenharmony_ci{ 13338c2ecf20Sopenharmony_ci u8 left = 0; 13348c2ecf20Sopenharmony_ci u8 lsr = readb(&ch->ch_neo_uart->lsr); 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci /* We must cache the LSR as some of the bits get reset once read... */ 13378c2ecf20Sopenharmony_ci ch->ch_cached_lsr |= lsr; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci /* Determine whether the Transmitter is empty or not */ 13408c2ecf20Sopenharmony_ci if (!(lsr & UART_LSR_TEMT)) 13418c2ecf20Sopenharmony_ci left = 1; 13428c2ecf20Sopenharmony_ci else { 13438c2ecf20Sopenharmony_ci ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); 13448c2ecf20Sopenharmony_ci left = 0; 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci return left; 13488c2ecf20Sopenharmony_ci} 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci/* Channel lock MUST be held by the calling function! */ 13518c2ecf20Sopenharmony_cistatic void neo_send_break(struct jsm_channel *ch) 13528c2ecf20Sopenharmony_ci{ 13538c2ecf20Sopenharmony_ci /* 13548c2ecf20Sopenharmony_ci * Set the time we should stop sending the break. 13558c2ecf20Sopenharmony_ci * If we are already sending a break, toss away the existing 13568c2ecf20Sopenharmony_ci * time to stop, and use this new value instead. 13578c2ecf20Sopenharmony_ci */ 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci /* Tell the UART to start sending the break */ 13608c2ecf20Sopenharmony_ci if (!(ch->ch_flags & CH_BREAK_SENDING)) { 13618c2ecf20Sopenharmony_ci u8 temp = readb(&ch->ch_neo_uart->lcr); 13628c2ecf20Sopenharmony_ci writeb((temp | UART_LCR_SBC), &ch->ch_neo_uart->lcr); 13638c2ecf20Sopenharmony_ci ch->ch_flags |= (CH_BREAK_SENDING); 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci /* flush write operation */ 13668c2ecf20Sopenharmony_ci neo_pci_posting_flush(ch->ch_bd); 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci} 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci/* 13718c2ecf20Sopenharmony_ci * neo_send_immediate_char. 13728c2ecf20Sopenharmony_ci * 13738c2ecf20Sopenharmony_ci * Sends a specific character as soon as possible to the UART, 13748c2ecf20Sopenharmony_ci * jumping over any bytes that might be in the write queue. 13758c2ecf20Sopenharmony_ci * 13768c2ecf20Sopenharmony_ci * The channel lock MUST be held by the calling function. 13778c2ecf20Sopenharmony_ci */ 13788c2ecf20Sopenharmony_cistatic void neo_send_immediate_char(struct jsm_channel *ch, unsigned char c) 13798c2ecf20Sopenharmony_ci{ 13808c2ecf20Sopenharmony_ci if (!ch) 13818c2ecf20Sopenharmony_ci return; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci writeb(c, &ch->ch_neo_uart->txrx); 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci /* flush write operation */ 13868c2ecf20Sopenharmony_ci neo_pci_posting_flush(ch->ch_bd); 13878c2ecf20Sopenharmony_ci} 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_cistruct board_ops jsm_neo_ops = { 13908c2ecf20Sopenharmony_ci .intr = neo_intr, 13918c2ecf20Sopenharmony_ci .uart_init = neo_uart_init, 13928c2ecf20Sopenharmony_ci .uart_off = neo_uart_off, 13938c2ecf20Sopenharmony_ci .param = neo_param, 13948c2ecf20Sopenharmony_ci .assert_modem_signals = neo_assert_modem_signals, 13958c2ecf20Sopenharmony_ci .flush_uart_write = neo_flush_uart_write, 13968c2ecf20Sopenharmony_ci .flush_uart_read = neo_flush_uart_read, 13978c2ecf20Sopenharmony_ci .disable_receiver = neo_disable_receiver, 13988c2ecf20Sopenharmony_ci .enable_receiver = neo_enable_receiver, 13998c2ecf20Sopenharmony_ci .send_break = neo_send_break, 14008c2ecf20Sopenharmony_ci .clear_break = neo_clear_break, 14018c2ecf20Sopenharmony_ci .send_start_character = neo_send_start_character, 14028c2ecf20Sopenharmony_ci .send_stop_character = neo_send_stop_character, 14038c2ecf20Sopenharmony_ci .copy_data_from_queue_to_uart = neo_copy_data_from_queue_to_uart, 14048c2ecf20Sopenharmony_ci .get_uart_bytes_left = neo_get_uart_bytes_left, 14058c2ecf20Sopenharmony_ci .send_immediate_char = neo_send_immediate_char 14068c2ecf20Sopenharmony_ci}; 1407