diff options
author | Jiri Slaby <jirislaby@gmail.com> | 2008-04-30 03:53:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-30 11:29:43 -0400 |
commit | a8f5cda067e2eeefe49fe386caf0f61fc5c825e0 (patch) | |
tree | 980c91f37b242ae9e6d7efa6cbb62f8550f3359c | |
parent | 2a5413416b6b2fd8a5a38601a4fe3b56a52cfb86 (diff) |
Char: moxa, rework open/close
- add locking to open/close/hangup and ioctl (tiocm)
- add pci hot-un-plug support (hangup on board remove, wait for openers)
- cleanup block_till_ready
- move close code common to close/hangup into separate function to be
able to call it from open when hangup occurs while block_till_ready
- let ldisc flush on tty layer, it will do it after we return
Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
Tested-by: Oyvind Aabling <Oyvind.Aabling@uni-c.dk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/char/moxa.c | 320 |
1 files changed, 158 insertions, 162 deletions
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index abcc16eba44f..af8077c25cbe 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c | |||
@@ -42,7 +42,6 @@ | |||
42 | #include <linux/pci.h> | 42 | #include <linux/pci.h> |
43 | #include <linux/init.h> | 43 | #include <linux/init.h> |
44 | #include <linux/bitops.h> | 44 | #include <linux/bitops.h> |
45 | #include <linux/completion.h> | ||
46 | 45 | ||
47 | #include <asm/system.h> | 46 | #include <asm/system.h> |
48 | #include <asm/io.h> | 47 | #include <asm/io.h> |
@@ -134,13 +133,11 @@ struct moxa_port { | |||
134 | 133 | ||
135 | int type; | 134 | int type; |
136 | int close_delay; | 135 | int close_delay; |
137 | int count; | 136 | unsigned int count; |
138 | int blocked_open; | ||
139 | int asyncflags; | 137 | int asyncflags; |
140 | int cflag; | 138 | int cflag; |
141 | unsigned long statusflags; | 139 | unsigned long statusflags; |
142 | wait_queue_head_t open_wait; | 140 | wait_queue_head_t open_wait; |
143 | struct completion close_wait; | ||
144 | 141 | ||
145 | u8 DCDState; | 142 | u8 DCDState; |
146 | u8 lineCtrl; | 143 | u8 lineCtrl; |
@@ -167,6 +164,7 @@ static int ttymajor = MOXAMAJOR; | |||
167 | static struct mon_str moxaLog; | 164 | static struct mon_str moxaLog; |
168 | static unsigned int moxaFuncTout = HZ / 2; | 165 | static unsigned int moxaFuncTout = HZ / 2; |
169 | static unsigned int moxaLowWaterChk; | 166 | static unsigned int moxaLowWaterChk; |
167 | static DEFINE_MUTEX(moxa_openlock); | ||
170 | /* Variables for insmod */ | 168 | /* Variables for insmod */ |
171 | #ifdef MODULE | 169 | #ifdef MODULE |
172 | static unsigned long baseaddr[MAX_BOARDS]; | 170 | static unsigned long baseaddr[MAX_BOARDS]; |
@@ -209,8 +207,6 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file, | |||
209 | unsigned int set, unsigned int clear); | 207 | unsigned int set, unsigned int clear); |
210 | static void moxa_poll(unsigned long); | 208 | static void moxa_poll(unsigned long); |
211 | static void moxa_set_tty_param(struct tty_struct *, struct ktermios *); | 209 | static void moxa_set_tty_param(struct tty_struct *, struct ktermios *); |
212 | static int moxa_block_till_ready(struct tty_struct *, struct file *, | ||
213 | struct moxa_port *); | ||
214 | static void moxa_setup_empty_event(struct tty_struct *); | 210 | static void moxa_setup_empty_event(struct tty_struct *); |
215 | static void moxa_shut_down(struct moxa_port *); | 211 | static void moxa_shut_down(struct moxa_port *); |
216 | /* | 212 | /* |
@@ -280,7 +276,7 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file, | |||
280 | { | 276 | { |
281 | struct moxa_port *ch = tty->driver_data; | 277 | struct moxa_port *ch = tty->driver_data; |
282 | void __user *argp = (void __user *)arg; | 278 | void __user *argp = (void __user *)arg; |
283 | int status; | 279 | int status, ret = 0; |
284 | 280 | ||
285 | if (tty->index == MAX_PORTS) { | 281 | if (tty->index == MAX_PORTS) { |
286 | if (cmd != MOXA_GETDATACOUNT && cmd != MOXA_GET_IOQUEUE && | 282 | if (cmd != MOXA_GETDATACOUNT && cmd != MOXA_GET_IOQUEUE && |
@@ -292,17 +288,19 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file, | |||
292 | switch (cmd) { | 288 | switch (cmd) { |
293 | case MOXA_GETDATACOUNT: | 289 | case MOXA_GETDATACOUNT: |
294 | moxaLog.tick = jiffies; | 290 | moxaLog.tick = jiffies; |
295 | return copy_to_user(argp, &moxaLog, sizeof(moxaLog)) ? | 291 | if (copy_to_user(argp, &moxaLog, sizeof(moxaLog))) |
296 | -EFAULT : 0; | 292 | ret = -EFAULT; |
293 | break; | ||
297 | case MOXA_FLUSH_QUEUE: | 294 | case MOXA_FLUSH_QUEUE: |
298 | MoxaPortFlushData(ch, arg); | 295 | MoxaPortFlushData(ch, arg); |
299 | return 0; | 296 | break; |
300 | case MOXA_GET_IOQUEUE: { | 297 | case MOXA_GET_IOQUEUE: { |
301 | struct moxaq_str __user *argm = argp; | 298 | struct moxaq_str __user *argm = argp; |
302 | struct moxaq_str tmp; | 299 | struct moxaq_str tmp; |
303 | struct moxa_port *p; | 300 | struct moxa_port *p; |
304 | unsigned int i, j; | 301 | unsigned int i, j; |
305 | 302 | ||
303 | mutex_lock(&moxa_openlock); | ||
306 | for (i = 0; i < MAX_BOARDS; i++) { | 304 | for (i = 0; i < MAX_BOARDS; i++) { |
307 | p = moxa_boards[i].ports; | 305 | p = moxa_boards[i].ports; |
308 | for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { | 306 | for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { |
@@ -311,23 +309,29 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file, | |||
311 | tmp.inq = MoxaPortRxQueue(p); | 309 | tmp.inq = MoxaPortRxQueue(p); |
312 | tmp.outq = MoxaPortTxQueue(p); | 310 | tmp.outq = MoxaPortTxQueue(p); |
313 | } | 311 | } |
314 | if (copy_to_user(argm, &tmp, sizeof(tmp))) | 312 | if (copy_to_user(argm, &tmp, sizeof(tmp))) { |
313 | mutex_unlock(&moxa_openlock); | ||
315 | return -EFAULT; | 314 | return -EFAULT; |
315 | } | ||
316 | } | 316 | } |
317 | } | 317 | } |
318 | return 0; | 318 | mutex_unlock(&moxa_openlock); |
319 | break; | ||
319 | } case MOXA_GET_OQUEUE: | 320 | } case MOXA_GET_OQUEUE: |
320 | status = MoxaPortTxQueue(ch); | 321 | status = MoxaPortTxQueue(ch); |
321 | return put_user(status, (unsigned long __user *)argp); | 322 | ret = put_user(status, (unsigned long __user *)argp); |
323 | break; | ||
322 | case MOXA_GET_IQUEUE: | 324 | case MOXA_GET_IQUEUE: |
323 | status = MoxaPortRxQueue(ch); | 325 | status = MoxaPortRxQueue(ch); |
324 | return put_user(status, (unsigned long __user *)argp); | 326 | ret = put_user(status, (unsigned long __user *)argp); |
327 | break; | ||
325 | case MOXA_GETMSTATUS: { | 328 | case MOXA_GETMSTATUS: { |
326 | struct mxser_mstatus __user *argm = argp; | 329 | struct mxser_mstatus __user *argm = argp; |
327 | struct mxser_mstatus tmp; | 330 | struct mxser_mstatus tmp; |
328 | struct moxa_port *p; | 331 | struct moxa_port *p; |
329 | unsigned int i, j; | 332 | unsigned int i, j; |
330 | 333 | ||
334 | mutex_lock(&moxa_openlock); | ||
331 | for (i = 0; i < MAX_BOARDS; i++) { | 335 | for (i = 0; i < MAX_BOARDS; i++) { |
332 | p = moxa_boards[i].ports; | 336 | p = moxa_boards[i].ports; |
333 | for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { | 337 | for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { |
@@ -348,18 +352,29 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file, | |||
348 | else | 352 | else |
349 | tmp.cflag = p->tty->termios->c_cflag; | 353 | tmp.cflag = p->tty->termios->c_cflag; |
350 | copy: | 354 | copy: |
351 | if (copy_to_user(argm, &tmp, sizeof(tmp))) | 355 | if (copy_to_user(argm, &tmp, sizeof(tmp))) { |
356 | mutex_unlock(&moxa_openlock); | ||
352 | return -EFAULT; | 357 | return -EFAULT; |
358 | } | ||
353 | } | 359 | } |
354 | } | 360 | } |
355 | return 0; | 361 | mutex_unlock(&moxa_openlock); |
362 | break; | ||
356 | } | 363 | } |
357 | case TIOCGSERIAL: | 364 | case TIOCGSERIAL: |
358 | return moxa_get_serial_info(ch, argp); | 365 | mutex_lock(&moxa_openlock); |
366 | ret = moxa_get_serial_info(ch, argp); | ||
367 | mutex_unlock(&moxa_openlock); | ||
368 | break; | ||
359 | case TIOCSSERIAL: | 369 | case TIOCSSERIAL: |
360 | return moxa_set_serial_info(ch, argp); | 370 | mutex_lock(&moxa_openlock); |
371 | ret = moxa_set_serial_info(ch, argp); | ||
372 | mutex_unlock(&moxa_openlock); | ||
373 | break; | ||
374 | default: | ||
375 | ret = -ENOIOCTLCMD; | ||
361 | } | 376 | } |
362 | return -ENOIOCTLCMD; | 377 | return ret; |
363 | } | 378 | } |
364 | 379 | ||
365 | static void moxa_break_ctl(struct tty_struct *tty, int state) | 380 | static void moxa_break_ctl(struct tty_struct *tty, int state) |
@@ -817,7 +832,6 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev) | |||
817 | p->close_delay = 5 * HZ / 10; | 832 | p->close_delay = 5 * HZ / 10; |
818 | p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; | 833 | p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; |
819 | init_waitqueue_head(&p->open_wait); | 834 | init_waitqueue_head(&p->open_wait); |
820 | init_completion(&p->close_wait); | ||
821 | } | 835 | } |
822 | 836 | ||
823 | switch (brd->boardType) { | 837 | switch (brd->boardType) { |
@@ -861,9 +875,29 @@ err: | |||
861 | 875 | ||
862 | static void moxa_board_deinit(struct moxa_board_conf *brd) | 876 | static void moxa_board_deinit(struct moxa_board_conf *brd) |
863 | { | 877 | { |
878 | unsigned int a, opened; | ||
879 | |||
880 | mutex_lock(&moxa_openlock); | ||
864 | spin_lock_bh(&moxa_lock); | 881 | spin_lock_bh(&moxa_lock); |
865 | brd->ready = 0; | 882 | brd->ready = 0; |
866 | spin_unlock_bh(&moxa_lock); | 883 | spin_unlock_bh(&moxa_lock); |
884 | |||
885 | /* pci hot-un-plug support */ | ||
886 | for (a = 0; a < brd->numPorts; a++) | ||
887 | if (brd->ports[a].asyncflags & ASYNC_INITIALIZED) | ||
888 | tty_hangup(brd->ports[a].tty); | ||
889 | while (1) { | ||
890 | opened = 0; | ||
891 | for (a = 0; a < brd->numPorts; a++) | ||
892 | if (brd->ports[a].asyncflags & ASYNC_INITIALIZED) | ||
893 | opened++; | ||
894 | mutex_unlock(&moxa_openlock); | ||
895 | if (!opened) | ||
896 | break; | ||
897 | msleep(50); | ||
898 | mutex_lock(&moxa_openlock); | ||
899 | } | ||
900 | |||
867 | iounmap(brd->basemem); | 901 | iounmap(brd->basemem); |
868 | brd->basemem = NULL; | 902 | brd->basemem = NULL; |
869 | kfree(brd->ports); | 903 | kfree(brd->ports); |
@@ -1061,6 +1095,49 @@ static void __exit moxa_exit(void) | |||
1061 | module_init(moxa_init); | 1095 | module_init(moxa_init); |
1062 | module_exit(moxa_exit); | 1096 | module_exit(moxa_exit); |
1063 | 1097 | ||
1098 | static void moxa_close_port(struct moxa_port *ch) | ||
1099 | { | ||
1100 | moxa_shut_down(ch); | ||
1101 | MoxaPortFlushData(ch, 2); | ||
1102 | ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE; | ||
1103 | ch->tty->driver_data = NULL; | ||
1104 | ch->tty = NULL; | ||
1105 | } | ||
1106 | |||
1107 | static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp, | ||
1108 | struct moxa_port *ch) | ||
1109 | { | ||
1110 | DEFINE_WAIT(wait); | ||
1111 | int retval = 0; | ||
1112 | u8 dcd; | ||
1113 | |||
1114 | while (1) { | ||
1115 | prepare_to_wait(&ch->open_wait, &wait, TASK_INTERRUPTIBLE); | ||
1116 | if (tty_hung_up_p(filp)) { | ||
1117 | #ifdef SERIAL_DO_RESTART | ||
1118 | retval = -ERESTARTSYS; | ||
1119 | #else | ||
1120 | retval = -EAGAIN; | ||
1121 | #endif | ||
1122 | break; | ||
1123 | } | ||
1124 | spin_lock_bh(&moxa_lock); | ||
1125 | dcd = ch->DCDState; | ||
1126 | spin_unlock_bh(&moxa_lock); | ||
1127 | if (dcd) | ||
1128 | break; | ||
1129 | |||
1130 | if (signal_pending(current)) { | ||
1131 | retval = -ERESTARTSYS; | ||
1132 | break; | ||
1133 | } | ||
1134 | schedule(); | ||
1135 | } | ||
1136 | finish_wait(&ch->open_wait, &wait); | ||
1137 | |||
1138 | return retval; | ||
1139 | } | ||
1140 | |||
1064 | static int moxa_open(struct tty_struct *tty, struct file *filp) | 1141 | static int moxa_open(struct tty_struct *tty, struct file *filp) |
1065 | { | 1142 | { |
1066 | struct moxa_board_conf *brd; | 1143 | struct moxa_board_conf *brd; |
@@ -1072,9 +1149,13 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) | |||
1072 | if (port == MAX_PORTS) { | 1149 | if (port == MAX_PORTS) { |
1073 | return capable(CAP_SYS_ADMIN) ? 0 : -EPERM; | 1150 | return capable(CAP_SYS_ADMIN) ? 0 : -EPERM; |
1074 | } | 1151 | } |
1152 | if (mutex_lock_interruptible(&moxa_openlock)) | ||
1153 | return -ERESTARTSYS; | ||
1075 | brd = &moxa_boards[port / MAX_PORTS_PER_BOARD]; | 1154 | brd = &moxa_boards[port / MAX_PORTS_PER_BOARD]; |
1076 | if (!brd->ready) | 1155 | if (!brd->ready) { |
1156 | mutex_unlock(&moxa_openlock); | ||
1077 | return -ENODEV; | 1157 | return -ENODEV; |
1158 | } | ||
1078 | 1159 | ||
1079 | ch = &brd->ports[port % MAX_PORTS_PER_BOARD]; | 1160 | ch = &brd->ports[port % MAX_PORTS_PER_BOARD]; |
1080 | ch->count++; | 1161 | ch->count++; |
@@ -1085,19 +1166,24 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) | |||
1085 | moxa_set_tty_param(tty, tty->termios); | 1166 | moxa_set_tty_param(tty, tty->termios); |
1086 | MoxaPortLineCtrl(ch, 1, 1); | 1167 | MoxaPortLineCtrl(ch, 1, 1); |
1087 | MoxaPortEnable(ch); | 1168 | MoxaPortEnable(ch); |
1169 | MoxaSetFifo(ch, ch->type == PORT_16550A); | ||
1088 | ch->asyncflags |= ASYNC_INITIALIZED; | 1170 | ch->asyncflags |= ASYNC_INITIALIZED; |
1089 | } | 1171 | } |
1090 | retval = moxa_block_till_ready(tty, filp, ch); | 1172 | mutex_unlock(&moxa_openlock); |
1091 | 1173 | ||
1092 | moxa_unthrottle(tty); | 1174 | retval = 0; |
1093 | 1175 | if (!(filp->f_flags & O_NONBLOCK) && !C_CLOCAL(tty)) | |
1094 | if (ch->type == PORT_16550A) { | 1176 | retval = moxa_block_till_ready(tty, filp, ch); |
1095 | MoxaSetFifo(ch, 1); | 1177 | mutex_lock(&moxa_openlock); |
1096 | } else { | 1178 | if (retval) { |
1097 | MoxaSetFifo(ch, 0); | 1179 | if (ch->count) /* 0 means already hung up... */ |
1098 | } | 1180 | if (--ch->count == 0) |
1181 | moxa_close_port(ch); | ||
1182 | } else | ||
1183 | ch->asyncflags |= ASYNC_NORMAL_ACTIVE; | ||
1184 | mutex_unlock(&moxa_openlock); | ||
1099 | 1185 | ||
1100 | return (retval); | 1186 | return retval; |
1101 | } | 1187 | } |
1102 | 1188 | ||
1103 | static void moxa_close(struct tty_struct *tty, struct file *filp) | 1189 | static void moxa_close(struct tty_struct *tty, struct file *filp) |
@@ -1106,18 +1192,14 @@ static void moxa_close(struct tty_struct *tty, struct file *filp) | |||
1106 | int port; | 1192 | int port; |
1107 | 1193 | ||
1108 | port = tty->index; | 1194 | port = tty->index; |
1109 | if (port == MAX_PORTS) { | 1195 | if (port == MAX_PORTS || tty_hung_up_p(filp)) |
1110 | return; | ||
1111 | } | ||
1112 | if (tty->driver_data == NULL) { | ||
1113 | return; | 1196 | return; |
1114 | } | ||
1115 | if (tty_hung_up_p(filp)) { | ||
1116 | return; | ||
1117 | } | ||
1118 | ch = (struct moxa_port *) tty->driver_data; | ||
1119 | 1197 | ||
1120 | if ((tty->count == 1) && (ch->count != 1)) { | 1198 | mutex_lock(&moxa_openlock); |
1199 | ch = tty->driver_data; | ||
1200 | if (ch == NULL) | ||
1201 | goto unlock; | ||
1202 | if (tty->count == 1 && ch->count != 1) { | ||
1121 | printk(KERN_WARNING "moxa_close: bad serial port count; " | 1203 | printk(KERN_WARNING "moxa_close: bad serial port count; " |
1122 | "tty->count is 1, ch->count is %d\n", ch->count); | 1204 | "tty->count is 1, ch->count is %d\n", ch->count); |
1123 | ch->count = 1; | 1205 | ch->count = 1; |
@@ -1127,33 +1209,18 @@ static void moxa_close(struct tty_struct *tty, struct file *filp) | |||
1127 | "device=%s\n", tty->name); | 1209 | "device=%s\n", tty->name); |
1128 | ch->count = 0; | 1210 | ch->count = 0; |
1129 | } | 1211 | } |
1130 | if (ch->count) { | 1212 | if (ch->count) |
1131 | return; | 1213 | goto unlock; |
1132 | } | ||
1133 | ch->asyncflags |= ASYNC_CLOSING; | ||
1134 | 1214 | ||
1135 | ch->cflag = tty->termios->c_cflag; | 1215 | ch->cflag = tty->termios->c_cflag; |
1136 | if (ch->asyncflags & ASYNC_INITIALIZED) { | 1216 | if (ch->asyncflags & ASYNC_INITIALIZED) { |
1137 | moxa_setup_empty_event(tty); | 1217 | moxa_setup_empty_event(tty); |
1138 | tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */ | 1218 | tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */ |
1139 | } | 1219 | } |
1140 | moxa_shut_down(ch); | ||
1141 | MoxaPortFlushData(ch, 2); | ||
1142 | 1220 | ||
1143 | if (tty->driver->flush_buffer) | 1221 | moxa_close_port(ch); |
1144 | tty->driver->flush_buffer(tty); | 1222 | unlock: |
1145 | tty_ldisc_flush(tty); | 1223 | mutex_unlock(&moxa_openlock); |
1146 | |||
1147 | tty->closing = 0; | ||
1148 | ch->tty = NULL; | ||
1149 | if (ch->blocked_open) { | ||
1150 | if (ch->close_delay) { | ||
1151 | msleep_interruptible(jiffies_to_msecs(ch->close_delay)); | ||
1152 | } | ||
1153 | wake_up_interruptible(&ch->open_wait); | ||
1154 | } | ||
1155 | ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); | ||
1156 | complete_all(&ch->close_wait); | ||
1157 | } | 1224 | } |
1158 | 1225 | ||
1159 | static int moxa_write(struct tty_struct *tty, | 1226 | static int moxa_write(struct tty_struct *tty, |
@@ -1249,11 +1316,15 @@ static void moxa_put_char(struct tty_struct *tty, unsigned char c) | |||
1249 | 1316 | ||
1250 | static int moxa_tiocmget(struct tty_struct *tty, struct file *file) | 1317 | static int moxa_tiocmget(struct tty_struct *tty, struct file *file) |
1251 | { | 1318 | { |
1252 | struct moxa_port *ch = tty->driver_data; | 1319 | struct moxa_port *ch; |
1253 | int flag = 0, dtr, rts; | 1320 | int flag = 0, dtr, rts; |
1254 | 1321 | ||
1255 | if (!ch) | 1322 | mutex_lock(&moxa_openlock); |
1323 | ch = tty->driver_data; | ||
1324 | if (!ch) { | ||
1325 | mutex_unlock(&moxa_openlock); | ||
1256 | return -EINVAL; | 1326 | return -EINVAL; |
1327 | } | ||
1257 | 1328 | ||
1258 | MoxaPortGetLineOut(ch, &dtr, &rts); | 1329 | MoxaPortGetLineOut(ch, &dtr, &rts); |
1259 | if (dtr) | 1330 | if (dtr) |
@@ -1267,19 +1338,24 @@ static int moxa_tiocmget(struct tty_struct *tty, struct file *file) | |||
1267 | flag |= TIOCM_DSR; | 1338 | flag |= TIOCM_DSR; |
1268 | if (dtr & 4) | 1339 | if (dtr & 4) |
1269 | flag |= TIOCM_CD; | 1340 | flag |= TIOCM_CD; |
1341 | mutex_unlock(&moxa_openlock); | ||
1270 | return flag; | 1342 | return flag; |
1271 | } | 1343 | } |
1272 | 1344 | ||
1273 | static int moxa_tiocmset(struct tty_struct *tty, struct file *file, | 1345 | static int moxa_tiocmset(struct tty_struct *tty, struct file *file, |
1274 | unsigned int set, unsigned int clear) | 1346 | unsigned int set, unsigned int clear) |
1275 | { | 1347 | { |
1276 | struct moxa_port *ch = tty->driver_data; | 1348 | struct moxa_port *ch; |
1277 | int port; | 1349 | int port; |
1278 | int dtr, rts; | 1350 | int dtr, rts; |
1279 | 1351 | ||
1280 | port = tty->index; | 1352 | port = tty->index; |
1281 | if (!ch) | 1353 | mutex_lock(&moxa_openlock); |
1354 | ch = tty->driver_data; | ||
1355 | if (!ch) { | ||
1356 | mutex_unlock(&moxa_openlock); | ||
1282 | return -EINVAL; | 1357 | return -EINVAL; |
1358 | } | ||
1283 | 1359 | ||
1284 | MoxaPortGetLineOut(ch, &dtr, &rts); | 1360 | MoxaPortGetLineOut(ch, &dtr, &rts); |
1285 | if (set & TIOCM_RTS) | 1361 | if (set & TIOCM_RTS) |
@@ -1291,6 +1367,7 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file, | |||
1291 | if (clear & TIOCM_DTR) | 1367 | if (clear & TIOCM_DTR) |
1292 | dtr = 0; | 1368 | dtr = 0; |
1293 | MoxaPortLineCtrl(ch, dtr, rts); | 1369 | MoxaPortLineCtrl(ch, dtr, rts); |
1370 | mutex_unlock(&moxa_openlock); | ||
1294 | return 0; | 1371 | return 0; |
1295 | } | 1372 | } |
1296 | 1373 | ||
@@ -1348,13 +1425,18 @@ static void moxa_start(struct tty_struct *tty) | |||
1348 | 1425 | ||
1349 | static void moxa_hangup(struct tty_struct *tty) | 1426 | static void moxa_hangup(struct tty_struct *tty) |
1350 | { | 1427 | { |
1351 | struct moxa_port *ch = (struct moxa_port *) tty->driver_data; | 1428 | struct moxa_port *ch; |
1352 | 1429 | ||
1353 | moxa_flush_buffer(tty); | 1430 | mutex_lock(&moxa_openlock); |
1354 | moxa_shut_down(ch); | 1431 | ch = tty->driver_data; |
1432 | if (ch == NULL) { | ||
1433 | mutex_unlock(&moxa_openlock); | ||
1434 | return; | ||
1435 | } | ||
1355 | ch->count = 0; | 1436 | ch->count = 0; |
1356 | ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE; | 1437 | moxa_close_port(ch); |
1357 | ch->tty = NULL; | 1438 | mutex_unlock(&moxa_openlock); |
1439 | |||
1358 | wake_up_interruptible(&ch->open_wait); | 1440 | wake_up_interruptible(&ch->open_wait); |
1359 | } | 1441 | } |
1360 | 1442 | ||
@@ -1363,11 +1445,8 @@ static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd) | |||
1363 | dcd = !!dcd; | 1445 | dcd = !!dcd; |
1364 | 1446 | ||
1365 | if ((dcd != p->DCDState) && p->tty && C_CLOCAL(p->tty)) { | 1447 | if ((dcd != p->DCDState) && p->tty && C_CLOCAL(p->tty)) { |
1366 | if (!dcd) { | 1448 | if (!dcd) |
1367 | tty_hangup(p->tty); | 1449 | tty_hangup(p->tty); |
1368 | p->asyncflags &= ~ASYNC_NORMAL_ACTIVE; | ||
1369 | } | ||
1370 | wake_up_interruptible(&p->open_wait); | ||
1371 | } | 1450 | } |
1372 | p->DCDState = dcd; | 1451 | p->DCDState = dcd; |
1373 | } | 1452 | } |
@@ -1499,91 +1578,6 @@ static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_term | |||
1499 | tty_encode_baud_rate(tty, baud, baud); | 1578 | tty_encode_baud_rate(tty, baud, baud); |
1500 | } | 1579 | } |
1501 | 1580 | ||
1502 | static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp, | ||
1503 | struct moxa_port *ch) | ||
1504 | { | ||
1505 | DECLARE_WAITQUEUE(wait,current); | ||
1506 | int retval; | ||
1507 | int do_clocal = C_CLOCAL(tty); | ||
1508 | |||
1509 | /* | ||
1510 | * If the device is in the middle of being closed, then block | ||
1511 | * until it's done, and then try again. | ||
1512 | */ | ||
1513 | if (tty_hung_up_p(filp) || (ch->asyncflags & ASYNC_CLOSING)) { | ||
1514 | if (ch->asyncflags & ASYNC_CLOSING) | ||
1515 | wait_for_completion_interruptible(&ch->close_wait); | ||
1516 | #ifdef SERIAL_DO_RESTART | ||
1517 | if (ch->asyncflags & ASYNC_HUP_NOTIFY) | ||
1518 | return (-EAGAIN); | ||
1519 | else | ||
1520 | return (-ERESTARTSYS); | ||
1521 | #else | ||
1522 | return (-EAGAIN); | ||
1523 | #endif | ||
1524 | } | ||
1525 | /* | ||
1526 | * If non-blocking mode is set, then make the check up front | ||
1527 | * and then exit. | ||
1528 | */ | ||
1529 | if (filp->f_flags & O_NONBLOCK) { | ||
1530 | ch->asyncflags |= ASYNC_NORMAL_ACTIVE; | ||
1531 | return (0); | ||
1532 | } | ||
1533 | /* | ||
1534 | * Block waiting for the carrier detect and the line to become free | ||
1535 | */ | ||
1536 | retval = 0; | ||
1537 | add_wait_queue(&ch->open_wait, &wait); | ||
1538 | pr_debug("block_til_ready before block: ttys%d, count = %d\n", | ||
1539 | tty->index, ch->count); | ||
1540 | spin_lock_bh(&moxa_lock); | ||
1541 | if (!tty_hung_up_p(filp)) | ||
1542 | ch->count--; | ||
1543 | ch->blocked_open++; | ||
1544 | spin_unlock_bh(&moxa_lock); | ||
1545 | |||
1546 | while (1) { | ||
1547 | set_current_state(TASK_INTERRUPTIBLE); | ||
1548 | if (tty_hung_up_p(filp) || | ||
1549 | !(ch->asyncflags & ASYNC_INITIALIZED)) { | ||
1550 | #ifdef SERIAL_DO_RESTART | ||
1551 | if (ch->asyncflags & ASYNC_HUP_NOTIFY) | ||
1552 | retval = -EAGAIN; | ||
1553 | else | ||
1554 | retval = -ERESTARTSYS; | ||
1555 | #else | ||
1556 | retval = -EAGAIN; | ||
1557 | #endif | ||
1558 | break; | ||
1559 | } | ||
1560 | if (!(ch->asyncflags & ASYNC_CLOSING) && (do_clocal || | ||
1561 | ch->DCDState)) | ||
1562 | break; | ||
1563 | |||
1564 | if (signal_pending(current)) { | ||
1565 | retval = -ERESTARTSYS; | ||
1566 | break; | ||
1567 | } | ||
1568 | schedule(); | ||
1569 | } | ||
1570 | set_current_state(TASK_RUNNING); | ||
1571 | remove_wait_queue(&ch->open_wait, &wait); | ||
1572 | |||
1573 | spin_lock_bh(&moxa_lock); | ||
1574 | if (!tty_hung_up_p(filp)) | ||
1575 | ch->count++; | ||
1576 | ch->blocked_open--; | ||
1577 | spin_unlock_bh(&moxa_lock); | ||
1578 | pr_debug("block_til_ready after blocking: ttys%d, count = %d\n", | ||
1579 | tty->index, ch->count); | ||
1580 | if (retval) | ||
1581 | return (retval); | ||
1582 | /* FIXME: review to see if we need to use set_bit on these */ | ||
1583 | ch->asyncflags |= ASYNC_NORMAL_ACTIVE; | ||
1584 | return 0; | ||
1585 | } | ||
1586 | |||
1587 | static void moxa_setup_empty_event(struct tty_struct *tty) | 1581 | static void moxa_setup_empty_event(struct tty_struct *tty) |
1588 | { | 1582 | { |
1589 | struct moxa_port *ch = tty->driver_data; | 1583 | struct moxa_port *ch = tty->driver_data; |
@@ -1595,22 +1589,22 @@ static void moxa_setup_empty_event(struct tty_struct *tty) | |||
1595 | 1589 | ||
1596 | static void moxa_shut_down(struct moxa_port *ch) | 1590 | static void moxa_shut_down(struct moxa_port *ch) |
1597 | { | 1591 | { |
1598 | struct tty_struct *tp; | 1592 | struct tty_struct *tp = ch->tty; |
1599 | 1593 | ||
1600 | if (!(ch->asyncflags & ASYNC_INITIALIZED)) | 1594 | if (!(ch->asyncflags & ASYNC_INITIALIZED)) |
1601 | return; | 1595 | return; |
1602 | 1596 | ||
1603 | tp = ch->tty; | ||
1604 | |||
1605 | MoxaPortDisable(ch); | 1597 | MoxaPortDisable(ch); |
1606 | 1598 | ||
1607 | /* | 1599 | /* |
1608 | * If we're a modem control device and HUPCL is on, drop RTS & DTR. | 1600 | * If we're a modem control device and HUPCL is on, drop RTS & DTR. |
1609 | */ | 1601 | */ |
1610 | if (tp->termios->c_cflag & HUPCL) | 1602 | if (C_HUPCL(tp)) |
1611 | MoxaPortLineCtrl(ch, 0, 0); | 1603 | MoxaPortLineCtrl(ch, 0, 0); |
1612 | 1604 | ||
1605 | spin_lock_bh(&moxa_lock); | ||
1613 | ch->asyncflags &= ~ASYNC_INITIALIZED; | 1606 | ch->asyncflags &= ~ASYNC_INITIALIZED; |
1607 | spin_unlock_bh(&moxa_lock); | ||
1614 | } | 1608 | } |
1615 | 1609 | ||
1616 | /***************************************************************************** | 1610 | /***************************************************************************** |
@@ -2029,7 +2023,9 @@ static int MoxaPortLineStatus(struct moxa_port *port) | |||
2029 | val &= 0x0B; | 2023 | val &= 0x0B; |
2030 | if (val & 8) | 2024 | if (val & 8) |
2031 | val |= 4; | 2025 | val |= 4; |
2026 | spin_lock_bh(&moxa_lock); | ||
2032 | moxa_new_dcdstate(port, val & 8); | 2027 | moxa_new_dcdstate(port, val & 8); |
2028 | spin_unlock_bh(&moxa_lock); | ||
2033 | val &= 7; | 2029 | val &= 7; |
2034 | return val; | 2030 | return val; |
2035 | } | 2031 | } |