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