1e3b3d0f5SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
2ab4382d2SGreg Kroah-Hartman /************************************************************************
3ab4382d2SGreg Kroah-Hartman * Copyright 2003 Digi International (www.digi.com)
4ab4382d2SGreg Kroah-Hartman *
5ab4382d2SGreg Kroah-Hartman * Copyright (C) 2004 IBM Corporation. All rights reserved.
6ab4382d2SGreg Kroah-Hartman *
7ab4382d2SGreg Kroah-Hartman * Contact Information:
8ab4382d2SGreg Kroah-Hartman * Scott H Kilau <Scott_Kilau@digi.com>
9ab4382d2SGreg Kroah-Hartman * Ananda Venkatarman <mansarov@us.ibm.com>
10ab4382d2SGreg Kroah-Hartman * Modifications:
11ab4382d2SGreg Kroah-Hartman * 01/19/06: changed jsm_input routine to use the dynamically allocated
12ab4382d2SGreg Kroah-Hartman * tty_buffer changes. Contributors: Scott Kilau and Ananda V.
13ab4382d2SGreg Kroah-Hartman ***********************************************************************/
14ab4382d2SGreg Kroah-Hartman #include <linux/tty.h>
15ab4382d2SGreg Kroah-Hartman #include <linux/tty_flip.h>
16ab4382d2SGreg Kroah-Hartman #include <linux/serial_reg.h>
17ab4382d2SGreg Kroah-Hartman #include <linux/delay.h> /* For udelay */
18ab4382d2SGreg Kroah-Hartman #include <linux/pci.h>
19ab4382d2SGreg Kroah-Hartman #include <linux/slab.h>
20ab4382d2SGreg Kroah-Hartman
21ab4382d2SGreg Kroah-Hartman #include "jsm.h"
22ab4382d2SGreg Kroah-Hartman
23ab4382d2SGreg Kroah-Hartman static DECLARE_BITMAP(linemap, MAXLINES);
24ab4382d2SGreg Kroah-Hartman
25ab4382d2SGreg Kroah-Hartman static void jsm_carrier(struct jsm_channel *ch);
26ab4382d2SGreg Kroah-Hartman
jsm_get_mstat(struct jsm_channel * ch)27ab4382d2SGreg Kroah-Hartman static inline int jsm_get_mstat(struct jsm_channel *ch)
28ab4382d2SGreg Kroah-Hartman {
29ab4382d2SGreg Kroah-Hartman unsigned char mstat;
30c100a3f1SGimcuan Hui int result;
31ab4382d2SGreg Kroah-Hartman
32669fef46SJoe Perches jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, "start\n");
33ab4382d2SGreg Kroah-Hartman
34ab4382d2SGreg Kroah-Hartman mstat = (ch->ch_mostat | ch->ch_mistat);
35ab4382d2SGreg Kroah-Hartman
36ab4382d2SGreg Kroah-Hartman result = 0;
37ab4382d2SGreg Kroah-Hartman
38ab4382d2SGreg Kroah-Hartman if (mstat & UART_MCR_DTR)
39ab4382d2SGreg Kroah-Hartman result |= TIOCM_DTR;
40ab4382d2SGreg Kroah-Hartman if (mstat & UART_MCR_RTS)
41ab4382d2SGreg Kroah-Hartman result |= TIOCM_RTS;
42ab4382d2SGreg Kroah-Hartman if (mstat & UART_MSR_CTS)
43ab4382d2SGreg Kroah-Hartman result |= TIOCM_CTS;
44ab4382d2SGreg Kroah-Hartman if (mstat & UART_MSR_DSR)
45ab4382d2SGreg Kroah-Hartman result |= TIOCM_DSR;
46ab4382d2SGreg Kroah-Hartman if (mstat & UART_MSR_RI)
47ab4382d2SGreg Kroah-Hartman result |= TIOCM_RI;
48ab4382d2SGreg Kroah-Hartman if (mstat & UART_MSR_DCD)
49ab4382d2SGreg Kroah-Hartman result |= TIOCM_CD;
50ab4382d2SGreg Kroah-Hartman
51669fef46SJoe Perches jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, "finish\n");
52ab4382d2SGreg Kroah-Hartman return result;
53ab4382d2SGreg Kroah-Hartman }
54ab4382d2SGreg Kroah-Hartman
jsm_tty_tx_empty(struct uart_port * port)55ab4382d2SGreg Kroah-Hartman static unsigned int jsm_tty_tx_empty(struct uart_port *port)
56ab4382d2SGreg Kroah-Hartman {
57ab4382d2SGreg Kroah-Hartman return TIOCSER_TEMT;
58ab4382d2SGreg Kroah-Hartman }
59ab4382d2SGreg Kroah-Hartman
60ab4382d2SGreg Kroah-Hartman /*
61ab4382d2SGreg Kroah-Hartman * Return modem signals to ld.
62ab4382d2SGreg Kroah-Hartman */
jsm_tty_get_mctrl(struct uart_port * port)63ab4382d2SGreg Kroah-Hartman static unsigned int jsm_tty_get_mctrl(struct uart_port *port)
64ab4382d2SGreg Kroah-Hartman {
65ab4382d2SGreg Kroah-Hartman int result;
66a15ad348SFabian Frederick struct jsm_channel *channel =
67a15ad348SFabian Frederick container_of(port, struct jsm_channel, uart_port);
68ab4382d2SGreg Kroah-Hartman
69669fef46SJoe Perches jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
70ab4382d2SGreg Kroah-Hartman
71ab4382d2SGreg Kroah-Hartman result = jsm_get_mstat(channel);
72ab4382d2SGreg Kroah-Hartman
73ab4382d2SGreg Kroah-Hartman if (result < 0)
74ab4382d2SGreg Kroah-Hartman return -ENXIO;
75ab4382d2SGreg Kroah-Hartman
76669fef46SJoe Perches jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n");
77ab4382d2SGreg Kroah-Hartman
78ab4382d2SGreg Kroah-Hartman return result;
79ab4382d2SGreg Kroah-Hartman }
80ab4382d2SGreg Kroah-Hartman
81ab4382d2SGreg Kroah-Hartman /*
82ab4382d2SGreg Kroah-Hartman * jsm_set_modem_info()
83ab4382d2SGreg Kroah-Hartman *
84ab4382d2SGreg Kroah-Hartman * Set modem signals, called by ld.
85ab4382d2SGreg Kroah-Hartman */
jsm_tty_set_mctrl(struct uart_port * port,unsigned int mctrl)86ab4382d2SGreg Kroah-Hartman static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl)
87ab4382d2SGreg Kroah-Hartman {
88a15ad348SFabian Frederick struct jsm_channel *channel =
89a15ad348SFabian Frederick container_of(port, struct jsm_channel, uart_port);
90ab4382d2SGreg Kroah-Hartman
91669fef46SJoe Perches jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
92ab4382d2SGreg Kroah-Hartman
93ab4382d2SGreg Kroah-Hartman if (mctrl & TIOCM_RTS)
94ab4382d2SGreg Kroah-Hartman channel->ch_mostat |= UART_MCR_RTS;
95ab4382d2SGreg Kroah-Hartman else
96ab4382d2SGreg Kroah-Hartman channel->ch_mostat &= ~UART_MCR_RTS;
97ab4382d2SGreg Kroah-Hartman
98ab4382d2SGreg Kroah-Hartman if (mctrl & TIOCM_DTR)
99ab4382d2SGreg Kroah-Hartman channel->ch_mostat |= UART_MCR_DTR;
100ab4382d2SGreg Kroah-Hartman else
101ab4382d2SGreg Kroah-Hartman channel->ch_mostat &= ~UART_MCR_DTR;
102ab4382d2SGreg Kroah-Hartman
103ab4382d2SGreg Kroah-Hartman channel->ch_bd->bd_ops->assert_modem_signals(channel);
104ab4382d2SGreg Kroah-Hartman
105669fef46SJoe Perches jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n");
106ab4382d2SGreg Kroah-Hartman udelay(10);
107ab4382d2SGreg Kroah-Hartman }
108ab4382d2SGreg Kroah-Hartman
1099d898966SThadeu Lima de Souza Cascardo /*
1109d898966SThadeu Lima de Souza Cascardo * jsm_tty_write()
1119d898966SThadeu Lima de Souza Cascardo *
1129d898966SThadeu Lima de Souza Cascardo * Take data from the user or kernel and send it out to the FEP.
1139d898966SThadeu Lima de Souza Cascardo * In here exists all the Transparent Print magic as well.
1149d898966SThadeu Lima de Souza Cascardo */
jsm_tty_write(struct uart_port * port)1159d898966SThadeu Lima de Souza Cascardo static void jsm_tty_write(struct uart_port *port)
1169d898966SThadeu Lima de Souza Cascardo {
1179d898966SThadeu Lima de Souza Cascardo struct jsm_channel *channel;
118d13551d1SGimcuan Hui
1199d898966SThadeu Lima de Souza Cascardo channel = container_of(port, struct jsm_channel, uart_port);
1209d898966SThadeu Lima de Souza Cascardo channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel);
1219d898966SThadeu Lima de Souza Cascardo }
1229d898966SThadeu Lima de Souza Cascardo
jsm_tty_start_tx(struct uart_port * port)123ab4382d2SGreg Kroah-Hartman static void jsm_tty_start_tx(struct uart_port *port)
124ab4382d2SGreg Kroah-Hartman {
125a15ad348SFabian Frederick struct jsm_channel *channel =
126a15ad348SFabian Frederick container_of(port, struct jsm_channel, uart_port);
127ab4382d2SGreg Kroah-Hartman
128669fef46SJoe Perches jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
129ab4382d2SGreg Kroah-Hartman
130ab4382d2SGreg Kroah-Hartman channel->ch_flags &= ~(CH_STOP);
131ab4382d2SGreg Kroah-Hartman jsm_tty_write(port);
132ab4382d2SGreg Kroah-Hartman
133669fef46SJoe Perches jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n");
134ab4382d2SGreg Kroah-Hartman }
135ab4382d2SGreg Kroah-Hartman
jsm_tty_stop_tx(struct uart_port * port)136ab4382d2SGreg Kroah-Hartman static void jsm_tty_stop_tx(struct uart_port *port)
137ab4382d2SGreg Kroah-Hartman {
138a15ad348SFabian Frederick struct jsm_channel *channel =
139a15ad348SFabian Frederick container_of(port, struct jsm_channel, uart_port);
140ab4382d2SGreg Kroah-Hartman
141669fef46SJoe Perches jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
142ab4382d2SGreg Kroah-Hartman
143ab4382d2SGreg Kroah-Hartman channel->ch_flags |= (CH_STOP);
144ab4382d2SGreg Kroah-Hartman
145669fef46SJoe Perches jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n");
146ab4382d2SGreg Kroah-Hartman }
147ab4382d2SGreg Kroah-Hartman
jsm_tty_send_xchar(struct uart_port * port,char ch)148ab4382d2SGreg Kroah-Hartman static void jsm_tty_send_xchar(struct uart_port *port, char ch)
149ab4382d2SGreg Kroah-Hartman {
150ab4382d2SGreg Kroah-Hartman unsigned long lock_flags;
151a15ad348SFabian Frederick struct jsm_channel *channel =
152a15ad348SFabian Frederick container_of(port, struct jsm_channel, uart_port);
153ab4382d2SGreg Kroah-Hartman struct ktermios *termios;
154ab4382d2SGreg Kroah-Hartman
155ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&port->lock, lock_flags);
156adc8d746SAlan Cox termios = &port->state->port.tty->termios;
157ab4382d2SGreg Kroah-Hartman if (ch == termios->c_cc[VSTART])
158ab4382d2SGreg Kroah-Hartman channel->ch_bd->bd_ops->send_start_character(channel);
159ab4382d2SGreg Kroah-Hartman
160ab4382d2SGreg Kroah-Hartman if (ch == termios->c_cc[VSTOP])
161ab4382d2SGreg Kroah-Hartman channel->ch_bd->bd_ops->send_stop_character(channel);
162ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&port->lock, lock_flags);
163ab4382d2SGreg Kroah-Hartman }
164ab4382d2SGreg Kroah-Hartman
jsm_tty_stop_rx(struct uart_port * port)165ab4382d2SGreg Kroah-Hartman static void jsm_tty_stop_rx(struct uart_port *port)
166ab4382d2SGreg Kroah-Hartman {
167a15ad348SFabian Frederick struct jsm_channel *channel =
168a15ad348SFabian Frederick container_of(port, struct jsm_channel, uart_port);
169ab4382d2SGreg Kroah-Hartman
170ab4382d2SGreg Kroah-Hartman channel->ch_bd->bd_ops->disable_receiver(channel);
171ab4382d2SGreg Kroah-Hartman }
172ab4382d2SGreg Kroah-Hartman
jsm_tty_break(struct uart_port * port,int break_state)173ab4382d2SGreg Kroah-Hartman static void jsm_tty_break(struct uart_port *port, int break_state)
174ab4382d2SGreg Kroah-Hartman {
175ab4382d2SGreg Kroah-Hartman unsigned long lock_flags;
176a15ad348SFabian Frederick struct jsm_channel *channel =
177a15ad348SFabian Frederick container_of(port, struct jsm_channel, uart_port);
178ab4382d2SGreg Kroah-Hartman
179ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&port->lock, lock_flags);
180ab4382d2SGreg Kroah-Hartman if (break_state == -1)
181ab4382d2SGreg Kroah-Hartman channel->ch_bd->bd_ops->send_break(channel);
182ab4382d2SGreg Kroah-Hartman else
183333f4eb1SKonrad Zapalowicz channel->ch_bd->bd_ops->clear_break(channel);
184ab4382d2SGreg Kroah-Hartman
185ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&port->lock, lock_flags);
186ab4382d2SGreg Kroah-Hartman }
187ab4382d2SGreg Kroah-Hartman
jsm_tty_open(struct uart_port * port)188ab4382d2SGreg Kroah-Hartman static int jsm_tty_open(struct uart_port *port)
189ab4382d2SGreg Kroah-Hartman {
190240e126cSZheyu Ma unsigned long lock_flags;
191ab4382d2SGreg Kroah-Hartman struct jsm_board *brd;
192a15ad348SFabian Frederick struct jsm_channel *channel =
193a15ad348SFabian Frederick container_of(port, struct jsm_channel, uart_port);
194ab4382d2SGreg Kroah-Hartman struct ktermios *termios;
195ab4382d2SGreg Kroah-Hartman
196ab4382d2SGreg Kroah-Hartman /* Get board pointer from our array of majors we have allocated */
197ab4382d2SGreg Kroah-Hartman brd = channel->ch_bd;
198ab4382d2SGreg Kroah-Hartman
199ab4382d2SGreg Kroah-Hartman /*
200ab4382d2SGreg Kroah-Hartman * Allocate channel buffers for read/write/error.
201ab4382d2SGreg Kroah-Hartman * Set flag, so we don't get trounced on.
202ab4382d2SGreg Kroah-Hartman */
203ab4382d2SGreg Kroah-Hartman channel->ch_flags |= (CH_OPENING);
204ab4382d2SGreg Kroah-Hartman
205ab4382d2SGreg Kroah-Hartman /* Drop locks, as malloc with GFP_KERNEL can sleep */
206ab4382d2SGreg Kroah-Hartman
207ab4382d2SGreg Kroah-Hartman if (!channel->ch_rqueue) {
208ab4382d2SGreg Kroah-Hartman channel->ch_rqueue = kzalloc(RQUEUESIZE, GFP_KERNEL);
209ab4382d2SGreg Kroah-Hartman if (!channel->ch_rqueue) {
210669fef46SJoe Perches jsm_dbg(INIT, &channel->ch_bd->pci_dev,
211669fef46SJoe Perches "unable to allocate read queue buf\n");
212ab4382d2SGreg Kroah-Hartman return -ENOMEM;
213ab4382d2SGreg Kroah-Hartman }
214ab4382d2SGreg Kroah-Hartman }
215ab4382d2SGreg Kroah-Hartman if (!channel->ch_equeue) {
216ab4382d2SGreg Kroah-Hartman channel->ch_equeue = kzalloc(EQUEUESIZE, GFP_KERNEL);
217ab4382d2SGreg Kroah-Hartman if (!channel->ch_equeue) {
218669fef46SJoe Perches jsm_dbg(INIT, &channel->ch_bd->pci_dev,
219669fef46SJoe Perches "unable to allocate error queue buf\n");
220ab4382d2SGreg Kroah-Hartman return -ENOMEM;
221ab4382d2SGreg Kroah-Hartman }
222ab4382d2SGreg Kroah-Hartman }
223ab4382d2SGreg Kroah-Hartman
224ab4382d2SGreg Kroah-Hartman channel->ch_flags &= ~(CH_OPENING);
225ab4382d2SGreg Kroah-Hartman /*
226ab4382d2SGreg Kroah-Hartman * Initialize if neither terminal is open.
227ab4382d2SGreg Kroah-Hartman */
228669fef46SJoe Perches jsm_dbg(OPEN, &channel->ch_bd->pci_dev,
229ab4382d2SGreg Kroah-Hartman "jsm_open: initializing channel in open...\n");
230ab4382d2SGreg Kroah-Hartman
231ab4382d2SGreg Kroah-Hartman /*
232ab4382d2SGreg Kroah-Hartman * Flush input queues.
233ab4382d2SGreg Kroah-Hartman */
234ab4382d2SGreg Kroah-Hartman channel->ch_r_head = channel->ch_r_tail = 0;
235ab4382d2SGreg Kroah-Hartman channel->ch_e_head = channel->ch_e_tail = 0;
236ab4382d2SGreg Kroah-Hartman
237ab4382d2SGreg Kroah-Hartman brd->bd_ops->flush_uart_write(channel);
238ab4382d2SGreg Kroah-Hartman brd->bd_ops->flush_uart_read(channel);
239ab4382d2SGreg Kroah-Hartman
240ab4382d2SGreg Kroah-Hartman channel->ch_flags = 0;
241ab4382d2SGreg Kroah-Hartman channel->ch_cached_lsr = 0;
242ab4382d2SGreg Kroah-Hartman channel->ch_stops_sent = 0;
243ab4382d2SGreg Kroah-Hartman
244240e126cSZheyu Ma spin_lock_irqsave(&port->lock, lock_flags);
245adc8d746SAlan Cox termios = &port->state->port.tty->termios;
246ab4382d2SGreg Kroah-Hartman channel->ch_c_cflag = termios->c_cflag;
247ab4382d2SGreg Kroah-Hartman channel->ch_c_iflag = termios->c_iflag;
248ab4382d2SGreg Kroah-Hartman channel->ch_c_oflag = termios->c_oflag;
249ab4382d2SGreg Kroah-Hartman channel->ch_c_lflag = termios->c_lflag;
250ab4382d2SGreg Kroah-Hartman channel->ch_startc = termios->c_cc[VSTART];
251ab4382d2SGreg Kroah-Hartman channel->ch_stopc = termios->c_cc[VSTOP];
252ab4382d2SGreg Kroah-Hartman
253ab4382d2SGreg Kroah-Hartman /* Tell UART to init itself */
254ab4382d2SGreg Kroah-Hartman brd->bd_ops->uart_init(channel);
255ab4382d2SGreg Kroah-Hartman
256ab4382d2SGreg Kroah-Hartman /*
257ab4382d2SGreg Kroah-Hartman * Run param in case we changed anything
258ab4382d2SGreg Kroah-Hartman */
259ab4382d2SGreg Kroah-Hartman brd->bd_ops->param(channel);
260ab4382d2SGreg Kroah-Hartman
261ab4382d2SGreg Kroah-Hartman jsm_carrier(channel);
262ab4382d2SGreg Kroah-Hartman
263ab4382d2SGreg Kroah-Hartman channel->ch_open_count++;
264240e126cSZheyu Ma spin_unlock_irqrestore(&port->lock, lock_flags);
265ab4382d2SGreg Kroah-Hartman
266669fef46SJoe Perches jsm_dbg(OPEN, &channel->ch_bd->pci_dev, "finish\n");
267ab4382d2SGreg Kroah-Hartman return 0;
268ab4382d2SGreg Kroah-Hartman }
269ab4382d2SGreg Kroah-Hartman
jsm_tty_close(struct uart_port * port)270ab4382d2SGreg Kroah-Hartman static void jsm_tty_close(struct uart_port *port)
271ab4382d2SGreg Kroah-Hartman {
272ab4382d2SGreg Kroah-Hartman struct jsm_board *bd;
273a15ad348SFabian Frederick struct jsm_channel *channel =
274a15ad348SFabian Frederick container_of(port, struct jsm_channel, uart_port);
275ab4382d2SGreg Kroah-Hartman
276669fef46SJoe Perches jsm_dbg(CLOSE, &channel->ch_bd->pci_dev, "start\n");
277ab4382d2SGreg Kroah-Hartman
278ab4382d2SGreg Kroah-Hartman bd = channel->ch_bd;
279ab4382d2SGreg Kroah-Hartman
280ab4382d2SGreg Kroah-Hartman channel->ch_flags &= ~(CH_STOPI);
281ab4382d2SGreg Kroah-Hartman
282ab4382d2SGreg Kroah-Hartman channel->ch_open_count--;
283ab4382d2SGreg Kroah-Hartman
284ab4382d2SGreg Kroah-Hartman /*
285ab4382d2SGreg Kroah-Hartman * If we have HUPCL set, lower DTR and RTS
286ab4382d2SGreg Kroah-Hartman */
287ab4382d2SGreg Kroah-Hartman if (channel->ch_c_cflag & HUPCL) {
288669fef46SJoe Perches jsm_dbg(CLOSE, &channel->ch_bd->pci_dev,
289ab4382d2SGreg Kroah-Hartman "Close. HUPCL set, dropping DTR/RTS\n");
290ab4382d2SGreg Kroah-Hartman
291ab4382d2SGreg Kroah-Hartman /* Drop RTS/DTR */
292ab4382d2SGreg Kroah-Hartman channel->ch_mostat &= ~(UART_MCR_DTR | UART_MCR_RTS);
293ab4382d2SGreg Kroah-Hartman bd->bd_ops->assert_modem_signals(channel);
294ab4382d2SGreg Kroah-Hartman }
295ab4382d2SGreg Kroah-Hartman
296ab4382d2SGreg Kroah-Hartman /* Turn off UART interrupts for this port */
297ab4382d2SGreg Kroah-Hartman channel->ch_bd->bd_ops->uart_off(channel);
298ab4382d2SGreg Kroah-Hartman
299669fef46SJoe Perches jsm_dbg(CLOSE, &channel->ch_bd->pci_dev, "finish\n");
300ab4382d2SGreg Kroah-Hartman }
301ab4382d2SGreg Kroah-Hartman
jsm_tty_set_termios(struct uart_port * port,struct ktermios * termios,const struct ktermios * old_termios)302ab4382d2SGreg Kroah-Hartman static void jsm_tty_set_termios(struct uart_port *port,
303ab4382d2SGreg Kroah-Hartman struct ktermios *termios,
304*bec5b814SIlpo Järvinen const struct ktermios *old_termios)
305ab4382d2SGreg Kroah-Hartman {
306ab4382d2SGreg Kroah-Hartman unsigned long lock_flags;
307a15ad348SFabian Frederick struct jsm_channel *channel =
308a15ad348SFabian Frederick container_of(port, struct jsm_channel, uart_port);
309ab4382d2SGreg Kroah-Hartman
310ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&port->lock, lock_flags);
311ab4382d2SGreg Kroah-Hartman channel->ch_c_cflag = termios->c_cflag;
312ab4382d2SGreg Kroah-Hartman channel->ch_c_iflag = termios->c_iflag;
313ab4382d2SGreg Kroah-Hartman channel->ch_c_oflag = termios->c_oflag;
314ab4382d2SGreg Kroah-Hartman channel->ch_c_lflag = termios->c_lflag;
315ab4382d2SGreg Kroah-Hartman channel->ch_startc = termios->c_cc[VSTART];
316ab4382d2SGreg Kroah-Hartman channel->ch_stopc = termios->c_cc[VSTOP];
317ab4382d2SGreg Kroah-Hartman
318ab4382d2SGreg Kroah-Hartman channel->ch_bd->bd_ops->param(channel);
319ab4382d2SGreg Kroah-Hartman jsm_carrier(channel);
320ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&port->lock, lock_flags);
321ab4382d2SGreg Kroah-Hartman }
322ab4382d2SGreg Kroah-Hartman
jsm_tty_type(struct uart_port * port)323ab4382d2SGreg Kroah-Hartman static const char *jsm_tty_type(struct uart_port *port)
324ab4382d2SGreg Kroah-Hartman {
325ab4382d2SGreg Kroah-Hartman return "jsm";
326ab4382d2SGreg Kroah-Hartman }
327ab4382d2SGreg Kroah-Hartman
jsm_tty_release_port(struct uart_port * port)328ab4382d2SGreg Kroah-Hartman static void jsm_tty_release_port(struct uart_port *port)
329ab4382d2SGreg Kroah-Hartman {
330ab4382d2SGreg Kroah-Hartman }
331ab4382d2SGreg Kroah-Hartman
jsm_tty_request_port(struct uart_port * port)332ab4382d2SGreg Kroah-Hartman static int jsm_tty_request_port(struct uart_port *port)
333ab4382d2SGreg Kroah-Hartman {
334ab4382d2SGreg Kroah-Hartman return 0;
335ab4382d2SGreg Kroah-Hartman }
336ab4382d2SGreg Kroah-Hartman
jsm_config_port(struct uart_port * port,int flags)337ab4382d2SGreg Kroah-Hartman static void jsm_config_port(struct uart_port *port, int flags)
338ab4382d2SGreg Kroah-Hartman {
339ab4382d2SGreg Kroah-Hartman port->type = PORT_JSM;
340ab4382d2SGreg Kroah-Hartman }
341ab4382d2SGreg Kroah-Hartman
3425d9b9530SJulia Lawall static const struct uart_ops jsm_ops = {
343ab4382d2SGreg Kroah-Hartman .tx_empty = jsm_tty_tx_empty,
344ab4382d2SGreg Kroah-Hartman .set_mctrl = jsm_tty_set_mctrl,
345ab4382d2SGreg Kroah-Hartman .get_mctrl = jsm_tty_get_mctrl,
346ab4382d2SGreg Kroah-Hartman .stop_tx = jsm_tty_stop_tx,
347ab4382d2SGreg Kroah-Hartman .start_tx = jsm_tty_start_tx,
348ab4382d2SGreg Kroah-Hartman .send_xchar = jsm_tty_send_xchar,
349ab4382d2SGreg Kroah-Hartman .stop_rx = jsm_tty_stop_rx,
350ab4382d2SGreg Kroah-Hartman .break_ctl = jsm_tty_break,
351ab4382d2SGreg Kroah-Hartman .startup = jsm_tty_open,
352ab4382d2SGreg Kroah-Hartman .shutdown = jsm_tty_close,
353ab4382d2SGreg Kroah-Hartman .set_termios = jsm_tty_set_termios,
354ab4382d2SGreg Kroah-Hartman .type = jsm_tty_type,
355ab4382d2SGreg Kroah-Hartman .release_port = jsm_tty_release_port,
356ab4382d2SGreg Kroah-Hartman .request_port = jsm_tty_request_port,
357ab4382d2SGreg Kroah-Hartman .config_port = jsm_config_port,
358ab4382d2SGreg Kroah-Hartman };
359ab4382d2SGreg Kroah-Hartman
360ab4382d2SGreg Kroah-Hartman /*
361ab4382d2SGreg Kroah-Hartman * jsm_tty_init()
362ab4382d2SGreg Kroah-Hartman *
363ab4382d2SGreg Kroah-Hartman * Init the tty subsystem. Called once per board after board has been
364ab4382d2SGreg Kroah-Hartman * downloaded and init'ed.
365ab4382d2SGreg Kroah-Hartman */
jsm_tty_init(struct jsm_board * brd)3669671f099SBill Pemberton int jsm_tty_init(struct jsm_board *brd)
367ab4382d2SGreg Kroah-Hartman {
368ab4382d2SGreg Kroah-Hartman int i;
369ab4382d2SGreg Kroah-Hartman void __iomem *vaddr;
370ab4382d2SGreg Kroah-Hartman struct jsm_channel *ch;
371ab4382d2SGreg Kroah-Hartman
372ab4382d2SGreg Kroah-Hartman if (!brd)
373ab4382d2SGreg Kroah-Hartman return -ENXIO;
374ab4382d2SGreg Kroah-Hartman
375669fef46SJoe Perches jsm_dbg(INIT, &brd->pci_dev, "start\n");
376ab4382d2SGreg Kroah-Hartman
377ab4382d2SGreg Kroah-Hartman /*
378ab4382d2SGreg Kroah-Hartman * Initialize board structure elements.
379ab4382d2SGreg Kroah-Hartman */
380ab4382d2SGreg Kroah-Hartman
381ab4382d2SGreg Kroah-Hartman brd->nasync = brd->maxports;
382ab4382d2SGreg Kroah-Hartman
383ab4382d2SGreg Kroah-Hartman /*
384ab4382d2SGreg Kroah-Hartman * Allocate channel memory that might not have been allocated
385ab4382d2SGreg Kroah-Hartman * when the driver was first loaded.
386ab4382d2SGreg Kroah-Hartman */
387ab4382d2SGreg Kroah-Hartman for (i = 0; i < brd->nasync; i++) {
388ab4382d2SGreg Kroah-Hartman if (!brd->channels[i]) {
389ab4382d2SGreg Kroah-Hartman
390ab4382d2SGreg Kroah-Hartman /*
391ab4382d2SGreg Kroah-Hartman * Okay to malloc with GFP_KERNEL, we are not at
392ab4382d2SGreg Kroah-Hartman * interrupt context, and there are no locks held.
393ab4382d2SGreg Kroah-Hartman */
394ab4382d2SGreg Kroah-Hartman brd->channels[i] = kzalloc(sizeof(struct jsm_channel), GFP_KERNEL);
395ab4382d2SGreg Kroah-Hartman if (!brd->channels[i]) {
396669fef46SJoe Perches jsm_dbg(CORE, &brd->pci_dev,
397ab4382d2SGreg Kroah-Hartman "%s:%d Unable to allocate memory for channel struct\n",
398ab4382d2SGreg Kroah-Hartman __FILE__, __LINE__);
399ab4382d2SGreg Kroah-Hartman }
400ab4382d2SGreg Kroah-Hartman }
401ab4382d2SGreg Kroah-Hartman }
402ab4382d2SGreg Kroah-Hartman
403ab4382d2SGreg Kroah-Hartman ch = brd->channels[0];
404ab4382d2SGreg Kroah-Hartman vaddr = brd->re_map_membase;
405ab4382d2SGreg Kroah-Hartman
406ab4382d2SGreg Kroah-Hartman /* Set up channel variables */
407ab4382d2SGreg Kroah-Hartman for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
408ab4382d2SGreg Kroah-Hartman
409ab4382d2SGreg Kroah-Hartman if (!brd->channels[i])
410ab4382d2SGreg Kroah-Hartman continue;
411ab4382d2SGreg Kroah-Hartman
412ab4382d2SGreg Kroah-Hartman spin_lock_init(&ch->ch_lock);
413ab4382d2SGreg Kroah-Hartman
414ab4382d2SGreg Kroah-Hartman if (brd->bd_uart_offset == 0x200)
415ab4382d2SGreg Kroah-Hartman ch->ch_neo_uart = vaddr + (brd->bd_uart_offset * i);
41603a8482cSKonrad Zapalowicz else
41703a8482cSKonrad Zapalowicz ch->ch_cls_uart = vaddr + (brd->bd_uart_offset * i);
418ab4382d2SGreg Kroah-Hartman
419ab4382d2SGreg Kroah-Hartman ch->ch_bd = brd;
420ab4382d2SGreg Kroah-Hartman ch->ch_portnum = i;
421ab4382d2SGreg Kroah-Hartman
422ab4382d2SGreg Kroah-Hartman /* .25 second delay */
423ab4382d2SGreg Kroah-Hartman ch->ch_close_delay = 250;
424ab4382d2SGreg Kroah-Hartman
425ab4382d2SGreg Kroah-Hartman init_waitqueue_head(&ch->ch_flags_wait);
426ab4382d2SGreg Kroah-Hartman }
427ab4382d2SGreg Kroah-Hartman
428669fef46SJoe Perches jsm_dbg(INIT, &brd->pci_dev, "finish\n");
429ab4382d2SGreg Kroah-Hartman return 0;
430ab4382d2SGreg Kroah-Hartman }
431ab4382d2SGreg Kroah-Hartman
jsm_uart_port_init(struct jsm_board * brd)432ab4382d2SGreg Kroah-Hartman int jsm_uart_port_init(struct jsm_board *brd)
433ab4382d2SGreg Kroah-Hartman {
434ab4382d2SGreg Kroah-Hartman int i, rc;
435ab4382d2SGreg Kroah-Hartman unsigned int line;
436ab4382d2SGreg Kroah-Hartman
437ab4382d2SGreg Kroah-Hartman if (!brd)
438ab4382d2SGreg Kroah-Hartman return -ENXIO;
439ab4382d2SGreg Kroah-Hartman
440669fef46SJoe Perches jsm_dbg(INIT, &brd->pci_dev, "start\n");
441ab4382d2SGreg Kroah-Hartman
442ab4382d2SGreg Kroah-Hartman /*
443ab4382d2SGreg Kroah-Hartman * Initialize board structure elements.
444ab4382d2SGreg Kroah-Hartman */
445ab4382d2SGreg Kroah-Hartman
446ab4382d2SGreg Kroah-Hartman brd->nasync = brd->maxports;
447ab4382d2SGreg Kroah-Hartman
448ab4382d2SGreg Kroah-Hartman /* Set up channel variables */
449819abf29SColin Ian King for (i = 0; i < brd->nasync; i++) {
450ab4382d2SGreg Kroah-Hartman
451ab4382d2SGreg Kroah-Hartman if (!brd->channels[i])
452ab4382d2SGreg Kroah-Hartman continue;
453ab4382d2SGreg Kroah-Hartman
454ab4382d2SGreg Kroah-Hartman brd->channels[i]->uart_port.irq = brd->irq;
455ab4382d2SGreg Kroah-Hartman brd->channels[i]->uart_port.uartclk = 14745600;
456ab4382d2SGreg Kroah-Hartman brd->channels[i]->uart_port.type = PORT_JSM;
457ab4382d2SGreg Kroah-Hartman brd->channels[i]->uart_port.iotype = UPIO_MEM;
458ab4382d2SGreg Kroah-Hartman brd->channels[i]->uart_port.membase = brd->re_map_membase;
459ab4382d2SGreg Kroah-Hartman brd->channels[i]->uart_port.fifosize = 16;
460ab4382d2SGreg Kroah-Hartman brd->channels[i]->uart_port.ops = &jsm_ops;
461ab4382d2SGreg Kroah-Hartman line = find_first_zero_bit(linemap, MAXLINES);
462ab4382d2SGreg Kroah-Hartman if (line >= MAXLINES) {
463ab4382d2SGreg Kroah-Hartman printk(KERN_INFO "jsm: linemap is full, added device failed\n");
464ab4382d2SGreg Kroah-Hartman continue;
465ab4382d2SGreg Kroah-Hartman } else
466ab4382d2SGreg Kroah-Hartman set_bit(line, linemap);
467ab4382d2SGreg Kroah-Hartman brd->channels[i]->uart_port.line = line;
468ab4382d2SGreg Kroah-Hartman rc = uart_add_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port);
469ab4382d2SGreg Kroah-Hartman if (rc) {
470ab4382d2SGreg Kroah-Hartman printk(KERN_INFO "jsm: Port %d failed. Aborting...\n", i);
471ab4382d2SGreg Kroah-Hartman return rc;
47267c6f4b6SGimcuan Hui } else
473ab4382d2SGreg Kroah-Hartman printk(KERN_INFO "jsm: Port %d added\n", i);
474ab4382d2SGreg Kroah-Hartman }
475ab4382d2SGreg Kroah-Hartman
476669fef46SJoe Perches jsm_dbg(INIT, &brd->pci_dev, "finish\n");
477ab4382d2SGreg Kroah-Hartman return 0;
478ab4382d2SGreg Kroah-Hartman }
479ab4382d2SGreg Kroah-Hartman
jsm_remove_uart_port(struct jsm_board * brd)480ab4382d2SGreg Kroah-Hartman int jsm_remove_uart_port(struct jsm_board *brd)
481ab4382d2SGreg Kroah-Hartman {
482ab4382d2SGreg Kroah-Hartman int i;
483ab4382d2SGreg Kroah-Hartman struct jsm_channel *ch;
484ab4382d2SGreg Kroah-Hartman
485ab4382d2SGreg Kroah-Hartman if (!brd)
486ab4382d2SGreg Kroah-Hartman return -ENXIO;
487ab4382d2SGreg Kroah-Hartman
488669fef46SJoe Perches jsm_dbg(INIT, &brd->pci_dev, "start\n");
489ab4382d2SGreg Kroah-Hartman
490ab4382d2SGreg Kroah-Hartman /*
491ab4382d2SGreg Kroah-Hartman * Initialize board structure elements.
492ab4382d2SGreg Kroah-Hartman */
493ab4382d2SGreg Kroah-Hartman
494ab4382d2SGreg Kroah-Hartman brd->nasync = brd->maxports;
495ab4382d2SGreg Kroah-Hartman
496ab4382d2SGreg Kroah-Hartman /* Set up channel variables */
497ab4382d2SGreg Kroah-Hartman for (i = 0; i < brd->nasync; i++) {
498ab4382d2SGreg Kroah-Hartman
499ab4382d2SGreg Kroah-Hartman if (!brd->channels[i])
500ab4382d2SGreg Kroah-Hartman continue;
501ab4382d2SGreg Kroah-Hartman
502ab4382d2SGreg Kroah-Hartman ch = brd->channels[i];
503ab4382d2SGreg Kroah-Hartman
504ab4382d2SGreg Kroah-Hartman clear_bit(ch->uart_port.line, linemap);
505ab4382d2SGreg Kroah-Hartman uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port);
506ab4382d2SGreg Kroah-Hartman }
507ab4382d2SGreg Kroah-Hartman
508669fef46SJoe Perches jsm_dbg(INIT, &brd->pci_dev, "finish\n");
509ab4382d2SGreg Kroah-Hartman return 0;
510ab4382d2SGreg Kroah-Hartman }
511ab4382d2SGreg Kroah-Hartman
jsm_input(struct jsm_channel * ch)512ab4382d2SGreg Kroah-Hartman void jsm_input(struct jsm_channel *ch)
513ab4382d2SGreg Kroah-Hartman {
514ab4382d2SGreg Kroah-Hartman struct jsm_board *bd;
515ab4382d2SGreg Kroah-Hartman struct tty_struct *tp;
516227434f8SJiri Slaby struct tty_port *port;
517ab4382d2SGreg Kroah-Hartman u32 rmask;
518ab4382d2SGreg Kroah-Hartman u16 head;
519ab4382d2SGreg Kroah-Hartman u16 tail;
520ab4382d2SGreg Kroah-Hartman int data_len;
521ab4382d2SGreg Kroah-Hartman unsigned long lock_flags;
522ab4382d2SGreg Kroah-Hartman int len = 0;
523ab4382d2SGreg Kroah-Hartman int s = 0;
524ab4382d2SGreg Kroah-Hartman int i = 0;
525ab4382d2SGreg Kroah-Hartman
526669fef46SJoe Perches jsm_dbg(READ, &ch->ch_bd->pci_dev, "start\n");
527ab4382d2SGreg Kroah-Hartman
528227434f8SJiri Slaby port = &ch->uart_port.state->port;
529227434f8SJiri Slaby tp = port->tty;
530ab4382d2SGreg Kroah-Hartman
531ab4382d2SGreg Kroah-Hartman bd = ch->ch_bd;
532ab4382d2SGreg Kroah-Hartman if (!bd)
533ab4382d2SGreg Kroah-Hartman return;
534ab4382d2SGreg Kroah-Hartman
535ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&ch->ch_lock, lock_flags);
536ab4382d2SGreg Kroah-Hartman
537ab4382d2SGreg Kroah-Hartman /*
538ab4382d2SGreg Kroah-Hartman *Figure the number of characters in the buffer.
539ab4382d2SGreg Kroah-Hartman *Exit immediately if none.
540ab4382d2SGreg Kroah-Hartman */
541ab4382d2SGreg Kroah-Hartman
542ab4382d2SGreg Kroah-Hartman rmask = RQUEUEMASK;
543ab4382d2SGreg Kroah-Hartman
544ab4382d2SGreg Kroah-Hartman head = ch->ch_r_head & rmask;
545ab4382d2SGreg Kroah-Hartman tail = ch->ch_r_tail & rmask;
546ab4382d2SGreg Kroah-Hartman
547ab4382d2SGreg Kroah-Hartman data_len = (head - tail) & rmask;
548ab4382d2SGreg Kroah-Hartman if (data_len == 0) {
549ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
550ab4382d2SGreg Kroah-Hartman return;
551ab4382d2SGreg Kroah-Hartman }
552ab4382d2SGreg Kroah-Hartman
553669fef46SJoe Perches jsm_dbg(READ, &ch->ch_bd->pci_dev, "start\n");
554ab4382d2SGreg Kroah-Hartman
555ab4382d2SGreg Kroah-Hartman /*
556ab4382d2SGreg Kroah-Hartman *If the device is not open, or CREAD is off, flush
557ab4382d2SGreg Kroah-Hartman *input data and return immediately.
558ab4382d2SGreg Kroah-Hartman */
5599db276f8SPeter Hurley if (!tp || !C_CREAD(tp)) {
560ab4382d2SGreg Kroah-Hartman
561669fef46SJoe Perches jsm_dbg(READ, &ch->ch_bd->pci_dev,
562669fef46SJoe Perches "input. dropping %d bytes on port %d...\n",
563669fef46SJoe Perches data_len, ch->ch_portnum);
564ab4382d2SGreg Kroah-Hartman ch->ch_r_head = tail;
565ab4382d2SGreg Kroah-Hartman
566ab4382d2SGreg Kroah-Hartman /* Force queue flow control to be released, if needed */
567ab4382d2SGreg Kroah-Hartman jsm_check_queue_flow_control(ch);
568ab4382d2SGreg Kroah-Hartman
569ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
570ab4382d2SGreg Kroah-Hartman return;
571ab4382d2SGreg Kroah-Hartman }
572ab4382d2SGreg Kroah-Hartman
573ab4382d2SGreg Kroah-Hartman /*
574ab4382d2SGreg Kroah-Hartman * If we are throttled, simply don't read any data.
575ab4382d2SGreg Kroah-Hartman */
576ab4382d2SGreg Kroah-Hartman if (ch->ch_flags & CH_STOPI) {
577ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
578669fef46SJoe Perches jsm_dbg(READ, &ch->ch_bd->pci_dev,
579ab4382d2SGreg Kroah-Hartman "Port %d throttled, not reading any data. head: %x tail: %x\n",
580ab4382d2SGreg Kroah-Hartman ch->ch_portnum, head, tail);
581ab4382d2SGreg Kroah-Hartman return;
582ab4382d2SGreg Kroah-Hartman }
583ab4382d2SGreg Kroah-Hartman
584669fef46SJoe Perches jsm_dbg(READ, &ch->ch_bd->pci_dev, "start 2\n");
585ab4382d2SGreg Kroah-Hartman
586227434f8SJiri Slaby len = tty_buffer_request_room(port, data_len);
587ab4382d2SGreg Kroah-Hartman
588ab4382d2SGreg Kroah-Hartman /*
58998cb4ab0SJakob Østergaard Jensen * len now contains the most amount of data we can copy,
590ab4382d2SGreg Kroah-Hartman * bounded either by the flip buffer size or the amount
591ab4382d2SGreg Kroah-Hartman * of data the card actually has pending...
592ab4382d2SGreg Kroah-Hartman */
59398cb4ab0SJakob Østergaard Jensen while (len) {
594ab4382d2SGreg Kroah-Hartman s = ((head >= tail) ? head : RQUEUESIZE) - tail;
59598cb4ab0SJakob Østergaard Jensen s = min(s, len);
596ab4382d2SGreg Kroah-Hartman
597ab4382d2SGreg Kroah-Hartman if (s <= 0)
598ab4382d2SGreg Kroah-Hartman break;
599ab4382d2SGreg Kroah-Hartman
600ab4382d2SGreg Kroah-Hartman /*
601ab4382d2SGreg Kroah-Hartman * If conditions are such that ld needs to see all
602ab4382d2SGreg Kroah-Hartman * UART errors, we will have to walk each character
603ab4382d2SGreg Kroah-Hartman * and error byte and send them to the buffer one at
604ab4382d2SGreg Kroah-Hartman * a time.
605ab4382d2SGreg Kroah-Hartman */
606ab4382d2SGreg Kroah-Hartman
607ab4382d2SGreg Kroah-Hartman if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
608ab4382d2SGreg Kroah-Hartman for (i = 0; i < s; i++) {
609df11abebSJiri Slaby u8 chr = ch->ch_rqueue[tail + i];
610df11abebSJiri Slaby u8 error = ch->ch_equeue[tail + i];
611df11abebSJiri Slaby char flag = TTY_NORMAL;
612df11abebSJiri Slaby
613ab4382d2SGreg Kroah-Hartman /*
614df11abebSJiri Slaby * Give the Linux ld the flags in the format it
615df11abebSJiri Slaby * likes.
616ab4382d2SGreg Kroah-Hartman */
617df11abebSJiri Slaby if (error & UART_LSR_BI)
618df11abebSJiri Slaby flag = TTY_BREAK;
619df11abebSJiri Slaby else if (error & UART_LSR_PE)
620df11abebSJiri Slaby flag = TTY_PARITY;
621df11abebSJiri Slaby else if (error & UART_LSR_FE)
622df11abebSJiri Slaby flag = TTY_FRAME;
623df11abebSJiri Slaby
624df11abebSJiri Slaby tty_insert_flip_char(port, chr, flag);
625ab4382d2SGreg Kroah-Hartman }
626ab4382d2SGreg Kroah-Hartman } else {
62705c7cd39SJiri Slaby tty_insert_flip_string(port, ch->ch_rqueue + tail, s);
628ab4382d2SGreg Kroah-Hartman }
629ab4382d2SGreg Kroah-Hartman tail += s;
63098cb4ab0SJakob Østergaard Jensen len -= s;
631ab4382d2SGreg Kroah-Hartman /* Flip queue if needed */
632ab4382d2SGreg Kroah-Hartman tail &= rmask;
633ab4382d2SGreg Kroah-Hartman }
634ab4382d2SGreg Kroah-Hartman
635ab4382d2SGreg Kroah-Hartman ch->ch_r_tail = tail & rmask;
636ab4382d2SGreg Kroah-Hartman ch->ch_e_tail = tail & rmask;
637ab4382d2SGreg Kroah-Hartman jsm_check_queue_flow_control(ch);
638ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
639ab4382d2SGreg Kroah-Hartman
640ab4382d2SGreg Kroah-Hartman /* Tell the tty layer its okay to "eat" the data now */
6412e124b4aSJiri Slaby tty_flip_buffer_push(port);
642ab4382d2SGreg Kroah-Hartman
643669fef46SJoe Perches jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, "finish\n");
644ab4382d2SGreg Kroah-Hartman }
645ab4382d2SGreg Kroah-Hartman
jsm_carrier(struct jsm_channel * ch)646ab4382d2SGreg Kroah-Hartman static void jsm_carrier(struct jsm_channel *ch)
647ab4382d2SGreg Kroah-Hartman {
648ab4382d2SGreg Kroah-Hartman struct jsm_board *bd;
649ab4382d2SGreg Kroah-Hartman
650ab4382d2SGreg Kroah-Hartman int virt_carrier = 0;
651ab4382d2SGreg Kroah-Hartman int phys_carrier = 0;
652ab4382d2SGreg Kroah-Hartman
653669fef46SJoe Perches jsm_dbg(CARR, &ch->ch_bd->pci_dev, "start\n");
654ab4382d2SGreg Kroah-Hartman
655ab4382d2SGreg Kroah-Hartman bd = ch->ch_bd;
656ab4382d2SGreg Kroah-Hartman if (!bd)
657ab4382d2SGreg Kroah-Hartman return;
658ab4382d2SGreg Kroah-Hartman
659ab4382d2SGreg Kroah-Hartman if (ch->ch_mistat & UART_MSR_DCD) {
660669fef46SJoe Perches jsm_dbg(CARR, &ch->ch_bd->pci_dev, "mistat: %x D_CD: %x\n",
661669fef46SJoe Perches ch->ch_mistat, ch->ch_mistat & UART_MSR_DCD);
662ab4382d2SGreg Kroah-Hartman phys_carrier = 1;
663ab4382d2SGreg Kroah-Hartman }
664ab4382d2SGreg Kroah-Hartman
665ab4382d2SGreg Kroah-Hartman if (ch->ch_c_cflag & CLOCAL)
666ab4382d2SGreg Kroah-Hartman virt_carrier = 1;
667ab4382d2SGreg Kroah-Hartman
668669fef46SJoe Perches jsm_dbg(CARR, &ch->ch_bd->pci_dev, "DCD: physical: %d virt: %d\n",
669669fef46SJoe Perches phys_carrier, virt_carrier);
670ab4382d2SGreg Kroah-Hartman
671ab4382d2SGreg Kroah-Hartman /*
672ab4382d2SGreg Kroah-Hartman * Test for a VIRTUAL carrier transition to HIGH.
673ab4382d2SGreg Kroah-Hartman */
674ab4382d2SGreg Kroah-Hartman if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) {
675ab4382d2SGreg Kroah-Hartman
676ab4382d2SGreg Kroah-Hartman /*
677ab4382d2SGreg Kroah-Hartman * When carrier rises, wake any threads waiting
678ab4382d2SGreg Kroah-Hartman * for carrier in the open routine.
679ab4382d2SGreg Kroah-Hartman */
680ab4382d2SGreg Kroah-Hartman
681669fef46SJoe Perches jsm_dbg(CARR, &ch->ch_bd->pci_dev, "carrier: virt DCD rose\n");
682ab4382d2SGreg Kroah-Hartman
683ab4382d2SGreg Kroah-Hartman if (waitqueue_active(&(ch->ch_flags_wait)))
684ab4382d2SGreg Kroah-Hartman wake_up_interruptible(&ch->ch_flags_wait);
685ab4382d2SGreg Kroah-Hartman }
686ab4382d2SGreg Kroah-Hartman
687ab4382d2SGreg Kroah-Hartman /*
688ab4382d2SGreg Kroah-Hartman * Test for a PHYSICAL carrier transition to HIGH.
689ab4382d2SGreg Kroah-Hartman */
690ab4382d2SGreg Kroah-Hartman if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) {
691ab4382d2SGreg Kroah-Hartman
692ab4382d2SGreg Kroah-Hartman /*
693ab4382d2SGreg Kroah-Hartman * When carrier rises, wake any threads waiting
694ab4382d2SGreg Kroah-Hartman * for carrier in the open routine.
695ab4382d2SGreg Kroah-Hartman */
696ab4382d2SGreg Kroah-Hartman
697669fef46SJoe Perches jsm_dbg(CARR, &ch->ch_bd->pci_dev,
698ab4382d2SGreg Kroah-Hartman "carrier: physical DCD rose\n");
699ab4382d2SGreg Kroah-Hartman
700ab4382d2SGreg Kroah-Hartman if (waitqueue_active(&(ch->ch_flags_wait)))
701ab4382d2SGreg Kroah-Hartman wake_up_interruptible(&ch->ch_flags_wait);
702ab4382d2SGreg Kroah-Hartman }
703ab4382d2SGreg Kroah-Hartman
704ab4382d2SGreg Kroah-Hartman /*
705ab4382d2SGreg Kroah-Hartman * Test for a PHYSICAL transition to low, so long as we aren't
706ab4382d2SGreg Kroah-Hartman * currently ignoring physical transitions (which is what "virtual
707ab4382d2SGreg Kroah-Hartman * carrier" indicates).
708ab4382d2SGreg Kroah-Hartman *
709ab4382d2SGreg Kroah-Hartman * The transition of the virtual carrier to low really doesn't
710ab4382d2SGreg Kroah-Hartman * matter... it really only means "ignore carrier state", not
711ab4382d2SGreg Kroah-Hartman * "make pretend that carrier is there".
712ab4382d2SGreg Kroah-Hartman */
713ab4382d2SGreg Kroah-Hartman if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0)
714ab4382d2SGreg Kroah-Hartman && (phys_carrier == 0)) {
715ab4382d2SGreg Kroah-Hartman /*
716ab4382d2SGreg Kroah-Hartman * When carrier drops:
717ab4382d2SGreg Kroah-Hartman *
718ab4382d2SGreg Kroah-Hartman * Drop carrier on all open units.
719ab4382d2SGreg Kroah-Hartman *
720ab4382d2SGreg Kroah-Hartman * Flush queues, waking up any task waiting in the
721ab4382d2SGreg Kroah-Hartman * line discipline.
722ab4382d2SGreg Kroah-Hartman *
723ab4382d2SGreg Kroah-Hartman * Send a hangup to the control terminal.
724ab4382d2SGreg Kroah-Hartman *
725ab4382d2SGreg Kroah-Hartman * Enable all select calls.
726ab4382d2SGreg Kroah-Hartman */
727ab4382d2SGreg Kroah-Hartman if (waitqueue_active(&(ch->ch_flags_wait)))
728ab4382d2SGreg Kroah-Hartman wake_up_interruptible(&ch->ch_flags_wait);
729ab4382d2SGreg Kroah-Hartman }
730ab4382d2SGreg Kroah-Hartman
731ab4382d2SGreg Kroah-Hartman /*
732ab4382d2SGreg Kroah-Hartman * Make sure that our cached values reflect the current reality.
733ab4382d2SGreg Kroah-Hartman */
734ab4382d2SGreg Kroah-Hartman if (virt_carrier == 1)
735ab4382d2SGreg Kroah-Hartman ch->ch_flags |= CH_FCAR;
736ab4382d2SGreg Kroah-Hartman else
737ab4382d2SGreg Kroah-Hartman ch->ch_flags &= ~CH_FCAR;
738ab4382d2SGreg Kroah-Hartman
739ab4382d2SGreg Kroah-Hartman if (phys_carrier == 1)
740ab4382d2SGreg Kroah-Hartman ch->ch_flags |= CH_CD;
741ab4382d2SGreg Kroah-Hartman else
742ab4382d2SGreg Kroah-Hartman ch->ch_flags &= ~CH_CD;
743ab4382d2SGreg Kroah-Hartman }
744ab4382d2SGreg Kroah-Hartman
745ab4382d2SGreg Kroah-Hartman
jsm_check_queue_flow_control(struct jsm_channel * ch)746ab4382d2SGreg Kroah-Hartman void jsm_check_queue_flow_control(struct jsm_channel *ch)
747ab4382d2SGreg Kroah-Hartman {
748ab4382d2SGreg Kroah-Hartman struct board_ops *bd_ops = ch->ch_bd->bd_ops;
749ab4382d2SGreg Kroah-Hartman int qleft;
750ab4382d2SGreg Kroah-Hartman
751ab4382d2SGreg Kroah-Hartman /* Store how much space we have left in the queue */
752b0db9263SAlexander Vorwerk qleft = ch->ch_r_tail - ch->ch_r_head - 1;
753b0db9263SAlexander Vorwerk if (qleft < 0)
754ab4382d2SGreg Kroah-Hartman qleft += RQUEUEMASK + 1;
755ab4382d2SGreg Kroah-Hartman
756ab4382d2SGreg Kroah-Hartman /*
757ab4382d2SGreg Kroah-Hartman * Check to see if we should enforce flow control on our queue because
758ab4382d2SGreg Kroah-Hartman * the ld (or user) isn't reading data out of our queue fast enuf.
759ab4382d2SGreg Kroah-Hartman *
760ab4382d2SGreg Kroah-Hartman * NOTE: This is done based on what the current flow control of the
761ab4382d2SGreg Kroah-Hartman * port is set for.
762ab4382d2SGreg Kroah-Hartman *
763ab4382d2SGreg Kroah-Hartman * 1) HWFLOW (RTS) - Turn off the UART's Receive interrupt.
764ab4382d2SGreg Kroah-Hartman * This will cause the UART's FIFO to back up, and force
765ab4382d2SGreg Kroah-Hartman * the RTS signal to be dropped.
766ab4382d2SGreg Kroah-Hartman * 2) SWFLOW (IXOFF) - Keep trying to send a stop character to
767ab4382d2SGreg Kroah-Hartman * the other side, in hopes it will stop sending data to us.
768ab4382d2SGreg Kroah-Hartman * 3) NONE - Nothing we can do. We will simply drop any extra data
769ab4382d2SGreg Kroah-Hartman * that gets sent into us when the queue fills up.
770ab4382d2SGreg Kroah-Hartman */
771ab4382d2SGreg Kroah-Hartman if (qleft < 256) {
772ab4382d2SGreg Kroah-Hartman /* HWFLOW */
773ab4382d2SGreg Kroah-Hartman if (ch->ch_c_cflag & CRTSCTS) {
774ab4382d2SGreg Kroah-Hartman if (!(ch->ch_flags & CH_RECEIVER_OFF)) {
775ab4382d2SGreg Kroah-Hartman bd_ops->disable_receiver(ch);
776ab4382d2SGreg Kroah-Hartman ch->ch_flags |= (CH_RECEIVER_OFF);
777669fef46SJoe Perches jsm_dbg(READ, &ch->ch_bd->pci_dev,
778669fef46SJoe Perches "Internal queue hit hilevel mark (%d)! Turning off interrupts\n",
779ab4382d2SGreg Kroah-Hartman qleft);
780ab4382d2SGreg Kroah-Hartman }
781ab4382d2SGreg Kroah-Hartman }
782ab4382d2SGreg Kroah-Hartman /* SWFLOW */
783ab4382d2SGreg Kroah-Hartman else if (ch->ch_c_iflag & IXOFF) {
784ab4382d2SGreg Kroah-Hartman if (ch->ch_stops_sent <= MAX_STOPS_SENT) {
785ab4382d2SGreg Kroah-Hartman bd_ops->send_stop_character(ch);
786ab4382d2SGreg Kroah-Hartman ch->ch_stops_sent++;
787669fef46SJoe Perches jsm_dbg(READ, &ch->ch_bd->pci_dev,
788669fef46SJoe Perches "Sending stop char! Times sent: %x\n",
789669fef46SJoe Perches ch->ch_stops_sent);
790ab4382d2SGreg Kroah-Hartman }
791ab4382d2SGreg Kroah-Hartman }
792ab4382d2SGreg Kroah-Hartman }
793ab4382d2SGreg Kroah-Hartman
794ab4382d2SGreg Kroah-Hartman /*
795ab4382d2SGreg Kroah-Hartman * Check to see if we should unenforce flow control because
796ab4382d2SGreg Kroah-Hartman * ld (or user) finally read enuf data out of our queue.
797ab4382d2SGreg Kroah-Hartman *
798ab4382d2SGreg Kroah-Hartman * NOTE: This is done based on what the current flow control of the
799ab4382d2SGreg Kroah-Hartman * port is set for.
800ab4382d2SGreg Kroah-Hartman *
801ab4382d2SGreg Kroah-Hartman * 1) HWFLOW (RTS) - Turn back on the UART's Receive interrupt.
802ab4382d2SGreg Kroah-Hartman * This will cause the UART's FIFO to raise RTS back up,
803ab4382d2SGreg Kroah-Hartman * which will allow the other side to start sending data again.
804ab4382d2SGreg Kroah-Hartman * 2) SWFLOW (IXOFF) - Send a start character to
805ab4382d2SGreg Kroah-Hartman * the other side, so it will start sending data to us again.
806ab4382d2SGreg Kroah-Hartman * 3) NONE - Do nothing. Since we didn't do anything to turn off the
807ab4382d2SGreg Kroah-Hartman * other side, we don't need to do anything now.
808ab4382d2SGreg Kroah-Hartman */
809ab4382d2SGreg Kroah-Hartman if (qleft > (RQUEUESIZE / 2)) {
810ab4382d2SGreg Kroah-Hartman /* HWFLOW */
811ab4382d2SGreg Kroah-Hartman if (ch->ch_c_cflag & CRTSCTS) {
812ab4382d2SGreg Kroah-Hartman if (ch->ch_flags & CH_RECEIVER_OFF) {
813ab4382d2SGreg Kroah-Hartman bd_ops->enable_receiver(ch);
814ab4382d2SGreg Kroah-Hartman ch->ch_flags &= ~(CH_RECEIVER_OFF);
815669fef46SJoe Perches jsm_dbg(READ, &ch->ch_bd->pci_dev,
816669fef46SJoe Perches "Internal queue hit lowlevel mark (%d)! Turning on interrupts\n",
817ab4382d2SGreg Kroah-Hartman qleft);
818ab4382d2SGreg Kroah-Hartman }
819ab4382d2SGreg Kroah-Hartman }
820ab4382d2SGreg Kroah-Hartman /* SWFLOW */
821ab4382d2SGreg Kroah-Hartman else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) {
822ab4382d2SGreg Kroah-Hartman ch->ch_stops_sent = 0;
823ab4382d2SGreg Kroah-Hartman bd_ops->send_start_character(ch);
824669fef46SJoe Perches jsm_dbg(READ, &ch->ch_bd->pci_dev,
825669fef46SJoe Perches "Sending start char!\n");
826ab4382d2SGreg Kroah-Hartman }
827ab4382d2SGreg Kroah-Hartman }
828ab4382d2SGreg Kroah-Hartman }
829