aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/dz.c
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@linux-mips.org>2008-02-07 03:15:12 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-07 11:42:24 -0500
commit54c0f37e9a200d74ec43cffa6526d9ad17a388a7 (patch)
treebe288402e111b2b20350c296ccc325eda660f616 /drivers/serial/dz.c
parent43d46ab1cdeb12b8d072cfdf84956073a1fa8866 (diff)
dz: handle special conditions on reception correctly
Handle the read and ignore status masks correctly. Handle the BREAK condition as expected: a framing error with a null character is a BREAK, any other framing error is a framing error indeed. Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org> Cc: Jiri Slaby <jirislaby@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/serial/dz.c')
-rw-r--r--drivers/serial/dz.c82
1 files changed, 44 insertions, 38 deletions
diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c
index 656c342a80f8..ae3203b20134 100644
--- a/drivers/serial/dz.c
+++ b/drivers/serial/dz.c
@@ -166,6 +166,7 @@ static void dz_enable_ms(struct uart_port *port)
166 */ 166 */
167static inline void dz_receive_chars(struct dz_port *dport_in) 167static inline void dz_receive_chars(struct dz_port *dport_in)
168{ 168{
169 struct uart_port *uport;
169 struct dz_port *dport; 170 struct dz_port *dport;
170 struct tty_struct *tty = NULL; 171 struct tty_struct *tty = NULL;
171 struct uart_icount *icount; 172 struct uart_icount *icount;
@@ -176,57 +177,56 @@ static inline void dz_receive_chars(struct dz_port *dport_in)
176 177
177 while ((status = dz_in(dport_in, DZ_RBUF)) & DZ_DVAL) { 178 while ((status = dz_in(dport_in, DZ_RBUF)) & DZ_DVAL) {
178 dport = &dz_ports[LINE(status)]; 179 dport = &dz_ports[LINE(status)];
179 tty = dport->port.info->tty; /* point to the proper dev */ 180 uport = &dport->port;
181 tty = uport->info->tty; /* point to the proper dev */
180 182
181 ch = UCHAR(status); /* grab the char */ 183 ch = UCHAR(status); /* grab the char */
184 flag = TTY_NORMAL;
182 185
183 icount = &dport->port.icount; 186 icount = &uport->icount;
184 icount->rx++; 187 icount->rx++;
185 188
186 flag = TTY_NORMAL; 189 if (unlikely(status & (DZ_OERR | DZ_FERR | DZ_PERR))) {
187 if (status & DZ_FERR) { /* frame error */ 190
188 /* 191 /*
189 * There is no separate BREAK status bit, so 192 * There is no separate BREAK status bit, so treat
190 * treat framing errors as BREAKs for Magic SysRq 193 * null characters with framing errors as BREAKs;
191 * and SAK; normally, otherwise. 194 * normally, otherwise. For this move the Framing
195 * Error bit to a simulated BREAK bit.
192 */ 196 */
193 if (uart_handle_break(&dport->port)) 197 if (!ch) {
194 continue; 198 status |= (status & DZ_FERR) >>
195 if (dport->port.flags & UPF_SAK) 199 (ffs(DZ_FERR) - ffs(DZ_BREAK));
200 status &= ~DZ_FERR;
201 }
202
203 /* Handle SysRq/SAK & keep track of the statistics. */
204 if (status & DZ_BREAK) {
205 icount->brk++;
206 if (uart_handle_break(uport))
207 continue;
208 } else if (status & DZ_FERR)
209 icount->frame++;
210 else if (status & DZ_PERR)
211 icount->parity++;
212 if (status & DZ_OERR)
213 icount->overrun++;
214
215 status &= uport->read_status_mask;
216 if (status & DZ_BREAK)
196 flag = TTY_BREAK; 217 flag = TTY_BREAK;
197 else 218 else if (status & DZ_FERR)
198 flag = TTY_FRAME; 219 flag = TTY_FRAME;
199 } else if (status & DZ_OERR) /* overrun error */ 220 else if (status & DZ_PERR)
200 flag = TTY_OVERRUN; 221 flag = TTY_PARITY;
201 else if (status & DZ_PERR) /* parity error */ 222
202 flag = TTY_PARITY;
203
204 /* keep track of the statistics */
205 switch (flag) {
206 case TTY_FRAME:
207 icount->frame++;
208 break;
209 case TTY_PARITY:
210 icount->parity++;
211 break;
212 case TTY_OVERRUN:
213 icount->overrun++;
214 break;
215 case TTY_BREAK:
216 icount->brk++;
217 break;
218 default:
219 break;
220 } 223 }
221 224
222 if (uart_handle_sysrq_char(&dport->port, ch)) 225 if (uart_handle_sysrq_char(uport, ch))
223 continue; 226 continue;
224 227
225 if ((status & dport->port.ignore_status_mask) == 0) { 228 uart_insert_char(uport, status, DZ_OERR, ch, flag);
226 uart_insert_char(&dport->port, 229 lines_rx[LINE(status)] = 1;
227 status, DZ_OERR, ch, flag);
228 lines_rx[LINE(status)] = 1;
229 }
230 } 230 }
231 for (i = 0; i < DZ_NB_PORT; i++) 231 for (i = 0; i < DZ_NB_PORT; i++)
232 if (lines_rx[i]) 232 if (lines_rx[i])
@@ -556,11 +556,17 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
556 dport->port.read_status_mask = DZ_OERR; 556 dport->port.read_status_mask = DZ_OERR;
557 if (termios->c_iflag & INPCK) 557 if (termios->c_iflag & INPCK)
558 dport->port.read_status_mask |= DZ_FERR | DZ_PERR; 558 dport->port.read_status_mask |= DZ_FERR | DZ_PERR;
559 if (termios->c_iflag & (BRKINT | PARMRK))
560 dport->port.read_status_mask |= DZ_BREAK;
559 561
560 /* characters to ignore */ 562 /* characters to ignore */
561 uport->ignore_status_mask = 0; 563 uport->ignore_status_mask = 0;
564 if ((termios->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
565 dport->port.ignore_status_mask |= DZ_OERR;
562 if (termios->c_iflag & IGNPAR) 566 if (termios->c_iflag & IGNPAR)
563 dport->port.ignore_status_mask |= DZ_FERR | DZ_PERR; 567 dport->port.ignore_status_mask |= DZ_FERR | DZ_PERR;
568 if (termios->c_iflag & IGNBRK)
569 dport->port.ignore_status_mask |= DZ_BREAK;
564 570
565 spin_unlock_irqrestore(&dport->port.lock, flags); 571 spin_unlock_irqrestore(&dport->port.lock, flags);
566} 572}