diff options
Diffstat (limited to 'drivers/char/moxa.c')
-rw-r--r-- | drivers/char/moxa.c | 310 |
1 files changed, 93 insertions, 217 deletions
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index dd0083bbb64a..107b0bd58d19 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c | |||
@@ -34,7 +34,6 @@ | |||
34 | #include <linux/tty.h> | 34 | #include <linux/tty.h> |
35 | #include <linux/tty_flip.h> | 35 | #include <linux/tty_flip.h> |
36 | #include <linux/major.h> | 36 | #include <linux/major.h> |
37 | #include <linux/smp_lock.h> | ||
38 | #include <linux/string.h> | 37 | #include <linux/string.h> |
39 | #include <linux/fcntl.h> | 38 | #include <linux/fcntl.h> |
40 | #include <linux/ptrace.h> | 39 | #include <linux/ptrace.h> |
@@ -44,6 +43,7 @@ | |||
44 | #include <linux/pci.h> | 43 | #include <linux/pci.h> |
45 | #include <linux/init.h> | 44 | #include <linux/init.h> |
46 | #include <linux/bitops.h> | 45 | #include <linux/bitops.h> |
46 | #include <linux/slab.h> | ||
47 | 47 | ||
48 | #include <asm/system.h> | 48 | #include <asm/system.h> |
49 | #include <asm/io.h> | 49 | #include <asm/io.h> |
@@ -139,7 +139,7 @@ struct moxa_port { | |||
139 | int cflag; | 139 | int cflag; |
140 | unsigned long statusflags; | 140 | unsigned long statusflags; |
141 | 141 | ||
142 | u8 DCDState; | 142 | u8 DCDState; /* Protected by the port lock */ |
143 | u8 lineCtrl; | 143 | u8 lineCtrl; |
144 | u8 lowChkFlag; | 144 | u8 lowChkFlag; |
145 | }; | 145 | }; |
@@ -151,10 +151,9 @@ struct mon_str { | |||
151 | }; | 151 | }; |
152 | 152 | ||
153 | /* statusflags */ | 153 | /* statusflags */ |
154 | #define TXSTOPPED 0x1 | 154 | #define TXSTOPPED 1 |
155 | #define LOWWAIT 0x2 | 155 | #define LOWWAIT 2 |
156 | #define EMPTYWAIT 0x4 | 156 | #define EMPTYWAIT 3 |
157 | #define THROTTLE 0x8 | ||
158 | 157 | ||
159 | #define SERIAL_DO_RESTART | 158 | #define SERIAL_DO_RESTART |
160 | 159 | ||
@@ -165,24 +164,26 @@ static struct mon_str moxaLog; | |||
165 | static unsigned int moxaFuncTout = HZ / 2; | 164 | static unsigned int moxaFuncTout = HZ / 2; |
166 | static unsigned int moxaLowWaterChk; | 165 | static unsigned int moxaLowWaterChk; |
167 | static DEFINE_MUTEX(moxa_openlock); | 166 | static DEFINE_MUTEX(moxa_openlock); |
168 | /* Variables for insmod */ | 167 | static DEFINE_SPINLOCK(moxa_lock); |
169 | #ifdef MODULE | 168 | |
170 | static unsigned long baseaddr[MAX_BOARDS]; | 169 | static unsigned long baseaddr[MAX_BOARDS]; |
171 | static unsigned int type[MAX_BOARDS]; | 170 | static unsigned int type[MAX_BOARDS]; |
172 | static unsigned int numports[MAX_BOARDS]; | 171 | static unsigned int numports[MAX_BOARDS]; |
173 | #endif | ||
174 | 172 | ||
175 | MODULE_AUTHOR("William Chen"); | 173 | MODULE_AUTHOR("William Chen"); |
176 | MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver"); | 174 | MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver"); |
177 | MODULE_LICENSE("GPL"); | 175 | MODULE_LICENSE("GPL"); |
178 | #ifdef MODULE | 176 | MODULE_FIRMWARE("c218tunx.cod"); |
177 | MODULE_FIRMWARE("cp204unx.cod"); | ||
178 | MODULE_FIRMWARE("c320tunx.cod"); | ||
179 | |||
179 | module_param_array(type, uint, NULL, 0); | 180 | module_param_array(type, uint, NULL, 0); |
180 | MODULE_PARM_DESC(type, "card type: C218=2, C320=4"); | 181 | MODULE_PARM_DESC(type, "card type: C218=2, C320=4"); |
181 | module_param_array(baseaddr, ulong, NULL, 0); | 182 | module_param_array(baseaddr, ulong, NULL, 0); |
182 | MODULE_PARM_DESC(baseaddr, "base address"); | 183 | MODULE_PARM_DESC(baseaddr, "base address"); |
183 | module_param_array(numports, uint, NULL, 0); | 184 | module_param_array(numports, uint, NULL, 0); |
184 | MODULE_PARM_DESC(numports, "numports (ignored for C218)"); | 185 | MODULE_PARM_DESC(numports, "numports (ignored for C218)"); |
185 | #endif | 186 | |
186 | module_param(ttymajor, int, 0); | 187 | module_param(ttymajor, int, 0); |
187 | 188 | ||
188 | /* | 189 | /* |
@@ -194,8 +195,6 @@ static int moxa_write(struct tty_struct *, const unsigned char *, int); | |||
194 | static int moxa_write_room(struct tty_struct *); | 195 | static int moxa_write_room(struct tty_struct *); |
195 | static void moxa_flush_buffer(struct tty_struct *); | 196 | static void moxa_flush_buffer(struct tty_struct *); |
196 | static int moxa_chars_in_buffer(struct tty_struct *); | 197 | static int moxa_chars_in_buffer(struct tty_struct *); |
197 | static void moxa_throttle(struct tty_struct *); | ||
198 | static void moxa_unthrottle(struct tty_struct *); | ||
199 | static void moxa_set_termios(struct tty_struct *, struct ktermios *); | 198 | static void moxa_set_termios(struct tty_struct *, struct ktermios *); |
200 | static void moxa_stop(struct tty_struct *); | 199 | static void moxa_stop(struct tty_struct *); |
201 | static void moxa_start(struct tty_struct *); | 200 | static void moxa_start(struct tty_struct *); |
@@ -205,9 +204,9 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file, | |||
205 | unsigned int set, unsigned int clear); | 204 | unsigned int set, unsigned int clear); |
206 | static void moxa_poll(unsigned long); | 205 | static void moxa_poll(unsigned long); |
207 | static void moxa_set_tty_param(struct tty_struct *, struct ktermios *); | 206 | static void moxa_set_tty_param(struct tty_struct *, struct ktermios *); |
208 | static void moxa_setup_empty_event(struct tty_struct *); | 207 | static void moxa_shutdown(struct tty_port *); |
209 | static void moxa_shut_down(struct tty_struct *); | ||
210 | static int moxa_carrier_raised(struct tty_port *); | 208 | static int moxa_carrier_raised(struct tty_port *); |
209 | static void moxa_dtr_rts(struct tty_port *, int); | ||
211 | /* | 210 | /* |
212 | * moxa board interface functions: | 211 | * moxa board interface functions: |
213 | */ | 212 | */ |
@@ -234,6 +233,8 @@ static void MoxaSetFifo(struct moxa_port *port, int enable); | |||
234 | * I/O functions | 233 | * I/O functions |
235 | */ | 234 | */ |
236 | 235 | ||
236 | static DEFINE_SPINLOCK(moxafunc_lock); | ||
237 | |||
237 | static void moxa_wait_finish(void __iomem *ofsAddr) | 238 | static void moxa_wait_finish(void __iomem *ofsAddr) |
238 | { | 239 | { |
239 | unsigned long end = jiffies + moxaFuncTout; | 240 | unsigned long end = jiffies + moxaFuncTout; |
@@ -247,9 +248,25 @@ static void moxa_wait_finish(void __iomem *ofsAddr) | |||
247 | 248 | ||
248 | static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg) | 249 | static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg) |
249 | { | 250 | { |
251 | unsigned long flags; | ||
252 | spin_lock_irqsave(&moxafunc_lock, flags); | ||
250 | writew(arg, ofsAddr + FuncArg); | 253 | writew(arg, ofsAddr + FuncArg); |
251 | writew(cmd, ofsAddr + FuncCode); | 254 | writew(cmd, ofsAddr + FuncCode); |
252 | moxa_wait_finish(ofsAddr); | 255 | moxa_wait_finish(ofsAddr); |
256 | spin_unlock_irqrestore(&moxafunc_lock, flags); | ||
257 | } | ||
258 | |||
259 | static int moxafuncret(void __iomem *ofsAddr, u16 cmd, u16 arg) | ||
260 | { | ||
261 | unsigned long flags; | ||
262 | u16 ret; | ||
263 | spin_lock_irqsave(&moxafunc_lock, flags); | ||
264 | writew(arg, ofsAddr + FuncArg); | ||
265 | writew(cmd, ofsAddr + FuncCode); | ||
266 | moxa_wait_finish(ofsAddr); | ||
267 | ret = readw(ofsAddr + FuncArg); | ||
268 | spin_unlock_irqrestore(&moxafunc_lock, flags); | ||
269 | return ret; | ||
253 | } | 270 | } |
254 | 271 | ||
255 | static void moxa_low_water_check(void __iomem *ofsAddr) | 272 | static void moxa_low_water_check(void __iomem *ofsAddr) |
@@ -299,22 +316,20 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file, | |||
299 | struct moxa_port *p; | 316 | struct moxa_port *p; |
300 | unsigned int i, j; | 317 | unsigned int i, j; |
301 | 318 | ||
302 | mutex_lock(&moxa_openlock); | ||
303 | for (i = 0; i < MAX_BOARDS; i++) { | 319 | for (i = 0; i < MAX_BOARDS; i++) { |
304 | p = moxa_boards[i].ports; | 320 | p = moxa_boards[i].ports; |
305 | for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { | 321 | for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { |
306 | memset(&tmp, 0, sizeof(tmp)); | 322 | memset(&tmp, 0, sizeof(tmp)); |
323 | spin_lock_bh(&moxa_lock); | ||
307 | if (moxa_boards[i].ready) { | 324 | if (moxa_boards[i].ready) { |
308 | tmp.inq = MoxaPortRxQueue(p); | 325 | tmp.inq = MoxaPortRxQueue(p); |
309 | tmp.outq = MoxaPortTxQueue(p); | 326 | tmp.outq = MoxaPortTxQueue(p); |
310 | } | 327 | } |
311 | if (copy_to_user(argm, &tmp, sizeof(tmp))) { | 328 | spin_unlock_bh(&moxa_lock); |
312 | mutex_unlock(&moxa_openlock); | 329 | if (copy_to_user(argm, &tmp, sizeof(tmp))) |
313 | return -EFAULT; | 330 | return -EFAULT; |
314 | } | ||
315 | } | 331 | } |
316 | } | 332 | } |
317 | mutex_unlock(&moxa_openlock); | ||
318 | break; | 333 | break; |
319 | } case MOXA_GET_OQUEUE: | 334 | } case MOXA_GET_OQUEUE: |
320 | status = MoxaPortTxQueue(ch); | 335 | status = MoxaPortTxQueue(ch); |
@@ -330,16 +345,20 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file, | |||
330 | struct moxa_port *p; | 345 | struct moxa_port *p; |
331 | unsigned int i, j; | 346 | unsigned int i, j; |
332 | 347 | ||
333 | mutex_lock(&moxa_openlock); | ||
334 | for (i = 0; i < MAX_BOARDS; i++) { | 348 | for (i = 0; i < MAX_BOARDS; i++) { |
335 | p = moxa_boards[i].ports; | 349 | p = moxa_boards[i].ports; |
336 | for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { | 350 | for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { |
337 | struct tty_struct *ttyp; | 351 | struct tty_struct *ttyp; |
338 | memset(&tmp, 0, sizeof(tmp)); | 352 | memset(&tmp, 0, sizeof(tmp)); |
339 | if (!moxa_boards[i].ready) | 353 | spin_lock_bh(&moxa_lock); |
354 | if (!moxa_boards[i].ready) { | ||
355 | spin_unlock_bh(&moxa_lock); | ||
340 | goto copy; | 356 | goto copy; |
357 | } | ||
341 | 358 | ||
342 | status = MoxaPortLineStatus(p); | 359 | status = MoxaPortLineStatus(p); |
360 | spin_unlock_bh(&moxa_lock); | ||
361 | |||
343 | if (status & 1) | 362 | if (status & 1) |
344 | tmp.cts = 1; | 363 | tmp.cts = 1; |
345 | if (status & 2) | 364 | if (status & 2) |
@@ -354,24 +373,21 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file, | |||
354 | tmp.cflag = ttyp->termios->c_cflag; | 373 | tmp.cflag = ttyp->termios->c_cflag; |
355 | tty_kref_put(tty); | 374 | tty_kref_put(tty); |
356 | copy: | 375 | copy: |
357 | if (copy_to_user(argm, &tmp, sizeof(tmp))) { | 376 | if (copy_to_user(argm, &tmp, sizeof(tmp))) |
358 | mutex_unlock(&moxa_openlock); | ||
359 | return -EFAULT; | 377 | return -EFAULT; |
360 | } | ||
361 | } | 378 | } |
362 | } | 379 | } |
363 | mutex_unlock(&moxa_openlock); | ||
364 | break; | 380 | break; |
365 | } | 381 | } |
366 | case TIOCGSERIAL: | 382 | case TIOCGSERIAL: |
367 | mutex_lock(&moxa_openlock); | 383 | mutex_lock(&ch->port.mutex); |
368 | ret = moxa_get_serial_info(ch, argp); | 384 | ret = moxa_get_serial_info(ch, argp); |
369 | mutex_unlock(&moxa_openlock); | 385 | mutex_unlock(&ch->port.mutex); |
370 | break; | 386 | break; |
371 | case TIOCSSERIAL: | 387 | case TIOCSSERIAL: |
372 | mutex_lock(&moxa_openlock); | 388 | mutex_lock(&ch->port.mutex); |
373 | ret = moxa_set_serial_info(ch, argp); | 389 | ret = moxa_set_serial_info(ch, argp); |
374 | mutex_unlock(&moxa_openlock); | 390 | mutex_unlock(&ch->port.mutex); |
375 | break; | 391 | break; |
376 | default: | 392 | default: |
377 | ret = -ENOIOCTLCMD; | 393 | ret = -ENOIOCTLCMD; |
@@ -396,8 +412,6 @@ static const struct tty_operations moxa_ops = { | |||
396 | .flush_buffer = moxa_flush_buffer, | 412 | .flush_buffer = moxa_flush_buffer, |
397 | .chars_in_buffer = moxa_chars_in_buffer, | 413 | .chars_in_buffer = moxa_chars_in_buffer, |
398 | .ioctl = moxa_ioctl, | 414 | .ioctl = moxa_ioctl, |
399 | .throttle = moxa_throttle, | ||
400 | .unthrottle = moxa_unthrottle, | ||
401 | .set_termios = moxa_set_termios, | 415 | .set_termios = moxa_set_termios, |
402 | .stop = moxa_stop, | 416 | .stop = moxa_stop, |
403 | .start = moxa_start, | 417 | .start = moxa_start, |
@@ -409,11 +423,12 @@ static const struct tty_operations moxa_ops = { | |||
409 | 423 | ||
410 | static const struct tty_port_operations moxa_port_ops = { | 424 | static const struct tty_port_operations moxa_port_ops = { |
411 | .carrier_raised = moxa_carrier_raised, | 425 | .carrier_raised = moxa_carrier_raised, |
426 | .dtr_rts = moxa_dtr_rts, | ||
427 | .shutdown = moxa_shutdown, | ||
412 | }; | 428 | }; |
413 | 429 | ||
414 | static struct tty_driver *moxaDriver; | 430 | static struct tty_driver *moxaDriver; |
415 | static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0); | 431 | static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0); |
416 | static DEFINE_SPINLOCK(moxa_lock); | ||
417 | 432 | ||
418 | /* | 433 | /* |
419 | * HW init | 434 | * HW init |
@@ -1011,6 +1026,8 @@ static int __init moxa_init(void) | |||
1011 | { | 1026 | { |
1012 | unsigned int isabrds = 0; | 1027 | unsigned int isabrds = 0; |
1013 | int retval = 0; | 1028 | int retval = 0; |
1029 | struct moxa_board_conf *brd = moxa_boards; | ||
1030 | unsigned int i; | ||
1014 | 1031 | ||
1015 | printk(KERN_INFO "MOXA Intellio family driver version %s\n", | 1032 | printk(KERN_INFO "MOXA Intellio family driver version %s\n", |
1016 | MOXA_VERSION); | 1033 | MOXA_VERSION); |
@@ -1038,10 +1055,7 @@ static int __init moxa_init(void) | |||
1038 | } | 1055 | } |
1039 | 1056 | ||
1040 | /* Find the boards defined from module args. */ | 1057 | /* Find the boards defined from module args. */ |
1041 | #ifdef MODULE | 1058 | |
1042 | { | ||
1043 | struct moxa_board_conf *brd = moxa_boards; | ||
1044 | unsigned int i; | ||
1045 | for (i = 0; i < MAX_BOARDS; i++) { | 1059 | for (i = 0; i < MAX_BOARDS; i++) { |
1046 | if (!baseaddr[i]) | 1060 | if (!baseaddr[i]) |
1047 | break; | 1061 | break; |
@@ -1074,8 +1088,6 @@ static int __init moxa_init(void) | |||
1074 | isabrds++; | 1088 | isabrds++; |
1075 | } | 1089 | } |
1076 | } | 1090 | } |
1077 | } | ||
1078 | #endif | ||
1079 | 1091 | ||
1080 | #ifdef CONFIG_PCI | 1092 | #ifdef CONFIG_PCI |
1081 | retval = pci_register_driver(&moxa_pci_driver); | 1093 | retval = pci_register_driver(&moxa_pci_driver); |
@@ -1112,14 +1124,12 @@ static void __exit moxa_exit(void) | |||
1112 | module_init(moxa_init); | 1124 | module_init(moxa_init); |
1113 | module_exit(moxa_exit); | 1125 | module_exit(moxa_exit); |
1114 | 1126 | ||
1115 | static void moxa_close_port(struct tty_struct *tty) | 1127 | static void moxa_shutdown(struct tty_port *port) |
1116 | { | 1128 | { |
1117 | struct moxa_port *ch = tty->driver_data; | 1129 | struct moxa_port *ch = container_of(port, struct moxa_port, port); |
1118 | moxa_shut_down(tty); | 1130 | MoxaPortDisable(ch); |
1119 | MoxaPortFlushData(ch, 2); | 1131 | MoxaPortFlushData(ch, 2); |
1120 | ch->port.flags &= ~ASYNC_NORMAL_ACTIVE; | 1132 | clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); |
1121 | tty->driver_data = NULL; | ||
1122 | tty_port_tty_set(&ch->port, NULL); | ||
1123 | } | 1133 | } |
1124 | 1134 | ||
1125 | static int moxa_carrier_raised(struct tty_port *port) | 1135 | static int moxa_carrier_raised(struct tty_port *port) |
@@ -1127,45 +1137,19 @@ static int moxa_carrier_raised(struct tty_port *port) | |||
1127 | struct moxa_port *ch = container_of(port, struct moxa_port, port); | 1137 | struct moxa_port *ch = container_of(port, struct moxa_port, port); |
1128 | int dcd; | 1138 | int dcd; |
1129 | 1139 | ||
1130 | spin_lock_bh(&moxa_lock); | 1140 | spin_lock_irq(&port->lock); |
1131 | dcd = ch->DCDState; | 1141 | dcd = ch->DCDState; |
1132 | spin_unlock_bh(&moxa_lock); | 1142 | spin_unlock_irq(&port->lock); |
1133 | return dcd; | 1143 | return dcd; |
1134 | } | 1144 | } |
1135 | 1145 | ||
1136 | static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp, | 1146 | static void moxa_dtr_rts(struct tty_port *port, int onoff) |
1137 | struct moxa_port *ch) | ||
1138 | { | 1147 | { |
1139 | struct tty_port *port = &ch->port; | 1148 | struct moxa_port *ch = container_of(port, struct moxa_port, port); |
1140 | DEFINE_WAIT(wait); | 1149 | MoxaPortLineCtrl(ch, onoff, onoff); |
1141 | int retval = 0; | ||
1142 | u8 dcd; | ||
1143 | |||
1144 | while (1) { | ||
1145 | prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE); | ||
1146 | if (tty_hung_up_p(filp)) { | ||
1147 | #ifdef SERIAL_DO_RESTART | ||
1148 | retval = -ERESTARTSYS; | ||
1149 | #else | ||
1150 | retval = -EAGAIN; | ||
1151 | #endif | ||
1152 | break; | ||
1153 | } | ||
1154 | dcd = tty_port_carrier_raised(port); | ||
1155 | if (dcd) | ||
1156 | break; | ||
1157 | |||
1158 | if (signal_pending(current)) { | ||
1159 | retval = -ERESTARTSYS; | ||
1160 | break; | ||
1161 | } | ||
1162 | schedule(); | ||
1163 | } | ||
1164 | finish_wait(&port->open_wait, &wait); | ||
1165 | |||
1166 | return retval; | ||
1167 | } | 1150 | } |
1168 | 1151 | ||
1152 | |||
1169 | static int moxa_open(struct tty_struct *tty, struct file *filp) | 1153 | static int moxa_open(struct tty_struct *tty, struct file *filp) |
1170 | { | 1154 | { |
1171 | struct moxa_board_conf *brd; | 1155 | struct moxa_board_conf *brd; |
@@ -1194,6 +1178,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) | |||
1194 | ch->port.count++; | 1178 | ch->port.count++; |
1195 | tty->driver_data = ch; | 1179 | tty->driver_data = ch; |
1196 | tty_port_tty_set(&ch->port, tty); | 1180 | tty_port_tty_set(&ch->port, tty); |
1181 | mutex_lock(&ch->port.mutex); | ||
1197 | if (!(ch->port.flags & ASYNC_INITIALIZED)) { | 1182 | if (!(ch->port.flags & ASYNC_INITIALIZED)) { |
1198 | ch->statusflags = 0; | 1183 | ch->statusflags = 0; |
1199 | moxa_set_tty_param(tty, tty->termios); | 1184 | moxa_set_tty_param(tty, tty->termios); |
@@ -1202,58 +1187,20 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) | |||
1202 | MoxaSetFifo(ch, ch->type == PORT_16550A); | 1187 | MoxaSetFifo(ch, ch->type == PORT_16550A); |
1203 | ch->port.flags |= ASYNC_INITIALIZED; | 1188 | ch->port.flags |= ASYNC_INITIALIZED; |
1204 | } | 1189 | } |
1190 | mutex_unlock(&ch->port.mutex); | ||
1205 | mutex_unlock(&moxa_openlock); | 1191 | mutex_unlock(&moxa_openlock); |
1206 | 1192 | ||
1207 | retval = 0; | 1193 | retval = tty_port_block_til_ready(&ch->port, tty, filp); |
1208 | if (!(filp->f_flags & O_NONBLOCK) && !C_CLOCAL(tty)) | 1194 | if (retval == 0) |
1209 | retval = moxa_block_till_ready(tty, filp, ch); | 1195 | set_bit(ASYNCB_NORMAL_ACTIVE, &ch->port.flags); |
1210 | mutex_lock(&moxa_openlock); | ||
1211 | if (retval) { | ||
1212 | if (ch->port.count) /* 0 means already hung up... */ | ||
1213 | if (--ch->port.count == 0) | ||
1214 | moxa_close_port(tty); | ||
1215 | } else | ||
1216 | ch->port.flags |= ASYNC_NORMAL_ACTIVE; | ||
1217 | mutex_unlock(&moxa_openlock); | ||
1218 | |||
1219 | return retval; | 1196 | return retval; |
1220 | } | 1197 | } |
1221 | 1198 | ||
1222 | static void moxa_close(struct tty_struct *tty, struct file *filp) | 1199 | static void moxa_close(struct tty_struct *tty, struct file *filp) |
1223 | { | 1200 | { |
1224 | struct moxa_port *ch; | 1201 | struct moxa_port *ch = tty->driver_data; |
1225 | int port; | ||
1226 | |||
1227 | port = tty->index; | ||
1228 | if (port == MAX_PORTS || tty_hung_up_p(filp)) | ||
1229 | return; | ||
1230 | |||
1231 | mutex_lock(&moxa_openlock); | ||
1232 | ch = tty->driver_data; | ||
1233 | if (ch == NULL) | ||
1234 | goto unlock; | ||
1235 | if (tty->count == 1 && ch->port.count != 1) { | ||
1236 | printk(KERN_WARNING "moxa_close: bad serial port count; " | ||
1237 | "tty->count is 1, ch->port.count is %d\n", ch->port.count); | ||
1238 | ch->port.count = 1; | ||
1239 | } | ||
1240 | if (--ch->port.count < 0) { | ||
1241 | printk(KERN_WARNING "moxa_close: bad serial port count, " | ||
1242 | "device=%s\n", tty->name); | ||
1243 | ch->port.count = 0; | ||
1244 | } | ||
1245 | if (ch->port.count) | ||
1246 | goto unlock; | ||
1247 | |||
1248 | ch->cflag = tty->termios->c_cflag; | 1202 | ch->cflag = tty->termios->c_cflag; |
1249 | if (ch->port.flags & ASYNC_INITIALIZED) { | 1203 | tty_port_close(&ch->port, tty, filp); |
1250 | moxa_setup_empty_event(tty); | ||
1251 | tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */ | ||
1252 | } | ||
1253 | |||
1254 | moxa_close_port(tty); | ||
1255 | unlock: | ||
1256 | mutex_unlock(&moxa_openlock); | ||
1257 | } | 1204 | } |
1258 | 1205 | ||
1259 | static int moxa_write(struct tty_struct *tty, | 1206 | static int moxa_write(struct tty_struct *tty, |
@@ -1269,7 +1216,7 @@ static int moxa_write(struct tty_struct *tty, | |||
1269 | len = MoxaPortWriteData(tty, buf, count); | 1216 | len = MoxaPortWriteData(tty, buf, count); |
1270 | spin_unlock_bh(&moxa_lock); | 1217 | spin_unlock_bh(&moxa_lock); |
1271 | 1218 | ||
1272 | ch->statusflags |= LOWWAIT; | 1219 | set_bit(LOWWAIT, &ch->statusflags); |
1273 | return len; | 1220 | return len; |
1274 | } | 1221 | } |
1275 | 1222 | ||
@@ -1300,40 +1247,21 @@ static int moxa_chars_in_buffer(struct tty_struct *tty) | |||
1300 | struct moxa_port *ch = tty->driver_data; | 1247 | struct moxa_port *ch = tty->driver_data; |
1301 | int chars; | 1248 | int chars; |
1302 | 1249 | ||
1303 | /* | ||
1304 | * Sigh...I have to check if driver_data is NULL here, because | ||
1305 | * if an open() fails, the TTY subsystem eventually calls | ||
1306 | * tty_wait_until_sent(), which calls the driver's chars_in_buffer() | ||
1307 | * routine. And since the open() failed, we return 0 here. TDJ | ||
1308 | */ | ||
1309 | if (ch == NULL) | ||
1310 | return 0; | ||
1311 | lock_kernel(); | ||
1312 | chars = MoxaPortTxQueue(ch); | 1250 | chars = MoxaPortTxQueue(ch); |
1313 | if (chars) { | 1251 | if (chars) |
1314 | /* | 1252 | /* |
1315 | * Make it possible to wakeup anything waiting for output | 1253 | * Make it possible to wakeup anything waiting for output |
1316 | * in tty_ioctl.c, etc. | 1254 | * in tty_ioctl.c, etc. |
1317 | */ | 1255 | */ |
1318 | if (!(ch->statusflags & EMPTYWAIT)) | 1256 | set_bit(EMPTYWAIT, &ch->statusflags); |
1319 | moxa_setup_empty_event(tty); | ||
1320 | } | ||
1321 | unlock_kernel(); | ||
1322 | return chars; | 1257 | return chars; |
1323 | } | 1258 | } |
1324 | 1259 | ||
1325 | static int moxa_tiocmget(struct tty_struct *tty, struct file *file) | 1260 | static int moxa_tiocmget(struct tty_struct *tty, struct file *file) |
1326 | { | 1261 | { |
1327 | struct moxa_port *ch; | 1262 | struct moxa_port *ch = tty->driver_data; |
1328 | int flag = 0, dtr, rts; | 1263 | int flag = 0, dtr, rts; |
1329 | 1264 | ||
1330 | mutex_lock(&moxa_openlock); | ||
1331 | ch = tty->driver_data; | ||
1332 | if (!ch) { | ||
1333 | mutex_unlock(&moxa_openlock); | ||
1334 | return -EINVAL; | ||
1335 | } | ||
1336 | |||
1337 | MoxaPortGetLineOut(ch, &dtr, &rts); | 1265 | MoxaPortGetLineOut(ch, &dtr, &rts); |
1338 | if (dtr) | 1266 | if (dtr) |
1339 | flag |= TIOCM_DTR; | 1267 | flag |= TIOCM_DTR; |
@@ -1346,7 +1274,6 @@ static int moxa_tiocmget(struct tty_struct *tty, struct file *file) | |||
1346 | flag |= TIOCM_DSR; | 1274 | flag |= TIOCM_DSR; |
1347 | if (dtr & 4) | 1275 | if (dtr & 4) |
1348 | flag |= TIOCM_CD; | 1276 | flag |= TIOCM_CD; |
1349 | mutex_unlock(&moxa_openlock); | ||
1350 | return flag; | 1277 | return flag; |
1351 | } | 1278 | } |
1352 | 1279 | ||
@@ -1379,20 +1306,6 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file, | |||
1379 | return 0; | 1306 | return 0; |
1380 | } | 1307 | } |
1381 | 1308 | ||
1382 | static void moxa_throttle(struct tty_struct *tty) | ||
1383 | { | ||
1384 | struct moxa_port *ch = tty->driver_data; | ||
1385 | |||
1386 | ch->statusflags |= THROTTLE; | ||
1387 | } | ||
1388 | |||
1389 | static void moxa_unthrottle(struct tty_struct *tty) | ||
1390 | { | ||
1391 | struct moxa_port *ch = tty->driver_data; | ||
1392 | |||
1393 | ch->statusflags &= ~THROTTLE; | ||
1394 | } | ||
1395 | |||
1396 | static void moxa_set_termios(struct tty_struct *tty, | 1309 | static void moxa_set_termios(struct tty_struct *tty, |
1397 | struct ktermios *old_termios) | 1310 | struct ktermios *old_termios) |
1398 | { | 1311 | { |
@@ -1412,7 +1325,7 @@ static void moxa_stop(struct tty_struct *tty) | |||
1412 | if (ch == NULL) | 1325 | if (ch == NULL) |
1413 | return; | 1326 | return; |
1414 | MoxaPortTxDisable(ch); | 1327 | MoxaPortTxDisable(ch); |
1415 | ch->statusflags |= TXSTOPPED; | 1328 | set_bit(TXSTOPPED, &ch->statusflags); |
1416 | } | 1329 | } |
1417 | 1330 | ||
1418 | 1331 | ||
@@ -1427,38 +1340,32 @@ static void moxa_start(struct tty_struct *tty) | |||
1427 | return; | 1340 | return; |
1428 | 1341 | ||
1429 | MoxaPortTxEnable(ch); | 1342 | MoxaPortTxEnable(ch); |
1430 | ch->statusflags &= ~TXSTOPPED; | 1343 | clear_bit(TXSTOPPED, &ch->statusflags); |
1431 | } | 1344 | } |
1432 | 1345 | ||
1433 | static void moxa_hangup(struct tty_struct *tty) | 1346 | static void moxa_hangup(struct tty_struct *tty) |
1434 | { | 1347 | { |
1435 | struct moxa_port *ch; | 1348 | struct moxa_port *ch = tty->driver_data; |
1436 | 1349 | tty_port_hangup(&ch->port); | |
1437 | mutex_lock(&moxa_openlock); | ||
1438 | ch = tty->driver_data; | ||
1439 | if (ch == NULL) { | ||
1440 | mutex_unlock(&moxa_openlock); | ||
1441 | return; | ||
1442 | } | ||
1443 | ch->port.count = 0; | ||
1444 | moxa_close_port(tty); | ||
1445 | mutex_unlock(&moxa_openlock); | ||
1446 | |||
1447 | wake_up_interruptible(&ch->port.open_wait); | ||
1448 | } | 1350 | } |
1449 | 1351 | ||
1450 | static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd) | 1352 | static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd) |
1451 | { | 1353 | { |
1452 | struct tty_struct *tty; | 1354 | struct tty_struct *tty; |
1355 | unsigned long flags; | ||
1453 | dcd = !!dcd; | 1356 | dcd = !!dcd; |
1454 | 1357 | ||
1358 | spin_lock_irqsave(&p->port.lock, flags); | ||
1455 | if (dcd != p->DCDState) { | 1359 | if (dcd != p->DCDState) { |
1360 | p->DCDState = dcd; | ||
1361 | spin_unlock_irqrestore(&p->port.lock, flags); | ||
1456 | tty = tty_port_tty_get(&p->port); | 1362 | tty = tty_port_tty_get(&p->port); |
1457 | if (tty && C_CLOCAL(tty) && !dcd) | 1363 | if (tty && C_CLOCAL(tty) && !dcd) |
1458 | tty_hangup(tty); | 1364 | tty_hangup(tty); |
1459 | tty_kref_put(tty); | 1365 | tty_kref_put(tty); |
1460 | } | 1366 | } |
1461 | p->DCDState = dcd; | 1367 | else |
1368 | spin_unlock_irqrestore(&p->port.lock, flags); | ||
1462 | } | 1369 | } |
1463 | 1370 | ||
1464 | static int moxa_poll_port(struct moxa_port *p, unsigned int handle, | 1371 | static int moxa_poll_port(struct moxa_port *p, unsigned int handle, |
@@ -1470,24 +1377,24 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle, | |||
1470 | u16 intr; | 1377 | u16 intr; |
1471 | 1378 | ||
1472 | if (tty) { | 1379 | if (tty) { |
1473 | if ((p->statusflags & EMPTYWAIT) && | 1380 | if (test_bit(EMPTYWAIT, &p->statusflags) && |
1474 | MoxaPortTxQueue(p) == 0) { | 1381 | MoxaPortTxQueue(p) == 0) { |
1475 | p->statusflags &= ~EMPTYWAIT; | 1382 | clear_bit(EMPTYWAIT, &p->statusflags); |
1476 | tty_wakeup(tty); | 1383 | tty_wakeup(tty); |
1477 | } | 1384 | } |
1478 | if ((p->statusflags & LOWWAIT) && !tty->stopped && | 1385 | if (test_bit(LOWWAIT, &p->statusflags) && !tty->stopped && |
1479 | MoxaPortTxQueue(p) <= WAKEUP_CHARS) { | 1386 | MoxaPortTxQueue(p) <= WAKEUP_CHARS) { |
1480 | p->statusflags &= ~LOWWAIT; | 1387 | clear_bit(LOWWAIT, &p->statusflags); |
1481 | tty_wakeup(tty); | 1388 | tty_wakeup(tty); |
1482 | } | 1389 | } |
1483 | 1390 | ||
1484 | if (inited && !(p->statusflags & THROTTLE) && | 1391 | if (inited && !test_bit(TTY_THROTTLED, &tty->flags) && |
1485 | MoxaPortRxQueue(p) > 0) { /* RX */ | 1392 | MoxaPortRxQueue(p) > 0) { /* RX */ |
1486 | MoxaPortReadData(p); | 1393 | MoxaPortReadData(p); |
1487 | tty_schedule_flip(tty); | 1394 | tty_schedule_flip(tty); |
1488 | } | 1395 | } |
1489 | } else { | 1396 | } else { |
1490 | p->statusflags &= ~EMPTYWAIT; | 1397 | clear_bit(EMPTYWAIT, &p->statusflags); |
1491 | MoxaPortFlushData(p, 0); /* flush RX */ | 1398 | MoxaPortFlushData(p, 0); /* flush RX */ |
1492 | } | 1399 | } |
1493 | 1400 | ||
@@ -1588,35 +1495,6 @@ static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_term | |||
1588 | tty_encode_baud_rate(tty, baud, baud); | 1495 | tty_encode_baud_rate(tty, baud, baud); |
1589 | } | 1496 | } |
1590 | 1497 | ||
1591 | static void moxa_setup_empty_event(struct tty_struct *tty) | ||
1592 | { | ||
1593 | struct moxa_port *ch = tty->driver_data; | ||
1594 | |||
1595 | spin_lock_bh(&moxa_lock); | ||
1596 | ch->statusflags |= EMPTYWAIT; | ||
1597 | spin_unlock_bh(&moxa_lock); | ||
1598 | } | ||
1599 | |||
1600 | static void moxa_shut_down(struct tty_struct *tty) | ||
1601 | { | ||
1602 | struct moxa_port *ch = tty->driver_data; | ||
1603 | |||
1604 | if (!(ch->port.flags & ASYNC_INITIALIZED)) | ||
1605 | return; | ||
1606 | |||
1607 | MoxaPortDisable(ch); | ||
1608 | |||
1609 | /* | ||
1610 | * If we're a modem control device and HUPCL is on, drop RTS & DTR. | ||
1611 | */ | ||
1612 | if (C_HUPCL(tty)) | ||
1613 | MoxaPortLineCtrl(ch, 0, 0); | ||
1614 | |||
1615 | spin_lock_bh(&moxa_lock); | ||
1616 | ch->port.flags &= ~ASYNC_INITIALIZED; | ||
1617 | spin_unlock_bh(&moxa_lock); | ||
1618 | } | ||
1619 | |||
1620 | /***************************************************************************** | 1498 | /***************************************************************************** |
1621 | * Driver level functions: * | 1499 | * Driver level functions: * |
1622 | *****************************************************************************/ | 1500 | *****************************************************************************/ |
@@ -1918,10 +1796,12 @@ static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio, | |||
1918 | baud = MoxaPortSetBaud(port, baud); | 1796 | baud = MoxaPortSetBaud(port, baud); |
1919 | 1797 | ||
1920 | if (termio->c_iflag & (IXON | IXOFF | IXANY)) { | 1798 | if (termio->c_iflag & (IXON | IXOFF | IXANY)) { |
1799 | spin_lock_irq(&moxafunc_lock); | ||
1921 | writeb(termio->c_cc[VSTART], ofsAddr + FuncArg); | 1800 | writeb(termio->c_cc[VSTART], ofsAddr + FuncArg); |
1922 | writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1); | 1801 | writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1); |
1923 | writeb(FC_SetXonXoff, ofsAddr + FuncCode); | 1802 | writeb(FC_SetXonXoff, ofsAddr + FuncCode); |
1924 | moxa_wait_finish(ofsAddr); | 1803 | moxa_wait_finish(ofsAddr); |
1804 | spin_unlock_irq(&moxafunc_lock); | ||
1925 | 1805 | ||
1926 | } | 1806 | } |
1927 | return baud; | 1807 | return baud; |
@@ -1974,18 +1854,14 @@ static int MoxaPortLineStatus(struct moxa_port *port) | |||
1974 | int val; | 1854 | int val; |
1975 | 1855 | ||
1976 | ofsAddr = port->tableAddr; | 1856 | ofsAddr = port->tableAddr; |
1977 | if (MOXA_IS_320(port->board)) { | 1857 | if (MOXA_IS_320(port->board)) |
1978 | moxafunc(ofsAddr, FC_LineStatus, 0); | 1858 | val = moxafuncret(ofsAddr, FC_LineStatus, 0); |
1979 | val = readw(ofsAddr + FuncArg); | 1859 | else |
1980 | } else { | ||
1981 | val = readw(ofsAddr + FlagStat) >> 4; | 1860 | val = readw(ofsAddr + FlagStat) >> 4; |
1982 | } | ||
1983 | val &= 0x0B; | 1861 | val &= 0x0B; |
1984 | if (val & 8) | 1862 | if (val & 8) |
1985 | val |= 4; | 1863 | val |= 4; |
1986 | spin_lock_bh(&moxa_lock); | ||
1987 | moxa_new_dcdstate(port, val & 8); | 1864 | moxa_new_dcdstate(port, val & 8); |
1988 | spin_unlock_bh(&moxa_lock); | ||
1989 | val &= 7; | 1865 | val &= 7; |
1990 | return val; | 1866 | return val; |
1991 | } | 1867 | } |