aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/sunsab.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2007-09-17 19:47:07 -0400
committerDavid S. Miller <davem@davemloft.net>2007-09-17 19:47:07 -0400
commit9c5b34806c28195e4d0f2deaa41d8158ca5874e1 (patch)
treed12e521ee1adcf5130c4c2ae4cc360cf50db07a7 /drivers/serial/sunsab.c
parentc2f828977ba5d17c13debba374ea252d18e5ccfb (diff)
[SUNSAB]: Fix several bugs.
* don't register irq until ->startup() (and release in ->shutdown()). That avoids oopsen with the current tree when interrupt comes before we'd set up the data structures for ttyb. * handle console=ttyS... even when OBP talks to screen/keyboard * register irq handler for each port, let kernel/irq/handle.c call it for both if needed. Kills code duplication in sunsab_interrupt(). BTW, there'd been bitrot in it - ttya handling had stopped calling check_status() on BRK (correctly), ttyb copy of that code had kept the bogus call in that case. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/serial/sunsab.c')
-rw-r--r--drivers/serial/sunsab.c107
1 files changed, 42 insertions, 65 deletions
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index bca57bb94939..e348ba684050 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -58,6 +58,7 @@ struct uart_sunsab_port {
58 unsigned char interrupt_mask1;/* ISR1 masking */ 58 unsigned char interrupt_mask1;/* ISR1 masking */
59 unsigned char pvr_dtr_bit; /* Which PVR bit is DTR */ 59 unsigned char pvr_dtr_bit; /* Which PVR bit is DTR */
60 unsigned char pvr_dsr_bit; /* Which PVR bit is DSR */ 60 unsigned char pvr_dsr_bit; /* Which PVR bit is DSR */
61 unsigned int gis_shift;
61 int type; /* SAB82532 version */ 62 int type; /* SAB82532 version */
62 63
63 /* Setting configuration bits while the transmitter is active 64 /* Setting configuration bits while the transmitter is active
@@ -305,13 +306,15 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id)
305 struct tty_struct *tty; 306 struct tty_struct *tty;
306 union sab82532_irq_status status; 307 union sab82532_irq_status status;
307 unsigned long flags; 308 unsigned long flags;
309 unsigned char gis;
308 310
309 spin_lock_irqsave(&up->port.lock, flags); 311 spin_lock_irqsave(&up->port.lock, flags);
310 312
311 status.stat = 0; 313 status.stat = 0;
312 if (readb(&up->regs->r.gis) & SAB82532_GIS_ISA0) 314 gis = readb(&up->regs->r.gis) >> up->gis_shift;
315 if (gis & 1)
313 status.sreg.isr0 = readb(&up->regs->r.isr0); 316 status.sreg.isr0 = readb(&up->regs->r.isr0);
314 if (readb(&up->regs->r.gis) & SAB82532_GIS_ISA1) 317 if (gis & 2)
315 status.sreg.isr1 = readb(&up->regs->r.isr1); 318 status.sreg.isr1 = readb(&up->regs->r.isr1);
316 319
317 tty = NULL; 320 tty = NULL;
@@ -327,35 +330,6 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id)
327 transmit_chars(up, &status); 330 transmit_chars(up, &status);
328 } 331 }
329 332
330 spin_unlock(&up->port.lock);
331
332 if (tty)
333 tty_flip_buffer_push(tty);
334
335 up++;
336
337 spin_lock(&up->port.lock);
338
339 status.stat = 0;
340 if (readb(&up->regs->r.gis) & SAB82532_GIS_ISB0)
341 status.sreg.isr0 = readb(&up->regs->r.isr0);
342 if (readb(&up->regs->r.gis) & SAB82532_GIS_ISB1)
343 status.sreg.isr1 = readb(&up->regs->r.isr1);
344
345 tty = NULL;
346 if (status.stat) {
347 if ((status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |
348 SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) ||
349 (status.sreg.isr1 & SAB82532_ISR1_BRK))
350
351 tty = receive_chars(up, &status);
352 if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) ||
353 (status.sreg.isr1 & (SAB82532_ISR1_BRK | SAB82532_ISR1_CSC)))
354 check_status(up, &status);
355 if (status.sreg.isr1 & (SAB82532_ISR1_ALLS | SAB82532_ISR1_XPR))
356 transmit_chars(up, &status);
357 }
358
359 spin_unlock_irqrestore(&up->port.lock, flags); 333 spin_unlock_irqrestore(&up->port.lock, flags);
360 334
361 if (tty) 335 if (tty)
@@ -539,6 +513,10 @@ static int sunsab_startup(struct uart_port *port)
539 struct uart_sunsab_port *up = (struct uart_sunsab_port *) port; 513 struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
540 unsigned long flags; 514 unsigned long flags;
541 unsigned char tmp; 515 unsigned char tmp;
516 int err = request_irq(up->port.irq, sunsab_interrupt,
517 IRQF_SHARED, "sab", up);
518 if (err)
519 return err;
542 520
543 spin_lock_irqsave(&up->port.lock, flags); 521 spin_lock_irqsave(&up->port.lock, flags);
544 522
@@ -641,6 +619,7 @@ static void sunsab_shutdown(struct uart_port *port)
641#endif 619#endif
642 620
643 spin_unlock_irqrestore(&up->port.lock, flags); 621 spin_unlock_irqrestore(&up->port.lock, flags);
622 free_irq(up->port.irq, up);
644} 623}
645 624
646/* 625/*
@@ -1008,9 +987,11 @@ static int __devinit sunsab_init_one(struct uart_sunsab_port *up,
1008 if ((up->port.line & 0x1) == 0) { 987 if ((up->port.line & 0x1) == 0) {
1009 up->pvr_dsr_bit = (1 << 0); 988 up->pvr_dsr_bit = (1 << 0);
1010 up->pvr_dtr_bit = (1 << 1); 989 up->pvr_dtr_bit = (1 << 1);
990 up->gis_shift = 2;
1011 } else { 991 } else {
1012 up->pvr_dsr_bit = (1 << 3); 992 up->pvr_dsr_bit = (1 << 3);
1013 up->pvr_dtr_bit = (1 << 2); 993 up->pvr_dtr_bit = (1 << 2);
994 up->gis_shift = 0;
1014 } 995 }
1015 up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4); 996 up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4);
1016 writeb(up->cached_pvr, &up->regs->w.pvr); 997 writeb(up->cached_pvr, &up->regs->w.pvr);
@@ -1023,19 +1004,6 @@ static int __devinit sunsab_init_one(struct uart_sunsab_port *up,
1023 up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT; 1004 up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT;
1024 up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT; 1005 up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT;
1025 1006
1026 if (!(up->port.line & 0x01)) {
1027 int err;
1028
1029 err = request_irq(up->port.irq, sunsab_interrupt,
1030 IRQF_SHARED, "sab", up);
1031 if (err) {
1032 of_iounmap(&op->resource[0],
1033 up->port.membase,
1034 sizeof(union sab82532_async_regs));
1035 return err;
1036 }
1037 }
1038
1039 return 0; 1007 return 0;
1040} 1008}
1041 1009
@@ -1051,52 +1019,60 @@ static int __devinit sab_probe(struct of_device *op, const struct of_device_id *
1051 0, 1019 0,
1052 (inst * 2) + 0); 1020 (inst * 2) + 0);
1053 if (err) 1021 if (err)
1054 return err; 1022 goto out;
1055 1023
1056 err = sunsab_init_one(&up[1], op, 1024 err = sunsab_init_one(&up[1], op,
1057 sizeof(union sab82532_async_regs), 1025 sizeof(union sab82532_async_regs),
1058 (inst * 2) + 1); 1026 (inst * 2) + 1);
1059 if (err) { 1027 if (err)
1060 of_iounmap(&op->resource[0], 1028 goto out1;
1061 up[0].port.membase,
1062 sizeof(union sab82532_async_regs));
1063 free_irq(up[0].port.irq, &up[0]);
1064 return err;
1065 }
1066 1029
1067 sunserial_console_match(SUNSAB_CONSOLE(), op->node, 1030 sunserial_console_match(SUNSAB_CONSOLE(), op->node,
1068 &sunsab_reg, up[0].port.line); 1031 &sunsab_reg, up[0].port.line);
1069 uart_add_one_port(&sunsab_reg, &up[0].port);
1070 1032
1071 sunserial_console_match(SUNSAB_CONSOLE(), op->node, 1033 sunserial_console_match(SUNSAB_CONSOLE(), op->node,
1072 &sunsab_reg, up[1].port.line); 1034 &sunsab_reg, up[1].port.line);
1073 uart_add_one_port(&sunsab_reg, &up[1].port); 1035
1036 err = uart_add_one_port(&sunsab_reg, &up[0].port);
1037 if (err)
1038 goto out2;
1039
1040 err = uart_add_one_port(&sunsab_reg, &up[1].port);
1041 if (err)
1042 goto out3;
1074 1043
1075 dev_set_drvdata(&op->dev, &up[0]); 1044 dev_set_drvdata(&op->dev, &up[0]);
1076 1045
1077 inst++; 1046 inst++;
1078 1047
1079 return 0; 1048 return 0;
1080}
1081
1082static void __devexit sab_remove_one(struct uart_sunsab_port *up)
1083{
1084 struct of_device *op = to_of_device(up->port.dev);
1085 1049
1086 uart_remove_one_port(&sunsab_reg, &up->port); 1050out3:
1087 if (!(up->port.line & 1)) 1051 uart_remove_one_port(&sunsab_reg, &up[0].port);
1088 free_irq(up->port.irq, up); 1052out2:
1089 of_iounmap(&op->resource[0], 1053 of_iounmap(&op->resource[0],
1090 up->port.membase, 1054 up[1].port.membase,
1091 sizeof(union sab82532_async_regs)); 1055 sizeof(union sab82532_async_regs));
1056out1:
1057 of_iounmap(&op->resource[0],
1058 up[0].port.membase,
1059 sizeof(union sab82532_async_regs));
1060out:
1061 return err;
1092} 1062}
1093 1063
1094static int __devexit sab_remove(struct of_device *op) 1064static int __devexit sab_remove(struct of_device *op)
1095{ 1065{
1096 struct uart_sunsab_port *up = dev_get_drvdata(&op->dev); 1066 struct uart_sunsab_port *up = dev_get_drvdata(&op->dev);
1097 1067
1098 sab_remove_one(&up[0]); 1068 uart_remove_one_port(&sunsab_reg, &up[1].port);
1099 sab_remove_one(&up[1]); 1069 uart_remove_one_port(&sunsab_reg, &up[0].port);
1070 of_iounmap(&op->resource[0],
1071 up[1].port.membase,
1072 sizeof(union sab82532_async_regs));
1073 of_iounmap(&op->resource[0],
1074 up[0].port.membase,
1075 sizeof(union sab82532_async_regs));
1100 1076
1101 dev_set_drvdata(&op->dev, NULL); 1077 dev_set_drvdata(&op->dev, NULL);
1102 1078
@@ -1143,6 +1119,7 @@ static int __init sunsab_init(void)
1143 1119
1144 sunsab_reg.minor = sunserial_current_minor; 1120 sunsab_reg.minor = sunserial_current_minor;
1145 sunsab_reg.nr = num_channels; 1121 sunsab_reg.nr = num_channels;
1122 sunsab_reg.cons = SUNSAB_CONSOLE();
1146 1123
1147 err = uart_register_driver(&sunsab_reg); 1124 err = uart_register_driver(&sunsab_reg);
1148 if (err) { 1125 if (err) {