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
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>
43 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-09-2007
44 #include <linux/config.h>
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>
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>
74 #include <asm/system.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"
84 #define MXSERCUMAJOR 35
87 #if (LINUX_VERSION_CODE < VERSION_CODE(2,1,0))
88 #include <linux/bios32.h>
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
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
156 #define PORTNO(x) (MINOR((x)->device) - (x)->driver.minor_start)
158 #define PORTNO(x) ((x)->index)
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)
166 #define MIN(a,b) ((a) < (b) ? (a) : (b))
173 static char *mxser_brdname
[] = {
178 static int mxser_numports
[] = {
183 unsigned short vendor_id
;
184 unsigned short device_id
;
185 unsigned short board_type
;
188 #ifdef CONFIG_ARCH_IA241 // add by Victor Yu. 02-16-2006
189 static mxser_pciinfo mxser_pcibrds
[] = {
190 {0x1393,0x0001,UC7110_BOARD
},
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)
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
220 #define RS485_2WIRE_MODE 1
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)
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
249 struct mxser_hwconf
{
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
{
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
;
278 int x_char
; /* xon/xoff character */
280 unsigned short closing_wait
;
281 int IER
; /* Interrupt Enable Register */
282 int MCR
; /* Modem control register */
284 int count
; /* # of fd on device */
285 int blocked_open
; /* # of blocked opens */
287 long session
; /* Session of opening process */
288 long pgrp
; /* pgrp of opening process */
290 unsigned char *xmit_buf
;
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 */
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
310 int rxcnt
[MXSER_PORTS
];
311 int txcnt
[MXSER_PORTS
];
314 struct mxser_mstatus
{
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
];
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
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
*);
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);
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 *);
388 static irqreturn_t
mxser_interrupt(int, void *, struct pt_regs
*);
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 *);
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
);
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
425 #define MOXA_MUST_GDL_REGISTER 7
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
437 #define MOXA_MUST_EFR_REGISTER 2
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
453 #define MOXA_MUST_XON1_REGISTER 4
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
460 #define MOXA_MUST_XON2_REGISTER 5
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
467 #define MOXA_MUST_XOFF1_REGISTER 6
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
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
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
530 #define MOXA_MUST_EFR_SF_TX1 0x08
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
554 typedef unsigned char UCHAR
;
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); \
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) { \
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) { \
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 )
837 port
+= mxsercfg
[board
].ports
;
840 len
= sprintf(page
, "Ports: %d\n", port
);
842 len
= sprintf(page
, "%d\n", port
);
845 goto end_mxser_read_proc
;
847 len
+= sprintf(page
+len
, "PortNo InBytes OutBytes Speed Opened Interface DataBits Parity CTS DSR DCD RTS DTR\n");
849 for ( board
=0, p
=0; board
<MXSER_BOARDS
; board
++ ) {
850 if ( mxsercfg
[board
].board_type
== -1 )
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
857 len
+= sprintf(page
+len
, "Port%d: %lu %lu", p
, mxvar_log
.rxcnt
[i
], mxvar_log
.txcnt
[i
]);
859 len
+= sprintf(page
+len
, "%lu %lu", mxvar_log
.rxcnt
[i
], mxvar_log
.txcnt
[i
]);
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
866 #define B921600 (B460800 +1)
868 switch( info
->tty
->termios
->c_cflag
& (CBAUD
| CBAUDEX
) ){
869 #ifdef CONFIG_MOXA_SUPPORT_SPECIAL_BAUD_RATE
871 len
+= sprintf(page
+len
, " %d 1", info
->speed
);
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;
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 */
904 if ((info
->flags
& ASYNC_SPD_MASK
) == ASYNC_SPD_SHI
)
907 #ifdef ASYNC_SPD_WARP
908 if ((info
->flags
& ASYNC_SPD_MASK
) == ASYNC_SPD_WARP
)
912 len
+= sprintf(page
+len
, " %d 1", mxvar_baud_table
[j
]);
914 len
+= sprintf(page
+len
, " %d 1", info
->speed
);
916 } else { // not opened
917 #if 0 // mask by Victor Yu. 02-21-2006
918 len
+= sprintf(page
+len
, " 9600 2");
920 len
+= sprintf(page
+len
, " %d 2", info
->speed
);
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
929 switch ( info
->interface
) {
931 len
+= sprintf(page
+len
, " 2");
934 len
+= sprintf(page
+len
, " 3");
937 len
+= sprintf(page
+len
, " 1");
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
;
948 shiftbit
= (info
->port
%4) * 2;
949 opmode
= inb(info
->opmode_ioaddr
) >> shiftbit
;
951 opmode
&= OP_MODE_MASK
;
954 len
+= sprintf(page
+len
, " 2");
957 len
+= sprintf(page
+len
, " 3");
960 len
+= sprintf(page
+len
, " 1");
967 if ( info
->count
) { // has opened
968 switch ( info
->tty
->termios
->c_cflag
& CSIZE
) {
970 len
+= sprintf(page
+len
, " 5");
973 len
+= sprintf(page
+len
, " 6");
976 len
+= sprintf(page
+len
, " 7");
980 len
+= sprintf(page
+len
, " 8");
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");
992 len
+= sprintf(page
+len
, " 1");
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");
1004 len
+= sprintf(page
+len
, " 3");
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");
1018 len
+= sprintf(page
+len
, " 3");
1019 if ( j
& UART_MSR_DSR
)
1020 len
+= sprintf(page
+len
, " 2");
1022 len
+= sprintf(page
+len
, " 3");
1023 if ( j
& UART_MSR_DCD
)
1024 len
+= sprintf(page
+len
, " 2");
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");
1033 len
+= sprintf(page
+len
, " 3");
1034 if ( j
& UART_MCR_DTR
)
1035 len
+= sprintf(page
+len
, " 2");
1037 len
+= sprintf(page
+len
, " 3");
1040 len
+= sprintf(page
+len
, "\n");
1044 end_mxser_read_proc
:
1045 if ( len
<= (off
+ count
) )
1047 *start
= page
+ off
;
1059 * The MOXA Smartio/Industio serial driver boot-time initialization code!
1061 static int __init
mxser_init_module(void)
1066 printk("Loading module mxser ...\n");
1073 static void __exit
mxser_exit_module(void)
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
;
1091 if(mxsercfg
[i
].board_type
== -1)
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
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
;
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
++ ) {
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");
1132 printk(" max. baud rate up to 921600 bps.\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
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)");
1179 request_region(hwconf
->vector
,16,"mxser(vector)");
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
);
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
),
1198 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1199 local_irq_restore(flags
);
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
);
1207 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1208 local_irq_restore(flags
);
1210 restore_flags(flags
);
1211 #endif // LINUX_VERSION_CODE
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
)
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),
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);
1240 outb(0x06, hwconf
->ioaddr
[i
]+2);
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),
1253 hwconf
->vector
= ioaddress
;
1255 // following add by Victor Yu. 01-05-2004
1256 for (i
= 0; i
< hwconf
->ports
; i
++) {
1258 hwconf
->opmode_ioaddr
[i
] = ioaddress
+ 4;
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;
1278 #ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006
1279 static void ia240_hw_set(struct mxser_hwconf
*hwconf
)
1283 hwconf
->board_type
= UC7110_BOARD
;
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
;
1299 int mxser_init(void)
1303 #ifdef CONFIG_ARCH_IA241 // add by Victor Yu. 02-16-2006
1304 struct pci_dev
*pdev
=NULL
;
1305 int n
, index
, retval
, b
;
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
;
1348 printk("Tty devices major number = %d\n",ttymajor
);
1351 memset(mxvar_table
, 0, MXSER_PORTS
* sizeof(struct mxser_struct
));
1352 memset(&mxvar_log
, 0, sizeof(struct mxser_log
));
1355 #ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-15-2006
1356 ia240_hw_set(&hwconf
);
1357 if ( mxser_initbrd(m
,&hwconf
) < 0 )
1359 mxser_getcfg(m
,&hwconf
);
1363 n
= sizeof (mxser_pcibrds
)/sizeof (mxser_pciinfo
);
1367 pdev
= pci_find_device(mxser_pcibrds
[b
].vendor_id
,
1368 mxser_pcibrds
[b
].device_id
,
1370 if ( pdev
== NULL
) {
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
);
1382 if ( pci_enable_device(pdev
) ) {
1383 printk("Moxa SmartI/O PCI enable fail !\n");
1386 retval
= mxser_get_PCI_conf(mxser_pcibrds
[b
].board_type
,&hwconf
);
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");
1400 if(mxser_initbrd(m
,&hwconf
)<0)
1402 mxser_getcfg(m
,&hwconf
);
1409 for(i
=m
; i
<MXSER_BOARDS
; i
++){
1410 mxsercfg
[i
].board_type
= -1;
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
1422 printk("Couldn't install MOXA Smartio/Industio family driver !\n");
1426 for(i
=0; i
<MXSER_BOARDS
; i
++){
1427 if(mxsercfg
[i
].board_type
== -1)
1430 free_irq(mxsercfg
[i
].irq
, &mxvar_table
[i
*MXSER_PORTS_PER_BOARD
]);
1439 static void mxser_do_softint(void *private_
)
1441 struct mxser_struct
* info
= (struct mxser_struct
*)private_
;
1442 struct tty_struct
* 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
) ) {
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
;
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
);
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
);
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);
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
);
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
);
1513 restore_flags(flags
);
1514 #endif // LINUX_VERSION_CODE
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
;
1529 #if 1 // add by Victor Yu. 12-28-2004
1530 unsigned long flags
;
1534 if ( line
== MXSER_PORTS
)
1536 if ( (line
< 0) || (line
> MXSER_PORTS
) )
1539 info
= mxvar_table
+ line
;
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
);
1549 #endif // LINUX_VERSION_CODE
1551 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1552 local_irq_restore(flags
);
1554 restore_flags(flags
);
1555 #endif // LINUX_VERSION_CODE
1557 if ( !mxvar_tmp_buf
) {
1558 page
= get_zeroed_page(GFP_KERNEL
);
1561 if ( mxvar_tmp_buf
)
1564 mxvar_tmp_buf
= (unsigned char *)page
;
1568 * Start up serial port
1570 retval
= mxser_startup(info
);
1574 retval
= mxser_block_til_ready(tty
, filp
, info
);
1578 #if 0 // mask by Victor Yu. 12-28-2004
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
);
1586 #endif // LINUX_VERSION_CODE
1588 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1589 local_irq_restore(flags
);
1591 restore_flags(flags
);
1592 #endif // LINUX_VERSION_CODE
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
1604 clear_bit(TTY_DONT_FLIP
, &tty
->flags
);
1605 restore_flags(flags
);
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;
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
)
1633 if ( tty_hung_up_p(filp
) ) {
1634 //MOD_DEC_USE_COUNT;
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
);
1644 #endif // LINUX_VERSION_CODE
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
);
1658 if ( --info
->count
< 0 ) {
1659 printk("mxser_close: bad serial port count for ttyM%d: %d\n",
1660 info
->port
, info
->count
);
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
);
1667 restore_flags(flags
);
1668 #endif // LINUX_VERSION_CODE
1669 //MOD_DEC_USE_COUNT;
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
);
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.
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
) )
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
);
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
|
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
)
1742 static int mxser_write(struct tty_struct
* tty
, int from_user
, const unsigned char * buf
, int count
)
1743 #endif // LINUX_VERSION_CODE
1746 struct mxser_struct
*info
= (struct mxser_struct
*)tty
->driver_data
;
1747 unsigned long flags
;
1749 if ( !tty
|| !info
->xmit_buf
|| !mxvar_tmp_buf
)
1752 #if 0 // mask by Victor Yu. 10-13-2004
1754 down(&mxvar_tmp_buf_sem
);
1756 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1757 local_irq_save(flags
);
1761 #endif // LINUX_VERSION_CODE
1764 c
= MIN(count
, MIN(SERIAL_XMIT_SIZE
- info
->xmit_cnt
- 1,
1765 SERIAL_XMIT_SIZE
- info
->xmit_head
));
1769 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // add by Victor Yu. 02-16-2007
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
);
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);
1788 #if 0 // mask by Victor Yu. 10-13-2004
1790 up(&mxvar_tmp_buf_sem
);
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
);
1802 restore_flags(flags
);
1803 #endif // LINUX_VERSION_CODE
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
)
1815 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1816 local_irq_save(flags
);
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
);
1825 restore_flags(flags
);
1826 #endif // LINUX_VERSION_CODE
1830 info
->xmit_buf
[info
->xmit_head
++] = ch
;
1831 info
->xmit_head
&= SERIAL_XMIT_SIZE
- 1;
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
);
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
))
1855 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
1856 local_irq_save(flags
);
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
);
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
;
1875 ret
= SERIAL_XMIT_SIZE
- info
->xmit_cnt
- 1;
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
);
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
);
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.
1917 unsigned long flags
;
1918 struct mxser_struct
* info
= (struct mxser_struct
*)tty
->driver_data
;
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
) {
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));
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
)
1942 #ifdef CONFIG_ARCH_MOXART // add by Victor Yu. 02-16-2006
1943 shiftbit
= (p
+2) * 2;
1944 val
= inl(info
->opmode_ioaddr
);
1947 val
= inb(info
->opmode_ioaddr
);
1949 val
&= (~(3 << shiftbit
));
1950 val
|= (opmode
<< shiftbit
);
1951 #ifdef CONFIG_ARCH_MOXART
1952 outl(val
, info
->opmode_ioaddr
);
1954 outb(val
, info
->opmode_ioaddr
);
1957 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu.
1958 error
= verify_area(VERIFY_WRITE
, (void *)arg
, sizeof(int));
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
;
1967 opmode
= inb(info
->opmode_ioaddr
) >> shiftbit
;
1969 opmode
&= OP_MODE_MASK
;
1970 copy_to_user((int*)arg
, &opmode
, sizeof(int));
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
) {
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
) {
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
) {
1987 if ( cmd
== MOXA_SET_SPECIAL_BAUD_RATE
||
1988 cmd
== MOXA_SET_SPECIAL_BAUD_RATE
) {
1990 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu.
1991 error
= verify_area(VERIFY_READ
, (void *)arg
, sizeof(int));
1994 #endif // LINUX_VERSION_CODE
1995 get_from_user(speed
,(int *)arg
);
1996 if ( speed
<= 0 || speed
> info
->MaxCanSetBaudRate
)
1998 if ( !info
->tty
|| !info
->tty
->termios
|| !info
->base
)
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
;
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;
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);
2035 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu.
2036 error
= verify_area(VERIFY_WRITE
, (void *)arg
, sizeof(int));
2039 #endif // LINUX_VERSION_CODE
2040 copy_to_user((int*)arg
, &info
->speed
, sizeof(int));
2046 if ( (cmd
!= TIOCGSERIAL
) && (cmd
!= TIOCMIWAIT
) &&
2047 (cmd
!= TIOCGICOUNT
) ) {
2048 if ( tty
->flags
& (1 << TTY_IO_ERROR
) )
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
);
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
);
2063 #endif // LINUX_VERSION_CODE
2064 outb(inb(info
->base
+ UART_LCR
) | UART_LCR_SBC
, info
->base
+ UART_LCR
);
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
);
2070 restore_flags(flags
);
2071 #endif // LINUX_VERSION_CODE
2074 #if 1 // add by Victor Yu. 12-28-2004
2075 case TIOCSBRK
: // start to send break
2076 retval
= tty_check_change(tty
);
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
);
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
);
2090 restore_flags(flags
);
2091 #endif // LINUX_VERSION_CODE
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
);
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
);
2104 restore_flags(flags
);
2105 #endif // LINUX_VERSION_CODE
2108 case TCSBRK
: /* SVID version: non-zero arg --> no break */
2109 retval
= tty_check_change(tty
);
2112 tty_wait_until_sent(tty
, 0);
2114 mxser_send_break(info
, HZ
/4); /* 1/4 second */
2116 case TCSBRKP
: /* support for POSIX tcsendbreak() */
2117 retval
= tty_check_change(tty
);
2120 tty_wait_until_sent(tty
, 0);
2121 mxser_send_break(info
, arg
? arg
*(HZ
/10) : HZ
/4);
2124 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu.
2125 error
= verify_area(VERIFY_WRITE
, (void *)arg
, sizeof(long));
2128 #endif // LINUX_VERSION_CODE
2129 put_to_user(C_CLOCAL(tty
) ? 1 : 0, (unsigned long *)arg
);
2132 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12) // mask by Victor Yu.
2133 error
= verify_area(VERIFY_READ
, (void *)arg
, sizeof(long));
2136 #endif // LINUX_VERSION_CODE
2137 get_from_user(templ
,(unsigned long *)arg
);
2139 tty
->termios
->c_cflag
= ((tty
->termios
->c_cflag
& ~CLOCAL
) |
2140 (arg
? CLOCAL
: 0));
2142 #if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) // add by Victor Yu. 04-28-2006, for 2.6.x
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));
2149 #endif // LINUX_VERSION_CODE
2150 return(mxser_get_modem_info(info
, (unsigned int *)arg
));
2154 return(mxser_set_modem_info(info
, cmd
, (unsigned int *)arg
));
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
));
2162 #endif // LINUX_VERSION_CODE
2163 return(mxser_get_serial_info(info
, (struct serial_struct
*)arg
));
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
));
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));
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
2188 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2189 local_irq_save(flags
);
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
);
2198 restore_flags(flags
);
2199 #endif // LINUX_VERSION_CODE
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
);
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
);
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
)) ) {
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
)) ) {
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
2261 wake_up_interruptible(&info
->delta_msr_wait
);
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
));
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
);
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
);
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
))
2289 if (put_user(cnow
.brk
, &p_cuser
->brk
))
2291 if (put_user(cnow
.overrun
, &p_cuser
->overrun
))
2293 if (put_user(cnow
.buf_overrun
, &p_cuser
->buf_overrun
))
2295 if (put_user(cnow
.parity
, &p_cuser
->parity
))
2297 if (put_user(cnow
.rx
, &p_cuser
->rx
))
2299 if (put_user(cnow
.tx
, &p_cuser
->tx
))
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
);
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));
2315 #endif // LINUX_VERSION_CODE
2316 put_to_user(info
->baud_base
!= 115200 ? 1 : 0, (int *)arg
);
2319 return(-ENOIOCTLCMD
);
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
;
2329 int i
, result
, status
;
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);
2339 #endif // LINUX_VERSION_CODE
2340 copy_to_user((struct mxser_hwconf
*)arg
, mxsercfg
,
2341 sizeof(struct mxser_hwconf
)*4);
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));
2348 #endif // LINUX_VERSION_CODE
2349 copy_to_user((int*)arg
, &ttymajor
, sizeof(int));
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));
2357 #endif // LINUX_VERSION_CODE
2358 copy_to_user((int*)arg
, &calloutmajor
, sizeof(int));
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));
2366 #endif // LINUX_VERSION_CODE
2368 for ( i
=0; i
<MXSER_PORTS
; i
++ ) {
2369 if ( mxvar_table
[i
].base
)
2372 put_to_user(result
, (unsigned long *)arg
);
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
));
2380 #endif // LINUX_VERSION_CODE
2381 copy_to_user((struct mxser_log
*)arg
, &mxvar_log
, sizeof(mxvar_log
));
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
);
2389 #endif // LINUX_VERSION_CODE
2391 for(i
=0; i
<MXSER_PORTS
; i
++){
2393 if ( !mxvar_table
[i
].base
){
2394 GMStatus
[i
].dcd
= 0;
2395 GMStatus
[i
].dsr
= 0;
2396 GMStatus
[i
].cts
= 0;
2400 if ( !mxvar_table
[i
].tty
|| !mxvar_table
[i
].tty
->termios
)
2401 GMStatus
[i
].cflag
=mxvar_table
[i
].normal_termios
.c_cflag
;
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;
2409 GMStatus
[i
].dcd
= 0;
2411 if(status
& 0x20/*UART_MSR_DSR*/)
2412 GMStatus
[i
].dsr
= 1;
2414 GMStatus
[i
].dsr
= 0;
2417 if(status
& 0x10/*UART_MSR_CTS*/)
2418 GMStatus
[i
].cts
= 1;
2420 GMStatus
[i
].cts
= 0;
2422 copy_to_user((struct mxser_mstatus
*)arg
, GMStatus
,
2423 sizeof(struct mxser_mstatus
) * MXSER_PORTS
);
2426 return(-ENOIOCTLCMD
);
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
);
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
);
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
) ) {
2466 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2467 local_irq_save(flags
);
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
);
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
);
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
);
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
) ) {
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;
2522 /* Handle sw stopped */
2523 if ( (old_termios
->c_iflag
& IXON
) &&
2524 !(tty
->termios
->c_iflag
& IXON
) ) {
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
);
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
);
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
);
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
);
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
;
2591 if (info
->type
== PORT_UNKNOWN
)
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
2605 char_time
= (info
->timeout
- HZ
/50) / info
->xmit_fifo_size
;
2606 char_time
= char_time
/ 5;
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
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
);
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
);
2631 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,3,0))
2632 set_current_state(TASK_INTERRUPTIBLE
);
2634 current
->state
= TASK_INTERRUPTIBLE
;
2636 schedule_timeout(char_time
);
2637 if (signal_pending(current
))
2639 if (timeout
&& time_after(jiffies
, orig_jiffies
))
2642 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,3,0))
2643 set_current_state(TASK_RUNNING
);
2645 current
->state
= TASK_RUNNING
;
2648 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
2649 printk("lsr = %d (jiff=%lu)...done\n", lsr
, jiffies
);
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
;
2665 mxser_flush_buffer(tty
);
2666 mxser_shutdown(info
);
2667 #if 0 // mask by Victor Yu. 12-28-2004
2670 info
->flags
&= ~(ASYNC_NORMAL_ACTIVE
|ASYNC_CALLOUT_ACTIVE
);
2673 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2674 local_irq_save(flags
);
2678 #endif // LINUX_VERSION_CODE
2682 info
->flags
&= ~(ASYNC_NORMAL_ACTIVE
|ASYNC_CALLOUT_ACTIVE
);
2684 info
->flags
&= ~(ASYNC_NORMAL_ACTIVE
);
2687 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
2688 local_irq_restore(flags
);
2690 restore_flags(flags
);
2691 #endif // LINUX_VERSION_CODE
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
)
2702 static irqreturn_t
mxser_interrupt(int irq
, void *dev_id
, struct pt_regs
* regs
)
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
]) ) {
2717 if ( port
== NULL
) {
2720 max
= mxser_numports
[mxsercfg
[i
].board_type
-1];
2723 irqbits
= inb(port
->vector
) & port
->vectormask
;
2724 if ( irqbits
== port
->vectormask
)
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 ) {
2729 for ( i
=0, bits
=4; i
<max
; i
++, irqbits
|= bits
, bits
<<= 1 ) {
2731 if ( irqbits
== port
->vectormask
)
2733 if ( bits
& irqbits
)
2737 // following add by Victor Yu. 09-13-2002
2738 iir
= inb(info
->base
+UART_IIR
);
2739 if ( iir
& UART_IIR_NO_INT
)
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
);
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
);
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
);
2773 mxser_transmit_chars(info
);
2775 if ( pass_counter
++ > MXSER_ISR_PASS_LIMIT
) {
2776 break; /* Prevent infinite loops */
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
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
,
2789 struct tty_struct
* tty
= info
->tty
;
2790 unsigned char ch
, gdl
;
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
) )
2801 gdl
= inb(info
->base
+MOXA_MUST_GDL_REGISTER
);
2803 // following add by Victor Yu. 10-13-2004
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
);
2815 cnt
= gdl
= MIN(gdl
, tty
->receive_room
);
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
2824 ch
= inb(info
->base
+ UART_RX
);
2825 #ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004
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);
2833 *tty
->flip
.char_buf_ptr
++ = ch
;
2834 *tty
->flip
.flag_buf_ptr
++ = 0;
2835 #endif // LINUX_VERSION_CODE
2836 #endif // BYPASS_FLIP
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
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
2858 if ( *status
& UART_LSR_BI
) {
2862 if ( *status
& UART_LSR_PE
) {
2863 info
->icount
.parity
++;
2866 if ( *status
& UART_LSR_FE
) {
2867 info
->icount
.frame
++;
2870 if ( *status
& UART_LSR_OE
) {
2871 info
->icount
.overrun
++;
2875 wake_up_interruptible(&info
->delta_msr_wait
);
2879 *status
&= info
->read_status_mask
;
2880 // above add by Victor Yu. 09-02-2002
2882 if ( !(*status
& info
->ignore_status_mask
) ) {
2884 #ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004
2885 if ( cnt
>= TTY_FLIPBUF_SIZE
)
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
)
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
2899 #if 0 // mask by Victor Yu. 02-08-2007
2900 *tty
->flip
.flag_buf_ptr
++ = TTY_BREAK
;
2906 if ( info
->flags
& ASYNC_SAK
)
2908 } else if ( *status
& UART_LSR_PE
) {
2909 #ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004
2912 #if 0 // mask by Victor Yu. 02-08-2007
2913 *tty
->flip
.flag_buf_ptr
++ = TTY_PARITY
;
2918 } else if ( *status
& UART_LSR_FE
) {
2919 #ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004
2922 #if 0 // mask by Victor Yu. 02-08-2007
2923 *tty
->flip
.flag_buf_ptr
++ = TTY_FRAME
;
2928 } else if ( *status
& UART_LSR_OE
) {
2929 #ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004
2930 *fp
++ = TTY_OVERRUN
;
2932 #if 0 // mask by Victor Yu. 02-08-2007
2933 *tty
->flip
.flag_buf_ptr
++ = TTY_OVERRUN
;
2939 #ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004
2942 #if 0 // mask by Victor Yu. 02-08-2007
2943 *tty
->flip
.flag_buf_ptr
++ = 0;
2950 #ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004
2953 #if 0 // mask by Victor Yu. 02-08-2007
2954 *tty
->flip
.flag_buf_ptr
++ = 0;
2958 #endif // BYPASS_FLIP
2960 #ifdef BYPASS_FLIP // add by Victor Yu. 09-17-2004
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
);
2966 *tty
->flip
.char_buf_ptr
++ = ch
;
2968 #endif // BYPASS_FLIP
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
;
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
);
2984 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0))
2985 tty_flip_buffer_push(tty
);
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
)
2996 if ( info
->x_char
) {
2997 outb(info
->x_char
, info
->base
+ UART_TX
);
2999 mxvar_log
.txcnt
[info
->port
]++;
3000 /* added by casper 1/11/2000 */
3001 #if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0))
3008 if ( info
->xmit_buf
== 0 )
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
);
3018 #if 0 // mask by Victor Yu. 10-12-2004
3019 cnt
= info
->xmit_cnt
;
3020 count
= info
->xmit_fifo_size
;
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 )
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
;
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
;
3054 if ( info
->xmit_cnt
< WAKEUP_CHARS
) {
3055 set_bit(MXSER_EVENT_TXLOW
,&info
->event
);
3058 if (schedule_task(&info
->tqueue
) == 0)
3060 queue_task(&info
->tqueue
,&tq_scheduler
);
3062 schedule_work(&info
->tqueue
);
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
,
3074 /* update input line counters */
3075 if ( status
& UART_MSR_TERI
)
3077 if ( status
& UART_MSR_DDSR
)
3079 if ( status
& UART_MSR_DDCD
)
3081 if ( status
& UART_MSR_DCTS
)
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
);
3089 else if ( !((info
->flags
& ASYNC_CALLOUT_ACTIVE
) &&
3090 (info
->flags
& ASYNC_CALLOUT_NOHUP
)) )
3094 set_bit(MXSER_EVENT_HANGUP
,&info
->event
);
3097 if (schedule_task(&info
->tqueue
) == 0)
3100 schedule_work(&info
->tqueue
);
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
);
3115 if (schedule_task(&info
->tqueue
) == 0)
3118 schedule_work(&info
->tqueue
);
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
);
3139 struct wait_queue wait
= { current
, NULL
};
3141 unsigned long flags
;
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
)
3156 return(-ERESTARTSYS
);
3163 * If this is a callout device, then just make sure the normal
3164 * device isn't being used.
3167 if ( tty
->driver
->subtype
== SERIAL_TYPE_CALLOUT
) {
3168 if ( info
->flags
& ASYNC_NORMAL_ACTIVE
)
3170 if ( (info
->flags
& ASYNC_CALLOUT_ACTIVE
) &&
3171 (info
->flags
& ASYNC_SESSION_LOCKOUT
) &&
3172 (info
->session
!= current
->session
) )
3174 if ( (info
->flags
& ASYNC_CALLOUT_ACTIVE
) &&
3175 (info
->flags
& ASYNC_PGRP_LOCKOUT
) &&
3176 (info
->pgrp
!= current
->pgrp
) )
3178 info
->flags
|= ASYNC_CALLOUT_ACTIVE
;
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
)) ) {
3190 if ( info
->flags
& ASYNC_CALLOUT_ACTIVE
)
3193 info
->flags
|= ASYNC_NORMAL_ACTIVE
;
3198 if ( info
->flags
& ASYNC_CALLOUT_ACTIVE
) {
3199 if ( info
->normal_termios
.c_cflag
& CLOCAL
)
3203 if ( tty
->termios
->c_cflag
& CLOCAL
)
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.
3217 add_wait_queue(&info
->open_wait
, &wait
);
3218 #if 0 // mask by Victor Yu. 12-28-2004
3221 if ( !tty_hung_up_p(filp
) )
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
);
3231 #endif // LINUX_VERSION_CODE
3233 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3234 local_irq_restore(flags
);
3236 restore_flags(flags
);
3237 #endif // LINUX_VERSION_CODE
3240 info
->blocked_open
++;
3242 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3243 local_irq_save(flags
);
3247 #endif // LINUX_VERSION_CODE
3249 if ( !(info
->flags
& ASYNC_CALLOUT_ACTIVE
) )
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
);
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
)
3264 retval
= -ERESTARTSYS
;
3271 if ( !(info
->flags
& ASYNC_CALLOUT_ACTIVE
) &&
3272 !(info
->flags
& ASYNC_CLOSING
) &&
3273 (do_clocal
|| (inb(info
->base
+ UART_MSR
) & UART_MSR_DCD
)) )
3275 if ( !(info
->flags
& ASYNC_CLOSING
) &&
3276 (do_clocal
|| (inb(info
->base
+ UART_MSR
) & UART_MSR_DCD
)) )
3279 if ( signal_pending(current
) ) {
3280 retval
= -ERESTARTSYS
;
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
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
);
3296 #endif // LINUX_VERSION_CODE
3298 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3299 local_irq_restore(flags
);
3301 restore_flags(flags
);
3302 #endif // LINUX_VERSION_CODE
3305 info
->blocked_open
--;
3308 info
->flags
|= ASYNC_NORMAL_ACTIVE
;
3312 static int mxser_startup(struct mxser_struct
* info
)
3314 unsigned long flags
;
3317 page
= get_zeroed_page(GFP_KERNEL
);
3321 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3322 local_irq_save(flags
);
3326 #endif // LINUX_VERSION_CODE
3328 if ( info
->flags
& ASYNC_INITIALIZED
) {
3330 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3331 local_irq_restore(flags
);
3333 restore_flags(flags
);
3334 #endif // LINUX_VERSION_CODE
3338 if ( !info
->base
|| !info
->type
) {
3340 set_bit(TTY_IO_ERROR
, &info
->tty
->flags
);
3342 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3343 local_irq_restore(flags
);
3345 restore_flags(flags
);
3346 #endif // LINUX_VERSION_CODE
3349 if ( info
->xmit_buf
)
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
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
);
3375 restore_flags(flags
);
3376 #endif // LINUX_VERSION_CODE
3377 #if (LINUX_VERSION_CODE < VERSION_CODE(2,1,0))
3380 if (capable(CAP_SYS_ADMIN
)) {
3383 set_bit(TTY_IO_ERROR
, &info
->tty
->flags
);
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))
3420 clear_bit(TTY_IO_ERROR
, &info
->tty
->flags
);
3423 test_and_clear_bit(TTY_IO_ERROR
, &info
->tty
->flags
);
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
);
3434 restore_flags(flags
);
3435 #endif // LINUX_VERSION_CODE
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
);
3445 #endif // LINUX_VERSION_CODE
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
);
3451 restore_flags(flags
);
3452 #endif // LINUX_VERSION_CODE
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
) )
3467 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3468 local_irq_save(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
);
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
);
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
);
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
)
3521 unsigned cflag
, cval
, fcr
;
3524 unsigned long flags
;
3526 if ( !info
->tty
|| !info
->tty
->termios
)
3528 cflag
= info
->tty
->termios
->c_cflag
;
3529 if ( !(info
->base
) )
3533 #define B921600 (B460800 +1)
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;
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;
3544 case B921600
: bindex
= 20; break;
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
)
3579 #ifdef ASYNC_SPD_WARP
3580 if ((info
->flags
& ASYNC_SPD_MASK
) == ASYNC_SPD_WARP
)
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
)
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
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
)
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
];
3606 if (!quot
&& old_termios
) {
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;
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
)
3645 #ifdef ASYNC_SPD_WARP
3646 if ((info
->flags
& ASYNC_SPD_MASK
) == ASYNC_SPD_WARP
)
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
)
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
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
)
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
];
3683 info
->timeout
= ((info
->xmit_fifo_size
*HZ
*10*quot
) / info
->baud_base
);
3684 info
->timeout
+= HZ
/50; /* Add .02 seconds of slop */
3687 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3688 local_irq_save(flags
);
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
);
3698 restore_flags(flags
);
3699 #endif // LINUX_VERSION_CODE
3701 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
3702 local_irq_save(flags
);
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
);
3712 restore_flags(flags
);
3713 #endif // LINUX_VERSION_CODE
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
)
3726 if ( cflag
& PARENB
)
3727 cval
|= UART_LCR_PARITY
;
3729 #define CMSPAR 010000000000
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
) ) {
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
);
3749 #endif // LINUX_VERSION_CODE
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
);
3756 restore_flags(flags
);
3757 #endif // LINUX_VERSION_CODE
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
);
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
;
3778 if ( (quot
% info
->speed
) > (info
->speed
/ 2) ) {
3779 quot
/= info
->speed
;
3782 quot
/= info
->speed
;
3784 SET_MOXA_MUST_ENUM_VALUE(info
->base
, quot
);
3786 SET_MOXA_MUST_ENUM_VALUE(info
->base
, 0);
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
;
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
;
3802 unsigned char status
;
3803 #if 0 // mask by Victor Yu. 12-30-2004
3807 status
= inb(info
->base
+ UART_MSR
);
3808 #if 0 // mask by Victor Yu. 12-30-2004
3809 restore_flags(flags
);
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
);
3821 if (schedule_task(&info
->tqueue
) == 0)
3824 schedule_work(&info
->tqueue
);
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
);
3838 info
->flags
&= ~ASYNC_CTS_FLOW
;
3840 #if 0 // add by Victor Yu. 12-27-2004
3844 outb(info
->MCR
, info
->base
+ UART_MCR
);
3845 if ( cflag
& CLOCAL
){
3846 info
->flags
&= ~ASYNC_CHECK_CD
;
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
);
3856 restore_flags(flags
);
3857 #endif // LINUX_VERSION_CODE
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;
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
;
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
);
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
;
3903 ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info
->base
);
3905 #if 1 // add by Victor Yu. 01-04-2005
3906 info
->IER
&= ~MOXA_MUST_IER_XINT
;
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
);
3913 if ( I_IXOFF(info
->tty
) ) {
3914 ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info
->base
);
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
);
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
);
3928 restore_flags(flags
);
3929 #endif // LINUX_VERSION_CODE
3930 // above add by Victor Yu. 09-02-2002
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
;
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
;
3958 copy_to_user(retinfo
, &tmp
, sizeof(*retinfo
));
3962 static int mxser_set_serial_info(struct mxser_struct
* info
,
3963 struct serial_struct
* new_info
)
3965 struct serial_struct new_serial
;
3969 if ( !new_info
|| !info
->base
)
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
) )
3979 flags
= info
->flags
& ASYNC_SPD_MASK
;
3981 #if (LINUX_VERSION_CODE < VERSION_CODE(2,1,0))
3984 if ( !capable(CAP_SYS_ADMIN
)) {
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
)) )
3991 info
->flags
= ((info
->flags
& ~ASYNC_USR_MASK
) |
3992 (new_serial
.flags
& ASYNC_USR_MASK
));
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;
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);
4016 retval
= mxser_startup(info
);
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
);
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
);
4047 restore_flags(flags
);
4048 #endif // LINUX_VERSION_CODE
4049 result
= ((status
& UART_LSR_TEMT
) ? TIOCSER_TEMT
: 0);
4050 put_to_user(result
, value
);
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
;
4066 #if 0 // mask by Victor Yu. 12-27-2004
4067 current
->state
= TASK_INTERRUPTIBLE
;
4069 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
4070 local_irq_save(flags
);
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
);
4082 restore_flags(flags
);
4083 #endif // LINUX_VERSION_CODE
4084 timeout
= jiffies
+ (unsigned long)duration
;
4086 current
->state
= TASK_INTERRUPTIBLE
;
4087 schedule_timeout(5);
4088 if ( time_after(jiffies
, timeout
) )
4091 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
4092 local_irq_save(flags
);
4096 #endif // LINUX_VERSION_CODE
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
);
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
);
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
);
4126 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) // add by Victor Yu. 02-09-2007
4127 local_irq_restore(flags
);
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
);
4141 static int mxser_set_modem_info(struct mxser_struct
* info
, unsigned int cmd
,
4142 unsigned int *value
)
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));
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
);
4160 #endif // LINUX_VERSION_CODE
4164 if ( arg
& TIOCM_RTS
)
4165 info
->MCR
|= UART_MCR_RTS
;
4166 if ( arg
& TIOCM_DTR
)
4167 info
->MCR
|= UART_MCR_DTR
;
4170 if ( arg
& TIOCM_RTS
)
4171 info
->MCR
&= ~UART_MCR_RTS
;
4172 if ( arg
& TIOCM_DTR
)
4173 info
->MCR
&= ~UART_MCR_DTR
;
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));
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
);
4185 restore_flags(flags
);
4186 #endif // LINUX_VERSION_CODE
4190 #if 0 // mask by Victor Yu. 12-30-2004
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
);
4198 restore_flags(flags
);
4199 #endif // LINUX_VERSION_CODE