blob: aedca66cbe4110b81766897e9d45c84abd022d5d [file] [log] [blame]
Lidza Louina0b99d582013-08-01 17:00:20 -04001/*
2 * Copyright 2003 Digi International (www.digi.com)
3 * Scott H Kilau <Scott_Kilau at digi dot com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
Lidza Louina5ca46fd2013-08-21 11:08:00 -04009 *
Lidza Louina0b99d582013-08-01 17:00:20 -040010 * This program is distributed in the hope that it will be useful,
Lidza Louina5ca46fd2013-08-21 11:08:00 -040011 * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
12 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
Lidza Louina0b99d582013-08-01 17:00:20 -040013 * PURPOSE. See the GNU General Public License for more details.
Lidza Louina0b99d582013-08-01 17:00:20 -040014 */
15
16#include <linux/kernel.h>
Lidza Louina0b99d582013-08-01 17:00:20 -040017#include <linux/sched.h> /* For jiffies, task states */
18#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */
19#include <linux/delay.h> /* For udelay */
Archana kumari4a75ffa2013-10-16 08:08:54 +053020#include <linux/io.h> /* For read[bwl]/write[bwl] */
Lidza Louina0b99d582013-08-01 17:00:20 -040021#include <linux/serial.h> /* For struct async_serial */
22#include <linux/serial_reg.h> /* For the various UART offsets */
23#include <linux/pci.h>
24
25#include "dgnc_driver.h" /* Driver main header file */
26#include "dgnc_cls.h"
27#include "dgnc_tty.h"
Lidza Louina0b99d582013-08-01 17:00:20 -040028
Lidza Louina0b99d582013-08-01 17:00:20 -040029static inline void cls_set_cts_flow_control(struct channel_t *ch)
30{
Ebru Akagunduz446393e2014-10-01 23:04:48 +030031 unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
32 unsigned char ier = readb(&ch->ch_cls_uart->ier);
33 unsigned char isr_fcr = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -040034
Lidza Louina0b99d582013-08-01 17:00:20 -040035 /*
36 * The Enhanced Register Set may only be accessed when
37 * the Line Control Register is set to 0xBFh.
38 */
39 writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
40
41 isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
Lidza Louina5ca46fd2013-08-21 11:08:00 -040042
Lidza Louina0b99d582013-08-01 17:00:20 -040043 /* Turn on CTS flow control, turn off IXON flow control */
44 isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_CTSDSR);
45 isr_fcr &= ~(UART_EXAR654_EFR_IXON);
46
47 writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
48
49 /* Write old LCR value back out, which turns enhanced access off */
50 writeb(lcrb, &ch->ch_cls_uart->lcr);
51
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +053052 /*
53 * Enable interrupts for CTS flow, turn off interrupts for
54 * received XOFF chars
55 */
Lidza Louina0b99d582013-08-01 17:00:20 -040056 ier |= (UART_EXAR654_IER_CTSDSR);
57 ier &= ~(UART_EXAR654_IER_XOFF);
58 writeb(ier, &ch->ch_cls_uart->ier);
59
60 /* Set the usual FIFO values */
61 writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
62
63 writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 |
64 UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
65 &ch->ch_cls_uart->isr_fcr);
66
67 ch->ch_t_tlevel = 16;
Lidza Louina0b99d582013-08-01 17:00:20 -040068}
69
Lidza Louina0b99d582013-08-01 17:00:20 -040070static inline void cls_set_ixon_flow_control(struct channel_t *ch)
71{
Ebru Akagunduz446393e2014-10-01 23:04:48 +030072 unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
73 unsigned char ier = readb(&ch->ch_cls_uart->ier);
74 unsigned char isr_fcr = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -040075
Lidza Louina0b99d582013-08-01 17:00:20 -040076 /*
77 * The Enhanced Register Set may only be accessed when
78 * the Line Control Register is set to 0xBFh.
79 */
80 writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
81
82 isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
Lidza Louina5ca46fd2013-08-21 11:08:00 -040083
Lidza Louina0b99d582013-08-01 17:00:20 -040084 /* Turn on IXON flow control, turn off CTS flow control */
85 isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXON);
86 isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR);
87
88 writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
89
90 /* Now set our current start/stop chars while in enhanced mode */
91 writeb(ch->ch_startc, &ch->ch_cls_uart->mcr);
92 writeb(0, &ch->ch_cls_uart->lsr);
93 writeb(ch->ch_stopc, &ch->ch_cls_uart->msr);
94 writeb(0, &ch->ch_cls_uart->spr);
95
96 /* Write old LCR value back out, which turns enhanced access off */
97 writeb(lcrb, &ch->ch_cls_uart->lcr);
98
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +053099 /*
100 * Disable interrupts for CTS flow, turn on interrupts for
101 * received XOFF chars
102 */
Lidza Louina0b99d582013-08-01 17:00:20 -0400103 ier &= ~(UART_EXAR654_IER_CTSDSR);
104 ier |= (UART_EXAR654_IER_XOFF);
105 writeb(ier, &ch->ch_cls_uart->ier);
106
107 /* Set the usual FIFO values */
108 writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
109
110 writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
111 UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
112 &ch->ch_cls_uart->isr_fcr);
Lidza Louina0b99d582013-08-01 17:00:20 -0400113}
114
Lidza Louina0b99d582013-08-01 17:00:20 -0400115static inline void cls_set_no_output_flow_control(struct channel_t *ch)
116{
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300117 unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
118 unsigned char ier = readb(&ch->ch_cls_uart->ier);
119 unsigned char isr_fcr = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -0400120
Lidza Louina0b99d582013-08-01 17:00:20 -0400121 /*
122 * The Enhanced Register Set may only be accessed when
123 * the Line Control Register is set to 0xBFh.
124 */
125 writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
126
127 isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400128
Lidza Louina0b99d582013-08-01 17:00:20 -0400129 /* Turn off IXON flow control, turn off CTS flow control */
130 isr_fcr |= (UART_EXAR654_EFR_ECB);
131 isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR | UART_EXAR654_EFR_IXON);
132
133 writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
134
135 /* Write old LCR value back out, which turns enhanced access off */
136 writeb(lcrb, &ch->ch_cls_uart->lcr);
137
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530138 /*
139 * Disable interrupts for CTS flow, turn off interrupts for
140 * received XOFF chars
141 */
Lidza Louina0b99d582013-08-01 17:00:20 -0400142 ier &= ~(UART_EXAR654_IER_CTSDSR);
143 ier &= ~(UART_EXAR654_IER_XOFF);
144 writeb(ier, &ch->ch_cls_uart->ier);
145
146 /* Set the usual FIFO values */
147 writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
148
149 writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
150 UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
151 &ch->ch_cls_uart->isr_fcr);
152
153 ch->ch_r_watermark = 0;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530154 ch->ch_t_tlevel = 16;
155 ch->ch_r_tlevel = 16;
Lidza Louina0b99d582013-08-01 17:00:20 -0400156}
157
Lidza Louina0b99d582013-08-01 17:00:20 -0400158static inline void cls_set_rts_flow_control(struct channel_t *ch)
159{
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300160 unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
161 unsigned char ier = readb(&ch->ch_cls_uart->ier);
162 unsigned char isr_fcr = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -0400163
Lidza Louina0b99d582013-08-01 17:00:20 -0400164 /*
165 * The Enhanced Register Set may only be accessed when
166 * the Line Control Register is set to 0xBFh.
167 */
168 writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
169
170 isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400171
Lidza Louina0b99d582013-08-01 17:00:20 -0400172 /* Turn on RTS flow control, turn off IXOFF flow control */
173 isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_RTSDTR);
174 isr_fcr &= ~(UART_EXAR654_EFR_IXOFF);
175
176 writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
177
178 /* Write old LCR value back out, which turns enhanced access off */
179 writeb(lcrb, &ch->ch_cls_uart->lcr);
180
181 /* Enable interrupts for RTS flow */
182 ier |= (UART_EXAR654_IER_RTSDTR);
183 writeb(ier, &ch->ch_cls_uart->ier);
184
185 /* Set the usual FIFO values */
186 writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
187
188 writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 |
189 UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
190 &ch->ch_cls_uart->isr_fcr);
191
Lidza Louina0b99d582013-08-01 17:00:20 -0400192 ch->ch_r_watermark = 4;
193 ch->ch_r_tlevel = 8;
Lidza Louina0b99d582013-08-01 17:00:20 -0400194}
195
Lidza Louina0b99d582013-08-01 17:00:20 -0400196static inline void cls_set_ixoff_flow_control(struct channel_t *ch)
197{
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300198 unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
199 unsigned char ier = readb(&ch->ch_cls_uart->ier);
200 unsigned char isr_fcr = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -0400201
Lidza Louina0b99d582013-08-01 17:00:20 -0400202 /*
203 * The Enhanced Register Set may only be accessed when
204 * the Line Control Register is set to 0xBFh.
205 */
206 writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
207
208 isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400209
Lidza Louina0b99d582013-08-01 17:00:20 -0400210 /* Turn on IXOFF flow control, turn off RTS flow control */
211 isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXOFF);
212 isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR);
213
214 writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
215
216 /* Now set our current start/stop chars while in enhanced mode */
217 writeb(ch->ch_startc, &ch->ch_cls_uart->mcr);
218 writeb(0, &ch->ch_cls_uart->lsr);
219 writeb(ch->ch_stopc, &ch->ch_cls_uart->msr);
220 writeb(0, &ch->ch_cls_uart->spr);
221
222 /* Write old LCR value back out, which turns enhanced access off */
223 writeb(lcrb, &ch->ch_cls_uart->lcr);
224
225 /* Disable interrupts for RTS flow */
226 ier &= ~(UART_EXAR654_IER_RTSDTR);
227 writeb(ier, &ch->ch_cls_uart->ier);
228
229 /* Set the usual FIFO values */
230 writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
231
232 writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
233 UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
234 &ch->ch_cls_uart->isr_fcr);
Lidza Louina0b99d582013-08-01 17:00:20 -0400235}
236
Lidza Louina0b99d582013-08-01 17:00:20 -0400237static inline void cls_set_no_input_flow_control(struct channel_t *ch)
238{
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300239 unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
240 unsigned char ier = readb(&ch->ch_cls_uart->ier);
241 unsigned char isr_fcr = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -0400242
Lidza Louina0b99d582013-08-01 17:00:20 -0400243 /*
244 * The Enhanced Register Set may only be accessed when
245 * the Line Control Register is set to 0xBFh.
246 */
247 writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
248
249 isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400250
Lidza Louina0b99d582013-08-01 17:00:20 -0400251 /* Turn off IXOFF flow control, turn off RTS flow control */
252 isr_fcr |= (UART_EXAR654_EFR_ECB);
253 isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR | UART_EXAR654_EFR_IXOFF);
254
255 writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
256
257 /* Write old LCR value back out, which turns enhanced access off */
258 writeb(lcrb, &ch->ch_cls_uart->lcr);
259
260 /* Disable interrupts for RTS flow */
261 ier &= ~(UART_EXAR654_IER_RTSDTR);
262 writeb(ier, &ch->ch_cls_uart->ier);
263
264 /* Set the usual FIFO values */
265 writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
266
267 writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
268 UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
269 &ch->ch_cls_uart->isr_fcr);
270
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530271 ch->ch_t_tlevel = 16;
272 ch->ch_r_tlevel = 16;
Lidza Louina0b99d582013-08-01 17:00:20 -0400273}
274
Lidza Louina0b99d582013-08-01 17:00:20 -0400275/*
276 * cls_clear_break.
277 * Determines whether its time to shut off break condition.
278 *
279 * No locks are assumed to be held when calling this function.
280 * channel lock is held and released in this function.
281 */
282static inline void cls_clear_break(struct channel_t *ch, int force)
283{
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300284 unsigned long flags;
Lidza Louina0b99d582013-08-01 17:00:20 -0400285
286 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
287 return;
288
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300289 spin_lock_irqsave(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400290
291 /* Bail if we aren't currently sending a break. */
292 if (!ch->ch_stop_sending_break) {
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300293 spin_unlock_irqrestore(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400294 return;
295 }
296
297 /* Turn break off, and unset some variables */
298 if (ch->ch_flags & CH_BREAK_SENDING) {
stalinsrinivasan.sf0dcc9f2013-12-20 22:03:27 +0530299 if (time_after(jiffies, ch->ch_stop_sending_break) || force) {
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300300 unsigned char temp = readb(&ch->ch_cls_uart->lcr);
Konrad Zapalowicz8aa5d0d2014-08-06 22:17:09 +0200301
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530302 writeb((temp & ~UART_LCR_SBC), &ch->ch_cls_uart->lcr);
Lidza Louina0b99d582013-08-01 17:00:20 -0400303 ch->ch_flags &= ~(CH_BREAK_SENDING);
304 ch->ch_stop_sending_break = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -0400305 }
306 }
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300307 spin_unlock_irqrestore(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400308}
309
Daeseok Youna2237a22016-07-06 15:14:37 +0900310static void cls_copy_data_from_uart_to_queue(struct channel_t *ch)
311{
312 int qleft = 0;
313 unsigned char linestatus = 0;
314 unsigned char error_mask = 0;
315 ushort head;
316 ushort tail;
317 unsigned long flags;
318
319 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
320 return;
321
322 spin_lock_irqsave(&ch->ch_lock, flags);
323
324 /* cache head and tail of queue */
325 head = ch->ch_r_head;
326 tail = ch->ch_r_tail;
327
328 /* Store how much space we have left in the queue */
329 qleft = tail - head - 1;
330 if (qleft < 0)
331 qleft += RQUEUEMASK + 1;
332
333 /*
334 * Create a mask to determine whether we should
335 * insert the character (if any) into our queue.
336 */
337 if (ch->ch_c_iflag & IGNBRK)
338 error_mask |= UART_LSR_BI;
339
340 while (1) {
341 linestatus = readb(&ch->ch_cls_uart->lsr);
342
343 if (!(linestatus & (UART_LSR_DR)))
344 break;
345
346 /*
347 * Discard character if we are ignoring the error mask.
Fernando Apesteguia8c524252016-09-25 19:20:31 +0200348 */
Daeseok Youna2237a22016-07-06 15:14:37 +0900349 if (linestatus & error_mask) {
350 linestatus = 0;
351 readb(&ch->ch_cls_uart->txrx);
352 continue;
353 }
354
355 /*
356 * If our queue is full, we have no choice but to drop some
357 * data. The assumption is that HWFLOW or SWFLOW should have
358 * stopped things way way before we got to this point.
359 *
360 * I decided that I wanted to ditch the oldest data first,
361 * I hope thats okay with everyone? Yes? Good.
362 */
363 while (qleft < 1) {
364 tail = (tail + 1) & RQUEUEMASK;
365 ch->ch_r_tail = tail;
366 ch->ch_err_overrun++;
367 qleft++;
368 }
369
370 ch->ch_equeue[head] = linestatus & (UART_LSR_BI | UART_LSR_PE
371 | UART_LSR_FE);
372 ch->ch_rqueue[head] = readb(&ch->ch_cls_uart->txrx);
373
374 qleft--;
375
376 if (ch->ch_equeue[head] & UART_LSR_PE)
377 ch->ch_err_parity++;
378 if (ch->ch_equeue[head] & UART_LSR_BI)
379 ch->ch_err_break++;
380 if (ch->ch_equeue[head] & UART_LSR_FE)
381 ch->ch_err_frame++;
382
383 /* Add to, and flip head if needed */
384 head = (head + 1) & RQUEUEMASK;
385 ch->ch_rxcount++;
386 }
387
388 /*
389 * Write new final heads to channel structure.
390 */
391 ch->ch_r_head = head & RQUEUEMASK;
392 ch->ch_e_head = head & EQUEUEMASK;
393
394 spin_unlock_irqrestore(&ch->ch_lock, flags);
395}
396
397/* Make the UART raise any of the output signals we want up */
398static void cls_assert_modem_signals(struct channel_t *ch)
399{
400 unsigned char out;
401
402 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
403 return;
404
405 out = ch->ch_mostat;
406
407 if (ch->ch_flags & CH_LOOPBACK)
408 out |= UART_MCR_LOOP;
409
410 writeb(out, &ch->ch_cls_uart->mcr);
411
412 /* Give time for the UART to actually drop the signals */
413 udelay(10);
414}
415
416static void cls_copy_data_from_queue_to_uart(struct channel_t *ch)
417{
418 ushort head;
419 ushort tail;
420 int n;
421 int qlen;
422 uint len_written = 0;
423 unsigned long flags;
424
425 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
426 return;
427
428 spin_lock_irqsave(&ch->ch_lock, flags);
429
430 /* No data to write to the UART */
431 if (ch->ch_w_tail == ch->ch_w_head)
432 goto exit_unlock;
433
434 /* If port is "stopped", don't send any data to the UART */
435 if ((ch->ch_flags & CH_FORCED_STOP) ||
436 (ch->ch_flags & CH_BREAK_SENDING))
437 goto exit_unlock;
438
439 if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM)))
440 goto exit_unlock;
441
442 n = 32;
443
444 /* cache head and tail of queue */
445 head = ch->ch_w_head & WQUEUEMASK;
446 tail = ch->ch_w_tail & WQUEUEMASK;
447 qlen = (head - tail) & WQUEUEMASK;
448
449 /* Find minimum of the FIFO space, versus queue length */
450 n = min(n, qlen);
451
452 while (n > 0) {
453 /*
454 * If RTS Toggle mode is on, turn on RTS now if not already set,
455 * and make sure we get an event when the data transfer has
456 * completed.
457 */
458 if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) {
459 if (!(ch->ch_mostat & UART_MCR_RTS)) {
460 ch->ch_mostat |= (UART_MCR_RTS);
461 cls_assert_modem_signals(ch);
462 }
463 ch->ch_tun.un_flags |= (UN_EMPTY);
464 }
465
466 /*
467 * If DTR Toggle mode is on, turn on DTR now if not already set,
468 * and make sure we get an event when the data transfer has
469 * completed.
470 */
471 if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) {
472 if (!(ch->ch_mostat & UART_MCR_DTR)) {
473 ch->ch_mostat |= (UART_MCR_DTR);
474 cls_assert_modem_signals(ch);
475 }
476 ch->ch_tun.un_flags |= (UN_EMPTY);
477 }
478 writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_cls_uart->txrx);
479 ch->ch_w_tail++;
480 ch->ch_w_tail &= WQUEUEMASK;
481 ch->ch_txcount++;
482 len_written++;
483 n--;
484 }
485
486 if (len_written > 0)
487 ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
488
489exit_unlock:
490 spin_unlock_irqrestore(&ch->ch_lock, flags);
491}
492
493static void cls_parse_modem(struct channel_t *ch, unsigned char signals)
494{
495 unsigned char msignals = signals;
496 unsigned long flags;
497
498 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
499 return;
500
501 /*
502 * Do altpin switching. Altpin switches DCD and DSR.
503 * This prolly breaks DSRPACE, so we should be more clever here.
504 */
505 spin_lock_irqsave(&ch->ch_lock, flags);
506 if (ch->ch_digi.digi_flags & DIGI_ALTPIN) {
507 unsigned char mswap = signals;
508
509 if (mswap & UART_MSR_DDCD) {
510 msignals &= ~UART_MSR_DDCD;
511 msignals |= UART_MSR_DDSR;
512 }
513 if (mswap & UART_MSR_DDSR) {
514 msignals &= ~UART_MSR_DDSR;
515 msignals |= UART_MSR_DDCD;
516 }
517 if (mswap & UART_MSR_DCD) {
518 msignals &= ~UART_MSR_DCD;
519 msignals |= UART_MSR_DSR;
520 }
521 if (mswap & UART_MSR_DSR) {
522 msignals &= ~UART_MSR_DSR;
523 msignals |= UART_MSR_DCD;
524 }
525 }
526 spin_unlock_irqrestore(&ch->ch_lock, flags);
527
528 /*
529 * Scrub off lower bits. They signify delta's, which I don't
530 * care about
531 */
532 signals &= 0xf0;
533
534 spin_lock_irqsave(&ch->ch_lock, flags);
535 if (msignals & UART_MSR_DCD)
536 ch->ch_mistat |= UART_MSR_DCD;
537 else
538 ch->ch_mistat &= ~UART_MSR_DCD;
539
540 if (msignals & UART_MSR_DSR)
541 ch->ch_mistat |= UART_MSR_DSR;
542 else
543 ch->ch_mistat &= ~UART_MSR_DSR;
544
545 if (msignals & UART_MSR_RI)
546 ch->ch_mistat |= UART_MSR_RI;
547 else
548 ch->ch_mistat &= ~UART_MSR_RI;
549
550 if (msignals & UART_MSR_CTS)
551 ch->ch_mistat |= UART_MSR_CTS;
552 else
553 ch->ch_mistat &= ~UART_MSR_CTS;
554 spin_unlock_irqrestore(&ch->ch_lock, flags);
555}
556
Lidza Louina0b99d582013-08-01 17:00:20 -0400557/* Parse the ISR register for the specific port */
Lidza Louina03425f52013-09-09 15:01:22 -0400558static inline void cls_parse_isr(struct dgnc_board *brd, uint port)
Lidza Louina0b99d582013-08-01 17:00:20 -0400559{
560 struct channel_t *ch;
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300561 unsigned char isr = 0;
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300562 unsigned long flags;
Lidza Louina0b99d582013-08-01 17:00:20 -0400563
564 /*
565 * No need to verify board pointer, it was already
566 * verified in the interrupt routine.
567 */
568
Dan Carpenter4bef52f2015-03-12 20:24:31 +0300569 if (port >= brd->nasync)
Lidza Louina0b99d582013-08-01 17:00:20 -0400570 return;
571
572 ch = brd->channels[port];
Giedrius Statkevičius071494d2015-04-10 02:42:31 +0300573 if (ch->magic != DGNC_CHANNEL_MAGIC)
Lidza Louina0b99d582013-08-01 17:00:20 -0400574 return;
575
576 /* Here we try to figure out what caused the interrupt to happen */
577 while (1) {
Lidza Louina0b99d582013-08-01 17:00:20 -0400578 isr = readb(&ch->ch_cls_uart->isr_fcr);
579
580 /* Bail if no pending interrupt on port */
Archana kumari3d479102013-10-17 18:45:16 +0530581 if (isr & UART_IIR_NO_INT)
Lidza Louina0b99d582013-08-01 17:00:20 -0400582 break;
Lidza Louina0b99d582013-08-01 17:00:20 -0400583
Lidza Louina0b99d582013-08-01 17:00:20 -0400584 /* Receive Interrupt pending */
585 if (isr & (UART_IIR_RDI | UART_IIR_RDI_TIMEOUT)) {
586 /* Read data from uart -> queue */
Lidza Louina0b99d582013-08-01 17:00:20 -0400587 cls_copy_data_from_uart_to_queue(ch);
588 dgnc_check_queue_flow_control(ch);
589 }
590
591 /* Transmit Hold register empty pending */
592 if (isr & UART_IIR_THRI) {
593 /* Transfer data (if any) from Write Queue -> UART. */
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300594 spin_lock_irqsave(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400595 ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300596 spin_unlock_irqrestore(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400597 cls_copy_data_from_queue_to_uart(ch);
598 }
599
Lidza Louina0b99d582013-08-01 17:00:20 -0400600 /* Parse any modem signal changes */
Lidza Louina0b99d582013-08-01 17:00:20 -0400601 cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr));
602 }
603}
604
Daeseok Youna2237a22016-07-06 15:14:37 +0900605/* Channel lock MUST be held before calling this function! */
606static void cls_flush_uart_write(struct channel_t *ch)
607{
608 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
609 return;
610
611 writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT),
612 &ch->ch_cls_uart->isr_fcr);
613 usleep_range(10, 20);
614
615 ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
616}
617
618/* Channel lock MUST be held before calling this function! */
619static void cls_flush_uart_read(struct channel_t *ch)
620{
621 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
622 return;
623
624 /*
625 * For complete POSIX compatibility, we should be purging the
626 * read FIFO in the UART here.
627 *
628 * However, clearing the read FIFO (UART_FCR_CLEAR_RCVR) also
629 * incorrectly flushes write data as well as just basically trashing the
630 * FIFO.
631 *
632 * Presumably, this is a bug in this UART.
633 */
634
635 udelay(10);
636}
637
Lidza Louina0b99d582013-08-01 17:00:20 -0400638/*
639 * cls_param()
640 * Send any/all changes to the line to the UART.
641 */
642static void cls_param(struct tty_struct *tty)
643{
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300644 unsigned char lcr = 0;
645 unsigned char uart_lcr = 0;
646 unsigned char ier = 0;
647 unsigned char uart_ier = 0;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530648 uint baud = 9600;
Lidza Louina0b99d582013-08-01 17:00:20 -0400649 int quot = 0;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530650 struct dgnc_board *bd;
Lidza Louina0b99d582013-08-01 17:00:20 -0400651 struct channel_t *ch;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530652 struct un_t *un;
Lidza Louina0b99d582013-08-01 17:00:20 -0400653
Archana kumari3d479102013-10-17 18:45:16 +0530654 if (!tty || tty->magic != TTY_MAGIC)
Lidza Louina0b99d582013-08-01 17:00:20 -0400655 return;
Lidza Louina0b99d582013-08-01 17:00:20 -0400656
Sudip Mukherjee6f418252015-10-04 19:50:13 +0530657 un = (struct un_t *)tty->driver_data;
Archana kumari3d479102013-10-17 18:45:16 +0530658 if (!un || un->magic != DGNC_UNIT_MAGIC)
Lidza Louina0b99d582013-08-01 17:00:20 -0400659 return;
Lidza Louina0b99d582013-08-01 17:00:20 -0400660
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400661 ch = un->un_ch;
Archana kumari3d479102013-10-17 18:45:16 +0530662 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
Lidza Louina0b99d582013-08-01 17:00:20 -0400663 return;
Lidza Louina0b99d582013-08-01 17:00:20 -0400664
665 bd = ch->ch_bd;
Archana kumari3d479102013-10-17 18:45:16 +0530666 if (!bd || bd->magic != DGNC_BOARD_MAGIC)
Lidza Louina0b99d582013-08-01 17:00:20 -0400667 return;
Lidza Louina0b99d582013-08-01 17:00:20 -0400668
Lidza Louina0b99d582013-08-01 17:00:20 -0400669 /*
670 * If baud rate is zero, flush queues, and set mval to drop DTR.
671 */
672 if ((ch->ch_c_cflag & (CBAUD)) == 0) {
Seunghun Lee587abd72014-09-01 22:46:59 +0900673 ch->ch_r_head = 0;
674 ch->ch_r_tail = 0;
675 ch->ch_e_head = 0;
676 ch->ch_e_tail = 0;
677 ch->ch_w_head = 0;
678 ch->ch_w_tail = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -0400679
680 cls_flush_uart_write(ch);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530681 cls_flush_uart_read(ch);
Lidza Louina0b99d582013-08-01 17:00:20 -0400682
683 /* The baudrate is B0 so all modem lines are to be dropped. */
684 ch->ch_flags |= (CH_BAUD0);
685 ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
686 cls_assert_modem_signals(ch);
687 ch->ch_old_baud = 0;
688 return;
689 } else if (ch->ch_custom_speed) {
Lidza Louina0b99d582013-08-01 17:00:20 -0400690 baud = ch->ch_custom_speed;
691 /* Handle transition from B0 */
692 if (ch->ch_flags & CH_BAUD0) {
693 ch->ch_flags &= ~(CH_BAUD0);
694
695 /*
696 * Bring back up RTS and DTR...
697 * Also handle RTS or DTR toggle if set.
698 */
699 if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE))
700 ch->ch_mostat |= (UART_MCR_RTS);
701 if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE))
702 ch->ch_mostat |= (UART_MCR_DTR);
703 }
704
705 } else {
706 int iindex = 0;
707 int jindex = 0;
708
709 ulong bauds[4][16] = {
710 { /* slowbaud */
711 0, 50, 75, 110,
712 134, 150, 200, 300,
713 600, 1200, 1800, 2400,
714 4800, 9600, 19200, 38400 },
715 { /* slowbaud & CBAUDEX */
716 0, 57600, 115200, 230400,
717 460800, 150, 200, 921600,
718 600, 1200, 1800, 2400,
719 4800, 9600, 19200, 38400 },
720 { /* fastbaud */
721 0, 57600, 76800, 115200,
722 131657, 153600, 230400, 460800,
723 921600, 1200, 1800, 2400,
724 4800, 9600, 19200, 38400 },
725 { /* fastbaud & CBAUDEX */
726 0, 57600, 115200, 230400,
727 460800, 150, 200, 921600,
728 600, 1200, 1800, 2400,
729 4800, 9600, 19200, 38400 }
730 };
731
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530732 /*
733 * Only use the TXPrint baud rate if the terminal
734 * unit is NOT open
735 */
736 if (!(ch->ch_tun.un_flags & UN_ISOPEN) &&
Sudip Mukherjeee352d3f2015-10-04 19:50:14 +0530737 (un->un_type == DGNC_PRINT))
Lidza Louina0b99d582013-08-01 17:00:20 -0400738 baud = C_BAUD(ch->ch_pun.un_tty) & 0xff;
739 else
740 baud = C_BAUD(ch->ch_tun.un_tty) & 0xff;
741
742 if (ch->ch_c_cflag & CBAUDEX)
743 iindex = 1;
744
745 if (ch->ch_digi.digi_flags & DIGI_FAST)
746 iindex += 2;
747
748 jindex = baud;
749
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530750 if ((iindex >= 0) && (iindex < 4) && (jindex >= 0) &&
Sudip Mukherjeee352d3f2015-10-04 19:50:14 +0530751 (jindex < 16)) {
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400752 baud = bauds[iindex][jindex];
Lidza Louina0b99d582013-08-01 17:00:20 -0400753 } else {
Lidza Louina0b99d582013-08-01 17:00:20 -0400754 baud = 0;
755 }
756
757 if (baud == 0)
758 baud = 9600;
759
760 /* Handle transition from B0 */
761 if (ch->ch_flags & CH_BAUD0) {
762 ch->ch_flags &= ~(CH_BAUD0);
763
764 /*
765 * Bring back up RTS and DTR...
766 * Also handle RTS or DTR toggle if set.
767 */
768 if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE))
769 ch->ch_mostat |= (UART_MCR_RTS);
770 if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE))
771 ch->ch_mostat |= (UART_MCR_DTR);
772 }
773 }
774
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530775 if (ch->ch_c_cflag & PARENB)
Lidza Louina0b99d582013-08-01 17:00:20 -0400776 lcr |= UART_LCR_PARITY;
Lidza Louina0b99d582013-08-01 17:00:20 -0400777
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530778 if (!(ch->ch_c_cflag & PARODD))
Lidza Louina0b99d582013-08-01 17:00:20 -0400779 lcr |= UART_LCR_EPAR;
Lidza Louina0b99d582013-08-01 17:00:20 -0400780
781 /*
782 * Not all platforms support mark/space parity,
783 * so this will hide behind an ifdef.
784 */
785#ifdef CMSPAR
786 if (ch->ch_c_cflag & CMSPAR)
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400787 lcr |= UART_LCR_SPAR;
Lidza Louina0b99d582013-08-01 17:00:20 -0400788#endif
789
790 if (ch->ch_c_cflag & CSTOPB)
791 lcr |= UART_LCR_STOP;
792
793 switch (ch->ch_c_cflag & CSIZE) {
794 case CS5:
795 lcr |= UART_LCR_WLEN5;
796 break;
797 case CS6:
798 lcr |= UART_LCR_WLEN6;
799 break;
800 case CS7:
801 lcr |= UART_LCR_WLEN7;
802 break;
803 case CS8:
804 default:
805 lcr |= UART_LCR_WLEN8;
806 break;
807 }
808
Seunghun Lee587abd72014-09-01 22:46:59 +0900809 uart_ier = readb(&ch->ch_cls_uart->ier);
810 ier = uart_ier;
Lidza Louina0b99d582013-08-01 17:00:20 -0400811 uart_lcr = readb(&ch->ch_cls_uart->lcr);
812
813 if (baud == 0)
814 baud = 9600;
815
816 quot = ch->ch_bd->bd_dividend / baud;
817
818 if (quot != 0 && ch->ch_old_baud != baud) {
819 ch->ch_old_baud = baud;
820 writeb(UART_LCR_DLAB, &ch->ch_cls_uart->lcr);
821 writeb((quot & 0xff), &ch->ch_cls_uart->txrx);
822 writeb((quot >> 8), &ch->ch_cls_uart->ier);
823 writeb(lcr, &ch->ch_cls_uart->lcr);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530824 }
Lidza Louina0b99d582013-08-01 17:00:20 -0400825
826 if (uart_lcr != lcr)
827 writeb(lcr, &ch->ch_cls_uart->lcr);
828
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530829 if (ch->ch_c_cflag & CREAD)
Lidza Louina0b99d582013-08-01 17:00:20 -0400830 ier |= (UART_IER_RDI | UART_IER_RLSI);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530831 else
Lidza Louina0b99d582013-08-01 17:00:20 -0400832 ier &= ~(UART_IER_RDI | UART_IER_RLSI);
Lidza Louina0b99d582013-08-01 17:00:20 -0400833
834 /*
835 * Have the UART interrupt on modem signal changes ONLY when
836 * we are in hardware flow control mode, or CLOCAL/FORCEDCD is not set.
837 */
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530838 if ((ch->ch_digi.digi_flags & CTSPACE) ||
Cristina Moraruc76d2942015-10-01 21:43:57 +0300839 (ch->ch_digi.digi_flags & RTSPACE) ||
840 (ch->ch_c_cflag & CRTSCTS) ||
841 !(ch->ch_digi.digi_flags & DIGI_FORCEDCD) ||
842 !(ch->ch_c_cflag & CLOCAL))
843 ier |= UART_IER_MSI;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530844 else
Cristina Moraruc76d2942015-10-01 21:43:57 +0300845 ier &= ~UART_IER_MSI;
Lidza Louina0b99d582013-08-01 17:00:20 -0400846
847 ier |= UART_IER_THRI;
848
849 if (ier != uart_ier)
850 writeb(ier, &ch->ch_cls_uart->ier);
851
852 if (ch->ch_digi.digi_flags & CTSPACE || ch->ch_c_cflag & CRTSCTS) {
853 cls_set_cts_flow_control(ch);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530854 } else if (ch->ch_c_iflag & IXON) {
855 /*
856 * If start/stop is set to disable, then we should
857 * disable flow control
858 */
859 if ((ch->ch_startc == _POSIX_VDISABLE) ||
Sudip Mukherjeee352d3f2015-10-04 19:50:14 +0530860 (ch->ch_stopc == _POSIX_VDISABLE))
Lidza Louina0b99d582013-08-01 17:00:20 -0400861 cls_set_no_output_flow_control(ch);
862 else
863 cls_set_ixon_flow_control(ch);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530864 } else {
Lidza Louina0b99d582013-08-01 17:00:20 -0400865 cls_set_no_output_flow_control(ch);
866 }
867
868 if (ch->ch_digi.digi_flags & RTSPACE || ch->ch_c_cflag & CRTSCTS) {
869 cls_set_rts_flow_control(ch);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530870 } else if (ch->ch_c_iflag & IXOFF) {
871 /*
872 * If start/stop is set to disable, then we should disable
873 * flow control
874 */
875 if ((ch->ch_startc == _POSIX_VDISABLE) ||
Sudip Mukherjeee352d3f2015-10-04 19:50:14 +0530876 (ch->ch_stopc == _POSIX_VDISABLE))
Lidza Louina0b99d582013-08-01 17:00:20 -0400877 cls_set_no_input_flow_control(ch);
878 else
879 cls_set_ixoff_flow_control(ch);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530880 } else {
Lidza Louina0b99d582013-08-01 17:00:20 -0400881 cls_set_no_input_flow_control(ch);
882 }
883
884 cls_assert_modem_signals(ch);
885
886 /* Get current status of the modem signals now */
887 cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr));
888}
889
Lidza Louina0b99d582013-08-01 17:00:20 -0400890/*
891 * Our board poller function.
892 */
893static void cls_tasklet(unsigned long data)
894{
Sudip Mukherjee6f418252015-10-04 19:50:13 +0530895 struct dgnc_board *bd = (struct dgnc_board *)data;
Lidza Louina0b99d582013-08-01 17:00:20 -0400896 struct channel_t *ch;
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300897 unsigned long flags;
Lidza Louina0b99d582013-08-01 17:00:20 -0400898 int i;
899 int state = 0;
900 int ports = 0;
901
Roberta Dobrescu1f26adc2014-10-07 13:08:12 +0300902 if (!bd || bd->magic != DGNC_BOARD_MAGIC)
Lidza Louina0b99d582013-08-01 17:00:20 -0400903 return;
Lidza Louina0b99d582013-08-01 17:00:20 -0400904
905 /* Cache a couple board values */
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300906 spin_lock_irqsave(&bd->bd_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400907 state = bd->state;
908 ports = bd->nasync;
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300909 spin_unlock_irqrestore(&bd->bd_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400910
911 /*
912 * Do NOT allow the interrupt routine to read the intr registers
913 * Until we release this lock.
914 */
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300915 spin_lock_irqsave(&bd->bd_intr_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400916
917 /*
918 * If board is ready, parse deeper to see if there is anything to do.
919 */
920 if ((state == BOARD_READY) && (ports > 0)) {
Lidza Louina0b99d582013-08-01 17:00:20 -0400921 /* Loop on each port */
922 for (i = 0; i < ports; i++) {
923 ch = bd->channels[i];
Lidza Louina0b99d582013-08-01 17:00:20 -0400924
925 /*
926 * NOTE: Remember you CANNOT hold any channel
927 * locks when calling input.
928 * During input processing, its possible we
929 * will call ld, which might do callbacks back
930 * into us.
931 */
932 dgnc_input(ch);
933
934 /*
935 * Channel lock is grabbed and then released
936 * inside this routine.
937 */
938 cls_copy_data_from_queue_to_uart(ch);
939 dgnc_wakeup_writes(ch);
940
941 /*
942 * Check carrier function.
943 */
944 dgnc_carrier(ch);
945
946 /*
947 * The timing check of turning off the break is done
948 * inside clear_break()
949 */
950 if (ch->ch_stop_sending_break)
951 cls_clear_break(ch, 0);
952 }
953 }
954
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300955 spin_unlock_irqrestore(&bd->bd_intr_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400956}
957
Lidza Louina0b99d582013-08-01 17:00:20 -0400958/*
959 * cls_intr()
960 *
961 * Classic specific interrupt handler.
962 */
963static irqreturn_t cls_intr(int irq, void *voidbrd)
964{
Tapasweni Pathakfc33bd22014-10-30 17:02:04 +0530965 struct dgnc_board *brd = voidbrd;
Lidza Louina0b99d582013-08-01 17:00:20 -0400966 uint i = 0;
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300967 unsigned char poll_reg;
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300968 unsigned long flags;
Lidza Louina0b99d582013-08-01 17:00:20 -0400969
Lidza Louina0b99d582013-08-01 17:00:20 -0400970 /*
Roberta Dobrescu1f26adc2014-10-07 13:08:12 +0300971 * Check to make sure it didn't receive interrupt with a null board
972 * associated or a board pointer that wasn't ours.
Lidza Louina0b99d582013-08-01 17:00:20 -0400973 */
Roberta Dobrescu1f26adc2014-10-07 13:08:12 +0300974 if (!brd || brd->magic != DGNC_BOARD_MAGIC)
Lidza Louina0b99d582013-08-01 17:00:20 -0400975 return IRQ_NONE;
Lidza Louina0b99d582013-08-01 17:00:20 -0400976
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300977 spin_lock_irqsave(&brd->bd_intr_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400978
Lidza Louina0b99d582013-08-01 17:00:20 -0400979 /*
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400980 * Check the board's global interrupt offset to see if we
Lidza Louina0b99d582013-08-01 17:00:20 -0400981 * we actually do have an interrupt pending for us.
982 */
983 poll_reg = readb(brd->re_map_membase + UART_CLASSIC_POLL_ADDR_OFFSET);
984
985 /* If 0, no interrupts pending */
986 if (!poll_reg) {
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300987 spin_unlock_irqrestore(&brd->bd_intr_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400988 return IRQ_NONE;
989 }
990
Lidza Louina0b99d582013-08-01 17:00:20 -0400991 /* Parse each port to find out what caused the interrupt */
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530992 for (i = 0; i < brd->nasync; i++)
Lidza Louina0b99d582013-08-01 17:00:20 -0400993 cls_parse_isr(brd, i);
Lidza Louina0b99d582013-08-01 17:00:20 -0400994
995 /*
996 * Schedule tasklet to more in-depth servicing at a better time.
997 */
998 tasklet_schedule(&brd->helper_tasklet);
999
Roberta Dobrescu707505b2014-09-23 01:55:55 +03001000 spin_unlock_irqrestore(&brd->bd_intr_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -04001001
Lidza Louina0b99d582013-08-01 17:00:20 -04001002 return IRQ_HANDLED;
1003}
1004
Lidza Louina0b99d582013-08-01 17:00:20 -04001005static void cls_disable_receiver(struct channel_t *ch)
1006{
Ebru Akagunduz446393e2014-10-01 23:04:48 +03001007 unsigned char tmp = readb(&ch->ch_cls_uart->ier);
Konrad Zapalowicz8aa5d0d2014-08-06 22:17:09 +02001008
Lidza Louina0b99d582013-08-01 17:00:20 -04001009 tmp &= ~(UART_IER_RDI);
1010 writeb(tmp, &ch->ch_cls_uart->ier);
1011}
1012
Lidza Louina0b99d582013-08-01 17:00:20 -04001013static void cls_enable_receiver(struct channel_t *ch)
1014{
Ebru Akagunduz446393e2014-10-01 23:04:48 +03001015 unsigned char tmp = readb(&ch->ch_cls_uart->ier);
Konrad Zapalowicz8aa5d0d2014-08-06 22:17:09 +02001016
Lidza Louina0b99d582013-08-01 17:00:20 -04001017 tmp |= (UART_IER_RDI);
1018 writeb(tmp, &ch->ch_cls_uart->ier);
1019}
1020
Lidza Louina0b99d582013-08-01 17:00:20 -04001021/*
1022 * This function basically goes to sleep for secs, or until
1023 * it gets signalled that the port has fully drained.
1024 */
1025static int cls_drain(struct tty_struct *tty, uint seconds)
1026{
Roberta Dobrescu707505b2014-09-23 01:55:55 +03001027 unsigned long flags;
Lidza Louina0b99d582013-08-01 17:00:20 -04001028 struct channel_t *ch;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301029 struct un_t *un;
Lidza Louina0b99d582013-08-01 17:00:20 -04001030
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301031 if (!tty || tty->magic != TTY_MAGIC)
Lidza Louina8f90ef82013-09-09 15:01:23 -04001032 return -ENXIO;
Lidza Louina0b99d582013-08-01 17:00:20 -04001033
Sudip Mukherjee6f418252015-10-04 19:50:13 +05301034 un = (struct un_t *)tty->driver_data;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301035 if (!un || un->magic != DGNC_UNIT_MAGIC)
Lidza Louina8f90ef82013-09-09 15:01:23 -04001036 return -ENXIO;
Lidza Louina0b99d582013-08-01 17:00:20 -04001037
Lidza Louina5ca46fd2013-08-21 11:08:00 -04001038 ch = un->un_ch;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301039 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
Lidza Louina8f90ef82013-09-09 15:01:23 -04001040 return -ENXIO;
Lidza Louina0b99d582013-08-01 17:00:20 -04001041
Roberta Dobrescu707505b2014-09-23 01:55:55 +03001042 spin_lock_irqsave(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -04001043 un->un_flags |= UN_EMPTY;
Roberta Dobrescu707505b2014-09-23 01:55:55 +03001044 spin_unlock_irqrestore(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -04001045
1046 /*
1047 * NOTE: Do something with time passed in.
1048 */
Lidza Louina0b99d582013-08-01 17:00:20 -04001049
1050 /* If ret is non-zero, user ctrl-c'ed us */
Lidza Louina0b99d582013-08-01 17:00:20 -04001051
Heena Sirwanica5dd0b2014-10-06 10:19:09 +05301052 return wait_event_interruptible(un->un_flags_wait,
1053 ((un->un_flags & UN_EMPTY) == 0));
Lidza Louina0b99d582013-08-01 17:00:20 -04001054}
Lidza Louina5ca46fd2013-08-21 11:08:00 -04001055
Lidza Louina0b99d582013-08-01 17:00:20 -04001056static void cls_send_start_character(struct channel_t *ch)
1057{
1058 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
1059 return;
1060
1061 if (ch->ch_startc != _POSIX_VDISABLE) {
1062 ch->ch_xon_sends++;
1063 writeb(ch->ch_startc, &ch->ch_cls_uart->txrx);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301064 }
Lidza Louina0b99d582013-08-01 17:00:20 -04001065}
1066
Lidza Louina0b99d582013-08-01 17:00:20 -04001067static void cls_send_stop_character(struct channel_t *ch)
1068{
1069 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
1070 return;
1071
1072 if (ch->ch_stopc != _POSIX_VDISABLE) {
1073 ch->ch_xoff_sends++;
1074 writeb(ch->ch_stopc, &ch->ch_cls_uart->txrx);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301075 }
Lidza Louina0b99d582013-08-01 17:00:20 -04001076}
1077
Lidza Louina0b99d582013-08-01 17:00:20 -04001078/* Inits UART */
1079static void cls_uart_init(struct channel_t *ch)
1080{
Ebru Akagunduz446393e2014-10-01 23:04:48 +03001081 unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
1082 unsigned char isr_fcr = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -04001083
1084 writeb(0, &ch->ch_cls_uart->ier);
1085
1086 /*
1087 * The Enhanced Register Set may only be accessed when
1088 * the Line Control Register is set to 0xBFh.
1089 */
1090 writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
1091
1092 isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
Lidza Louina5ca46fd2013-08-21 11:08:00 -04001093
Lidza Louina0b99d582013-08-01 17:00:20 -04001094 /* Turn on Enhanced/Extended controls */
1095 isr_fcr |= (UART_EXAR654_EFR_ECB);
1096
1097 writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
1098
1099 /* Write old LCR value back out, which turns enhanced access off */
1100 writeb(lcrb, &ch->ch_cls_uart->lcr);
1101
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301102 /* Clear out UART and FIFO */
Lidza Louina0b99d582013-08-01 17:00:20 -04001103 readb(&ch->ch_cls_uart->txrx);
1104
Daeseok Younea753f22016-04-04 18:52:03 +09001105 writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
Sudip Mukherjeee352d3f2015-10-04 19:50:14 +05301106 &ch->ch_cls_uart->isr_fcr);
Lidza Louina0b99d582013-08-01 17:00:20 -04001107 udelay(10);
1108
1109 ch->ch_flags |= (CH_FIFO_ENABLED | CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
1110
1111 readb(&ch->ch_cls_uart->lsr);
1112 readb(&ch->ch_cls_uart->msr);
1113}
1114
Lidza Louina0b99d582013-08-01 17:00:20 -04001115/*
1116 * Turns off UART.
1117 */
1118static void cls_uart_off(struct channel_t *ch)
1119{
1120 writeb(0, &ch->ch_cls_uart->ier);
1121}
1122
Lidza Louina0b99d582013-08-01 17:00:20 -04001123/*
1124 * cls_get_uarts_bytes_left.
1125 * Returns 0 is nothing left in the FIFO, returns 1 otherwise.
1126 *
1127 * The channel lock MUST be held by the calling function.
1128 */
1129static uint cls_get_uart_bytes_left(struct channel_t *ch)
1130{
Ebru Akagunduz446393e2014-10-01 23:04:48 +03001131 unsigned char left = 0;
1132 unsigned char lsr = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -04001133
1134 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
1135 return 0;
1136
1137 lsr = readb(&ch->ch_cls_uart->lsr);
1138
1139 /* Determine whether the Transmitter is empty or not */
1140 if (!(lsr & UART_LSR_TEMT)) {
Archana kumari3d479102013-10-17 18:45:16 +05301141 if (ch->ch_flags & CH_TX_FIFO_EMPTY)
Lidza Louina0b99d582013-08-01 17:00:20 -04001142 tasklet_schedule(&ch->ch_bd->helper_tasklet);
Lidza Louina0b99d582013-08-01 17:00:20 -04001143 left = 1;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301144 } else {
Lidza Louina0b99d582013-08-01 17:00:20 -04001145 ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
1146 left = 0;
1147 }
1148
1149 return left;
1150}
1151
Lidza Louina0b99d582013-08-01 17:00:20 -04001152/*
1153 * cls_send_break.
1154 * Starts sending a break thru the UART.
1155 *
1156 * The channel lock MUST be held by the calling function.
1157 */
1158static void cls_send_break(struct channel_t *ch, int msecs)
1159{
1160 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
1161 return;
1162
1163 /*
1164 * If we receive a time of 0, this means turn off the break.
1165 */
1166 if (msecs == 0) {
1167 /* Turn break off, and unset some variables */
1168 if (ch->ch_flags & CH_BREAK_SENDING) {
Ebru Akagunduz446393e2014-10-01 23:04:48 +03001169 unsigned char temp = readb(&ch->ch_cls_uart->lcr);
Konrad Zapalowicz8aa5d0d2014-08-06 22:17:09 +02001170
Lidza Louina0b99d582013-08-01 17:00:20 -04001171 writeb((temp & ~UART_LCR_SBC), &ch->ch_cls_uart->lcr);
1172 ch->ch_flags &= ~(CH_BREAK_SENDING);
1173 ch->ch_stop_sending_break = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -04001174 }
1175 return;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301176 }
Lidza Louina0b99d582013-08-01 17:00:20 -04001177
1178 /*
1179 * Set the time we should stop sending the break.
1180 * If we are already sending a break, toss away the existing
1181 * time to stop, and use this new value instead.
1182 */
1183 ch->ch_stop_sending_break = jiffies + dgnc_jiffies_from_ms(msecs);
1184
1185 /* Tell the UART to start sending the break */
1186 if (!(ch->ch_flags & CH_BREAK_SENDING)) {
Ebru Akagunduz446393e2014-10-01 23:04:48 +03001187 unsigned char temp = readb(&ch->ch_cls_uart->lcr);
Konrad Zapalowicz8aa5d0d2014-08-06 22:17:09 +02001188
Lidza Louina0b99d582013-08-01 17:00:20 -04001189 writeb((temp | UART_LCR_SBC), &ch->ch_cls_uart->lcr);
1190 ch->ch_flags |= (CH_BREAK_SENDING);
Lidza Louina0b99d582013-08-01 17:00:20 -04001191 }
1192}
1193
Lidza Louina0b99d582013-08-01 17:00:20 -04001194/*
1195 * cls_send_immediate_char.
1196 * Sends a specific character as soon as possible to the UART,
1197 * jumping over any bytes that might be in the write queue.
1198 *
1199 * The channel lock MUST be held by the calling function.
1200 */
1201static void cls_send_immediate_char(struct channel_t *ch, unsigned char c)
1202{
1203 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
1204 return;
1205
1206 writeb(c, &ch->ch_cls_uart->txrx);
1207}
1208
Lidza Louina03425f52013-09-09 15:01:22 -04001209static void cls_vpd(struct dgnc_board *brd)
Lidza Louina0b99d582013-08-01 17:00:20 -04001210{
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301211 ulong vpdbase; /* Start of io base of the card */
1212 u8 __iomem *re_map_vpdbase;/* Remapped memory of the card */
Lidza Louina0b99d582013-08-01 17:00:20 -04001213 int i = 0;
1214
Lidza Louina0b99d582013-08-01 17:00:20 -04001215 vpdbase = pci_resource_start(brd->pdev, 3);
1216
1217 /* No VPD */
1218 if (!vpdbase)
1219 return;
1220
1221 re_map_vpdbase = ioremap(vpdbase, 0x400);
1222
1223 if (!re_map_vpdbase)
1224 return;
1225
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301226 /* Store the VPD into our buffer */
1227 for (i = 0; i < 0x40; i++) {
Lidza Louina0b99d582013-08-01 17:00:20 -04001228 brd->vpd[i] = readb(re_map_vpdbase + i);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301229 pr_info("%x ", brd->vpd[i]);
1230 }
1231 pr_info("\n");
Lidza Louina0b99d582013-08-01 17:00:20 -04001232
Sudip Mukherjeee24bb0e2015-10-03 20:52:46 +05301233 iounmap(re_map_vpdbase);
Lidza Louina0b99d582013-08-01 17:00:20 -04001234}
Daeseok Youna2237a22016-07-06 15:14:37 +09001235
1236struct board_ops dgnc_cls_ops = {
1237 .tasklet = cls_tasklet,
1238 .intr = cls_intr,
1239 .uart_init = cls_uart_init,
1240 .uart_off = cls_uart_off,
1241 .drain = cls_drain,
1242 .param = cls_param,
1243 .vpd = cls_vpd,
1244 .assert_modem_signals = cls_assert_modem_signals,
1245 .flush_uart_write = cls_flush_uart_write,
1246 .flush_uart_read = cls_flush_uart_read,
1247 .disable_receiver = cls_disable_receiver,
1248 .enable_receiver = cls_enable_receiver,
1249 .send_break = cls_send_break,
1250 .send_start_character = cls_send_start_character,
1251 .send_stop_character = cls_send_stop_character,
1252 .copy_data_from_queue_to_uart = cls_copy_data_from_queue_to_uart,
1253 .get_uart_bytes_left = cls_get_uart_bytes_left,
1254 .send_immediate_char = cls_send_immediate_char
1255};