MOXA linux-2.6.x / linux-2.6.19-uc1 from UC-7110-LX-BOOTLOADER-1.9_VERSION-4.2.tgz
[linux-2.6.19-moxart.git] / drivers / char / mxser.c
blob3edb0f278b06753f253e594c1e2ca33db79620d9
1 /*
2 * mxser.c -- MOXA Smartio/Industio family multiport serial driver.
4 * Copyright (C) 1999-2001 Moxa Technologies (support@moxa.com.tw).
6 * This code is loosely based on the Linux serial driver, written by
7 * Linus Torvalds, Theodore T'so and others.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * Original release 10/26/00
25 * 02/06/01 Support MOXA Industio family boards.
26 * 02/06/01 Support TIOCGICOUNT.
27 * 02/06/01 Fix the problem for connecting to serial mouse.
28 * 02/06/01 Fix the problem for H/W flow control.
29 * 02/06/01 Fix the compling warning when CONFIG_PCI
30 * don't be defined.
31 * 08/12/04 Add to supprt special baud rate
32 * 09/17/04 To support by pass flip, and directly send to ldisc
33 * 12/28/04 Add to support TIOCSBRK, TIOCCBRK ioctl.
34 * 12/31/04 Add TICOM_BRK, TICOM_PARITY & TIOCM_FRAME on TIOCMIWAIT input argument for Moxa
35 * private RealCOM used.
36 * 01/04/05 Add TICOM_XOFFHOLD and use buf_overrun to note xoff hold to support RealCOM.
37 * 02/04/05 Add to support for Q-Free specical used.
38 * 11/22/05 Porting to Moxa Embedded system.
40 #if 1 // add by Victor Yu. 02-09-2007
41 #include <linux/version.h>
42 #endif
43 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-09-2007
44 #include <linux/config.h>
45 #endif
46 #include <asm/arch/moxa.h>
47 #include <linux/module.h>
48 #include <asm/arch/cpe_int.h>
49 #include <linux/version.h>
50 #include <linux/autoconf.h>
51 #include <linux/errno.h>
52 #include <linux/signal.h>
53 #include <linux/sched.h>
54 #include <linux/timer.h>
55 #include <linux/interrupt.h>
56 #include <linux/tty.h>
57 #include <linux/tty_flip.h>
58 #include <linux/serial.h>
59 #include <linux/serial_reg.h>
61 #include <linux/major.h>
62 #include <linux/string.h>
63 #include <linux/fcntl.h>
64 #include <linux/ptrace.h>
65 #include <linux/ioport.h>
66 #include <linux/mm.h>
67 #include <linux/smp_lock.h>
68 #include <linux/delay.h>
69 #include <linux/init.h>
70 #if 1 // add by Victor Yu. 02-21-2006
71 #include <linux/proc_fs.h>
72 #endif
74 #include <asm/system.h>
75 #include <asm/io.h>
76 #include <asm/irq.h>
77 #include <asm/segment.h>
78 #include <asm/bitops.h>
80 #define VERSION_CODE(ver,rel,seq) ((ver << 16) | (rel << 8) | seq)
82 #define MXSER_VERSION "2.0"
83 #define MXSERMAJOR 30
84 #define MXSERCUMAJOR 35
86 #ifdef CONFIG_PCI
87 #if (LINUX_VERSION_CODE < VERSION_CODE(2,1,0))
88 #include <linux/bios32.h>
89 #endif
90 #include <linux/pci.h>
91 #endif /* ENABLE_PCI */
93 #include <asm/uaccess.h>
94 #define put_to_user(arg1, arg2) put_user(arg1, (unsigned long *)arg2)
95 #define get_from_user(arg1, arg2) get_user(arg1, (unsigned int *)arg2)
97 #ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006, to use embedded UART
98 #undef UART_RX
99 #undef UART_TX
100 #undef UART_DLL
101 #undef UART_TRG
102 #undef UART_DLM
103 #undef UART_IER
104 #undef UART_FCTR
105 #undef UART_IIR
106 #undef UART_FCR
107 #undef UART_EFR
108 #undef UART_LCR
109 #undef UART_MCR
110 #undef UART_LSR
111 #undef UART_MSR
112 #undef UART_SCR
113 #undef UART_EMSR
114 #define UART_RX 0
115 #define UART_TX 0
116 #define UART_DLL 0
117 #define UART_TRG 0
118 #define UART_DLM 4
119 #define UART_IER 4
120 #define UART_FCTR 4
121 #define UART_IIR 8
122 #define UART_FCR 8
123 #define UART_EFR 8
124 #define UART_LCR 12
125 #define UART_MCR 16
126 #define UART_LSR 20
127 #define UART_MSR 24
128 #define UART_SCR 28
129 #define UART_EMSR 28
130 #endif
132 #define MXSER_EVENT_TXLOW 1
133 #define MXSER_EVENT_HANGUP 2
135 #define SERIAL_DO_RESTART
137 #define MXSER_BOARDS 4 /* Max. boards */
138 #define MXSER_PORTS 32 /* Max. ports */
139 #define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board*/
140 #define MXSER_ISR_PASS_LIMIT 256 // mask by Victor Yu. 02-04-2005
142 #define MXSER_ERR_IOADDR -1
143 #define MXSER_ERR_IRQ -2
144 #define MXSER_ERR_IRQ_CONFLIT -3
145 #define MXSER_ERR_VECTOR -4
147 #define SERIAL_TYPE_NORMAL 1
148 #define SERIAL_TYPE_CALLOUT 2
150 #define WAKEUP_CHARS 256
152 #define UART_MCR_AFE 0x20
153 #define UART_LSR_SPECIAL 0x1E
155 #if 0
156 #define PORTNO(x) (MINOR((x)->device) - (x)->driver.minor_start)
157 #else
158 #define PORTNO(x) ((x)->index)
159 #endif
161 #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
163 #define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
165 #ifndef MIN
166 #define MIN(a,b) ((a) < (b) ? (a) : (b))
167 #endif
169 enum {
170 UC7110_BOARD=1,
173 static char *mxser_brdname[] = {
174 "MU860 UART",
177 /* FIXME */
178 static int mxser_numports[] = {
182 typedef struct {
183 unsigned short vendor_id;
184 unsigned short device_id;
185 unsigned short board_type;
186 } mxser_pciinfo;
188 #ifdef CONFIG_ARCH_IA241 // add by Victor Yu. 02-16-2006
189 static mxser_pciinfo mxser_pcibrds[] = {
190 {0x1393,0x0001,UC7110_BOARD},
192 #endif
195 * MOXA ioctls
197 #define MOXA 0x400
198 #define MOXA_GETDATACOUNT (MOXA + 23)
199 #define MOXA_GET_CONF (MOXA + 35)
200 #define MOXA_DIAGNOSE (MOXA + 50)
201 #define MOXA_CHKPORTENABLE (MOXA + 60)
202 #define MOXA_HighSpeedOn (MOXA + 61)
203 #define MOXA_GET_MAJOR (MOXA + 63)
204 #define MOXA_GET_CUMAJOR (MOXA + 64)
205 #define MOXA_GETMSTATUS (MOXA + 65)
207 // following add by Victor Yu. 01-05-2004
208 #define MOXA_SET_OP_MODE (MOXA + 66)
209 #define MOXA_GET_OP_MODE (MOXA + 67)
210 #if 1 // add by Victor Yu. 05-02-2007, for GL ODM, I let it to be a Moxa standard feature
211 #define MOXA_BREAK_TIMER (MOXA+70)
212 #endif
214 #if 1 // add by Victor Yu. 01-26-2005
215 #define MOXA_UNWAIT (MOXA+200)
216 #define MXSER_PROC_NODE "driver/mxser" // add by Victor Yu. 07-27-2004
217 #endif
219 #define RS232_MODE 0
220 #define RS485_2WIRE_MODE 1
221 #define RS422_MODE 2
222 #define RS485_4WIRE_MODE 3
223 #define OP_MODE_MASK 3
224 // above add by Victor Yu. 01-05-2004
226 #define CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE
227 #ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-12-2004
228 #define MOXA_SET_SPECIAL_BAUD_RATE (MOXA+68)
229 #define MOXA_GET_SPECIAL_BAUD_RATE (MOXA+69)
230 #define NEW_MOXA_SET_SPECIAL_BAUD_RATE (MOXA+100)
231 #define NEW_MOXA_GET_SPECIAL_BAUD_RATE (MOXA+101)
232 #endif
234 static int ttymajor=MXSERMAJOR;
235 static int calloutmajor=MXSERCUMAJOR;
236 static int verbose=0;
238 /* Variables for insmod */
239 MODULE_AUTHOR("Victor Yu.");
240 MODULE_LICENSE("GPL");
241 MODULE_DESCRIPTION("MOXA MU860 UART Device Driver");
243 typedef struct _moxa_pci_info {
244 unsigned short busNum;
245 unsigned short devNum;
246 struct pci_dev *pdev; // add by Victor Yu. 06-23-2003
247 } moxa_pci_info;
249 struct mxser_hwconf {
250 int board_type;
251 int ports;
252 int irq;
253 int vector;
254 int vector_mask;
255 int uart_type;
256 int ioaddr[MXSER_PORTS_PER_BOARD];
257 int baud_base[MXSER_PORTS_PER_BOARD];
258 moxa_pci_info pciInfo;
259 int MaxCanSetBaudRate[MXSER_PORTS_PER_BOARD]; // add by Victor Yu. 09-04-2002
260 int opmode_ioaddr[MXSER_PORTS_PER_BOARD]; // add by Victor Yu. 01-05-2004
263 struct mxser_struct {
264 int port;
265 int base; /* port base address */
266 int irq; /* port using irq no. */
267 int vector; /* port irq vector */
268 int vectormask; /* port vector mask */
269 int rx_trigger; /* Rx fifo trigger level */
270 int baud_base; /* max. speed */
271 int flags; /* defined in tty.h */
272 int type; /* UART type */
273 struct tty_struct * tty;
274 int read_status_mask;
275 int ignore_status_mask;
276 int xmit_fifo_size;
277 int custom_divisor;
278 int x_char; /* xon/xoff character */
279 int close_delay;
280 unsigned short closing_wait;
281 int IER; /* Interrupt Enable Register */
282 int MCR; /* Modem control register */
283 unsigned long event;
284 int count; /* # of fd on device */
285 int blocked_open; /* # of blocked opens */
286 #if 0
287 long session; /* Session of opening process */
288 long pgrp; /* pgrp of opening process */
289 #endif
290 unsigned char *xmit_buf;
291 int xmit_head;
292 int xmit_tail;
293 int xmit_cnt;
294 struct work_struct tqueue;
295 struct termios normal_termios;
296 wait_queue_head_t open_wait;
297 wait_queue_head_t close_wait;
298 wait_queue_head_t delta_msr_wait;
299 struct async_icount icount; /* kernel counters for the 4 input interrupts */
300 int timeout;
301 int MaxCanSetBaudRate; // add by Victor Yu. 09-04-2002
302 int opmode_ioaddr; // add by Victor Yu. 01-05-2004
303 #ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-12-2004
304 int speed;
305 #endif
308 struct mxser_log {
309 int tick;
310 int rxcnt[MXSER_PORTS];
311 int txcnt[MXSER_PORTS];
314 struct mxser_mstatus{
315 tcflag_t cflag;
316 int cts;
317 int dsr;
318 int ri;
319 int dcd;
322 static struct mxser_mstatus GMStatus[MXSER_PORTS];
324 static struct tty_driver mxvar_sdriver;
325 static struct mxser_struct mxvar_table[MXSER_PORTS];
326 static struct termios * mxvar_termios[MXSER_PORTS+1];
327 static struct termios * mxvar_termios_locked[MXSER_PORTS+1];
328 static struct mxser_log mxvar_log;
329 static int mxvar_diagflag;
331 * mxvar_tmp_buf is used as a temporary buffer by serial_write. We need
332 * to lock it in case the memcpy_fromfs blocks while swapping in a page,
333 * and some other program tries to do a serial write at the same time.
334 * Since the lock will only come under contention when the system is
335 * swapping and available memory is low, it makes sense to share one
336 * buffer across all the serial ports, since it significantly saves
337 * memory if large numbers of serial ports are open.
339 static unsigned char * mxvar_tmp_buf;
340 static struct semaphore mxvar_tmp_buf_sem;
343 * This is used to figure out the divisor speeds and the timeouts
345 #define B50_INDEX 1 // add by Victor Yu. 08-12-2004
346 static int mxvar_baud_table[] = {
347 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
348 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600, 0 };
349 #define BAUD_TABLE_NO (sizeof(mxvar_baud_table)/sizeof(int))
351 struct mxser_hwconf mxsercfg[MXSER_BOARDS];
354 * static functions:
356 #if 1 // add by Victor Yu. 02-21-2006
357 static int mxser_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data); // add by Victor Yu. 07-27-2004
358 #endif
359 static void mxser_getcfg(int board,struct mxser_hwconf *hwconf);
360 int mxser_init(void);
361 #ifdef CONFIG_ARCH_IA241 // add by Victor Yu. 02-16-2006
362 static int mxser_get_PCI_conf(int ,struct mxser_hwconf *);
363 #endif
364 static void mxser_do_softint(void *);
365 static int mxser_open(struct tty_struct *, struct file *);
366 static void mxser_close(struct tty_struct *, struct file *);
367 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-16-2007
368 static int mxser_write(struct tty_struct *, const unsigned char *, int);
369 #else
370 static int mxser_write(struct tty_struct *, int, const unsigned char *, int);
371 #endif // LINUX_VERSION_CODE
372 static int mxser_write_room(struct tty_struct *);
373 static void mxser_flush_buffer(struct tty_struct *);
374 static int mxser_chars_in_buffer(struct tty_struct *);
375 static void mxser_flush_chars(struct tty_struct *);
376 static void mxser_put_char(struct tty_struct *, unsigned char);
377 static int mxser_ioctl(struct tty_struct *, struct file *, uint, ulong);
378 static int mxser_ioctl_special(unsigned int, unsigned long);
379 static void mxser_throttle(struct tty_struct *);
380 static void mxser_unthrottle(struct tty_struct *);
381 static void mxser_set_termios(struct tty_struct *, struct termios *);
382 static void mxser_stop(struct tty_struct *);
383 static void mxser_start(struct tty_struct *);
384 static void mxser_hangup(struct tty_struct *);
385 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-16-2007
386 static irqreturn_t mxser_interrupt(int, void *);
387 #else
388 static irqreturn_t mxser_interrupt(int, void *, struct pt_regs *);
389 #endif
390 static inline void mxser_receive_chars(struct mxser_struct *, int *);
391 static inline void mxser_transmit_chars(struct mxser_struct *);
392 static inline void mxser_check_modem_status(struct mxser_struct *, int);
393 static int mxser_block_til_ready(struct tty_struct *, struct file *, struct mxser_struct *);
394 static int mxser_startup(struct mxser_struct *);
395 static void mxser_shutdown(struct mxser_struct *);
396 static int mxser_change_speed(struct mxser_struct *, struct termios *old_termios);
397 static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct *);
398 static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct *);
399 static int mxser_get_lsr_info(struct mxser_struct *, unsigned int *);
400 static void mxser_send_break(struct mxser_struct *, int);
401 #if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) // add by Victor Yu. 04-28-2006, for 2.6.x
402 static int mxser_get_modem_info(struct mxser_struct *, unsigned int *);
403 static int mxser_set_modem_info(struct mxser_struct *, unsigned int, unsigned int *);
404 #endif
405 static void mxser_wait_until_sent(struct tty_struct *tty, int timeout);
407 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,6,0)) // add by Victor Yu. 04-28-2006, for 2.6.x
408 static int mxser_tiocmget(struct tty_struct *tty, struct file *file);
409 static int mxser_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear);
410 #endif
412 // follwoing is modified by Victor Yu. 08-15-2002
414 // follow just for Moxa Must chip define.
416 // when LCR register (offset 0x03) write following value,
417 // the Must chip will enter enchance mode. And write value
418 // on EFR (offset 0x02) bit 6,7 to change bank.
419 #define MOXA_MUST_ENTER_ENCHANCE 0xBF
421 // when enhance mode enable, access on general bank register
422 #ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006
423 #define MOXA_MUST_GDL_REGISTER 28
424 #else
425 #define MOXA_MUST_GDL_REGISTER 7
426 #endif
428 #define MOXA_MUST_GDL_MASK 0x7F
429 #define MOXA_MUST_GDL_HAS_BAD_DATA 0x80
431 #define MOXA_MUST_LSR_RERR 0x80 // error in receive FIFO
432 // enchance register bank select and enchance mode setting register
433 // when LCR register equal to 0xBF
434 #ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006
435 #define MOXA_MUST_EFR_REGISTER 8
436 #else
437 #define MOXA_MUST_EFR_REGISTER 2
438 #endif
440 // enchance mode enable
441 #define MOXA_MUST_EFR_EFRB_ENABLE 0x10
442 // enchance reister bank set 0, 1, 2
443 #define MOXA_MUST_EFR_BANK0 0x00
444 #define MOXA_MUST_EFR_BANK1 0x40
445 #define MOXA_MUST_EFR_BANK2 0x80
446 #define MOXA_MUST_EFR_BANK3 0xC0
447 #define MOXA_MUST_EFR_BANK_MASK 0xC0
449 // set XON1 value register, when LCR=0xBF and change to bank0
450 #ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006
451 #define MOXA_MUST_XON1_REGISTER 16
452 #else
453 #define MOXA_MUST_XON1_REGISTER 4
454 #endif
456 // set XON2 value register, when LCR=0xBF and change to bank0
457 #ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006
458 #define MOXA_MUST_XON2_REGISTER 20
459 #else
460 #define MOXA_MUST_XON2_REGISTER 5
461 #endif
463 // set XOFF1 value register, when LCR=0xBF and change to bank0
464 #ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006
465 #define MOXA_MUST_XOFF1_REGISTER 24
466 #else
467 #define MOXA_MUST_XOFF1_REGISTER 6
468 #endif
470 // set XOFF2 value register, when LCR=0xBF and change to bank0
471 #ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006
472 #define MOXA_MUST_XOFF2_REGISTER 28
473 #define MOXA_MUST_RBRTL_REGISTER 16
474 #define MOXA_MUST_RBRTH_REGISTER 20
475 #define MOXA_MUST_RBRTI_REGISTER 24
476 #define MOXA_MUST_THRTL_REGISTER 28
477 #define MOXA_MUST_ENUM_REGISTER 16
478 #define MOXA_MUST_HWID_REGISTER 20
479 #define MOXA_MUST_ECR_REGISTER 24
480 #define MOXA_MUST_CSR_REGISTER 28
481 #else
482 #define MOXA_MUST_XOFF2_REGISTER 7
483 #define MOXA_MUST_RBRTL_REGISTER 4
484 #define MOXA_MUST_RBRTH_REGISTER 5
485 #define MOXA_MUST_RBRTI_REGISTER 6
486 #define MOXA_MUST_THRTL_REGISTER 7
487 #define MOXA_MUST_ENUM_REGISTER 4
488 #define MOXA_MUST_HWID_REGISTER 5
489 #define MOXA_MUST_ECR_REGISTER 6
490 #define MOXA_MUST_CSR_REGISTER 7
491 #endif
493 // good data mode enable
494 #define MOXA_MUST_FCR_GDA_MODE_ENABLE 0x20
495 // only good data put into RxFIFO
496 #define MOXA_MUST_FCR_GDA_ONLY_ENABLE 0x10
498 // enable CTS interrupt
499 #define MOXA_MUST_IER_ECTSI 0x80
500 // eanble RTS interrupt
501 #define MOXA_MUST_IER_ERTSI 0x40
502 // enable Xon/Xoff interrupt
503 #define MOXA_MUST_IER_XINT 0x20
504 // enable GDA interrupt
505 #define MOXA_MUST_IER_EGDAI 0x10
507 #define MOXA_MUST_RECV_ISR (UART_IER_RDI | MOXA_MUST_IER_EGDAI)
509 // GDA interrupt pending
510 #define MOXA_MUST_IIR_GDA 0x1C
511 #define MOXA_MUST_IIR_RDA 0x04
512 #define MOXA_MUST_IIR_RTO 0x0C
513 #define MOXA_MUST_IIR_LSR 0x06
515 // recieved Xon/Xoff or specical interrupt pending
516 #define MOXA_MUST_IIR_XSC 0x10
518 // RTS/CTS change state interrupt pending
519 #define MOXA_MUST_IIR_RTSCTS 0x20
520 #define MOXA_MUST_IIR_MASK 0x3E
522 #define MOXA_MUST_MCR_XON_FLAG 0x40
523 #define MOXA_MUST_MCR_XON_ANY 0x80
524 #define MOXA_MUST_HARDWARE_ID 0x01
525 #define MOXA_MUST_HARDWARE_ID1 0x02
527 // software flow control on chip mask value
528 #define MOXA_MUST_EFR_SF_MASK 0x0F
529 // send Xon1/Xoff1
530 #define MOXA_MUST_EFR_SF_TX1 0x08
531 // send Xon2/Xoff2
532 #define MOXA_MUST_EFR_SF_TX2 0x04
533 // send Xon1,Xon2/Xoff1,Xoff2
534 #define MOXA_MUST_EFR_SF_TX12 0x0C
535 // don't send Xon/Xoff
536 #define MOXA_MUST_EFR_SF_TX_NO 0x00
537 // Tx software flow control mask
538 #define MOXA_MUST_EFR_SF_TX_MASK 0x0C
539 // don't receive Xon/Xoff
540 #define MOXA_MUST_EFR_SF_RX_NO 0x00
541 // receive Xon1/Xoff1
542 #define MOXA_MUST_EFR_SF_RX1 0x02
543 // receive Xon2/Xoff2
544 #define MOXA_MUST_EFR_SF_RX2 0x01
545 // receive Xon1,Xon2/Xoff1,Xoff2
546 #define MOXA_MUST_EFR_SF_RX12 0x03
547 // Rx software flow control mask
548 #define MOXA_MUST_EFR_SF_RX_MASK 0x03
550 #define MOXA_MUST_MIN_XOFFLIMIT 66
551 #define MOXA_MUST_MIN_XONLIMIT 20
553 #ifndef UCHAR
554 typedef unsigned char UCHAR;
555 #endif
557 #define CHECK_MOXA_MUST_XOFFLIMIT(info) { \
558 if ( (info)->HandFlow.XoffLimit < MOXA_MUST_MIN_XOFFLIMIT ) { \
559 (info)->HandFlow.XoffLimit = MOXA_MUST_MIN_XOFFLIMIT; \
560 (info)->HandFlow.XonLimit = MOXA_MUST_MIN_XONLIMIT; \
564 #define ENABLE_MOXA_MUST_ENCHANCE_MODE(baseio) { \
565 UCHAR __oldlcr, __efr; \
566 __oldlcr = inb((baseio)+UART_LCR); \
567 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
568 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
569 __efr |= MOXA_MUST_EFR_EFRB_ENABLE; \
570 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
571 outb(__oldlcr, (baseio)+UART_LCR); \
574 #define DISABLE_MOXA_MUST_ENCHANCE_MODE(baseio) { \
575 UCHAR __oldlcr, __efr; \
576 __oldlcr = inb((baseio)+UART_LCR); \
577 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
578 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
579 __efr &= ~MOXA_MUST_EFR_EFRB_ENABLE; \
580 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
581 outb(__oldlcr, (baseio)+UART_LCR); \
584 #define SET_MOXA_MUST_XON1_VALUE(baseio, Value) { \
585 UCHAR __oldlcr, __efr; \
586 __oldlcr = inb((baseio)+UART_LCR); \
587 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
588 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
589 __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
590 __efr |= MOXA_MUST_EFR_BANK0; \
591 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
592 outb((UCHAR)(Value), (baseio)+MOXA_MUST_XON1_REGISTER); \
593 outb(__oldlcr, (baseio)+UART_LCR); \
596 #define SET_MOXA_MUST_XON2_VALUE(baseio, Value) { \
597 UCHAR __oldlcr, __efr; \
598 __oldlcr = inb((baseio)+UART_LCR); \
599 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
600 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
601 __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
602 __efr |= MOXA_MUST_EFR_BANK0; \
603 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
604 outb((UCHAR)(Value), (baseio)+MOXA_MUST_XON2_REGISTER); \
605 outb(__oldlcr, (baseio)+UART_LCR); \
608 #define SET_MOXA_MUST_XOFF1_VALUE(baseio, Value) { \
609 UCHAR __oldlcr, __efr; \
610 __oldlcr = inb((baseio)+UART_LCR); \
611 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
612 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
613 __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
614 __efr |= MOXA_MUST_EFR_BANK0; \
615 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
616 outb((UCHAR)(Value), (baseio)+MOXA_MUST_XOFF1_REGISTER); \
617 outb(__oldlcr, (baseio)+UART_LCR); \
620 #define SET_MOXA_MUST_XOFF2_VALUE(baseio, Value) { \
621 UCHAR __oldlcr, __efr; \
622 __oldlcr = inb((baseio)+UART_LCR); \
623 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
624 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
625 __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
626 __efr |= MOXA_MUST_EFR_BANK0; \
627 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
628 outb((UCHAR)(Value), (baseio)+MOXA_MUST_XOFF2_REGISTER); \
629 outb(__oldlcr, (baseio)+UART_LCR); \
632 #define SET_MOXA_MUST_RBRTL_VALUE(baseio, Value) { \
633 UCHAR __oldlcr, __efr; \
634 __oldlcr = inb((baseio)+UART_LCR); \
635 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
636 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
637 __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
638 __efr |= MOXA_MUST_EFR_BANK1; \
639 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
640 outb((UCHAR)(Value), (baseio)+MOXA_MUST_RBRTL_REGISTER); \
641 outb(__oldlcr, (baseio)+UART_LCR); \
644 #define SET_MOXA_MUST_RBRTH_VALUE(baseio, Value) { \
645 UCHAR __oldlcr, __efr; \
646 __oldlcr = inb((baseio)+UART_LCR); \
647 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
648 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
649 __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
650 __efr |= MOXA_MUST_EFR_BANK1; \
651 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
652 outb((UCHAR)(Value), (baseio)+MOXA_MUST_RBRTH_REGISTER); \
653 outb(__oldlcr, (baseio)+UART_LCR); \
656 #define SET_MOXA_MUST_RBRTI_VALUE(baseio, Value) { \
657 UCHAR __oldlcr, __efr; \
658 __oldlcr = inb((baseio)+UART_LCR); \
659 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
660 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
661 __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
662 __efr |= MOXA_MUST_EFR_BANK1; \
663 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
664 outb((UCHAR)(Value), (baseio)+MOXA_MUST_RBRTI_REGISTER); \
665 outb(__oldlcr, (baseio)+UART_LCR); \
668 #define SET_MOXA_MUST_THRTL_VALUE(baseio, Value) { \
669 UCHAR __oldlcr, __efr; \
670 __oldlcr = inb((baseio)+UART_LCR); \
671 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
672 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
673 __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
674 __efr |= MOXA_MUST_EFR_BANK1; \
675 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
676 outb((UCHAR)(Value), (baseio)+MOXA_MUST_THRTL_REGISTER); \
677 outb(__oldlcr, (baseio)+UART_LCR); \
680 #define MOXA_MUST_RBRL_VALUE 4
681 #define SET_MOXA_MUST_FIFO_VALUE(info) { \
682 UCHAR __oldlcr, __efr; \
683 __oldlcr = inb((info)->base+UART_LCR); \
684 outb(MOXA_MUST_ENTER_ENCHANCE, (info)->base+UART_LCR); \
685 __efr = inb((info)->base+MOXA_MUST_EFR_REGISTER); \
686 __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
687 __efr |= MOXA_MUST_EFR_BANK1; \
688 outb(__efr, (info)->base+MOXA_MUST_EFR_REGISTER); \
689 outb((UCHAR)0, (info)->base+MOXA_MUST_THRTL_REGISTER); \
690 outb((UCHAR)((info)->rx_trigger), (info)->base+MOXA_MUST_RBRTH_REGISTER); \
691 if ( (info)->rx_trigger <= MOXA_MUST_RBRL_VALUE ) { \
692 outb((UCHAR)0, (info)->base+MOXA_MUST_RBRTI_REGISTER); \
693 outb((UCHAR)0, (info)->base+MOXA_MUST_RBRTL_REGISTER); \
694 } else { \
695 outb((UCHAR)((info)->rx_trigger-MOXA_MUST_RBRL_VALUE), \
696 (info)->base+MOXA_MUST_RBRTI_REGISTER); \
697 outb((UCHAR)((info)->rx_trigger-MOXA_MUST_RBRL_VALUE), \
698 (info)->base+MOXA_MUST_RBRTL_REGISTER); \
700 outb(__oldlcr, (info)->base+UART_LCR); \
703 #define SET_MOXA_MUST_ENUM_VALUE(baseio, Value) { \
704 UCHAR __oldlcr, __efr; \
705 __oldlcr = inb((baseio)+UART_LCR); \
706 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
707 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
708 __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
709 __efr |= MOXA_MUST_EFR_BANK2; \
710 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
711 outb((UCHAR)(Value), (baseio)+MOXA_MUST_ENUM_REGISTER); \
712 outb(__oldlcr, (baseio)+UART_LCR); \
715 #define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) { \
716 UCHAR __oldlcr, __efr; \
717 __oldlcr = inb((baseio)+UART_LCR); \
718 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
719 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
720 __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
721 __efr |= MOXA_MUST_EFR_BANK2; \
722 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
723 *pId = inb((baseio)+MOXA_MUST_HWID_REGISTER); \
724 outb(__oldlcr, (baseio)+UART_LCR); \
727 #define SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(baseio) { \
728 UCHAR __oldlcr, __efr; \
729 __oldlcr = inb((baseio)+UART_LCR); \
730 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
731 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
732 __efr &= ~MOXA_MUST_EFR_SF_MASK; \
733 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
734 outb(__oldlcr, (baseio)+UART_LCR); \
737 #define SET_MOXA_MUST_JUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \
738 UCHAR __oldlcr, __efr; \
739 __oldlcr = inb((baseio)+UART_LCR); \
740 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
741 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
742 __efr &= ~MOXA_MUST_EFR_SF_MASK; \
743 __efr |= MOXA_MUST_EFR_SF_TX1; \
744 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
745 outb(__oldlcr, (baseio)+UART_LCR); \
748 #define ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \
749 UCHAR __oldlcr, __efr; \
750 __oldlcr = inb((baseio)+UART_LCR); \
751 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
752 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
753 __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
754 __efr |= MOXA_MUST_EFR_SF_TX1; \
755 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
756 outb(__oldlcr, (baseio)+UART_LCR); \
759 #define DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) { \
760 UCHAR __oldlcr, __efr; \
761 __oldlcr = inb((baseio)+UART_LCR); \
762 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
763 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
764 __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
765 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
766 outb(__oldlcr, (baseio)+UART_LCR); \
769 #define SET_MOXA_MUST_JUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
770 UCHAR __oldlcr, __efr; \
771 __oldlcr = inb((baseio)+UART_LCR); \
772 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
773 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
774 __efr &= ~MOXA_MUST_EFR_SF_MASK; \
775 __efr |= MOXA_MUST_EFR_SF_RX1; \
776 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
777 outb(__oldlcr, (baseio)+UART_LCR); \
780 #define ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
781 UCHAR __oldlcr, __efr; \
782 __oldlcr = inb((baseio)+UART_LCR); \
783 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
784 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
785 __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
786 __efr |= MOXA_MUST_EFR_SF_RX1; \
787 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
788 outb(__oldlcr, (baseio)+UART_LCR); \
791 #define DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
792 UCHAR __oldlcr, __efr; \
793 __oldlcr = inb((baseio)+UART_LCR); \
794 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
795 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
796 __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
797 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
798 outb(__oldlcr, (baseio)+UART_LCR); \
801 #define ENABLE_MOXA_MUST_TX_RX_SOFTWARE_FLOW_CONTROL(baseio) { \
802 UCHAR __oldlcr, __efr; \
803 __oldlcr = inb((baseio)+UART_LCR); \
804 outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
805 __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
806 __efr &= ~MOXA_MUST_EFR_SF_MASK; \
807 __efr |= (MOXA_MUST_EFR_SF_RX1|MOXA_MUST_EFR_SF_TX1); \
808 outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
809 outb(__oldlcr, (baseio)+UART_LCR); \
812 #define ENABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(baseio) { \
813 UCHAR __oldmcr; \
814 __oldmcr = inb((baseio)+UART_MCR); \
815 __oldmcr |= MOXA_MUST_MCR_XON_ANY; \
816 outb(__oldmcr, (baseio)+UART_MCR); \
819 #define DISABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(baseio) { \
820 UCHAR __oldmcr; \
821 __oldmcr = inb((baseio)+UART_MCR); \
822 __oldmcr &= ~MOXA_MUST_MCR_XON_ANY; \
823 outb(__oldmcr, (baseio)+UART_MCR); \
826 #define READ_MOXA_MUST_GDL(baseio) inb((baseio)+MOXA_MUST_GDL_REGISTER)
828 #if 1 // add by Victor Yu. 02-21-2006
829 static int mxser_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
831 int len=0, board, port, p, i, j;
832 struct mxser_struct *info;
834 for ( board=0, port=0; board<MXSER_BOARDS; board++ ) {
835 if ( mxsercfg[board].board_type == -1 )
836 continue;
837 port += mxsercfg[board].ports;
839 #if 0
840 len = sprintf(page, "Ports: %d\n", port);
841 #else
842 len = sprintf(page, "%d\n", port);
843 #endif
844 if ( !port )
845 goto end_mxser_read_proc;
846 #if 0
847 len += sprintf(page+len, "PortNo InBytes OutBytes Speed Opened Interface DataBits Parity CTS DSR DCD RTS DTR\n");
848 #endif
849 for ( board=0, p=0; board<MXSER_BOARDS; board++ ) {
850 if ( mxsercfg[board].board_type == -1 )
851 continue;
852 for ( port=0, i=(board*MXSER_PORTS_PER_BOARD); port<mxsercfg[board].ports; port++, p++, i++ ) {
853 info = &mxvar_table[i];
855 // output PortNo InBytes OutBytes
856 #if 0
857 len += sprintf(page+len, "Port%d: %lu %lu", p, mxvar_log.rxcnt[i], mxvar_log.txcnt[i]);
858 #else
859 len += sprintf(page+len, "%lu %lu", mxvar_log.rxcnt[i], mxvar_log.txcnt[i]);
860 #endif
862 // output Speed Opened (1 - opened, 2 - not opened)
863 if ( info->count ) { // has opened
864 #if 0 // mask by Victor Yu. 02-21-2006
865 #ifndef B921600
866 #define B921600 (B460800 +1)
867 #endif
868 switch( info->tty->termios->c_cflag & (CBAUD | CBAUDEX) ){
869 #ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE
870 case B40000000 :
871 len += sprintf(page+len, " %d 1", info->speed);
872 goto read_proc_l1;
873 break;
874 #endif
875 case B921600 : j = 20; break;
876 case B460800 : j = 19; break;
877 case B230400 : j = 18; break;
878 case B115200 : j = 17; break;
879 case B57600 : j = 16; break;
880 case B38400 : j = 15; break;
881 case B19200 : j = 14; break;
882 case B9600 : j = 13; break;
883 case B4800 : j = 12; break;
884 case B2400 : j = 11; break;
885 case B1800 : j = 10; break;
886 case B1200 : j = 9; break;
887 case B600 : j = 8; break;
888 case B300 : j = 7; break;
889 case B200 : j = 6; break;
890 case B150 : j = 5; break;
891 case B134 : j = 4; break;
892 case B110 : j = 3; break;
893 case B75 : j = 2; break;
894 case B50 : j = 1; break;
895 default: j = 0; break;
898 if ( j == 15 ) {
899 if ( (info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI )
900 j = 16; /* 57600 bps */
901 if ( (info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI )
902 j = 17; /* 115200 bps */
903 #ifdef ASYNC_SPD_SHI
904 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
905 j = 18;
906 #endif
907 #ifdef ASYNC_SPD_WARP
908 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
909 j = 19;
910 #endif
912 len += sprintf(page+len, " %d 1", mxvar_baud_table[j]);
913 #else
914 len += sprintf(page+len, " %d 1", info->speed);
915 #endif
916 } else { // not opened
917 #if 0 // mask by Victor Yu. 02-21-2006
918 len += sprintf(page+len, " 9600 2");
919 #else
920 len += sprintf(page+len, " %d 2", info->speed);
921 #endif
924 // output interface (1-other, 2-rs232, 3-rs422, 4-rs423, 5-v35)
925 #if 0 // mask by Victor Yu. 02-21-2006
926 #ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE
927 read_proc_l1:
928 #endif
929 switch ( info->interface ) {
930 case RS232_MODE :
931 len += sprintf(page+len, " 2");
932 break;
933 case RS422_MODE :
934 len += sprintf(page+len, " 3");
935 break;
936 default :
937 len += sprintf(page+len, " 1");
938 break;
940 #else
942 int opmode;
943 int shiftbit;
944 #ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-16-2006
945 shiftbit = ((info->port%4)+2) * 2;
946 opmode = inl(info->opmode_ioaddr) >> shiftbit;
947 #else
948 shiftbit = (info->port%4) * 2;
949 opmode = inb(info->opmode_ioaddr) >> shiftbit;
950 #endif
951 opmode &= OP_MODE_MASK;
952 switch ( opmode ) {
953 case RS232_MODE :
954 len += sprintf(page+len, " 2");
955 break;
956 case RS422_MODE :
957 len += sprintf(page+len, " 3");
958 break;
959 default :
960 len += sprintf(page+len, " 1");
961 break;
964 #endif
966 // output data bits
967 if ( info->count ) { // has opened
968 switch ( info->tty->termios->c_cflag & CSIZE ) {
969 case CS5 :
970 len += sprintf(page+len, " 5");
971 break;
972 case CS6 :
973 len += sprintf(page+len, " 6");
974 break;
975 case CS7 :
976 len += sprintf(page+len, " 7");
977 break;
978 case CS8 :
979 default :
980 len += sprintf(page+len, " 8");
981 break;
983 } else { // not opened
984 len += sprintf(page+len, " 8");
987 // output stop bits (1-one, 2-two, 3-one-and-half, 4-dynamic)
988 if ( info->count ) { // has opened
989 if ( info->tty->termios->c_cflag & CSTOPB ) {
990 len += sprintf(page+len, " 2");
991 } else {
992 len += sprintf(page+len, " 1");
994 } else {
995 len += sprintf(page+len, " 1");
998 // output parity (1-none, 2-odd, 3-even, 4-mark, 5-space)
999 if ( info->count ) { // has opened
1000 if ( info->tty->termios->c_cflag & PARENB ) {
1001 if ( info->tty->termios->c_cflag & PARODD ) {
1002 len += sprintf(page+len, " 2");
1003 } else {
1004 len += sprintf(page+len, " 3");
1006 } else {
1007 len += sprintf(page+len, " 1");
1009 } else { // not opened
1010 len += sprintf(page+len, " 1");
1013 // output CTS DSR DCD status (1-none, 2-on, 3-off)
1014 j = inb(info->base+UART_MSR);
1015 if ( j & UART_MSR_CTS )
1016 len += sprintf(page+len, " 2");
1017 else
1018 len += sprintf(page+len, " 3");
1019 if ( j & UART_MSR_DSR )
1020 len += sprintf(page+len, " 2");
1021 else
1022 len += sprintf(page+len, " 3");
1023 if ( j & UART_MSR_DCD )
1024 len += sprintf(page+len, " 2");
1025 else
1026 len += sprintf(page+len, " 3");
1028 // output RTS DTR status (1-none, 2-on, 3-off)
1029 j = inb(info->base+UART_MCR);
1030 if ( j & UART_MCR_RTS )
1031 len += sprintf(page+len, " 2");
1032 else
1033 len += sprintf(page+len, " 3");
1034 if ( j & UART_MCR_DTR )
1035 len += sprintf(page+len, " 2");
1036 else
1037 len += sprintf(page+len, " 3");
1039 // end output
1040 len += sprintf(page+len, "\n");
1044 end_mxser_read_proc:
1045 if ( len <= (off + count) )
1046 *eof = 1;
1047 *start = page + off;
1048 len -= off;
1049 if ( len > count )
1050 len = count;
1051 if ( len < 0 )
1052 len = 0;
1054 return len;
1056 #endif
1059 * The MOXA Smartio/Industio serial driver boot-time initialization code!
1061 static int __init mxser_init_module(void)
1063 int ret;
1065 if (verbose)
1066 printk("Loading module mxser ...\n");
1067 ret = mxser_init();
1068 if (verbose)
1069 printk("Done.\n");
1070 return (ret);
1073 static void __exit mxser_exit_module(void)
1075 int i,err = 0;
1078 if (verbose)
1079 printk("Unloading module mxser ...\n");
1080 #if 1 // mask by Victor Yu. 11-22-2005
1081 if ((err |= tty_unregister_driver(&mxvar_sdriver)))
1082 printk("Couldn't unregister MOXA Smartio/Industio family serial driver\n");
1083 #else // add by Victor Yu. 11-22-2005
1084 put_tty_driver(&mxvar_sdriver);
1085 #endif // 11-22-2005
1087 for(i=0; i<MXSER_BOARDS; i++){
1088 #ifdef CONFIG_ARCH_IA241 // add by Victor Yu. 02-16-2006
1089 struct pci_dev *pdev;
1090 #endif
1091 if(mxsercfg[i].board_type == -1)
1092 continue;
1093 else{
1094 free_irq(mxsercfg[i].irq, &mxvar_table[i*MXSER_PORTS_PER_BOARD]);
1095 #ifdef CONFIG_ARCH_IA241 // add by Victor Yu. 02-16-2006
1096 pdev = mxsercfg[i].pciInfo.pdev;
1097 release_region(pci_resource_start(pdev, 2),
1098 pci_resource_len(pdev, 2));
1099 release_region(pci_resource_start(pdev, 3),
1100 pci_resource_len(pdev, 3));
1101 #endif // 11-22-2005
1105 #if 1 // add by Victor Yu. 02-21-2006
1106 remove_proc_entry(MXSER_PROC_NODE, NULL); // add by Victor Yu. 07-27-2004
1107 #endif
1109 if (verbose)
1110 printk("Done.\n");
1113 module_init(mxser_init_module);
1114 module_exit(mxser_exit_module);
1116 int mxser_initbrd(int board,struct mxser_hwconf *hwconf)
1118 struct mxser_struct * info;
1119 unsigned long flags;
1120 int retval;
1121 int i,n;
1123 init_MUTEX(&mxvar_tmp_buf_sem);
1124 n = board*MXSER_PORTS_PER_BOARD;
1125 info = &mxvar_table[n];
1126 for ( i=0; i<hwconf->ports; i++, n++, info++ ) {
1127 if (verbose) {
1128 printk(" ttyM%d/cum%d at 0x%04x ", n, n, hwconf->ioaddr[i]);
1129 if ( hwconf->baud_base[i] == 115200 )
1130 printk(" max. baud rate up to 115200 bps.\n");
1131 else
1132 printk(" max. baud rate up to 921600 bps.\n");
1134 info->port = n;
1135 info->base = hwconf->ioaddr[i];
1136 info->irq = hwconf->irq;
1137 info->vector = hwconf->vector;
1138 info->vectormask = hwconf->vector_mask;
1139 info->opmode_ioaddr = hwconf->opmode_ioaddr[i]; // add by Victor Yu. 01-05-2004
1141 // following add by Victor Yu. 08-30-2002
1142 // Moxa Must UART support FIFO is 64bytes for Tx/Rx
1143 // but receive FIFO just can set up to 62 will be OK.
1144 info->rx_trigger = 120;
1145 info->baud_base = hwconf->baud_base[i];
1146 info->flags = ASYNC_SHARE_IRQ;
1147 info->type = hwconf->uart_type;
1149 // following add by Victor Yu. 08-30-2002
1150 info->xmit_fifo_size = 128;
1151 ENABLE_MOXA_MUST_ENCHANCE_MODE(info->base);
1152 info->MaxCanSetBaudRate = hwconf->MaxCanSetBaudRate[i];
1153 // above add by Victor Yu. 08-30-2002
1155 info->custom_divisor = hwconf->baud_base[i] * 16;
1156 info->close_delay = 5*HZ/10;
1157 info->closing_wait = 30*HZ;
1158 INIT_WORK(&info->tqueue, mxser_do_softint, info);
1159 info->normal_termios = mxvar_sdriver.init_termios;
1160 init_waitqueue_head(&info->open_wait);
1161 init_waitqueue_head(&info->close_wait);
1162 init_waitqueue_head(&info->delta_msr_wait);
1163 info->icount.rx = info->icount.tx = 0;
1164 info->icount.cts = info->icount.dsr =
1165 info->icount.dsr = info->icount.dcd = 0;
1166 info->icount.frame = info->icount.overrun =
1167 info->icount.brk = info->icount.parity = 0;
1168 info->icount.buf_overrun = 0;
1169 #ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add b Victor Yu. 08-12-2004
1170 info->speed = 9600;
1171 #endif
1174 #ifdef CONFIG_ARCH_IA241 // add by Victor Yu. 02-16-2006
1175 request_region(hwconf->ioaddr[0],8*hwconf->ports,"mxser(io)");
1176 if ((hwconf->pciInfo.busNum == 0)&&(hwconf->pciInfo.devNum == 0))
1177 request_region(hwconf->vector,1,"mxser(vector)");
1178 else
1179 request_region(hwconf->vector,16,"mxser(vector)");
1180 #endif
1183 * Allocate the IRQ if necessary
1185 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1186 local_irq_save(flags);
1187 #else
1188 save_flags(flags);
1189 cli();
1190 #endif // LINUX_VERSION_COODE
1192 n = board*MXSER_PORTS_PER_BOARD;
1193 info = &mxvar_table[n];
1195 retval = request_irq(hwconf->irq, mxser_interrupt, IRQ_T(info),
1196 "mxser", info);
1197 if ( retval ) {
1198 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1199 local_irq_restore(flags);
1200 #else
1201 restore_flags(flags);
1202 #endif // LINUX_VERSION_CODE
1203 printk("Board %d: %s", board, mxser_brdname[hwconf->board_type-1]);
1204 printk(" Request irq fail,IRQ (%d) may be conflit with another device.\n",info->irq);
1205 return(retval);
1207 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1208 local_irq_restore(flags);
1209 #else
1210 restore_flags(flags);
1211 #endif // LINUX_VERSION_CODE
1213 return 0;
1216 static void mxser_getcfg(int board,struct mxser_hwconf *hwconf)
1218 mxsercfg[board] = *hwconf;
1221 #ifdef CONFIG_ARCH_IA241 // add by Victor Yu. 02-16-2006
1222 static int mxser_get_PCI_conf(int board_type,struct mxser_hwconf *hwconf)
1224 int i;
1225 unsigned int ioaddress;
1226 struct pci_dev *pdev=hwconf->pciInfo.pdev;
1228 hwconf->board_type = board_type;
1229 hwconf->ports = mxser_numports[board_type-1];
1230 ioaddress = pci_resource_start(pdev, 2);
1231 request_region(pci_resource_start(pdev, 2),
1232 pci_resource_len(pdev, 2),
1233 "mxser(IO)");
1234 for (i = 0; i < hwconf->ports; i++) {
1235 hwconf->ioaddr[i] = ioaddress + 8*i;
1237 // disable the interrupt
1238 outb(0, hwconf->ioaddr[i]+1);
1239 // flush FIFO
1240 outb(0x06, hwconf->ioaddr[i]+2);
1241 // flush interrupt
1242 inb(hwconf->ioaddr[i]+2);
1243 inb(hwconf->ioaddr[i]+6);
1244 inb(hwconf->ioaddr[i]+5);
1245 inb(hwconf->ioaddr[i]);
1246 hwconf->MaxCanSetBaudRate[i] = 921600;
1249 ioaddress = pci_resource_start(pdev, 3);
1250 request_region(pci_resource_start(pdev, 3),
1251 pci_resource_len(pdev, 3),
1252 "mxser(vector)");
1253 hwconf->vector = ioaddress;
1255 // following add by Victor Yu. 01-05-2004
1256 for (i = 0; i < hwconf->ports; i++) {
1257 if ( i < 4 )
1258 hwconf->opmode_ioaddr[i] = ioaddress + 4;
1259 else
1260 hwconf->opmode_ioaddr[i] = ioaddress + 0x0c;
1262 outb(0, ioaddress+4); // default set to RS232 mode
1263 outb(0, ioaddress+0x0c); //default set to RS232 mode
1264 // above add by Victor Yu. 01-05-2004
1266 hwconf->irq = hwconf->pciInfo.pdev->irq;
1268 hwconf->uart_type = PORT_16550A;
1269 hwconf->vector_mask = 0;
1270 for (i = 0; i < hwconf->ports; i++) {
1271 hwconf->vector_mask |= (1<<i);
1272 hwconf->baud_base[i] = 921600;
1274 return(0);
1276 #endif
1278 #ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006
1279 static void ia240_hw_set(struct mxser_hwconf *hwconf)
1281 int i;
1283 hwconf->board_type = UC7110_BOARD;
1284 /* FIXME */
1285 hwconf->ports = 2;
1286 hwconf->vector_mask = 0x0c;
1287 hwconf->irq = IRQ_UART;
1288 hwconf->vector = CPE_UART_INT_VEC_VA_BASE;
1289 hwconf->uart_type = PORT_16550A;
1290 for ( i=0; i<hwconf->ports; i++ ) {
1291 hwconf->ioaddr[i] = CPE_UART3_VA_BASE + i * 32;
1292 hwconf->baud_base[i] = 921600;
1293 hwconf->MaxCanSetBaudRate[i] = 921600;
1294 hwconf->opmode_ioaddr[i] = CPE_UART_MODE_VA_BASE;
1297 #endif
1299 int mxser_init(void)
1301 int i, m;
1302 int ret1, ret2;
1303 #ifdef CONFIG_ARCH_IA241 // add by Victor Yu. 02-16-2006
1304 struct pci_dev *pdev=NULL;
1305 int n, index, retval, b;
1306 #endif
1307 struct mxser_hwconf hwconf;
1309 printk("MOXA MU860 UART Device Driver version %s\n",MXSER_VERSION);
1311 /* Initialize the tty_driver structure */
1312 memset(&mxvar_sdriver, 0, sizeof(struct tty_driver));
1313 mxvar_sdriver.magic = TTY_DRIVER_MAGIC;
1314 mxvar_sdriver.name = "ttyM";
1315 mxvar_sdriver.major = ttymajor;
1316 mxvar_sdriver.minor_start = 0;
1317 mxvar_sdriver.num = MXSER_PORTS + 1;
1318 mxvar_sdriver.type = TTY_DRIVER_TYPE_SERIAL;
1319 mxvar_sdriver.subtype = SERIAL_TYPE_NORMAL;
1320 mxvar_sdriver.init_termios = tty_std_termios;
1321 mxvar_sdriver.init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
1322 mxvar_sdriver.flags = TTY_DRIVER_REAL_RAW;
1323 mxvar_sdriver.refcount = 0;
1324 mxvar_sdriver.termios = mxvar_termios;
1325 mxvar_sdriver.termios_locked = mxvar_termios_locked;
1327 mxvar_sdriver.open = mxser_open;
1328 mxvar_sdriver.close = mxser_close;
1329 mxvar_sdriver.write = mxser_write;
1330 mxvar_sdriver.put_char = mxser_put_char;
1331 mxvar_sdriver.flush_chars = mxser_flush_chars;
1332 mxvar_sdriver.write_room = mxser_write_room;
1333 mxvar_sdriver.chars_in_buffer = mxser_chars_in_buffer;
1334 mxvar_sdriver.flush_buffer = mxser_flush_buffer;
1335 mxvar_sdriver.ioctl = mxser_ioctl;
1336 mxvar_sdriver.throttle = mxser_throttle;
1337 mxvar_sdriver.unthrottle = mxser_unthrottle;
1338 mxvar_sdriver.set_termios = mxser_set_termios;
1339 mxvar_sdriver.stop = mxser_stop;
1340 mxvar_sdriver.start = mxser_start;
1341 mxvar_sdriver.hangup = mxser_hangup;
1342 mxvar_sdriver.wait_until_sent = mxser_wait_until_sent;
1343 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,6,0)) // add by Victor Yu. 04-28-2006, for 2.6.x
1344 mxvar_sdriver.tiocmget = mxser_tiocmget;
1345 mxvar_sdriver.tiocmset = mxser_tiocmset;
1346 #endif
1348 printk("Tty devices major number = %d\n",ttymajor);
1350 mxvar_diagflag = 0;
1351 memset(mxvar_table, 0, MXSER_PORTS * sizeof(struct mxser_struct));
1352 memset(&mxvar_log, 0, sizeof(struct mxser_log));
1354 m = 0;
1355 #ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006
1356 ia240_hw_set(&hwconf);
1357 if ( mxser_initbrd(m,&hwconf) < 0 )
1358 return -1;
1359 mxser_getcfg(m,&hwconf);
1360 m++;
1361 #else
1363 n = sizeof (mxser_pcibrds)/sizeof (mxser_pciinfo);
1364 index = 0;
1365 b = 0;
1366 while (b < n) {
1367 pdev = pci_find_device(mxser_pcibrds[b].vendor_id,
1368 mxser_pcibrds[b].device_id,
1369 pdev);
1370 if ( pdev == NULL ) {
1371 b++;
1372 continue;
1374 hwconf.pciInfo.busNum = pdev->bus->number;
1375 hwconf.pciInfo.devNum = pdev->devfn;
1376 hwconf.pciInfo.pdev = pdev;
1377 printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n",mxser_brdname[mxser_pcibrds[b].board_type-1],pdev->bus->number,pdev->devfn >> 3);
1378 if ( m >= MXSER_BOARDS) {
1379 printk("Too many Smartio/Industio family boards find (maximum %d),board not configured\n",MXSER_BOARDS);
1381 else {
1382 if ( pci_enable_device(pdev) ) {
1383 printk("Moxa SmartI/O PCI enable fail !\n");
1384 continue;
1386 retval = mxser_get_PCI_conf(mxser_pcibrds[b].board_type,&hwconf);
1387 if (retval < 0) {
1388 if (retval == MXSER_ERR_IRQ)
1389 printk("Invalid interrupt number,board not configured\n");
1390 else if (retval == MXSER_ERR_IRQ_CONFLIT)
1391 printk("Invalid interrupt number,board not configured\n");
1392 else if (retval == MXSER_ERR_VECTOR)
1393 printk("Invalid interrupt vector,board not configured\n");
1394 else if (retval == MXSER_ERR_IOADDR)
1395 printk("Invalid I/O address,board not configured\n");
1396 continue;
1400 if(mxser_initbrd(m,&hwconf)<0)
1401 continue;
1402 mxser_getcfg(m,&hwconf);
1403 m++;
1407 #endif
1409 for(i=m; i<MXSER_BOARDS; i++){
1410 mxsercfg[i].board_type = -1;
1414 ret1 = 0;
1415 ret2 = 0;
1416 if ( !(ret1=tty_register_driver(&mxvar_sdriver)) ){
1417 #if 1 // add by Victor Yu. 02-21-2006
1418 create_proc_read_entry(MXSER_PROC_NODE, 0, 0, mxser_read_proc, NULL); // add by Victor Yu. 07-27-2004
1419 #endif
1420 return 0;
1421 }else
1422 printk("Couldn't install MOXA Smartio/Industio family driver !\n");
1425 if(ret1 || ret2){
1426 for(i=0; i<MXSER_BOARDS; i++){
1427 if(mxsercfg[i].board_type == -1)
1428 continue;
1429 else{
1430 free_irq(mxsercfg[i].irq, &mxvar_table[i*MXSER_PORTS_PER_BOARD]);
1433 return -1;
1436 return(0);
1439 static void mxser_do_softint(void *private_)
1441 struct mxser_struct * info = (struct mxser_struct *)private_;
1442 struct tty_struct * tty;
1444 tty = info->tty;
1446 if (tty) {
1447 if ( test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event) ) {
1448 if ( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
1449 tty->ldisc.write_wakeup )
1450 (tty->ldisc.write_wakeup)(tty);
1451 wake_up_interruptible(&tty->write_wait);
1453 if ( test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event) ) {
1454 tty_hangup(tty);
1457 //MOD_DEC_USE_COUNT;
1460 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,6,0)) // add by Victor Yu. 04-28-2006, for 2.6.x
1461 static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
1463 struct mxser_struct * info = (struct mxser_struct *)tty->driver_data;
1464 unsigned char control, status;
1465 int result;
1466 unsigned long flags;
1468 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1469 local_irq_save(flags);
1470 #else
1471 save_flags(flags);
1472 cli();
1473 #endif // LINUX_VERSION_CODE
1474 control = info->MCR;
1475 status = inb(info->base + UART_MSR);
1476 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1477 local_irq_restore(flags);
1478 #else
1479 restore_flags(flags);
1480 #endif // LINUX_VERSION_CODE
1481 result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
1482 ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
1483 ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) |
1484 ((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
1485 ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
1486 ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
1487 return(result);
1490 static int mxser_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear)
1492 struct mxser_struct * info = (struct mxser_struct *)tty->driver_data;
1493 unsigned long flags;
1495 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1496 local_irq_save(flags);
1497 #else
1498 save_flags(flags);
1499 cli();
1500 #endif // LINUX_VERSION_CODE
1501 if ( set & TIOCM_RTS )
1502 info->MCR |= UART_MCR_RTS;
1503 if ( set & TIOCM_DTR )
1504 info->MCR |= UART_MCR_DTR;
1505 if ( clear & TIOCM_RTS )
1506 info->MCR &= ~UART_MCR_RTS;
1507 if ( clear & TIOCM_DTR )
1508 info->MCR &= ~UART_MCR_DTR;
1509 outb(info->MCR, info->base + UART_MCR);
1510 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1511 local_irq_restore(flags);
1512 #else
1513 restore_flags(flags);
1514 #endif // LINUX_VERSION_CODE
1515 return(0);
1517 #endif
1519 * This routine is called whenever a serial port is opened. It
1520 * enables interrupts for a serial port, linking in its async structure into
1521 * the IRQ chain. It also performs the serial-specific
1522 * initialization for the tty structure.
1524 static int mxser_open(struct tty_struct * tty, struct file * filp)
1526 struct mxser_struct * info;
1527 int retval, line;
1528 unsigned long page;
1529 #if 1 // add by Victor Yu. 12-28-2004
1530 unsigned long flags;
1531 #endif
1533 line = PORTNO(tty);
1534 if ( line == MXSER_PORTS )
1535 return(0);
1536 if ( (line < 0) || (line > MXSER_PORTS) )
1537 return(-ENODEV);
1539 info = mxvar_table + line;
1540 if ( !info->base )
1541 return(-ENODEV);
1543 tty->driver_data = info;
1544 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1545 local_irq_save(flags);
1546 #else
1547 save_flags(flags);
1548 cli();
1549 #endif // LINUX_VERSION_CODE
1550 info->tty = tty;
1551 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1552 local_irq_restore(flags);
1553 #else
1554 restore_flags(flags);
1555 #endif // LINUX_VERSION_CODE
1557 if ( !mxvar_tmp_buf ) {
1558 page = get_zeroed_page(GFP_KERNEL);
1559 if ( !page )
1560 return(-ENOMEM);
1561 if ( mxvar_tmp_buf )
1562 free_page(page);
1563 else
1564 mxvar_tmp_buf = (unsigned char *)page;
1568 * Start up serial port
1570 retval = mxser_startup(info);
1571 if ( retval )
1572 return(retval);
1574 retval = mxser_block_til_ready(tty, filp, info);
1575 if ( retval )
1576 return(retval);
1578 #if 0 // mask by Victor Yu. 12-28-2004
1579 info->count++;
1580 #else // add by Victor Yu. 12-28-2004
1581 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1582 local_irq_save(flags);
1583 #else
1584 save_flags(flags);
1585 cli();
1586 #endif // LINUX_VERSION_CODE
1587 info->count++;
1588 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1589 local_irq_restore(flags);
1590 #else
1591 restore_flags(flags);
1592 #endif // LINUX_VERSION_CODE
1593 #endif
1594 //MOD_INC_USE_COUNT;
1596 if ( (info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS) ) {
1597 *tty->termios = info->normal_termios;
1598 mxser_change_speed(info, 0);
1601 #if 0 // mask by Victor Yu. 02-08-2007
1602 save_flags(flags);
1603 cli();
1604 clear_bit(TTY_DONT_FLIP, &tty->flags);
1605 restore_flags(flags);
1606 #endif
1608 /* unmark here for very high baud rate (ex. 921600 bps) used
1610 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0))
1611 tty->low_latency = 1;
1612 #endif
1613 return(0);
1617 * This routine is called when the serial port gets closed. First, we
1618 * wait for the last remaining data to be sent. Then, we unlink its
1619 * async structure from the interrupt chain if necessary, and we free
1620 * that IRQ if nothing is left in the chain.
1622 static void mxser_close(struct tty_struct * tty, struct file * filp)
1624 struct mxser_struct * info = (struct mxser_struct *)tty->driver_data;
1625 unsigned long flags;
1626 unsigned long timeout;
1628 if ( PORTNO(tty) == MXSER_PORTS )
1629 return;
1630 if ( !info )
1631 return;
1633 if ( tty_hung_up_p(filp) ) {
1634 //MOD_DEC_USE_COUNT;
1635 return;
1638 #if 1 // add by Victor Yu. 12-28-2004
1639 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1640 local_irq_save(flags);
1641 #else
1642 save_flags(flags);
1643 cli();
1644 #endif // LINUX_VERSION_CODE
1645 #endif
1646 if ( (tty->count == 1) && (info->count != 1) ) {
1648 * Uh, oh. tty->count is 1, which means that the tty
1649 * structure will be freed. Info->count should always
1650 * be one in these conditions. If it's greater than
1651 * one, we've got real problems, since it means the
1652 * serial port won't be shutdown.
1654 printk("mxser_close: bad serial port count; tty->count is 1, "
1655 "info->count is %d\n", info->count);
1656 info->count = 1;
1658 if ( --info->count < 0 ) {
1659 printk("mxser_close: bad serial port count for ttyM%d: %d\n",
1660 info->port, info->count);
1661 info->count = 0;
1663 if ( info->count ) {
1664 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1665 local_irq_restore(flags);
1666 #else
1667 restore_flags(flags);
1668 #endif // LINUX_VERSION_CODE
1669 //MOD_DEC_USE_COUNT;
1670 return;
1672 info->flags |= ASYNC_CLOSING;
1673 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1674 local_irq_restore(flags);
1675 #else
1676 restore_flags(flags); // add by Victor Yu. 09-26-2002
1677 #endif // LINUX_VERSION_CODE
1680 * Save the termios structure, since this port may have
1681 * separate termios for callout and dialin.
1683 if ( info->flags & ASYNC_NORMAL_ACTIVE )
1684 info->normal_termios = *tty->termios;
1686 * Now we wait for the transmit buffer to clear; and we notify
1687 * the line discipline to only process XON/XOFF characters.
1689 tty->closing = 1;
1690 if ( info->closing_wait != ASYNC_CLOSING_WAIT_NONE ) {
1691 tty_wait_until_sent(tty, info->closing_wait);
1694 * At this point we stop accepting input. To do this, we
1695 * disable the receive line status interrupts, and tell the
1696 * interrupt driver to stop checking the data ready bit in the
1697 * line status register.
1699 info->IER &= ~(UART_IER_RLSI|MOXA_MUST_RECV_ISR);
1700 if ( info->flags & ASYNC_INITIALIZED ) {
1701 outb(info->IER, info->base + UART_IER);
1703 * Before we drop DTR, make sure the UART transmitter
1704 * has completely drained; this is especially
1705 * important if there is a transmit FIFO!
1707 timeout = jiffies + HZ;
1708 while ( !(inb(info->base + UART_LSR) & UART_LSR_TEMT) ) {
1709 current->state = TASK_INTERRUPTIBLE;
1710 schedule_timeout(5);
1711 if ( time_after(jiffies, timeout) )
1712 break;
1715 mxser_shutdown(info);
1717 if ( tty->driver->flush_buffer )
1718 tty->driver->flush_buffer(tty);
1719 if ( tty->ldisc.flush_buffer )
1720 tty->ldisc.flush_buffer(tty);
1721 tty->closing = 0;
1722 info->event = 0;
1723 info->tty = 0;
1724 if ( info->blocked_open ) {
1725 if ( info->close_delay ) {
1726 current->state = TASK_INTERRUPTIBLE;
1727 schedule_timeout(info->close_delay);
1729 wake_up_interruptible(&info->open_wait);
1732 info->flags &= ~(ASYNC_NORMAL_ACTIVE |
1733 ASYNC_CLOSING);
1734 wake_up_interruptible(&info->close_wait);
1736 //MOD_DEC_USE_COUNT;
1739 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-16-2007
1740 static int mxser_write(struct tty_struct * tty, const unsigned char * buf, int count)
1741 #else
1742 static int mxser_write(struct tty_struct * tty, int from_user, const unsigned char * buf, int count)
1743 #endif // LINUX_VERSION_CODE
1745 int c, total = 0;
1746 struct mxser_struct *info = (struct mxser_struct *)tty->driver_data;
1747 unsigned long flags;
1749 if ( !tty || !info->xmit_buf || !mxvar_tmp_buf )
1750 return(0);
1752 #if 0 // mask by Victor Yu. 10-13-2004
1753 if ( from_user )
1754 down(&mxvar_tmp_buf_sem);
1755 #endif
1756 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1757 local_irq_save(flags);
1758 #else
1759 save_flags(flags);
1760 cli();
1761 #endif // LINUX_VERSION_CODE
1762 while ( 1 ) {
1763 // cli();
1764 c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
1765 SERIAL_XMIT_SIZE - info->xmit_head));
1766 if ( c <= 0 )
1767 break;
1769 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-16-2007
1770 if ( from_user ) {
1772 copy_from_user(mxvar_tmp_buf, buf, c);
1773 c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
1774 SERIAL_XMIT_SIZE - info->xmit_head));
1775 memcpy(info->xmit_buf + info->xmit_head, mxvar_tmp_buf, c);
1777 copy_from_user(info->xmit_buf+info->xmit_head, buf, c);
1778 } else
1779 #endif // LINUX_VERSION_CODE
1780 memcpy(info->xmit_buf + info->xmit_head, buf, c);
1781 info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1);
1782 info->xmit_cnt += c;
1783 // restore_flags(flags);
1784 buf += c;
1785 count -= c;
1786 total += c;
1788 #if 0 // mask by Victor Yu. 10-13-2004
1789 if ( from_user )
1790 up(&mxvar_tmp_buf_sem);
1791 #endif
1792 if ( info->xmit_cnt && !tty->stopped &&
1793 !(info->IER & UART_IER_THRI) ) {
1794 if (!tty->hw_stopped||(info->type == PORT_16550A)) {
1795 info->IER |= UART_IER_THRI;
1796 outb(info->IER, info->base + UART_IER);
1799 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1800 local_irq_restore(flags);
1801 #else
1802 restore_flags(flags);
1803 #endif // LINUX_VERSION_CODE
1804 return(total);
1807 static void mxser_put_char(struct tty_struct * tty, unsigned char ch)
1809 struct mxser_struct *info = (struct mxser_struct *)tty->driver_data;
1810 unsigned long flags;
1812 if ( !tty || !info->xmit_buf )
1813 return;
1815 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1816 local_irq_save(flags);
1817 #else
1818 save_flags(flags);
1819 cli();
1820 #endif // LINUX_VERSION_CODE
1821 if ( info->xmit_cnt >= SERIAL_XMIT_SIZE - 1 ) {
1822 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1823 local_irq_restore(flags);
1824 #else
1825 restore_flags(flags);
1826 #endif // LINUX_VERSION_CODE
1827 return;
1830 info->xmit_buf[info->xmit_head++] = ch;
1831 info->xmit_head &= SERIAL_XMIT_SIZE - 1;
1832 info->xmit_cnt++;
1833 if ( !tty->stopped && !(info->IER & UART_IER_THRI) ) {
1834 if (!tty->hw_stopped||(info->type == PORT_16550A)) {
1835 info->IER |= UART_IER_THRI;
1836 outb(info->IER, info->base + UART_IER);
1839 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1840 local_irq_restore(flags);
1841 #else
1842 restore_flags(flags);
1843 #endif // LINUX_VERSION_CODE
1846 static void mxser_flush_chars(struct tty_struct * tty)
1848 struct mxser_struct *info = (struct mxser_struct *)tty->driver_data;
1849 unsigned long flags;
1851 if ( info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf ||
1852 (tty->hw_stopped && info->type!=PORT_16550A))
1853 return;
1855 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1856 local_irq_save(flags);
1857 #else
1858 save_flags(flags);
1859 cli();
1860 #endif // LINUX_VERSION_CODE
1861 info->IER |= UART_IER_THRI;
1862 outb(info->IER, info->base + UART_IER);
1863 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1864 local_irq_restore(flags);
1865 #else
1866 restore_flags(flags);
1867 #endif // LINUX_VERSION_CODE
1870 static int mxser_write_room(struct tty_struct * tty)
1872 struct mxser_struct *info = (struct mxser_struct *)tty->driver_data;
1873 int ret;
1875 ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
1876 if ( ret < 0 )
1877 ret = 0;
1878 return(ret);
1881 static int mxser_chars_in_buffer(struct tty_struct * tty)
1883 struct mxser_struct *info = (struct mxser_struct *)tty->driver_data;
1885 return(info->xmit_cnt);
1888 static void mxser_flush_buffer(struct tty_struct * tty)
1890 struct mxser_struct *info = (struct mxser_struct *)tty->driver_data;
1891 unsigned long flags;
1893 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1894 local_irq_save(flags);
1895 #else
1896 save_flags(flags);
1897 cli();
1898 #endif // LINUX_VERSION_CODE
1899 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1900 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1901 local_irq_restore(flags);
1902 #else
1903 restore_flags(flags);
1904 #endif // LINUX_VERSION_CODE
1905 wake_up_interruptible(&tty->write_wait);
1906 if ( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
1907 tty->ldisc.write_wakeup )
1908 (tty->ldisc.write_wakeup)(tty);
1911 static int mxser_ioctl(struct tty_struct * tty, struct file * file,
1912 unsigned int cmd, unsigned long arg)
1914 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu.
1915 int error;
1916 #endif
1917 unsigned long flags;
1918 struct mxser_struct * info = (struct mxser_struct *)tty->driver_data;
1919 int retval;
1920 struct async_icount cprev, cnow; /* kernel counter temps */
1921 struct serial_icounter_struct *p_cuser; /* user space */
1922 unsigned long templ;
1923 if ( PORTNO(tty) == MXSER_PORTS )
1924 return(mxser_ioctl_special(cmd, arg));
1926 // following add by Victor Yu. 01-05-2004
1927 if ( cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE ) {
1928 int opmode, p;
1929 int shiftbit;
1930 unsigned int val;
1932 p = info->port % 4;
1933 if ( cmd == MOXA_SET_OP_MODE ) {
1934 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu.
1935 error = verify_area(VERIFY_READ, (void *)arg, sizeof(int));
1936 if ( error )
1937 return(error);
1938 #endif // LINUX_VERSION_CODE
1939 get_from_user(opmode,(int *)arg);
1940 if ( opmode != RS232_MODE && opmode != RS485_2WIRE_MODE && opmode != RS422_MODE && opmode != RS485_4WIRE_MODE )
1941 return -EFAULT;
1942 #ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-16-2006
1943 shiftbit = (p+2) * 2;
1944 val = inl(info->opmode_ioaddr);
1945 #else
1946 shiftbit = p * 2;
1947 val = inb(info->opmode_ioaddr);
1948 #endif
1949 val &= (~(3 << shiftbit));
1950 val |= (opmode << shiftbit);
1951 #ifdef CONFIG_ARCH_MOXART
1952 outl(val, info->opmode_ioaddr);
1953 #else
1954 outb(val, info->opmode_ioaddr);
1955 #endif
1956 } else {
1957 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu.
1958 error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int));
1959 if ( error )
1960 return(error);
1961 #endif // LINUX_VERSION_CODE
1962 #ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-16-2006
1963 shiftbit = (p+2) * 2;
1964 opmode = inl(info->opmode_ioaddr) >> shiftbit;
1965 #else
1966 shiftbit = p * 2;
1967 opmode = inb(info->opmode_ioaddr) >> shiftbit;
1968 #endif
1969 opmode &= OP_MODE_MASK;
1970 copy_to_user((int*)arg, &opmode, sizeof(int));
1972 return 0;
1974 // above add by Victor Yu. 01-05-2004
1976 #ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-12-2004
1977 #if 0 // 02-16-2007, mask by Victor Yu. To support Moxa Group define about this
1978 if ( cmd == MOXA_SET_SPECIAL_BAUD_RATE || cmd == MOXA_GET_SPECIAL_BAUD_RATE ) {
1979 #else
1980 if ( cmd == MOXA_SET_SPECIAL_BAUD_RATE || cmd == MOXA_GET_SPECIAL_BAUD_RATE ||
1981 cmd == NEW_MOXA_SET_SPECIAL_BAUD_RATE || cmd == NEW_MOXA_GET_SPECIAL_BAUD_RATE ) {
1982 #endif
1983 int speed, i;
1984 #if 0 // 02-16-2007, mask by Victor Yu. To support Moxa Group define about this
1985 if ( cmd == MOXA_SET_SPECIAL_BAUD_RATE ) {
1986 #else
1987 if ( cmd == MOXA_SET_SPECIAL_BAUD_RATE ||
1988 cmd == MOXA_SET_SPECIAL_BAUD_RATE ) {
1989 #endif
1990 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu.
1991 error = verify_area(VERIFY_READ, (void *)arg, sizeof(int));
1992 if ( error )
1993 return(error);
1994 #endif // LINUX_VERSION_CODE
1995 get_from_user(speed,(int *)arg);
1996 if ( speed <= 0 || speed > info->MaxCanSetBaudRate )
1997 return -EFAULT;
1998 if ( !info->tty || !info->tty->termios || !info->base )
1999 return 0;
2000 info->tty->termios->c_cflag &= ~(CBAUD | CBAUDEX);
2001 for ( i=0; i<BAUD_TABLE_NO && speed != mxvar_baud_table[i]; i++ );
2002 if ( i == BAUD_TABLE_NO ) {
2003 info->tty->termios->c_cflag |= B4000000;
2004 } else {
2005 switch ( mxvar_baud_table[i] ) {
2006 case 921600 : info->tty->termios->c_cflag |= B921600; break;
2007 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-16-2007
2008 case 576000 : info->tty->termios->c_cflag |= B576000; break;
2009 case 500000 : info->tty->termios->c_cflag |= B500000; break;
2010 #endif
2011 case 460800 : info->tty->termios->c_cflag |= B460800; break;
2012 case 230400 : info->tty->termios->c_cflag |= B230400; break;
2013 case 115200 : info->tty->termios->c_cflag |= B115200; break;
2014 case 57600 : info->tty->termios->c_cflag |= B57600; break;
2015 case 38400 : info->tty->termios->c_cflag |= B38400; break;
2016 case 19200 : info->tty->termios->c_cflag |= B19200; break;
2017 case 9600 : info->tty->termios->c_cflag |= B9600; break;
2018 case 4800 : info->tty->termios->c_cflag |= B4800; break;
2019 case 2400 : info->tty->termios->c_cflag |= B2400; break;
2020 case 1800 : info->tty->termios->c_cflag |= B1800; break;
2021 case 1200 : info->tty->termios->c_cflag |= B1200; break;
2022 case 600 : info->tty->termios->c_cflag |= B600; break;
2023 case 300 : info->tty->termios->c_cflag |= B300; break;
2024 case 200 : info->tty->termios->c_cflag |= B200; break;
2025 case 150 : info->tty->termios->c_cflag |= B150; break;
2026 case 134 : info->tty->termios->c_cflag |= B134; break;
2027 case 110 : info->tty->termios->c_cflag |= B110; break;
2028 case 75 : info->tty->termios->c_cflag |= B75; break;
2029 case 50 : info->tty->termios->c_cflag |= B50; break;
2032 info->speed = speed;
2033 mxser_change_speed(info, 0);
2034 } else {
2035 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu.
2036 error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int));
2037 if ( error )
2038 return(error);
2039 #endif // LINUX_VERSION_CODE
2040 copy_to_user((int*)arg, &info->speed, sizeof(int));
2042 return 0;
2044 #endif
2046 if ( (cmd != TIOCGSERIAL) && (cmd != TIOCMIWAIT) &&
2047 (cmd != TIOCGICOUNT) ) {
2048 if ( tty->flags & (1 << TTY_IO_ERROR) )
2049 return(-EIO);
2051 switch ( cmd ) {
2052 #if 1 // add by Victor Yu. 05-02-2007, for GL ODM, I let it to be Moxa standard feature
2053 case MOXA_BREAK_TIMER :
2054 retval = tty_check_change(tty);
2055 if ( retval )
2056 return(retval);
2057 tty_wait_until_sent(tty, 0);
2058 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2059 local_irq_save(flags);
2060 #else
2061 save_flags(flags);
2062 cli();
2063 #endif // LINUX_VERSION_CODE
2064 outb(inb(info->base + UART_LCR) | UART_LCR_SBC, info->base + UART_LCR);
2065 udelay(arg);
2066 outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, info->base + UART_LCR);
2067 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2068 local_irq_restore(flags);
2069 #else
2070 restore_flags(flags);
2071 #endif // LINUX_VERSION_CODE
2072 break;
2073 #endif
2074 #if 1 // add by Victor Yu. 12-28-2004
2075 case TIOCSBRK : // start to send break
2076 retval = tty_check_change(tty);
2077 if ( retval )
2078 return(retval);
2079 tty_wait_until_sent(tty, 0);
2080 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2081 local_irq_save(flags);
2082 #else
2083 save_flags(flags);
2084 cli();
2085 #endif // LINUX_VERSION_CODE
2086 outb(inb(info->base + UART_LCR) | UART_LCR_SBC, info->base + UART_LCR);
2087 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2088 local_irq_restore(flags);
2089 #else
2090 restore_flags(flags);
2091 #endif // LINUX_VERSION_CODE
2092 return 0;
2093 case TIOCCBRK : // stop to send break
2094 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2095 local_irq_save(flags);
2096 #else
2097 save_flags(flags);
2098 cli();
2099 #endif // LINUX_VERSION_CODE
2100 outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, info->base + UART_LCR);
2101 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2102 local_irq_restore(flags);
2103 #else
2104 restore_flags(flags);
2105 #endif // LINUX_VERSION_CODE
2106 return 0;
2107 #endif
2108 case TCSBRK: /* SVID version: non-zero arg --> no break */
2109 retval = tty_check_change(tty);
2110 if ( retval )
2111 return(retval);
2112 tty_wait_until_sent(tty, 0);
2113 if ( !arg )
2114 mxser_send_break(info, HZ/4); /* 1/4 second */
2115 return(0);
2116 case TCSBRKP: /* support for POSIX tcsendbreak() */
2117 retval = tty_check_change(tty);
2118 if ( retval )
2119 return(retval);
2120 tty_wait_until_sent(tty, 0);
2121 mxser_send_break(info, arg ? arg*(HZ/10) : HZ/4);
2122 return(0);
2123 case TIOCGSOFTCAR:
2124 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu.
2125 error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(long));
2126 if ( error )
2127 return(error);
2128 #endif // LINUX_VERSION_CODE
2129 put_to_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg);
2130 return 0;
2131 case TIOCSSOFTCAR:
2132 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu.
2133 error = verify_area(VERIFY_READ, (void *)arg, sizeof(long));
2134 if ( error )
2135 return(error);
2136 #endif // LINUX_VERSION_CODE
2137 get_from_user(templ,(unsigned long *)arg);
2138 arg = templ;
2139 tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) |
2140 (arg ? CLOCAL : 0));
2141 return(0);
2142 #if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) // add by Victor Yu. 04-28-2006, for 2.6.x
2143 case TIOCMGET:
2144 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu.
2145 error = verify_area(VERIFY_WRITE, (void *)arg,
2146 sizeof(unsigned int));
2147 if ( error )
2148 return(error);
2149 #endif // LINUX_VERSION_CODE
2150 return(mxser_get_modem_info(info, (unsigned int *)arg));
2151 case TIOCMBIS:
2152 case TIOCMBIC:
2153 case TIOCMSET:
2154 return(mxser_set_modem_info(info, cmd, (unsigned int *)arg));
2155 #endif
2156 case TIOCGSERIAL:
2157 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu.
2158 error = verify_area(VERIFY_WRITE, (void *)arg,
2159 sizeof(struct serial_struct));
2160 if ( error )
2161 return(error);
2162 #endif // LINUX_VERSION_CODE
2163 return(mxser_get_serial_info(info, (struct serial_struct *)arg));
2164 case TIOCSSERIAL:
2165 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu.
2166 error = verify_area(VERIFY_READ, (void *)arg,
2167 sizeof(struct serial_struct));
2168 if ( error )
2169 return(error);
2170 #endif // LINUX_VERSION_CODE
2171 return(mxser_set_serial_info(info, (struct serial_struct *)arg));
2172 case TIOCSERGETLSR: /* Get line status register */
2173 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu.
2174 error = verify_area(VERIFY_WRITE, (void *)arg,
2175 sizeof(unsigned int));
2176 if ( error )
2177 return(error);
2178 else
2179 #endif // LINUX_VERSION_CODE
2180 return(mxser_get_lsr_info(info, (unsigned int *)arg));
2182 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
2183 * - mask passed in arg for lines of interest
2184 * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
2185 * Caller should use TIOCGICOUNT to see which one it was
2187 case TIOCMIWAIT:
2188 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2189 local_irq_save(flags);
2190 #else
2191 save_flags(flags);
2192 cli();
2193 #endif // LINUX_VERSION_CODE
2194 cprev = info->icount; /* note the counters on entry */
2195 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2196 local_irq_restore(flags);
2197 #else
2198 restore_flags(flags);
2199 #endif // LINUX_VERSION_CODE
2200 while ( 1 ) {
2201 interruptible_sleep_on(&info->delta_msr_wait);
2202 /* see if a signal did it */
2203 if ( signal_pending(current) ) {
2204 return(-ERESTARTSYS);
2206 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2207 local_irq_save(flags);
2208 #else
2209 save_flags(flags);
2210 cli();
2211 #endif // LINUX_VERSION_CODE
2212 cnow = info->icount; /* atomic copy */
2213 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2214 local_irq_restore(flags);
2215 #else
2216 restore_flags(flags);
2217 #endif // LINUX_VERSION_CODE
2218 #if 0 // mask by Victor Yu. 12-31-2004
2219 if ( cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
2220 cnow.dcd == cprev.dcd && cnow.cts == cprev.cts )
2221 return(-EIO); /* no change => error */
2222 if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
2223 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
2224 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
2225 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
2226 return(0);
2228 #else // add by Victor Yu. 12-31-2004
2229 #define TIOCM_BRK 0x10000
2230 #define TIOCM_PARITY 0x20000
2231 #define TIOCM_FRAME 0x40000
2232 #define TIOCM_XOFFHOLD 0x80000
2233 if ( cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
2234 cnow.dcd == cprev.dcd && cnow.cts == cprev.cts &&
2235 cnow.brk == cprev.brk && cnow.parity == cprev.parity &&
2236 cnow.frame == cprev.frame && cnow.buf_overrun == cprev.buf_overrun )
2237 return(-EIO); /* no change => error */
2238 if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
2239 ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
2240 ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
2241 ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ||
2242 ((arg & TIOCM_BRK) && (cnow.brk != cprev.brk)) ||
2243 ((arg & TIOCM_PARITY) && (cnow.parity != cprev.parity)) ||
2244 ((arg & TIOCM_FRAME) && (cnow.frame != cprev.frame)) ||
2245 ((arg & TIOCM_XOFFHOLD) && (cnow.buf_overrun != cprev.buf_overrun)) ) {
2246 return(0);
2248 #endif
2249 cprev = cnow;
2251 /* NOTREACHED */
2253 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2254 * Return: write counters to the user passed counter struct
2255 * NB: both 1->0 and 0->1 transitions are counted except for
2256 * RI where only 0->1 is counted.
2259 #if 1 // add by Victor Yu. 01-26-2005
2260 case MOXA_UNWAIT :
2261 wake_up_interruptible(&info->delta_msr_wait);
2262 break;
2263 #endif
2265 case TIOCGICOUNT:
2266 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-09-2007
2267 error = verify_area(VERIFY_WRITE, (void *)arg,
2268 sizeof(struct serial_icounter_struct));
2269 if ( error )
2270 return(error);
2271 #endif // LINUX_VERSION_CODE
2272 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2273 local_irq_save(flags);
2274 #else
2275 save_flags(flags);
2276 cli();
2277 #endif // LINUX_VERSION_CODE
2278 cnow = info->icount;
2279 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2280 local_irq_restore(flags);
2281 #else
2282 restore_flags(flags);
2283 #endif // LINUX_VERSION_CODE
2284 p_cuser = (struct serial_icounter_struct *)arg;
2285 /* modified by casper 1/11/2000 */
2286 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0))
2287 if (put_user(cnow.frame, &p_cuser->frame))
2288 return -EFAULT;
2289 if (put_user(cnow.brk, &p_cuser->brk))
2290 return -EFAULT;
2291 if (put_user(cnow.overrun, &p_cuser->overrun))
2292 return -EFAULT;
2293 if (put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
2294 return -EFAULT;
2295 if (put_user(cnow.parity, &p_cuser->parity))
2296 return -EFAULT;
2297 if (put_user(cnow.rx, &p_cuser->rx))
2298 return -EFAULT;
2299 if (put_user(cnow.tx, &p_cuser->tx))
2300 return -EFAULT;
2301 #endif
2303 put_to_user(cnow.cts, &p_cuser->cts);
2304 put_to_user(cnow.dsr, &p_cuser->dsr);
2305 put_to_user(cnow.rng, &p_cuser->rng);
2306 put_to_user(cnow.dcd, &p_cuser->dcd);
2308 /* */
2309 return(0);
2310 case MOXA_HighSpeedOn:
2311 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-09-2007
2312 error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int));
2313 if ( error )
2314 return(error);
2315 #endif // LINUX_VERSION_CODE
2316 put_to_user(info->baud_base != 115200 ? 1 : 0, (int *)arg);
2317 return(0);
2318 default:
2319 return(-ENOIOCTLCMD);
2321 return(0);
2324 static int mxser_ioctl_special(unsigned int cmd, unsigned long arg)
2326 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-09-2007
2327 int error, i, result, status;
2328 #else
2329 int i, result, status;
2330 #endif
2332 switch ( cmd ) {
2333 case MOXA_GET_CONF:
2334 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-09-2007
2335 error = verify_area(VERIFY_WRITE, (void *)arg,
2336 sizeof(struct mxser_hwconf)*4);
2337 if ( error )
2338 return(error);
2339 #endif // LINUX_VERSION_CODE
2340 copy_to_user((struct mxser_hwconf *)arg, mxsercfg,
2341 sizeof(struct mxser_hwconf)*4);
2342 return 0;
2343 case MOXA_GET_MAJOR:
2344 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-09-2007
2345 error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int));
2346 if ( error )
2347 return(error);
2348 #endif // LINUX_VERSION_CODE
2349 copy_to_user((int*)arg, &ttymajor, sizeof(int));
2350 return 0;
2352 case MOXA_GET_CUMAJOR:
2353 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-09-2007
2354 error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int));
2355 if ( error )
2356 return(error);
2357 #endif // LINUX_VERSION_CODE
2358 copy_to_user((int*)arg, &calloutmajor, sizeof(int));
2359 return 0;
2361 case MOXA_CHKPORTENABLE:
2362 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-09-2007
2363 error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(long));
2364 if ( error )
2365 return(error);
2366 #endif // LINUX_VERSION_CODE
2367 result = 0;
2368 for ( i=0; i<MXSER_PORTS; i++ ) {
2369 if ( mxvar_table[i].base )
2370 result |= (1 << i);
2372 put_to_user(result, (unsigned long *)arg);
2373 return(0);
2374 case MOXA_GETDATACOUNT:
2375 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-09-2007
2376 error = verify_area(VERIFY_WRITE, (void *)arg,
2377 sizeof(struct mxser_log));
2378 if ( error )
2379 return(error);
2380 #endif // LINUX_VERSION_CODE
2381 copy_to_user((struct mxser_log *)arg, &mxvar_log, sizeof(mxvar_log));
2382 return(0);
2383 case MOXA_GETMSTATUS:
2384 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-09-2007
2385 error = verify_area(VERIFY_WRITE, (void *)arg,
2386 sizeof(struct mxser_mstatus) * MXSER_PORTS);
2387 if ( error )
2388 return(error);
2389 #endif // LINUX_VERSION_CODE
2391 for(i=0; i<MXSER_PORTS; i++){
2392 GMStatus[i].ri = 0;
2393 if ( !mxvar_table[i].base ){
2394 GMStatus[i].dcd = 0;
2395 GMStatus[i].dsr = 0;
2396 GMStatus[i].cts = 0;
2397 continue;
2400 if ( !mxvar_table[i].tty || !mxvar_table[i].tty->termios )
2401 GMStatus[i].cflag=mxvar_table[i].normal_termios.c_cflag;
2402 else
2403 GMStatus[i].cflag = mxvar_table[i].tty->termios->c_cflag;
2405 status = inb(mxvar_table[i].base + UART_MSR);
2406 if(status & 0x80/*UART_MSR_DCD*/)
2407 GMStatus[i].dcd = 1;
2408 else
2409 GMStatus[i].dcd = 0;
2411 if(status & 0x20/*UART_MSR_DSR*/)
2412 GMStatus[i].dsr = 1;
2413 else
2414 GMStatus[i].dsr = 0;
2417 if(status & 0x10/*UART_MSR_CTS*/)
2418 GMStatus[i].cts = 1;
2419 else
2420 GMStatus[i].cts = 0;
2422 copy_to_user((struct mxser_mstatus *)arg, GMStatus,
2423 sizeof(struct mxser_mstatus) * MXSER_PORTS);
2424 return 0;
2425 default:
2426 return(-ENOIOCTLCMD);
2428 return(0);
2432 * This routine is called by the upper-layer tty layer to signal that
2433 * incoming characters should be throttled.
2435 static void mxser_throttle(struct tty_struct * tty)
2437 struct mxser_struct *info = (struct mxser_struct *)tty->driver_data;
2438 unsigned long flags;
2440 if ( I_IXOFF(tty) || (info->tty->termios->c_cflag & CRTSCTS) ) {
2441 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2442 local_irq_save(flags);
2443 #else
2444 save_flags(flags);
2445 cli();
2446 #endif // LINUX_VERSION_CODE
2447 info->IER &= ~MOXA_MUST_RECV_ISR;
2448 outb(info->IER, info->base+UART_IER);
2449 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2450 local_irq_restore(flags);
2451 #else
2452 restore_flags(flags);
2453 #endif // LINUX_VERSION_CODE
2457 static void mxser_unthrottle(struct tty_struct * tty)
2459 struct mxser_struct *info = (struct mxser_struct *)tty->driver_data;
2460 unsigned long flags;
2462 if ( I_IXOFF(tty) ) {
2463 if ( info->x_char )
2464 info->x_char = 0;
2465 else {
2466 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2467 local_irq_save(flags);
2468 #else
2469 save_flags(flags);
2470 cli();
2471 #endif // LINUX_VERSION_CODE
2472 info->IER |= MOXA_MUST_RECV_ISR;
2473 outb(info->IER, info->base+UART_IER);
2474 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2475 local_irq_restore(flags);
2476 #else
2477 restore_flags(flags);
2478 #endif // LINUX_VERSION_CODE
2482 if ( info->tty->termios->c_cflag & CRTSCTS ) {
2483 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2484 local_irq_save(flags);
2485 #else
2486 save_flags(flags);
2487 cli();
2488 #endif // LINUX_VERSION_CODE
2489 info->IER |= MOXA_MUST_RECV_ISR;
2490 outb(info->IER, info->base+UART_IER);
2491 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2492 local_irq_restore(flags);
2493 #else
2494 restore_flags(flags);
2495 #endif // LINUX_VERSION_CODE
2499 static void mxser_set_termios(struct tty_struct * tty,
2500 struct termios * old_termios)
2502 struct mxser_struct *info = (struct mxser_struct *)tty->driver_data;
2504 #if 0 // mask by Victor Yu. 01-04-2005
2505 if ( (tty->termios->c_cflag != old_termios->c_cflag) ||
2506 (RELEVANT_IFLAG(tty->termios->c_iflag) !=
2507 RELEVANT_IFLAG(old_termios->c_iflag)) ) {
2508 #else // add by Victor Yu. 01-04-2005
2509 if ( (tty->termios->c_cflag != old_termios->c_cflag) ||
2510 (tty->termios->c_iflag != old_termios->c_iflag) ) {
2511 #endif
2513 mxser_change_speed(info, old_termios);
2515 if ( (old_termios->c_cflag & CRTSCTS) &&
2516 !(tty->termios->c_cflag & CRTSCTS) ) {
2517 tty->hw_stopped = 0;
2518 mxser_start(tty);
2522 /* Handle sw stopped */
2523 if ( (old_termios->c_iflag & IXON) &&
2524 !(tty->termios->c_iflag & IXON) ) {
2525 tty->stopped = 0;
2526 mxser_start(tty);
2531 * mxser_stop() and mxser_start()
2533 * This routines are called before setting or resetting tty->stopped.
2534 * They enable or disable transmitter interrupts, as necessary.
2536 static void mxser_stop(struct tty_struct * tty)
2538 struct mxser_struct *info = (struct mxser_struct *)tty->driver_data;
2539 unsigned long flags;
2541 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2542 local_irq_save(flags);
2543 #else
2544 save_flags(flags);
2545 cli();
2546 #endif // LINUX_VERSION_CODE
2547 if ( info->IER & UART_IER_THRI ) {
2548 info->IER &= ~UART_IER_THRI;
2549 outb(info->IER, info->base + UART_IER);
2551 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2552 local_irq_restore(flags);
2553 #else
2554 restore_flags(flags);
2555 #endif // LINUX_VERSION_CODE
2558 static void mxser_start(struct tty_struct * tty)
2560 struct mxser_struct *info = (struct mxser_struct *)tty->driver_data;
2561 unsigned long flags;
2563 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2564 local_irq_save(flags);
2565 #else
2566 save_flags(flags);
2567 cli();
2568 #endif // LINUX_VERSION_CODE
2569 if ( info->xmit_cnt && info->xmit_buf &&
2570 !(info->IER & UART_IER_THRI) ) {
2571 info->IER |= UART_IER_THRI;
2572 outb(info->IER, info->base + UART_IER);
2574 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2575 local_irq_restore(flags);
2576 #else
2577 restore_flags(flags);
2578 #endif // LINUX_VERSION_CODE
2581 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0))
2583 * mxser_wait_until_sent() --- wait until the transmitter is empty
2585 static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
2587 struct mxser_struct * info = (struct mxser_struct *)tty->driver_data;
2588 unsigned long orig_jiffies, char_time;
2589 int lsr;
2591 if (info->type == PORT_UNKNOWN)
2592 return;
2594 if (info->xmit_fifo_size == 0)
2595 return; /* Just in case.... */
2598 * Set the check interval to be 1/5 of the estimated time to
2599 * send a single character, and make it at least 1. The check
2600 * interval should also be less than the timeout.
2602 * Note: we have to use pretty tight timings here to satisfy
2603 * the NIST-PCTS.
2605 char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
2606 char_time = char_time / 5;
2607 if (char_time == 0)
2608 char_time = 1;
2609 if (timeout && timeout < char_time)
2610 char_time = timeout;
2612 * If the transmitter hasn't cleared in twice the approximate
2613 * amount of time to send the entire FIFO, it probably won't
2614 * ever clear. This assumes the UART isn't doing flow
2615 * control, which is currently the case. Hence, if it ever
2616 * takes longer than info->timeout, this is probably due to a
2617 * UART bug of some kind. So, we clamp the timeout parameter at
2618 * 2*info->timeout.
2620 if (!timeout || timeout > 2*info->timeout)
2621 timeout = 2*info->timeout;
2622 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
2623 printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
2624 printk("jiff=%lu...", jiffies);
2625 #endif
2626 orig_jiffies = jiffies + timeout;
2627 while (!((lsr = inb(info->base+ UART_LSR)) & UART_LSR_TEMT)) {
2628 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
2629 printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
2630 #endif
2631 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,3,0))
2632 set_current_state(TASK_INTERRUPTIBLE);
2633 #else
2634 current->state = TASK_INTERRUPTIBLE;
2635 #endif
2636 schedule_timeout(char_time);
2637 if (signal_pending(current))
2638 break;
2639 if (timeout && time_after(jiffies, orig_jiffies))
2640 break;
2642 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,3,0))
2643 set_current_state(TASK_RUNNING);
2644 #else
2645 current->state = TASK_RUNNING;
2646 #endif
2648 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
2649 printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
2650 #endif
2652 #endif
2656 * This routine is called by tty_hangup() when a hangup is signaled.
2658 void mxser_hangup(struct tty_struct * tty)
2660 struct mxser_struct * info = (struct mxser_struct *)tty->driver_data;
2661 #if 1 // add by Victor Yu. 12-28-2004
2662 unsigned long flags;
2663 #endif
2665 mxser_flush_buffer(tty);
2666 mxser_shutdown(info);
2667 #if 0 // mask by Victor Yu. 12-28-2004
2668 info->event = 0;
2669 info->count = 0;
2670 info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
2671 info->tty = 0;
2672 #else
2673 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2674 local_irq_save(flags);
2675 #else
2676 save_flags(flags);
2677 cli();
2678 #endif // LINUX_VERSION_CODE
2679 info->event = 0;
2680 info->count = 0;
2681 #if 0
2682 info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
2683 #else
2684 info->flags &= ~(ASYNC_NORMAL_ACTIVE);
2685 #endif
2686 info->tty = 0;
2687 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2688 local_irq_restore(flags);
2689 #else
2690 restore_flags(flags);
2691 #endif // LINUX_VERSION_CODE
2692 #endif
2693 wake_up_interruptible(&info->open_wait);
2697 * This is the serial driver's generic interrupt routine
2699 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-16-2007
2700 static irqreturn_t mxser_interrupt(int irq, void *dev_id)
2701 #else
2702 static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs * regs)
2703 #endif
2705 int status, iir, i;
2706 struct mxser_struct * info;
2707 struct mxser_struct * port=NULL;
2708 int max, irqbits, msr;
2709 int pass_counter=0, bits;
2711 for ( i=0; i<MXSER_BOARDS; i++ ) {
2712 if ( dev_id == &(mxvar_table[i*MXSER_PORTS_PER_BOARD]) ) {
2713 port = dev_id;
2714 break;
2717 if ( port == NULL ) {
2718 return IRQ_NONE;
2720 max = mxser_numports[mxsercfg[i].board_type-1];
2722 while ( 1 ) {
2723 irqbits = inb(port->vector) & port->vectormask;
2724 if ( irqbits == port->vectormask )
2725 break;
2726 #ifdef CONFIG_ARCH_IA241 // add by Victor Yu. 02-16-2006
2727 for ( i=0, bits=1; i<max; i++, irqbits |= bits, bits <<= 1 ) {
2728 #else
2729 for ( i=0, bits=4; i<max; i++, irqbits |= bits, bits <<= 1 ) {
2730 #endif
2731 if ( irqbits == port->vectormask )
2732 break;
2733 if ( bits & irqbits )
2734 continue;
2735 info = port + i;
2737 // following add by Victor Yu. 09-13-2002
2738 iir = inb(info->base+UART_IIR);
2739 if ( iir & UART_IIR_NO_INT )
2740 continue;
2741 iir &= MOXA_MUST_IIR_MASK;
2742 if ( !info->tty ) { // because the UART chip has bug. so need to do this
2743 status = inb(info->base+UART_LSR);
2744 outb(0x27, info->base+UART_FCR);
2745 inb(info->base+UART_MSR);
2746 continue;
2748 // above add by Victor Yu. 09-13-2002
2750 #if 1 // add by Victor Yu. 01-04-2005
2751 if ( iir == MOXA_MUST_IIR_XSC ) {
2752 if ( !(inb(info->base+UART_MCR) & MOXA_MUST_MCR_XON_FLAG) ) {
2753 info->icount.buf_overrun++;
2754 wake_up_interruptible(&info->delta_msr_wait);
2756 continue;
2758 #endif
2760 if ( iir == MOXA_MUST_IIR_GDA ||
2761 iir == MOXA_MUST_IIR_RDA ||
2762 iir == MOXA_MUST_IIR_RTO ||
2763 iir == MOXA_MUST_IIR_LSR ) {
2764 status = inb(info->base+UART_LSR);
2765 mxser_receive_chars(info, &status);
2767 msr = inb(info->base + UART_MSR);
2768 if ( msr & UART_MSR_ANY_DELTA ) {
2769 mxser_check_modem_status(info, msr);
2772 if ( iir == 0x02 )
2773 mxser_transmit_chars(info);
2775 if ( pass_counter++ > MXSER_ISR_PASS_LIMIT ) {
2776 break; /* Prevent infinite loops */
2779 return IRQ_HANDLED;
2782 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-16-2007
2783 #define BYPASS_FLIP // add by Victor Yu. 09-17-2004
2784 #endif
2785 #define N_TTY_BUF_SIZE_MASK (N_TTY_BUF_SIZE-1) // add by Victor Yu. 02-04-2005
2786 static inline void mxser_receive_chars(struct mxser_struct *info,
2787 int *status)
2789 struct tty_struct * tty = info->tty;
2790 unsigned char ch, gdl;
2791 int cnt = 0;
2792 #ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004
2793 unsigned char *cp=tty->flip.char_buf;
2794 char *fp=tty->flip.flag_buf;
2795 #endif // BYPASS_FLIP
2797 // following add by Victor Yu. 09-02-2002
2798 if ( *status & (UART_LSR_SPECIAL|MOXA_MUST_LSR_RERR) )
2799 goto intr_old;
2801 gdl = inb(info->base+MOXA_MUST_GDL_REGISTER);
2803 // following add by Victor Yu. 10-13-2004
2804 #ifdef BYPASS_FLIP
2805 cnt = gdl;
2806 #else
2807 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-16-2007
2808 if ( tty->receive_room == 0 ) {
2809 if ( I_IXOFF(tty) || (tty->termios->c_cflag & CRTSCTS) ) { // has flow control
2810 cnt = gdl = MIN(gdl, tty->receive_room);
2811 } else {
2812 cnt = gdl;
2814 } else {
2815 cnt = gdl = MIN(gdl, tty->receive_room);
2817 #else
2818 cnt = gdl = MIN(gdl, TTY_FLIPBUF_SIZE-tty->flip.count);
2819 #endif // LINUX_VERSION_CODE
2820 #endif // BYPASS_FLIP
2821 // above add by Victor Yu. 10-13-2004
2823 while ( gdl-- ) {
2824 ch = inb(info->base + UART_RX);
2825 #ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004
2826 *cp++ = ch;
2827 *fp++ = 0;
2828 #else
2829 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-16-2007
2830 tty_insert_flip_char(tty, ch, 0);
2831 #else
2832 tty->flip.count++;
2833 *tty->flip.char_buf_ptr++ = ch;
2834 *tty->flip.flag_buf_ptr++ = 0;
2835 #endif // LINUX_VERSION_CODE
2836 #endif // BYPASS_FLIP
2838 goto end_intr;
2840 intr_old:
2841 // above add by Victor Yu. 09-02-2002
2843 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-16-2007
2844 if ( tty->receive_room == 0 ) {
2845 if ( I_IXOFF(tty) || (tty->termios->c_cflag & CRTSCTS) ) // has flow control
2846 goto end_intr;
2848 #endif
2849 ch = inb(info->base + UART_RX);
2851 // following add by Victor Yu. 09-02-2002
2852 if ( (*status&UART_LSR_OE) && !(*status&UART_LSR_DR) )
2853 outb(0x23, info->base+UART_FCR);
2855 #if 1 // add by Victor Yu. 01-06-2005
2857 int __flag=0;
2858 if ( *status & UART_LSR_BI ) {
2859 info->icount.brk++;
2860 __flag = 1;
2862 if ( *status & UART_LSR_PE ) {
2863 info->icount.parity++;
2864 __flag = 1;
2866 if ( *status & UART_LSR_FE ) {
2867 info->icount.frame++;
2868 __flag = 1;
2870 if ( *status & UART_LSR_OE ) {
2871 info->icount.overrun++;
2872 __flag = 1;
2874 if ( __flag )
2875 wake_up_interruptible(&info->delta_msr_wait);
2877 #endif
2879 *status &= info->read_status_mask;
2880 // above add by Victor Yu. 09-02-2002
2882 if ( !(*status & info->ignore_status_mask) ) {
2883 char flag;
2884 #ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004
2885 if ( cnt >= TTY_FLIPBUF_SIZE )
2886 goto end_intr;
2887 #else
2888 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-16-2007
2889 if ( tty->flip.count >= TTY_FLIPBUF_SIZE )
2890 goto end_intr;
2891 tty->flip.count++;
2892 #endif
2893 #endif // BYPASS_FLIP
2894 if ( *status & UART_LSR_SPECIAL ) {
2895 if ( *status & UART_LSR_BI ) {
2896 #ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004
2897 *fp++ = TTY_BREAK;
2898 #else
2899 #if 0 // mask by Victor Yu. 02-08-2007
2900 *tty->flip.flag_buf_ptr++ = TTY_BREAK;
2901 #else
2902 flag = TTY_BREAK;
2903 #endif
2904 #endif
2906 if ( info->flags & ASYNC_SAK )
2907 do_SAK(tty);
2908 } else if ( *status & UART_LSR_PE ) {
2909 #ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004
2910 *fp++ = TTY_PARITY;
2911 #else
2912 #if 0 // mask by Victor Yu. 02-08-2007
2913 *tty->flip.flag_buf_ptr++ = TTY_PARITY;
2914 #else
2915 flag = TTY_PARITY;
2916 #endif
2917 #endif
2918 } else if ( *status & UART_LSR_FE ) {
2919 #ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004
2920 *fp++ = TTY_FRAME;
2921 #else
2922 #if 0 // mask by Victor Yu. 02-08-2007
2923 *tty->flip.flag_buf_ptr++ = TTY_FRAME;
2924 #else
2925 flag = TTY_FRAME;
2926 #endif
2927 #endif
2928 } else if ( *status & UART_LSR_OE ) {
2929 #ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004
2930 *fp++ = TTY_OVERRUN;
2931 #else
2932 #if 0 // mask by Victor Yu. 02-08-2007
2933 *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
2934 #else
2935 flag = TTY_OVERRUN;
2936 #endif
2937 #endif
2938 } else {
2939 #ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004
2940 *fp++ = 0;
2941 #else
2942 #if 0 // mask by Victor Yu. 02-08-2007
2943 *tty->flip.flag_buf_ptr++ = 0;
2944 #else
2945 flag = 0;
2946 #endif
2947 #endif
2949 } else {
2950 #ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004
2951 *fp++ = 0;
2952 #else
2953 #if 0 // mask by Victor Yu. 02-08-2007
2954 *tty->flip.flag_buf_ptr++ = 0;
2955 #else
2956 flag = 0;
2957 #endif
2958 #endif // BYPASS_FLIP
2960 #ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004
2961 *cp++ = ch;
2962 #else
2963 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-16-2007
2964 tty_insert_flip_char(tty, ch, flag);
2965 #else
2966 *tty->flip.char_buf_ptr++ = ch;
2967 #endif
2968 #endif // BYPASS_FLIP
2969 cnt++;
2972 end_intr: // add by Victor Yu. 09-02-2002
2974 mxvar_log.rxcnt[info->port] += cnt;
2976 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)) // add by Victor Yu. 02-04-2005
2977 info->icount.rx += cnt;
2978 #endif
2980 /* added by casper 1/11/2000 */
2981 #ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004
2982 tty->ldisc.receive_buf(tty, tty->flip.char_buf, tty->flip.flag_buf, cnt);
2983 #else
2984 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0))
2985 tty_flip_buffer_push(tty);
2986 #else
2987 queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
2988 #endif // LINUX_VERSION_CODE
2989 #endif // BYPASS_FLIP
2992 static inline void mxser_transmit_chars(struct mxser_struct *info)
2994 int count, cnt;
2996 if ( info->x_char ) {
2997 outb(info->x_char, info->base + UART_TX);
2998 info->x_char = 0;
2999 mxvar_log.txcnt[info->port]++;
3000 /* added by casper 1/11/2000 */
3001 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0))
3002 info->icount.tx++;
3003 #endif
3004 /* */
3005 return;
3008 if ( info->xmit_buf == 0 )
3009 return;
3011 if ((info->xmit_cnt <= 0) || info->tty->stopped ||
3012 (info->tty->hw_stopped && (info->type != PORT_16550A))) {
3013 info->IER &= ~UART_IER_THRI;
3014 outb(info->IER, info->base + UART_IER);
3015 return;
3018 #if 0 // mask by Victor Yu. 10-12-2004
3019 cnt = info->xmit_cnt;
3020 count = info->xmit_fifo_size;
3021 do {
3022 outb(info->xmit_buf[info->xmit_tail++], info->base + UART_TX);
3023 info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE - 1);
3024 if ( --info->xmit_cnt <= 0 )
3025 break;
3026 } while ( --count > 0 );
3027 mxvar_log.txcnt[info->port] += (cnt - info->xmit_cnt);
3028 #else // add by Victor Yu. 10-12-2004
3030 int tail=info->xmit_tail;
3031 unsigned char *ptr=info->xmit_buf;
3032 #define XMIT_SIZE_MASK (SERIAL_XMIT_SIZE - 1)
3033 cnt = count = MIN(info->xmit_fifo_size, info->xmit_cnt);
3034 while ( count-- > 0 ) {
3035 outb(ptr[tail++], info->base);
3036 tail &= XMIT_SIZE_MASK;
3038 info->xmit_tail = tail;
3039 info->xmit_cnt -= cnt;
3040 mxvar_log.txcnt[info->port] += cnt;
3042 #endif
3044 /* added by casper 1/11/2000 */
3045 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0))
3046 #if 0 // mask by Victor Yu. 10-12-2004
3047 info->icount.tx += (cnt - info->xmit_cnt);
3048 #else // add by Victor Yu. 10-12-2004
3049 info->icount.tx += cnt;
3050 #endif
3051 #endif
3052 /* */
3054 if ( info->xmit_cnt < WAKEUP_CHARS ) {
3055 set_bit(MXSER_EVENT_TXLOW,&info->event);
3056 #if 0
3057 MOD_INC_USE_COUNT;
3058 if (schedule_task(&info->tqueue) == 0)
3059 MOD_DEC_USE_COUNT;
3060 queue_task(&info->tqueue,&tq_scheduler);
3061 #else
3062 schedule_work(&info->tqueue);
3063 #endif
3065 if (info->xmit_cnt <= 0) {
3066 info->IER &= ~UART_IER_THRI;
3067 outb(info->IER, info->base + UART_IER);
3071 static inline void mxser_check_modem_status(struct mxser_struct *info,
3072 int status)
3074 /* update input line counters */
3075 if ( status & UART_MSR_TERI )
3076 info->icount.rng++;
3077 if ( status & UART_MSR_DDSR )
3078 info->icount.dsr++;
3079 if ( status & UART_MSR_DDCD )
3080 info->icount.dcd++;
3081 if ( status & UART_MSR_DCTS )
3082 info->icount.cts++;
3083 wake_up_interruptible(&info->delta_msr_wait);
3085 if ( (info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD) ) {
3086 if ( status & UART_MSR_DCD )
3087 wake_up_interruptible(&info->open_wait);
3088 #if 0
3089 else if ( !((info->flags & ASYNC_CALLOUT_ACTIVE) &&
3090 (info->flags & ASYNC_CALLOUT_NOHUP)) )
3091 #else
3092 else
3093 #endif
3094 set_bit(MXSER_EVENT_HANGUP,&info->event);
3095 #if 0
3096 MOD_INC_USE_COUNT;
3097 if (schedule_task(&info->tqueue) == 0)
3098 MOD_DEC_USE_COUNT;
3099 #else
3100 schedule_work(&info->tqueue);
3101 #endif
3103 if ( info->flags & ASYNC_CTS_FLOW ) {
3104 if ( info->tty->hw_stopped ) {
3105 if (status & UART_MSR_CTS ){
3106 info->tty->hw_stopped = 0;
3108 if (info->type != PORT_16550A) {
3109 info->IER |= UART_IER_THRI;
3110 outb(info->IER, info->base + UART_IER);
3112 set_bit(MXSER_EVENT_TXLOW,&info->event);
3113 #if 0
3114 MOD_INC_USE_COUNT;
3115 if (schedule_task(&info->tqueue) == 0)
3116 MOD_DEC_USE_COUNT;
3117 #else
3118 schedule_work(&info->tqueue);
3119 #endif
3121 } else {
3122 if ( !(status & UART_MSR_CTS) ){
3123 info->tty->hw_stopped = 1;
3124 if (info->type != PORT_16550A) {
3125 info->IER &= ~UART_IER_THRI;
3126 outb(info->IER, info->base + UART_IER);
3133 static int mxser_block_til_ready(struct tty_struct *tty, struct file * filp,
3134 struct mxser_struct *info)
3136 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,4,0))
3137 DECLARE_WAITQUEUE(wait, current);
3138 #else
3139 struct wait_queue wait = { current, NULL };
3140 #endif
3141 unsigned long flags;
3142 int retval;
3143 int do_clocal = 0;
3146 * If the device is in the middle of being closed, then block
3147 * until it's done, and then try again.
3149 if ( tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING) ) {
3150 if ( info->flags & ASYNC_CLOSING )
3151 interruptible_sleep_on(&info->close_wait);
3152 #ifdef SERIAL_DO_RESTART
3153 if ( info->flags & ASYNC_HUP_NOTIFY )
3154 return(-EAGAIN);
3155 else
3156 return(-ERESTARTSYS);
3157 #else
3158 return(-EAGAIN);
3159 #endif
3163 * If this is a callout device, then just make sure the normal
3164 * device isn't being used.
3166 #if 0
3167 if ( tty->driver->subtype == SERIAL_TYPE_CALLOUT ) {
3168 if ( info->flags & ASYNC_NORMAL_ACTIVE )
3169 return(-EBUSY);
3170 if ( (info->flags & ASYNC_CALLOUT_ACTIVE) &&
3171 (info->flags & ASYNC_SESSION_LOCKOUT) &&
3172 (info->session != current->session) )
3173 return(-EBUSY);
3174 if ( (info->flags & ASYNC_CALLOUT_ACTIVE) &&
3175 (info->flags & ASYNC_PGRP_LOCKOUT) &&
3176 (info->pgrp != current->pgrp) )
3177 return(-EBUSY);
3178 info->flags |= ASYNC_CALLOUT_ACTIVE;
3179 return(0);
3181 #endif
3184 * If non-blocking mode is set, or the port is not enabled,
3185 * then make the check up front and then exit.
3187 if ( (filp->f_flags & O_NONBLOCK) ||
3188 (tty->flags & (1 << TTY_IO_ERROR)) ) {
3189 #if 0
3190 if ( info->flags & ASYNC_CALLOUT_ACTIVE )
3191 return(-EBUSY);
3192 #endif
3193 info->flags |= ASYNC_NORMAL_ACTIVE;
3194 return(0);
3197 #if 0
3198 if ( info->flags & ASYNC_CALLOUT_ACTIVE ) {
3199 if ( info->normal_termios.c_cflag & CLOCAL )
3200 do_clocal = 1;
3201 } else {
3202 #endif
3203 if ( tty->termios->c_cflag & CLOCAL )
3204 do_clocal = 1;
3205 #if 0
3207 #endif
3210 * Block waiting for the carrier detect and the line to become
3211 * free (i.e., not in use by the callout). While we are in
3212 * this loop, info->count is dropped by one, so that
3213 * mxser_close() knows when to free things. We restore it upon
3214 * exit, either normal or abnormal.
3216 retval = 0;
3217 add_wait_queue(&info->open_wait, &wait);
3218 #if 0 // mask by Victor Yu. 12-28-2004
3219 save_flags(flags);
3220 cli();
3221 if ( !tty_hung_up_p(filp) )
3222 info->count--;
3223 restore_flags(flags);
3224 // #else // add by Victor Yu. 12-28-2004, remark by Victor Yu. 06-22-2007
3225 if ( !tty_hung_up_p(filp) ) {
3226 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3227 local_irq_save(flags);
3228 #else
3229 save_flags(flags);
3230 cli();
3231 #endif // LINUX_VERSION_CODE
3232 info->count--;
3233 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3234 local_irq_restore(flags);
3235 #else
3236 restore_flags(flags);
3237 #endif // LINUX_VERSION_CODE
3239 #endif
3240 info->blocked_open++;
3241 while ( 1 ) {
3242 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3243 local_irq_save(flags);
3244 #else
3245 save_flags(flags);
3246 cli();
3247 #endif // LINUX_VERSION_CODE
3248 #if 0
3249 if ( !(info->flags & ASYNC_CALLOUT_ACTIVE) )
3250 #endif
3251 outb(inb(info->base + UART_MCR) | UART_MCR_DTR | UART_MCR_RTS,
3252 info->base + UART_MCR);
3253 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3254 local_irq_restore(flags);
3255 #else
3256 restore_flags(flags);
3257 #endif // LINUX_VERSION_CODE
3258 current->state = TASK_INTERRUPTIBLE;
3259 if ( tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED) ) {
3260 #ifdef SERIAL_DO_RESTART
3261 if ( info->flags & ASYNC_HUP_NOTIFY )
3262 retval = -EAGAIN;
3263 else
3264 retval = -ERESTARTSYS;
3265 #else
3266 retval = -EAGAIN;
3267 #endif
3268 break;
3270 #if 0
3271 if ( !(info->flags & ASYNC_CALLOUT_ACTIVE) &&
3272 !(info->flags & ASYNC_CLOSING) &&
3273 (do_clocal || (inb(info->base + UART_MSR) & UART_MSR_DCD)) )
3274 #else
3275 if ( !(info->flags & ASYNC_CLOSING) &&
3276 (do_clocal || (inb(info->base + UART_MSR) & UART_MSR_DCD)) )
3277 #endif
3278 break;
3279 if ( signal_pending(current) ) {
3280 retval = -ERESTARTSYS;
3281 break;
3283 schedule();
3285 current->state = TASK_RUNNING;
3286 remove_wait_queue(&info->open_wait, &wait);
3287 if ( !tty_hung_up_p(filp) ) {
3288 #if 0 // mask by Victor 12-28-2004
3289 info->count++;
3290 // #else // add by Victor Yu. 12-28-2004, remark by Victor Yu. 06-22-2007
3291 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3292 local_irq_save(flags);
3293 #else
3294 save_flags(flags);
3295 cli();
3296 #endif // LINUX_VERSION_CODE
3297 info->count++;
3298 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3299 local_irq_restore(flags);
3300 #else
3301 restore_flags(flags);
3302 #endif // LINUX_VERSION_CODE
3303 #endif
3305 info->blocked_open--;
3306 if ( retval )
3307 return(retval);
3308 info->flags |= ASYNC_NORMAL_ACTIVE;
3309 return(0);
3312 static int mxser_startup(struct mxser_struct * info)
3314 unsigned long flags;
3315 unsigned long page;
3317 page = get_zeroed_page(GFP_KERNEL);
3318 if ( !page )
3319 return(-ENOMEM);
3321 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3322 local_irq_save(flags);
3323 #else
3324 save_flags(flags);
3325 cli();
3326 #endif // LINUX_VERSION_CODE
3328 if ( info->flags & ASYNC_INITIALIZED ) {
3329 free_page(page);
3330 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3331 local_irq_restore(flags);
3332 #else
3333 restore_flags(flags);
3334 #endif // LINUX_VERSION_CODE
3335 return(0);
3338 if ( !info->base || !info->type ) {
3339 if ( info->tty )
3340 set_bit(TTY_IO_ERROR, &info->tty->flags);
3341 free_page(page);
3342 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3343 local_irq_restore(flags);
3344 #else
3345 restore_flags(flags);
3346 #endif // LINUX_VERSION_CODE
3347 return(0);
3349 if ( info->xmit_buf )
3350 free_page(page);
3351 else
3352 info->xmit_buf = (unsigned char *)page;
3355 * Clear the FIFO buffers and disable them
3356 * (they will be reenabled in mxser_change_speed())
3358 if ( info->xmit_fifo_size == 16 )
3359 outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
3360 info->base + UART_FCR);
3361 // following add by Victor Yu. 08-30-2002
3362 else if ( info->xmit_fifo_size == 64 || info->xmit_fifo_size == 128 )
3363 outb((UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT|MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base+UART_FCR);
3364 // above add by Victor Yu. 08-30-2002
3367 * At this point there's no way the LSR could still be 0xFF;
3368 * if it is, then bail out, because there's likely no UART
3369 * here.
3371 if ( inb(info->base + UART_LSR) == 0xff ) {
3372 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3373 local_irq_restore(flags);
3374 #else
3375 restore_flags(flags);
3376 #endif // LINUX_VERSION_CODE
3377 #if (LINUX_VERSION_CODE < VERSION_CODE(2,1,0))
3378 if ( suser() ) {
3379 #else
3380 if (capable(CAP_SYS_ADMIN)) {
3381 #endif
3382 if ( info->tty )
3383 set_bit(TTY_IO_ERROR, &info->tty->flags);
3384 return(0);
3385 } else
3386 return(-ENODEV);
3390 * Clear the interrupt registers.
3392 (void)inb(info->base + UART_LSR);
3393 (void)inb(info->base + UART_RX);
3394 (void)inb(info->base + UART_IIR);
3395 (void)inb(info->base + UART_MSR);
3398 * Now, initialize the UART
3400 outb(UART_LCR_WLEN8, info->base + UART_LCR); /* reset DLAB */
3401 info->MCR = UART_MCR_DTR | UART_MCR_RTS;
3402 outb(info->MCR, info->base + UART_MCR);
3405 * Finally, enable interrupts
3407 info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI | MOXA_MUST_IER_EGDAI;
3408 outb(info->IER, info->base + UART_IER); /* enable interrupts */
3411 * And clear the interrupt registers again for luck.
3413 (void)inb(info->base + UART_LSR);
3414 (void)inb(info->base + UART_RX);
3415 (void)inb(info->base + UART_IIR);
3416 (void)inb(info->base + UART_MSR);
3418 #if (LINUX_VERSION_CODE < VERSION_CODE(2,1,0))
3419 if ( info->tty )
3420 clear_bit(TTY_IO_ERROR, &info->tty->flags);
3421 #else
3422 if ( info->tty )
3423 test_and_clear_bit(TTY_IO_ERROR, &info->tty->flags);
3424 #endif
3425 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
3428 * and set the speed of the serial port
3430 #if 1 // add by Victor Yu. 12-27-2004
3431 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3432 local_irq_restore(flags);
3433 #else
3434 restore_flags(flags);
3435 #endif // LINUX_VERSION_CODE
3436 #endif
3437 mxser_change_speed(info, 0);
3439 #if 1 // add by Victor Yu. 12-27-2004
3440 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3441 local_irq_save(flags);
3442 #else
3443 save_flags(flags);
3444 cli();
3445 #endif // LINUX_VERSION_CODE
3446 #endif
3447 info->flags |= ASYNC_INITIALIZED;
3448 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3449 local_irq_restore(flags);
3450 #else
3451 restore_flags(flags);
3452 #endif // LINUX_VERSION_CODE
3453 return(0);
3457 * This routine will shutdown a serial port; interrupts maybe disabled, and
3458 * DTR is dropped if the hangup on close termio flag is on.
3460 static void mxser_shutdown(struct mxser_struct * info)
3462 unsigned long flags;
3464 if ( !(info->flags & ASYNC_INITIALIZED) )
3465 return;
3467 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3468 local_irq_save(flags);
3469 #else
3470 save_flags(flags);
3471 cli(); /* Disable interrupts */
3472 #endif // LINUX_VERSION_CODE
3475 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
3476 * here so the queue might never be waken up
3478 wake_up_interruptible(&info->delta_msr_wait);
3481 * Free the IRQ, if necessary
3483 if ( info->xmit_buf ) {
3484 free_page((unsigned long)info->xmit_buf);
3485 info->xmit_buf = 0;
3488 info->IER = 0;
3489 outb(0x00, info->base + UART_IER);
3491 if ( !info->tty || (info->tty->termios->c_cflag & HUPCL) )
3492 info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
3493 outb(info->MCR, info->base + UART_MCR);
3495 /* clear Rx/Tx FIFO's */
3496 outb((UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT|MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
3498 /* read data port to reset things */
3499 (void)inb(info->base + UART_RX);
3501 if ( info->tty )
3502 set_bit(TTY_IO_ERROR, &info->tty->flags);
3504 info->flags &= ~ASYNC_INITIALIZED;
3505 SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->base);
3506 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3507 local_irq_restore(flags);
3508 #else
3509 restore_flags(flags);
3510 #endif // LINUX_VERSION_CODE
3514 * This routine is called to set the UART divisor registers to match
3515 * the specified baud rate for a serial port.
3517 static int mxser_change_speed(struct mxser_struct *info,
3518 struct termios *old_termios)
3520 int quot = 0;
3521 unsigned cflag, cval, fcr;
3522 int bindex;
3523 int ret = 0;
3524 unsigned long flags;
3526 if ( !info->tty || !info->tty->termios )
3527 return ret;
3528 cflag = info->tty->termios->c_cflag;
3529 if ( !(info->base) )
3530 return ret;
3532 #ifndef B921600
3533 #define B921600 (B460800 +1)
3534 #endif
3535 switch( cflag & (CBAUD | CBAUDEX) ){
3536 #ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-13-2004
3537 case B4000000 : bindex = BAUD_TABLE_NO; break;
3538 #endif
3539 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) /// add by Victor Yu. 02-16-2007
3540 case B921600 : bindex = 22; break;
3541 case B576000 : bindex = 21; break;
3542 case B500000 : bindex = 20; break;
3543 #else
3544 case B921600 : bindex = 20; break;
3545 #endif
3546 case B460800 : bindex = 19; break;
3547 case B230400 : bindex = 18; break;
3548 case B115200 : bindex = 17; break;
3549 case B57600 : bindex = 16; break;
3550 case B38400 : bindex = 15; break;
3551 case B19200 : bindex = 14; break;
3552 case B9600 : bindex = 13; break;
3553 case B4800 : bindex = 12; break;
3554 case B2400 : bindex = 11; break;
3555 case B1800 : bindex = 10; break;
3556 case B1200 : bindex = 9; break;
3557 case B600 : bindex = 8; break;
3558 case B300 : bindex = 7; break;
3559 case B200 : bindex = 6; break;
3560 case B150 : bindex = 5; break;
3561 case B134 : bindex = 4; break;
3562 case B110 : bindex = 3; break;
3563 case B75 : bindex = 2; break;
3564 case B50 : bindex = 1; break;
3565 default: bindex = 0; break;
3568 if ( bindex == 15 ) {
3569 if ( (info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI )
3570 bindex = 16; /* 57600 bps */
3571 if ( (info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI )
3572 bindex = 17; /* 115200 bps */
3574 #ifdef ASYNC_SPD_SHI
3575 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
3576 bindex = 18;
3577 #endif
3579 #ifdef ASYNC_SPD_WARP
3580 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
3581 bindex = 19;
3582 #endif
3584 #ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-13-2004
3585 if ( bindex == BAUD_TABLE_NO ) {
3586 quot = info->baud_base / info->speed;
3587 if ( info->speed <= 0 || info->speed > info->MaxCanSetBaudRate )
3588 quot = 0;
3590 else
3591 #endif
3592 if ( mxvar_baud_table[bindex] == 134 ) {
3593 quot = (2 * info->baud_base / 269);
3594 #ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-12-2004
3595 info->speed = 134;
3596 #endif
3597 } else if ( mxvar_baud_table[bindex] ) {
3598 quot = info->baud_base / mxvar_baud_table[bindex];
3599 // following add by Victor Yu. 09-04-2002
3600 if ( mxvar_baud_table[bindex] > info->MaxCanSetBaudRate )
3601 quot = 0;
3602 // add by Victor Yu. 09-04-2002
3603 #ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-12-2004
3604 info->speed = mxvar_baud_table[bindex];
3605 #endif
3606 if (!quot && old_termios) {
3607 /* re-calculate */
3608 info->tty->termios->c_cflag &= ~CBAUD;
3609 info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
3610 switch( info->tty->termios->c_cflag & (CBAUD | CBAUDEX) ){
3611 #ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-13-2004
3612 case B4000000 : bindex = BAUD_TABLE_NO; break;
3613 #endif
3614 case B921600 : bindex = 20; break;
3615 case B460800 : bindex = 19; break;
3616 case B230400 : bindex = 18; break;
3617 case B115200 : bindex = 17; break;
3618 case B57600 : bindex = 16; break;
3619 case B38400 : bindex = 15; break;
3620 case B19200 : bindex = 14; break;
3621 case B9600 : bindex = 13; break;
3622 case B4800 : bindex = 12; break;
3623 case B2400 : bindex = 11; break;
3624 case B1800 : bindex = 10; break;
3625 case B1200 : bindex = 9; break;
3626 case B600 : bindex = 8; break;
3627 case B300 : bindex = 7; break;
3628 case B200 : bindex = 6; break;
3629 case B150 : bindex = 5; break;
3630 case B134 : bindex = 4; break;
3631 case B110 : bindex = 3; break;
3632 case B75 : bindex = 2; break;
3633 case B50 : bindex = 1; break;
3634 default: bindex = 0; break;
3636 if ( bindex == 15 ) {
3637 if ( (info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI )
3638 bindex = 16; /* 57600 bps */
3639 if ( (info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI )
3640 bindex = 17; /* 115200 bps */
3641 #ifdef ASYNC_SPD_SHI
3642 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
3643 bindex = 18;
3644 #endif
3645 #ifdef ASYNC_SPD_WARP
3646 if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
3647 bindex = 19;
3648 #endif
3650 #ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-13-2004
3651 if ( bindex == BAUD_TABLE_NO ) {
3652 quot = info->baud_base / info->speed;
3653 if ( info->speed <= 0 || info->speed > info->MaxCanSetBaudRate )
3654 quot = 0;
3656 else
3657 #endif
3658 if ( mxvar_baud_table[bindex] == 134 ) {
3659 quot = (2 * info->baud_base / 269);
3660 #ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-12-2004
3661 info->speed = 134;
3662 #endif
3663 } else if ( mxvar_baud_table[bindex] ) {
3664 quot = info->baud_base / mxvar_baud_table[bindex];
3665 // following add by Victor Yu. 09-04-2002
3666 if ( mxvar_baud_table[bindex] > info->MaxCanSetBaudRate )
3667 quot = 0;
3668 // above add by Victor Yu. 09-04-2002
3669 #ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-12-2004
3670 info->speed = mxvar_baud_table[bindex];
3671 #endif
3672 if(quot==0)
3673 quot = 1;
3674 } else {
3675 quot = 0;
3677 }else if(quot==0)
3678 quot = 1;
3679 } else {
3680 quot = 0;
3683 info->timeout = ((info->xmit_fifo_size*HZ*10*quot) / info->baud_base);
3684 info->timeout += HZ/50; /* Add .02 seconds of slop */
3686 if ( quot ) {
3687 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3688 local_irq_save(flags);
3689 #else
3690 save_flags(flags);
3691 cli();
3692 #endif // LINUX_VERSION_CODE
3693 info->MCR |= UART_MCR_DTR;
3694 outb(info->MCR, info->base + UART_MCR);
3695 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3696 local_irq_restore(flags);
3697 #else
3698 restore_flags(flags);
3699 #endif // LINUX_VERSION_CODE
3700 } else {
3701 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3702 local_irq_save(flags);
3703 #else
3704 save_flags(flags);
3705 cli();
3706 #endif // LINUX_VERSION_CODE
3707 info->MCR &= ~UART_MCR_DTR;
3708 outb(info->MCR, info->base + UART_MCR);
3709 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3710 local_irq_restore(flags);
3711 #else
3712 restore_flags(flags);
3713 #endif // LINUX_VERSION_CODE
3714 return ret;
3716 /* byte size and parity */
3717 switch ( cflag & CSIZE ) {
3718 case CS5: cval = 0x00; break;
3719 case CS6: cval = 0x01; break;
3720 case CS7: cval = 0x02; break;
3721 case CS8: cval = 0x03; break;
3722 default: cval = 0x00; break; /* too keep GCC shut... */
3724 if ( cflag & CSTOPB )
3725 cval |= 0x04;
3726 if ( cflag & PARENB )
3727 cval |= UART_LCR_PARITY;
3728 #ifndef CMSPAR
3729 #define CMSPAR 010000000000
3730 #endif
3731 if ( !(cflag & PARODD) ){
3732 cval |= UART_LCR_EPAR;
3734 if ( cflag & CMSPAR )
3735 cval |= UART_LCR_SPAR;
3737 if ( (info->type == PORT_8250) || (info->type == PORT_16450) ) {
3738 fcr = 0;
3739 } else {
3740 fcr = UART_FCR_ENABLE_FIFO;
3741 // following add by Victor Yu. 08-30-2002
3742 fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
3743 #if 1 // add by Victor Yu. 05-04-2005
3744 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3745 local_irq_save(flags);
3746 #else
3747 save_flags(flags);
3748 cli();
3749 #endif // LINUX_VERSION_CODE
3750 #endif
3751 SET_MOXA_MUST_FIFO_VALUE(info);
3752 #if 1 // add by Victor Yu. 05-04-2005
3753 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3754 local_irq_restore(flags);
3755 #else
3756 restore_flags(flags);
3757 #endif // LINUX_VERSION_CODE
3758 #endif
3761 /* CTS flow control flag and modem status interrupts */
3762 #if 1 // add by Victor Yu. 12-30-2004
3763 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3764 local_irq_save(flags);
3765 #else
3766 save_flags(flags);
3767 cli();
3768 #endif // LINUX_VERSION_CODE
3769 #if 1 // add by Victor Yu. 05-04-2005
3770 outb(cval | UART_LCR_DLAB, info->base + UART_LCR); /* set DLAB */
3771 outb(quot & 0xff, info->base + UART_DLL); /* LS of divisor */
3772 outb(quot >> 8, info->base + UART_DLM); /* MS of divisor */
3773 outb(cval, info->base + UART_LCR); /* reset DLAB */
3774 #ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE // add by Victor Yu. 08-12-2004
3775 if ( info->speed ) {
3776 quot = info->baud_base % info->speed;
3777 quot *= 8;
3778 if ( (quot % info->speed) > (info->speed / 2) ) {
3779 quot /= info->speed;
3780 quot++;
3781 } else {
3782 quot /= info->speed;
3784 SET_MOXA_MUST_ENUM_VALUE(info->base, quot);
3785 } else {
3786 SET_MOXA_MUST_ENUM_VALUE(info->base, 0);
3788 #endif
3789 outb(fcr, info->base + UART_FCR); /* set fcr */
3790 #endif // 05-04-2005
3791 #endif // 12-30-2004
3792 #if 0 // mask by Victor Yu. 12-31-2004
3793 info->IER &= ~UART_IER_MSI;
3794 #endif
3795 info->MCR &= ~UART_MCR_AFE;
3796 if ( cflag & CRTSCTS ) {
3797 info->flags |= ASYNC_CTS_FLOW;
3798 info->IER |= UART_IER_MSI;
3799 if ( info->type == PORT_16550A ) {
3800 info->MCR |= UART_MCR_AFE;
3801 } else {
3802 unsigned char status;
3803 #if 0 // mask by Victor Yu. 12-30-2004
3804 save_flags(flags);
3805 cli();
3806 #endif
3807 status = inb(info->base + UART_MSR);
3808 #if 0 // mask by Victor Yu. 12-30-2004
3809 restore_flags(flags);
3810 #endif
3811 if (info->tty->hw_stopped) {
3812 if (status & UART_MSR_CTS) {
3813 info->tty->hw_stopped = 0;
3814 if (info->type != PORT_16550A) {
3815 info->IER |= UART_IER_THRI;
3816 outb(info->IER, info->base + UART_IER);
3818 set_bit(MXSER_EVENT_TXLOW, &info->event);
3819 #if 0
3820 MOD_INC_USE_COUNT;
3821 if (schedule_task(&info->tqueue) == 0)
3822 MOD_DEC_USE_COUNT;
3823 #else
3824 schedule_work(&info->tqueue);
3825 #endif
3827 } else {
3828 if (!(status & UART_MSR_CTS)) {
3829 info->tty->hw_stopped = 1;
3830 if (info->type != PORT_16550A) {
3831 info->IER &= ~UART_IER_THRI;
3832 outb(info->IER, info->base + UART_IER);
3837 } else {
3838 info->flags &= ~ASYNC_CTS_FLOW;
3840 #if 0 // add by Victor Yu. 12-27-2004
3841 save_flags(flags);
3842 cli();
3843 #endif
3844 outb(info->MCR, info->base + UART_MCR);
3845 if ( cflag & CLOCAL ){
3846 info->flags &= ~ASYNC_CHECK_CD;
3847 }else {
3848 info->flags |= ASYNC_CHECK_CD;
3849 info->IER |= UART_IER_MSI;
3851 outb(info->IER, info->base + UART_IER);
3852 #if 1 // add by Victor Yu. 12-27-2004
3853 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3854 local_irq_restore(flags);
3855 #else
3856 restore_flags(flags);
3857 #endif // LINUX_VERSION_CODE
3858 #endif
3861 * Set up parity check flag
3863 info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
3864 if ( I_INPCK(info->tty) )
3865 info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
3866 if ( I_BRKINT(info->tty) || I_PARMRK(info->tty) )
3867 info->read_status_mask |= UART_LSR_BI;
3869 info->ignore_status_mask = 0;
3870 #if 0
3871 /* This should be safe, but for some broken bits of hardware... */
3872 if ( I_IGNPAR(info->tty) ) {
3873 info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
3874 info->read_status_mask |= UART_LSR_PE | UART_LSR_FE;
3876 #endif
3877 if ( I_IGNBRK(info->tty) ) {
3878 info->ignore_status_mask |= UART_LSR_BI;
3879 info->read_status_mask |= UART_LSR_BI;
3881 * If we're ignore parity and break indicators, ignore
3882 * overruns too. (For real raw support).
3884 if ( I_IGNPAR(info->tty) ) {
3885 info->ignore_status_mask |= UART_LSR_OE|UART_LSR_PE|UART_LSR_FE;
3886 info->read_status_mask |= UART_LSR_OE|UART_LSR_PE|UART_LSR_FE;
3890 // following add by Victor Yu. 09-02-2002
3891 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3892 local_irq_save(flags);
3893 #else
3894 save_flags(flags);
3895 cli();
3896 #endif // LINUX_VERSION_CODE
3897 SET_MOXA_MUST_XON1_VALUE(info->base, START_CHAR(info->tty));
3898 SET_MOXA_MUST_XOFF1_VALUE(info->base, STOP_CHAR(info->tty));
3899 if ( I_IXON(info->tty) ) {
3900 #if 1 // add by Victor Yu. 01-04-2005
3901 info->IER |= MOXA_MUST_IER_XINT;
3902 #endif
3903 ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base);
3904 } else {
3905 #if 1 // add by Victor Yu. 01-04-2005
3906 info->IER &= ~MOXA_MUST_IER_XINT;
3907 #endif
3908 DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base);
3910 #if 1 // add by Victor Yu. 01-04-2005
3911 outb(info->IER, info->base+UART_IER);
3912 #endif
3913 if ( I_IXOFF(info->tty) ) {
3914 ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->base);
3915 } else {
3916 DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->base);
3918 if ( I_IXANY(info->tty) ) {
3919 info->MCR |= MOXA_MUST_MCR_XON_ANY;
3920 ENABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->base);
3921 } else {
3922 info->MCR &= ~MOXA_MUST_MCR_XON_ANY;
3923 DISABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->base);
3925 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3926 local_irq_restore(flags);
3927 #else
3928 restore_flags(flags);
3929 #endif // LINUX_VERSION_CODE
3930 // above add by Victor Yu. 09-02-2002
3932 return ret;
3936 * ------------------------------------------------------------
3937 * friends of mxser_ioctl()
3938 * ------------------------------------------------------------
3940 static int mxser_get_serial_info(struct mxser_struct * info,
3941 struct serial_struct * retinfo)
3943 struct serial_struct tmp;
3945 if ( !retinfo )
3946 return(-EFAULT);
3947 memset(&tmp, 0, sizeof(tmp));
3948 tmp.type = info->type;
3949 tmp.line = info->port;
3950 tmp.port = info->base;
3951 tmp.irq = info->irq;
3952 tmp.flags = info->flags;
3953 tmp.baud_base = info->baud_base;
3954 tmp.close_delay = info->close_delay;
3955 tmp.closing_wait = info->closing_wait;
3956 tmp.custom_divisor = info->custom_divisor;
3957 tmp.hub6 = 0;
3958 copy_to_user(retinfo, &tmp, sizeof(*retinfo));
3959 return(0);
3962 static int mxser_set_serial_info(struct mxser_struct * info,
3963 struct serial_struct * new_info)
3965 struct serial_struct new_serial;
3966 unsigned int flags;
3967 int retval = 0;
3969 if ( !new_info || !info->base )
3970 return(-EFAULT);
3971 copy_from_user(&new_serial, new_info, sizeof(new_serial));
3973 if ( (new_serial.irq != info->irq) ||
3974 (new_serial.port != info->base) ||
3975 (new_serial.custom_divisor != info->custom_divisor) ||
3976 (new_serial.baud_base != info->baud_base) )
3977 return(-EPERM);
3979 flags = info->flags & ASYNC_SPD_MASK;
3981 #if (LINUX_VERSION_CODE < VERSION_CODE(2,1,0))
3982 if ( !suser() ) {
3983 #else
3984 if ( !capable(CAP_SYS_ADMIN)) {
3985 #endif
3986 if ( (new_serial.baud_base != info->baud_base) ||
3987 (new_serial.close_delay != info->close_delay) ||
3988 ((new_serial.flags & ~ASYNC_USR_MASK) !=
3989 (info->flags & ~ASYNC_USR_MASK)) )
3990 return(-EPERM);
3991 info->flags = ((info->flags & ~ASYNC_USR_MASK) |
3992 (new_serial.flags & ASYNC_USR_MASK));
3993 } else {
3995 * OK, past this point, all the error checking has been done.
3996 * At this point, we start making changes.....
3998 info->flags = ((info->flags & ~ASYNC_FLAGS) |
3999 (new_serial.flags & ASYNC_FLAGS));
4000 info->close_delay = new_serial.close_delay * HZ/100;
4001 info->closing_wait = new_serial.closing_wait * HZ/100;
4002 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0))
4003 info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
4004 #endif
4007 /* added by casper, 3/17/2000, for mouse */
4008 info->type = new_serial.type;
4010 info->xmit_fifo_size = 128;
4011 if ( info->flags & ASYNC_INITIALIZED ) {
4012 if ( flags != (info->flags & ASYNC_SPD_MASK) ){
4013 mxser_change_speed(info,0);
4015 } else{
4016 retval = mxser_startup(info);
4018 return(retval);
4022 * mxser_get_lsr_info - get line status register info
4024 * Purpose: Let user call ioctl() to get info when the UART physically
4025 * is emptied. On bus types like RS485, the transmitter must
4026 * release the bus after transmitting. This must be done when
4027 * the transmit shift register is empty, not be done when the
4028 * transmit holding register is empty. This functionality
4029 * allows an RS485 driver to be written in user space.
4031 static int mxser_get_lsr_info(struct mxser_struct * info, unsigned int *value)
4033 unsigned char status;
4034 unsigned int result;
4035 unsigned long flags;
4037 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
4038 local_irq_save(flags);
4039 #else
4040 save_flags(flags);
4041 cli();
4042 #endif // LINUX_VERSION_CODE
4043 status = inb(info->base + UART_LSR);
4044 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
4045 local_irq_restore(flags);
4046 #else
4047 restore_flags(flags);
4048 #endif // LINUX_VERSION_CODE
4049 result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
4050 put_to_user(result, value);
4051 return(0);
4055 * This routine sends a break character out the serial port.
4057 static void mxser_send_break(struct mxser_struct * info, int duration)
4059 unsigned long flags;
4060 #if 1 // add by Victor Yu. 12-27-2004
4061 unsigned long timeout;
4062 #endif
4064 if ( !info->base )
4065 return;
4066 #if 0 // mask by Victor Yu. 12-27-2004
4067 current->state = TASK_INTERRUPTIBLE;
4068 #endif
4069 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
4070 local_irq_save(flags);
4071 #else
4072 save_flags(flags);
4073 cli();
4074 #endif // LINUX_VERSION_CODE
4075 outb(inb(info->base + UART_LCR) | UART_LCR_SBC, info->base + UART_LCR);
4076 #if 0 // mask by Victor Yu. 12-27-2004
4077 schedule_timeout(duration);
4078 #else // add by Victor Yu. 12-27-2004
4079 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
4080 local_irq_restore(flags);
4081 #else
4082 restore_flags(flags);
4083 #endif // LINUX_VERSION_CODE
4084 timeout = jiffies + (unsigned long)duration;
4085 while ( 1 ) {
4086 current->state = TASK_INTERRUPTIBLE;
4087 schedule_timeout(5);
4088 if ( time_after(jiffies, timeout) )
4089 break;
4091 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
4092 local_irq_save(flags);
4093 #else
4094 save_flags(flags);
4095 cli();
4096 #endif // LINUX_VERSION_CODE
4097 #endif
4098 outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, info->base + UART_LCR);
4099 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
4100 local_irq_restore(flags);
4101 #else
4102 restore_flags(flags);
4103 #endif // LINUX_VERSION_CODE
4106 #if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) // add by Victor Yu. 04-28-2006, for 2.6.x
4107 static int mxser_get_modem_info(struct mxser_struct * info,
4108 unsigned int *value)
4110 unsigned char control, status;
4111 unsigned int result;
4112 unsigned long flags;
4114 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
4115 local_irq_save(flags);
4116 #else
4117 save_flags(flags);
4118 cli();
4119 #endif // LINUX_VERSION_CODE
4120 control = info->MCR;
4121 status = inb(info->base + UART_MSR);
4122 #if 0 // mask by Victor Yu. 12-30-2004, I think that we donot need to do it. Because the interrupt service will do it.
4123 if ( status & UART_MSR_ANY_DELTA )
4124 mxser_check_modem_status(info, status);
4125 #endif
4126 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
4127 local_irq_restore(flags);
4128 #else
4129 restore_flags(flags);
4130 #endif // LINUX_VERSION_CODE
4131 result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
4132 ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
4133 ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) |
4134 ((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
4135 ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
4136 ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
4137 put_to_user(result, value);
4138 return(0);
4141 static int mxser_set_modem_info(struct mxser_struct * info, unsigned int cmd,
4142 unsigned int *value)
4144 int error;
4145 unsigned int arg;
4146 unsigned long flags;
4148 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu. 02-09-2007
4149 error = verify_area(VERIFY_READ, value, sizeof(int));
4150 if ( error )
4151 return(error);
4152 #endif // LINUX_VERSION_CODE
4153 get_from_user(arg,value);
4154 #if 1 // add by Victor Yu. 12-30-2004
4155 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
4156 local_irq_save(flags);
4157 #else
4158 save_flags(flags);
4159 cli();
4160 #endif // LINUX_VERSION_CODE
4161 #endif
4162 switch ( cmd ) {
4163 case TIOCMBIS:
4164 if ( arg & TIOCM_RTS )
4165 info->MCR |= UART_MCR_RTS;
4166 if ( arg & TIOCM_DTR )
4167 info->MCR |= UART_MCR_DTR;
4168 break;
4169 case TIOCMBIC:
4170 if ( arg & TIOCM_RTS )
4171 info->MCR &= ~UART_MCR_RTS;
4172 if ( arg & TIOCM_DTR )
4173 info->MCR &= ~UART_MCR_DTR;
4174 break;
4175 case TIOCMSET:
4176 info->MCR = ((info->MCR & ~(UART_MCR_RTS | UART_MCR_DTR)) |
4177 ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) |
4178 ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
4179 break;
4180 default:
4181 #if 1 // add by Victor Yu. 12-30-2004
4182 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
4183 local_irq_restore(flags);
4184 #else
4185 restore_flags(flags);
4186 #endif // LINUX_VERSION_CODE
4187 #endif
4188 return(-EINVAL);
4190 #if 0 // mask by Victor Yu. 12-30-2004
4191 save_flags(flags);
4192 cli();
4193 #endif
4194 outb(info->MCR, info->base + UART_MCR);
4195 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
4196 local_irq_restore(flags);
4197 #else
4198 restore_flags(flags);
4199 #endif // LINUX_VERSION_CODE
4200 return(0);
4202 #endif