blob: 46c050cc7dbe79d3793f550c7c1ce4fbd589f3d6 [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 Louina03425f52013-09-09 15:01:22 -040029static inline void cls_parse_isr(struct dgnc_board *brd, uint port);
Lidza Louina0b99d582013-08-01 17:00:20 -040030static inline void cls_clear_break(struct channel_t *ch, int force);
31static inline void cls_set_cts_flow_control(struct channel_t *ch);
32static inline void cls_set_rts_flow_control(struct channel_t *ch);
33static inline void cls_set_ixon_flow_control(struct channel_t *ch);
34static inline void cls_set_ixoff_flow_control(struct channel_t *ch);
35static inline void cls_set_no_output_flow_control(struct channel_t *ch);
36static inline void cls_set_no_input_flow_control(struct channel_t *ch);
Ebru Akagunduz446393e2014-10-01 23:04:48 +030037static void cls_parse_modem(struct channel_t *ch, unsigned char signals);
Lidza Louina0b99d582013-08-01 17:00:20 -040038static void cls_tasklet(unsigned long data);
Lidza Louina03425f52013-09-09 15:01:22 -040039static void cls_vpd(struct dgnc_board *brd);
Lidza Louina0b99d582013-08-01 17:00:20 -040040static void cls_uart_init(struct channel_t *ch);
41static void cls_uart_off(struct channel_t *ch);
42static int cls_drain(struct tty_struct *tty, uint seconds);
43static void cls_param(struct tty_struct *tty);
44static void cls_assert_modem_signals(struct channel_t *ch);
45static void cls_flush_uart_write(struct channel_t *ch);
46static void cls_flush_uart_read(struct channel_t *ch);
47static void cls_disable_receiver(struct channel_t *ch);
48static void cls_enable_receiver(struct channel_t *ch);
49static void cls_send_break(struct channel_t *ch, int msecs);
50static void cls_send_start_character(struct channel_t *ch);
51static void cls_send_stop_character(struct channel_t *ch);
52static void cls_copy_data_from_uart_to_queue(struct channel_t *ch);
53static void cls_copy_data_from_queue_to_uart(struct channel_t *ch);
54static uint cls_get_uart_bytes_left(struct channel_t *ch);
55static void cls_send_immediate_char(struct channel_t *ch, unsigned char);
56static irqreturn_t cls_intr(int irq, void *voidbrd);
57
58struct board_ops dgnc_cls_ops = {
59 .tasklet = cls_tasklet,
60 .intr = cls_intr,
61 .uart_init = cls_uart_init,
62 .uart_off = cls_uart_off,
63 .drain = cls_drain,
64 .param = cls_param,
65 .vpd = cls_vpd,
66 .assert_modem_signals = cls_assert_modem_signals,
67 .flush_uart_write = cls_flush_uart_write,
68 .flush_uart_read = cls_flush_uart_read,
69 .disable_receiver = cls_disable_receiver,
70 .enable_receiver = cls_enable_receiver,
71 .send_break = cls_send_break,
72 .send_start_character = cls_send_start_character,
73 .send_stop_character = cls_send_stop_character,
74 .copy_data_from_queue_to_uart = cls_copy_data_from_queue_to_uart,
75 .get_uart_bytes_left = cls_get_uart_bytes_left,
76 .send_immediate_char = cls_send_immediate_char
77};
78
Lidza Louina0b99d582013-08-01 17:00:20 -040079static inline void cls_set_cts_flow_control(struct channel_t *ch)
80{
Ebru Akagunduz446393e2014-10-01 23:04:48 +030081 unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
82 unsigned char ier = readb(&ch->ch_cls_uart->ier);
83 unsigned char isr_fcr = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -040084
Lidza Louina0b99d582013-08-01 17:00:20 -040085 /*
86 * The Enhanced Register Set may only be accessed when
87 * the Line Control Register is set to 0xBFh.
88 */
89 writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
90
91 isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
Lidza Louina5ca46fd2013-08-21 11:08:00 -040092
Lidza Louina0b99d582013-08-01 17:00:20 -040093 /* Turn on CTS flow control, turn off IXON flow control */
94 isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_CTSDSR);
95 isr_fcr &= ~(UART_EXAR654_EFR_IXON);
96
97 writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
98
99 /* Write old LCR value back out, which turns enhanced access off */
100 writeb(lcrb, &ch->ch_cls_uart->lcr);
101
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530102 /*
103 * Enable interrupts for CTS flow, turn off interrupts for
104 * received XOFF chars
105 */
Lidza Louina0b99d582013-08-01 17:00:20 -0400106 ier |= (UART_EXAR654_IER_CTSDSR);
107 ier &= ~(UART_EXAR654_IER_XOFF);
108 writeb(ier, &ch->ch_cls_uart->ier);
109
110 /* Set the usual FIFO values */
111 writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
112
113 writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 |
114 UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
115 &ch->ch_cls_uart->isr_fcr);
116
117 ch->ch_t_tlevel = 16;
Lidza Louina0b99d582013-08-01 17:00:20 -0400118}
119
Lidza Louina0b99d582013-08-01 17:00:20 -0400120static inline void cls_set_ixon_flow_control(struct channel_t *ch)
121{
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300122 unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
123 unsigned char ier = readb(&ch->ch_cls_uart->ier);
124 unsigned char isr_fcr = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -0400125
Lidza Louina0b99d582013-08-01 17:00:20 -0400126 /*
127 * The Enhanced Register Set may only be accessed when
128 * the Line Control Register is set to 0xBFh.
129 */
130 writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
131
132 isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400133
Lidza Louina0b99d582013-08-01 17:00:20 -0400134 /* Turn on IXON flow control, turn off CTS flow control */
135 isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXON);
136 isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR);
137
138 writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
139
140 /* Now set our current start/stop chars while in enhanced mode */
141 writeb(ch->ch_startc, &ch->ch_cls_uart->mcr);
142 writeb(0, &ch->ch_cls_uart->lsr);
143 writeb(ch->ch_stopc, &ch->ch_cls_uart->msr);
144 writeb(0, &ch->ch_cls_uart->spr);
145
146 /* Write old LCR value back out, which turns enhanced access off */
147 writeb(lcrb, &ch->ch_cls_uart->lcr);
148
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530149 /*
150 * Disable interrupts for CTS flow, turn on interrupts for
151 * received XOFF chars
152 */
Lidza Louina0b99d582013-08-01 17:00:20 -0400153 ier &= ~(UART_EXAR654_IER_CTSDSR);
154 ier |= (UART_EXAR654_IER_XOFF);
155 writeb(ier, &ch->ch_cls_uart->ier);
156
157 /* Set the usual FIFO values */
158 writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
159
160 writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
161 UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
162 &ch->ch_cls_uart->isr_fcr);
Lidza Louina0b99d582013-08-01 17:00:20 -0400163}
164
Lidza Louina0b99d582013-08-01 17:00:20 -0400165static inline void cls_set_no_output_flow_control(struct channel_t *ch)
166{
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300167 unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
168 unsigned char ier = readb(&ch->ch_cls_uart->ier);
169 unsigned char isr_fcr = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -0400170
Lidza Louina0b99d582013-08-01 17:00:20 -0400171 /*
172 * The Enhanced Register Set may only be accessed when
173 * the Line Control Register is set to 0xBFh.
174 */
175 writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
176
177 isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400178
Lidza Louina0b99d582013-08-01 17:00:20 -0400179 /* Turn off IXON flow control, turn off CTS flow control */
180 isr_fcr |= (UART_EXAR654_EFR_ECB);
181 isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR | UART_EXAR654_EFR_IXON);
182
183 writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
184
185 /* Write old LCR value back out, which turns enhanced access off */
186 writeb(lcrb, &ch->ch_cls_uart->lcr);
187
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530188 /*
189 * Disable interrupts for CTS flow, turn off interrupts for
190 * received XOFF chars
191 */
Lidza Louina0b99d582013-08-01 17:00:20 -0400192 ier &= ~(UART_EXAR654_IER_CTSDSR);
193 ier &= ~(UART_EXAR654_IER_XOFF);
194 writeb(ier, &ch->ch_cls_uart->ier);
195
196 /* Set the usual FIFO values */
197 writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
198
199 writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
200 UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
201 &ch->ch_cls_uart->isr_fcr);
202
203 ch->ch_r_watermark = 0;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530204 ch->ch_t_tlevel = 16;
205 ch->ch_r_tlevel = 16;
Lidza Louina0b99d582013-08-01 17:00:20 -0400206}
207
Lidza Louina0b99d582013-08-01 17:00:20 -0400208static inline void cls_set_rts_flow_control(struct channel_t *ch)
209{
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300210 unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
211 unsigned char ier = readb(&ch->ch_cls_uart->ier);
212 unsigned char isr_fcr = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -0400213
Lidza Louina0b99d582013-08-01 17:00:20 -0400214 /*
215 * The Enhanced Register Set may only be accessed when
216 * the Line Control Register is set to 0xBFh.
217 */
218 writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
219
220 isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400221
Lidza Louina0b99d582013-08-01 17:00:20 -0400222 /* Turn on RTS flow control, turn off IXOFF flow control */
223 isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_RTSDTR);
224 isr_fcr &= ~(UART_EXAR654_EFR_IXOFF);
225
226 writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
227
228 /* Write old LCR value back out, which turns enhanced access off */
229 writeb(lcrb, &ch->ch_cls_uart->lcr);
230
231 /* Enable interrupts for RTS flow */
232 ier |= (UART_EXAR654_IER_RTSDTR);
233 writeb(ier, &ch->ch_cls_uart->ier);
234
235 /* Set the usual FIFO values */
236 writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
237
238 writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 |
239 UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
240 &ch->ch_cls_uart->isr_fcr);
241
Lidza Louina0b99d582013-08-01 17:00:20 -0400242 ch->ch_r_watermark = 4;
243 ch->ch_r_tlevel = 8;
Lidza Louina0b99d582013-08-01 17:00:20 -0400244}
245
Lidza Louina0b99d582013-08-01 17:00:20 -0400246static inline void cls_set_ixoff_flow_control(struct channel_t *ch)
247{
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300248 unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
249 unsigned char ier = readb(&ch->ch_cls_uart->ier);
250 unsigned char isr_fcr = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -0400251
Lidza Louina0b99d582013-08-01 17:00:20 -0400252 /*
253 * The Enhanced Register Set may only be accessed when
254 * the Line Control Register is set to 0xBFh.
255 */
256 writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
257
258 isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400259
Lidza Louina0b99d582013-08-01 17:00:20 -0400260 /* Turn on IXOFF flow control, turn off RTS flow control */
261 isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXOFF);
262 isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR);
263
264 writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
265
266 /* Now set our current start/stop chars while in enhanced mode */
267 writeb(ch->ch_startc, &ch->ch_cls_uart->mcr);
268 writeb(0, &ch->ch_cls_uart->lsr);
269 writeb(ch->ch_stopc, &ch->ch_cls_uart->msr);
270 writeb(0, &ch->ch_cls_uart->spr);
271
272 /* Write old LCR value back out, which turns enhanced access off */
273 writeb(lcrb, &ch->ch_cls_uart->lcr);
274
275 /* Disable interrupts for RTS flow */
276 ier &= ~(UART_EXAR654_IER_RTSDTR);
277 writeb(ier, &ch->ch_cls_uart->ier);
278
279 /* Set the usual FIFO values */
280 writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
281
282 writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
283 UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
284 &ch->ch_cls_uart->isr_fcr);
Lidza Louina0b99d582013-08-01 17:00:20 -0400285}
286
Lidza Louina0b99d582013-08-01 17:00:20 -0400287static inline void cls_set_no_input_flow_control(struct channel_t *ch)
288{
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300289 unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
290 unsigned char ier = readb(&ch->ch_cls_uart->ier);
291 unsigned char isr_fcr = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -0400292
Lidza Louina0b99d582013-08-01 17:00:20 -0400293 /*
294 * The Enhanced Register Set may only be accessed when
295 * the Line Control Register is set to 0xBFh.
296 */
297 writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
298
299 isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400300
Lidza Louina0b99d582013-08-01 17:00:20 -0400301 /* Turn off IXOFF flow control, turn off RTS flow control */
302 isr_fcr |= (UART_EXAR654_EFR_ECB);
303 isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR | UART_EXAR654_EFR_IXOFF);
304
305 writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
306
307 /* Write old LCR value back out, which turns enhanced access off */
308 writeb(lcrb, &ch->ch_cls_uart->lcr);
309
310 /* Disable interrupts for RTS flow */
311 ier &= ~(UART_EXAR654_IER_RTSDTR);
312 writeb(ier, &ch->ch_cls_uart->ier);
313
314 /* Set the usual FIFO values */
315 writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
316
317 writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
318 UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
319 &ch->ch_cls_uart->isr_fcr);
320
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530321 ch->ch_t_tlevel = 16;
322 ch->ch_r_tlevel = 16;
Lidza Louina0b99d582013-08-01 17:00:20 -0400323}
324
Lidza Louina0b99d582013-08-01 17:00:20 -0400325/*
326 * cls_clear_break.
327 * Determines whether its time to shut off break condition.
328 *
329 * No locks are assumed to be held when calling this function.
330 * channel lock is held and released in this function.
331 */
332static inline void cls_clear_break(struct channel_t *ch, int force)
333{
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300334 unsigned long flags;
Lidza Louina0b99d582013-08-01 17:00:20 -0400335
336 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
337 return;
338
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300339 spin_lock_irqsave(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400340
341 /* Bail if we aren't currently sending a break. */
342 if (!ch->ch_stop_sending_break) {
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300343 spin_unlock_irqrestore(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400344 return;
345 }
346
347 /* Turn break off, and unset some variables */
348 if (ch->ch_flags & CH_BREAK_SENDING) {
stalinsrinivasan.sf0dcc9f2013-12-20 22:03:27 +0530349 if (time_after(jiffies, ch->ch_stop_sending_break) || force) {
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300350 unsigned char temp = readb(&ch->ch_cls_uart->lcr);
Konrad Zapalowicz8aa5d0d2014-08-06 22:17:09 +0200351
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530352 writeb((temp & ~UART_LCR_SBC), &ch->ch_cls_uart->lcr);
Lidza Louina0b99d582013-08-01 17:00:20 -0400353 ch->ch_flags &= ~(CH_BREAK_SENDING);
354 ch->ch_stop_sending_break = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -0400355 }
356 }
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300357 spin_unlock_irqrestore(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400358}
359
Lidza Louina0b99d582013-08-01 17:00:20 -0400360/* Parse the ISR register for the specific port */
Lidza Louina03425f52013-09-09 15:01:22 -0400361static inline void cls_parse_isr(struct dgnc_board *brd, uint port)
Lidza Louina0b99d582013-08-01 17:00:20 -0400362{
363 struct channel_t *ch;
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300364 unsigned char isr = 0;
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300365 unsigned long flags;
Lidza Louina0b99d582013-08-01 17:00:20 -0400366
367 /*
368 * No need to verify board pointer, it was already
369 * verified in the interrupt routine.
370 */
371
Dan Carpenter4bef52f2015-03-12 20:24:31 +0300372 if (port >= brd->nasync)
Lidza Louina0b99d582013-08-01 17:00:20 -0400373 return;
374
375 ch = brd->channels[port];
Giedrius Statkevičius071494d2015-04-10 02:42:31 +0300376 if (ch->magic != DGNC_CHANNEL_MAGIC)
Lidza Louina0b99d582013-08-01 17:00:20 -0400377 return;
378
379 /* Here we try to figure out what caused the interrupt to happen */
380 while (1) {
Lidza Louina0b99d582013-08-01 17:00:20 -0400381 isr = readb(&ch->ch_cls_uart->isr_fcr);
382
383 /* Bail if no pending interrupt on port */
Archana kumari3d479102013-10-17 18:45:16 +0530384 if (isr & UART_IIR_NO_INT)
Lidza Louina0b99d582013-08-01 17:00:20 -0400385 break;
Lidza Louina0b99d582013-08-01 17:00:20 -0400386
Lidza Louina0b99d582013-08-01 17:00:20 -0400387 /* Receive Interrupt pending */
388 if (isr & (UART_IIR_RDI | UART_IIR_RDI_TIMEOUT)) {
389 /* Read data from uart -> queue */
390 brd->intr_rx++;
391 ch->ch_intr_rx++;
392 cls_copy_data_from_uart_to_queue(ch);
393 dgnc_check_queue_flow_control(ch);
394 }
395
396 /* Transmit Hold register empty pending */
397 if (isr & UART_IIR_THRI) {
398 /* Transfer data (if any) from Write Queue -> UART. */
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300399 spin_lock_irqsave(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400400 ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
401 brd->intr_tx++;
402 ch->ch_intr_tx++;
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300403 spin_unlock_irqrestore(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400404 cls_copy_data_from_queue_to_uart(ch);
405 }
406
Lidza Louina0b99d582013-08-01 17:00:20 -0400407 /* CTS/RTS change of state */
408 if (isr & UART_IIR_CTSRTS) {
409 brd->intr_modem++;
410 ch->ch_intr_modem++;
411 /*
412 * Don't need to do anything, the cls_parse_modem
413 * below will grab the updated modem signals.
414 */
415 }
416
417 /* Parse any modem signal changes */
Lidza Louina0b99d582013-08-01 17:00:20 -0400418 cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr));
419 }
420}
421
Lidza Louina0b99d582013-08-01 17:00:20 -0400422/*
423 * cls_param()
424 * Send any/all changes to the line to the UART.
425 */
426static void cls_param(struct tty_struct *tty)
427{
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300428 unsigned char lcr = 0;
429 unsigned char uart_lcr = 0;
430 unsigned char ier = 0;
431 unsigned char uart_ier = 0;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530432 uint baud = 9600;
Lidza Louina0b99d582013-08-01 17:00:20 -0400433 int quot = 0;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530434 struct dgnc_board *bd;
Lidza Louina0b99d582013-08-01 17:00:20 -0400435 struct channel_t *ch;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530436 struct un_t *un;
Lidza Louina0b99d582013-08-01 17:00:20 -0400437
Archana kumari3d479102013-10-17 18:45:16 +0530438 if (!tty || tty->magic != TTY_MAGIC)
Lidza Louina0b99d582013-08-01 17:00:20 -0400439 return;
Lidza Louina0b99d582013-08-01 17:00:20 -0400440
Sudip Mukherjee6f418252015-10-04 19:50:13 +0530441 un = (struct un_t *)tty->driver_data;
Archana kumari3d479102013-10-17 18:45:16 +0530442 if (!un || un->magic != DGNC_UNIT_MAGIC)
Lidza Louina0b99d582013-08-01 17:00:20 -0400443 return;
Lidza Louina0b99d582013-08-01 17:00:20 -0400444
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400445 ch = un->un_ch;
Archana kumari3d479102013-10-17 18:45:16 +0530446 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
Lidza Louina0b99d582013-08-01 17:00:20 -0400447 return;
Lidza Louina0b99d582013-08-01 17:00:20 -0400448
449 bd = ch->ch_bd;
Archana kumari3d479102013-10-17 18:45:16 +0530450 if (!bd || bd->magic != DGNC_BOARD_MAGIC)
Lidza Louina0b99d582013-08-01 17:00:20 -0400451 return;
Lidza Louina0b99d582013-08-01 17:00:20 -0400452
Lidza Louina0b99d582013-08-01 17:00:20 -0400453 /*
454 * If baud rate is zero, flush queues, and set mval to drop DTR.
455 */
456 if ((ch->ch_c_cflag & (CBAUD)) == 0) {
Seunghun Lee587abd72014-09-01 22:46:59 +0900457 ch->ch_r_head = 0;
458 ch->ch_r_tail = 0;
459 ch->ch_e_head = 0;
460 ch->ch_e_tail = 0;
461 ch->ch_w_head = 0;
462 ch->ch_w_tail = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -0400463
464 cls_flush_uart_write(ch);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530465 cls_flush_uart_read(ch);
Lidza Louina0b99d582013-08-01 17:00:20 -0400466
467 /* The baudrate is B0 so all modem lines are to be dropped. */
468 ch->ch_flags |= (CH_BAUD0);
469 ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
470 cls_assert_modem_signals(ch);
471 ch->ch_old_baud = 0;
472 return;
473 } else if (ch->ch_custom_speed) {
Lidza Louina0b99d582013-08-01 17:00:20 -0400474 baud = ch->ch_custom_speed;
475 /* Handle transition from B0 */
476 if (ch->ch_flags & CH_BAUD0) {
477 ch->ch_flags &= ~(CH_BAUD0);
478
479 /*
480 * Bring back up RTS and DTR...
481 * Also handle RTS or DTR toggle if set.
482 */
483 if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE))
484 ch->ch_mostat |= (UART_MCR_RTS);
485 if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE))
486 ch->ch_mostat |= (UART_MCR_DTR);
487 }
488
489 } else {
490 int iindex = 0;
491 int jindex = 0;
492
493 ulong bauds[4][16] = {
494 { /* slowbaud */
495 0, 50, 75, 110,
496 134, 150, 200, 300,
497 600, 1200, 1800, 2400,
498 4800, 9600, 19200, 38400 },
499 { /* slowbaud & CBAUDEX */
500 0, 57600, 115200, 230400,
501 460800, 150, 200, 921600,
502 600, 1200, 1800, 2400,
503 4800, 9600, 19200, 38400 },
504 { /* fastbaud */
505 0, 57600, 76800, 115200,
506 131657, 153600, 230400, 460800,
507 921600, 1200, 1800, 2400,
508 4800, 9600, 19200, 38400 },
509 { /* fastbaud & CBAUDEX */
510 0, 57600, 115200, 230400,
511 460800, 150, 200, 921600,
512 600, 1200, 1800, 2400,
513 4800, 9600, 19200, 38400 }
514 };
515
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530516 /*
517 * Only use the TXPrint baud rate if the terminal
518 * unit is NOT open
519 */
520 if (!(ch->ch_tun.un_flags & UN_ISOPEN) &&
Sudip Mukherjeee352d3f2015-10-04 19:50:14 +0530521 (un->un_type == DGNC_PRINT))
Lidza Louina0b99d582013-08-01 17:00:20 -0400522 baud = C_BAUD(ch->ch_pun.un_tty) & 0xff;
523 else
524 baud = C_BAUD(ch->ch_tun.un_tty) & 0xff;
525
526 if (ch->ch_c_cflag & CBAUDEX)
527 iindex = 1;
528
529 if (ch->ch_digi.digi_flags & DIGI_FAST)
530 iindex += 2;
531
532 jindex = baud;
533
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530534 if ((iindex >= 0) && (iindex < 4) && (jindex >= 0) &&
Sudip Mukherjeee352d3f2015-10-04 19:50:14 +0530535 (jindex < 16)) {
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400536 baud = bauds[iindex][jindex];
Lidza Louina0b99d582013-08-01 17:00:20 -0400537 } else {
Lidza Louina0b99d582013-08-01 17:00:20 -0400538 baud = 0;
539 }
540
541 if (baud == 0)
542 baud = 9600;
543
544 /* Handle transition from B0 */
545 if (ch->ch_flags & CH_BAUD0) {
546 ch->ch_flags &= ~(CH_BAUD0);
547
548 /*
549 * Bring back up RTS and DTR...
550 * Also handle RTS or DTR toggle if set.
551 */
552 if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE))
553 ch->ch_mostat |= (UART_MCR_RTS);
554 if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE))
555 ch->ch_mostat |= (UART_MCR_DTR);
556 }
557 }
558
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530559 if (ch->ch_c_cflag & PARENB)
Lidza Louina0b99d582013-08-01 17:00:20 -0400560 lcr |= UART_LCR_PARITY;
Lidza Louina0b99d582013-08-01 17:00:20 -0400561
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530562 if (!(ch->ch_c_cflag & PARODD))
Lidza Louina0b99d582013-08-01 17:00:20 -0400563 lcr |= UART_LCR_EPAR;
Lidza Louina0b99d582013-08-01 17:00:20 -0400564
565 /*
566 * Not all platforms support mark/space parity,
567 * so this will hide behind an ifdef.
568 */
569#ifdef CMSPAR
570 if (ch->ch_c_cflag & CMSPAR)
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400571 lcr |= UART_LCR_SPAR;
Lidza Louina0b99d582013-08-01 17:00:20 -0400572#endif
573
574 if (ch->ch_c_cflag & CSTOPB)
575 lcr |= UART_LCR_STOP;
576
577 switch (ch->ch_c_cflag & CSIZE) {
578 case CS5:
579 lcr |= UART_LCR_WLEN5;
580 break;
581 case CS6:
582 lcr |= UART_LCR_WLEN6;
583 break;
584 case CS7:
585 lcr |= UART_LCR_WLEN7;
586 break;
587 case CS8:
588 default:
589 lcr |= UART_LCR_WLEN8;
590 break;
591 }
592
Seunghun Lee587abd72014-09-01 22:46:59 +0900593 uart_ier = readb(&ch->ch_cls_uart->ier);
594 ier = uart_ier;
Lidza Louina0b99d582013-08-01 17:00:20 -0400595 uart_lcr = readb(&ch->ch_cls_uart->lcr);
596
597 if (baud == 0)
598 baud = 9600;
599
600 quot = ch->ch_bd->bd_dividend / baud;
601
602 if (quot != 0 && ch->ch_old_baud != baud) {
603 ch->ch_old_baud = baud;
604 writeb(UART_LCR_DLAB, &ch->ch_cls_uart->lcr);
605 writeb((quot & 0xff), &ch->ch_cls_uart->txrx);
606 writeb((quot >> 8), &ch->ch_cls_uart->ier);
607 writeb(lcr, &ch->ch_cls_uart->lcr);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530608 }
Lidza Louina0b99d582013-08-01 17:00:20 -0400609
610 if (uart_lcr != lcr)
611 writeb(lcr, &ch->ch_cls_uart->lcr);
612
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530613 if (ch->ch_c_cflag & CREAD)
Lidza Louina0b99d582013-08-01 17:00:20 -0400614 ier |= (UART_IER_RDI | UART_IER_RLSI);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530615 else
Lidza Louina0b99d582013-08-01 17:00:20 -0400616 ier &= ~(UART_IER_RDI | UART_IER_RLSI);
Lidza Louina0b99d582013-08-01 17:00:20 -0400617
618 /*
619 * Have the UART interrupt on modem signal changes ONLY when
620 * we are in hardware flow control mode, or CLOCAL/FORCEDCD is not set.
621 */
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530622 if ((ch->ch_digi.digi_flags & CTSPACE) ||
Cristina Moraruc76d2942015-10-01 21:43:57 +0300623 (ch->ch_digi.digi_flags & RTSPACE) ||
624 (ch->ch_c_cflag & CRTSCTS) ||
625 !(ch->ch_digi.digi_flags & DIGI_FORCEDCD) ||
626 !(ch->ch_c_cflag & CLOCAL))
627 ier |= UART_IER_MSI;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530628 else
Cristina Moraruc76d2942015-10-01 21:43:57 +0300629 ier &= ~UART_IER_MSI;
Lidza Louina0b99d582013-08-01 17:00:20 -0400630
631 ier |= UART_IER_THRI;
632
633 if (ier != uart_ier)
634 writeb(ier, &ch->ch_cls_uart->ier);
635
636 if (ch->ch_digi.digi_flags & CTSPACE || ch->ch_c_cflag & CRTSCTS) {
637 cls_set_cts_flow_control(ch);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530638 } else if (ch->ch_c_iflag & IXON) {
639 /*
640 * If start/stop is set to disable, then we should
641 * disable flow control
642 */
643 if ((ch->ch_startc == _POSIX_VDISABLE) ||
Sudip Mukherjeee352d3f2015-10-04 19:50:14 +0530644 (ch->ch_stopc == _POSIX_VDISABLE))
Lidza Louina0b99d582013-08-01 17:00:20 -0400645 cls_set_no_output_flow_control(ch);
646 else
647 cls_set_ixon_flow_control(ch);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530648 } else {
Lidza Louina0b99d582013-08-01 17:00:20 -0400649 cls_set_no_output_flow_control(ch);
650 }
651
652 if (ch->ch_digi.digi_flags & RTSPACE || ch->ch_c_cflag & CRTSCTS) {
653 cls_set_rts_flow_control(ch);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530654 } else if (ch->ch_c_iflag & IXOFF) {
655 /*
656 * If start/stop is set to disable, then we should disable
657 * flow control
658 */
659 if ((ch->ch_startc == _POSIX_VDISABLE) ||
Sudip Mukherjeee352d3f2015-10-04 19:50:14 +0530660 (ch->ch_stopc == _POSIX_VDISABLE))
Lidza Louina0b99d582013-08-01 17:00:20 -0400661 cls_set_no_input_flow_control(ch);
662 else
663 cls_set_ixoff_flow_control(ch);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530664 } else {
Lidza Louina0b99d582013-08-01 17:00:20 -0400665 cls_set_no_input_flow_control(ch);
666 }
667
668 cls_assert_modem_signals(ch);
669
670 /* Get current status of the modem signals now */
671 cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr));
672}
673
Lidza Louina0b99d582013-08-01 17:00:20 -0400674/*
675 * Our board poller function.
676 */
677static void cls_tasklet(unsigned long data)
678{
Sudip Mukherjee6f418252015-10-04 19:50:13 +0530679 struct dgnc_board *bd = (struct dgnc_board *)data;
Lidza Louina0b99d582013-08-01 17:00:20 -0400680 struct channel_t *ch;
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300681 unsigned long flags;
Lidza Louina0b99d582013-08-01 17:00:20 -0400682 int i;
683 int state = 0;
684 int ports = 0;
685
Roberta Dobrescu1f26adc2014-10-07 13:08:12 +0300686 if (!bd || bd->magic != DGNC_BOARD_MAGIC)
Lidza Louina0b99d582013-08-01 17:00:20 -0400687 return;
Lidza Louina0b99d582013-08-01 17:00:20 -0400688
689 /* Cache a couple board values */
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300690 spin_lock_irqsave(&bd->bd_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400691 state = bd->state;
692 ports = bd->nasync;
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300693 spin_unlock_irqrestore(&bd->bd_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400694
695 /*
696 * Do NOT allow the interrupt routine to read the intr registers
697 * Until we release this lock.
698 */
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300699 spin_lock_irqsave(&bd->bd_intr_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400700
701 /*
702 * If board is ready, parse deeper to see if there is anything to do.
703 */
704 if ((state == BOARD_READY) && (ports > 0)) {
Lidza Louina0b99d582013-08-01 17:00:20 -0400705 /* Loop on each port */
706 for (i = 0; i < ports; i++) {
707 ch = bd->channels[i];
Lidza Louina0b99d582013-08-01 17:00:20 -0400708
709 /*
710 * NOTE: Remember you CANNOT hold any channel
711 * locks when calling input.
712 * During input processing, its possible we
713 * will call ld, which might do callbacks back
714 * into us.
715 */
716 dgnc_input(ch);
717
718 /*
719 * Channel lock is grabbed and then released
720 * inside this routine.
721 */
722 cls_copy_data_from_queue_to_uart(ch);
723 dgnc_wakeup_writes(ch);
724
725 /*
726 * Check carrier function.
727 */
728 dgnc_carrier(ch);
729
730 /*
731 * The timing check of turning off the break is done
732 * inside clear_break()
733 */
734 if (ch->ch_stop_sending_break)
735 cls_clear_break(ch, 0);
736 }
737 }
738
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300739 spin_unlock_irqrestore(&bd->bd_intr_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400740}
741
Lidza Louina0b99d582013-08-01 17:00:20 -0400742/*
743 * cls_intr()
744 *
745 * Classic specific interrupt handler.
746 */
747static irqreturn_t cls_intr(int irq, void *voidbrd)
748{
Tapasweni Pathakfc33bd22014-10-30 17:02:04 +0530749 struct dgnc_board *brd = voidbrd;
Lidza Louina0b99d582013-08-01 17:00:20 -0400750 uint i = 0;
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300751 unsigned char poll_reg;
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300752 unsigned long flags;
Lidza Louina0b99d582013-08-01 17:00:20 -0400753
Lidza Louina0b99d582013-08-01 17:00:20 -0400754 /*
Roberta Dobrescu1f26adc2014-10-07 13:08:12 +0300755 * Check to make sure it didn't receive interrupt with a null board
756 * associated or a board pointer that wasn't ours.
Lidza Louina0b99d582013-08-01 17:00:20 -0400757 */
Roberta Dobrescu1f26adc2014-10-07 13:08:12 +0300758 if (!brd || brd->magic != DGNC_BOARD_MAGIC)
Lidza Louina0b99d582013-08-01 17:00:20 -0400759 return IRQ_NONE;
Lidza Louina0b99d582013-08-01 17:00:20 -0400760
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300761 spin_lock_irqsave(&brd->bd_intr_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400762
763 brd->intr_count++;
764
765 /*
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400766 * Check the board's global interrupt offset to see if we
Lidza Louina0b99d582013-08-01 17:00:20 -0400767 * we actually do have an interrupt pending for us.
768 */
769 poll_reg = readb(brd->re_map_membase + UART_CLASSIC_POLL_ADDR_OFFSET);
770
771 /* If 0, no interrupts pending */
772 if (!poll_reg) {
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300773 spin_unlock_irqrestore(&brd->bd_intr_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400774 return IRQ_NONE;
775 }
776
Lidza Louina0b99d582013-08-01 17:00:20 -0400777 /* Parse each port to find out what caused the interrupt */
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530778 for (i = 0; i < brd->nasync; i++)
Lidza Louina0b99d582013-08-01 17:00:20 -0400779 cls_parse_isr(brd, i);
Lidza Louina0b99d582013-08-01 17:00:20 -0400780
781 /*
782 * Schedule tasklet to more in-depth servicing at a better time.
783 */
784 tasklet_schedule(&brd->helper_tasklet);
785
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300786 spin_unlock_irqrestore(&brd->bd_intr_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400787
Lidza Louina0b99d582013-08-01 17:00:20 -0400788 return IRQ_HANDLED;
789}
790
Lidza Louina0b99d582013-08-01 17:00:20 -0400791static void cls_disable_receiver(struct channel_t *ch)
792{
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300793 unsigned char tmp = readb(&ch->ch_cls_uart->ier);
Konrad Zapalowicz8aa5d0d2014-08-06 22:17:09 +0200794
Lidza Louina0b99d582013-08-01 17:00:20 -0400795 tmp &= ~(UART_IER_RDI);
796 writeb(tmp, &ch->ch_cls_uart->ier);
797}
798
Lidza Louina0b99d582013-08-01 17:00:20 -0400799static void cls_enable_receiver(struct channel_t *ch)
800{
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300801 unsigned char tmp = readb(&ch->ch_cls_uart->ier);
Konrad Zapalowicz8aa5d0d2014-08-06 22:17:09 +0200802
Lidza Louina0b99d582013-08-01 17:00:20 -0400803 tmp |= (UART_IER_RDI);
804 writeb(tmp, &ch->ch_cls_uart->ier);
805}
806
Lidza Louina0b99d582013-08-01 17:00:20 -0400807static void cls_copy_data_from_uart_to_queue(struct channel_t *ch)
808{
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530809 int qleft = 0;
Ebru Akagunduz446393e2014-10-01 23:04:48 +0300810 unsigned char linestatus = 0;
811 unsigned char error_mask = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -0400812 ushort head;
813 ushort tail;
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300814 unsigned long flags;
Lidza Louina0b99d582013-08-01 17:00:20 -0400815
816 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
817 return;
818
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300819 spin_lock_irqsave(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400820
821 /* cache head and tail of queue */
822 head = ch->ch_r_head;
823 tail = ch->ch_r_tail;
824
825 /* Store how much space we have left in the queue */
Eva Rachel Retuya0b7ceaa2016-02-24 00:34:56 +0800826 qleft = tail - head - 1;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530827 if (qleft < 0)
Lidza Louina0b99d582013-08-01 17:00:20 -0400828 qleft += RQUEUEMASK + 1;
829
830 /*
831 * Create a mask to determine whether we should
832 * insert the character (if any) into our queue.
833 */
834 if (ch->ch_c_iflag & IGNBRK)
835 error_mask |= UART_LSR_BI;
836
837 while (1) {
838 linestatus = readb(&ch->ch_cls_uart->lsr);
839
840 if (!(linestatus & (UART_LSR_DR)))
841 break;
842
843 /*
844 * Discard character if we are ignoring the error mask.
845 */
846 if (linestatus & error_mask) {
Lidza Louina0b99d582013-08-01 17:00:20 -0400847 linestatus = 0;
Sudip Mukherjee2d9920e2015-10-03 20:52:39 +0530848 readb(&ch->ch_cls_uart->txrx);
Lidza Louina0b99d582013-08-01 17:00:20 -0400849 continue;
850 }
851
852 /*
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530853 * If our queue is full, we have no choice but to drop some
854 * data. The assumption is that HWFLOW or SWFLOW should have
855 * stopped things way way before we got to this point.
Lidza Louina0b99d582013-08-01 17:00:20 -0400856 *
857 * I decided that I wanted to ditch the oldest data first,
858 * I hope thats okay with everyone? Yes? Good.
859 */
860 while (qleft < 1) {
Seunghun Lee587abd72014-09-01 22:46:59 +0900861 tail = (tail + 1) & RQUEUEMASK;
862 ch->ch_r_tail = tail;
Lidza Louina0b99d582013-08-01 17:00:20 -0400863 ch->ch_err_overrun++;
864 qleft++;
865 }
866
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530867 ch->ch_equeue[head] = linestatus & (UART_LSR_BI | UART_LSR_PE
868 | UART_LSR_FE);
Lidza Louina0b99d582013-08-01 17:00:20 -0400869 ch->ch_rqueue[head] = readb(&ch->ch_cls_uart->txrx);
Lidza Louina0b99d582013-08-01 17:00:20 -0400870
871 qleft--;
872
Lidza Louina0b99d582013-08-01 17:00:20 -0400873 if (ch->ch_equeue[head] & UART_LSR_PE)
874 ch->ch_err_parity++;
875 if (ch->ch_equeue[head] & UART_LSR_BI)
876 ch->ch_err_break++;
877 if (ch->ch_equeue[head] & UART_LSR_FE)
878 ch->ch_err_frame++;
879
880 /* Add to, and flip head if needed */
881 head = (head + 1) & RQUEUEMASK;
882 ch->ch_rxcount++;
883 }
884
885 /*
886 * Write new final heads to channel structure.
887 */
888 ch->ch_r_head = head & RQUEUEMASK;
889 ch->ch_e_head = head & EQUEUEMASK;
890
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300891 spin_unlock_irqrestore(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400892}
893
Lidza Louina0b99d582013-08-01 17:00:20 -0400894/*
895 * This function basically goes to sleep for secs, or until
896 * it gets signalled that the port has fully drained.
897 */
898static int cls_drain(struct tty_struct *tty, uint seconds)
899{
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300900 unsigned long flags;
Lidza Louina0b99d582013-08-01 17:00:20 -0400901 struct channel_t *ch;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530902 struct un_t *un;
Lidza Louina0b99d582013-08-01 17:00:20 -0400903
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530904 if (!tty || tty->magic != TTY_MAGIC)
Lidza Louina8f90ef82013-09-09 15:01:23 -0400905 return -ENXIO;
Lidza Louina0b99d582013-08-01 17:00:20 -0400906
Sudip Mukherjee6f418252015-10-04 19:50:13 +0530907 un = (struct un_t *)tty->driver_data;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530908 if (!un || un->magic != DGNC_UNIT_MAGIC)
Lidza Louina8f90ef82013-09-09 15:01:23 -0400909 return -ENXIO;
Lidza Louina0b99d582013-08-01 17:00:20 -0400910
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400911 ch = un->un_ch;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530912 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
Lidza Louina8f90ef82013-09-09 15:01:23 -0400913 return -ENXIO;
Lidza Louina0b99d582013-08-01 17:00:20 -0400914
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300915 spin_lock_irqsave(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400916 un->un_flags |= UN_EMPTY;
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300917 spin_unlock_irqrestore(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400918
919 /*
920 * NOTE: Do something with time passed in.
921 */
Lidza Louina0b99d582013-08-01 17:00:20 -0400922
923 /* If ret is non-zero, user ctrl-c'ed us */
Lidza Louina0b99d582013-08-01 17:00:20 -0400924
Heena Sirwanica5dd0b2014-10-06 10:19:09 +0530925 return wait_event_interruptible(un->un_flags_wait,
926 ((un->un_flags & UN_EMPTY) == 0));
Lidza Louina0b99d582013-08-01 17:00:20 -0400927}
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400928
Lidza Louina0b99d582013-08-01 17:00:20 -0400929/* Channel lock MUST be held before calling this function! */
930static void cls_flush_uart_write(struct channel_t *ch)
931{
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530932 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
Lidza Louina0b99d582013-08-01 17:00:20 -0400933 return;
Lidza Louina0b99d582013-08-01 17:00:20 -0400934
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530935 writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT),
Sudip Mukherjeee352d3f2015-10-04 19:50:14 +0530936 &ch->ch_cls_uart->isr_fcr);
Jitendra Kumar Khasdev6e411752015-11-24 23:01:13 +0530937 usleep_range(10, 20);
Lidza Louina0b99d582013-08-01 17:00:20 -0400938
939 ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
940}
941
Lidza Louina0b99d582013-08-01 17:00:20 -0400942/* Channel lock MUST be held before calling this function! */
943static void cls_flush_uart_read(struct channel_t *ch)
944{
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530945 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
Lidza Louina0b99d582013-08-01 17:00:20 -0400946 return;
Lidza Louina0b99d582013-08-01 17:00:20 -0400947
948 /*
949 * For complete POSIX compatibility, we should be purging the
950 * read FIFO in the UART here.
Lidza Louina5ca46fd2013-08-21 11:08:00 -0400951 *
Seunghun Lee83f053d2014-07-31 22:30:32 +0900952 * However, clearing the read FIFO (UART_FCR_CLEAR_RCVR) also
953 * incorrectly flushes write data as well as just basically trashing the
954 * FIFO.
Lidza Louina0b99d582013-08-01 17:00:20 -0400955 *
Seunghun Lee83f053d2014-07-31 22:30:32 +0900956 * Presumably, this is a bug in this UART.
Lidza Louina0b99d582013-08-01 17:00:20 -0400957 */
Seunghun Lee645b0312014-07-26 01:49:01 +0900958
Lidza Louina0b99d582013-08-01 17:00:20 -0400959 udelay(10);
960}
961
Lidza Louina0b99d582013-08-01 17:00:20 -0400962static void cls_copy_data_from_queue_to_uart(struct channel_t *ch)
963{
964 ushort head;
965 ushort tail;
966 int n;
967 int qlen;
968 uint len_written = 0;
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300969 unsigned long flags;
Lidza Louina0b99d582013-08-01 17:00:20 -0400970
971 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
972 return;
973
Roberta Dobrescu707505b2014-09-23 01:55:55 +0300974 spin_lock_irqsave(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -0400975
976 /* No data to write to the UART */
Quentin Lambertf6a14cf2015-03-11 15:22:00 +0100977 if (ch->ch_w_tail == ch->ch_w_head)
978 goto exit_unlock;
Lidza Louina0b99d582013-08-01 17:00:20 -0400979
980 /* If port is "stopped", don't send any data to the UART */
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530981 if ((ch->ch_flags & CH_FORCED_STOP) ||
Sudip Mukherjeee352d3f2015-10-04 19:50:14 +0530982 (ch->ch_flags & CH_BREAK_SENDING))
Quentin Lambertf6a14cf2015-03-11 15:22:00 +0100983 goto exit_unlock;
Lidza Louina0b99d582013-08-01 17:00:20 -0400984
Quentin Lambertf6a14cf2015-03-11 15:22:00 +0100985 if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM)))
986 goto exit_unlock;
Lidza Louina0b99d582013-08-01 17:00:20 -0400987
988 n = 32;
989
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +0530990 /* cache head and tail of queue */
991 head = ch->ch_w_head & WQUEUEMASK;
992 tail = ch->ch_w_tail & WQUEUEMASK;
993 qlen = (head - tail) & WQUEUEMASK;
Lidza Louina0b99d582013-08-01 17:00:20 -0400994
995 /* Find minimum of the FIFO space, versus queue length */
996 n = min(n, qlen);
997
998 while (n > 0) {
Lidza Louina0b99d582013-08-01 17:00:20 -0400999 /*
1000 * If RTS Toggle mode is on, turn on RTS now if not already set,
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301001 * and make sure we get an event when the data transfer has
1002 * completed.
Lidza Louina0b99d582013-08-01 17:00:20 -04001003 */
1004 if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) {
1005 if (!(ch->ch_mostat & UART_MCR_RTS)) {
1006 ch->ch_mostat |= (UART_MCR_RTS);
1007 cls_assert_modem_signals(ch);
1008 }
1009 ch->ch_tun.un_flags |= (UN_EMPTY);
1010 }
1011
1012 /*
1013 * If DTR Toggle mode is on, turn on DTR now if not already set,
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301014 * and make sure we get an event when the data transfer has
1015 * completed.
Lidza Louina0b99d582013-08-01 17:00:20 -04001016 */
1017 if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) {
1018 if (!(ch->ch_mostat & UART_MCR_DTR)) {
1019 ch->ch_mostat |= (UART_MCR_DTR);
1020 cls_assert_modem_signals(ch);
1021 }
1022 ch->ch_tun.un_flags |= (UN_EMPTY);
1023 }
1024 writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_cls_uart->txrx);
Lidza Louina0b99d582013-08-01 17:00:20 -04001025 ch->ch_w_tail++;
1026 ch->ch_w_tail &= WQUEUEMASK;
1027 ch->ch_txcount++;
1028 len_written++;
1029 n--;
1030 }
1031
1032 if (len_written > 0)
1033 ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
1034
Quentin Lambertf6a14cf2015-03-11 15:22:00 +01001035exit_unlock:
Roberta Dobrescu707505b2014-09-23 01:55:55 +03001036 spin_unlock_irqrestore(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -04001037}
1038
Ebru Akagunduz446393e2014-10-01 23:04:48 +03001039static void cls_parse_modem(struct channel_t *ch, unsigned char signals)
Lidza Louina0b99d582013-08-01 17:00:20 -04001040{
Ebru Akagunduz446393e2014-10-01 23:04:48 +03001041 unsigned char msignals = signals;
Roberta Dobrescu707505b2014-09-23 01:55:55 +03001042 unsigned long flags;
Lidza Louina0b99d582013-08-01 17:00:20 -04001043
1044 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
1045 return;
1046
Lidza Louina0b99d582013-08-01 17:00:20 -04001047 /*
1048 * Do altpin switching. Altpin switches DCD and DSR.
1049 * This prolly breaks DSRPACE, so we should be more clever here.
1050 */
Roberta Dobrescu707505b2014-09-23 01:55:55 +03001051 spin_lock_irqsave(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -04001052 if (ch->ch_digi.digi_flags & DIGI_ALTPIN) {
Ebru Akagunduz446393e2014-10-01 23:04:48 +03001053 unsigned char mswap = signals;
Konrad Zapalowicz8aa5d0d2014-08-06 22:17:09 +02001054
Lidza Louina0b99d582013-08-01 17:00:20 -04001055 if (mswap & UART_MSR_DDCD) {
1056 msignals &= ~UART_MSR_DDCD;
1057 msignals |= UART_MSR_DDSR;
1058 }
1059 if (mswap & UART_MSR_DDSR) {
1060 msignals &= ~UART_MSR_DDSR;
1061 msignals |= UART_MSR_DDCD;
1062 }
1063 if (mswap & UART_MSR_DCD) {
1064 msignals &= ~UART_MSR_DCD;
1065 msignals |= UART_MSR_DSR;
1066 }
1067 if (mswap & UART_MSR_DSR) {
1068 msignals &= ~UART_MSR_DSR;
1069 msignals |= UART_MSR_DCD;
1070 }
1071 }
Roberta Dobrescu707505b2014-09-23 01:55:55 +03001072 spin_unlock_irqrestore(&ch->ch_lock, flags);
Lidza Louina5ca46fd2013-08-21 11:08:00 -04001073
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301074 /*
1075 * Scrub off lower bits. They signify delta's, which I don't
1076 * care about
1077 */
Lidza Louina0b99d582013-08-01 17:00:20 -04001078 signals &= 0xf0;
1079
Roberta Dobrescu707505b2014-09-23 01:55:55 +03001080 spin_lock_irqsave(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -04001081 if (msignals & UART_MSR_DCD)
1082 ch->ch_mistat |= UART_MSR_DCD;
1083 else
1084 ch->ch_mistat &= ~UART_MSR_DCD;
1085
1086 if (msignals & UART_MSR_DSR)
1087 ch->ch_mistat |= UART_MSR_DSR;
1088 else
1089 ch->ch_mistat &= ~UART_MSR_DSR;
1090
1091 if (msignals & UART_MSR_RI)
1092 ch->ch_mistat |= UART_MSR_RI;
1093 else
1094 ch->ch_mistat &= ~UART_MSR_RI;
1095
1096 if (msignals & UART_MSR_CTS)
1097 ch->ch_mistat |= UART_MSR_CTS;
1098 else
1099 ch->ch_mistat &= ~UART_MSR_CTS;
Roberta Dobrescu707505b2014-09-23 01:55:55 +03001100 spin_unlock_irqrestore(&ch->ch_lock, flags);
Lidza Louina0b99d582013-08-01 17:00:20 -04001101}
1102
Lidza Louina0b99d582013-08-01 17:00:20 -04001103/* Make the UART raise any of the output signals we want up */
1104static void cls_assert_modem_signals(struct channel_t *ch)
1105{
Ebru Akagunduz446393e2014-10-01 23:04:48 +03001106 unsigned char out;
Lidza Louina0b99d582013-08-01 17:00:20 -04001107
1108 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
1109 return;
1110
1111 out = ch->ch_mostat;
1112
1113 if (ch->ch_flags & CH_LOOPBACK)
1114 out |= UART_MCR_LOOP;
1115
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301116 writeb(out, &ch->ch_cls_uart->mcr);
Lidza Louina0b99d582013-08-01 17:00:20 -04001117
1118 /* Give time for the UART to actually drop the signals */
1119 udelay(10);
1120}
1121
Lidza Louina0b99d582013-08-01 17:00:20 -04001122static void cls_send_start_character(struct channel_t *ch)
1123{
1124 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
1125 return;
1126
1127 if (ch->ch_startc != _POSIX_VDISABLE) {
1128 ch->ch_xon_sends++;
1129 writeb(ch->ch_startc, &ch->ch_cls_uart->txrx);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301130 }
Lidza Louina0b99d582013-08-01 17:00:20 -04001131}
1132
Lidza Louina0b99d582013-08-01 17:00:20 -04001133static void cls_send_stop_character(struct channel_t *ch)
1134{
1135 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
1136 return;
1137
1138 if (ch->ch_stopc != _POSIX_VDISABLE) {
1139 ch->ch_xoff_sends++;
1140 writeb(ch->ch_stopc, &ch->ch_cls_uart->txrx);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301141 }
Lidza Louina0b99d582013-08-01 17:00:20 -04001142}
1143
Lidza Louina0b99d582013-08-01 17:00:20 -04001144/* Inits UART */
1145static void cls_uart_init(struct channel_t *ch)
1146{
Ebru Akagunduz446393e2014-10-01 23:04:48 +03001147 unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
1148 unsigned char isr_fcr = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -04001149
1150 writeb(0, &ch->ch_cls_uart->ier);
1151
1152 /*
1153 * The Enhanced Register Set may only be accessed when
1154 * the Line Control Register is set to 0xBFh.
1155 */
1156 writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
1157
1158 isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
Lidza Louina5ca46fd2013-08-21 11:08:00 -04001159
Lidza Louina0b99d582013-08-01 17:00:20 -04001160 /* Turn on Enhanced/Extended controls */
1161 isr_fcr |= (UART_EXAR654_EFR_ECB);
1162
1163 writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
1164
1165 /* Write old LCR value back out, which turns enhanced access off */
1166 writeb(lcrb, &ch->ch_cls_uart->lcr);
1167
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301168 /* Clear out UART and FIFO */
Lidza Louina0b99d582013-08-01 17:00:20 -04001169 readb(&ch->ch_cls_uart->txrx);
1170
Daeseok Younea753f22016-04-04 18:52:03 +09001171 writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
Sudip Mukherjeee352d3f2015-10-04 19:50:14 +05301172 &ch->ch_cls_uart->isr_fcr);
Lidza Louina0b99d582013-08-01 17:00:20 -04001173 udelay(10);
1174
1175 ch->ch_flags |= (CH_FIFO_ENABLED | CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
1176
1177 readb(&ch->ch_cls_uart->lsr);
1178 readb(&ch->ch_cls_uart->msr);
1179}
1180
Lidza Louina0b99d582013-08-01 17:00:20 -04001181/*
1182 * Turns off UART.
1183 */
1184static void cls_uart_off(struct channel_t *ch)
1185{
1186 writeb(0, &ch->ch_cls_uart->ier);
1187}
1188
Lidza Louina0b99d582013-08-01 17:00:20 -04001189/*
1190 * cls_get_uarts_bytes_left.
1191 * Returns 0 is nothing left in the FIFO, returns 1 otherwise.
1192 *
1193 * The channel lock MUST be held by the calling function.
1194 */
1195static uint cls_get_uart_bytes_left(struct channel_t *ch)
1196{
Ebru Akagunduz446393e2014-10-01 23:04:48 +03001197 unsigned char left = 0;
1198 unsigned char lsr = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -04001199
1200 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
1201 return 0;
1202
1203 lsr = readb(&ch->ch_cls_uart->lsr);
1204
1205 /* Determine whether the Transmitter is empty or not */
1206 if (!(lsr & UART_LSR_TEMT)) {
Archana kumari3d479102013-10-17 18:45:16 +05301207 if (ch->ch_flags & CH_TX_FIFO_EMPTY)
Lidza Louina0b99d582013-08-01 17:00:20 -04001208 tasklet_schedule(&ch->ch_bd->helper_tasklet);
Lidza Louina0b99d582013-08-01 17:00:20 -04001209 left = 1;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301210 } else {
Lidza Louina0b99d582013-08-01 17:00:20 -04001211 ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
1212 left = 0;
1213 }
1214
1215 return left;
1216}
1217
Lidza Louina0b99d582013-08-01 17:00:20 -04001218/*
1219 * cls_send_break.
1220 * Starts sending a break thru the UART.
1221 *
1222 * The channel lock MUST be held by the calling function.
1223 */
1224static void cls_send_break(struct channel_t *ch, int msecs)
1225{
1226 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
1227 return;
1228
1229 /*
1230 * If we receive a time of 0, this means turn off the break.
1231 */
1232 if (msecs == 0) {
1233 /* Turn break off, and unset some variables */
1234 if (ch->ch_flags & CH_BREAK_SENDING) {
Ebru Akagunduz446393e2014-10-01 23:04:48 +03001235 unsigned char temp = readb(&ch->ch_cls_uart->lcr);
Konrad Zapalowicz8aa5d0d2014-08-06 22:17:09 +02001236
Lidza Louina0b99d582013-08-01 17:00:20 -04001237 writeb((temp & ~UART_LCR_SBC), &ch->ch_cls_uart->lcr);
1238 ch->ch_flags &= ~(CH_BREAK_SENDING);
1239 ch->ch_stop_sending_break = 0;
Lidza Louina0b99d582013-08-01 17:00:20 -04001240 }
1241 return;
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301242 }
Lidza Louina0b99d582013-08-01 17:00:20 -04001243
1244 /*
1245 * Set the time we should stop sending the break.
1246 * If we are already sending a break, toss away the existing
1247 * time to stop, and use this new value instead.
1248 */
1249 ch->ch_stop_sending_break = jiffies + dgnc_jiffies_from_ms(msecs);
1250
1251 /* Tell the UART to start sending the break */
1252 if (!(ch->ch_flags & CH_BREAK_SENDING)) {
Ebru Akagunduz446393e2014-10-01 23:04:48 +03001253 unsigned char temp = readb(&ch->ch_cls_uart->lcr);
Konrad Zapalowicz8aa5d0d2014-08-06 22:17:09 +02001254
Lidza Louina0b99d582013-08-01 17:00:20 -04001255 writeb((temp | UART_LCR_SBC), &ch->ch_cls_uart->lcr);
1256 ch->ch_flags |= (CH_BREAK_SENDING);
Lidza Louina0b99d582013-08-01 17:00:20 -04001257 }
1258}
1259
Lidza Louina0b99d582013-08-01 17:00:20 -04001260/*
1261 * cls_send_immediate_char.
1262 * Sends a specific character as soon as possible to the UART,
1263 * jumping over any bytes that might be in the write queue.
1264 *
1265 * The channel lock MUST be held by the calling function.
1266 */
1267static void cls_send_immediate_char(struct channel_t *ch, unsigned char c)
1268{
1269 if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
1270 return;
1271
1272 writeb(c, &ch->ch_cls_uart->txrx);
1273}
1274
Lidza Louina03425f52013-09-09 15:01:22 -04001275static void cls_vpd(struct dgnc_board *brd)
Lidza Louina0b99d582013-08-01 17:00:20 -04001276{
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301277 ulong vpdbase; /* Start of io base of the card */
1278 u8 __iomem *re_map_vpdbase;/* Remapped memory of the card */
Lidza Louina0b99d582013-08-01 17:00:20 -04001279 int i = 0;
1280
Lidza Louina0b99d582013-08-01 17:00:20 -04001281 vpdbase = pci_resource_start(brd->pdev, 3);
1282
1283 /* No VPD */
1284 if (!vpdbase)
1285 return;
1286
1287 re_map_vpdbase = ioremap(vpdbase, 0x400);
1288
1289 if (!re_map_vpdbase)
1290 return;
1291
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301292 /* Store the VPD into our buffer */
1293 for (i = 0; i < 0x40; i++) {
Lidza Louina0b99d582013-08-01 17:00:20 -04001294 brd->vpd[i] = readb(re_map_vpdbase + i);
stalinsrinivasan.scb3714a2013-12-20 22:03:25 +05301295 pr_info("%x ", brd->vpd[i]);
1296 }
1297 pr_info("\n");
Lidza Louina0b99d582013-08-01 17:00:20 -04001298
Sudip Mukherjeee24bb0e2015-10-03 20:52:46 +05301299 iounmap(re_map_vpdbase);
Lidza Louina0b99d582013-08-01 17:00:20 -04001300}