diff options
| -rw-r--r-- | drivers/serial/sunsab.c | 107 |
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 | |||
| 1082 | static 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); | 1050 | out3: |
| 1087 | if (!(up->port.line & 1)) | 1051 | uart_remove_one_port(&sunsab_reg, &up[0].port); |
| 1088 | free_irq(up->port.irq, up); | 1052 | out2: |
| 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)); |
| 1056 | out1: | ||
| 1057 | of_iounmap(&op->resource[0], | ||
| 1058 | up[0].port.membase, | ||
| 1059 | sizeof(union sab82532_async_regs)); | ||
| 1060 | out: | ||
| 1061 | return err; | ||
| 1092 | } | 1062 | } |
| 1093 | 1063 | ||
| 1094 | static int __devexit sab_remove(struct of_device *op) | 1064 | static 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) { |
