diff options
author | Maciej W. Rozycki <macro@linux-mips.org> | 2008-02-07 03:15:12 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-07 11:42:24 -0500 |
commit | 54c0f37e9a200d74ec43cffa6526d9ad17a388a7 (patch) | |
tree | be288402e111b2b20350c296ccc325eda660f616 /drivers/serial | |
parent | 43d46ab1cdeb12b8d072cfdf84956073a1fa8866 (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')
-rw-r--r-- | drivers/serial/dz.c | 82 | ||||
-rw-r--r-- | drivers/serial/dz.h | 2 |
2 files changed, 46 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 | */ |
167 | static inline void dz_receive_chars(struct dz_port *dport_in) | 167 | static 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 | } |
diff --git a/drivers/serial/dz.h b/drivers/serial/dz.h index 6b34d50bf42d..1e836c3411d4 100644 --- a/drivers/serial/dz.h +++ b/drivers/serial/dz.h | |||
@@ -33,6 +33,8 @@ | |||
33 | #define DZ_FERR 0x2000 /* Frame error indicator */ | 33 | #define DZ_FERR 0x2000 /* Frame error indicator */ |
34 | #define DZ_PERR 0x1000 /* Parity error indicator */ | 34 | #define DZ_PERR 0x1000 /* Parity error indicator */ |
35 | 35 | ||
36 | #define DZ_BREAK 0x0800 /* BREAK event software flag */ | ||
37 | |||
36 | #define LINE(x) ((x & DZ_LINE_MASK) >> 8) /* Get the line number | 38 | #define LINE(x) ((x & DZ_LINE_MASK) >> 8) /* Get the line number |
37 | from the input buffer */ | 39 | from the input buffer */ |
38 | #define UCHAR(x) ((unsigned char)(x & DZ_RBUF_MASK)) | 40 | #define UCHAR(x) ((unsigned char)(x & DZ_RBUF_MASK)) |