1938 lines · 48.7 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0+/* *          mxser.c  -- MOXA Smartio/Industio family multiport serial driver. * *      Copyright (C) 1999-2006  Moxa Technologies (support@moxa.com). *	Copyright (C) 2006-2008  Jiri Slaby <jirislaby@gmail.com> * *      This code is loosely based on the 1.8 moxa driver which is based on *	Linux serial driver, written by Linus Torvalds, Theodore T'so and *	others. * *	Fed through a cleanup, indent and remove of non 2.6 code by Alan Cox *	<alan@lxorguk.ukuu.org.uk>. The original 1.8 code is available on *	www.moxa.com. *	- Fixed x86_64 cleanness */ #include <linux/module.h>#include <linux/errno.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/interrupt.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/serial.h>#include <linux/serial_reg.h>#include <linux/major.h>#include <linux/string.h>#include <linux/fcntl.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/mm.h>#include <linux/delay.h>#include <linux/pci.h>#include <linux/bitops.h>#include <linux/slab.h>#include <linux/ratelimit.h> #include <asm/io.h>#include <asm/irq.h>#include <linux/uaccess.h> /* *	Semi-public control interfaces */ /* *	MOXA ioctls */ #define MOXA			0x400#define MOXA_SET_OP_MODE	(MOXA + 66)#define MOXA_GET_OP_MODE	(MOXA + 67) #define RS232_MODE		0#define RS485_2WIRE_MODE	1#define RS422_MODE		2#define RS485_4WIRE_MODE	3#define OP_MODE_MASK		3 /* --------------------------------------------------- */ /* * Follow just what Moxa Must chip defines. * * When LCR register (offset 0x03) is written the following value, the Must chip * will enter enhanced mode. And a write to EFR (offset 0x02) bit 6,7 will * change bank. */#define MOXA_MUST_ENTER_ENHANCED	0xBF /* when enhanced mode is enabled, access to general bank register */#define MOXA_MUST_GDL_REGISTER		0x07#define MOXA_MUST_GDL_MASK		0x7F#define MOXA_MUST_GDL_HAS_BAD_DATA	0x80 #define MOXA_MUST_LSR_RERR		0x80	/* error in receive FIFO *//* enhanced register bank select and enhanced mode setting register *//* This works only when LCR register equals to 0xBF */#define MOXA_MUST_EFR_REGISTER		0x02#define MOXA_MUST_EFR_EFRB_ENABLE	0x10 /* enhanced mode enable *//* enhanced register bank set 0, 1, 2 */#define MOXA_MUST_EFR_BANK0		0x00#define MOXA_MUST_EFR_BANK1		0x40#define MOXA_MUST_EFR_BANK2		0x80#define MOXA_MUST_EFR_BANK3		0xC0#define MOXA_MUST_EFR_BANK_MASK		0xC0 /* set XON1 value register, when LCR=0xBF and change to bank0 */#define MOXA_MUST_XON1_REGISTER		0x04 /* set XON2 value register, when LCR=0xBF and change to bank0 */#define MOXA_MUST_XON2_REGISTER		0x05 /* set XOFF1 value register, when LCR=0xBF and change to bank0 */#define MOXA_MUST_XOFF1_REGISTER	0x06 /* set XOFF2 value register, when LCR=0xBF and change to bank0 */#define MOXA_MUST_XOFF2_REGISTER	0x07 #define MOXA_MUST_RBRTL_REGISTER	0x04#define MOXA_MUST_RBRTH_REGISTER	0x05#define MOXA_MUST_RBRTI_REGISTER	0x06#define MOXA_MUST_THRTL_REGISTER	0x07#define MOXA_MUST_ENUM_REGISTER		0x04#define MOXA_MUST_HWID_REGISTER		0x05#define MOXA_MUST_ECR_REGISTER		0x06#define MOXA_MUST_CSR_REGISTER		0x07 #define MOXA_MUST_FCR_GDA_MODE_ENABLE	0x20 /* good data mode enable */#define MOXA_MUST_FCR_GDA_ONLY_ENABLE	0x10 /* only good data put into RxFIFO */ #define MOXA_MUST_IER_ECTSI		0x80 /* enable CTS interrupt */#define MOXA_MUST_IER_ERTSI		0x40 /* enable RTS interrupt */#define MOXA_MUST_IER_XINT		0x20 /* enable Xon/Xoff interrupt */#define MOXA_MUST_IER_EGDAI		0x10 /* enable GDA interrupt */ #define MOXA_MUST_RECV_ISR		(UART_IER_RDI | MOXA_MUST_IER_EGDAI) /* GDA interrupt pending */#define MOXA_MUST_IIR_GDA		0x1C#define MOXA_MUST_IIR_RDA		0x04#define MOXA_MUST_IIR_RTO		0x0C#define MOXA_MUST_IIR_LSR		0x06 /* received Xon/Xoff or specical interrupt pending */#define MOXA_MUST_IIR_XSC		0x10 /* RTS/CTS change state interrupt pending */#define MOXA_MUST_IIR_RTSCTS		0x20#define MOXA_MUST_IIR_MASK		0x3E #define MOXA_MUST_MCR_XON_FLAG		0x40#define MOXA_MUST_MCR_XON_ANY		0x80#define MOXA_MUST_MCR_TX_XON		0x08 #define MOXA_MUST_EFR_SF_MASK		0x0F /* software flow control on chip mask value */#define MOXA_MUST_EFR_SF_TX1		0x08 /* send Xon1/Xoff1 */#define MOXA_MUST_EFR_SF_TX2		0x04 /* send Xon2/Xoff2 */#define MOXA_MUST_EFR_SF_TX12		0x0C /* send Xon1,Xon2/Xoff1,Xoff2 */#define MOXA_MUST_EFR_SF_TX_NO		0x00 /* don't send Xon/Xoff */#define MOXA_MUST_EFR_SF_TX_MASK	0x0C /* Tx software flow control mask */#define MOXA_MUST_EFR_SF_RX_NO		0x00 /* don't receive Xon/Xoff */#define MOXA_MUST_EFR_SF_RX1		0x02 /* receive Xon1/Xoff1 */#define MOXA_MUST_EFR_SF_RX2		0x01 /* receive Xon2/Xoff2 */#define MOXA_MUST_EFR_SF_RX12		0x03 /* receive Xon1,Xon2/Xoff1,Xoff2 */#define MOXA_MUST_EFR_SF_RX_MASK	0x03 /* Rx software flow control mask */ #define	MXSERMAJOR	 174 #define MXSER_BOARDS		4	/* Max. boards */#define MXSER_PORTS_PER_BOARD	8	/* Max. ports per board */#define MXSER_PORTS		(MXSER_BOARDS * MXSER_PORTS_PER_BOARD)#define MXSER_ISR_PASS_LIMIT	100 #define WAKEUP_CHARS		256 #define MXSER_BAUD_BASE		921600#define MXSER_CUSTOM_DIVISOR	(MXSER_BAUD_BASE * 16) #define PCI_DEVICE_ID_MOXA_RC7000	0x0001#define PCI_DEVICE_ID_MOXA_CP102	0x1020#define PCI_DEVICE_ID_MOXA_CP102UL	0x1021#define PCI_DEVICE_ID_MOXA_CP102U	0x1022#define PCI_DEVICE_ID_MOXA_CP102UF	0x1023#define PCI_DEVICE_ID_MOXA_C104		0x1040#define PCI_DEVICE_ID_MOXA_CP104U	0x1041#define PCI_DEVICE_ID_MOXA_CP104JU	0x1042#define PCI_DEVICE_ID_MOXA_CP104EL	0x1043#define PCI_DEVICE_ID_MOXA_POS104UL	0x1044#define PCI_DEVICE_ID_MOXA_CB108	0x1080#define PCI_DEVICE_ID_MOXA_CP112UL	0x1120#define PCI_DEVICE_ID_MOXA_CT114	0x1140#define PCI_DEVICE_ID_MOXA_CP114	0x1141#define PCI_DEVICE_ID_MOXA_CB114	0x1142#define PCI_DEVICE_ID_MOXA_CP114UL	0x1143#define PCI_DEVICE_ID_MOXA_CP118U	0x1180#define PCI_DEVICE_ID_MOXA_CP118EL	0x1181#define PCI_DEVICE_ID_MOXA_CP132	0x1320#define PCI_DEVICE_ID_MOXA_CP132U	0x1321#define PCI_DEVICE_ID_MOXA_CP134U	0x1340#define PCI_DEVICE_ID_MOXA_CB134I	0x1341#define PCI_DEVICE_ID_MOXA_CP138U	0x1380#define PCI_DEVICE_ID_MOXA_C168		0x1680#define PCI_DEVICE_ID_MOXA_CP168U	0x1681#define PCI_DEVICE_ID_MOXA_CP168EL	0x1682 #define MXSER_NPORTS(ddata)		((ddata) & 0xffU)#define MXSER_HIGHBAUD			0x0100 enum mxser_must_hwid {	MOXA_OTHER_UART		= 0x00,	MOXA_MUST_MU150_HWID	= 0x01,	MOXA_MUST_MU860_HWID	= 0x02,}; static const struct {	u8 type;	u8 fifo_size;	u8 rx_high_water;	u8 rx_low_water;	speed_t max_baud;} Gpci_uart_info[] = {	{ MOXA_OTHER_UART,	 16, 14,  1, 921600 },	{ MOXA_MUST_MU150_HWID,	 64, 48, 16, 230400 },	{ MOXA_MUST_MU860_HWID, 128, 96, 32, 921600 }};#define UART_INFO_NUM	ARRAY_SIZE(Gpci_uart_info)  /* driver_data correspond to the lines in the structure above   see also ISA probe function before you change something */static const struct pci_device_id mxser_pcibrds[] = {	{ PCI_DEVICE_DATA(MOXA, C168,		8) },	{ PCI_DEVICE_DATA(MOXA, C104,		4) },	{ PCI_DEVICE_DATA(MOXA, CP132,		2) },	{ PCI_DEVICE_DATA(MOXA, CP114,		4) },	{ PCI_DEVICE_DATA(MOXA, CT114,		4) },	{ PCI_DEVICE_DATA(MOXA, CP102,		2 | MXSER_HIGHBAUD) },	{ PCI_DEVICE_DATA(MOXA, CP104U,		4) },	{ PCI_DEVICE_DATA(MOXA, CP168U,		8) },	{ PCI_DEVICE_DATA(MOXA, CP132U,		2) },	{ PCI_DEVICE_DATA(MOXA, CP134U,		4) },	{ PCI_DEVICE_DATA(MOXA, CP104JU,	4) },	{ PCI_DEVICE_DATA(MOXA, RC7000,		8) }, /* RC7000 */	{ PCI_DEVICE_DATA(MOXA, CP118U,		8) },	{ PCI_DEVICE_DATA(MOXA, CP102UL,	2) },	{ PCI_DEVICE_DATA(MOXA, CP102U,		2) },	{ PCI_DEVICE_DATA(MOXA, CP118EL,	8) },	{ PCI_DEVICE_DATA(MOXA, CP168EL,	8) },	{ PCI_DEVICE_DATA(MOXA, CP104EL,	4) },	{ PCI_DEVICE_DATA(MOXA, CB108,		8) },	{ PCI_DEVICE_DATA(MOXA, CB114,		4) },	{ PCI_DEVICE_DATA(MOXA, CB134I,		4) },	{ PCI_DEVICE_DATA(MOXA, CP138U,		8) },	{ PCI_DEVICE_DATA(MOXA, POS104UL,	4) },	{ PCI_DEVICE_DATA(MOXA, CP114UL,	4) },	{ PCI_DEVICE_DATA(MOXA, CP102UF,	2) },	{ PCI_DEVICE_DATA(MOXA, CP112UL,	2) },	{ }};MODULE_DEVICE_TABLE(pci, mxser_pcibrds); static int ttymajor = MXSERMAJOR; /* Variables for insmod */ MODULE_AUTHOR("Casper Yang");MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver");module_param(ttymajor, int, 0);MODULE_LICENSE("GPL"); struct mxser_board; struct mxser_port {	struct tty_port port;	struct mxser_board *board; 	unsigned long ioaddr;	unsigned long opmode_ioaddr; 	u8 rx_high_water;	u8 rx_low_water;	int type;		/* UART type */ 	unsigned char x_char;	/* xon/xoff character */	u8 IER;			/* Interrupt Enable Register */	u8 MCR;			/* Modem control register */	u8 FCR;			/* FIFO control register */ 	struct async_icount icount; /* kernel counters for 4 input interrupts */	unsigned int timeout; 	u8 read_status_mask;	u8 ignore_status_mask;	u8 xmit_fifo_size; 	spinlock_t slock;}; struct mxser_board {	unsigned int idx;	unsigned short nports;	int irq;	unsigned long vector; 	enum mxser_must_hwid must_hwid;	speed_t max_baud; 	struct mxser_port ports[];}; static DECLARE_BITMAP(mxser_boards, MXSER_BOARDS);static struct tty_driver *mxvar_sdriver; static u8 __mxser_must_set_EFR(unsigned long baseio, u8 clear, u8 set,		bool restore_LCR){	u8 oldlcr, efr; 	oldlcr = inb(baseio + UART_LCR);	outb(MOXA_MUST_ENTER_ENHANCED, baseio + UART_LCR); 	efr = inb(baseio + MOXA_MUST_EFR_REGISTER);	efr &= ~clear;	efr |= set; 	outb(efr, baseio + MOXA_MUST_EFR_REGISTER); 	if (restore_LCR)		outb(oldlcr, baseio + UART_LCR); 	return oldlcr;} static u8 mxser_must_select_bank(unsigned long baseio, u8 bank){	return __mxser_must_set_EFR(baseio, MOXA_MUST_EFR_BANK_MASK, bank,			false);} static void mxser_set_must_xon1_value(unsigned long baseio, u8 value){	u8 oldlcr = mxser_must_select_bank(baseio, MOXA_MUST_EFR_BANK0);	outb(value, baseio + MOXA_MUST_XON1_REGISTER);	outb(oldlcr, baseio + UART_LCR);} static void mxser_set_must_xoff1_value(unsigned long baseio, u8 value){	u8 oldlcr = mxser_must_select_bank(baseio, MOXA_MUST_EFR_BANK0);	outb(value, baseio + MOXA_MUST_XOFF1_REGISTER);	outb(oldlcr, baseio + UART_LCR);} static void mxser_set_must_fifo_value(struct mxser_port *info){	u8 oldlcr = mxser_must_select_bank(info->ioaddr, MOXA_MUST_EFR_BANK1);	outb(info->rx_high_water, info->ioaddr + MOXA_MUST_RBRTH_REGISTER);	outb(info->rx_high_water, info->ioaddr + MOXA_MUST_RBRTI_REGISTER);	outb(info->rx_low_water, info->ioaddr + MOXA_MUST_RBRTL_REGISTER);	outb(oldlcr, info->ioaddr + UART_LCR);} static void mxser_set_must_enum_value(unsigned long baseio, u8 value){	u8 oldlcr = mxser_must_select_bank(baseio, MOXA_MUST_EFR_BANK2);	outb(value, baseio + MOXA_MUST_ENUM_REGISTER);	outb(oldlcr, baseio + UART_LCR);} static u8 mxser_get_must_hardware_id(unsigned long baseio){	u8 oldlcr = mxser_must_select_bank(baseio, MOXA_MUST_EFR_BANK2);	u8 id = inb(baseio + MOXA_MUST_HWID_REGISTER);	outb(oldlcr, baseio + UART_LCR); 	return id;} static void mxser_must_set_EFR(unsigned long baseio, u8 clear, u8 set){	__mxser_must_set_EFR(baseio, clear, set, true);} static void mxser_must_set_enhance_mode(unsigned long baseio, bool enable){	mxser_must_set_EFR(baseio,			enable ? 0 : MOXA_MUST_EFR_EFRB_ENABLE,			enable ? MOXA_MUST_EFR_EFRB_ENABLE : 0);} static void mxser_must_no_sw_flow_control(unsigned long baseio){	mxser_must_set_EFR(baseio, MOXA_MUST_EFR_SF_MASK, 0);} static void mxser_must_set_tx_sw_flow_control(unsigned long baseio, bool enable){	mxser_must_set_EFR(baseio, MOXA_MUST_EFR_SF_TX_MASK,			enable ? MOXA_MUST_EFR_SF_TX1 : 0);} static void mxser_must_set_rx_sw_flow_control(unsigned long baseio, bool enable){	mxser_must_set_EFR(baseio, MOXA_MUST_EFR_SF_RX_MASK,			enable ? MOXA_MUST_EFR_SF_RX1 : 0);} static enum mxser_must_hwid mxser_must_get_hwid(unsigned long io){	u8 oldmcr, hwid;	int i; 	outb(0, io + UART_LCR);	mxser_must_set_enhance_mode(io, false);	oldmcr = inb(io + UART_MCR);	outb(0, io + UART_MCR);	mxser_set_must_xon1_value(io, 0x11);	if (inb(io + UART_MCR) != 0) {		outb(oldmcr, io + UART_MCR);		return MOXA_OTHER_UART;	} 	hwid = mxser_get_must_hardware_id(io);	for (i = 1; i < UART_INFO_NUM; i++) /* 0 = OTHER_UART */		if (hwid == Gpci_uart_info[i].type)			return hwid; 	return MOXA_OTHER_UART;} static bool mxser_16550A_or_MUST(struct mxser_port *info){	return info->type == PORT_16550A || info->board->must_hwid;} static void mxser_process_txrx_fifo(struct mxser_port *info){	unsigned int i; 	if (info->type == PORT_16450 || info->type == PORT_8250) {		info->rx_high_water = 1;		info->rx_low_water = 1;		info->xmit_fifo_size = 1;		return;	} 	for (i = 0; i < UART_INFO_NUM; i++)		if (info->board->must_hwid == Gpci_uart_info[i].type) {			info->rx_low_water = Gpci_uart_info[i].rx_low_water;			info->rx_high_water = Gpci_uart_info[i].rx_high_water;			info->xmit_fifo_size = Gpci_uart_info[i].fifo_size;			break;		}} static void __mxser_start_tx(struct mxser_port *info){	outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);	info->IER |= UART_IER_THRI;	outb(info->IER, info->ioaddr + UART_IER);} static void mxser_start_tx(struct mxser_port *info){	unsigned long flags; 	spin_lock_irqsave(&info->slock, flags);	__mxser_start_tx(info);	spin_unlock_irqrestore(&info->slock, flags);} static void __mxser_stop_tx(struct mxser_port *info){	info->IER &= ~UART_IER_THRI;	outb(info->IER, info->ioaddr + UART_IER);} static int mxser_carrier_raised(struct tty_port *port){	struct mxser_port *mp = container_of(port, struct mxser_port, port);	return (inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD)?1:0;} static void mxser_dtr_rts(struct tty_port *port, int on){	struct mxser_port *mp = container_of(port, struct mxser_port, port);	unsigned long flags;	u8 mcr; 	spin_lock_irqsave(&mp->slock, flags);	mcr = inb(mp->ioaddr + UART_MCR);	if (on)		mcr |= UART_MCR_DTR | UART_MCR_RTS;	else		mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);	outb(mcr, mp->ioaddr + UART_MCR);	spin_unlock_irqrestore(&mp->slock, flags);} static int mxser_set_baud(struct tty_struct *tty, speed_t newspd){	struct mxser_port *info = tty->driver_data;	unsigned int quot = 0, baud;	unsigned char cval;	u64 timeout; 	if (newspd > info->board->max_baud)		return -1; 	if (newspd == 134) {		quot = 2 * MXSER_BAUD_BASE / 269;		tty_encode_baud_rate(tty, 134, 134);	} else if (newspd) {		quot = MXSER_BAUD_BASE / newspd;		if (quot == 0)			quot = 1;		baud = MXSER_BAUD_BASE / quot;

Lines 1–500 of 1938.