diff options
Diffstat (limited to 'drivers/tty/hvc/hvcs.c')
| -rw-r--r-- | drivers/tty/hvc/hvcs.c | 82 |
1 files changed, 49 insertions, 33 deletions
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index d56788c83974..cab5c7adf8e8 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c | |||
| @@ -1102,27 +1102,20 @@ static struct hvcs_struct *hvcs_get_by_index(int index) | |||
| 1102 | return NULL; | 1102 | return NULL; |
| 1103 | } | 1103 | } |
| 1104 | 1104 | ||
| 1105 | /* | 1105 | static int hvcs_install(struct tty_driver *driver, struct tty_struct *tty) |
| 1106 | * This is invoked via the tty_open interface when a user app connects to the | ||
| 1107 | * /dev node. | ||
| 1108 | */ | ||
| 1109 | static int hvcs_open(struct tty_struct *tty, struct file *filp) | ||
| 1110 | { | 1106 | { |
| 1111 | struct hvcs_struct *hvcsd; | 1107 | struct hvcs_struct *hvcsd; |
| 1112 | int rc, retval = 0; | ||
| 1113 | unsigned long flags; | ||
| 1114 | unsigned int irq; | ||
| 1115 | struct vio_dev *vdev; | 1108 | struct vio_dev *vdev; |
| 1116 | unsigned long unit_address; | 1109 | unsigned long unit_address, flags; |
| 1117 | 1110 | unsigned int irq; | |
| 1118 | if (tty->driver_data) | 1111 | int retval; |
| 1119 | goto fast_open; | ||
| 1120 | 1112 | ||
| 1121 | /* | 1113 | /* |
| 1122 | * Is there a vty-server that shares the same index? | 1114 | * Is there a vty-server that shares the same index? |
| 1123 | * This function increments the kref index. | 1115 | * This function increments the kref index. |
| 1124 | */ | 1116 | */ |
| 1125 | if (!(hvcsd = hvcs_get_by_index(tty->index))) { | 1117 | hvcsd = hvcs_get_by_index(tty->index); |
| 1118 | if (!hvcsd) { | ||
| 1126 | printk(KERN_WARNING "HVCS: open failed, no device associated" | 1119 | printk(KERN_WARNING "HVCS: open failed, no device associated" |
| 1127 | " with tty->index %d.\n", tty->index); | 1120 | " with tty->index %d.\n", tty->index); |
| 1128 | return -ENODEV; | 1121 | return -ENODEV; |
| @@ -1130,11 +1123,16 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) | |||
| 1130 | 1123 | ||
| 1131 | spin_lock_irqsave(&hvcsd->lock, flags); | 1124 | spin_lock_irqsave(&hvcsd->lock, flags); |
| 1132 | 1125 | ||
| 1133 | if (hvcsd->connected == 0) | 1126 | if (hvcsd->connected == 0) { |
| 1134 | if ((retval = hvcs_partner_connect(hvcsd))) | 1127 | retval = hvcs_partner_connect(hvcsd); |
| 1135 | goto error_release; | 1128 | if (retval) { |
| 1129 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
| 1130 | printk(KERN_WARNING "HVCS: partner connect failed.\n"); | ||
| 1131 | goto err_put; | ||
| 1132 | } | ||
| 1133 | } | ||
| 1136 | 1134 | ||
| 1137 | hvcsd->port.count = 1; | 1135 | hvcsd->port.count = 0; |
| 1138 | hvcsd->port.tty = tty; | 1136 | hvcsd->port.tty = tty; |
| 1139 | tty->driver_data = hvcsd; | 1137 | tty->driver_data = hvcsd; |
| 1140 | 1138 | ||
| @@ -1155,37 +1153,48 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) | |||
| 1155 | * This must be done outside of the spinlock because it requests irqs | 1153 | * This must be done outside of the spinlock because it requests irqs |
| 1156 | * and will grab the spinlock and free the connection if it fails. | 1154 | * and will grab the spinlock and free the connection if it fails. |
| 1157 | */ | 1155 | */ |
| 1158 | if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) { | 1156 | retval = hvcs_enable_device(hvcsd, unit_address, irq, vdev); |
| 1159 | tty_port_put(&hvcsd->port); | 1157 | if (retval) { |
| 1160 | printk(KERN_WARNING "HVCS: enable device failed.\n"); | 1158 | printk(KERN_WARNING "HVCS: enable device failed.\n"); |
| 1161 | return rc; | 1159 | goto err_put; |
| 1162 | } | 1160 | } |
| 1163 | 1161 | ||
| 1164 | goto open_success; | 1162 | retval = tty_port_install(&hvcsd->port, driver, tty); |
| 1163 | if (retval) | ||
| 1164 | goto err_irq; | ||
| 1165 | 1165 | ||
| 1166 | fast_open: | 1166 | return 0; |
| 1167 | hvcsd = tty->driver_data; | 1167 | err_irq: |
| 1168 | spin_lock_irqsave(&hvcsd->lock, flags); | ||
| 1169 | vio_disable_interrupts(hvcsd->vdev); | ||
| 1170 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
| 1171 | free_irq(irq, hvcsd); | ||
| 1172 | err_put: | ||
| 1173 | tty_port_put(&hvcsd->port); | ||
| 1174 | |||
| 1175 | return retval; | ||
| 1176 | } | ||
| 1177 | |||
| 1178 | /* | ||
| 1179 | * This is invoked via the tty_open interface when a user app connects to the | ||
| 1180 | * /dev node. | ||
| 1181 | */ | ||
| 1182 | static int hvcs_open(struct tty_struct *tty, struct file *filp) | ||
| 1183 | { | ||
| 1184 | struct hvcs_struct *hvcsd = tty->driver_data; | ||
| 1185 | unsigned long flags; | ||
| 1168 | 1186 | ||
| 1169 | spin_lock_irqsave(&hvcsd->lock, flags); | 1187 | spin_lock_irqsave(&hvcsd->lock, flags); |
| 1170 | tty_port_get(&hvcsd->port); | ||
| 1171 | hvcsd->port.count++; | 1188 | hvcsd->port.count++; |
| 1172 | hvcsd->todo_mask |= HVCS_SCHED_READ; | 1189 | hvcsd->todo_mask |= HVCS_SCHED_READ; |
| 1173 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 1190 | spin_unlock_irqrestore(&hvcsd->lock, flags); |
| 1174 | 1191 | ||
| 1175 | open_success: | ||
| 1176 | hvcs_kick(); | 1192 | hvcs_kick(); |
| 1177 | 1193 | ||
| 1178 | printk(KERN_INFO "HVCS: vty-server@%X connection opened.\n", | 1194 | printk(KERN_INFO "HVCS: vty-server@%X connection opened.\n", |
| 1179 | hvcsd->vdev->unit_address ); | 1195 | hvcsd->vdev->unit_address ); |
| 1180 | 1196 | ||
| 1181 | return 0; | 1197 | return 0; |
| 1182 | |||
| 1183 | error_release: | ||
| 1184 | spin_unlock_irqrestore(&hvcsd->lock, flags); | ||
| 1185 | tty_port_put(&hvcsd->port); | ||
| 1186 | |||
| 1187 | printk(KERN_WARNING "HVCS: partner connect failed.\n"); | ||
| 1188 | return retval; | ||
| 1189 | } | 1198 | } |
| 1190 | 1199 | ||
| 1191 | static void hvcs_close(struct tty_struct *tty, struct file *filp) | 1200 | static void hvcs_close(struct tty_struct *tty, struct file *filp) |
| @@ -1236,7 +1245,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) | |||
| 1236 | tty->driver_data = NULL; | 1245 | tty->driver_data = NULL; |
| 1237 | 1246 | ||
| 1238 | free_irq(irq, hvcsd); | 1247 | free_irq(irq, hvcsd); |
| 1239 | tty_port_put(&hvcsd->port); | ||
| 1240 | return; | 1248 | return; |
| 1241 | } else if (hvcsd->port.count < 0) { | 1249 | } else if (hvcsd->port.count < 0) { |
| 1242 | printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" | 1250 | printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" |
| @@ -1245,6 +1253,12 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) | |||
| 1245 | } | 1253 | } |
| 1246 | 1254 | ||
| 1247 | spin_unlock_irqrestore(&hvcsd->lock, flags); | 1255 | spin_unlock_irqrestore(&hvcsd->lock, flags); |
| 1256 | } | ||
| 1257 | |||
| 1258 | static void hvcs_cleanup(struct tty_struct * tty) | ||
| 1259 | { | ||
| 1260 | struct hvcs_struct *hvcsd = tty->driver_data; | ||
| 1261 | |||
| 1248 | tty_port_put(&hvcsd->port); | 1262 | tty_port_put(&hvcsd->port); |
| 1249 | } | 1263 | } |
| 1250 | 1264 | ||
| @@ -1431,8 +1445,10 @@ static int hvcs_chars_in_buffer(struct tty_struct *tty) | |||
| 1431 | } | 1445 | } |
| 1432 | 1446 | ||
| 1433 | static const struct tty_operations hvcs_ops = { | 1447 | static const struct tty_operations hvcs_ops = { |
| 1448 | .install = hvcs_install, | ||
| 1434 | .open = hvcs_open, | 1449 | .open = hvcs_open, |
| 1435 | .close = hvcs_close, | 1450 | .close = hvcs_close, |
| 1451 | .cleanup = hvcs_cleanup, | ||
| 1436 | .hangup = hvcs_hangup, | 1452 | .hangup = hvcs_hangup, |
| 1437 | .write = hvcs_write, | 1453 | .write = hvcs_write, |
| 1438 | .write_room = hvcs_write_room, | 1454 | .write_room = hvcs_write_room, |
