diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-07-06 00:08:24 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-07-06 00:08:24 +0300 |
commit | c932ed0adb09a7fa6d6649ee04dd78c83ab07ada (patch) | |
tree | 02b055bd7b350e7aca9104a9c69330896bb6382b /drivers/tty | |
parent | a16d8644bad461bb073b92e812080ea6715ddf2b (diff) | |
parent | 15279ebe99d7c6142d9f1a6ae4ded66c0f168678 (diff) | |
download | linux-c932ed0adb09a7fa6d6649ee04dd78c83ab07ada.tar.xz |
Merge tag 'tty-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty / serial updates from Greg KH:
"Here is the big set of tty and serial driver patches for 5.14-rc1.
A bit more than normal, but nothing major, lots of cleanups.
Highlights are:
- lots of tty api cleanups and mxser driver cleanups from Jiri
- build warning fixes
- various serial driver updates
- coding style cleanups
- various tty driver minor fixes and updates
- removal of broken and disable r3964 line discipline (finally!)
All of these have been in linux-next for a while with no reported
issues"
* tag 'tty-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (227 commits)
serial: mvebu-uart: remove unused member nb from struct mvebu_uart
arm64: dts: marvell: armada-37xx: Fix reg for standard variant of UART
dt-bindings: mvebu-uart: fix documentation
serial: mvebu-uart: correctly calculate minimal possible baudrate
serial: mvebu-uart: do not allow changing baudrate when uartclk is not available
serial: mvebu-uart: fix calculation of clock divisor
tty: make linux/tty_flip.h self-contained
serial: Prefer unsigned int to bare use of unsigned
serial: 8250: 8250_omap: Fix possible interrupt storm on K3 SoCs
serial: qcom_geni_serial: use DT aliases according to DT bindings
Revert "tty: serial: Add UART driver for Cortina-Access platform"
tty: serial: Add UART driver for Cortina-Access platform
MAINTAINERS: add me back as mxser maintainer
mxser: Documentation, fix typos
mxser: Documentation, make the docs up-to-date
mxser: Documentation, remove traces of callout device
mxser: introduce mxser_16550A_or_MUST helper
mxser: rename flags to old_speed in mxser_set_serial_info
mxser: use port variable in mxser_set_serial_info
mxser: access info->MCR under info->slock
...
Diffstat (limited to 'drivers/tty')
79 files changed, 1643 insertions, 3896 deletions
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index f6a7fd6d3bb6..476c11278235 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -204,7 +204,7 @@ config MOXA_INTELLIO config MOXA_SMARTIO tristate "Moxa SmartIO support v. 2.0" - depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA) + depends on SERIAL_NONSTANDARD && PCI help Say Y here if you have a Moxa SmartIO multiport serial card and/or want to help develop a new version of this driver. diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index c7054f5117c3..a2bd75fbaaa4 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_AUDIT) += tty_audit.o obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o obj-$(CONFIG_N_HDLC) += n_hdlc.o obj-$(CONFIG_N_GSM) += n_gsm.o -obj-$(CONFIG_R3964) += n_r3964.o obj-y += vt/ obj-$(CONFIG_HVC_DRIVER) += hvc/ diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index ca48ce5a0862..5ec19c48fb7a 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -148,7 +148,7 @@ static __inline__ void rtsdtr_ctrl(int bits) * ------------------------------------------------------------ * rs_stop() and rs_start() * - * This routines are called before setting or resetting tty->stopped. + * This routines are called before setting or resetting tty->flow.stopped. * They enable or disable transmitter interrupts, as necessary. * ------------------------------------------------------------ */ @@ -309,7 +309,7 @@ static void transmit_chars(struct serial_state *info) return; } if (info->xmit.head == info->xmit.tail - || info->tport.tty->stopped + || info->tport.tty->flow.stopped || info->tport.tty->hw_stopped) { info->IER &= ~UART_IER_THRI; custom.intena = IF_TBE; @@ -768,7 +768,7 @@ static void rs_flush_chars(struct tty_struct *tty) unsigned long flags; if (info->xmit.head == info->xmit.tail - || tty->stopped + || tty->flow.stopped || tty->hw_stopped || !info->xmit.buf) return; @@ -812,7 +812,7 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count local_irq_restore(flags); if (info->xmit.head != info->xmit.tail - && !tty->stopped + && !tty->flow.stopped && !tty->hw_stopped && !(info->IER & UART_IER_THRI)) { info->IER |= UART_IER_THRI; @@ -827,14 +827,14 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count return ret; } -static int rs_write_room(struct tty_struct *tty) +static unsigned int rs_write_room(struct tty_struct *tty) { struct serial_state *info = tty->driver_data; return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); } -static int rs_chars_in_buffer(struct tty_struct *tty) +static unsigned int rs_chars_in_buffer(struct tty_struct *tty) { struct serial_state *info = tty->driver_data; diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c index 3c6dd06ec5fb..445e5ff9b36d 100644 --- a/drivers/tty/ehv_bytechan.c +++ b/drivers/tty/ehv_bytechan.c @@ -536,11 +536,11 @@ static void ehv_bc_tty_close(struct tty_struct *ttys, struct file *filp) * how much write room the driver can guarantee will be sent OR BUFFERED. This * driver MUST honor the return value. */ -static int ehv_bc_tty_write_room(struct tty_struct *ttys) +static unsigned int ehv_bc_tty_write_room(struct tty_struct *ttys) { struct ehv_bc_data *bc = ttys->driver_data; unsigned long flags; - int count; + unsigned int count; spin_lock_irqsave(&bc->lock, flags); count = CIRC_SPACE(bc->head, bc->tail, BUF_SIZE); diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index cd23a4b05c8f..ccb683a6e6f5 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -193,12 +193,12 @@ static int goldfish_tty_write(struct tty_struct *tty, const unsigned char *buf, return count; } -static int goldfish_tty_write_room(struct tty_struct *tty) +static unsigned int goldfish_tty_write_room(struct tty_struct *tty) { return 0x10000; } -static int goldfish_tty_chars_in_buffer(struct tty_struct *tty) +static unsigned int goldfish_tty_chars_in_buffer(struct tty_struct *tty) { struct goldfish_tty *qtty = &goldfish_ttys[tty->index]; void __iomem *base = qtty->base; diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index cdcc64ea2554..5bb8c4e44961 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -292,7 +292,7 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops) if (vtermnos[index] != -1) return -1; - /* make sure no no tty has been registered in this index */ + /* make sure no tty has been registered in this index */ hp = hvc_get_by_index(index); if (hp) { tty_port_put(&hp->port); @@ -586,7 +586,7 @@ static void hvc_set_winsz(struct work_struct *work) * how much write room the driver can guarantee will be sent OR BUFFERED. This * driver MUST honor the return value. */ -static int hvc_write_room(struct tty_struct *tty) +static unsigned int hvc_write_room(struct tty_struct *tty) { struct hvc_struct *hp = tty->driver_data; @@ -596,7 +596,7 @@ static int hvc_write_room(struct tty_struct *tty) return hp->outbuf_size - hp->n_outbuf; } -static int hvc_chars_in_buffer(struct tty_struct *tty) +static unsigned int hvc_chars_in_buffer(struct tty_struct *tty) { struct hvc_struct *hp = tty->driver_data; @@ -620,7 +620,7 @@ static u32 timeout = MIN_TIMEOUT; /* * Maximum number of bytes to get from the console driver if hvc_poll is * called from driver (and can't sleep). Any more than this and we break - * and start polling with khvcd. This value was derived from from an OpenBMC + * and start polling with khvcd. This value was derived from an OpenBMC * console with the OPAL driver that results in about 0.25ms interrupts off * latency. */ diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c index 297fa7b38b65..82a76cac94de 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c @@ -438,8 +438,6 @@ static void hvc_iucv_sndbuf_work(struct work_struct *work) struct hvc_iucv_private *priv; priv = container_of(work, struct hvc_iucv_private, sndbuf_work.work); - if (!priv) - return; spin_lock_bh(&priv->lock); hvc_iucv_send(priv); diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 197988c55e0c..fe5e6b4f43de 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -1376,7 +1376,7 @@ static int hvcs_write(struct tty_struct *tty, * absolutely WILL BUFFER if we can't send it. This driver MUST honor the * return value, hence the reason for hvcs_struct buffering. */ -static int hvcs_write_room(struct tty_struct *tty) +static unsigned int hvcs_write_room(struct tty_struct *tty) { struct hvcs_struct *hvcsd = tty->driver_data; @@ -1386,7 +1386,7 @@ static int hvcs_write_room(struct tty_struct *tty) return HVCS_BUFF_LEN - hvcsd->chars_in_buffer; } -static int hvcs_chars_in_buffer(struct tty_struct *tty) +static unsigned int hvcs_chars_in_buffer(struct tty_struct *tty) { struct hvcs_struct *hvcsd = tty->driver_data; diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index e8c58f9bd263..bfc15279d5bc 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -890,14 +890,14 @@ out: spin_unlock_irqrestore(&hp->lock, flags); } -static int hvsi_write_room(struct tty_struct *tty) +static unsigned int hvsi_write_room(struct tty_struct *tty) { struct hvsi_struct *hp = tty->driver_data; return N_OUTBUF - hp->n_outbuf; } -static int hvsi_chars_in_buffer(struct tty_struct *tty) +static unsigned int hvsi_chars_in_buffer(struct tty_struct *tty) { struct hvsi_struct *hp = tty->driver_data; @@ -929,7 +929,7 @@ static int hvsi_write(struct tty_struct *tty, * will see there is no room in outbuf and return. */ while ((count > 0) && (hvsi_write_room(tty) > 0)) { - int chunksize = min(count, hvsi_write_room(tty)); + int chunksize = min_t(int, count, hvsi_write_room(tty)); BUG_ON(hp->n_outbuf < 0); memcpy(hp->outbuf + hp->n_outbuf, source, chunksize); diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index 99bb2f149ff5..e3a5a5ba752c 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -54,7 +54,6 @@ struct ipw_tty { unsigned int control_lines; struct mutex ipw_tty_mutex; int tx_bytes_queued; - int closing; }; static struct ipw_tty *ttys[IPWIRELESS_PCMCIA_MINORS]; @@ -228,7 +227,7 @@ static int ipw_write(struct tty_struct *linux_tty, return count; } -static int ipw_write_room(struct tty_struct *linux_tty) +static unsigned int ipw_write_room(struct tty_struct *linux_tty) { struct ipw_tty *tty = linux_tty->driver_data; int room; @@ -270,7 +269,7 @@ static int ipwireless_set_serial_info(struct tty_struct *linux_tty, return 0; /* Keeps the PCMCIA scripts happy. */ } -static int ipw_chars_in_buffer(struct tty_struct *linux_tty) +static unsigned int ipw_chars_in_buffer(struct tty_struct *linux_tty) { struct ipw_tty *tty = linux_tty->driver_data; @@ -525,7 +524,6 @@ void ipwireless_tty_free(struct ipw_tty *tty) printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": deregistering %s device ttyIPWp%d\n", tty_type_name(ttyj->tty_type), j); - ttyj->closing = 1; if (ttyj->port.tty != NULL) { mutex_unlock(&ttyj->ipw_tty_mutex); tty_vhangup(ttyj->port.tty); diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c index a8e19b4833bf..3b5915b94fac 100644 --- a/drivers/tty/mips_ejtag_fdc.c +++ b/drivers/tty/mips_ejtag_fdc.c @@ -840,11 +840,11 @@ static int mips_ejtag_fdc_tty_write(struct tty_struct *tty, return total; } -static int mips_ejtag_fdc_tty_write_room(struct tty_struct *tty) +static unsigned int mips_ejtag_fdc_tty_write_room(struct tty_struct *tty) { struct mips_ejtag_fdc_tty_port *dport = tty->driver_data; struct mips_ejtag_fdc_tty *priv = dport->driver; - int room; + unsigned int room; /* Report the space in the xmit buffer */ spin_lock(&dport->xmit_lock); @@ -854,10 +854,10 @@ static int mips_ejtag_fdc_tty_write_room(struct tty_struct *tty) return room; } -static int mips_ejtag_fdc_tty_chars_in_buffer(struct tty_struct *tty) +static unsigned int mips_ejtag_fdc_tty_chars_in_buffer(struct tty_struct *tty) { struct mips_ejtag_fdc_tty_port *dport = tty->driver_data; - int chars; + unsigned int chars; /* Report the number of bytes in the xmit buffer */ spin_lock(&dport->xmit_lock); diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index 4d4f15b5cd29..64b18177c790 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -188,9 +188,9 @@ module_param(ttymajor, int, 0); static int moxa_open(struct tty_struct *, struct file *); static void moxa_close(struct tty_struct *, struct file *); static int moxa_write(struct tty_struct *, const unsigned char *, int); -static int moxa_write_room(struct tty_struct *); +static unsigned int moxa_write_room(struct tty_struct *); static void moxa_flush_buffer(struct tty_struct *); -static int moxa_chars_in_buffer(struct tty_struct *); +static unsigned int moxa_chars_in_buffer(struct tty_struct *); static void moxa_set_termios(struct tty_struct *, struct ktermios *); static void moxa_stop(struct tty_struct *); static void moxa_start(struct tty_struct *); @@ -216,9 +216,9 @@ static int MoxaPortLineStatus(struct moxa_port *); static void MoxaPortFlushData(struct moxa_port *, int); static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int); static int MoxaPortReadData(struct moxa_port *); -static int MoxaPortTxQueue(struct moxa_port *); +static unsigned int MoxaPortTxQueue(struct moxa_port *); static int MoxaPortRxQueue(struct moxa_port *); -static int MoxaPortTxFree(struct moxa_port *); +static unsigned int MoxaPortTxFree(struct moxa_port *); static void MoxaPortTxDisable(struct moxa_port *); static void MoxaPortTxEnable(struct moxa_port *); static int moxa_get_serial_info(struct tty_struct *, struct serial_struct *); @@ -1217,11 +1217,11 @@ static int moxa_write(struct tty_struct *tty, return len; } -static int moxa_write_room(struct tty_struct *tty) +static unsigned int moxa_write_room(struct tty_struct *tty) { struct moxa_port *ch; - if (tty->stopped) + if (tty->flow.stopped) return 0; ch = tty->driver_data; if (ch == NULL) @@ -1239,10 +1239,10 @@ static void moxa_flush_buffer(struct tty_struct *tty) tty_wakeup(tty); } -static int moxa_chars_in_buffer(struct tty_struct *tty) +static unsigned int moxa_chars_in_buffer(struct tty_struct *tty) { struct moxa_port *ch = tty->driver_data; - int chars; + unsigned int chars; chars = MoxaPortTxQueue(ch); if (chars) @@ -1374,7 +1374,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle, clear_bit(EMPTYWAIT, &p->statusflags); tty_wakeup(tty); } - if (test_bit(LOWWAIT, &p->statusflags) && !tty->stopped && + if (test_bit(LOWWAIT, &p->statusflags) && !tty->flow.stopped && MoxaPortTxQueue(p) <= WAKEUP_CHARS) { clear_bit(LOWWAIT, &p->statusflags); tty_wakeup(tty); @@ -1981,7 +1981,7 @@ static int MoxaPortReadData(struct moxa_port *port) } -static int MoxaPortTxQueue(struct moxa_port *port) +static unsigned int MoxaPortTxQueue(struct moxa_port *port) { void __iomem *ofsAddr = port->tableAddr; u16 rptr, wptr, mask; @@ -1992,7 +1992,7 @@ static int MoxaPortTxQueue(struct moxa_port *port) return (wptr - rptr) & mask; } -static int MoxaPortTxFree(struct moxa_port *port) +static unsigned int MoxaPortTxFree(struct moxa_port *port) { void __iomem *ofsAddr = port->tableAddr; u16 rptr, wptr, mask; diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 16a852ecbe8a..900ccb2ca166 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -41,9 +41,112 @@ #include <asm/irq.h> #include <linux/uaccess.h> -#include "mxser.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 MXSER_VERSION "2.0.5" /* 1.14 */ #define MXSERMAJOR 174 #define MXSER_BOARDS 4 /* Max. boards */ @@ -51,15 +154,10 @@ #define MXSER_PORTS (MXSER_BOARDS * MXSER_PORTS_PER_BOARD) #define MXSER_ISR_PASS_LIMIT 100 -/*CheckIsMoxaMust return value*/ -#define MOXA_OTHER_UART 0x00 -#define MOXA_MUST_MU150_HWID 0x01 -#define MOXA_MUST_MU860_HWID 0x02 - #define WAKEUP_CHARS 256 -#define UART_MCR_AFE 0x20 -#define UART_LSR_SPECIAL 0x1E +#define MXSER_BAUD_BASE 921600 +#define MXSER_CUSTOM_DIVISOR (MXSER_BAUD_BASE * 16) #define PCI_DEVICE_ID_POS104UL 0x1044 #define PCI_DEVICE_ID_CB108 0x1080 @@ -70,151 +168,71 @@ #define PCI_DEVICE_ID_CB134I 0x1341 #define PCI_DEVICE_ID_CP138U 0x1380 +#define MXSER_NPORTS(ddata) ((ddata) & 0xffU) +#define MXSER_HIGHBAUD 0x0100 -#define C168_ASIC_ID 1 -#define C104_ASIC_ID 2 -#define C102_ASIC_ID 0xB -#define CI132_ASIC_ID 4 -#define CI134_ASIC_ID 3 -#define CI104J_ASIC_ID 5 - -#define MXSER_HIGHBAUD 1 -#define MXSER_HAS2 2 +enum mxser_must_hwid { + MOXA_OTHER_UART = 0x00, + MOXA_MUST_MU150_HWID = 0x01, + MOXA_MUST_MU860_HWID = 0x02, +}; -/* This is only for PCI */ static const struct { - int type; - int tx_fifo; - int rx_fifo; - int xmit_fifo_size; - int rx_high_water; - int rx_trigger; - int rx_low_water; - long max_baud; + u8 type; + u8 fifo_size; + u8 rx_high_water; + u8 rx_low_water; + speed_t max_baud; } Gpci_uart_info[] = { - {MOXA_OTHER_UART, 16, 16, 16, 14, 14, 1, 921600L}, - {MOXA_MUST_MU150_HWID, 64, 64, 64, 48, 48, 16, 230400L}, - {MOXA_MUST_MU860_HWID, 128, 128, 128, 96, 96, 32, 921600L} + { 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) -struct mxser_cardinfo { - char *name; - unsigned int nports; - unsigned int flags; -}; - -static const struct mxser_cardinfo mxser_cards[] = { -/* 0*/ { "C168 series", 8, }, - { "C104 series", 4, }, - { "CI-104J series", 4, }, - { "C168H/PCI series", 8, }, - { "C104H/PCI series", 4, }, -/* 5*/ { "C102 series", 4, MXSER_HAS2 }, /* C102-ISA */ - { "CI-132 series", 4, MXSER_HAS2 }, - { "CI-134 series", 4, }, - { "CP-132 series", 2, }, - { "CP-114 series", 4, }, -/*10*/ { "CT-114 series", 4, }, - { "CP-102 series", 2, MXSER_HIGHBAUD }, - { "CP-104U series", 4, }, - { "CP-168U series", 8, }, - { "CP-132U series", 2, }, -/*15*/ { "CP-134U series", 4, }, - { "CP-104JU series", 4, }, - { "Moxa UC7000 Serial", 8, }, /* RC7000 */ - { "CP-118U series", 8, }, - { "CP-102UL series", 2, }, -/*20*/ { "CP-102U series", 2, }, - { "CP-118EL series", 8, }, - { "CP-168EL series", 8, }, - { "CP-104EL series", 4, }, - { "CB-108 series", 8, }, -/*25*/ { "CB-114 series", 4, }, - { "CB-134I series", 4, }, - { "CP-138U series", 8, }, - { "POS-104UL series", 4, }, - { "CP-114UL series", 4, }, -/*30*/ { "CP-102UF series", 2, }, - { "CP-112UL series", 2, }, -}; /* 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_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168), .driver_data = 3 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168), .driver_data = 8 }, { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C104), .driver_data = 4 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132), .driver_data = 8 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114), .driver_data = 9 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CT114), .driver_data = 10 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102), .driver_data = 11 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104U), .driver_data = 12 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168U), .driver_data = 13 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132U), .driver_data = 14 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134U), .driver_data = 15 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104JU),.driver_data = 16 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_RC7000), .driver_data = 17 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118U), .driver_data = 18 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102UL),.driver_data = 19 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102U), .driver_data = 20 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL),.driver_data = 21 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL),.driver_data = 22 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL),.driver_data = 23 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB108), .driver_data = 24 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB114), .driver_data = 25 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB134I), .driver_data = 26 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP138U), .driver_data = 27 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_POS104UL), .driver_data = 28 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP114UL), .driver_data = 29 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP102UF), .driver_data = 30 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP112UL), .driver_data = 31 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132), .driver_data = 2 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114), .driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CT114), .driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102), .driver_data = 2 | MXSER_HIGHBAUD }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104U), .driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168U), .driver_data = 8 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132U), .driver_data = 2 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134U), .driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104JU),.driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_RC7000), .driver_data = 8 }, /* RC7000 */ + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118U), .driver_data = 8 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102UL),.driver_data = 2 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102U), .driver_data = 2 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL),.driver_data = 8 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL),.driver_data = 8 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL),.driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB108), .driver_data = 8 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB114), .driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB134I), .driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP138U), .driver_data = 8 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_POS104UL), .driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP114UL), .driver_data = 4 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP102UF), .driver_data = 2 }, + { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP112UL), .driver_data = 2 }, { } }; MODULE_DEVICE_TABLE(pci, mxser_pcibrds); -static unsigned long ioaddr[MXSER_BOARDS]; static int ttymajor = MXSERMAJOR; /* Variables for insmod */ MODULE_AUTHOR("Casper Yang"); MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver"); -module_param_hw_array(ioaddr, ulong, ioport, NULL, 0); -MODULE_PARM_DESC(ioaddr, "ISA io addresses to look for a moxa board"); module_param(ttymajor, int, 0); MODULE_LICENSE("GPL"); -struct mxser_log { - int tick; - unsigned long rxcnt[MXSER_PORTS]; - unsigned long txcnt[MXSER_PORTS]; -}; - -struct mxser_mon { - unsigned long rxcnt; - unsigned long txcnt; - unsigned long up_rxcnt; - unsigned long up_txcnt; - int modem_status; - unsigned char hold_reason; -}; - -struct mxser_mon_ext { - unsigned long rx_cnt[32]; - unsigned long tx_cnt[32]; - unsigned long up_rxcnt[32]; - unsigned long up_txcnt[32]; - int modem_status[32]; - - long baudrate[32]; - int databits[32]; - int stopbits[32]; - int parity[32]; - int flowctrl[32]; - int fifo[32]; - int iftype[32]; -}; - struct mxser_board; struct mxser_port { @@ -223,274 +241,147 @@ struct mxser_port { unsigned long ioaddr; unsigned long opmode_ioaddr; - int max_baud; - int rx_high_water; - int rx_trigger; /* Rx fifo trigger level */ - int rx_low_water; - int baud_base; /* max. speed */ + u8 rx_high_water; + u8 rx_low_water; int type; /* UART type */ - int x_char; /* xon/xoff character */ - int IER; /* Interrupt Enable Register */ - int MCR; /* Modem control register */ + unsigned char x_char; /* xon/xoff character */ + u8 IER; /* Interrupt Enable Register */ + u8 MCR; /* Modem control register */ - unsigned char stop_rx; unsigned char ldisc_stop_rx; - int custom_divisor; - unsigned char err_shadow; - struct async_icount icount; /* kernel counters for 4 input interrupts */ unsigned int timeout; - int read_status_mask; - int ignore_status_mask; - unsigned int xmit_fifo_size; - int xmit_head; - int xmit_tail; - int xmit_cnt; + u8 read_status_mask; + u8 ignore_status_mask; + u8 xmit_fifo_size; + unsigned int xmit_head; + unsigned int xmit_tail; + unsigned int xmit_cnt; int closing; - struct ktermios normal_termios; - - struct mxser_mon mon_data; - spinlock_t slock; }; struct mxser_board { unsigned int idx; + unsigned short nports; int irq; - const struct mxser_cardinfo *info; unsigned long vector; - unsigned long vector_mask; - - int chip_flag; - int uart_type; - struct mxser_port ports[MXSER_PORTS_PER_BOARD]; -}; + enum mxser_must_hwid must_hwid; + speed_t max_baud; -struct mxser_mstatus { - tcflag_t cflag; - int cts; - int dsr; - int ri; - int dcd; + struct mxser_port ports[]; }; -static struct mxser_board mxser_boards[MXSER_BOARDS]; +static DECLARE_BITMAP(mxser_boards, MXSER_BOARDS); static struct tty_driver *mxvar_sdriver; -static struct mxser_log mxvar_log; -static int mxser_set_baud_method[MXSER_PORTS + 1]; -static void mxser_enable_must_enchance_mode(unsigned long baseio) +static u8 __mxser_must_set_EFR(unsigned long baseio, u8 clear, u8 set, + bool restore_LCR) { - u8 oldlcr; - u8 efr; + u8 oldlcr, efr; oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); + outb(MOXA_MUST_ENTER_ENHANCED, baseio + UART_LCR); efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr |= MOXA_MUST_EFR_EFRB_ENABLE; + efr &= ~clear; + efr |= set; outb(efr, baseio + MOXA_MUST_EFR_REGISTER); - outb(oldlcr, baseio + UART_LCR); -} -#ifdef CONFIG_PCI -static void mxser_disable_must_enchance_mode(unsigned long baseio) -{ - u8 oldlcr; - u8 efr; + if (restore_LCR) + outb(oldlcr, baseio + UART_LCR); - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_EFRB_ENABLE; + return oldlcr; +} - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); - outb(oldlcr, baseio + UART_LCR); +static u8 mxser_must_select_bank(unsigned long baseio, u8 bank) +{ + return __mxser_must_set_EFR(baseio, MOXA_MUST_EFR_BANK_MASK, bank, + false); } -#endif static void mxser_set_must_xon1_value(unsigned long baseio, u8 value) { - u8 oldlcr; - u8 efr; - - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_BANK_MASK; - efr |= MOXA_MUST_EFR_BANK0; - - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); + 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; - u8 efr; - - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_BANK_MASK; - efr |= MOXA_MUST_EFR_BANK0; - - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); + 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; - u8 efr; - - oldlcr = inb(info->ioaddr + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, info->ioaddr + UART_LCR); - - efr = inb(info->ioaddr + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_BANK_MASK; - efr |= MOXA_MUST_EFR_BANK1; - - outb(efr, info->ioaddr + MOXA_MUST_EFR_REGISTER); - outb((u8)info->rx_high_water, info->ioaddr + MOXA_MUST_RBRTH_REGISTER); - outb((u8)info->rx_trigger, info->ioaddr + MOXA_MUST_RBRTI_REGISTER); - outb((u8)info->rx_low_water, info->ioaddr + MOXA_MUST_RBRTL_REGISTER); + 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; - u8 efr; - - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_BANK_MASK; - efr |= MOXA_MUST_EFR_BANK2; - - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); + u8 oldlcr = mxser_must_select_bank(baseio, MOXA_MUST_EFR_BANK2); outb(value, baseio + MOXA_MUST_ENUM_REGISTER); outb(oldlcr, baseio + UART_LCR); } -#ifdef CONFIG_PCI -static void mxser_get_must_hardware_id(unsigned long baseio, u8 *pId) +static u8 mxser_get_must_hardware_id(unsigned long baseio) { - u8 oldlcr; - u8 efr; - - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_BANK_MASK; - efr |= MOXA_MUST_EFR_BANK2; - - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); - *pId = inb(baseio + MOXA_MUST_HWID_REGISTER); + 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; } -#endif -static void SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(unsigned long baseio) +static void mxser_must_set_EFR(unsigned long baseio, u8 clear, u8 set) { - u8 oldlcr; - u8 efr; - - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_SF_MASK; - - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); - outb(oldlcr, baseio + UART_LCR); + __mxser_must_set_EFR(baseio, clear, set, true); } -static void mxser_enable_must_tx_software_flow_control(unsigned long baseio) +static void mxser_must_set_enhance_mode(unsigned long baseio, bool enable) { - u8 oldlcr; - u8 efr; - - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_SF_TX_MASK; - efr |= MOXA_MUST_EFR_SF_TX1; - - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); - outb(oldlcr, baseio + UART_LCR); + mxser_must_set_EFR(baseio, + enable ? 0 : MOXA_MUST_EFR_EFRB_ENABLE, + enable ? MOXA_MUST_EFR_EFRB_ENABLE : 0); } -static void mxser_disable_must_tx_software_flow_control(unsigned long baseio) +static void mxser_must_no_sw_flow_control(unsigned long baseio) { - u8 oldlcr; - u8 efr; - - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_SF_TX_MASK; - - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); - outb(oldlcr, baseio + UART_LCR); + mxser_must_set_EFR(baseio, MOXA_MUST_EFR_SF_MASK, 0); } -static void mxser_enable_must_rx_software_flow_control(unsigned long baseio) +static void mxser_must_set_tx_sw_flow_control(unsigned long baseio, bool enable) { - u8 oldlcr; - u8 efr; - - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_SF_RX_MASK; - efr |= MOXA_MUST_EFR_SF_RX1; - - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); - outb(oldlcr, baseio + UART_LCR); + mxser_must_set_EFR(baseio, MOXA_MUST_EFR_SF_TX_MASK, + enable ? MOXA_MUST_EFR_SF_TX1 : 0); } -static void mxser_disable_must_rx_software_flow_control(unsigned long baseio) +static void mxser_must_set_rx_sw_flow_control(unsigned long baseio, bool enable) { - u8 oldlcr; - u8 efr; - - oldlcr = inb(baseio + UART_LCR); - outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); - - efr = inb(baseio + MOXA_MUST_EFR_REGISTER); - efr &= ~MOXA_MUST_EFR_SF_RX_MASK; - - outb(efr, baseio + MOXA_MUST_EFR_REGISTER); - outb(oldlcr, baseio + UART_LCR); + mxser_must_set_EFR(baseio, MOXA_MUST_EFR_SF_RX_MASK, + enable ? MOXA_MUST_EFR_SF_RX1 : 0); } -#ifdef CONFIG_PCI -static int CheckIsMoxaMust(unsigned long io) +static enum mxser_must_hwid mxser_must_get_hwid(unsigned long io) { u8 oldmcr, hwid; int i; outb(0, io + UART_LCR); - mxser_disable_must_enchance_mode(io); + mxser_must_set_enhance_mode(io, false); oldmcr = inb(io + UART_MCR); outb(0, io + UART_MCR); mxser_set_must_xon1_value(io, 0x11); @@ -499,49 +390,59 @@ static int CheckIsMoxaMust(unsigned long io) return MOXA_OTHER_UART; } - mxser_get_must_hardware_id(io, &hwid); - for (i = 1; i < UART_INFO_NUM; i++) { /* 0 = 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 (int)hwid; - } + return hwid; + return MOXA_OTHER_UART; } -#endif -static void process_txrx_fifo(struct mxser_port *info) +static bool mxser_16550A_or_MUST(struct mxser_port *info) { - int i; + return info->type == PORT_16550A || info->board->must_hwid; +} - if ((info->type == PORT_16450) || (info->type == PORT_8250)) { - info->rx_trigger = 1; +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; - } else - for (i = 0; i < UART_INFO_NUM; i++) - if (info->board->chip_flag == Gpci_uart_info[i].type) { - info->rx_trigger = Gpci_uart_info[i].rx_trigger; - 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].xmit_fifo_size; - break; - } + 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 unsigned char mxser_get_msr(int baseaddr, int mode, int port) +static void __mxser_start_tx(struct mxser_port *info) { - static unsigned char mxser_msr[MXSER_PORTS + 1]; - unsigned char status = 0; + outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER); + info->IER |= UART_IER_THRI; + outb(info->IER, info->ioaddr + UART_IER); +} - status = inb(baseaddr + UART_MSR); +static void mxser_start_tx(struct mxser_port *info) +{ + unsigned long flags; - mxser_msr[port] &= 0x0F; - mxser_msr[port] |= status; - status = mxser_msr[port]; - if (mode) - mxser_msr[port] = 0; + spin_lock_irqsave(&info->slock, flags); + __mxser_start_tx(info); + spin_unlock_irqrestore(&info->slock, flags); +} - return status; +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) @@ -554,38 +455,36 @@ 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) - outb(inb(mp->ioaddr + UART_MCR) | - UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR); + mcr |= UART_MCR_DTR | UART_MCR_RTS; else - outb(inb(mp->ioaddr + UART_MCR)&~(UART_MCR_DTR | UART_MCR_RTS), - mp->ioaddr + UART_MCR); + 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, long newspd) +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 (!info->ioaddr) - return -1; - - if (newspd > info->max_baud) + if (newspd > info->board->max_baud) return -1; if (newspd == 134) { - quot = 2 * info->baud_base / 269; + quot = 2 * MXSER_BAUD_BASE / 269; tty_encode_baud_rate(tty, 134, 134); } else if (newspd) { - quot = info->baud_base / newspd; + quot = MXSER_BAUD_BASE / newspd; if (quot == 0) quot = 1; - baud = info->baud_base/quot; + baud = MXSER_BAUD_BASE / quot; tty_encode_baud_rate(tty, baud, baud); } else { quot = 0; @@ -596,7 +495,7 @@ static int mxser_set_baud(struct tty_struct *tty, long newspd) * u64 domain */ timeout = (u64)info->xmit_fifo_size * HZ * 10 * quot; - do_div(timeout, info->baud_base); + do_div(timeout, MXSER_BAUD_BASE); info->timeout = timeout + HZ / 50; /* Add .02 seconds of slop */ if (quot) { @@ -618,7 +517,7 @@ static int mxser_set_baud(struct tty_struct *tty, long newspd) #ifdef BOTHER if (C_BAUD(tty) == BOTHER) { - quot = info->baud_base % newspd; + quot = MXSER_BAUD_BASE % newspd; quot *= 8; if (quot % newspd > newspd / 2) { quot /= newspd; @@ -634,6 +533,28 @@ static int mxser_set_baud(struct tty_struct *tty, long newspd) return 0; } +static void mxser_handle_cts(struct tty_struct *tty, struct mxser_port *info, + u8 msr) +{ + bool cts = msr & UART_MSR_CTS; + + if (tty->hw_stopped) { + if (cts) { + tty->hw_stopped = 0; + + if (!mxser_16550A_or_MUST(info)) + __mxser_start_tx(info); + tty_wakeup(tty); + } + return; + } else if (cts) + return; + + tty->hw_stopped = 1; + if (!mxser_16550A_or_MUST(info)) + __mxser_stop_tx(info); +} + /* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. @@ -642,35 +563,30 @@ static void mxser_change_speed(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; unsigned cflag, cval, fcr; - unsigned char status; cflag = tty->termios.c_cflag; - if (!info->ioaddr) - return; - if (mxser_set_baud_method[tty->index] == 0) - mxser_set_baud(tty, tty_get_baud_rate(tty)); + mxser_set_baud(tty, tty_get_baud_rate(tty)); /* byte size and parity */ switch (cflag & CSIZE) { + default: case CS5: - cval = 0x00; + cval = UART_LCR_WLEN5; break; case CS6: - cval = 0x01; + cval = UART_LCR_WLEN6; break; case CS7: - cval = 0x02; + cval = UART_LCR_WLEN7; break; case CS8: - cval = 0x03; + cval = UART_LCR_WLEN8; break; - default: - cval = 0x00; - break; /* too keep GCC shut... */ } + if (cflag & CSTOPB) - cval |= 0x04; + cval |= UART_LCR_STOP; if (cflag & PARENB) cval |= UART_LCR_PARITY; if (!(cflag & PARODD)) @@ -679,7 +595,7 @@ static void mxser_change_speed(struct tty_struct *tty) cval |= UART_LCR_SPAR; if ((info->type == PORT_8250) || (info->type == PORT_16450)) { - if (info->board->chip_flag) { + if (info->board->must_hwid) { fcr = UART_FCR_ENABLE_FIFO; fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE; mxser_set_must_fifo_value(info); @@ -687,11 +603,11 @@ static void mxser_change_speed(struct tty_struct *tty) fcr = 0; } else { fcr = UART_FCR_ENABLE_FIFO; - if (info->board->chip_flag) { + if (info->board->must_hwid) { fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE; mxser_set_must_fifo_value(info); } else { - switch (info->rx_trigger) { + switch (info->rx_high_water) { case 1: fcr |= UART_FCR_TRIGGER_1; break; @@ -714,35 +630,11 @@ static void mxser_change_speed(struct tty_struct *tty) tty_port_set_cts_flow(&info->port, cflag & CRTSCTS); if (cflag & CRTSCTS) { info->IER |= UART_IER_MSI; - if ((info->type == PORT_16550A) || (info->board->chip_flag)) { + if (mxser_16550A_or_MUST(info)) { info->MCR |= UART_MCR_AFE; } else { - status = inb(info->ioaddr + UART_MSR); - if (tty->hw_stopped) { - if (status & UART_MSR_CTS) { - tty->hw_stopped = 0; - if (info->type != PORT_16550A && - !info->board->chip_flag) { - outb(info->IER & ~UART_IER_THRI, - info->ioaddr + - UART_IER); - info->IER |= UART_IER_THRI; - outb(info->IER, info->ioaddr + - UART_IER); - } - tty_wakeup(tty); - } - } else { - if (!(status & UART_MSR_CTS)) { - tty->hw_stopped = 1; - if ((info->type != PORT_16550A) && - (!info->board->chip_flag)) { - info->IER &= ~UART_IER_THRI; - outb(info->IER, info->ioaddr + - UART_IER); - } - } - } + mxser_handle_cts(tty, info, + inb(info->ioaddr + UART_MSR)); } } outb(info->MCR, info->ioaddr + UART_MCR); @@ -780,23 +672,11 @@ static void mxser_change_speed(struct tty_struct *tty) UART_LSR_FE; } } - if (info->board->chip_flag) { + if (info->board->must_hwid) { mxser_set_must_xon1_value(info->ioaddr, START_CHAR(tty)); mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(tty)); - if (I_IXON(tty)) { - mxser_enable_must_rx_software_flow_control( - info->ioaddr); - } else { - mxser_disable_must_rx_software_flow_control( - info->ioaddr); - } - if (I_IXOFF(tty)) { - mxser_enable_must_tx_software_flow_control( - info->ioaddr); - } else { - mxser_disable_must_tx_software_flow_control( - info->ioaddr); - } + mxser_must_set_rx_sw_flow_control(info->ioaddr, I_IXON(tty)); + mxser_must_set_tx_sw_flow_control(info->ioaddr, I_IXOFF(tty)); } @@ -816,7 +696,6 @@ static void mxser_check_modem_status(struct tty_struct *tty, port->icount.dcd++; if (status & UART_MSR_DCTS) port->icount.cts++; - port->mon_data.modem_status = status; wake_up_interruptible(&port->port.delta_msr_wait); if (tty_port_check_carrier(&port->port) && (status & UART_MSR_DDCD)) { @@ -824,33 +703,8 @@ static void mxser_check_modem_status(struct tty_struct *tty, wake_up_interruptible(&port->port.open_wait); } - if (tty_port_cts_enabled(&port->port)) { - if (tty->hw_stopped) { - if (status & UART_MSR_CTS) { - tty->hw_stopped = 0; - - if ((port->type != PORT_16550A) && - (!port->board->chip_flag)) { - outb(port->IER & ~UART_IER_THRI, - port->ioaddr + UART_IER); - port->IER |= UART_IER_THRI; - outb(port->IER, port->ioaddr + - UART_IER); - } - tty_wakeup(tty); - } - } else { - if (!(status & UART_MSR_CTS)) { - tty->hw_stopped = 1; - if (port->type != PORT_16550A && - !port->board->chip_flag) { - port->IER &= ~UART_IER_THRI; - outb(port->IER, port->ioaddr + - UART_IER); - } - } - } - } + if (tty_port_cts_enabled(&port->port)) + mxser_handle_cts(tty, port, status); } static int mxser_activate(struct tty_port *port, struct tty_struct *tty) @@ -865,7 +719,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) spin_lock_irqsave(&info->slock, flags); - if (!info->ioaddr || !info->type) { + if (!info->type) { set_bit(TTY_IO_ERROR, &tty->flags); free_page(page); spin_unlock_irqrestore(&info->slock, flags); @@ -877,7 +731,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) * Clear the FIFO buffers and disable them * (they will be reenabled in mxser_change_speed()) */ - if (info->board->chip_flag) + if (info->board->must_hwid) outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | MOXA_MUST_FCR_GDA_MODE_ENABLE), info->ioaddr + UART_FCR); @@ -919,7 +773,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) */ info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; - if (info->board->chip_flag) + if (info->board->must_hwid) info->IER |= MOXA_MUST_IER_EGDAI; outb(info->IER, info->ioaddr + UART_IER); /* enable interrupts */ @@ -971,7 +825,7 @@ static void mxser_shutdown_port(struct tty_port *port) outb(0x00, info->ioaddr + UART_IER); /* clear Rx/Tx FIFO's */ - if (info->board->chip_flag) + if (info->board->must_hwid) outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | MOXA_MUST_FCR_GDA_MODE_ENABLE, info->ioaddr + UART_FCR); @@ -983,8 +837,8 @@ static void mxser_shutdown_port(struct tty_port *port) (void) inb(info->ioaddr + UART_RX); - if (info->board->chip_flag) - SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr); + if (info->board->must_hwid) + mxser_must_no_sw_flow_control(info->ioaddr); spin_unlock_irqrestore(&info->slock, flags); } @@ -997,18 +851,12 @@ static void mxser_shutdown_port(struct tty_port *port) */ static int mxser_open(struct tty_struct *tty, struct file *filp) { - struct mxser_port *info; - int line; + struct tty_port *tport = tty->port; + struct mxser_port *port = container_of(tport, struct mxser_port, port); - line = tty->index; - if (line == MXSER_PORTS) - return 0; - info = &mxser_boards[line / MXSER_PORTS_PER_BOARD].ports[line % MXSER_PORTS_PER_BOARD]; - if (!info->ioaddr) - return -ENODEV; + tty->driver_data = port; - tty->driver_data = info; - return tty_port_open(&info->port, tty, filp); + return tty_port_open(tport, tty, filp); } static void mxser_flush_buffer(struct tty_struct *tty) @@ -1043,7 +891,7 @@ static void mxser_close_port(struct tty_port *port) * line status register. */ info->IER &= ~UART_IER_RLSI; - if (info->board->chip_flag) + if (info->board->must_hwid) info->IER &= ~MOXA_MUST_RECV_ISR; outb(info->IER, info->ioaddr + UART_IER); @@ -1071,7 +919,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) struct mxser_port *info = tty->driver_data; struct tty_port *port = &info->port; - if (tty->index == MXSER_PORTS || info == NULL) + if (info == NULL) return; if (tty_port_close_start(port, tty, filp) == 0) return; @@ -1118,18 +966,10 @@ static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int cou total += c; } - if (info->xmit_cnt && !tty->stopped) { - if (!tty->hw_stopped || - (info->type == PORT_16550A) || - (info->board->chip_flag)) { - spin_lock_irqsave(&info->slock, flags); - outb(info->IER & ~UART_IER_THRI, info->ioaddr + - UART_IER); - info->IER |= UART_IER_THRI; - outb(info->IER, info->ioaddr + UART_IER); - spin_unlock_irqrestore(&info->slock, flags); - } - } + if (info->xmit_cnt && !tty->flow.stopped) + if (!tty->hw_stopped || mxser_16550A_or_MUST(info)) + mxser_start_tx(info); + return total; } @@ -1149,17 +989,7 @@ static int mxser_put_char(struct tty_struct *tty, unsigned char ch) info->xmit_head &= SERIAL_XMIT_SIZE - 1; info->xmit_cnt++; spin_unlock_irqrestore(&info->slock, flags); - if (!tty->stopped) { - if (!tty->hw_stopped || - (info->type == PORT_16550A) || - info->board->chip_flag) { - spin_lock_irqsave(&info->slock, flags); - outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER); - info->IER |= UART_IER_THRI; - outb(info->IER, info->ioaddr + UART_IER); - spin_unlock_irqrestore(&info->slock, flags); - } - } + return 1; } @@ -1167,23 +997,15 @@ static int mxser_put_char(struct tty_struct *tty, unsigned char ch) static void mxser_flush_chars(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; - unsigned long flags; - if (info->xmit_cnt <= 0 || tty->stopped || !info->port.xmit_buf || - (tty->hw_stopped && info->type != PORT_16550A && - !info->board->chip_flag)) + if (!info->xmit_cnt || tty->flow.stopped || !info->port.xmit_buf || + (tty->hw_stopped && !mxser_16550A_or_MUST(info))) return; - spin_lock_irqsave(&info->slock, flags); - - outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER); - info->IER |= UART_IER_THRI; - outb(info->IER, info->ioaddr + UART_IER); - - spin_unlock_irqrestore(&info->slock, flags); + mxser_start_tx(info); } -static int mxser_write_room(struct tty_struct *tty) +static unsigned int mxser_write_room(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; int ret; @@ -1192,7 +1014,7 @@ static int mxser_write_room(struct tty_struct *tty) return ret < 0 ? 0 : ret; } -static int mxser_chars_in_buffer(struct tty_struct *tty) +static unsigned int mxser_chars_in_buffer(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; return info->xmit_cnt; @@ -1210,9 +1032,6 @@ static int mxser_get_serial_info(struct tty_struct *tty, struct tty_port *port = &info->port; unsigned int closing_wait, close_delay; - if (tty->index == MXSER_PORTS) - return -ENOTTY; - mutex_lock(&port->mutex); close_delay = jiffies_to_msecs(info->port.close_delay) / 10; @@ -1225,10 +1044,10 @@ static int mxser_get_serial_info(struct tty_struct *tty, ss->port = info->ioaddr, ss->irq = info->board->irq, ss->flags = info->port.flags, - ss->baud_base = info->baud_base, + ss->baud_base = MXSER_BAUD_BASE, ss->close_delay = close_delay; ss->closing_wait = closing_wait; - ss->custom_divisor = info->custom_divisor, + ss->custom_divisor = MXSER_CUSTOM_DIVISOR, mutex_unlock(&port->mutex); return 0; } @@ -1240,19 +1059,13 @@ static int mxser_set_serial_info(struct tty_struct *tty, struct tty_port *port = &info->port; speed_t baud; unsigned long sl_flags; - unsigned int flags, close_delay, closing_wait; + unsigned int old_speed, close_delay, closing_wait; int retval = 0; - if (tty->index == MXSER_PORTS) - return -ENOTTY; if (tty_io_error(tty)) return -EIO; mutex_lock(&port->mutex); - if (!info->ioaddr) { - mutex_unlock(&port->mutex); - return -ENODEV; - } if (ss->irq != info->board->irq || ss->port != info->ioaddr) { @@ -1260,7 +1073,7 @@ static int mxser_set_serial_info(struct tty_struct *tty, return -EINVAL; } - flags = port->flags & ASYNC_SPD_MASK; + old_speed = port->flags & ASYNC_SPD_MASK; close_delay = msecs_to_jiffies(ss->close_delay * 10); closing_wait = ss->closing_wait; @@ -1268,15 +1081,15 @@ static int mxser_set_serial_info(struct tty_struct *tty, closing_wait = msecs_to_jiffies(closing_wait * 10); if (!capable(CAP_SYS_ADMIN)) { - if ((ss->baud_base != info->baud_base) || - (close_delay != info->port.close_delay) || - (closing_wait != info->port.closing_wait) || - ((ss->flags & ~ASYNC_USR_MASK) != (info->port.flags & ~ASYNC_USR_MASK))) { + if ((ss->baud_base != MXSER_BAUD_BASE) || + (close_delay != port->close_delay) || + (closing_wait != port->closing_wait) || + ((ss->flags & ~ASYNC_USR_MASK) != (port->flags & ~ASYNC_USR_MASK))) { mutex_unlock(&port->mutex); return -EPERM; } - info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) | - (ss->flags & ASYNC_USR_MASK)); + port->flags = (port->flags & ~ASYNC_USR_MASK) | + (ss->flags & ASYNC_USR_MASK); } else { /* * OK, past this point, all the error checking has been done. @@ -1287,9 +1100,9 @@ static int mxser_set_serial_info(struct tty_struct *tty, port->close_delay = close_delay; port->closing_wait = closing_wait; if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST && - (ss->baud_base != info->baud_base || + (ss->baud_base != MXSER_BAUD_BASE || ss->custom_divisor != - info->custom_divisor)) { + MXSER_CUSTOM_DIVISOR)) { if (ss->custom_divisor == 0) { mutex_unlock(&port->mutex); return -EINVAL; @@ -1300,11 +1113,11 @@ static int mxser_set_serial_info(struct tty_struct *tty, info->type = ss->type; - process_txrx_fifo(info); + mxser_process_txrx_fifo(info); } if (tty_port_initialized(port)) { - if (flags != (port->flags & ASYNC_SPD_MASK)) { + if (old_speed != (port->flags & ASYNC_SPD_MASK)) { spin_lock_irqsave(&info->slock, sl_flags); mxser_change_speed(tty); spin_unlock_irqrestore(&info->slock, sl_flags); @@ -1348,19 +1161,16 @@ static int mxser_tiocmget(struct tty_struct *tty) unsigned char control, status; unsigned long flags; - - if (tty->index == MXSER_PORTS) - return -ENOIOCTLCMD; if (tty_io_error(tty)) return -EIO; - control = info->MCR; - spin_lock_irqsave(&info->slock, flags); + control = info->MCR; status = inb(info->ioaddr + UART_MSR); if (status & UART_MSR_ANY_DELTA) mxser_check_modem_status(tty, info, status); spin_unlock_irqrestore(&info->slock, flags); + return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) | @@ -1375,9 +1185,6 @@ static int mxser_tiocmset(struct tty_struct *tty, struct mxser_port *info = tty->driver_data; unsigned long flags; - - if (tty->index == MXSER_PORTS) - return -ENOIOCTLCMD; if (tty_io_error(tty)) return -EIO; @@ -1398,267 +1205,6 @@ static int mxser_tiocmset(struct tty_struct *tty, return 0; } -static int __init mxser_program_mode(int port) -{ - int id, i, j, n; - - outb(0, port); - outb(0, port); - outb(0, port); - (void)inb(port); - (void)inb(port); - outb(0, port); - (void)inb(port); - - id = inb(port + 1) & 0x1F; - if ((id != C168_ASIC_ID) && - (id != C104_ASIC_ID) && - (id != C102_ASIC_ID) && - (id != CI132_ASIC_ID) && - (id != CI134_ASIC_ID) && - (id != CI104J_ASIC_ID)) - return -1; - for (i = 0, j = 0; i < 4; i++) { - n = inb(port + 2); - if (n == 'M') { - j = 1; - } else if ((j == 1) && (n == 1)) { - j = 2; - break; - } else - j = 0; - } - if (j != 2) - id = -2; - return id; -} - -static void __init mxser_normal_mode(int port) -{ - int i, n; - - outb(0xA5, port + 1); - outb(0x80, port + 3); - outb(12, port + 0); /* 9600 bps */ - outb(0, port + 1); - outb(0x03, port + 3); /* 8 data bits */ - outb(0x13, port + 4); /* loop back mode */ - for (i = 0; i < 16; i++) { - n = inb(port + 5); - if ((n & 0x61) == 0x60) - break; - if ((n & 1) == 1) - (void)inb(port); - } - outb(0x00, port + 4); -} - -#define CHIP_SK 0x01 /* Serial Data Clock in Eprom */ -#define CHIP_DO 0x02 /* Serial Data Output in Eprom */ -#define CHIP_CS 0x04 /* Serial Chip Select in Eprom */ -#define CHIP_DI 0x08 /* Serial Data Input in Eprom */ -#define EN_CCMD 0x000 /* Chip's command register */ -#define EN0_RSARLO 0x008 /* Remote start address reg 0 */ -#define EN0_RSARHI 0x009 /* Remote start address reg 1 */ -#define EN0_RCNTLO 0x00A /* Remote byte count reg WR */ -#define EN0_RCNTHI 0x00B /* Remote byte count reg WR */ -#define EN0_DCFG 0x00E /* Data configuration reg WR */ -#define EN0_PORT 0x010 /* Rcv missed frame error counter RD */ -#define ENC_PAGE0 0x000 /* Select page 0 of chip registers */ -#define ENC_PAGE3 0x0C0 /* Select page 3 of chip registers */ -static int __init mxser_read_register(int port, unsigned short *regs) -{ - int i, k, value, id; - unsigned int j; - - id = mxser_program_mode(port); - if (id < 0) - return id; - for (i = 0; i < 14; i++) { - k = (i & 0x3F) | 0x180; - for (j = 0x100; j > 0; j >>= 1) { - outb(CHIP_CS, port); - if (k & j) { - outb(CHIP_CS | CHIP_DO, port); - outb(CHIP_CS | CHIP_DO | CHIP_SK, port); /* A? bit of read */ - } else { - outb(CHIP_CS, port); - outb(CHIP_CS | CHIP_SK, port); /* A? bit of read */ - } - } - (void)inb(port); - value = 0; - for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) { - outb(CHIP_CS, port); - outb(CHIP_CS | CHIP_SK, port); - if (inb(port) & CHIP_DI) - value |= j; - } - regs[i] = value; - outb(0, port); - } - mxser_normal_mode(port); - return id; -} - -static int mxser_ioctl_special(unsigned int cmd, void __user *argp) -{ - struct mxser_port *ip; - struct tty_port *port; - struct tty_struct *tty; - int result, status; - unsigned int i, j; - int ret = 0; - - switch (cmd) { - case MOXA_GET_MAJOR: - printk_ratelimited(KERN_WARNING "mxser: '%s' uses deprecated ioctl " - "%x (GET_MAJOR), fix your userspace\n", - current->comm, cmd); - return put_user(ttymajor, (int __user *)argp); - - case MOXA_CHKPORTENABLE: - result = 0; - for (i = 0; i < MXSER_BOARDS; i++) - for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) - if (mxser_boards[i].ports[j].ioaddr) - result |= (1 << i); - return put_user(result, (unsigned long __user *)argp); - case MOXA_GETDATACOUNT: - /* The receive side is locked by port->slock but it isn't - clear that an exact snapshot is worth copying here */ - if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log))) - ret = -EFAULT; - return ret; - case MOXA_GETMSTATUS: { - struct mxser_mstatus ms, __user *msu = argp; - for (i = 0; i < MXSER_BOARDS; i++) - for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) { - ip = &mxser_boards[i].ports[j]; - port = &ip->port; - memset(&ms, 0, sizeof(ms)); - - mutex_lock(&port->mutex); - if (!ip->ioaddr) - goto copy; - - tty = tty_port_tty_get(port); - - if (!tty) - ms.cflag = ip->normal_termios.c_cflag; - else - ms.cflag = tty->termios.c_cflag; - tty_kref_put(tty); - spin_lock_irq(&ip->slock); - status = inb(ip->ioaddr + UART_MSR); - spin_unlock_irq(&ip->slock); - if (status & UART_MSR_DCD) - ms.dcd = 1; - if (status & UART_MSR_DSR) - ms.dsr = 1; - if (status & UART_MSR_CTS) - ms.cts = 1; - copy: - mutex_unlock(&port->mutex); - if (copy_to_user(msu, &ms, sizeof(ms))) - return -EFAULT; - msu++; - } - return 0; - } - case MOXA_ASPP_MON_EXT: { - struct mxser_mon_ext *me; /* it's 2k, stack unfriendly */ - unsigned int cflag, iflag, p; - u8 opmode; - - me = kzalloc(sizeof(*me), GFP_KERNEL); - if (!me) - return -ENOMEM; - - for (i = 0, p = 0; i < MXSER_BOARDS; i++) { - for (j = 0; j < MXSER_PORTS_PER_BOARD; j++, p++) { - if (p >= ARRAY_SIZE(me->rx_cnt)) { - i = MXSER_BOARDS; - break; - } - ip = &mxser_boards[i].ports[j]; - port = &ip->port; - - mutex_lock(&port->mutex); - if (!ip->ioaddr) { - mutex_unlock(&port->mutex); - continue; - } - - spin_lock_irq(&ip->slock); - status = mxser_get_msr(ip->ioaddr, 0, p); - - if (status & UART_MSR_TERI) - ip->icount.rng++; - if (status & UART_MSR_DDSR) - ip->icount.dsr++; - if (status & UART_MSR_DDCD) - ip->icount.dcd++; - if (status & UART_MSR_DCTS) - ip->icount.cts++; - - ip->mon_data.modem_status = status; - me->rx_cnt[p] = ip->mon_data.rxcnt; - me->tx_cnt[p] = ip->mon_data.txcnt; - me->up_rxcnt[p] = ip->mon_data.up_rxcnt; - me->up_txcnt[p] = ip->mon_data.up_txcnt; - me->modem_status[p] = - ip->mon_data.modem_status; - spin_unlock_irq(&ip->slock); - - tty = tty_port_tty_get(&ip->port); - - if (!tty) { - cflag = ip->normal_termios.c_cflag; - iflag = ip->normal_termios.c_iflag; - me->baudrate[p] = tty_termios_baud_rate(&ip->normal_termios); - } else { - cflag = tty->termios.c_cflag; - iflag = tty->termios.c_iflag; - me->baudrate[p] = tty_get_baud_rate(tty); - } - tty_kref_put(tty); - - me->databits[p] = cflag & CSIZE; - me->stopbits[p] = cflag & CSTOPB; - me->parity[p] = cflag & (PARENB | PARODD | - CMSPAR); - - if (cflag & CRTSCTS) - me->flowctrl[p] |= 0x03; - - if (iflag & (IXON | IXOFF)) - me->flowctrl[p] |= 0x0C; - - if (ip->type == PORT_16550A) - me->fifo[p] = 1; - - if (ip->board->chip_flag == MOXA_MUST_MU860_HWID) { - opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2); - opmode &= OP_MODE_MASK; - } else { - opmode = RS232_MODE; - } - me->iftype[p] = opmode; - mutex_unlock(&port->mutex); - } - } - if (copy_to_user(argp, me, sizeof(*me))) - ret = -EFAULT; - kfree(me); - return ret; - } - default: - return -ENOIOCTLCMD; - } - return 0; -} - static int mxser_cflags_changed(struct mxser_port *info, unsigned long arg, struct async_icount *cprev) { @@ -1680,6 +1226,41 @@ static int mxser_cflags_changed(struct mxser_port *info, unsigned long arg, return ret; } +/* We should likely switch to TIOCGRS485/TIOCSRS485. */ +static int mxser_ioctl_op_mode(struct mxser_port *port, int index, bool set, + int __user *u_opmode) +{ + int opmode, p = index % 4; + int shiftbit = p * 2; + u8 val; + + if (port->board->must_hwid != MOXA_MUST_MU860_HWID) + return -EFAULT; + + if (set) { + if (get_user(opmode, u_opmode)) + return -EFAULT; + + if (opmode & ~OP_MODE_MASK) + return -EINVAL; + + spin_lock_irq(&port->slock); + val = inb(port->opmode_ioaddr); + val &= ~(OP_MODE_MASK << shiftbit); + val |= (opmode << shiftbit); + outb(val, port->opmode_ioaddr); + spin_unlock_irq(&port->slock); + + return 0; + } + + spin_lock_irq(&port->slock); + opmode = inb(port->opmode_ioaddr) >> shiftbit; + spin_unlock_irq(&port->slock); + + return put_user(opmode & OP_MODE_MASK, u_opmode); +} + static int mxser_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { @@ -1688,47 +1269,9 @@ static int mxser_ioctl(struct tty_struct *tty, unsigned long flags; void __user *argp = (void __user *)arg; - if (tty->index == MXSER_PORTS) - return mxser_ioctl_special(cmd, argp); - - if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) { - int p; - unsigned long opmode; - static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f }; - int shiftbit; - unsigned char val, mask; - - if (info->board->chip_flag != MOXA_MUST_MU860_HWID) - return -EFAULT; - - p = tty->index % 4; - if (cmd == MOXA_SET_OP_MODE) { - if (get_user(opmode, (int __user *) argp)) - return -EFAULT; - if (opmode != RS232_MODE && - opmode != RS485_2WIRE_MODE && - opmode != RS422_MODE && - opmode != RS485_4WIRE_MODE) - return -EFAULT; - mask = ModeMask[p]; - shiftbit = p * 2; - spin_lock_irq(&info->slock); - val = inb(info->opmode_ioaddr); - val &= mask; - val |= (opmode << shiftbit); - outb(val, info->opmode_ioaddr); - spin_unlock_irq(&info->slock); - } else { - shiftbit = p * 2; - spin_lock_irq(&info->slock); - opmode = inb(info->opmode_ioaddr) >> shiftbit; - spin_unlock_irq(&info->slock); - opmode &= OP_MODE_MASK; - if (put_user(opmode, (int __user *)argp)) - return -EFAULT; - } - return 0; - } + if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) + return mxser_ioctl_op_mode(info, tty->index, + cmd == MOXA_SET_OP_MODE, argp); if (cmd != TIOCMIWAIT && tty_io_error(tty)) return -EIO; @@ -1749,72 +1292,6 @@ static int mxser_ioctl(struct tty_struct *tty, return wait_event_interruptible(info->port.delta_msr_wait, mxser_cflags_changed(info, arg, &cnow)); - case MOXA_HighSpeedOn: - return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp); - case MOXA_SDS_RSTICOUNTER: - spin_lock_irq(&info->slock); - info->mon_data.rxcnt = 0; - info->mon_data.txcnt = 0; - spin_unlock_irq(&info->slock); - return 0; - - case MOXA_ASPP_OQUEUE:{ - int len, lsr; - - len = mxser_chars_in_buffer(tty); - spin_lock_irq(&info->slock); - lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_THRE; - spin_unlock_irq(&info->slock); - len += (lsr ? 0 : 1); - - return put_user(len, (int __user *)argp); - } - case MOXA_ASPP_MON: { - int mcr, status; - - spin_lock_irq(&info->slock); - status = mxser_get_msr(info->ioaddr, 1, tty->index); - mxser_check_modem_status(tty, info, status); - - mcr = inb(info->ioaddr + UART_MCR); - spin_unlock_irq(&info->slock); - - if (mcr & MOXA_MUST_MCR_XON_FLAG) - info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD; - else - info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFHOLD; - - if (mcr & MOXA_MUST_MCR_TX_XON) - info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFXENT; - else - info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT; - - if (tty->hw_stopped) - info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD; - else - info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD; - - if (copy_to_user(argp, &info->mon_data, - sizeof(struct mxser_mon))) - return -EFAULT; - - return 0; - } - case MOXA_ASPP_LSTATUS: { - if (put_user(info->err_shadow, (unsigned char __user *)argp)) - return -EFAULT; - - info->err_shadow = 0; - return 0; - } - case MOXA_SET_BAUD_METHOD: { - int method; - - if (get_user(method, (int __user *)argp)) - return -EFAULT; - mxser_set_baud_method[tty->index] = method; - return put_user(method, (int __user *)argp); - } default: return -ENOIOCTLCMD; } @@ -1860,7 +1337,7 @@ static void mxser_stoprx(struct tty_struct *tty) info->ldisc_stop_rx = 1; if (I_IXOFF(tty)) { - if (info->board->chip_flag) { + if (info->board->must_hwid) { info->IER &= ~MOXA_MUST_RECV_ISR; outb(info->IER, info->ioaddr + UART_IER); } else { @@ -1896,7 +1373,7 @@ static void mxser_unthrottle(struct tty_struct *tty) if (info->x_char) info->x_char = 0; else { - if (info->board->chip_flag) { + if (info->board->must_hwid) { info->IER |= MOXA_MUST_RECV_ISR; outb(info->IER, info->ioaddr + UART_IER); } else { @@ -1917,7 +1394,7 @@ static void mxser_unthrottle(struct tty_struct *tty) /* * mxser_stop() and mxser_start() * - * This routines are called before setting or resetting tty->stopped. + * This routines are called before setting or resetting tty->flow.stopped. * They enable or disable transmitter interrupts, as necessary. */ static void mxser_stop(struct tty_struct *tty) @@ -1926,10 +1403,8 @@ static void mxser_stop(struct tty_struct *tty) unsigned long flags; spin_lock_irqsave(&info->slock, flags); - if (info->IER & UART_IER_THRI) { - info->IER &= ~UART_IER_THRI; - outb(info->IER, info->ioaddr + UART_IER); - } + if (info->IER & UART_IER_THRI) + __mxser_stop_tx(info); spin_unlock_irqrestore(&info->slock, flags); } @@ -1939,11 +1414,8 @@ static void mxser_start(struct tty_struct *tty) unsigned long flags; spin_lock_irqsave(&info->slock, flags); - if (info->xmit_cnt && info->port.xmit_buf) { - outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER); - info->IER |= UART_IER_THRI; - outb(info->IER, info->ioaddr + UART_IER); - } + if (info->xmit_cnt && info->port.xmit_buf) + __mxser_start_tx(info); spin_unlock_irqrestore(&info->slock, flags); } @@ -1963,12 +1435,11 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi /* Handle sw stopped */ if ((old_termios->c_iflag & IXON) && !I_IXON(tty)) { - tty->stopped = 0; + tty->flow.stopped = 0; - if (info->board->chip_flag) { + if (info->board->must_hwid) { spin_lock_irqsave(&info->slock, flags); - mxser_disable_must_rx_software_flow_control( - info->ioaddr); + mxser_must_set_rx_sw_flow_control(info->ioaddr, false); spin_unlock_irqrestore(&info->slock, flags); } @@ -2051,88 +1522,92 @@ static int mxser_rs_break(struct tty_struct *tty, int break_state) { struct mxser_port *info = tty->driver_data; unsigned long flags; + u8 lcr; spin_lock_irqsave(&info->slock, flags); + lcr = inb(info->ioaddr + UART_LCR); if (break_state == -1) - outb(inb(info->ioaddr + UART_LCR) | UART_LCR_SBC, - info->ioaddr + UART_LCR); + lcr |= UART_LCR_SBC; else - outb(inb(info->ioaddr + UART_LCR) & ~UART_LCR_SBC, - info->ioaddr + UART_LCR); + lcr &= ~UART_LCR_SBC; + outb(lcr, info->ioaddr + UART_LCR); spin_unlock_irqrestore(&info->slock, flags); + return 0; } -static void mxser_receive_chars(struct tty_struct *tty, - struct mxser_port *port, int *status) +static bool mxser_receive_chars_new(struct tty_struct *tty, + struct mxser_port *port, u8 status) { - unsigned char ch, gdl; - int ignored = 0; - int cnt = 0; - int recv_room; - int max = 256; + enum mxser_must_hwid hwid = port->board->must_hwid; + u8 gdl; + + if (hwid == MOXA_OTHER_UART) + return false; + if (status & UART_LSR_BRK_ERROR_BITS) + return false; + if (hwid == MOXA_MUST_MU860_HWID && (status & MOXA_MUST_LSR_RERR)) + return false; + if (status & MOXA_MUST_LSR_RERR) + return false; - recv_room = tty->receive_room; - if (recv_room == 0 && !port->ldisc_stop_rx) + gdl = inb(port->ioaddr + MOXA_MUST_GDL_REGISTER); + if (hwid == MOXA_MUST_MU150_HWID) + gdl &= MOXA_MUST_GDL_MASK; + + if (gdl >= tty->receive_room && !port->ldisc_stop_rx) mxser_stoprx(tty); - if (port->board->chip_flag != MOXA_OTHER_UART) { - - if (*status & UART_LSR_SPECIAL) - goto intr_old; - if (port->board->chip_flag == MOXA_MUST_MU860_HWID && - (*status & MOXA_MUST_LSR_RERR)) - goto intr_old; - if (*status & MOXA_MUST_LSR_RERR) - goto intr_old; - - gdl = inb(port->ioaddr + MOXA_MUST_GDL_REGISTER); - - if (port->board->chip_flag == MOXA_MUST_MU150_HWID) - gdl &= MOXA_MUST_GDL_MASK; - if (gdl >= recv_room) { - if (!port->ldisc_stop_rx) - mxser_stoprx(tty); - } - while (gdl--) { - ch = inb(port->ioaddr + UART_RX); - tty_insert_flip_char(&port->port, ch, 0); - cnt++; - } - goto end_intr; + + while (gdl--) { + u8 ch = inb(port->ioaddr + UART_RX); + tty_insert_flip_char(&port->port, ch, 0); } -intr_old: + + return true; +} + +static u8 mxser_receive_chars_old(struct tty_struct *tty, + struct mxser_port *port, u8 status) +{ + enum mxser_must_hwid hwid = port->board->must_hwid; + int recv_room = tty->receive_room; + int ignored = 0; + int max = 256; + int cnt = 0; + u8 ch; do { if (max-- < 0) break; ch = inb(port->ioaddr + UART_RX); - if (port->board->chip_flag && (*status & UART_LSR_OE)) - outb(0x23, port->ioaddr + UART_FCR); - *status &= port->read_status_mask; - if (*status & port->ignore_status_mask) { + if (hwid && (status & UART_LSR_OE)) + outb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | + MOXA_MUST_FCR_GDA_MODE_ENABLE, + port->ioaddr + UART_FCR); + status &= port->read_status_mask; + if (status & port->ignore_status_mask) { if (++ignored > 100) break; } else { char flag = 0; - if (*status & UART_LSR_SPECIAL) { - if (*status & UART_LSR_BI) { + if (status & UART_LSR_BRK_ERROR_BITS) { + if (status & UART_LSR_BI) { flag = TTY_BREAK; port->icount.brk++; if (port->port.flags & ASYNC_SAK) do_SAK(tty); - } else if (*status & UART_LSR_PE) { + } else if (status & UART_LSR_PE) { flag = TTY_PARITY; port->icount.parity++; - } else if (*status & UART_LSR_FE) { + } else if (status & UART_LSR_FE) { flag = TTY_FRAME; port->icount.frame++; - } else if (*status & UART_LSR_OE) { + } else if (status & UART_LSR_OE) { flag = TTY_OVERRUN; port->icount.overrun++; - } else - flag = TTY_BREAK; + } } tty_insert_flip_char(&port->port, ch, flag); cnt++; @@ -2144,18 +1619,27 @@ intr_old: } - if (port->board->chip_flag) + if (hwid) break; - *status = inb(port->ioaddr + UART_LSR); - } while (*status & UART_LSR_DR); + status = inb(port->ioaddr + UART_LSR); + } while (status & UART_LSR_DR); + + return status; +} + +static u8 mxser_receive_chars(struct tty_struct *tty, + struct mxser_port *port, u8 status) +{ + if (tty->receive_room == 0 && !port->ldisc_stop_rx) + mxser_stoprx(tty); -end_intr: - mxvar_log.rxcnt[tty->index] += cnt; - port->mon_data.rxcnt += cnt; - port->mon_data.up_rxcnt += cnt; + if (!mxser_receive_chars_new(tty, port, status)) + status = mxser_receive_chars_old(tty, port, status); tty_flip_buffer_push(&port->port); + + return status; } static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port) @@ -2165,9 +1649,6 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port if (port->x_char) { outb(port->x_char, port->ioaddr + UART_TX); port->x_char = 0; - mxvar_log.txcnt[tty->index]++; - port->mon_data.txcnt++; - port->mon_data.up_txcnt++; port->icount.tx++; return; } @@ -2175,12 +1656,9 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port if (port->port.xmit_buf == NULL) return; - if (port->xmit_cnt <= 0 || tty->stopped || - (tty->hw_stopped && - (port->type != PORT_16550A) && - (!port->board->chip_flag))) { - port->IER &= ~UART_IER_THRI; - outb(port->IER, port->ioaddr + UART_IER); + if (!port->xmit_cnt || tty->flow.stopped || + (tty->hw_stopped && !mxser_16550A_or_MUST(port))) { + __mxser_stop_tx(port); return; } @@ -2190,22 +1668,72 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port outb(port->port.xmit_buf[port->xmit_tail++], port->ioaddr + UART_TX); port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1); - if (--port->xmit_cnt <= 0) + if (!--port->xmit_cnt) break; } while (--count > 0); - mxvar_log.txcnt[tty->index] += (cnt - port->xmit_cnt); - port->mon_data.txcnt += (cnt - port->xmit_cnt); - port->mon_data.up_txcnt += (cnt - port->xmit_cnt); port->icount.tx += (cnt - port->xmit_cnt); if (port->xmit_cnt < WAKEUP_CHARS) tty_wakeup(tty); - if (port->xmit_cnt <= 0) { - port->IER &= ~UART_IER_THRI; - outb(port->IER, port->ioaddr + UART_IER); + if (!port->xmit_cnt) + __mxser_stop_tx(port); +} + +static bool mxser_port_isr(struct mxser_port *port) +{ + struct tty_struct *tty; + u8 iir, msr, status; + bool error = false; + + iir = inb(port->ioaddr + UART_IIR); + if (iir & UART_IIR_NO_INT) + return true; + + iir &= MOXA_MUST_IIR_MASK; + tty = tty_port_tty_get(&port->port); + if (!tty || port->closing || !tty_port_initialized(&port->port)) { + status = inb(port->ioaddr + UART_LSR); + outb(MOXA_MUST_FCR_GDA_MODE_ENABLE | UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, + port->ioaddr + UART_FCR); + inb(port->ioaddr + UART_MSR); + + error = true; + goto put_tty; + } + + status = inb(port->ioaddr + UART_LSR); + + if (port->board->must_hwid) { + if (iir == MOXA_MUST_IIR_GDA || + iir == MOXA_MUST_IIR_RDA || + iir == MOXA_MUST_IIR_RTO || + iir == MOXA_MUST_IIR_LSR) + status = mxser_receive_chars(tty, port, status); + } else { + status &= port->read_status_mask; + if (status & UART_LSR_DR) + status = mxser_receive_chars(tty, port, status); + } + + msr = inb(port->ioaddr + UART_MSR); + if (msr & UART_MSR_ANY_DELTA) + mxser_check_modem_status(tty, port, msr); + + if (port->board->must_hwid) { + if (iir == 0x02 && (status & UART_LSR_THRE)) + mxser_transmit_chars(tty, port); + } else { + if (status & UART_LSR_THRE) + mxser_transmit_chars(tty, port); } + +put_tty: + tty_kref_put(tty); + + return error; } /* @@ -2213,33 +1741,21 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port */ static irqreturn_t mxser_interrupt(int irq, void *dev_id) { - int status, iir, i; - struct mxser_board *brd = NULL; + struct mxser_board *brd = dev_id; struct mxser_port *port; - int max, irqbits, bits, msr; unsigned int int_cnt, pass_counter = 0; + unsigned int i, max = brd->nports; int handled = IRQ_NONE; - struct tty_struct *tty; - - for (i = 0; i < MXSER_BOARDS; i++) - if (dev_id == &mxser_boards[i]) { - brd = dev_id; - break; - } + u8 irqbits, bits, mask = BIT(max) - 1; - if (i == MXSER_BOARDS) - goto irq_stop; - if (brd == NULL) - goto irq_stop; - max = brd->info->nports; while (pass_counter++ < MXSER_ISR_PASS_LIMIT) { - irqbits = inb(brd->vector) & brd->vector_mask; - if (irqbits == brd->vector_mask) + irqbits = inb(brd->vector) & mask; + if (irqbits == mask) break; handled = IRQ_HANDLED; for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) { - if (irqbits == brd->vector_mask) + if (irqbits == mask) break; if (bits & irqbits) continue; @@ -2248,65 +1764,13 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) int_cnt = 0; spin_lock(&port->slock); do { - iir = inb(port->ioaddr + UART_IIR); - if (iir & UART_IIR_NO_INT) + if (mxser_port_isr(port)) break; - iir &= MOXA_MUST_IIR_MASK; - tty = tty_port_tty_get(&port->port); - if (!tty || port->closing || - !tty_port_initialized(&port->port)) { - status = inb(port->ioaddr + UART_LSR); - outb(0x27, port->ioaddr + UART_FCR); - inb(port->ioaddr + UART_MSR); - tty_kref_put(tty); - break; - } - - status = inb(port->ioaddr + UART_LSR); - - if (status & UART_LSR_PE) - port->err_shadow |= NPPI_NOTIFY_PARITY; - if (status & UART_LSR_FE) - port->err_shadow |= NPPI_NOTIFY_FRAMING; - if (status & UART_LSR_OE) - port->err_shadow |= - NPPI_NOTIFY_HW_OVERRUN; - if (status & UART_LSR_BI) - port->err_shadow |= NPPI_NOTIFY_BREAK; - - if (port->board->chip_flag) { - if (iir == MOXA_MUST_IIR_GDA || - iir == MOXA_MUST_IIR_RDA || - iir == MOXA_MUST_IIR_RTO || - iir == MOXA_MUST_IIR_LSR) - mxser_receive_chars(tty, port, - &status); - - } else { - status &= port->read_status_mask; - if (status & UART_LSR_DR) - mxser_receive_chars(tty, port, - &status); - } - msr = inb(port->ioaddr + UART_MSR); - if (msr & UART_MSR_ANY_DELTA) - mxser_check_modem_status(tty, port, msr); - - if (port->board->chip_flag) { - if (iir == 0x02 && (status & - UART_LSR_THRE)) - mxser_transmit_chars(tty, port); - } else { - if (status & UART_LSR_THRE) - mxser_transmit_chars(tty, port); - } - tty_kref_put(tty); } while (int_cnt++ < MXSER_ISR_PASS_LIMIT); spin_unlock(&port->slock); } } -irq_stop: return handled; } @@ -2346,254 +1810,103 @@ static const struct tty_port_operations mxser_port_ops = { * The MOXA Smartio/Industio serial driver boot-time initialization code! */ -static bool allow_overlapping_vector; -module_param(allow_overlapping_vector, bool, S_IRUGO); -MODULE_PARM_DESC(allow_overlapping_vector, "whether we allow ISA cards to be configured such that vector overlabs IO ports (default=no)"); - -static bool mxser_overlapping_vector(struct mxser_board *brd) -{ - return allow_overlapping_vector && - brd->vector >= brd->ports[0].ioaddr && - brd->vector < brd->ports[0].ioaddr + 8 * brd->info->nports; -} - -static int mxser_request_vector(struct mxser_board *brd) +static void mxser_initbrd(struct mxser_board *brd, bool high_baud) { - if (mxser_overlapping_vector(brd)) - return 0; - return request_region(brd->vector, 1, "mxser(vector)") ? 0 : -EIO; -} + struct mxser_port *info; + unsigned int i; + bool is_mu860; -static void mxser_release_vector(struct mxser_board *brd) -{ - if (mxser_overlapping_vector(brd)) - return; - release_region(brd->vector, 1); -} + brd->must_hwid = mxser_must_get_hwid(brd->ports[0].ioaddr); + is_mu860 = brd->must_hwid == MOXA_MUST_MU860_HWID; -static void mxser_release_ISA_res(struct mxser_board *brd) -{ - release_region(brd->ports[0].ioaddr, 8 * brd->info->nports); - mxser_release_vector(brd); -} + for (i = 0; i < UART_INFO_NUM; i++) { + if (Gpci_uart_info[i].type == brd->must_hwid) { + brd->max_baud = Gpci_uart_info[i].max_baud; -static int mxser_initbrd(struct mxser_board *brd) -{ - struct mxser_port *info; - unsigned int i; - int retval; + /* exception....CP-102 */ + if (high_baud) + brd->max_baud = 921600; + break; + } + } - printk(KERN_INFO "mxser: max. baud rate = %d bps\n", - brd->ports[0].max_baud); + if (is_mu860) { + /* set to RS232 mode by default */ + outb(0, brd->vector + 4); + outb(0, brd->vector + 0x0c); + } - for (i = 0; i < brd->info->nports; i++) { + for (i = 0; i < brd->nports; i++) { info = &brd->ports[i]; + if (is_mu860) { + if (i < 4) + info->opmode_ioaddr = brd->vector + 4; + else + info->opmode_ioaddr = brd->vector + 0x0c; + } tty_port_init(&info->port); info->port.ops = &mxser_port_ops; info->board = brd; - info->stop_rx = 0; info->ldisc_stop_rx = 0; /* Enhance mode enabled here */ - if (brd->chip_flag != MOXA_OTHER_UART) - mxser_enable_must_enchance_mode(info->ioaddr); + if (brd->must_hwid != MOXA_OTHER_UART) + mxser_must_set_enhance_mode(info->ioaddr, true); - info->type = brd->uart_type; + info->type = PORT_16550A; - process_txrx_fifo(info); + mxser_process_txrx_fifo(info); - info->custom_divisor = info->baud_base * 16; info->port.close_delay = 5 * HZ / 10; info->port.closing_wait = 30 * HZ; - info->normal_termios = mxvar_sdriver->init_termios; - memset(&info->mon_data, 0, sizeof(struct mxser_mon)); - info->err_shadow = 0; spin_lock_init(&info->slock); /* before set INT ISR, disable all int */ outb(inb(info->ioaddr + UART_IER) & 0xf0, info->ioaddr + UART_IER); } - - retval = request_irq(brd->irq, mxser_interrupt, IRQF_SHARED, "mxser", - brd); - if (retval) { - for (i = 0; i < brd->info->nports; i++) - tty_port_destroy(&brd->ports[i].port); - printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may " - "conflict with another device.\n", - brd->info->name, brd->irq); - } - - return retval; -} - -static void mxser_board_remove(struct mxser_board *brd) -{ - unsigned int i; - - for (i = 0; i < brd->info->nports; i++) { - tty_unregister_device(mxvar_sdriver, brd->idx + i); - tty_port_destroy(&brd->ports[i].port); - } - free_irq(brd->irq, brd); -} - -static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd) -{ - int id, i, bits, ret; - unsigned short regs[16], irq; - unsigned char scratch, scratch2; - - brd->chip_flag = MOXA_OTHER_UART; - - id = mxser_read_register(cap, regs); - switch (id) { - case C168_ASIC_ID: - brd->info = &mxser_cards[0]; - break; - case C104_ASIC_ID: - brd->info = &mxser_cards[1]; - break; - case CI104J_ASIC_ID: - brd->info = &mxser_cards[2]; - break; - case C102_ASIC_ID: - brd->info = &mxser_cards[5]; - break; - case CI132_ASIC_ID: - brd->info = &mxser_cards[6]; - break; - case CI134_ASIC_ID: - brd->info = &mxser_cards[7]; - break; - default: - return 0; - } - - irq = 0; - /* some ISA cards have 2 ports, but we want to see them as 4-port (why?) - Flag-hack checks if configuration should be read as 2-port here. */ - if (brd->info->nports == 2 || (brd->info->flags & MXSER_HAS2)) { - irq = regs[9] & 0xF000; - irq = irq | (irq >> 4); - if (irq != (regs[9] & 0xFF00)) - goto err_irqconflict; - } else if (brd->info->nports == 4) { - irq = regs[9] & 0xF000; - irq = irq | (irq >> 4); - irq = irq | (irq >> 8); - if (irq != regs[9]) - goto err_irqconflict; - } else if (brd->info->nports == 8) { - irq = regs[9] & 0xF000; - irq = irq | (irq >> 4); - irq = irq | (irq >> 8); - if ((irq != regs[9]) || (irq != regs[10])) - goto err_irqconflict; - } - - if (!irq) { - printk(KERN_ERR "mxser: interrupt number unset\n"); - return -EIO; - } - brd->irq = ((int)(irq & 0xF000) >> 12); - for (i = 0; i < 8; i++) - brd->ports[i].ioaddr = (int) regs[i + 1] & 0xFFF8; - if ((regs[12] & 0x80) == 0) { - printk(KERN_ERR "mxser: invalid interrupt vector\n"); - return -EIO; - } - brd->vector = (int)regs[11]; /* interrupt vector */ - if (id == 1) - brd->vector_mask = 0x00FF; - else - brd->vector_mask = 0x000F; - for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) { - if (regs[12] & bits) { - brd->ports[i].baud_base = 921600; - brd->ports[i].max_baud = 921600; - } else { - brd->ports[i].baud_base = 115200; - brd->ports[i].max_baud = 115200; - } - } - scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB); - outb(scratch2 | UART_LCR_DLAB, cap + UART_LCR); - outb(0, cap + UART_EFR); /* EFR is the same as FCR */ - outb(scratch2, cap + UART_LCR); - outb(UART_FCR_ENABLE_FIFO, cap + UART_FCR); - scratch = inb(cap + UART_IIR); - - if (scratch & 0xC0) - brd->uart_type = PORT_16550A; - else - brd->uart_type = PORT_16450; - if (!request_region(brd->ports[0].ioaddr, 8 * brd->info->nports, - "mxser(IO)")) { - printk(KERN_ERR "mxser: can't request ports I/O region: " - "0x%.8lx-0x%.8lx\n", - brd->ports[0].ioaddr, brd->ports[0].ioaddr + - 8 * brd->info->nports - 1); - return -EIO; - } - - ret = mxser_request_vector(brd); - if (ret) { - release_region(brd->ports[0].ioaddr, 8 * brd->info->nports); - printk(KERN_ERR "mxser: can't request interrupt vector region: " - "0x%.8lx-0x%.8lx\n", - brd->ports[0].ioaddr, brd->ports[0].ioaddr + - 8 * brd->info->nports - 1); - return ret; - } - return brd->info->nports; - -err_irqconflict: - printk(KERN_ERR "mxser: invalid interrupt number\n"); - return -EIO; } static int mxser_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { -#ifdef CONFIG_PCI struct mxser_board *brd; - unsigned int i, j; + unsigned int i, base; unsigned long ioaddress; + unsigned short nports = MXSER_NPORTS(ent->driver_data); struct device *tty_dev; int retval = -EINVAL; - for (i = 0; i < MXSER_BOARDS; i++) - if (mxser_boards[i].info == NULL) - break; - + i = find_first_zero_bit(mxser_boards, MXSER_BOARDS); if (i >= MXSER_BOARDS) { dev_err(&pdev->dev, "too many boards found (maximum %d), board " "not configured\n", MXSER_BOARDS); goto err; } - brd = &mxser_boards[i]; - brd->idx = i * MXSER_PORTS_PER_BOARD; - dev_info(&pdev->dev, "found MOXA %s board (BusNo=%d, DevNo=%d)\n", - mxser_cards[ent->driver_data].name, - pdev->bus->number, PCI_SLOT(pdev->devfn)); + brd = devm_kzalloc(&pdev->dev, struct_size(brd, ports, nports), + GFP_KERNEL); + if (!brd) + goto err; + + brd->idx = i; + __set_bit(brd->idx, mxser_boards); + base = i * MXSER_PORTS_PER_BOARD; - retval = pci_enable_device(pdev); + retval = pcim_enable_device(pdev); if (retval) { dev_err(&pdev->dev, "PCI enable failed\n"); - goto err; + goto err_zero; } /* io address */ ioaddress = pci_resource_start(pdev, 2); retval = pci_request_region(pdev, 2, "mxser(IO)"); if (retval) - goto err_dis; + goto err_zero; - brd->info = &mxser_cards[ent->driver_data]; - for (i = 0; i < brd->info->nports; i++) + brd->nports = nports; + for (i = 0; i < nports; i++) brd->ports[i].ioaddr = ioaddress + 8 * i; /* vector */ @@ -2606,53 +1919,23 @@ static int mxser_probe(struct pci_dev *pdev, /* irq */ brd->irq = pdev->irq; - brd->chip_flag = CheckIsMoxaMust(brd->ports[0].ioaddr); - brd->uart_type = PORT_16550A; - brd->vector_mask = 0; - - for (i = 0; i < brd->info->nports; i++) { - for (j = 0; j < UART_INFO_NUM; j++) { - if (Gpci_uart_info[j].type == brd->chip_flag) { - brd->ports[i].max_baud = - Gpci_uart_info[j].max_baud; - - /* exception....CP-102 */ - if (brd->info->flags & MXSER_HIGHBAUD) - brd->ports[i].max_baud = 921600; - break; - } - } - } - - if (brd->chip_flag == MOXA_MUST_MU860_HWID) { - for (i = 0; i < brd->info->nports; i++) { - if (i < 4) - brd->ports[i].opmode_ioaddr = ioaddress + 4; - else - brd->ports[i].opmode_ioaddr = ioaddress + 0x0c; - } - outb(0, ioaddress + 4); /* default set to RS232 mode */ - outb(0, ioaddress + 0x0c); /* default set to RS232 mode */ - } + mxser_initbrd(brd, ent->driver_data & MXSER_HIGHBAUD); - for (i = 0; i < brd->info->nports; i++) { - brd->vector_mask |= (1 << i); - brd->ports[i].baud_base = 921600; + retval = devm_request_irq(&pdev->dev, brd->irq, mxser_interrupt, + IRQF_SHARED, "mxser", brd); + if (retval) { + dev_err(&pdev->dev, "request irq failed"); + goto err_relbrd; } - /* mxser_initbrd will hook ISR. */ - retval = mxser_initbrd(brd); - if (retval) - goto err_rel3; - - for (i = 0; i < brd->info->nports; i++) { + for (i = 0; i < nports; i++) { tty_dev = tty_port_register_device(&brd->ports[i].port, - mxvar_sdriver, brd->idx + i, &pdev->dev); + mxvar_sdriver, base + i, &pdev->dev); if (IS_ERR(tty_dev)) { retval = PTR_ERR(tty_dev); for (; i > 0; i--) tty_unregister_device(mxvar_sdriver, - brd->idx + i - 1); + base + i - 1); goto err_relbrd; } } @@ -2661,35 +1944,25 @@ static int mxser_probe(struct pci_dev *pdev, return 0; err_relbrd: - for (i = 0; i < brd->info->nports; i++) + for (i = 0; i < nports; i++) tty_port_destroy(&brd->ports[i].port); - free_irq(brd->irq, brd); -err_rel3: - pci_release_region(pdev, 3); err_zero: - brd->info = NULL; - pci_release_region(pdev, 2); -err_dis: - pci_disable_device(pdev); + __clear_bit(brd->idx, mxser_boards); err: return retval; -#else - return -ENODEV; -#endif } static void mxser_remove(struct pci_dev *pdev) { -#ifdef CONFIG_PCI struct mxser_board *brd = pci_get_drvdata(pdev); + unsigned int i, base = brd->idx * MXSER_PORTS_PER_BOARD; - mxser_board_remove(brd); + for (i = 0; i < brd->nports; i++) { + tty_unregister_device(mxvar_sdriver, base + i); + tty_port_destroy(&brd->ports[i].port); + } - pci_release_region(pdev, 2); - pci_release_region(pdev, 3); - pci_disable_device(pdev); - brd->info = NULL; -#endif + __clear_bit(brd->idx, mxser_boards); } static struct pci_driver mxser_driver = { @@ -2701,18 +1974,12 @@ static struct pci_driver mxser_driver = { static int __init mxser_module_init(void) { - struct mxser_board *brd; - struct device *tty_dev; - unsigned int b, i, m; int retval; - mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1); + mxvar_sdriver = alloc_tty_driver(MXSER_PORTS); if (!mxvar_sdriver) return -ENOMEM; - printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n", - MXSER_VERSION); - /* Initialize the tty_driver structure */ mxvar_sdriver->name = "ttyMI"; mxvar_sdriver->major = ttymajor; @@ -2731,57 +1998,10 @@ static int __init mxser_module_init(void) goto err_put; } - /* Start finding ISA boards here */ - for (m = 0, b = 0; b < MXSER_BOARDS; b++) { - if (!ioaddr[b]) - continue; - - brd = &mxser_boards[m]; - retval = mxser_get_ISA_conf(ioaddr[b], brd); - if (retval <= 0) { - brd->info = NULL; - continue; - } - - printk(KERN_INFO "mxser: found MOXA %s board (CAP=0x%lx)\n", - brd->info->name, ioaddr[b]); - - /* mxser_initbrd will hook ISR. */ - if (mxser_initbrd(brd) < 0) { - mxser_release_ISA_res(brd); - brd->info = NULL; - continue; - } - - brd->idx = m * MXSER_PORTS_PER_BOARD; - for (i = 0; i < brd->info->nports; i++) { - tty_dev = tty_port_register_device(&brd->ports[i].port, - mxvar_sdriver, brd->idx + i, NULL); - if (IS_ERR(tty_dev)) { - for (; i > 0; i--) - tty_unregister_device(mxvar_sdriver, - brd->idx + i - 1); - for (i = 0; i < brd->info->nports; i++) - tty_port_destroy(&brd->ports[i].port); - free_irq(brd->irq, brd); - mxser_release_ISA_res(brd); - brd->info = NULL; - break; - } - } - if (brd->info == NULL) - continue; - - m++; - } - retval = pci_register_driver(&mxser_driver); if (retval) { printk(KERN_ERR "mxser: can't register pci driver\n"); - if (!m) { - retval = -ENODEV; - goto err_unr; - } /* else: we have some ISA cards under control */ + goto err_unr; } return 0; @@ -2794,19 +2014,9 @@ err_put: static void __exit mxser_module_exit(void) { - unsigned int i; - pci_unregister_driver(&mxser_driver); - - for (i = 0; i < MXSER_BOARDS; i++) /* ISA remains */ - if (mxser_boards[i].info != NULL) - mxser_board_remove(&mxser_boards[i]); tty_unregister_driver(mxvar_sdriver); put_tty_driver(mxvar_sdriver); - - for (i = 0; i < MXSER_BOARDS; i++) - if (mxser_boards[i].info != NULL) - mxser_release_ISA_res(&mxser_boards[i]); } module_init(mxser_module_init); diff --git a/drivers/tty/mxser.h b/drivers/tty/mxser.h deleted file mode 100644 index e6cb15626567..000000000000 --- a/drivers/tty/mxser.h +++ /dev/null @@ -1,151 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _MXSER_H -#define _MXSER_H - -/* - * Semi-public control interfaces - */ - -/* - * MOXA ioctls - */ - -#define MOXA 0x400 -#define MOXA_GETDATACOUNT (MOXA + 23) -#define MOXA_DIAGNOSE (MOXA + 50) -#define MOXA_CHKPORTENABLE (MOXA + 60) -#define MOXA_HighSpeedOn (MOXA + 61) -#define MOXA_GET_MAJOR (MOXA + 63) -#define MOXA_GETMSTATUS (MOXA + 65) -#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 - -#define MOXA_SDS_RSTICOUNTER (MOXA + 69) -#define MOXA_ASPP_OQUEUE (MOXA + 70) -#define MOXA_ASPP_MON (MOXA + 73) -#define MOXA_ASPP_LSTATUS (MOXA + 74) -#define MOXA_ASPP_MON_EXT (MOXA + 75) -#define MOXA_SET_BAUD_METHOD (MOXA + 76) - -/* --------------------------------------------------- */ - -#define NPPI_NOTIFY_PARITY 0x01 -#define NPPI_NOTIFY_FRAMING 0x02 -#define NPPI_NOTIFY_HW_OVERRUN 0x04 -#define NPPI_NOTIFY_SW_OVERRUN 0x08 -#define NPPI_NOTIFY_BREAK 0x10 - -#define NPPI_NOTIFY_CTSHOLD 0x01 /* Tx hold by CTS low */ -#define NPPI_NOTIFY_DSRHOLD 0x02 /* Tx hold by DSR low */ -#define NPPI_NOTIFY_XOFFHOLD 0x08 /* Tx hold by Xoff received */ -#define NPPI_NOTIFY_XOFFXENT 0x10 /* Xoff Sent */ - -/* follow just for Moxa Must chip define. */ -/* */ -/* when LCR register (offset 0x03) write following value, */ -/* the Must chip will enter enchance mode. And write value */ -/* on EFR (offset 0x02) bit 6,7 to change bank. */ -#define MOXA_MUST_ENTER_ENCHANCE 0xBF - -/* when enhance mode enable, access on 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 */ -/* enchance register bank select and enchance mode setting register */ -/* when LCR register equal to 0xBF */ -#define MOXA_MUST_EFR_REGISTER 0x02 -/* enchance mode enable */ -#define MOXA_MUST_EFR_EFRB_ENABLE 0x10 -/* enchance reister 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 - -/* good data mode enable */ -#define MOXA_MUST_FCR_GDA_MODE_ENABLE 0x20 -/* only good data put into RxFIFO */ -#define MOXA_MUST_FCR_GDA_ONLY_ENABLE 0x10 - -/* enable CTS interrupt */ -#define MOXA_MUST_IER_ECTSI 0x80 -/* enable RTS interrupt */ -#define MOXA_MUST_IER_ERTSI 0x40 -/* enable Xon/Xoff interrupt */ -#define MOXA_MUST_IER_XINT 0x20 -/* enable GDA interrupt */ -#define MOXA_MUST_IER_EGDAI 0x10 - -#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 - -/* software flow control on chip mask value */ -#define MOXA_MUST_EFR_SF_MASK 0x0F -/* send Xon1/Xoff1 */ -#define MOXA_MUST_EFR_SF_TX1 0x08 -/* send Xon2/Xoff2 */ -#define MOXA_MUST_EFR_SF_TX2 0x04 -/* send Xon1,Xon2/Xoff1,Xoff2 */ -#define MOXA_MUST_EFR_SF_TX12 0x0C -/* don't send Xon/Xoff */ -#define MOXA_MUST_EFR_SF_TX_NO 0x00 -/* Tx software flow control mask */ -#define MOXA_MUST_EFR_SF_TX_MASK 0x0C -/* don't receive Xon/Xoff */ -#define MOXA_MUST_EFR_SF_RX_NO 0x00 -/* receive Xon1/Xoff1 */ -#define MOXA_MUST_EFR_SF_RX1 0x02 -/* receive Xon2/Xoff2 */ -#define MOXA_MUST_EFR_SF_RX2 0x01 -/* receive Xon1,Xon2/Xoff1,Xoff2 */ -#define MOXA_MUST_EFR_SF_RX12 0x03 -/* Rx software flow control mask */ -#define MOXA_MUST_EFR_SF_RX_MASK 0x03 - -#endif diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 5fea02cfb0cc..e907b7a5cab5 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -512,7 +512,7 @@ static void gsm_print_packet(const char *hdr, int addr, int cr, */ /** - * gsm_stuff_packet - bytestuff a packet + * gsm_stuff_frame - bytestuff a packet * @input: input buffer * @output: output buffer * @len: length of input @@ -1594,7 +1594,7 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen) } /** - * gsm_dlci_control - data arrived on control channel + * gsm_dlci_command - data arrived on control channel * @dlci: channel * @data: block of bytes received * @len: length of received block @@ -2424,7 +2424,7 @@ static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) } static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) + const char *fp, int count) { struct gsm_mux *gsm = tty->disc_data; char flags = TTY_NORMAL; @@ -2557,6 +2557,8 @@ static void gsmld_write_wakeup(struct tty_struct *tty) * @file: file object * @buf: userspace buffer pointer * @nr: size of I/O + * @cookie: unused + * @offset: unused * * Perform reads for the line discipline. We are guaranteed that the * line discipline will not be closed under us but we may get multiple @@ -2857,6 +2859,7 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc) /* Line discipline for real tty */ static struct tty_ldisc_ops tty_ldisc_packet = { .owner = THIS_MODULE, + .num = N_GSM0710, .name = "n_gsm", .open = gsmld_open, .close = gsmld_close, @@ -3055,7 +3058,7 @@ static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf, return sent; } -static int gsmtty_write_room(struct tty_struct *tty) +static unsigned int gsmtty_write_room(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; if (dlci->state == DLCI_CLOSED) @@ -3063,7 +3066,7 @@ static int gsmtty_write_room(struct tty_struct *tty) return TX_SIZE - kfifo_len(&dlci->fifo); } -static int gsmtty_chars_in_buffer(struct tty_struct *tty) +static unsigned int gsmtty_chars_in_buffer(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; if (dlci->state == DLCI_CLOSED) @@ -3242,7 +3245,7 @@ static const struct tty_operations gsmtty_ops = { static int __init gsm_init(void) { /* Fill in our line protocol discipline, and register it */ - int status = tty_register_ldisc(N_GSM0710, &tty_ldisc_packet); + int status = tty_register_ldisc(&tty_ldisc_packet); if (status != 0) { pr_err("n_gsm: can't register line discipline (err = %d)\n", status); @@ -3251,9 +3254,9 @@ static int __init gsm_init(void) gsm_tty_driver = alloc_tty_driver(256); if (!gsm_tty_driver) { - tty_unregister_ldisc(N_GSM0710); pr_err("gsm_init: tty allocation failed.\n"); - return -EINVAL; + status = -ENOMEM; + goto err_unreg_ldisc; } gsm_tty_driver->driver_name = "gsmtty"; gsm_tty_driver->name = "gsmtty"; @@ -3269,22 +3272,23 @@ static int __init gsm_init(void) tty_set_operations(gsm_tty_driver, &gsmtty_ops); if (tty_register_driver(gsm_tty_driver)) { - put_tty_driver(gsm_tty_driver); - tty_unregister_ldisc(N_GSM0710); pr_err("gsm_init: tty registration failed.\n"); - return -EBUSY; + status = -EBUSY; + goto err_put_driver; } pr_debug("gsm_init: loaded as %d,%d.\n", gsm_tty_driver->major, gsm_tty_driver->minor_start); return 0; +err_put_driver: + put_tty_driver(gsm_tty_driver); +err_unreg_ldisc: + tty_unregister_ldisc(&tty_ldisc_packet); + return status; } static void __exit gsm_exit(void) { - int status = tty_unregister_ldisc(N_GSM0710); - if (status != 0) - pr_err("n_gsm: can't unregister line discipline (err = %d)\n", - status); + tty_unregister_ldisc(&tty_ldisc_packet); tty_unregister_driver(gsm_tty_driver); put_tty_driver(gsm_tty_driver); } diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index b0f33e8ac819..580a37b3fe1b 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -358,7 +358,7 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty) * interpreted as one HDLC frame. */ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, - char *flags, int count) + const char *flags, int count) { register struct n_hdlc *n_hdlc = tty->disc_data; register struct n_hdlc_buf *buf; @@ -411,8 +411,10 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, * n_hdlc_tty_read - Called to retrieve one frame of data (if available) * @tty: pointer to tty instance data * @file: pointer to open file object - * @buf: pointer to returned data buffer + * @kbuf: pointer to returned data buffer * @nr: size of returned data buffer + * @cookie: stored rbuf from previous run + * @offset: offset into the data buffer * * Returns the number of bytes returned or error code. */ @@ -788,6 +790,7 @@ static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list) static struct tty_ldisc_ops n_hdlc_ldisc = { .owner = THIS_MODULE, + .num = N_HDLC, .name = "hdlc", .open = n_hdlc_tty_open, .close = n_hdlc_tty_close, @@ -807,7 +810,7 @@ static int __init n_hdlc_init(void) /* range check maxframe arg */ maxframe = clamp(maxframe, 4096, MAX_HDLC_FRAME_SIZE); - status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc); + status = tty_register_ldisc(&n_hdlc_ldisc); if (!status) pr_info("N_HDLC line discipline registered with maxframe=%d\n", maxframe); @@ -821,14 +824,7 @@ static int __init n_hdlc_init(void) static void __exit n_hdlc_exit(void) { - /* Release tty registration of line discipline */ - int status = tty_unregister_ldisc(N_HDLC); - - if (status) - pr_err("N_HDLC: can't unregister line discipline (err = %d)\n", - status); - else - pr_info("N_HDLC: line discipline unregistered\n"); + tty_unregister_ldisc(&n_hdlc_ldisc); } module_init(n_hdlc_init); diff --git a/drivers/tty/n_null.c b/drivers/tty/n_null.c index b8f67b5f1ef8..f913b665af72 100644 --- a/drivers/tty/n_null.c +++ b/drivers/tty/n_null.c @@ -33,13 +33,14 @@ static ssize_t n_null_write(struct tty_struct *tty, struct file *file, } static void n_null_receivebuf(struct tty_struct *tty, - const unsigned char *cp, char *fp, + const unsigned char *cp, const char *fp, int cnt) { } static struct tty_ldisc_ops null_ldisc = { .owner = THIS_MODULE, + .num = N_NULL, .name = "n_null", .open = n_null_open, .close = n_null_close, @@ -50,13 +51,13 @@ static struct tty_ldisc_ops null_ldisc = { static int __init n_null_init(void) { - BUG_ON(tty_register_ldisc(N_NULL, &null_ldisc)); + BUG_ON(tty_register_ldisc(&null_ldisc)); return 0; } static void __exit n_null_exit(void) { - tty_unregister_ldisc(N_NULL); + tty_unregister_ldisc(&null_ldisc); } module_init(n_null_init); diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c deleted file mode 100644 index 2eb76ea1d88d..000000000000 --- a/drivers/tty/n_r3964.c +++ /dev/null @@ -1,1283 +0,0 @@ -// SPDX-License-Identifier: GPL-1.0+ -/* r3964 linediscipline for linux - * - * ----------------------------------------------------------- - * Copyright by - * Philips Automation Projects - * Kassel (Germany) - * ----------------------------------------------------------- - * Author: - * L. Haag - * - * $Log: n_r3964.c,v $ - * Revision 1.10 2001/03/18 13:02:24 dwmw2 - * Fix timer usage, use spinlocks properly. - * - * Revision 1.9 2001/03/18 12:52:14 dwmw2 - * Merge changes in 2.4.2 - * - * Revision 1.8 2000/03/23 14:14:54 dwmw2 - * Fix race in sleeping in r3964_read() - * - * Revision 1.7 1999/28/08 11:41:50 dwmw2 - * Port to 2.3 kernel - * - * Revision 1.6 1998/09/30 00:40:40 dwmw2 - * Fixed compilation on 2.0.x kernels - * Updated to newly registered tty-ldisc number 9 - * - * Revision 1.5 1998/09/04 21:57:36 dwmw2 - * Signal handling bug fixes, port to 2.1.x. - * - * Revision 1.4 1998/04/02 20:26:59 lhaag - * select, blocking, ... - * - * Revision 1.3 1998/02/12 18:58:43 root - * fixed some memory leaks - * calculation of checksum characters - * - * Revision 1.2 1998/02/07 13:03:34 root - * ioctl read_telegram - * - * Revision 1.1 1998/02/06 19:21:03 root - * Initial revision - * - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/types.h> -#include <linux/fcntl.h> -#include <linux/interrupt.h> -#include <linux/ptrace.h> -#include <linux/ioport.h> -#include <linux/in.h> -#include <linux/slab.h> -#include <linux/tty.h> -#include <linux/errno.h> -#include <linux/string.h> /* used in new tty drivers */ -#include <linux/signal.h> /* used in new tty drivers */ -#include <linux/ioctl.h> -#include <linux/n_r3964.h> -#include <linux/poll.h> -#include <linux/init.h> -#include <linux/uaccess.h> - -/*#define DEBUG_QUEUE*/ - -/* Log successful handshake and protocol operations */ -/*#define DEBUG_PROTO_S*/ - -/* Log handshake and protocol errors: */ -/*#define DEBUG_PROTO_E*/ - -/* Log Linediscipline operations (open, close, read, write...): */ -/*#define DEBUG_LDISC*/ - -/* Log module and memory operations (init, cleanup; kmalloc, kfree): */ -/*#define DEBUG_MODUL*/ - -/* Macro helpers for debug output: */ -#define TRACE(format, args...) printk("r3964: " format "\n" , ## args) - -#ifdef DEBUG_MODUL -#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args) -#else -#define TRACE_M(fmt, arg...) do {} while (0) -#endif -#ifdef DEBUG_PROTO_S -#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args) -#else -#define TRACE_PS(fmt, arg...) do {} while (0) -#endif -#ifdef DEBUG_PROTO_E -#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args) -#else -#define TRACE_PE(fmt, arg...) do {} while (0) -#endif -#ifdef DEBUG_LDISC -#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args) -#else -#define TRACE_L(fmt, arg...) do {} while (0) -#endif -#ifdef DEBUG_QUEUE -#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args) -#else -#define TRACE_Q(fmt, arg...) do {} while (0) -#endif -static void add_tx_queue(struct r3964_info *, struct r3964_block_header *); -static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code); -static void put_char(struct r3964_info *pInfo, unsigned char ch); -static void trigger_transmit(struct r3964_info *pInfo); -static void retry_transmit(struct r3964_info *pInfo); -static void transmit_block(struct r3964_info *pInfo); -static void receive_char(struct r3964_info *pInfo, const unsigned char c); -static void receive_error(struct r3964_info *pInfo, const char flag); -static void on_timeout(struct timer_list *t); -static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg); -static int read_telegram(struct r3964_info *pInfo, struct pid *pid, - unsigned char __user * buf); -static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, - int error_code, struct r3964_block_header *pBlock); -static struct r3964_message *remove_msg(struct r3964_info *pInfo, - struct r3964_client_info *pClient); -static void remove_client_block(struct r3964_info *pInfo, - struct r3964_client_info *pClient); - -static int r3964_open(struct tty_struct *tty); -static void r3964_close(struct tty_struct *tty); -static ssize_t r3964_read(struct tty_struct *tty, struct file *file, - void *cookie, unsigned char *buf, size_t nr); -static ssize_t r3964_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr); -static int r3964_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg); -#ifdef CONFIG_COMPAT -static int r3964_compat_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg); -#endif -static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old); -static __poll_t r3964_poll(struct tty_struct *tty, struct file *file, - struct poll_table_struct *wait); -static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count); - -static struct tty_ldisc_ops tty_ldisc_N_R3964 = { - .owner = THIS_MODULE, - .name = "R3964", - .open = r3964_open, - .close = r3964_close, - .read = r3964_read, - .write = r3964_write, - .ioctl = r3964_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = r3964_compat_ioctl, -#endif - .set_termios = r3964_set_termios, - .poll = r3964_poll, - .receive_buf = r3964_receive_buf, -}; - -static void dump_block(const unsigned char *block, unsigned int length) -{ - unsigned int i, j; - char linebuf[16 * 3 + 1]; - - for (i = 0; i < length; i += 16) { - for (j = 0; (j < 16) && (j + i < length); j++) { - sprintf(linebuf + 3 * j, "%02x ", block[i + j]); - } - linebuf[3 * j] = '\0'; - TRACE_PS("%s", linebuf); - } -} - -/************************************************************* - * Driver initialisation - *************************************************************/ - -/************************************************************* - * Module support routines - *************************************************************/ - -static void __exit r3964_exit(void) -{ - int status; - - TRACE_M("cleanup_module()"); - - status = tty_unregister_ldisc(N_R3964); - - if (status != 0) { - printk(KERN_ERR "r3964: error unregistering linediscipline: " - "%d\n", status); - } else { - TRACE_L("linediscipline successfully unregistered"); - } -} - -static int __init r3964_init(void) -{ - int status; - - printk("r3964: Philips r3964 Driver $Revision: 1.10 $\n"); - - /* - * Register the tty line discipline - */ - - status = tty_register_ldisc(N_R3964, &tty_ldisc_N_R3964); - if (status == 0) { - TRACE_L("line discipline %d registered", N_R3964); - TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags, - tty_ldisc_N_R3964.num); - TRACE_L("open=%p", tty_ldisc_N_R3964.open); - TRACE_L("tty_ldisc_N_R3964 = %p", &tty_ldisc_N_R3964); - } else { - printk(KERN_ERR "r3964: error registering line discipline: " - "%d\n", status); - } - return status; -} - -module_init(r3964_init); -module_exit(r3964_exit); - -/************************************************************* - * Protocol implementation routines - *************************************************************/ - -static void add_tx_queue(struct r3964_info *pInfo, - struct r3964_block_header *pHeader) -{ - unsigned long flags; - - spin_lock_irqsave(&pInfo->lock, flags); - - pHeader->next = NULL; - - if (pInfo->tx_last == NULL) { - pInfo->tx_first = pInfo->tx_last = pHeader; - } else { - pInfo->tx_last->next = pHeader; - pInfo->tx_last = pHeader; - } - - spin_unlock_irqrestore(&pInfo->lock, flags); - - TRACE_Q("add_tx_queue %p, length %d, tx_first = %p", - pHeader, pHeader->length, pInfo->tx_first); -} - -static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code) -{ - struct r3964_block_header *pHeader; - unsigned long flags; -#ifdef DEBUG_QUEUE - struct r3964_block_header *pDump; -#endif - - pHeader = pInfo->tx_first; - - if (pHeader == NULL) - return; - -#ifdef DEBUG_QUEUE - printk("r3964: remove_from_tx_queue: %p, length %u - ", - pHeader, pHeader->length); - for (pDump = pHeader; pDump; pDump = pDump->next) - printk("%p ", pDump); - printk("\n"); -#endif - - if (pHeader->owner) { - if (error_code) { - add_msg(pHeader->owner, R3964_MSG_ACK, 0, - error_code, NULL); - } else { - add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length, - error_code, NULL); - } - wake_up_interruptible(&pInfo->tty->read_wait); - } - - spin_lock_irqsave(&pInfo->lock, flags); - - pInfo->tx_first = pHeader->next; - if (pInfo->tx_first == NULL) { - pInfo->tx_last = NULL; - } - - spin_unlock_irqrestore(&pInfo->lock, flags); - - kfree(pHeader); - TRACE_M("remove_from_tx_queue - kfree %p", pHeader); - - TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p", - pInfo->tx_first, pInfo->tx_last); -} - -static void add_rx_queue(struct r3964_info *pInfo, - struct r3964_block_header *pHeader) -{ - unsigned long flags; - - spin_lock_irqsave(&pInfo->lock, flags); - - pHeader->next = NULL; - - if (pInfo->rx_last == NULL) { - pInfo->rx_first = pInfo->rx_last = pHeader; - } else { - pInfo->rx_last->next = pHeader; - pInfo->rx_last = pHeader; - } - pInfo->blocks_in_rx_queue++; - - spin_unlock_irqrestore(&pInfo->lock, flags); - - TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d", - pHeader, pHeader->length, - pInfo->rx_first, pInfo->blocks_in_rx_queue); -} - -static void remove_from_rx_queue(struct r3964_info *pInfo, - struct r3964_block_header *pHeader) -{ - unsigned long flags; - struct r3964_block_header *pFind; - - if (pHeader == NULL) - return; - - TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d", - pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue); - TRACE_Q("remove_from_rx_queue: %p, length %u", - pHeader, pHeader->length); - - spin_lock_irqsave(&pInfo->lock, flags); - - if (pInfo->rx_first == pHeader) { - /* Remove the first block in the linked list: */ - pInfo->rx_first = pHeader->next; - - if (pInfo->rx_first == NULL) { - pInfo->rx_last = NULL; - } - pInfo->blocks_in_rx_queue--; - } else { - /* Find block to remove: */ - for (pFind = pInfo->rx_first; pFind; pFind = pFind->next) { - if (pFind->next == pHeader) { - /* Got it. */ - pFind->next = pHeader->next; - pInfo->blocks_in_rx_queue--; - if (pFind->next == NULL) { - /* Oh, removed the last one! */ - pInfo->rx_last = pFind; - } - break; - } - } - } - - spin_unlock_irqrestore(&pInfo->lock, flags); - - kfree(pHeader); - TRACE_M("remove_from_rx_queue - kfree %p", pHeader); - - TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d", - pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue); -} - -static void put_char(struct r3964_info *pInfo, unsigned char ch) -{ - struct tty_struct *tty = pInfo->tty; - /* FIXME: put_char should not be called from an IRQ */ - tty_put_char(tty, ch); - pInfo->bcc ^= ch; -} - -static void flush(struct r3964_info *pInfo) -{ - struct tty_struct *tty = pInfo->tty; - - if (tty == NULL || tty->ops->flush_chars == NULL) - return; - tty->ops->flush_chars(tty); -} - -static void trigger_transmit(struct r3964_info *pInfo) -{ - unsigned long flags; - - spin_lock_irqsave(&pInfo->lock, flags); - - if ((pInfo->state == R3964_IDLE) && (pInfo->tx_first != NULL)) { - pInfo->state = R3964_TX_REQUEST; - pInfo->nRetry = 0; - pInfo->flags &= ~R3964_ERROR; - mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ); - - spin_unlock_irqrestore(&pInfo->lock, flags); - - TRACE_PS("trigger_transmit - sent STX"); - - put_char(pInfo, STX); - flush(pInfo); - - pInfo->bcc = 0; - } else { - spin_unlock_irqrestore(&pInfo->lock, flags); - } -} - -static void retry_transmit(struct r3964_info *pInfo) -{ - if (pInfo->nRetry < R3964_MAX_RETRIES) { - TRACE_PE("transmission failed. Retry #%d", pInfo->nRetry); - pInfo->bcc = 0; - put_char(pInfo, STX); - flush(pInfo); - pInfo->state = R3964_TX_REQUEST; - pInfo->nRetry++; - mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ); - } else { - TRACE_PE("transmission failed after %d retries", - R3964_MAX_RETRIES); - - remove_from_tx_queue(pInfo, R3964_TX_FAIL); - - put_char(pInfo, NAK); - flush(pInfo); - pInfo->state = R3964_IDLE; - - trigger_transmit(pInfo); - } -} - -static void transmit_block(struct r3964_info *pInfo) -{ - struct tty_struct *tty = pInfo->tty; - struct r3964_block_header *pBlock = pInfo->tx_first; - int room = 0; - - if (tty == NULL || pBlock == NULL) { - return; - } - - room = tty_write_room(tty); - - TRACE_PS("transmit_block %p, room %d, length %d", - pBlock, room, pBlock->length); - - while (pInfo->tx_position < pBlock->length) { - if (room < 2) - break; - - if (pBlock->data[pInfo->tx_position] == DLE) { - /* send additional DLE char: */ - put_char(pInfo, DLE); - } - put_char(pInfo, pBlock->data[pInfo->tx_position++]); - - room--; - } - - if ((pInfo->tx_position == pBlock->length) && (room >= 3)) { - put_char(pInfo, DLE); - put_char(pInfo, ETX); - if (pInfo->flags & R3964_BCC) { - put_char(pInfo, pInfo->bcc); - } - pInfo->state = R3964_WAIT_FOR_TX_ACK; - mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ); - } - flush(pInfo); -} - -static void on_receive_block(struct r3964_info *pInfo) -{ - unsigned int length; - struct r3964_client_info *pClient; - struct r3964_block_header *pBlock; - - length = pInfo->rx_position; - - /* compare byte checksum characters: */ - if (pInfo->flags & R3964_BCC) { - if (pInfo->bcc != pInfo->last_rx) { - TRACE_PE("checksum error - got %x but expected %x", - pInfo->last_rx, pInfo->bcc); - pInfo->flags |= R3964_CHECKSUM; - } - } - - /* check for errors (parity, overrun,...): */ - if (pInfo->flags & R3964_ERROR) { - TRACE_PE("on_receive_block - transmission failed error %x", - pInfo->flags & R3964_ERROR); - - put_char(pInfo, NAK); - flush(pInfo); - if (pInfo->nRetry < R3964_MAX_RETRIES) { - pInfo->state = R3964_WAIT_FOR_RX_REPEAT; - pInfo->nRetry++; - mod_timer(&pInfo->tmr, jiffies + R3964_TO_RX_PANIC); - } else { - TRACE_PE("on_receive_block - failed after max retries"); - pInfo->state = R3964_IDLE; - } - return; - } - - /* received block; submit DLE: */ - put_char(pInfo, DLE); - flush(pInfo); - del_timer_sync(&pInfo->tmr); - TRACE_PS(" rx success: got %d chars", length); - - /* prepare struct r3964_block_header: */ - pBlock = kmalloc(length + sizeof(struct r3964_block_header), - GFP_KERNEL); - TRACE_M("on_receive_block - kmalloc %p", pBlock); - - if (pBlock == NULL) - return; - - pBlock->length = length; - pBlock->data = ((unsigned char *)pBlock) + - sizeof(struct r3964_block_header); - pBlock->locks = 0; - pBlock->next = NULL; - pBlock->owner = NULL; - - memcpy(pBlock->data, pInfo->rx_buf, length); - - /* queue block into rx_queue: */ - add_rx_queue(pInfo, pBlock); - - /* notify attached client processes: */ - for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) { - if (pClient->sig_flags & R3964_SIG_DATA) { - add_msg(pClient, R3964_MSG_DATA, length, R3964_OK, - pBlock); - } - } - wake_up_interruptible(&pInfo->tty->read_wait); - - pInfo->state = R3964_IDLE; - - trigger_transmit(pInfo); -} - -static void receive_char(struct r3964_info *pInfo, const unsigned char c) -{ - switch (pInfo->state) { - case R3964_TX_REQUEST: - if (c == DLE) { - TRACE_PS("TX_REQUEST - got DLE"); - - pInfo->state = R3964_TRANSMITTING; - pInfo->tx_position = 0; - - transmit_block(pInfo); - } else if (c == STX) { - if (pInfo->nRetry == 0) { - TRACE_PE("TX_REQUEST - init conflict"); - if (pInfo->priority == R3964_SLAVE) { - goto start_receiving; - } - } else { - TRACE_PE("TX_REQUEST - secondary init " - "conflict!? Switching to SLAVE mode " - "for next rx."); - goto start_receiving; - } - } else { - TRACE_PE("TX_REQUEST - char != DLE: %x", c); - retry_transmit(pInfo); - } - break; - case R3964_TRANSMITTING: - if (c == NAK) { - TRACE_PE("TRANSMITTING - got NAK"); - retry_transmit(pInfo); - } else { - TRACE_PE("TRANSMITTING - got invalid char"); - - pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY; - mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ); - } - break; - case R3964_WAIT_FOR_TX_ACK: - if (c == DLE) { - TRACE_PS("WAIT_FOR_TX_ACK - got DLE"); - remove_from_tx_queue(pInfo, R3964_OK); - - pInfo->state = R3964_IDLE; - trigger_transmit(pInfo); - } else { - retry_transmit(pInfo); - } - break; - case R3964_WAIT_FOR_RX_REPEAT: - case R3964_IDLE: - if (c == STX) { - /* Prevent rx_queue from overflow: */ - if (pInfo->blocks_in_rx_queue >= - R3964_MAX_BLOCKS_IN_RX_QUEUE) { - TRACE_PE("IDLE - got STX but no space in " - "rx_queue!"); - pInfo->state = R3964_WAIT_FOR_RX_BUF; - mod_timer(&pInfo->tmr, - jiffies + R3964_TO_NO_BUF); - break; - } -start_receiving: - /* Ok, start receiving: */ - TRACE_PS("IDLE - got STX"); - pInfo->rx_position = 0; - pInfo->last_rx = 0; - pInfo->flags &= ~R3964_ERROR; - pInfo->state = R3964_RECEIVING; - mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ); - pInfo->nRetry = 0; - put_char(pInfo, DLE); - flush(pInfo); - pInfo->bcc = 0; - } - break; - case R3964_RECEIVING: - if (pInfo->rx_position < RX_BUF_SIZE) { - pInfo->bcc ^= c; - - if (c == DLE) { - if (pInfo->last_rx == DLE) { - pInfo->last_rx = 0; - goto char_to_buf; - } - pInfo->last_rx = DLE; - break; - } else if ((c == ETX) && (pInfo->last_rx == DLE)) { - if (pInfo->flags & R3964_BCC) { - pInfo->state = R3964_WAIT_FOR_BCC; - mod_timer(&pInfo->tmr, - jiffies + R3964_TO_ZVZ); - } else { - on_receive_block(pInfo); - } - } else { - pInfo->last_rx = c; -char_to_buf: - pInfo->rx_buf[pInfo->rx_position++] = c; - mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ); - } - } - /* else: overflow-msg? BUF_SIZE>MTU; should not happen? */ - break; - case R3964_WAIT_FOR_BCC: - pInfo->last_rx = c; - on_receive_block(pInfo); - break; - } -} - -static void receive_error(struct r3964_info *pInfo, const char flag) -{ - switch (flag) { - case TTY_NORMAL: - break; - case TTY_BREAK: - TRACE_PE("received break"); - pInfo->flags |= R3964_BREAK; - break; - case TTY_PARITY: - TRACE_PE("parity error"); - pInfo->flags |= R3964_PARITY; - break; - case TTY_FRAME: - TRACE_PE("frame error"); - pInfo->flags |= R3964_FRAME; - break; - case TTY_OVERRUN: - TRACE_PE("frame overrun"); - pInfo->flags |= R3964_OVERRUN; - break; - default: - TRACE_PE("receive_error - unknown flag %d", flag); - pInfo->flags |= R3964_UNKNOWN; - break; - } -} - -static void on_timeout(struct timer_list *t) -{ - struct r3964_info *pInfo = from_timer(pInfo, t, tmr); - - switch (pInfo->state) { - case R3964_TX_REQUEST: - TRACE_PE("TX_REQUEST - timeout"); - retry_transmit(pInfo); - break; - case R3964_WAIT_ZVZ_BEFORE_TX_RETRY: - put_char(pInfo, NAK); - flush(pInfo); - retry_transmit(pInfo); - break; - case R3964_WAIT_FOR_TX_ACK: - TRACE_PE("WAIT_FOR_TX_ACK - timeout"); - retry_transmit(pInfo); - break; - case R3964_WAIT_FOR_RX_BUF: - TRACE_PE("WAIT_FOR_RX_BUF - timeout"); - put_char(pInfo, NAK); - flush(pInfo); - pInfo->state = R3964_IDLE; - break; - case R3964_RECEIVING: - TRACE_PE("RECEIVING - timeout after %d chars", - pInfo->rx_position); - put_char(pInfo, NAK); - flush(pInfo); - pInfo->state = R3964_IDLE; - break; - case R3964_WAIT_FOR_RX_REPEAT: - TRACE_PE("WAIT_FOR_RX_REPEAT - timeout"); - pInfo->state = R3964_IDLE; - break; - case R3964_WAIT_FOR_BCC: - TRACE_PE("WAIT_FOR_BCC - timeout"); - put_char(pInfo, NAK); - flush(pInfo); - pInfo->state = R3964_IDLE; - break; - } -} - -static struct r3964_client_info *findClient(struct r3964_info *pInfo, - struct pid *pid) -{ - struct r3964_client_info *pClient; - - for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) { - if (pClient->pid == pid) { - return pClient; - } - } - return NULL; -} - -static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg) -{ - struct r3964_client_info *pClient; - struct r3964_client_info **ppClient; - struct r3964_message *pMsg; - - if ((arg & R3964_SIG_ALL) == 0) { - /* Remove client from client list */ - for (ppClient = &pInfo->firstClient; *ppClient; - ppClient = &(*ppClient)->next) { - pClient = *ppClient; - - if (pClient->pid == pid) { - TRACE_PS("removing client %d from client list", - pid_nr(pid)); - *ppClient = pClient->next; - while (pClient->msg_count) { - pMsg = remove_msg(pInfo, pClient); - if (pMsg) { - kfree(pMsg); - TRACE_M("enable_signals - msg " - "kfree %p", pMsg); - } - } - put_pid(pClient->pid); - kfree(pClient); - TRACE_M("enable_signals - kfree %p", pClient); - return 0; - } - } - return -EINVAL; - } else { - pClient = findClient(pInfo, pid); - if (pClient) { - /* update signal options */ - pClient->sig_flags = arg; - } else { - /* add client to client list */ - pClient = kmalloc(sizeof(struct r3964_client_info), - GFP_KERNEL); - TRACE_M("enable_signals - kmalloc %p", pClient); - if (pClient == NULL) - return -ENOMEM; - - TRACE_PS("add client %d to client list", pid_nr(pid)); - spin_lock_init(&pClient->lock); - pClient->sig_flags = arg; - pClient->pid = get_pid(pid); - pClient->next = pInfo->firstClient; - pClient->first_msg = NULL; - pClient->last_msg = NULL; - pClient->next_block_to_read = NULL; - pClient->msg_count = 0; - pInfo->firstClient = pClient; - } - } - - return 0; -} - -static int read_telegram(struct r3964_info *pInfo, struct pid *pid, - unsigned char __user * buf) -{ - struct r3964_client_info *pClient; - struct r3964_block_header *block; - - if (!buf) { - return -EINVAL; - } - - pClient = findClient(pInfo, pid); - if (pClient == NULL) { - return -EINVAL; - } - - block = pClient->next_block_to_read; - if (!block) { - return 0; - } else { - if (copy_to_user(buf, block->data, block->length)) - return -EFAULT; - - remove_client_block(pInfo, pClient); - return block->length; - } - - return -EINVAL; -} - -static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg, - int error_code, struct r3964_block_header *pBlock) -{ - struct r3964_message *pMsg; - unsigned long flags; - - if (pClient->msg_count < R3964_MAX_MSG_COUNT - 1) { -queue_the_message: - - pMsg = kmalloc(sizeof(struct r3964_message), - error_code ? GFP_ATOMIC : GFP_KERNEL); - TRACE_M("add_msg - kmalloc %p", pMsg); - if (pMsg == NULL) { - return; - } - - spin_lock_irqsave(&pClient->lock, flags); - - pMsg->msg_id = msg_id; - pMsg->arg = arg; - pMsg->error_code = error_code; - pMsg->block = pBlock; - pMsg->next = NULL; - - if (pClient->last_msg == NULL) { - pClient->first_msg = pClient->last_msg = pMsg; - } else { - pClient->last_msg->next = pMsg; - pClient->last_msg = pMsg; - } - - pClient->msg_count++; - - if (pBlock != NULL) { - pBlock->locks++; - } - spin_unlock_irqrestore(&pClient->lock, flags); - } else { - if ((pClient->last_msg->msg_id == R3964_MSG_ACK) - && (pClient->last_msg->error_code == R3964_OVERFLOW)) { - pClient->last_msg->arg++; - TRACE_PE("add_msg - inc prev OVERFLOW-msg"); - } else { - msg_id = R3964_MSG_ACK; - arg = 0; - error_code = R3964_OVERFLOW; - pBlock = NULL; - TRACE_PE("add_msg - queue OVERFLOW-msg"); - goto queue_the_message; - } - } - /* Send SIGIO signal to client process: */ - if (pClient->sig_flags & R3964_USE_SIGIO) { - kill_pid(pClient->pid, SIGIO, 1); - } -} - -static struct r3964_message *remove_msg(struct r3964_info *pInfo, - struct r3964_client_info *pClient) -{ - struct r3964_message *pMsg = NULL; - unsigned long flags; - - if (pClient->first_msg) { - spin_lock_irqsave(&pClient->lock, flags); - - pMsg = pClient->first_msg; - pClient->first_msg = pMsg->next; - if (pClient->first_msg == NULL) { - pClient->last_msg = NULL; - } - - pClient->msg_count--; - if (pMsg->block) { - remove_client_block(pInfo, pClient); - pClient->next_block_to_read = pMsg->block; - } - spin_unlock_irqrestore(&pClient->lock, flags); - } - return pMsg; -} - -static void remove_client_block(struct r3964_info *pInfo, - struct r3964_client_info *pClient) -{ - struct r3964_block_header *block; - - TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid)); - - block = pClient->next_block_to_read; - if (block) { - block->locks--; - if (block->locks == 0) { - remove_from_rx_queue(pInfo, block); - } - } - pClient->next_block_to_read = NULL; -} - -/************************************************************* - * Line discipline routines - *************************************************************/ - -static int r3964_open(struct tty_struct *tty) -{ - struct r3964_info *pInfo; - - TRACE_L("open"); - TRACE_L("tty=%p, PID=%d, disc_data=%p", - tty, current->pid, tty->disc_data); - - pInfo = kmalloc(sizeof(struct r3964_info), GFP_KERNEL); - TRACE_M("r3964_open - info kmalloc %p", pInfo); - - if (!pInfo) { - printk(KERN_ERR "r3964: failed to alloc info structure\n"); - return -ENOMEM; - } - - pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL); - TRACE_M("r3964_open - rx_buf kmalloc %p", pInfo->rx_buf); - - if (!pInfo->rx_buf) { - printk(KERN_ERR "r3964: failed to alloc receive buffer\n"); - kfree(pInfo); - TRACE_M("r3964_open - info kfree %p", pInfo); - return -ENOMEM; - } - - pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL); - TRACE_M("r3964_open - tx_buf kmalloc %p", pInfo->tx_buf); - - if (!pInfo->tx_buf) { - printk(KERN_ERR "r3964: failed to alloc transmit buffer\n"); - kfree(pInfo->rx_buf); - TRACE_M("r3964_open - rx_buf kfree %p", pInfo->rx_buf); - kfree(pInfo); - TRACE_M("r3964_open - info kfree %p", pInfo); - return -ENOMEM; - } - - spin_lock_init(&pInfo->lock); - mutex_init(&pInfo->read_lock); - pInfo->tty = tty; - pInfo->priority = R3964_MASTER; - pInfo->rx_first = pInfo->rx_last = NULL; - pInfo->tx_first = pInfo->tx_last = NULL; - pInfo->rx_position = 0; - pInfo->tx_position = 0; - pInfo->last_rx = 0; - pInfo->blocks_in_rx_queue = 0; - pInfo->firstClient = NULL; - pInfo->state = R3964_IDLE; - pInfo->flags = R3964_DEBUG; - pInfo->nRetry = 0; - - tty->disc_data = pInfo; - tty->receive_room = 65536; - - timer_setup(&pInfo->tmr, on_timeout, 0); - - return 0; -} - -static void r3964_close(struct tty_struct *tty) -{ - struct r3964_info *pInfo = tty->disc_data; - struct r3964_client_info *pClient, *pNext; - struct r3964_message *pMsg; - struct r3964_block_header *pHeader, *pNextHeader; - unsigned long flags; - - TRACE_L("close"); - - /* - * Make sure that our task queue isn't activated. If it - * is, take it out of the linked list. - */ - del_timer_sync(&pInfo->tmr); - - /* Remove client-structs and message queues: */ - pClient = pInfo->firstClient; - while (pClient) { - pNext = pClient->next; - while (pClient->msg_count) { - pMsg = remove_msg(pInfo, pClient); - if (pMsg) { - kfree(pMsg); - TRACE_M("r3964_close - msg kfree %p", pMsg); - } - } - put_pid(pClient->pid); - kfree(pClient); - TRACE_M("r3964_close - client kfree %p", pClient); - pClient = pNext; - } - /* Remove jobs from tx_queue: */ - spin_lock_irqsave(&pInfo->lock, flags); - pHeader = pInfo->tx_first; - pInfo->tx_first = pInfo->tx_last = NULL; - spin_unlock_irqrestore(&pInfo->lock, flags); - - while (pHeader) { - pNextHeader = pHeader->next; - kfree(pHeader); - pHeader = pNextHeader; - } - - /* Free buffers: */ - kfree(pInfo->rx_buf); - TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf); - kfree(pInfo->tx_buf); - TRACE_M("r3964_close - tx_buf kfree %p", pInfo->tx_buf); - kfree(pInfo); - TRACE_M("r3964_close - info kfree %p", pInfo); -} - -static ssize_t r3964_read(struct tty_struct *tty, struct file *file, - unsigned char *kbuf, size_t nr, - void **cookie, unsigned long offset) -{ - struct r3964_info *pInfo = tty->disc_data; - struct r3964_client_info *pClient; - struct r3964_message *pMsg; - struct r3964_client_message theMsg; - int ret; - - TRACE_L("read()"); - - /* - * Internal serialization of reads. - */ - if (file->f_flags & O_NONBLOCK) { - if (!mutex_trylock(&pInfo->read_lock)) - return -EAGAIN; - } else { - if (mutex_lock_interruptible(&pInfo->read_lock)) - return -ERESTARTSYS; - } - - pClient = findClient(pInfo, task_pid(current)); - if (pClient) { - pMsg = remove_msg(pInfo, pClient); - if (pMsg == NULL) { - /* no messages available. */ - if (tty_io_nonblock(tty, file)) { - ret = -EAGAIN; - goto unlock; - } - /* block until there is a message: */ - wait_event_interruptible(tty->read_wait, - (pMsg = remove_msg(pInfo, pClient))); - } - - /* If we still haven't got a message, we must have been signalled */ - - if (!pMsg) { - ret = -EINTR; - goto unlock; - } - - /* deliver msg to client process: */ - theMsg.msg_id = pMsg->msg_id; - theMsg.arg = pMsg->arg; - theMsg.error_code = pMsg->error_code; - ret = sizeof(struct r3964_client_message); - - kfree(pMsg); - TRACE_M("r3964_read - msg kfree %p", pMsg); - - memcpy(kbuf, &theMsg, ret); - - TRACE_PS("read - return %d", ret); - goto unlock; - } - ret = -EPERM; -unlock: - mutex_unlock(&pInfo->read_lock); - return ret; -} - -static ssize_t r3964_write(struct tty_struct *tty, struct file *file, - const unsigned char *data, size_t count) -{ - struct r3964_info *pInfo = tty->disc_data; - struct r3964_block_header *pHeader; - struct r3964_client_info *pClient; - unsigned char *new_data; - - TRACE_L("write request, %d characters", count); -/* - * Verify the pointers - */ - - if (!pInfo) - return -EIO; - -/* - * Ensure that the caller does not wish to send too much. - */ - if (count > R3964_MTU) { - if (pInfo->flags & R3964_DEBUG) { - TRACE_L(KERN_WARNING "r3964_write: truncating user " - "packet from %u to mtu %d", count, R3964_MTU); - } - count = R3964_MTU; - } -/* - * Allocate a buffer for the data and copy it from the buffer with header prepended - */ - new_data = kmalloc(count + sizeof(struct r3964_block_header), - GFP_KERNEL); - TRACE_M("r3964_write - kmalloc %p", new_data); - if (new_data == NULL) { - if (pInfo->flags & R3964_DEBUG) { - printk(KERN_ERR "r3964_write: no memory\n"); - } - return -ENOSPC; - } - - pHeader = (struct r3964_block_header *)new_data; - pHeader->data = new_data + sizeof(struct r3964_block_header); - pHeader->length = count; - pHeader->locks = 0; - pHeader->owner = NULL; - - pClient = findClient(pInfo, task_pid(current)); - if (pClient) { - pHeader->owner = pClient; - } - - memcpy(pHeader->data, data, count); /* We already verified this */ - - if (pInfo->flags & R3964_DEBUG) { - dump_block(pHeader->data, count); - } - -/* - * Add buffer to transmit-queue: - */ - add_tx_queue(pInfo, pHeader); - trigger_transmit(pInfo); - - return 0; -} - -static int r3964_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct r3964_info *pInfo = tty->disc_data; - if (pInfo == NULL) - return -EINVAL; - switch (cmd) { - case R3964_ENABLE_SIGNALS: - return enable_signals(pInfo, task_pid(current), arg); - case R3964_SETPRIORITY: - if (arg < R3964_MASTER || arg > R3964_SLAVE) - return -EINVAL; - pInfo->priority = arg & 0xff; - return 0; - case R3964_USE_BCC: - if (arg) - pInfo->flags |= R3964_BCC; - else - pInfo->flags &= ~R3964_BCC; - return 0; - case R3964_READ_TELEGRAM: - return read_telegram(pInfo, task_pid(current), - (unsigned char __user *)arg); - default: - return -ENOIOCTLCMD; - } -} - -#ifdef CONFIG_COMPAT -static int r3964_compat_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case R3964_ENABLE_SIGNALS: - case R3964_SETPRIORITY: - case R3964_USE_BCC: - return r3964_ioctl(tty, file, cmd, arg); - default: - return -ENOIOCTLCMD; - } -} -#endif - -static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old) -{ - TRACE_L("set_termios"); -} - -/* Called without the kernel lock held - fine */ -static __poll_t r3964_poll(struct tty_struct *tty, struct file *file, - struct poll_table_struct *wait) -{ - struct r3964_info *pInfo = tty->disc_data; - struct r3964_client_info *pClient; - struct r3964_message *pMsg = NULL; - unsigned long flags; - __poll_t result = EPOLLOUT; - - TRACE_L("POLL"); - - pClient = findClient(pInfo, task_pid(current)); - if (pClient) { - poll_wait(file, &tty->read_wait, wait); - spin_lock_irqsave(&pInfo->lock, flags); - pMsg = pClient->first_msg; - spin_unlock_irqrestore(&pInfo->lock, flags); - if (pMsg) - result |= EPOLLIN | EPOLLRDNORM; - } else { - result = -EINVAL; - } - return result; -} - -static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) -{ - struct r3964_info *pInfo = tty->disc_data; - const unsigned char *p; - char *f, flags = TTY_NORMAL; - int i; - - for (i = count, p = cp, f = fp; i; i--, p++) { - if (f) - flags = *f++; - if (flags == TTY_NORMAL) { - receive_char(pInfo, *p); - } else { - receive_error(pInfo, flags); - } - - } -} - -MODULE_LICENSE("GPL"); -MODULE_ALIAS_LDISC(N_R3964); diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 9686c5d10571..0ec93f1a61f5 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -342,10 +342,10 @@ static void n_tty_packet_mode_flush(struct tty_struct *tty) { unsigned long flags; - if (tty->link->packet) { - spin_lock_irqsave(&tty->ctrl_lock, flags); - tty->ctrl_status |= TIOCPKT_FLUSHREAD; - spin_unlock_irqrestore(&tty->ctrl_lock, flags); + if (tty->link->ctrl.packet) { + spin_lock_irqsave(&tty->ctrl.lock, flags); + tty->ctrl.pktstatus |= TIOCPKT_FLUSHREAD; + spin_unlock_irqrestore(&tty->ctrl.lock, flags); wake_up_interruptible(&tty->link->read_wait); } } @@ -361,7 +361,7 @@ static void n_tty_packet_mode_flush(struct tty_struct *tty) * Holds termios_rwsem to exclude producer/consumer while * buffer indices are reset. * - * Locking: ctrl_lock, exclusive termios_rwsem + * Locking: ctrl.lock, exclusive termios_rwsem */ static void n_tty_flush_buffer(struct tty_struct *tty) @@ -1103,7 +1103,7 @@ static void eraser(unsigned char c, struct tty_struct *tty) * buffer is 'output'. The signal is processed first to alert any current * readers or writers to discontinue and exit their i/o loops. * - * Locking: ctrl_lock + * Locking: ctrl.lock */ static void __isig(int sig, struct tty_struct *tty) @@ -1245,7 +1245,6 @@ n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c) commit_echoes(tty); } else process_echoes(tty); - return; } /** @@ -1260,12 +1259,8 @@ n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c) * n_tty_receive_buf()/producer path: * caller holds non-exclusive termios_rwsem * publishes canon_head if canonical mode is active - * - * Returns 1 if LNEXT was received, else returns 0 */ - -static int -n_tty_receive_char_special(struct tty_struct *tty, unsigned char c) +static void n_tty_receive_char_special(struct tty_struct *tty, unsigned char c) { struct n_tty_data *ldata = tty->disc_data; @@ -1273,35 +1268,35 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c) if (c == START_CHAR(tty)) { start_tty(tty); process_echoes(tty); - return 0; + return; } if (c == STOP_CHAR(tty)) { stop_tty(tty); - return 0; + return; } } if (L_ISIG(tty)) { if (c == INTR_CHAR(tty)) { n_tty_receive_signal_char(tty, SIGINT, c); - return 0; + return; } else if (c == QUIT_CHAR(tty)) { n_tty_receive_signal_char(tty, SIGQUIT, c); - return 0; + return; } else if (c == SUSP_CHAR(tty)) { n_tty_receive_signal_char(tty, SIGTSTP, c); - return 0; + return; } } - if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) { + if (tty->flow.stopped && !tty->flow.tco_stopped && I_IXON(tty) && I_IXANY(tty)) { start_tty(tty); process_echoes(tty); } if (c == '\r') { if (I_IGNCR(tty)) - return 0; + return; if (I_ICRNL(tty)) c = '\n'; } else if (c == '\n' && I_INLCR(tty)) @@ -1312,7 +1307,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c) (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) { eraser(c, tty); commit_echoes(tty); - return 0; + return; } if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) { ldata->lnext = 1; @@ -1324,7 +1319,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c) commit_echoes(tty); } } - return 1; + return; } if (c == REPRINT_CHAR(tty) && L_ECHO(tty) && L_IEXTEN(tty)) { size_t tail = ldata->canon_head; @@ -1337,7 +1332,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c) tail++; } commit_echoes(tty); - return 0; + return; } if (c == '\n') { if (L_ECHO(tty) || L_ECHONL(tty)) { @@ -1375,7 +1370,7 @@ handle_newline: smp_store_release(&ldata->canon_head, ldata->read_head); kill_fasync(&tty->fasync, SIGIO, POLL_IN); wake_up_interruptible_poll(&tty->read_wait, EPOLLIN); - return 0; + return; } } @@ -1397,15 +1392,13 @@ handle_newline: put_tty_queue(c, ldata); put_tty_queue(c, ldata); - return 0; } -static inline void -n_tty_receive_char_inline(struct tty_struct *tty, unsigned char c) +static void n_tty_receive_char(struct tty_struct *tty, unsigned char c) { struct n_tty_data *ldata = tty->disc_data; - if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) { + if (tty->flow.stopped && !tty->flow.tco_stopped && I_IXON(tty) && I_IXANY(tty)) { start_tty(tty); process_echoes(tty); } @@ -1423,31 +1416,6 @@ n_tty_receive_char_inline(struct tty_struct *tty, unsigned char c) put_tty_queue(c, ldata); } -static void n_tty_receive_char(struct tty_struct *tty, unsigned char c) -{ - n_tty_receive_char_inline(tty, c); -} - -static inline void -n_tty_receive_char_fast(struct tty_struct *tty, unsigned char c) -{ - struct n_tty_data *ldata = tty->disc_data; - - if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) { - start_tty(tty); - process_echoes(tty); - } - if (L_ECHO(tty)) { - finish_erasing(ldata); - /* Record the column of first canon char. */ - if (ldata->canon_head == ldata->read_head) - echo_set_canon_col(ldata); - echo_char(c, tty); - commit_echoes(tty); - } - put_tty_queue(c, ldata); -} - static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c) { if (I_ISTRIP(tty)) @@ -1459,7 +1427,7 @@ static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c) if (c == STOP_CHAR(tty)) stop_tty(tty); else if (c == START_CHAR(tty) || - (tty->stopped && !tty->flow_stopped && I_IXANY(tty) && + (tty->flow.stopped && !tty->flow.tco_stopped && I_IXANY(tty) && c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty))) { start_tty(tty); @@ -1506,7 +1474,7 @@ n_tty_receive_char_lnext(struct tty_struct *tty, unsigned char c, char flag) static void n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) + const char *fp, int count) { struct n_tty_data *ldata = tty->disc_data; size_t n, head; @@ -1526,7 +1494,7 @@ n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp, static void n_tty_receive_buf_raw(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) + const char *fp, int count) { struct n_tty_data *ldata = tty->disc_data; char flag = TTY_NORMAL; @@ -1543,7 +1511,7 @@ n_tty_receive_buf_raw(struct tty_struct *tty, const unsigned char *cp, static void n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) + const char *fp, int count) { char flag = TTY_NORMAL; @@ -1555,68 +1523,46 @@ n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp, } } -static void -n_tty_receive_buf_standard(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) +static void n_tty_receive_buf_standard(struct tty_struct *tty, + const unsigned char *cp, const char *fp, int count) { struct n_tty_data *ldata = tty->disc_data; char flag = TTY_NORMAL; while (count--) { + unsigned char c = *cp++; + if (fp) flag = *fp++; - if (likely(flag == TTY_NORMAL)) { - unsigned char c = *cp++; - - if (I_ISTRIP(tty)) - c &= 0x7f; - if (I_IUCLC(tty) && L_IEXTEN(tty)) - c = tolower(c); - if (L_EXTPROC(tty)) { - put_tty_queue(c, ldata); - continue; - } - if (!test_bit(c, ldata->char_map)) - n_tty_receive_char_inline(tty, c); - else if (n_tty_receive_char_special(tty, c) && count) { - if (fp) - flag = *fp++; - n_tty_receive_char_lnext(tty, *cp++, flag); - count--; - } - } else - n_tty_receive_char_flagged(tty, *cp++, flag); - } -} -static void -n_tty_receive_buf_fast(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) -{ - struct n_tty_data *ldata = tty->disc_data; - char flag = TTY_NORMAL; + if (ldata->lnext) { + n_tty_receive_char_lnext(tty, c, flag); + continue; + } - while (count--) { - if (fp) - flag = *fp++; - if (likely(flag == TTY_NORMAL)) { - unsigned char c = *cp++; - - if (!test_bit(c, ldata->char_map)) - n_tty_receive_char_fast(tty, c); - else if (n_tty_receive_char_special(tty, c) && count) { - if (fp) - flag = *fp++; - n_tty_receive_char_lnext(tty, *cp++, flag); - count--; - } - } else - n_tty_receive_char_flagged(tty, *cp++, flag); + if (unlikely(flag != TTY_NORMAL)) { + n_tty_receive_char_flagged(tty, c, flag); + continue; + } + + if (I_ISTRIP(tty)) + c &= 0x7f; + if (I_IUCLC(tty) && L_IEXTEN(tty)) + c = tolower(c); + if (L_EXTPROC(tty)) { + put_tty_queue(c, ldata); + continue; + } + + if (test_bit(c, ldata->char_map)) + n_tty_receive_char_special(tty, c); + else + n_tty_receive_char(tty, c); } } static void __receive_buf(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) + const char *fp, int count) { struct n_tty_data *ldata = tty->disc_data; bool preops = I_ISTRIP(tty) || (I_IUCLC(tty) && L_IEXTEN(tty)); @@ -1628,19 +1574,7 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp, else if (tty->closing && !L_EXTPROC(tty)) n_tty_receive_buf_closing(tty, cp, fp, count); else { - if (ldata->lnext) { - char flag = TTY_NORMAL; - - if (fp) - flag = *fp++; - n_tty_receive_char_lnext(tty, *cp++, flag); - count--; - } - - if (!preops && !I_PARMRK(tty)) - n_tty_receive_buf_fast(tty, cp, fp, count); - else - n_tty_receive_buf_standard(tty, cp, fp, count); + n_tty_receive_buf_standard(tty, cp, fp, count); flush_echoes(tty); if (tty->ops->flush_chars) @@ -1695,7 +1629,7 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp, */ static int n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count, int flow) + const char *fp, int count, int flow) { struct n_tty_data *ldata = tty->disc_data; int room, n, rcvd = 0, overflow; @@ -1764,13 +1698,13 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp, } static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) + const char *fp, int count) { n_tty_receive_buf_common(tty, cp, fp, count, 0); } static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) + const char *fp, int count) { return n_tty_receive_buf_common(tty, cp, fp, count, 1); } @@ -1863,7 +1797,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) * Fix tty hang when I_IXON(tty) is cleared, but the tty * been stopped by STOP_CHAR(tty) before it. */ - if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped) { + if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow.tco_stopped) { start_tty(tty); process_echoes(tty); } @@ -2091,7 +2025,7 @@ static bool canon_copy_from_read_buf(struct tty_struct *tty, * * Locking: redirected write test is safe * current->signal->tty check is safe - * ctrl_lock to safely reference tty->pgrp + * ctrl.lock to safely reference tty->ctrl.pgrp */ static int job_control(struct tty_struct *tty, struct file *file) @@ -2138,7 +2072,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, int minimum, time; ssize_t retval = 0; long timeout; - int packet; + bool packet; size_t tail; /* @@ -2194,20 +2128,20 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, } } - packet = tty->packet; + packet = tty->ctrl.packet; tail = ldata->read_tail; add_wait_queue(&tty->read_wait, &wait); while (nr) { /* First test for status change. */ - if (packet && tty->link->ctrl_status) { + if (packet && tty->link->ctrl.pktstatus) { unsigned char cs; if (kb != kbuf) break; - spin_lock_irq(&tty->link->ctrl_lock); - cs = tty->link->ctrl_status; - tty->link->ctrl_status = 0; - spin_unlock_irq(&tty->link->ctrl_lock); + spin_lock_irq(&tty->link->ctrl.lock); + cs = tty->link->ctrl.pktstatus; + tty->link->ctrl.pktstatus = 0; + spin_unlock_irq(&tty->link->ctrl.lock); *kb++ = cs; nr--; break; @@ -2434,7 +2368,7 @@ static __poll_t n_tty_poll(struct tty_struct *tty, struct file *file, if (input_available_p(tty, 1)) mask |= EPOLLIN | EPOLLRDNORM; } - if (tty->packet && tty->link->ctrl_status) + if (tty->ctrl.packet && tty->link->ctrl.pktstatus) mask |= EPOLLPRI | EPOLLIN | EPOLLRDNORM; if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) mask |= EPOLLHUP; @@ -2490,6 +2424,7 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file, static struct tty_ldisc_ops n_tty_ops = { .owner = THIS_MODULE, + .num = N_TTY, .name = "n_tty", .open = n_tty_open, .close = n_tty_close, @@ -2515,11 +2450,11 @@ void n_tty_inherit_ops(struct tty_ldisc_ops *ops) { *ops = n_tty_ops; ops->owner = NULL; - ops->refcount = ops->flags = 0; + ops->flags = 0; } EXPORT_SYMBOL_GPL(n_tty_inherit_ops); void __init n_tty_init(void) { - tty_register_ldisc(N_TTY, &n_tty_ops); + tty_register_ldisc(&n_tty_ops); } diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index 9a2d78ace49b..0c80f25c8c3d 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -1378,7 +1378,7 @@ static int nozomi_card_init(struct pci_dev *pdev, NOZOMI_NAME, dc); if (unlikely(ret)) { dev_err(&pdev->dev, "can't request irq %d\n", pdev->irq); - goto err_free_kfifo; + goto err_free_all_kfifo; } DBG1("base_addr: %p", dc->base_addr); @@ -1416,12 +1416,15 @@ static int nozomi_card_init(struct pci_dev *pdev, return 0; err_free_tty: - for (i = 0; i < MAX_PORT; ++i) { + for (i--; i >= 0; i--) { tty_unregister_device(ntty_driver, dc->index_start + i); tty_port_destroy(&dc->port[i].port); } + free_irq(pdev->irq, dc); +err_free_all_kfifo: + i = MAX_PORT; err_free_kfifo: - for (i = 0; i < MAX_PORT; i++) + for (i--; i >= PORT_MDM; i--) kfifo_free(&dc->port[i].fifo_ul); err_free_sbuf: kfree(dc->send_buf); @@ -1636,10 +1639,10 @@ static int ntty_write(struct tty_struct *tty, const unsigned char *buffer, * If the port is unplugged report lots of room and let the bits * dribble away so we don't block anything. */ -static int ntty_write_room(struct tty_struct *tty) +static unsigned int ntty_write_room(struct tty_struct *tty) { struct port *port = tty->driver_data; - int room = 4096; + unsigned int room = 4096; const struct nozomi *dc = get_dc_by_tty(tty); if (dc) @@ -1776,20 +1779,15 @@ static void ntty_throttle(struct tty_struct *tty) } /* Returns number of chars in buffer, called by tty layer */ -static s32 ntty_chars_in_buffer(struct tty_struct *tty) +static unsigned int ntty_chars_in_buffer(struct tty_struct *tty) { struct port *port = tty->driver_data; struct nozomi *dc = get_dc_by_tty(tty); - s32 rval = 0; - if (unlikely(!dc || !port)) { - goto exit_in_buffer; - } - - rval = kfifo_len(&port->fifo_ul); + if (unlikely(!dc || !port)) + return 0; -exit_in_buffer: - return rval; + return kfifo_len(&port->fifo_ul); } static const struct tty_port_operations noz_tty_port_ops = { diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 9b5d4ae5d8f2..74bfabe5b453 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -57,9 +57,9 @@ static void pty_close(struct tty_struct *tty, struct file *filp) set_bit(TTY_IO_ERROR, &tty->flags); wake_up_interruptible(&tty->read_wait); wake_up_interruptible(&tty->write_wait); - spin_lock_irq(&tty->ctrl_lock); - tty->packet = 0; - spin_unlock_irq(&tty->ctrl_lock); + spin_lock_irq(&tty->ctrl.lock); + tty->ctrl.packet = false; + spin_unlock_irq(&tty->ctrl.lock); /* Review - krefs on tty_link ?? */ if (!tty->link) return; @@ -113,7 +113,7 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c) struct tty_struct *to = tty->link; unsigned long flags; - if (tty->stopped) + if (tty->flow.stopped) return 0; if (c > 0) { @@ -136,26 +136,13 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c) * the other device. */ -static int pty_write_room(struct tty_struct *tty) +static unsigned int pty_write_room(struct tty_struct *tty) { - if (tty->stopped) + if (tty->flow.stopped) return 0; return tty_buffer_space_avail(tty->link->port); } -/** - * pty_chars_in_buffer - characters currently in our tx queue - * @tty: our tty - * - * Report how much we have in the transmit queue. As everything is - * instantly at the other end this is easy to implement. - */ - -static int pty_chars_in_buffer(struct tty_struct *tty) -{ - return 0; -} - /* Set the lock flag on a pty */ static int pty_set_lock(struct tty_struct *tty, int __user *arg) { @@ -185,16 +172,16 @@ static int pty_set_pktmode(struct tty_struct *tty, int __user *arg) if (get_user(pktmode, arg)) return -EFAULT; - spin_lock_irq(&tty->ctrl_lock); + spin_lock_irq(&tty->ctrl.lock); if (pktmode) { - if (!tty->packet) { - tty->link->ctrl_status = 0; + if (!tty->ctrl.packet) { + tty->link->ctrl.pktstatus = 0; smp_mb(); - tty->packet = 1; + tty->ctrl.packet = true; } } else - tty->packet = 0; - spin_unlock_irq(&tty->ctrl_lock); + tty->ctrl.packet = false; + spin_unlock_irq(&tty->ctrl.lock); return 0; } @@ -202,7 +189,7 @@ static int pty_set_pktmode(struct tty_struct *tty, int __user *arg) /* Get the packet mode of a pty */ static int pty_get_pktmode(struct tty_struct *tty, int __user *arg) { - int pktmode = tty->packet; + int pktmode = tty->ctrl.packet; return put_user(pktmode, arg); } @@ -232,11 +219,11 @@ static void pty_flush_buffer(struct tty_struct *tty) return; tty_buffer_flush(to, NULL); - if (to->packet) { - spin_lock_irq(&tty->ctrl_lock); - tty->ctrl_status |= TIOCPKT_FLUSHWRITE; + if (to->ctrl.packet) { + spin_lock_irq(&tty->ctrl.lock); + tty->ctrl.pktstatus |= TIOCPKT_FLUSHWRITE; wake_up_interruptible(&to->read_wait); - spin_unlock_irq(&tty->ctrl_lock); + spin_unlock_irq(&tty->ctrl.lock); } } @@ -266,7 +253,7 @@ static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { /* See if packet mode change of state. */ - if (tty->link && tty->link->packet) { + if (tty->link && tty->link->ctrl.packet) { int extproc = (old_termios->c_lflag & EXTPROC) | L_EXTPROC(tty); int old_flow = ((old_termios->c_iflag & IXON) && (old_termios->c_cc[VSTOP] == '\023') && @@ -275,17 +262,17 @@ static void pty_set_termios(struct tty_struct *tty, STOP_CHAR(tty) == '\023' && START_CHAR(tty) == '\021'); if ((old_flow != new_flow) || extproc) { - spin_lock_irq(&tty->ctrl_lock); + spin_lock_irq(&tty->ctrl.lock); if (old_flow != new_flow) { - tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP); + tty->ctrl.pktstatus &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP); if (new_flow) - tty->ctrl_status |= TIOCPKT_DOSTOP; + tty->ctrl.pktstatus |= TIOCPKT_DOSTOP; else - tty->ctrl_status |= TIOCPKT_NOSTOP; + tty->ctrl.pktstatus |= TIOCPKT_NOSTOP; } if (extproc) - tty->ctrl_status |= TIOCPKT_IOCTL; - spin_unlock_irq(&tty->ctrl_lock); + tty->ctrl.pktstatus |= TIOCPKT_IOCTL; + spin_unlock_irq(&tty->ctrl.lock); wake_up_interruptible(&tty->link->read_wait); } } @@ -295,7 +282,7 @@ static void pty_set_termios(struct tty_struct *tty, } /** - * pty_do_resize - resize event + * pty_resize - resize event * @tty: tty being resized * @ws: window size being set. * @@ -346,11 +333,11 @@ static void pty_start(struct tty_struct *tty) { unsigned long flags; - if (tty->link && tty->link->packet) { - spin_lock_irqsave(&tty->ctrl_lock, flags); - tty->ctrl_status &= ~TIOCPKT_STOP; - tty->ctrl_status |= TIOCPKT_START; - spin_unlock_irqrestore(&tty->ctrl_lock, flags); + if (tty->link && tty->link->ctrl.packet) { + spin_lock_irqsave(&tty->ctrl.lock, flags); + tty->ctrl.pktstatus &= ~TIOCPKT_STOP; + tty->ctrl.pktstatus |= TIOCPKT_START; + spin_unlock_irqrestore(&tty->ctrl.lock, flags); wake_up_interruptible_poll(&tty->link->read_wait, EPOLLIN); } } @@ -359,11 +346,11 @@ static void pty_stop(struct tty_struct *tty) { unsigned long flags; - if (tty->link && tty->link->packet) { - spin_lock_irqsave(&tty->ctrl_lock, flags); - tty->ctrl_status &= ~TIOCPKT_START; - tty->ctrl_status |= TIOCPKT_STOP; - spin_unlock_irqrestore(&tty->ctrl_lock, flags); + if (tty->link && tty->link->ctrl.packet) { + spin_lock_irqsave(&tty->ctrl.lock, flags); + tty->ctrl.pktstatus &= ~TIOCPKT_START; + tty->ctrl.pktstatus |= TIOCPKT_STOP; + spin_unlock_irqrestore(&tty->ctrl.lock, flags); wake_up_interruptible_poll(&tty->link->read_wait, EPOLLIN); } } @@ -525,7 +512,6 @@ static const struct tty_operations master_pty_ops_bsd = { .write = pty_write, .write_room = pty_write_room, .flush_buffer = pty_flush_buffer, - .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .ioctl = pty_bsd_ioctl, .compat_ioctl = pty_bsd_compat_ioctl, @@ -541,7 +527,6 @@ static const struct tty_operations slave_pty_ops_bsd = { .write = pty_write, .write_room = pty_write_room, .flush_buffer = pty_flush_buffer, - .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, .cleanup = pty_cleanup, @@ -626,7 +611,7 @@ static struct cdev ptmx_cdev; */ int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags) { - int fd = -1; + int fd; struct file *filp; int retval = -EINVAL; struct path path; @@ -776,7 +761,6 @@ static const struct tty_operations ptm_unix98_ops = { .write = pty_write, .write_room = pty_write_room, .flush_buffer = pty_flush_buffer, - .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .ioctl = pty_unix98_ioctl, .compat_ioctl = pty_unix98_compat_ioctl, @@ -794,7 +778,6 @@ static const struct tty_operations pty_unix98_ops = { .write = pty_write, .write_room = pty_write_room, .flush_buffer = pty_flush_buffer, - .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, .start = pty_start, diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index aead0c0c9796..9cdfcfe07e87 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -798,7 +798,7 @@ void serdev_controller_remove(struct serdev_controller *ctrl) EXPORT_SYMBOL_GPL(serdev_controller_remove); /** - * serdev_driver_register() - Register client driver with serdev core + * __serdev_device_driver_register() - Register client driver with serdev core * @sdrv: client driver to be associated with client-device. * @owner: client driver owner to set. * diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c index d035d08cb987..4caab8714e2c 100644 --- a/drivers/tty/serial/8250/8250_aspeed_vuart.c +++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c @@ -34,7 +34,6 @@ struct aspeed_vuart { struct device *dev; - void __iomem *regs; struct clk *clk; int line; struct timer_list unthrottle_timer; @@ -64,14 +63,24 @@ static const int unthrottle_timeout = HZ/10; * different system (though most of them use 3f8/4). */ +static inline u8 aspeed_vuart_readb(struct aspeed_vuart *vuart, u8 reg) +{ + return readb(vuart->port->port.membase + reg); +} + +static inline void aspeed_vuart_writeb(struct aspeed_vuart *vuart, u8 val, u8 reg) +{ + writeb(val, vuart->port->port.membase + reg); +} + static ssize_t lpc_address_show(struct device *dev, struct device_attribute *attr, char *buf) { struct aspeed_vuart *vuart = dev_get_drvdata(dev); u16 addr; - addr = (readb(vuart->regs + ASPEED_VUART_ADDRH) << 8) | - (readb(vuart->regs + ASPEED_VUART_ADDRL)); + addr = (aspeed_vuart_readb(vuart, ASPEED_VUART_ADDRH) << 8) | + (aspeed_vuart_readb(vuart, ASPEED_VUART_ADDRL)); return snprintf(buf, PAGE_SIZE - 1, "0x%x\n", addr); } @@ -81,8 +90,8 @@ static int aspeed_vuart_set_lpc_address(struct aspeed_vuart *vuart, u32 addr) if (addr > U16_MAX) return -EINVAL; - writeb(addr >> 8, vuart->regs + ASPEED_VUART_ADDRH); - writeb(addr >> 0, vuart->regs + ASPEED_VUART_ADDRL); + aspeed_vuart_writeb(vuart, addr >> 8, ASPEED_VUART_ADDRH); + aspeed_vuart_writeb(vuart, addr >> 0, ASPEED_VUART_ADDRL); return 0; } @@ -111,7 +120,7 @@ static ssize_t sirq_show(struct device *dev, struct aspeed_vuart *vuart = dev_get_drvdata(dev); u8 reg; - reg = readb(vuart->regs + ASPEED_VUART_GCRB); + reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRB); reg &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK; reg >>= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT; @@ -128,10 +137,10 @@ static int aspeed_vuart_set_sirq(struct aspeed_vuart *vuart, u32 sirq) sirq <<= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT; sirq &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK; - reg = readb(vuart->regs + ASPEED_VUART_GCRB); + reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRB); reg &= ~ASPEED_VUART_GCRB_HOST_SIRQ_MASK; reg |= sirq; - writeb(reg, vuart->regs + ASPEED_VUART_GCRB); + aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRB); return 0; } @@ -159,7 +168,7 @@ static ssize_t sirq_polarity_show(struct device *dev, struct aspeed_vuart *vuart = dev_get_drvdata(dev); u8 reg; - reg = readb(vuart->regs + ASPEED_VUART_GCRA); + reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA); reg &= ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY; return snprintf(buf, PAGE_SIZE - 1, "%u\n", reg ? 1 : 0); @@ -168,14 +177,14 @@ static ssize_t sirq_polarity_show(struct device *dev, static void aspeed_vuart_set_sirq_polarity(struct aspeed_vuart *vuart, bool polarity) { - u8 reg = readb(vuart->regs + ASPEED_VUART_GCRA); + u8 reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA); if (polarity) reg |= ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY; else reg &= ~ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY; - writeb(reg, vuart->regs + ASPEED_VUART_GCRA); + aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRA); } static ssize_t sirq_polarity_store(struct device *dev, @@ -210,14 +219,14 @@ static const struct attribute_group aspeed_vuart_attr_group = { static void aspeed_vuart_set_enabled(struct aspeed_vuart *vuart, bool enabled) { - u8 reg = readb(vuart->regs + ASPEED_VUART_GCRA); + u8 reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA); if (enabled) reg |= ASPEED_VUART_GCRA_VUART_EN; else reg &= ~ASPEED_VUART_GCRA_VUART_EN; - writeb(reg, vuart->regs + ASPEED_VUART_GCRA); + aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRA); } static void aspeed_vuart_set_host_tx_discard(struct aspeed_vuart *vuart, @@ -225,7 +234,7 @@ static void aspeed_vuart_set_host_tx_discard(struct aspeed_vuart *vuart, { u8 reg; - reg = readb(vuart->regs + ASPEED_VUART_GCRA); + reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA); /* If the DISABLE_HOST_TX_DISCARD bit is set, discard is disabled */ if (!discard) @@ -233,7 +242,7 @@ static void aspeed_vuart_set_host_tx_discard(struct aspeed_vuart *vuart, else reg &= ~ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD; - writeb(reg, vuart->regs + ASPEED_VUART_GCRA); + aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRA); } static int aspeed_vuart_startup(struct uart_port *uart_port) @@ -320,7 +329,7 @@ static int aspeed_vuart_handle_irq(struct uart_port *port) { struct uart_8250_port *up = up_to_u8250p(port); unsigned int iir, lsr; - int space, count; + unsigned int space, count; iir = serial_port_in(port, UART_IIR); @@ -339,14 +348,12 @@ static int aspeed_vuart_handle_irq(struct uart_port *port) struct aspeed_vuart *vuart = port->private_data; __aspeed_vuart_set_throttle(up, true); - if (!timer_pending(&vuart->unthrottle_timer)) { - vuart->port = up; + if (!timer_pending(&vuart->unthrottle_timer)) mod_timer(&vuart->unthrottle_timer, jiffies + unthrottle_timeout); - } } else { - count = min(space, 256); + count = min(space, 256U); do { serial8250_read_char(up, lsr); @@ -421,13 +428,9 @@ static int aspeed_vuart_probe(struct platform_device *pdev) timer_setup(&vuart->unthrottle_timer, aspeed_vuart_unthrottle_exp, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - vuart->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(vuart->regs)) - return PTR_ERR(vuart->regs); memset(&port, 0, sizeof(port)); port.port.private_data = vuart; - port.port.membase = vuart->regs; port.port.mapbase = res->start; port.port.mapsize = resource_size(res); port.port.startup = aspeed_vuart_startup; @@ -485,7 +488,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev) port.port.iotype = UPIO_MEM; port.port.type = PORT_16550A; port.port.uartclk = clk; - port.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF + port.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_NO_THRE_TEST; if (of_property_read_bool(np, "no-loopback-test")) @@ -502,6 +505,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev) goto err_clk_disable; vuart->line = rc; + vuart->port = serial8250_get_port(vuart->line); rc = of_parse_phandle_with_fixed_args( np, "aspeed,sirq-polarity-sense", 2, 0, diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index cae61d1ebec5..1ce193daea7f 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -172,7 +172,6 @@ static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up) static int serial_link_irq_chain(struct uart_8250_port *up) { struct hlist_head *h; - struct hlist_node *n; struct irq_info *i; int ret; @@ -180,13 +179,11 @@ static int serial_link_irq_chain(struct uart_8250_port *up) h = &irq_lists[up->port.irq % NR_IRQ_HASH]; - hlist_for_each(n, h) { - i = hlist_entry(n, struct irq_info, node); + hlist_for_each_entry(i, h, node) if (i->irq == up->port.irq) break; - } - if (n == NULL) { + if (i == NULL) { i = kzalloc(sizeof(struct irq_info), GFP_KERNEL); if (i == NULL) { mutex_unlock(&hash_mutex); @@ -220,25 +217,18 @@ static int serial_link_irq_chain(struct uart_8250_port *up) static void serial_unlink_irq_chain(struct uart_8250_port *up) { - /* - * yes, some broken gcc emit "warning: 'i' may be used uninitialized" - * but no, we are not going to take a patch that assigns NULL below. - */ struct irq_info *i; - struct hlist_node *n; struct hlist_head *h; mutex_lock(&hash_mutex); h = &irq_lists[up->port.irq % NR_IRQ_HASH]; - hlist_for_each(n, h) { - i = hlist_entry(n, struct irq_info, node); + hlist_for_each_entry(i, h, node) if (i->irq == up->port.irq) break; - } - BUG_ON(n == NULL); + BUG_ON(i == NULL); BUG_ON(i->head == NULL); if (list_empty(i->head)) @@ -331,9 +321,9 @@ static int univ8250_setup_irq(struct uart_8250_port *up) * hardware interrupt, we use a timer-based system. The original * driver used to do this with IRQ0. */ - if (!port->irq) { + if (!port->irq) mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); - } else + else retval = serial_link_irq_chain(up); return retval; @@ -762,6 +752,7 @@ void serial8250_suspend_port(int line) if (!console_suspend_enabled && uart_console(port) && port->type != PORT_8250) { unsigned char canary = 0xa5; + serial_out(up, UART_SCR, canary); if (serial_in(up, UART_SCR) == canary) up->canary = canary; @@ -915,7 +906,7 @@ static struct platform_device *serial8250_isa_devs; */ static DEFINE_MUTEX(serial_mutex); -static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port) +static struct uart_8250_port *serial8250_find_match_or_unused(const struct uart_port *port) { int i; @@ -980,7 +971,7 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work) * * On success the port is ready to use and the line number is returned. */ -int serial8250_register_8250_port(struct uart_8250_port *up) +int serial8250_register_8250_port(const struct uart_8250_port *up) { struct uart_8250_port *uart; int ret = -ENOSPC; diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index bd4e9f6ac29c..3ffeedc29c83 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -501,23 +501,27 @@ static const struct dmi_system_id exar_platforms[] = { {} }; +static const struct exar8250_platform *exar_get_platform(void) +{ + const struct dmi_system_id *dmi_match; + + dmi_match = dmi_first_match(exar_platforms); + if (dmi_match) + return dmi_match->driver_data; + + return &exar8250_default_platform; +} + static int pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev, struct uart_8250_port *port, int idx) { - const struct exar8250_platform *platform; - const struct dmi_system_id *dmi_match; + const struct exar8250_platform *platform = exar_get_platform(); unsigned int offset = idx * 0x400; unsigned int baud = 7812500; u8 __iomem *p; int ret; - dmi_match = dmi_first_match(exar_platforms); - if (dmi_match) - platform = dmi_match->driver_data; - else - platform = &exar8250_default_platform; - port->port.uartclk = baud * 16; port->port.rs485_config = platform->rs485_config; diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 0b077b45d6a9..bce28729dd7b 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -192,6 +192,10 @@ static int of_platform_serial_probe(struct platform_device *ofdev) u32 tx_threshold; int ret; + if (IS_ENABLED(CONFIG_SERIAL_8250_BCM7271) && + of_device_is_compatible(ofdev->dev.of_node, "brcm,bcm7271-uart")) + return -ENODEV; + port_type = (unsigned long)of_device_get_match_data(&ofdev->dev); if (port_type == PORT_UNKNOWN) return -EINVAL; diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 8ac11eaeca51..79418d4beb48 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -43,6 +43,7 @@ #define UART_ERRATA_CLOCK_DISABLE (1 << 3) #define UART_HAS_EFR2 BIT(4) #define UART_HAS_RHR_IT_DIS BIT(5) +#define UART_RX_TIMEOUT_QUIRK BIT(6) #define OMAP_UART_FCR_RX_TRIG 6 #define OMAP_UART_FCR_TX_TRIG 4 @@ -104,6 +105,9 @@ #define UART_OMAP_EFR2 0x23 #define UART_OMAP_EFR2_TIMEOUT_BEHAVE BIT(6) +/* RX FIFO occupancy indicator */ +#define UART_OMAP_RX_LVL 0x64 + struct omap8250_priv { int line; u8 habit; @@ -611,6 +615,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port); static irqreturn_t omap8250_irq(int irq, void *dev_id) { struct uart_port *port = dev_id; + struct omap8250_priv *priv = port->private_data; struct uart_8250_port *up = up_to_u8250p(port); unsigned int iir; int ret; @@ -625,6 +630,18 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id) serial8250_rpm_get(up); iir = serial_port_in(port, UART_IIR); ret = serial8250_handle_irq(port, iir); + + /* + * On K3 SoCs, it is observed that RX TIMEOUT is signalled after + * FIFO has been drained, in which case a dummy read of RX FIFO + * is required to clear RX TIMEOUT condition. + */ + if (priv->habit & UART_RX_TIMEOUT_QUIRK && + (iir & UART_IIR_RX_TIMEOUT) == UART_IIR_RX_TIMEOUT && + serial_port_in(port, UART_OMAP_RX_LVL) == 0) { + serial_port_in(port, UART_RX); + } + serial8250_rpm_put(up); return IRQ_RETVAL(ret); @@ -813,7 +830,7 @@ static void __dma_rx_do_complete(struct uart_8250_port *p) poll_count--) cpu_relax(); - if (!poll_count) + if (poll_count == -1) dev_err(p->port.dev, "teardown incomplete\n"); } } @@ -1218,7 +1235,8 @@ static struct omap8250_dma_params am33xx_dma = { static struct omap8250_platdata am654_platdata = { .dma_params = &am654_dma, - .habit = UART_HAS_EFR2 | UART_HAS_RHR_IT_DIS, + .habit = UART_HAS_EFR2 | UART_HAS_RHR_IT_DIS | + UART_RX_TIMEOUT_QUIRK, }; static struct omap8250_platdata am33xx_platdata = { diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 780cc99732b6..75827b608fdb 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -2851,7 +2851,7 @@ enum pci_board_num_t { pbn_b0_2_1843200, pbn_b0_4_1843200, - pbn_b0_1_4000000, + pbn_b0_1_3906250, pbn_b0_bt_1_115200, pbn_b0_bt_2_115200, @@ -2931,10 +2931,10 @@ enum pci_board_num_t { pbn_plx_romulus, pbn_endrun_2_4000000, pbn_oxsemi, - pbn_oxsemi_1_4000000, - pbn_oxsemi_2_4000000, - pbn_oxsemi_4_4000000, - pbn_oxsemi_8_4000000, + pbn_oxsemi_1_3906250, + pbn_oxsemi_2_3906250, + pbn_oxsemi_4_3906250, + pbn_oxsemi_8_3906250, pbn_intel_i960, pbn_sgi_ioc3, pbn_computone_4, @@ -2972,6 +2972,10 @@ enum pci_board_num_t { pbn_sunix_pci_4s, pbn_sunix_pci_8s, pbn_sunix_pci_16s, + pbn_titan_1_4000000, + pbn_titan_2_4000000, + pbn_titan_4_4000000, + pbn_titan_8_4000000, pbn_moxa8250_2p, pbn_moxa8250_4p, pbn_moxa8250_8p, @@ -3077,10 +3081,10 @@ static struct pciserial_board pci_boards[] = { .uart_offset = 8, }, - [pbn_b0_1_4000000] = { + [pbn_b0_1_3906250] = { .flags = FL_BASE0, .num_ports = 1, - .base_baud = 4000000, + .base_baud = 3906250, .uart_offset = 8, }, @@ -3475,31 +3479,31 @@ static struct pciserial_board pci_boards[] = { .base_baud = 115200, .uart_offset = 8, }, - [pbn_oxsemi_1_4000000] = { + [pbn_oxsemi_1_3906250] = { .flags = FL_BASE0, .num_ports = 1, - .base_baud = 4000000, + .base_baud = 3906250, .uart_offset = 0x200, .first_offset = 0x1000, }, - [pbn_oxsemi_2_4000000] = { + [pbn_oxsemi_2_3906250] = { .flags = FL_BASE0, .num_ports = 2, - .base_baud = 4000000, + .base_baud = 3906250, .uart_offset = 0x200, .first_offset = 0x1000, }, - [pbn_oxsemi_4_4000000] = { + [pbn_oxsemi_4_3906250] = { .flags = FL_BASE0, .num_ports = 4, - .base_baud = 4000000, + .base_baud = 3906250, .uart_offset = 0x200, .first_offset = 0x1000, }, - [pbn_oxsemi_8_4000000] = { + [pbn_oxsemi_8_3906250] = { .flags = FL_BASE0, .num_ports = 8, - .base_baud = 4000000, + .base_baud = 3906250, .uart_offset = 0x200, .first_offset = 0x1000, }, @@ -3759,6 +3763,34 @@ static struct pciserial_board pci_boards[] = { .base_baud = 921600, .uart_offset = 0x8, }, + [pbn_titan_1_4000000] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 4000000, + .uart_offset = 0x200, + .first_offset = 0x1000, + }, + [pbn_titan_2_4000000] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 4000000, + .uart_offset = 0x200, + .first_offset = 0x1000, + }, + [pbn_titan_4_4000000] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 4000000, + .uart_offset = 0x200, + .first_offset = 0x1000, + }, + [pbn_titan_8_4000000] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 4000000, + .uart_offset = 0x200, + .first_offset = 0x1000, + }, [pbn_moxa8250_2p] = { .flags = FL_BASE1, .num_ports = 2, @@ -4478,158 +4510,158 @@ static const struct pci_device_id serial_pci_tbl[] = { */ { PCI_VENDOR_ID_OXSEMI, 0xc101, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, + pbn_b0_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc105, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, + pbn_b0_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc11b, /* OXPCIe952 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc11f, /* OXPCIe952 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc120, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, + pbn_b0_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc124, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, + pbn_b0_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc138, /* OXPCIe952 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc13d, /* OXPCIe952 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc140, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, + pbn_b0_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc141, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, + pbn_b0_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc144, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, + pbn_b0_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc145, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_4000000 }, + pbn_b0_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc158, /* OXPCIe952 2 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_4000000 }, + pbn_oxsemi_2_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc15d, /* OXPCIe952 2 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_4000000 }, + pbn_oxsemi_2_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc208, /* OXPCIe954 4 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_4_4000000 }, + pbn_oxsemi_4_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc20d, /* OXPCIe954 4 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_4_4000000 }, + pbn_oxsemi_4_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc308, /* OXPCIe958 8 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_8_4000000 }, + pbn_oxsemi_8_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc30d, /* OXPCIe958 8 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_8_4000000 }, + pbn_oxsemi_8_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc40b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc40f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc41b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc41f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc42b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc42f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc43b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc43f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc44b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc44f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc45b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc45f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc46b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc46f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc47b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc47f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc48b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc48f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc49b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc49f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc4ab, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc4af, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc4bb, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc4bf, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc4cb, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_OXSEMI, 0xc4cf, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, /* * Mainpine Inc. IQ Express "Rev3" utilizing OxSemi Tornado */ { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 1 Port V.34 Super-G3 Fax */ PCI_VENDOR_ID_MAINPINE, 0x4001, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_oxsemi_1_3906250 }, { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 2 Port V.34 Super-G3 Fax */ PCI_VENDOR_ID_MAINPINE, 0x4002, 0, 0, - pbn_oxsemi_2_4000000 }, + pbn_oxsemi_2_3906250 }, { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 4 Port V.34 Super-G3 Fax */ PCI_VENDOR_ID_MAINPINE, 0x4004, 0, 0, - pbn_oxsemi_4_4000000 }, + pbn_oxsemi_4_3906250 }, { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 8 Port V.34 Super-G3 Fax */ PCI_VENDOR_ID_MAINPINE, 0x4008, 0, 0, - pbn_oxsemi_8_4000000 }, + pbn_oxsemi_8_3906250 }, /* * Digi/IBM PCIe 2-port Async EIA-232 Adapter utilizing OxSemi Tornado */ { PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_2_OX_IBM, PCI_SUBVENDOR_ID_IBM, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_4000000 }, + pbn_oxsemi_2_3906250 }, /* * SBS Technologies, Inc. P-Octal and PMC-OCTPRO cards, @@ -4703,22 +4735,22 @@ static const struct pci_device_id serial_pci_tbl[] = { pbn_b0_4_921600 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_4000000 }, + pbn_titan_1_4000000 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_4000000 }, + pbn_titan_2_4000000 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_4_4000000 }, + pbn_titan_4_4000000 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_8_4000000 }, + pbn_titan_8_4000000 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EI, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_4000000 }, + pbn_titan_2_4000000 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_4000000 }, + pbn_titan_2_4000000 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200V3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_2_921600 }, diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index fc5ab2032282..2164290cbd31 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2512,19 +2512,45 @@ static unsigned int serial8250_do_get_divisor(struct uart_port *port, unsigned int baud, unsigned int *frac) { + upf_t magic_multiplier = port->flags & UPF_MAGIC_MULTIPLIER; struct uart_8250_port *up = up_to_u8250p(port); unsigned int quot; /* - * Handle magic divisors for baud rates above baud_base on - * SMSC SuperIO chips. + * Handle magic divisors for baud rates above baud_base on SMSC + * Super I/O chips. We clamp custom rates from clk/6 and clk/12 + * up to clk/4 (0x8001) and clk/8 (0x8002) respectively. These + * magic divisors actually reprogram the baud rate generator's + * reference clock derived from chips's 14.318MHz clock input. * + * Documentation claims that with these magic divisors the base + * frequencies of 7.3728MHz and 3.6864MHz are used respectively + * for the extra baud rates of 460800bps and 230400bps rather + * than the usual base frequency of 1.8462MHz. However empirical + * evidence contradicts that. + * + * Instead bit 7 of the DLM register (bit 15 of the divisor) is + * effectively used as a clock prescaler selection bit for the + * base frequency of 7.3728MHz, always used. If set to 0, then + * the base frequency is divided by 4 for use by the Baud Rate + * Generator, for the usual arrangement where the value of 1 of + * the divisor produces the baud rate of 115200bps. Conversely, + * if set to 1 and high-speed operation has been enabled with the + * Serial Port Mode Register in the Device Configuration Space, + * then the base frequency is supplied directly to the Baud Rate + * Generator, so for the divisor values of 0x8001, 0x8002, 0x8003, + * 0x8004, etc. the respective baud rates produced are 460800bps, + * 230400bps, 153600bps, 115200bps, etc. + * + * In all cases only low 15 bits of the divisor are used to divide + * the baud base and therefore 32767 is the maximum divisor value + * possible, even though documentation says that the programmable + * Baud Rate Generator is capable of dividing the internal PLL + * clock by any divisor from 1 to 65535. */ - if ((port->flags & UPF_MAGIC_MULTIPLIER) && - baud == (port->uartclk/4)) + if (magic_multiplier && baud >= port->uartclk / 6) quot = 0x8001; - else if ((port->flags & UPF_MAGIC_MULTIPLIER) && - baud == (port->uartclk/8)) + else if (magic_multiplier && baud >= port->uartclk / 12) quot = 0x8002; else if (up->port.type == PORT_NPCM) quot = npcm_get_divisor(up, baud); @@ -2629,6 +2655,21 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, struct ktermios *old) { unsigned int tolerance = port->uartclk / 100; + unsigned int min; + unsigned int max; + + /* + * Handle magic divisors for baud rates above baud_base on SMSC + * Super I/O chips. Enable custom rates of clk/4 and clk/8, but + * disable divisor values beyond 32767, which are unavailable. + */ + if (port->flags & UPF_MAGIC_MULTIPLIER) { + min = port->uartclk / 16 / UART_DIV_MAX >> 1; + max = (port->uartclk + tolerance) / 4; + } else { + min = port->uartclk / 16 / UART_DIV_MAX; + max = (port->uartclk + tolerance) / 16; + } /* * Ask the core to calculate the divisor for us. @@ -2636,9 +2677,7 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, * slower than nominal still match standard baud rates without * causing transmission errors. */ - return uart_get_baud_rate(port, termios, old, - port->uartclk / 16 / UART_DIV_MAX, - (port->uartclk + tolerance) / 16); + return uart_get_baud_rate(port, termios, old, min, max); } /* diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c index 63ea9c4da3d5..dc2ef05a10eb 100644 --- a/drivers/tty/serial/8250/serial_cs.c +++ b/drivers/tty/serial/8250/serial_cs.c @@ -306,6 +306,7 @@ static int serial_resume(struct pcmcia_device *link) static int serial_probe(struct pcmcia_device *link) { struct serial_info *info; + int ret; dev_dbg(&link->dev, "serial_attach()\n"); @@ -320,7 +321,15 @@ static int serial_probe(struct pcmcia_device *link) if (do_sound) link->config_flags |= CONF_ENABLE_SPKR; - return serial_config(link); + ret = serial_config(link); + if (ret) + goto free_info; + + return 0; + +free_info: + kfree(info); + return ret; } static void serial_detach(struct pcmcia_device *link) @@ -777,6 +786,7 @@ static const struct pcmcia_device_id serial_ids[] = { PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT2834LT", 0x5f73be51, 0x4cd7c09e), PCMCIA_DEVICE_PROD_ID12("OEM ", "C288MX ", 0xb572d360, 0xd2385b7a), PCMCIA_DEVICE_PROD_ID12("Option International", "V34bis GSM/PSTN Data/Fax Modem", 0x9d7cd6f5, 0x5cb8bf41), + PCMCIA_DEVICE_PROD_ID12("Option International", "GSM-Ready 56K/ISDN", 0x9d7cd6f5, 0xb23844aa), PCMCIA_DEVICE_PROD_ID12("PCMCIA ", "C336MX ", 0x99bcafe9, 0xaa25bcab), PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f), PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "Dual RS-232 Serial Port PC Card", 0xc4420b35, 0x031a380d), @@ -804,7 +814,6 @@ static const struct pcmcia_device_id serial_ids[] = { PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "cis/COMpad4.cis"), PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "cis/COMpad2.cis"), PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "cis/RS-COM-2P.cis"), - PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "cis/GLOBETROTTER.cis"), PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100 1.00.", 0x19ca78af, 0xf964f42b), PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL100", 0x19ca78af, 0x71d98e83), PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.", "SERIAL CARD: SL232 1.00.", 0x19ca78af, 0x69fb7490), diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 682f9171c82c..24282ad99d85 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1553,6 +1553,7 @@ config SERIAL_LITEUART_CONSOLE bool "LiteUART serial port console support" depends on SERIAL_LITEUART=y select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON help Say 'Y' or 'M' here if you wish to use the FPGA-based LiteUART serial controller from LiteX SoC builder as the system console diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 78682c12156a..e14f3378b8a0 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1062,7 +1062,7 @@ static void pl011_dma_rx_poll(struct timer_list *t) struct tty_port *port = &uap->port.state->port; struct pl011_dmarx_data *dmarx = &uap->dmarx; struct dma_chan *rxchan = uap->dmarx.chan; - unsigned long flags = 0; + unsigned long flags; unsigned int dmataken = 0; unsigned int size = 0; struct pl011_sgbuf *sgbuf; diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 1a9444b6b57e..596217d10d5c 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -149,7 +149,7 @@ static unsigned int arc_serial_tx_empty(struct uart_port *port) /* * Driver internal routine, used by both tty(serial core) as well as tx-isr * -Called under spinlock in either cases - * -also tty->stopped has already been checked + * -also tty->flow.stopped has already been checked * = by uart_start( ) before calling us * = tx_ist checks that too before calling */ diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 058886d9045b..249ea35088d2 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -30,9 +30,9 @@ #include <linux/irq.h> #include <linux/suspend.h> #include <linux/mm.h> +#include <linux/io.h> #include <asm/div64.h> -#include <asm/io.h> #include <asm/ioctls.h> #define PDC_BUFFER_SIZE 512 diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index 58aaa533203b..c719aa2b1832 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -524,24 +524,7 @@ static void cpm_uart_set_termios(struct uart_port *port, scval = 0; /* byte size */ - switch (termios->c_cflag & CSIZE) { - case CS5: - bits = 5; - break; - case CS6: - bits = 6; - break; - case CS7: - bits = 7; - break; - case CS8: - bits = 8; - break; - /* Never happens, but GCC is too dumb to figure it out */ - default: - bits = 8; - break; - } + bits = tty_get_char_size(termios->c_cflag); sbits = bits - 5; if (termios->c_cflag & CSTOPB) { diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c index 4552742c3859..e9edabc5a211 100644 --- a/drivers/tty/serial/dz.c +++ b/drivers/tty/serial/dz.c @@ -47,8 +47,8 @@ #include <linux/tty_flip.h> #include <linux/atomic.h> +#include <linux/io.h> #include <asm/bootinfo.h> -#include <asm/io.h> #include <asm/dec/interrupts.h> #include <asm/dec/kn01.h> @@ -115,7 +115,7 @@ static void dz_out(struct dz_port *dport, unsigned offset, u16 value) * rs_stop () and rs_start () * * These routines are called before setting or resetting - * tty->stopped. They enable or disable transmitter interrupts, + * tty->flow.stopped. They enable or disable transmitter interrupts, * as necessary. * ------------------------------------------------------------ */ diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 794035041744..508128ddfa01 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -824,21 +824,18 @@ static unsigned int lpuart32_tx_empty(struct uart_port *port) static void lpuart_txint(struct lpuart_port *sport) { - unsigned long flags; - - spin_lock_irqsave(&sport->port.lock, flags); + spin_lock(&sport->port.lock); lpuart_transmit_buffer(sport); - spin_unlock_irqrestore(&sport->port.lock, flags); + spin_unlock(&sport->port.lock); } static void lpuart_rxint(struct lpuart_port *sport) { unsigned int flg, ignored = 0, overrun = 0; struct tty_port *port = &sport->port.state->port; - unsigned long flags; unsigned char rx, sr; - spin_lock_irqsave(&sport->port.lock, flags); + spin_lock(&sport->port.lock); while (!(readb(sport->port.membase + UARTSFIFO) & UARTSFIFO_RXEMPT)) { flg = TTY_NORMAL; @@ -850,7 +847,7 @@ static void lpuart_rxint(struct lpuart_port *sport) sr = readb(sport->port.membase + UARTSR1); rx = readb(sport->port.membase + UARTDR); - if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) + if (uart_prepare_sysrq_char(&sport->port, rx)) continue; if (sr & (UARTSR1_PE | UARTSR1_OR | UARTSR1_FE)) { @@ -896,28 +893,26 @@ out: writeb(UARTSFIFO_RXOF, sport->port.membase + UARTSFIFO); } - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_unlock_and_check_sysrq(&sport->port); tty_flip_buffer_push(port); } static void lpuart32_txint(struct lpuart_port *sport) { - unsigned long flags; - - spin_lock_irqsave(&sport->port.lock, flags); + spin_lock(&sport->port.lock); lpuart32_transmit_buffer(sport); - spin_unlock_irqrestore(&sport->port.lock, flags); + spin_unlock(&sport->port.lock); } static void lpuart32_rxint(struct lpuart_port *sport) { unsigned int flg, ignored = 0; struct tty_port *port = &sport->port.state->port; - unsigned long flags; unsigned long rx, sr; + bool is_break; - spin_lock_irqsave(&sport->port.lock, flags); + spin_lock(&sport->port.lock); while (!(lpuart32_read(&sport->port, UARTFIFO) & UARTFIFO_RXEMPT)) { flg = TTY_NORMAL; @@ -928,16 +923,29 @@ static void lpuart32_rxint(struct lpuart_port *sport) */ sr = lpuart32_read(&sport->port, UARTSTAT); rx = lpuart32_read(&sport->port, UARTDATA); - rx &= 0x3ff; + rx &= UARTDATA_MASK; + + /* + * The LPUART can't distinguish between a break and a framing error, + * thus we assume it is a break if the received data is zero. + */ + is_break = (sr & UARTSTAT_FE) && !rx; - if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) + if (is_break && uart_handle_break(&sport->port)) + continue; + + if (uart_prepare_sysrq_char(&sport->port, rx)) continue; if (sr & (UARTSTAT_PE | UARTSTAT_OR | UARTSTAT_FE)) { - if (sr & UARTSTAT_PE) - sport->port.icount.parity++; - else if (sr & UARTSTAT_FE) + if (sr & UARTSTAT_PE) { + if (is_break) + sport->port.icount.brk++; + else + sport->port.icount.parity++; + } else if (sr & UARTSTAT_FE) { sport->port.icount.frame++; + } if (sr & UARTSTAT_OR) sport->port.icount.overrun++; @@ -950,22 +958,24 @@ static void lpuart32_rxint(struct lpuart_port *sport) sr &= sport->port.read_status_mask; - if (sr & UARTSTAT_PE) - flg = TTY_PARITY; - else if (sr & UARTSTAT_FE) + if (sr & UARTSTAT_PE) { + if (is_break) + flg = TTY_BREAK; + else + flg = TTY_PARITY; + } else if (sr & UARTSTAT_FE) { flg = TTY_FRAME; + } if (sr & UARTSTAT_OR) flg = TTY_OVERRUN; - - sport->port.sysrq = 0; } tty_insert_flip_char(port, rx, flg); } out: - spin_unlock_irqrestore(&sport->port.lock, flags); + uart_unlock_and_check_sysrq(&sport->port); tty_flip_buffer_push(port); } @@ -1393,58 +1403,54 @@ static int lpuart32_config_rs485(struct uart_port *port, static unsigned int lpuart_get_mctrl(struct uart_port *port) { - unsigned int temp = 0; - unsigned char reg; - - reg = readb(port->membase + UARTMODEM); - if (reg & UARTMODEM_TXCTSE) - temp |= TIOCM_CTS; + unsigned int mctrl = 0; + u8 reg; - if (reg & UARTMODEM_RXRTSE) - temp |= TIOCM_RTS; + reg = readb(port->membase + UARTCR1); + if (reg & UARTCR1_LOOPS) + mctrl |= TIOCM_LOOP; - return temp; + return mctrl; } static unsigned int lpuart32_get_mctrl(struct uart_port *port) { - unsigned int temp = 0; - unsigned long reg; - - reg = lpuart32_read(port, UARTMODIR); - if (reg & UARTMODIR_TXCTSE) - temp |= TIOCM_CTS; + unsigned int mctrl = 0; + u32 reg; - if (reg & UARTMODIR_RXRTSE) - temp |= TIOCM_RTS; + reg = lpuart32_read(port, UARTCTRL); + if (reg & UARTCTRL_LOOPS) + mctrl |= TIOCM_LOOP; - return temp; + return mctrl; } static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl) { - unsigned char temp; - struct lpuart_port *sport = container_of(port, - struct lpuart_port, port); + u8 reg; - /* Make sure RXRTSE bit is not set when RS485 is enabled */ - if (!(sport->port.rs485.flags & SER_RS485_ENABLED)) { - temp = readb(sport->port.membase + UARTMODEM) & - ~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); + reg = readb(port->membase + UARTCR1); - if (mctrl & TIOCM_RTS) - temp |= UARTMODEM_RXRTSE; + /* for internal loopback we need LOOPS=1 and RSRC=0 */ + reg &= ~(UARTCR1_LOOPS | UARTCR1_RSRC); + if (mctrl & TIOCM_LOOP) + reg |= UARTCR1_LOOPS; - if (mctrl & TIOCM_CTS) - temp |= UARTMODEM_TXCTSE; - - writeb(temp, port->membase + UARTMODEM); - } + writeb(reg, port->membase + UARTCR1); } static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl) { + u32 reg; + + reg = lpuart32_read(port, UARTCTRL); + /* for internal loopback we need LOOPS=1 and RSRC=0 */ + reg &= ~(UARTCTRL_LOOPS | UARTCTRL_RSRC); + if (mctrl & TIOCM_LOOP) + reg |= UARTCTRL_LOOPS; + + lpuart32_write(port, reg, UARTCTRL); } static void lpuart_break_ctl(struct uart_port *port, int break_state) @@ -1581,6 +1587,9 @@ static void lpuart_tx_dma_startup(struct lpuart_port *sport) u32 uartbaud; int ret; + if (uart_console(&sport->port)) + goto err; + if (!sport->dma_tx_chan) goto err; @@ -1610,6 +1619,9 @@ static void lpuart_rx_dma_startup(struct lpuart_port *sport) int ret; unsigned char cr3; + if (uart_console(&sport->port)) + goto err; + if (!sport->dma_rx_chan) goto err; @@ -1625,7 +1637,7 @@ static void lpuart_rx_dma_startup(struct lpuart_port *sport) sport->lpuart_dma_rx_use = true; rx_dma_timer_init(sport); - if (sport->port.has_sysrq) { + if (sport->port.has_sysrq && !lpuart_is_32(sport)) { cr3 = readb(sport->port.membase + UARTCR3); cr3 |= UARTCR3_FEIE; writeb(cr3, sport->port.membase + UARTCR3); @@ -2278,7 +2290,7 @@ lpuart_console_write(struct console *co, const char *s, unsigned int count) unsigned long flags; int locked = 1; - if (sport->port.sysrq || oops_in_progress) + if (oops_in_progress) locked = spin_trylock_irqsave(&sport->port.lock, flags); else spin_lock_irqsave(&sport->port.lock, flags); @@ -2308,7 +2320,7 @@ lpuart32_console_write(struct console *co, const char *s, unsigned int count) unsigned long flags; int locked = 1; - if (sport->port.sysrq || oops_in_progress) + if (oops_in_progress) locked = spin_trylock_irqsave(&sport->port.lock, flags); else spin_lock_irqsave(&sport->port.lock, flags); @@ -2414,6 +2426,9 @@ lpuart32_console_get_options(struct lpuart_port *sport, int *baud, bd = lpuart32_read(&sport->port, UARTBAUD); bd &= UARTBAUD_SBR_MASK; + if (!bd) + return; + sbr = bd; uartclk = lpuart_get_baud_clk_rate(sport); /* diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index 9e9abfc4824a..03a2fe9f4c9a 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -37,7 +37,7 @@ #include <linux/firmware.h> #include <linux/bitops.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> #include <linux/uaccess.h> diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 7d5a8dfa3e91..8b121cd869e9 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -225,6 +225,8 @@ struct imx_port { struct scatterlist rx_sgl, tx_sgl[2]; void *rx_buf; struct circ_buf rx_ring; + unsigned int rx_buf_size; + unsigned int rx_period_length; unsigned int rx_periods; dma_cookie_t rx_cookie; unsigned int tx_bytes; @@ -1183,10 +1185,6 @@ static void imx_uart_dma_rx_callback(void *data) } } -/* RX DMA buffer periods */ -#define RX_DMA_PERIODS 16 -#define RX_BUF_SIZE (RX_DMA_PERIODS * PAGE_SIZE / 4) - static int imx_uart_start_rx_dma(struct imx_port *sport) { struct scatterlist *sgl = &sport->rx_sgl; @@ -1197,9 +1195,8 @@ static int imx_uart_start_rx_dma(struct imx_port *sport) sport->rx_ring.head = 0; sport->rx_ring.tail = 0; - sport->rx_periods = RX_DMA_PERIODS; - sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE); + sg_init_one(sgl, sport->rx_buf, sport->rx_buf_size); ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE); if (ret == 0) { dev_err(dev, "DMA mapping error for RX.\n"); @@ -1316,7 +1313,8 @@ static int imx_uart_dma_init(struct imx_port *sport) goto err; } - sport->rx_buf = kzalloc(RX_BUF_SIZE, GFP_KERNEL); + sport->rx_buf_size = sport->rx_period_length * sport->rx_periods; + sport->rx_buf = kzalloc(sport->rx_buf_size, GFP_KERNEL); if (!sport->rx_buf) { ret = -ENOMEM; goto err; @@ -1975,8 +1973,8 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count) { struct imx_port *sport = imx_uart_ports[co->index]; struct imx_port_ucrs old_ucr; + unsigned long flags; unsigned int ucr1; - unsigned long flags = 0; int locked = 1; if (sport->port.sysrq) @@ -2179,11 +2177,16 @@ static enum hrtimer_restart imx_trigger_stop_tx(struct hrtimer *t) return HRTIMER_NORESTART; } +/* Default RX DMA buffer configuration */ +#define RX_DMA_PERIODS 16 +#define RX_DMA_PERIOD_LEN (PAGE_SIZE / 4) + static int imx_uart_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct imx_port *sport; void __iomem *base; + u32 dma_buf_conf[2]; int ret = 0; u32 ucr1; struct resource *res; @@ -2218,6 +2221,14 @@ static int imx_uart_probe(struct platform_device *pdev) if (of_get_property(np, "fsl,inverted-rx", NULL)) sport->inverted_rx = 1; + if (!of_property_read_u32_array(np, "fsl,dma-info", dma_buf_conf, 2)) { + sport->rx_period_length = dma_buf_conf[0]; + sport->rx_periods = dma_buf_conf[1]; + } else { + sport->rx_period_length = RX_DMA_PERIOD_LEN; + sport->rx_periods = RX_DMA_PERIODS; + } + if (sport->port.line >= ARRAY_SIZE(imx_uart_ports)) { dev_err(&pdev->dev, "serial%d out of range\n", sport->port.line); diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c index 86fff69d7e7c..f4dc5fe4ba92 100644 --- a/drivers/tty/serial/ip22zilog.c +++ b/drivers/tty/serial/ip22zilog.c @@ -31,7 +31,7 @@ #include <linux/spinlock.h> #include <linux/init.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> #include <asm/sgialib.h> #include <asm/sgi/ioc.h> diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c index db059b66438e..3e7c6ee8e4b3 100644 --- a/drivers/tty/serial/kgdb_nmi.c +++ b/drivers/tty/serial/kgdb_nmi.c @@ -115,7 +115,7 @@ static void kgdb_tty_recv(int ch) static int kgdb_nmi_poll_one_knock(void) { static int n; - int c = -1; + int c; const char *magic = kgdb_nmi_magic; size_t m = strlen(magic); bool printch = false; @@ -298,7 +298,7 @@ static void kgdb_nmi_tty_hangup(struct tty_struct *tty) tty_port_hangup(&priv->port); } -static int kgdb_nmi_tty_write_room(struct tty_struct *tty) +static unsigned int kgdb_nmi_tty_write_room(struct tty_struct *tty) { /* Actually, we can handle any amount as we use polled writes. */ return 2048; diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c index 0b06770642cb..dbc0559a9157 100644 --- a/drivers/tty/serial/liteuart.c +++ b/drivers/tty/serial/liteuart.c @@ -370,6 +370,27 @@ static int __init liteuart_console_init(void) return 0; } console_initcall(liteuart_console_init); + +static void early_liteuart_write(struct console *console, const char *s, + unsigned int count) +{ + struct earlycon_device *device = console->data; + struct uart_port *port = &device->port; + + uart_console_write(port, s, count, liteuart_putchar); +} + +static int __init early_liteuart_setup(struct earlycon_device *device, + const char *options) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = early_liteuart_write; + return 0; +} + +OF_EARLYCON_DECLARE(liteuart, "litex,liteuart", early_liteuart_setup); #endif /* CONFIG_SERIAL_LITEUART_CONSOLE */ static int __init liteuart_init(void) diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 3cbc757d7be7..0c1e4df52215 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -552,7 +552,7 @@ static int max310x_update_best_err(unsigned long f, long *besterr) return 1; } -static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s, +static u32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s, unsigned long freq, bool xtal) { unsigned int div, clksrc, pllcfg = 0; @@ -618,7 +618,7 @@ static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s, } } - return (int)bestfreq; + return bestfreq; } static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len) @@ -1253,9 +1253,10 @@ static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset, static int max310x_probe(struct device *dev, const struct max310x_devtype *devtype, struct regmap *regmap, int irq) { - int i, ret, fmin, fmax, freq, uartclk; + int i, ret, fmin, fmax, freq; struct max310x_port *s; - bool xtal = false; + u32 uartclk = 0; + bool xtal; if (IS_ERR(regmap)) return PTR_ERR(regmap); @@ -1267,24 +1268,20 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty return -ENOMEM; } + /* Always ask for fixed clock rate from a property. */ + device_property_read_u32(dev, "clock-frequency", &uartclk); + s->clk = devm_clk_get_optional(dev, "osc"); if (IS_ERR(s->clk)) return PTR_ERR(s->clk); if (s->clk) { - fmin = 500000; - fmax = 35000000; + xtal = false; } else { s->clk = devm_clk_get_optional(dev, "xtal"); if (IS_ERR(s->clk)) return PTR_ERR(s->clk); - if (s->clk) { - fmin = 1000000; - fmax = 4000000; - xtal = true; - } else { - dev_err(dev, "Cannot get clock\n"); - return -EINVAL; - } + + xtal = true; } ret = clk_prepare_enable(s->clk); @@ -1292,6 +1289,21 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty return ret; freq = clk_get_rate(s->clk); + if (freq == 0) + freq = uartclk; + if (freq == 0) { + dev_err(dev, "Cannot get clock rate\n"); + return -EINVAL; + } + + if (xtal) { + fmin = 1000000; + fmax = 4000000; + } else { + fmin = 500000; + fmax = 35000000; + } + /* Check frequency limits */ if (freq < fmin || freq > fmax) { ret = -ERANGE; diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 529cd0289056..efee3935917f 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -715,13 +715,15 @@ static int meson_uart_probe(struct platform_device *pdev) { struct resource *res_mem, *res_irq; struct uart_port *port; + u32 fifosize = 64; /* Default is 64, 128 for EE UART_0 */ int ret = 0; - int id = -1; if (pdev->dev.of_node) pdev->id = of_alias_get_id(pdev->dev.of_node, "serial"); if (pdev->id < 0) { + int id; + for (id = AML_UART_PORT_OFFSET; id < AML_UART_PORT_NUM; id++) { if (!meson_ports[id]) { pdev->id = id; @@ -741,6 +743,8 @@ static int meson_uart_probe(struct platform_device *pdev) if (!res_irq) return -ENODEV; + of_property_read_u32(pdev->dev.of_node, "fifo-size", &fifosize); + if (meson_ports[pdev->id]) { dev_err(&pdev->dev, "port %d already allocated\n", pdev->id); return -EBUSY; @@ -770,7 +774,7 @@ static int meson_uart_probe(struct platform_device *pdev) port->type = PORT_MESON; port->x_char = 0; port->ops = &meson_uart_ops; - port->fifosize = 64; + port->fifosize = fifosize; meson_ports[pdev->id] = port; platform_set_drvdata(pdev, port); diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c index 47ab280f553b..be640d9863cd 100644 --- a/drivers/tty/serial/mux.c +++ b/drivers/tty/serial/mux.c @@ -21,7 +21,7 @@ #include <linux/console.h> #include <linux/delay.h> /* for udelay */ #include <linux/device.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> #include <asm/parisc-device.h> diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index 51b0ecabf2ec..231de29a6452 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -128,7 +128,6 @@ struct mvebu_uart { struct uart_port *port; struct clk *clk; int irq[UART_IRQ_COUNT]; - unsigned char __iomem *nb; struct mvebu_uart_driver_data *data; #if defined(CONFIG_PM) struct mvebu_uart_pm_regs pm_regs; @@ -445,12 +444,11 @@ static void mvebu_uart_shutdown(struct uart_port *port) static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud) { - struct mvebu_uart *mvuart = to_mvuart(port); unsigned int d_divisor, m_divisor; u32 brdv, osamp; - if (IS_ERR(mvuart->clk)) - return -PTR_ERR(mvuart->clk); + if (!port->uartclk) + return -EOPNOTSUPP; /* * The baudrate is derived from the UART clock thanks to two divisors: @@ -463,7 +461,7 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud) * makes use of D to configure the desired baudrate. */ m_divisor = OSAMP_DEFAULT_DIVISOR; - d_divisor = DIV_ROUND_UP(port->uartclk, baud * m_divisor); + d_divisor = DIV_ROUND_CLOSEST(port->uartclk, baud * m_divisor); brdv = readl(port->membase + UART_BRDV); brdv &= ~BRDV_BAUD_MASK; @@ -482,7 +480,7 @@ static void mvebu_uart_set_termios(struct uart_port *port, struct ktermios *old) { unsigned long flags; - unsigned int baud; + unsigned int baud, min_baud, max_baud; spin_lock_irqsave(&port->lock, flags); @@ -501,16 +499,21 @@ static void mvebu_uart_set_termios(struct uart_port *port, port->ignore_status_mask |= STAT_RX_RDY(port) | STAT_BRK_ERR; /* + * Maximal divisor is 1023 * 16 when using default (x16) scheme. * Maximum achievable frequency with simple baudrate divisor is 230400. * Since the error per bit frame would be of more than 15%, achieving * higher frequencies would require to implement the fractional divisor * feature. */ - baud = uart_get_baud_rate(port, termios, old, 0, 230400); + min_baud = DIV_ROUND_UP(port->uartclk, 1023 * 16); + max_baud = 230400; + + baud = uart_get_baud_rate(port, termios, old, min_baud, max_baud); if (mvebu_uart_baud_rate_set(port, baud)) { /* No clock available, baudrate cannot be changed */ if (old) - baud = uart_get_baud_rate(port, old, NULL, 0, 230400); + baud = uart_get_baud_rate(port, old, NULL, + min_baud, max_baud); } else { tty_termios_encode_baud_rate(termios, baud, baud); uart_update_timeout(port, termios->c_cflag, baud); @@ -617,7 +620,7 @@ static void mvebu_uart_putc(struct uart_port *port, int c) static void mvebu_uart_putc_early_write(struct console *con, const char *s, - unsigned n) + unsigned int n) { struct earlycon_device *dev = con->data; diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index f414d6acad69..ac45f3386e97 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -87,7 +87,7 @@ #define AUART_LINECTRL_BAUD_DIVFRAC(v) (((v) & 0x3f) << 8) #define AUART_LINECTRL_SPS (1 << 7) #define AUART_LINECTRL_WLEN_MASK 0x00000060 -#define AUART_LINECTRL_WLEN(v) (((v) & 0x3) << 5) +#define AUART_LINECTRL_WLEN(v) ((((v) - 5) & 0x3) << 5) #define AUART_LINECTRL_FEN (1 << 4) #define AUART_LINECTRL_STP2 (1 << 3) #define AUART_LINECTRL_EPS (1 << 2) @@ -962,7 +962,7 @@ static void mxs_auart_settermios(struct uart_port *u, struct ktermios *old) { struct mxs_auart_port *s = to_auart_port(u); - u32 bm, ctrl, ctrl2, div; + u32 ctrl, ctrl2, div; unsigned int cflag, baud, baud_min, baud_max; cflag = termios->c_cflag; @@ -970,25 +970,7 @@ static void mxs_auart_settermios(struct uart_port *u, ctrl = AUART_LINECTRL_FEN; ctrl2 = mxs_read(s, REG_CTRL2); - /* byte size */ - switch (cflag & CSIZE) { - case CS5: - bm = 0; - break; - case CS6: - bm = 1; - break; - case CS7: - bm = 2; - break; - case CS8: - bm = 3; - break; - default: - return; - } - - ctrl |= AUART_LINECTRL_WLEN(bm); + ctrl |= AUART_LINECTRL_WLEN(tty_get_char_size(cflag)); /* parity */ if (cflag & PARENB) { @@ -1403,7 +1385,7 @@ auart_console_get_options(struct mxs_auart_port *s, int *baud, *parity = 'o'; } - if ((lcr_h & AUART_LINECTRL_WLEN_MASK) == AUART_LINECTRL_WLEN(2)) + if ((lcr_h & AUART_LINECTRL_WLEN_MASK) == AUART_LINECTRL_WLEN(7)) *bits = 7; else *bits = 8; diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 84e8158088cd..9e81b09ba08e 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -626,7 +626,7 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id) static unsigned int serial_omap_tx_empty(struct uart_port *port) { struct uart_omap_port *up = to_uart_omap_port(port); - unsigned long flags = 0; + unsigned long flags; unsigned int ret = 0; pm_runtime_get_sync(up->dev); @@ -704,7 +704,7 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) static void serial_omap_break_ctl(struct uart_port *port, int break_state) { struct uart_omap_port *up = to_uart_omap_port(port); - unsigned long flags = 0; + unsigned long flags; dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->port.line); pm_runtime_get_sync(up->dev); @@ -722,7 +722,7 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state) static int serial_omap_startup(struct uart_port *port) { struct uart_omap_port *up = to_uart_omap_port(port); - unsigned long flags = 0; + unsigned long flags; int retval; /* @@ -797,7 +797,7 @@ static int serial_omap_startup(struct uart_port *port) static void serial_omap_shutdown(struct uart_port *port) { struct uart_omap_port *up = to_uart_omap_port(port); - unsigned long flags = 0; + unsigned long flags; dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->port.line); @@ -845,7 +845,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, { struct uart_omap_port *up = to_uart_omap_port(port); unsigned char cval = 0; - unsigned long flags = 0; + unsigned long flags; unsigned int baud, quot; switch (termios->c_cflag & CSIZE) { diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index d6aef8a1f0a4..12ce150b0ad4 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -47,7 +47,7 @@ #include <linux/of_address.h> #include <linux/of_irq.h> #include <asm/sections.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> #ifdef CONFIG_PPC_PMAC diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 23d729ed3bf6..aedc38893e6c 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -1050,21 +1050,7 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, } /* bits per char */ - switch (termios->c_cflag & CSIZE) { - case CS5: - bits_per_char = 5; - break; - case CS6: - bits_per_char = 6; - break; - case CS7: - bits_per_char = 7; - break; - case CS8: - default: - bits_per_char = 8; - break; - } + bits_per_char = tty_get_char_size(termios->c_cflag); /* stop bits */ if (termios->c_cflag & CSTOPB) @@ -1338,7 +1324,7 @@ static const struct uart_ops qcom_geni_uart_pops = { static int qcom_geni_serial_probe(struct platform_device *pdev) { int ret = 0; - int line = -1; + int line; struct qcom_geni_serial_port *port; struct uart_port *uport; struct resource *res; @@ -1354,7 +1340,9 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) line = of_alias_get_id(pdev->dev.of_node, "serial"); } else { drv = &qcom_geni_uart_driver; - line = of_alias_get_id(pdev->dev.of_node, "hsuart"); + line = of_alias_get_id(pdev->dev.of_node, "serial"); + if (line == -ENODEV) /* compat with non-standard aliases */ + line = of_alias_get_id(pdev->dev.of_node, "hsuart"); } port = get_port_from_line(line, console); diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index d9e4b67a12a0..9fbc61151c2e 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -2220,8 +2220,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) default: dev_warn(&pdev->dev, "unsupported reg-io-width (%d)\n", prop); - ret = -EINVAL; - break; + return -EINVAL; } } } diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c index 22c7bc90b104..738df6d9c0d9 100644 --- a/drivers/tty/serial/sb1250-duart.c +++ b/drivers/tty/serial/sb1250-duart.c @@ -34,7 +34,7 @@ #include <linux/types.h> #include <linux/refcount.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/sibyte/sb1250.h> #include <asm/sibyte/sb1250_uart.h> diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 9adb8362578c..acbb615dd28f 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1208,8 +1208,16 @@ static int sc16is7xx_probe(struct device *dev, /* Always ask for fixed clock rate from a property. */ device_property_read_u32(dev, "clock-frequency", &uartclk); - s->clk = devm_clk_get(dev, NULL); - if (IS_ERR(s->clk)) { + s->clk = devm_clk_get_optional(dev, NULL); + if (IS_ERR(s->clk)) + return PTR_ERR(s->clk); + + ret = clk_prepare_enable(s->clk); + if (ret) + return ret; + + freq = clk_get_rate(s->clk); + if (freq == 0) { if (uartclk) freq = uartclk; if (pfreq) @@ -1217,13 +1225,7 @@ static int sc16is7xx_probe(struct device *dev, if (freq) dev_dbg(dev, "Clock frequency: %luHz\n", freq); else - return PTR_ERR(s->clk); - } else { - ret = clk_prepare_enable(s->clk); - if (ret) - return ret; - - freq = clk_get_rate(s->clk); + return -EINVAL; } s->regmap = regmap; @@ -1358,8 +1360,7 @@ out_thread: kthread_stop(s->kworker_task); out_clk: - if (!IS_ERR(s->clk)) - clk_disable_unprepare(s->clk); + clk_disable_unprepare(s->clk); return ret; } @@ -1383,8 +1384,7 @@ static int sc16is7xx_remove(struct device *dev) kthread_flush_worker(&s->kworker); kthread_stop(s->kworker_task); - if (!IS_ERR(s->clk)) - clk_disable_unprepare(s->clk); + clk_disable_unprepare(s->clk); return 0; } diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 18ff85a83f80..69092deba11f 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -184,8 +184,8 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, int init_hw) { struct uart_port *uport = uart_port_check(state); + unsigned long flags; unsigned long page; - unsigned long flags = 0; int retval = 0; if (uport->type == PORT_UNKNOWN) @@ -275,7 +275,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) { struct uart_port *uport = uart_port_check(state); struct tty_port *port = &state->port; - unsigned long flags = 0; + unsigned long flags; char *xmit_buf = NULL; /* @@ -334,39 +334,15 @@ void uart_update_timeout(struct uart_port *port, unsigned int cflag, unsigned int baud) { - unsigned int bits; + unsigned int size; - /* byte size and parity */ - switch (cflag & CSIZE) { - case CS5: - bits = 7; - break; - case CS6: - bits = 8; - break; - case CS7: - bits = 9; - break; - default: - bits = 10; - break; /* CS8 */ - } - - if (cflag & CSTOPB) - bits++; - if (cflag & PARENB) - bits++; - - /* - * The total number of bits to be transmitted in the fifo. - */ - bits = bits * port->fifosize; + size = tty_get_frame_size(cflag) * port->fifosize; /* * Figure the timeout to send the above number of bits. * Add .02 seconds of slop */ - port->timeout = (HZ * bits) / baud + HZ/50; + port->timeout = (HZ * size) / baud + HZ/50; } EXPORT_SYMBOL(uart_update_timeout); @@ -616,12 +592,12 @@ static int uart_write(struct tty_struct *tty, return ret; } -static int uart_write_room(struct tty_struct *tty) +static unsigned int uart_write_room(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; struct uart_port *port; unsigned long flags; - int ret; + unsigned int ret; port = uart_port_lock(state, flags); ret = uart_circ_chars_free(&state->xmit); @@ -629,12 +605,12 @@ static int uart_write_room(struct tty_struct *tty) return ret; } -static int uart_chars_in_buffer(struct tty_struct *tty) +static unsigned int uart_chars_in_buffer(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; struct uart_port *port; unsigned long flags; - int ret; + unsigned int ret; port = uart_port_lock(state, flags); ret = uart_circ_chars_pending(&state->xmit); @@ -3029,26 +3005,28 @@ out: /* * Are the two ports equivalent? */ -int uart_match_port(struct uart_port *port1, struct uart_port *port2) +bool uart_match_port(const struct uart_port *port1, + const struct uart_port *port2) { if (port1->iotype != port2->iotype) - return 0; + return false; switch (port1->iotype) { case UPIO_PORT: - return (port1->iobase == port2->iobase); + return port1->iobase == port2->iobase; case UPIO_HUB6: - return (port1->iobase == port2->iobase) && - (port1->hub6 == port2->hub6); + return port1->iobase == port2->iobase && + port1->hub6 == port2->hub6; case UPIO_MEM: case UPIO_MEM16: case UPIO_MEM32: case UPIO_MEM32BE: case UPIO_AU: case UPIO_TSI: - return (port1->mapbase == port2->mapbase); + return port1->mapbase == port2->mapbase; } - return 0; + + return false; } EXPORT_SYMBOL(uart_match_port); diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index 0a7e5b74bc1d..aaca4fe38486 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -24,7 +24,7 @@ #include <linux/tty.h> #include <linux/tty_flip.h> -#include <asm/io.h> +#include <linux/io.h> static char *serial_version = "1.11"; static char *serial_name = "TX39/49 Serial driver"; diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 4baf1316ea72..07eb56294371 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -289,7 +289,7 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { }, /* - * The "SCIFA" that is in RZ/T and RZ/A2. + * The "SCIFA" that is in RZ/A2, RZ/G2L and RZ/T. * It looks like a normal SCIF with FIFO data, but with a * compressed address space. Also, the break out of interrupts * are different: ERI/BRI, RXI, TXI, TEI, DRI. @@ -306,6 +306,7 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = { [SCFDR] = { 0x0E, 16 }, [SCSPTR] = { 0x10, 16 }, [SCLSR] = { 0x12, 16 }, + [SEMR] = { 0x14, 8 }, }, .fifosize = 16, .overrun_reg = SCLSR, @@ -610,6 +611,14 @@ static void sci_stop_tx(struct uart_port *port) ctrl &= ~SCSCR_TIE; serial_port_out(port, SCSCR, ctrl); + +#ifdef CONFIG_SERIAL_SH_SCI_DMA + if (to_sci_port(port)->chan_tx && + !dma_submit_error(to_sci_port(port)->cookie_tx)) { + dmaengine_terminate_async(to_sci_port(port)->chan_tx); + to_sci_port(port)->cookie_tx = -EINVAL; + } +#endif } static void sci_start_rx(struct uart_port *port) @@ -840,9 +849,6 @@ static void sci_transmit_chars(struct uart_port *port) } -/* On SH3, SCIF may read end-of-break as a space->mark char */ -#define STEPFN(c) ({int __c = (c); (((__c-1)|(__c)) == -1); }) - static void sci_receive_chars(struct uart_port *port) { struct tty_port *tport = &port->state->port; @@ -2494,25 +2500,10 @@ done: uart_update_timeout(port, termios->c_cflag, baud); /* byte size and parity */ - switch (termios->c_cflag & CSIZE) { - case CS5: - bits = 7; - break; - case CS6: - bits = 8; - break; - case CS7: - bits = 9; - break; - default: - bits = 10; - break; - } + bits = tty_get_frame_size(termios->c_cflag); - if (termios->c_cflag & CSTOPB) - bits++; - if (termios->c_cflag & PARENB) - bits++; + if (sci_getreg(port, SEMR)->size) + serial_port_out(port, SEMR, 0); if (best_clk >= 0) { if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) @@ -3170,6 +3161,10 @@ static const struct of_device_id of_sci_match[] = { .compatible = "renesas,scif-r7s9210", .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE), }, + { + .compatible = "renesas,scif-r9a07g044", + .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE), + }, /* Family-specific types */ { .compatible = "renesas,rcar-gen1-scif", @@ -3452,6 +3447,7 @@ static int __init rzscifa_early_console_setup(struct earlycon_device *device, port_cfg.regtype = SCIx_RZ_SCIFA_REGTYPE; return early_console_setup(device, PORT_SCIF); } + static int __init scifa_early_console_setup(struct earlycon_device *device, const char *opt) { @@ -3471,6 +3467,7 @@ static int __init hscif_early_console_setup(struct earlycon_device *device, OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup); OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup); OF_EARLYCON_DECLARE(scif, "renesas,scif-r7s9210", rzscifa_early_console_setup); +OF_EARLYCON_DECLARE(scif, "renesas,scif-r9a07g044", rzscifa_early_console_setup); OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup); OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup); OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup); diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h index c0dfe4382898..c0ae78632dda 100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@ -31,6 +31,7 @@ enum { SCCKS, /* BRG Clock Select Register */ HSRTRGR, /* Rx FIFO Data Count Trigger Register */ HSTTRGR, /* Tx FIFO Data Count Trigger Register */ + SEMR, /* Serial extended mode register */ SCIx_NR_REGS, }; diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index e7048515a79c..87e480cc8206 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -65,7 +65,7 @@ static struct uart_driver asc_uart_driver; /* ASC_RXBUF */ #define ASC_RXBUF_PE 0x100 #define ASC_RXBUF_FE 0x200 -/** +/* * Some of status comes from higher bits of the character and some come from * the status register. Combining both of them in to single status using dummy * bits. @@ -478,7 +478,7 @@ static void asc_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { struct asc_port *ascport = to_asc_port(port); - unsigned long flags = 0; + unsigned long flags; u32 ctl; switch (state) { diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index c2ae7b392b86..ef793b3b4591 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -718,36 +718,6 @@ static void stm32_usart_shutdown(struct uart_port *port) free_irq(port->irq, port); } -static unsigned int stm32_usart_get_databits(struct ktermios *termios) -{ - unsigned int bits; - - tcflag_t cflag = termios->c_cflag; - - switch (cflag & CSIZE) { - /* - * CSIZE settings are not necessarily supported in hardware. - * CSIZE unsupported configurations are handled here to set word length - * to 8 bits word as default configuration and to print debug message. - */ - case CS5: - bits = 5; - break; - case CS6: - bits = 6; - break; - case CS7: - bits = 7; - break; - /* default including CS8 */ - default: - bits = 8; - break; - } - - return bits; -} - static void stm32_usart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) @@ -805,7 +775,7 @@ static void stm32_usart_set_termios(struct uart_port *port, if (cflag & CSTOPB) cr2 |= USART_CR2_STOP_2B; - bits = stm32_usart_get_databits(termios); + bits = tty_get_char_size(cflag); stm32_port->rdr_mask = (BIT(bits) - 1); if (cflag & PARENB) { @@ -980,7 +950,7 @@ static void stm32_usart_pm(struct uart_port *port, unsigned int state, struct stm32_port, port); const struct stm32_usart_offsets *ofs = &stm32port->info->ofs; const struct stm32_usart_config *cfg = &stm32port->info->cfg; - unsigned long flags = 0; + unsigned long flags; switch (state) { case UART_PM_STATE_ON: @@ -1182,6 +1152,14 @@ static const struct of_device_id stm32_match[] = { MODULE_DEVICE_TABLE(of, stm32_match); #endif +static void stm32_usart_of_dma_rx_remove(struct stm32_port *stm32port, + struct platform_device *pdev) +{ + if (stm32port->rx_buf) + dma_free_coherent(&pdev->dev, RX_BUF_L, stm32port->rx_buf, + stm32port->rx_dma_buf); +} + static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, struct platform_device *pdev) { @@ -1199,19 +1177,11 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, if (uart_console(port)) return -ENODEV; - /* Request DMA RX channel */ - stm32port->rx_ch = dma_request_slave_channel(dev, "rx"); - if (!stm32port->rx_ch) { - dev_info(dev, "rx dma alloc failed\n"); - return -ENODEV; - } stm32port->rx_buf = dma_alloc_coherent(&pdev->dev, RX_BUF_L, &stm32port->rx_dma_buf, GFP_KERNEL); - if (!stm32port->rx_buf) { - ret = -ENOMEM; - goto alloc_err; - } + if (!stm32port->rx_buf) + return -ENOMEM; /* Configure DMA channel */ memset(&config, 0, sizeof(config)); @@ -1221,8 +1191,8 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, ret = dmaengine_slave_config(stm32port->rx_ch, &config); if (ret < 0) { dev_err(dev, "rx dma channel config failed\n"); - ret = -ENODEV; - goto config_err; + stm32_usart_of_dma_rx_remove(stm32port, pdev); + return ret; } /* Prepare a DMA cyclic transaction */ @@ -1232,8 +1202,8 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, DMA_PREP_INTERRUPT); if (!desc) { dev_err(dev, "rx dma prep cyclic failed\n"); - ret = -ENODEV; - goto config_err; + stm32_usart_of_dma_rx_remove(stm32port, pdev); + return -ENODEV; } /* No callback as dma buffer is drained on usart interrupt */ @@ -1244,24 +1214,22 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, ret = dma_submit_error(dmaengine_submit(desc)); if (ret) { dmaengine_terminate_sync(stm32port->rx_ch); - goto config_err; + stm32_usart_of_dma_rx_remove(stm32port, pdev); + return ret; } /* Issue pending DMA requests */ dma_async_issue_pending(stm32port->rx_ch); return 0; +} -config_err: - dma_free_coherent(&pdev->dev, - RX_BUF_L, stm32port->rx_buf, - stm32port->rx_dma_buf); - -alloc_err: - dma_release_channel(stm32port->rx_ch); - stm32port->rx_ch = NULL; - - return ret; +static void stm32_usart_of_dma_tx_remove(struct stm32_port *stm32port, + struct platform_device *pdev) +{ + if (stm32port->tx_buf) + dma_free_coherent(&pdev->dev, TX_BUF_L, stm32port->tx_buf, + stm32port->tx_dma_buf); } static int stm32_usart_of_dma_tx_probe(struct stm32_port *stm32port, @@ -1275,19 +1243,11 @@ static int stm32_usart_of_dma_tx_probe(struct stm32_port *stm32port, stm32port->tx_dma_busy = false; - /* Request DMA TX channel */ - stm32port->tx_ch = dma_request_slave_channel(dev, "tx"); - if (!stm32port->tx_ch) { - dev_info(dev, "tx dma alloc failed\n"); - return -ENODEV; - } stm32port->tx_buf = dma_alloc_coherent(&pdev->dev, TX_BUF_L, &stm32port->tx_dma_buf, GFP_KERNEL); - if (!stm32port->tx_buf) { - ret = -ENOMEM; - goto alloc_err; - } + if (!stm32port->tx_buf) + return -ENOMEM; /* Configure DMA channel */ memset(&config, 0, sizeof(config)); @@ -1297,22 +1257,11 @@ static int stm32_usart_of_dma_tx_probe(struct stm32_port *stm32port, ret = dmaengine_slave_config(stm32port->tx_ch, &config); if (ret < 0) { dev_err(dev, "tx dma channel config failed\n"); - ret = -ENODEV; - goto config_err; + stm32_usart_of_dma_tx_remove(stm32port, pdev); + return ret; } return 0; - -config_err: - dma_free_coherent(&pdev->dev, - TX_BUF_L, stm32port->tx_buf, - stm32port->tx_dma_buf); - -alloc_err: - dma_release_channel(stm32port->tx_ch); - stm32port->tx_ch = NULL; - - return ret; } static int stm32_usart_serial_probe(struct platform_device *pdev) @@ -1336,16 +1285,43 @@ static int stm32_usart_serial_probe(struct platform_device *pdev) device_set_wakeup_capable(&pdev->dev, true); ret = dev_pm_set_wake_irq(&pdev->dev, stm32port->port.irq); if (ret) - goto err_nowup; + goto err_deinit_port; } - ret = stm32_usart_of_dma_rx_probe(stm32port, pdev); - if (ret) - dev_info(&pdev->dev, "interrupt mode used for rx (no dma)\n"); + stm32port->rx_ch = dma_request_chan(&pdev->dev, "rx"); + if (PTR_ERR(stm32port->rx_ch) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_wakeirq; + } + /* Fall back in interrupt mode for any non-deferral error */ + if (IS_ERR(stm32port->rx_ch)) + stm32port->rx_ch = NULL; + + stm32port->tx_ch = dma_request_chan(&pdev->dev, "tx"); + if (PTR_ERR(stm32port->tx_ch) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_dma_rx; + } + /* Fall back in interrupt mode for any non-deferral error */ + if (IS_ERR(stm32port->tx_ch)) + stm32port->tx_ch = NULL; - ret = stm32_usart_of_dma_tx_probe(stm32port, pdev); - if (ret) - dev_info(&pdev->dev, "interrupt mode used for tx (no dma)\n"); + if (stm32port->rx_ch && stm32_usart_of_dma_rx_probe(stm32port, pdev)) { + /* Fall back in interrupt mode */ + dma_release_channel(stm32port->rx_ch); + stm32port->rx_ch = NULL; + } + + if (stm32port->tx_ch && stm32_usart_of_dma_tx_probe(stm32port, pdev)) { + /* Fall back in interrupt mode */ + dma_release_channel(stm32port->tx_ch); + stm32port->tx_ch = NULL; + } + + if (!stm32port->rx_ch) + dev_info(&pdev->dev, "interrupt mode for rx (no dma)\n"); + if (!stm32port->tx_ch) + dev_info(&pdev->dev, "interrupt mode for tx (no dma)\n"); platform_set_drvdata(pdev, &stm32port->port); @@ -1366,30 +1342,23 @@ err_port: pm_runtime_set_suspended(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); - if (stm32port->rx_ch) { - dmaengine_terminate_async(stm32port->rx_ch); - dma_release_channel(stm32port->rx_ch); - } - - if (stm32port->rx_dma_buf) - dma_free_coherent(&pdev->dev, - RX_BUF_L, stm32port->rx_buf, - stm32port->rx_dma_buf); - if (stm32port->tx_ch) { - dmaengine_terminate_async(stm32port->tx_ch); + stm32_usart_of_dma_tx_remove(stm32port, pdev); dma_release_channel(stm32port->tx_ch); } - if (stm32port->tx_dma_buf) - dma_free_coherent(&pdev->dev, - TX_BUF_L, stm32port->tx_buf, - stm32port->tx_dma_buf); + if (stm32port->rx_ch) + stm32_usart_of_dma_rx_remove(stm32port, pdev); + +err_dma_rx: + if (stm32port->rx_ch) + dma_release_channel(stm32port->rx_ch); +err_wakeirq: if (stm32port->wakeup_src) dev_pm_clear_wake_irq(&pdev->dev); -err_nowup: +err_deinit_port: if (stm32port->wakeup_src) device_set_wakeup_capable(&pdev->dev, false); @@ -1416,28 +1385,20 @@ static int stm32_usart_serial_remove(struct platform_device *pdev) stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + if (stm32_port->tx_ch) { + dmaengine_terminate_async(stm32_port->tx_ch); + stm32_usart_of_dma_tx_remove(stm32_port, pdev); + dma_release_channel(stm32_port->tx_ch); + } + if (stm32_port->rx_ch) { dmaengine_terminate_async(stm32_port->rx_ch); + stm32_usart_of_dma_rx_remove(stm32_port, pdev); dma_release_channel(stm32_port->rx_ch); } - if (stm32_port->rx_dma_buf) - dma_free_coherent(&pdev->dev, - RX_BUF_L, stm32_port->rx_buf, - stm32_port->rx_dma_buf); - stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - if (stm32_port->tx_ch) { - dmaengine_terminate_async(stm32_port->tx_ch); - dma_release_channel(stm32_port->tx_ch); - } - - if (stm32_port->tx_dma_buf) - dma_free_coherent(&pdev->dev, - TX_BUF_L, stm32_port->tx_buf, - stm32_port->tx_dma_buf); - if (stm32_port->wakeup_src) { dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index bab551f46963..92e572634009 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -35,7 +35,7 @@ #include <linux/init.h> #include <linux/of_device.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> #include <asm/prom.h> #include <asm/setup.h> diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 12c2468f2b0e..425a016f9db7 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -39,7 +39,7 @@ #include <linux/delay.h> #include <linux/of_device.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> #include <asm/prom.h> #include <asm/setup.h> diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index 001e19d7c17d..1a54e3e52ed6 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -35,7 +35,7 @@ #include <linux/init.h> #include <linux/of_device.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> #include <asm/prom.h> #include <asm/setup.h> diff --git a/drivers/tty/serial/tegra-tcu.c b/drivers/tty/serial/tegra-tcu.c index 52687c65ad74..4877c54c613d 100644 --- a/drivers/tty/serial/tegra-tcu.c +++ b/drivers/tty/serial/tegra-tcu.c @@ -195,13 +195,6 @@ static int tegra_tcu_probe(struct platform_device *pdev) return err; } - tcu->rx = mbox_request_channel_byname(&tcu->rx_client, "rx"); - if (IS_ERR(tcu->rx)) { - err = PTR_ERR(tcu->rx); - dev_err(&pdev->dev, "failed to get rx mailbox: %d\n", err); - goto free_tx; - } - #if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) /* setup the console */ strcpy(tcu->console.name, "ttyTCU"); @@ -226,7 +219,7 @@ static int tegra_tcu_probe(struct platform_device *pdev) if (err) { dev_err(&pdev->dev, "failed to register UART driver: %d\n", err); - goto free_rx; + goto free_tx; } /* setup the port */ @@ -246,6 +239,17 @@ static int tegra_tcu_probe(struct platform_device *pdev) goto unregister_uart; } + /* + * Request RX channel after creating port to ensure tcu->port + * is ready for any immediate incoming bytes. + */ + tcu->rx = mbox_request_channel_byname(&tcu->rx_client, "rx"); + if (IS_ERR(tcu->rx)) { + err = PTR_ERR(tcu->rx); + dev_err(&pdev->dev, "failed to get rx mailbox: %d\n", err); + goto remove_uart_port; + } + platform_set_drvdata(pdev, tcu); #if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) register_console(&tcu->console); @@ -253,10 +257,10 @@ static int tegra_tcu_probe(struct platform_device *pdev) return 0; +remove_uart_port: + uart_remove_one_port(&tcu->driver, &tcu->port); unregister_uart: uart_unregister_driver(&tcu->driver); -free_rx: - mbox_free_channel(tcu->rx); free_tx: mbox_free_channel(tcu->tx); @@ -270,9 +274,9 @@ static int tegra_tcu_remove(struct platform_device *pdev) #if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) unregister_console(&tcu->console); #endif + mbox_free_channel(tcu->rx); uart_remove_one_port(&tcu->driver, &tcu->port); uart_unregister_driver(&tcu->driver); - mbox_free_channel(tcu->rx); mbox_free_channel(tcu->tx); return 0; diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index f42ccc40ffa6..a5f15f22d9ef 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -505,21 +505,23 @@ static void ulite_console_write(struct console *co, const char *s, static int ulite_console_setup(struct console *co, char *options) { - struct uart_port *port; + struct uart_port *port = NULL; int baud = 9600; int bits = 8; int parity = 'n'; int flow = 'n'; - - port = console_port; + if (co->index >= 0 && co->index < ULITE_NR_UARTS) + port = ulite_ports + co->index; /* Has the device been initialized yet? */ - if (!port->mapbase) { + if (!port || !port->mapbase) { pr_debug("console on ttyUL%i not present\n", co->index); return -ENODEV; } + console_port = port; + /* not initialized yet? */ if (!port->membase) { if (ulite_request_port(port)) @@ -655,17 +657,6 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq, dev_set_drvdata(dev, port); -#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE - /* - * If console hasn't been found yet try to assign this port - * because it is required to be assigned for console setup function. - * If register_console() don't assign value, then console_port pointer - * is cleanup. - */ - if (ulite_uart_driver.cons->index == -1) - console_port = port; -#endif - /* Register the port */ rc = uart_add_one_port(&ulite_uart_driver, port); if (rc) { @@ -675,12 +666,6 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq, return rc; } -#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE - /* This is not port which is used for console that's why clean it up */ - if (ulite_uart_driver.cons->index == -1) - console_port = NULL; -#endif - return 0; } diff --git a/drivers/tty/serial/vr41xx_siu.c b/drivers/tty/serial/vr41xx_siu.c index eeb4b6568776..647198b1e2b9 100644 --- a/drivers/tty/serial/vr41xx_siu.c +++ b/drivers/tty/serial/vr41xx_siu.c @@ -20,7 +20,7 @@ #include <linux/tty.h> #include <linux/tty_flip.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/vr41xx/siu.h> #include <asm/vr41xx/vr41xx.h> diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 67a2db621e2b..962e522ccc45 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -484,7 +484,7 @@ static unsigned int cdns_uart_set_baud_rate(struct uart_port *port, #ifdef CONFIG_COMMON_CLK /** - * cdns_uart_clk_notitifer_cb - Clock notifier callback + * cdns_uart_clk_notifier_cb - Clock notifier callback * @nb: Notifier block * @event: Notify event * @data: Notifier data @@ -497,8 +497,8 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb, struct uart_port *port; int locked = 0; struct clk_notifier_data *ndata = data; - unsigned long flags = 0; struct cdns_uart *cdns_uart = to_cdns_uart(nb); + unsigned long flags; port = cdns_uart->port; if (port->suspended) @@ -1149,7 +1149,7 @@ static void cdns_uart_console_putchar(struct uart_port *port, int ch) } static void cdns_early_write(struct console *con, const char *s, - unsigned n) + unsigned int n) { struct earlycon_device *dev = con->data; @@ -1210,7 +1210,7 @@ static void cdns_uart_console_write(struct console *co, const char *s, unsigned int count) { struct uart_port *port = console_port; - unsigned long flags = 0; + unsigned long flags; unsigned int imr, ctrl; int locked = 1; @@ -1308,7 +1308,7 @@ static int cdns_uart_suspend(struct device *device) may_wake = device_may_wakeup(device); if (console_suspend_enabled && uart_console(port) && may_wake) { - unsigned long flags = 0; + unsigned long flags; spin_lock_irqsave(&port->lock, flags); /* Empty the receive FIFO 1st before making changes */ @@ -1339,7 +1339,7 @@ static int cdns_uart_resume(struct device *device) { struct uart_port *port = dev_get_drvdata(device); struct cdns_uart *cdns_uart = port->private_data; - unsigned long flags = 0; + unsigned long flags; u32 ctrl_reg; int may_wake; diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 5523cf7bd1c2..5bb928b7873e 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -768,7 +768,7 @@ static int write(struct tty_struct *tty, if (!info->tx_buf || (count > info->max_frame_size)) return -EIO; - if (!count || tty->stopped || tty->hw_stopped) + if (!count || tty->flow.stopped || tty->hw_stopped) return 0; spin_lock_irqsave(&info->lock, flags); @@ -868,15 +868,15 @@ exit: DBGINFO(("%s wait_until_sent exit\n", info->device_name)); } -static int write_room(struct tty_struct *tty) +static unsigned int write_room(struct tty_struct *tty) { struct slgt_info *info = tty->driver_data; - int ret; + unsigned int ret; if (sanity_check(info, tty->name, "write_room")) return 0; ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE; - DBGINFO(("%s write_room=%d\n", info->device_name, ret)); + DBGINFO(("%s write_room=%u\n", info->device_name, ret)); return ret; } @@ -889,7 +889,7 @@ static void flush_chars(struct tty_struct *tty) return; DBGINFO(("%s flush_chars entry tx_count=%d\n", info->device_name, info->tx_count)); - if (info->tx_count <= 0 || tty->stopped || + if (info->tx_count <= 0 || tty->flow.stopped || tty->hw_stopped || !info->tx_buf) return; @@ -1254,14 +1254,14 @@ static int synclink_gt_proc_show(struct seq_file *m, void *v) /* * return count of bytes in transmit buffer */ -static int chars_in_buffer(struct tty_struct *tty) +static unsigned int chars_in_buffer(struct tty_struct *tty) { struct slgt_info *info = tty->driver_data; - int count; + unsigned int count; if (sanity_check(info, tty->name, "chars_in_buffer")) return 0; count = tbuf_bytes(info); - DBGINFO(("%s chars_in_buffer()=%d\n", info->device_name, count)); + DBGINFO(("%s chars_in_buffer()=%u\n", info->device_name, count)); return count; } @@ -2241,7 +2241,7 @@ static void isr_txeom(struct slgt_info *info, unsigned short status) else #endif { - if (info->port.tty && (info->port.tty->stopped || info->port.tty->hw_stopped)) { + if (info->port.tty && (info->port.tty->flow.stopped || info->port.tty->hw_stopped)) { tx_stop(info); return; } @@ -2465,14 +2465,7 @@ static void change_params(struct slgt_info *info) /* byte size and parity */ - switch (cflag & CSIZE) { - case CS5: info->params.data_bits = 5; break; - case CS6: info->params.data_bits = 6; break; - case CS7: info->params.data_bits = 7; break; - case CS8: info->params.data_bits = 8; break; - default: info->params.data_bits = 7; break; - } - + info->params.data_bits = tty_get_char_size(cflag); info->params.stop_bits = (cflag & CSTOPB) ? 2 : 1; if (cflag & PARENB) diff --git a/drivers/tty/tty_baudrate.c b/drivers/tty/tty_baudrate.c index 48b5de659c77..426b1252781a 100644 --- a/drivers/tty/tty_baudrate.c +++ b/drivers/tty/tty_baudrate.c @@ -147,7 +147,7 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, int iclose = ibaud/50, oclose = obaud/50; int ibinput = 0; - if (obaud == 0) /* CD dropped */ + if (obaud == 0) /* CD dropped */ ibaud = 0; /* Clear ibaud to be sure */ termios->c_ispeed = ibaud; @@ -159,8 +159,9 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, #endif #ifdef BOTHER /* If the user asked for a precise weird speed give a precise weird - answer. If they asked for a Bfoo speed they may have problems - digesting non-exact replies so fuzz a bit */ + * answer. If they asked for a Bfoo speed they may have problems + * digesting non-exact replies so fuzz a bit. + */ if ((termios->c_cflag & CBAUD) == BOTHER) { oclose = 0; @@ -191,7 +192,8 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, if (ibaud - iclose <= baud_table[i] && ibaud + iclose >= baud_table[i]) { /* For the case input == output don't set IBAUD bits - if the user didn't do so */ + * if the user didn't do so. + */ if (ofound == i && !ibinput) ifound = i; #ifdef IBSHIFT @@ -211,7 +213,8 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, if (ofound == -1) termios->c_cflag |= BOTHER; /* Set exact input bits only if the input and output differ or the - user already did */ + * user already did. + */ if (ifound == -1 && (ibaud != obaud || ibinput)) termios->c_cflag |= (BOTHER << IBSHIFT); #else diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 9733469a14b2..635d0af229b7 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -32,8 +32,8 @@ * We default to dicing tty buffer allocations to this many characters * in order to avoid multiple page allocations. We know the size of * tty_buffer itself but it must also be taken into account that the - * the buffer is 256 byte aligned. See tty_buffer_find for the allocation - * logic this must match + * buffer is 256 byte aligned. See tty_buffer_find for the allocation + * logic this must match. */ #define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF) @@ -88,9 +88,10 @@ EXPORT_SYMBOL_GPL(tty_buffer_unlock_exclusive); * pre-allocate if memory guarantee is required). */ -int tty_buffer_space_avail(struct tty_port *port) +unsigned int tty_buffer_space_avail(struct tty_port *port) { int space = port->buf.mem_limit - atomic_read(&port->buf.mem_used); + return max(space, 0); } EXPORT_SYMBOL_GPL(tty_buffer_space_avail); @@ -169,7 +170,8 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size) } /* Should possibly check if this fails for the largest buffer we - have queued and recycle that ? */ + * have queued and recycle that ? + */ if (atomic_read(&port->buf.mem_used) > port->buf.mem_limit) return NULL; p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); @@ -242,7 +244,7 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld) } /** - * tty_buffer_request_room - grow tty buffer if needed + * __tty_buffer_request_room - grow tty buffer if needed * @port: tty port * @size: size desired * @flags: buffer flags if new buffer allocated (default = 0) @@ -312,11 +314,13 @@ int tty_insert_flip_string_fixed_flag(struct tty_port *port, const unsigned char *chars, char flag, size_t size) { int copied = 0; + do { int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0; int space = __tty_buffer_request_room(port, goal, flags); struct tty_buffer *tb = port->buf.tail; + if (unlikely(space == 0)) break; memcpy(char_buf_ptr(tb, tb->used), chars, space); @@ -326,7 +330,8 @@ int tty_insert_flip_string_fixed_flag(struct tty_port *port, copied += space; chars += space; /* There is a small chance that we need to split the data over - several buffers. If this is the case we must loop */ + * several buffers. If this is the case we must loop. + */ } while (unlikely(size > copied)); return copied; } @@ -348,10 +353,12 @@ int tty_insert_flip_string_flags(struct tty_port *port, const unsigned char *chars, const char *flags, size_t size) { int copied = 0; + do { int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); int space = tty_buffer_request_room(port, goal); struct tty_buffer *tb = port->buf.tail; + if (unlikely(space == 0)) break; memcpy(char_buf_ptr(tb, tb->used), chars, space); @@ -361,7 +368,8 @@ int tty_insert_flip_string_flags(struct tty_port *port, chars += space; flags += space; /* There is a small chance that we need to split the data over - several buffers. If this is the case we must loop */ + * several buffers. If this is the case we must loop. + */ } while (unlikely(size > copied)); return copied; } @@ -431,8 +439,10 @@ int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars, size_t size) { int space = __tty_buffer_request_room(port, size, TTYB_NORMAL); + if (likely(space)) { struct tty_buffer *tb = port->buf.tail; + *chars = char_buf_ptr(tb, tb->used); if (~tb->flags & TTYB_NORMAL) memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space); @@ -455,7 +465,7 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string); * Returns the number of bytes processed */ int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p, - char *f, int count) + const char *f, int count) { if (ld->ops->receive_buf2) count = ld->ops->receive_buf2(ld->tty, p, f, count); @@ -472,7 +482,7 @@ static int receive_buf(struct tty_port *port, struct tty_buffer *head, int count) { unsigned char *p = char_buf_ptr(head, head->read); - char *f = NULL; + const char *f = NULL; int n; if (~head->flags & TTYB_NORMAL) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 5b5e99604989..26debec26b4e 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -33,7 +33,7 @@ * -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993. * * Rewrote canonical mode and added more termios flags. - * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94 + * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94 * * Reorganized FASYNC support so mouse code can share it. * -- ctm@ardi.com, 9Sep95 @@ -131,12 +131,12 @@ struct ktermios tty_std_termios = { /* for the benefit of tty drivers */ .c_ospeed = 38400, /* .c_line = N_TTY, */ }; - EXPORT_SYMBOL(tty_std_termios); /* This list gets poked at by procfs and various bits of boot up code. This - could do with some rationalisation such as pulling the tty proc function - into this file */ + * could do with some rationalisation such as pulling the tty proc function + * into this file. + */ LIST_HEAD(tty_drivers); /* linked list of tty drivers */ @@ -248,7 +248,6 @@ const char *tty_name(const struct tty_struct *tty) return "NULL tty"; return tty->name; } - EXPORT_SYMBOL(tty_name); const char *tty_driver_name(const struct tty_struct *tty) @@ -320,6 +319,7 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index) list_for_each_entry(p, &tty_drivers, tty_drivers) { dev_t base = MKDEV(p->major, p->minor_start); + if (device < base || device >= base + p->num) continue; *index = device - base; @@ -537,7 +537,6 @@ void tty_wakeup(struct tty_struct *tty) } wake_up_interruptible_poll(&tty->write_wait, EPOLLOUT); } - EXPORT_SYMBOL_GPL(tty_wakeup); /** @@ -613,8 +612,9 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) set_bit(TTY_HUPPING, &tty->flags); /* inuse_filps is protected by the single tty lock, - this really needs to change if we want to flush the - workqueue with the lock held */ + * this really needs to change if we want to flush the + * workqueue with the lock held. + */ check_tty_count(tty, "tty_hangup"); spin_lock(&tty->files_lock); @@ -638,15 +638,15 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) tty_ldisc_hangup(tty, cons_filp != NULL); - spin_lock_irq(&tty->ctrl_lock); + spin_lock_irq(&tty->ctrl.lock); clear_bit(TTY_THROTTLED, &tty->flags); clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - put_pid(tty->session); - put_pid(tty->pgrp); - tty->session = NULL; - tty->pgrp = NULL; - tty->ctrl_status = 0; - spin_unlock_irq(&tty->ctrl_lock); + put_pid(tty->ctrl.session); + put_pid(tty->ctrl.pgrp); + tty->ctrl.session = NULL; + tty->ctrl.pgrp = NULL; + tty->ctrl.pktstatus = 0; + spin_unlock_irq(&tty->ctrl.lock); /* * If one of the devices matches a console pointer, we @@ -694,7 +694,6 @@ void tty_hangup(struct tty_struct *tty) tty_debug_hangup(tty, "hangup\n"); schedule_work(&tty->hangup_work); } - EXPORT_SYMBOL(tty_hangup); /** @@ -711,7 +710,6 @@ void tty_vhangup(struct tty_struct *tty) tty_debug_hangup(tty, "vhangup\n"); __tty_hangup(tty, 0); } - EXPORT_SYMBOL(tty_vhangup); @@ -761,9 +759,17 @@ int tty_hung_up_p(struct file *filp) { return (filp && filp->f_op == &hung_up_tty_fops); } - EXPORT_SYMBOL(tty_hung_up_p); +void __stop_tty(struct tty_struct *tty) +{ + if (tty->flow.stopped) + return; + tty->flow.stopped = true; + if (tty->ops->stop) + tty->ops->stop(tty); +} + /** * stop_tty - propagate flow control * @tty: tty to stop @@ -778,28 +784,28 @@ EXPORT_SYMBOL(tty_hung_up_p); * but not always. * * Locking: - * flow_lock + * flow.lock */ - -void __stop_tty(struct tty_struct *tty) -{ - if (tty->stopped) - return; - tty->stopped = 1; - if (tty->ops->stop) - tty->ops->stop(tty); -} - void stop_tty(struct tty_struct *tty) { unsigned long flags; - spin_lock_irqsave(&tty->flow_lock, flags); + spin_lock_irqsave(&tty->flow.lock, flags); __stop_tty(tty); - spin_unlock_irqrestore(&tty->flow_lock, flags); + spin_unlock_irqrestore(&tty->flow.lock, flags); } EXPORT_SYMBOL(stop_tty); +void __start_tty(struct tty_struct *tty) +{ + if (!tty->flow.stopped || tty->flow.tco_stopped) + return; + tty->flow.stopped = false; + if (tty->ops->start) + tty->ops->start(tty); + tty_wakeup(tty); +} + /** * start_tty - propagate flow control * @tty: tty to start @@ -809,26 +815,15 @@ EXPORT_SYMBOL(stop_tty); * start method is invoked and the line discipline woken. * * Locking: - * flow_lock + * flow.lock */ - -void __start_tty(struct tty_struct *tty) -{ - if (!tty->stopped || tty->flow_stopped) - return; - tty->stopped = 0; - if (tty->ops->start) - tty->ops->start(tty); - tty_wakeup(tty); -} - void start_tty(struct tty_struct *tty) { unsigned long flags; - spin_lock_irqsave(&tty->flow_lock, flags); + spin_lock_irqsave(&tty->flow.lock, flags); __start_tty(tty); - spin_unlock_irqrestore(&tty->flow_lock, flags); + spin_unlock_irqrestore(&tty->flow.lock, flags); } EXPORT_SYMBOL(start_tty); @@ -914,10 +909,8 @@ static int iterate_tty_read(struct tty_ldisc *ld, struct tty_struct *tty, /** * tty_read - read method for tty device files - * @file: pointer to tty file - * @buf: user buffer - * @count: size of user buffer - * @ppos: unused + * @iocb: kernel I/O control block + * @to: destination for the data read * * Perform the read system call function on this terminal device. Checks * for hung up devices before calling the line discipline method. @@ -941,7 +934,8 @@ static ssize_t tty_read(struct kiocb *iocb, struct iov_iter *to) return -EIO; /* We want to wait for the line discipline to sort out in this - situation */ + * situation. + */ ld = tty_ldisc_ref_wait(tty); if (!ld) return hung_up_tty_read(iocb, to); @@ -1033,6 +1027,7 @@ static inline ssize_t do_tty_write( /* Do the write .. */ for (;;) { size_t size = count; + if (size > chunk) size = chunk; @@ -1091,36 +1086,18 @@ void tty_write_message(struct tty_struct *tty, char *msg) tty_unlock(tty); tty_write_unlock(tty); } - return; } - -/** - * tty_write - write method for tty device file - * @file: tty file pointer - * @buf: user data to write - * @count: bytes to write - * @ppos: unused - * - * Write data to a tty device via the line discipline. - * - * Locking: - * Locks the line discipline as required - * Writes to the tty driver are serialized by the atomic_write_lock - * and are then processed in chunks to the device. The line discipline - * write method will not be invoked in parallel for each device. - */ - static ssize_t file_tty_write(struct file *file, struct kiocb *iocb, struct iov_iter *from) { struct tty_struct *tty = file_tty(file); - struct tty_ldisc *ld; + struct tty_ldisc *ld; ssize_t ret; if (tty_paranoia_check(tty, file_inode(file), "tty_write")) return -EIO; if (!tty || !tty->ops->write || tty_io_error(tty)) - return -EIO; + return -EIO; /* Short term debug to catch buggy drivers */ if (tty->ops->write_room == NULL) tty_err(tty, "missing write_room method\n"); @@ -1135,6 +1112,20 @@ static ssize_t file_tty_write(struct file *file, struct kiocb *iocb, struct iov_ return ret; } +/** + * tty_write - write method for tty device file + * @iocb: kernel I/O control block + * @from: iov_iter with data to write + * + * Write data to a tty device via the line discipline. + * + * Locking: + * Locks the line discipline as required + * Writes to the tty driver are serialized by the atomic_write_lock + * and are then processed in chunks to the device. The line + * discipline write method will not be invoked in parallel for + * each device. + */ static ssize_t tty_write(struct kiocb *iocb, struct iov_iter *from) { return file_tty_write(iocb->ki_filp, iocb, from); @@ -1150,11 +1141,12 @@ ssize_t redirected_tty_write(struct kiocb *iocb, struct iov_iter *iter) spin_unlock(&redirect_lock); /* - * We know the redirected tty is just another tty, we can can + * We know the redirected tty is just another tty, we can * call file_tty_write() directly with that file pointer. */ if (p) { ssize_t res; + res = file_tty_write(p, iocb, iter); fput(p); return res; @@ -1172,7 +1164,7 @@ ssize_t redirected_tty_write(struct kiocb *iocb, struct iov_iter *iter) int tty_send_xchar(struct tty_struct *tty, char ch) { - int was_stopped = tty->stopped; + bool was_stopped = tty->flow.stopped; if (tty->ops->send_xchar) { down_read(&tty->termios_rwsem); @@ -1559,8 +1551,8 @@ static void release_one_tty(struct work_struct *work) list_del_init(&tty->tty_files); spin_unlock(&tty->files_lock); - put_pid(tty->pgrp); - put_pid(tty->session); + put_pid(tty->ctrl.pgrp); + put_pid(tty->ctrl.session); free_tty_struct(tty); } @@ -1569,7 +1561,8 @@ static void queue_release_one_tty(struct kref *kref) struct tty_struct *tty = container_of(kref, struct tty_struct, kref); /* The hangup queue is now free so we can reuse it rather than - waste a chunk of memory for each port */ + * waste a chunk of memory for each port. + */ INIT_WORK(&tty->hangup_work, release_one_tty); schedule_work(&tty->hangup_work); } @@ -1861,9 +1854,9 @@ int tty_release(struct inode *inode, struct file *filp) */ if (!tty->count) { read_lock(&tasklist_lock); - session_clear_tty(tty->session); + session_clear_tty(tty->ctrl.session); if (o_tty) - session_clear_tty(o_tty->session); + session_clear_tty(o_tty->ctrl.session); read_unlock(&tasklist_lock); } @@ -1874,7 +1867,8 @@ int tty_release(struct inode *inode, struct file *filp) tty_unlock(tty); /* At this point, the tty->count == 0 should ensure a dead tty - cannot be re-opened by a racing opener */ + * cannot be re-opened by a racing opener. + */ if (!final) return 0; @@ -1928,8 +1922,8 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp) * @index: index for the device in the @return driver * @return: driver for this inode (with increased refcount) * - * If @return is not erroneous, the caller is responsible to decrement the - * refcount by tty_driver_kref_put. + * If @return is not erroneous, the caller is responsible to decrement the + * refcount by tty_driver_kref_put. * * Locking: tty_mutex protects get_tty_driver */ @@ -1942,6 +1936,7 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, #ifdef CONFIG_VT case MKDEV(TTY_MAJOR, 0): { extern struct tty_driver *console_driver; + driver = tty_driver_kref_get(console_driver); *index = fg_console; break; @@ -1949,6 +1944,7 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, #endif case MKDEV(TTYAUX_MAJOR, 1): { struct tty_driver *console_driver = console_device(index); + if (console_driver) { driver = tty_driver_kref_get(console_driver); if (driver && filp) { @@ -2250,16 +2246,16 @@ static int __tty_fasync(int fd, struct file *filp, int on) enum pid_type type; struct pid *pid; - spin_lock_irqsave(&tty->ctrl_lock, flags); - if (tty->pgrp) { - pid = tty->pgrp; + spin_lock_irqsave(&tty->ctrl.lock, flags); + if (tty->ctrl.pgrp) { + pid = tty->ctrl.pgrp; type = PIDTYPE_PGID; } else { pid = task_pid(current); type = PIDTYPE_TGID; } get_pid(pid); - spin_unlock_irqrestore(&tty->ctrl_lock, flags); + spin_unlock_irqrestore(&tty->ctrl.lock, flags); __f_setown(filp, pid, type, 0); put_pid(pid); retval = 0; @@ -2336,7 +2332,7 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg) err = copy_to_user(arg, &tty->winsize, sizeof(*arg)); mutex_unlock(&tty->winsize_mutex); - return err ? -EFAULT: 0; + return err ? -EFAULT : 0; } /** @@ -2381,13 +2377,14 @@ EXPORT_SYMBOL(tty_do_resize); * * Locking: * Driver dependent. The default do_resize method takes the - * tty termios mutex and ctrl_lock. The console takes its own lock + * tty termios mutex and ctrl.lock. The console takes its own lock * then calls into the default method. */ static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg) { struct winsize tmp_ws; + if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) return -EFAULT; @@ -2412,6 +2409,7 @@ static int tioccons(struct file *file) return -EPERM; if (file->f_op->write_iter == redirected_tty_write) { struct file *f; + spin_lock(&redirect_lock); f = redirect; redirect = NULL; @@ -2734,6 +2732,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TIOCGEXCL: { int excl = test_bit(TTY_EXCLUSIVE, &tty->flags); + return put_user(excl, (int __user *)p); } case TIOCGETD: @@ -2748,6 +2747,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TIOCGDEV: { unsigned int ret = new_encode_dev(tty_devnum(real_tty)); + return put_user(ret, (unsigned int __user *)p); } /* @@ -3006,7 +3006,7 @@ static int this_tty(const void *t, struct file *file, unsigned fd) return 0; return file_tty(file) != t ? 0 : fd + 1; } - + /* * This implements the "Secure Attention Key" --- the idea is to * prevent trojan horses by killing all processes associated with this @@ -3039,9 +3039,9 @@ void __do_SAK(struct tty_struct *tty) if (!tty) return; - spin_lock_irqsave(&tty->ctrl_lock, flags); - session = get_pid(tty->session); - spin_unlock_irqrestore(&tty->ctrl_lock, flags); + spin_lock_irqsave(&tty->ctrl.lock, flags); + session = get_pid(tty->ctrl.session); + spin_unlock_irqrestore(&tty->ctrl.lock, flags); tty_ldisc_flush(tty); @@ -3096,13 +3096,13 @@ void do_SAK(struct tty_struct *tty) return; schedule_work(&tty->SAK_work); } - EXPORT_SYMBOL(do_SAK); /* Must put_device() after it's unused! */ static struct device *tty_get_device(struct tty_struct *tty) { dev_t devt = tty_devnum(tty); + return class_find_device_by_devt(tty_class, devt); } @@ -3129,8 +3129,8 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx) kfree(tty); return NULL; } - tty->session = NULL; - tty->pgrp = NULL; + tty->ctrl.session = NULL; + tty->ctrl.pgrp = NULL; mutex_init(&tty->legacy_mutex); mutex_init(&tty->throttle_mutex); init_rwsem(&tty->termios_rwsem); @@ -3140,8 +3140,8 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx) init_waitqueue_head(&tty->read_wait); INIT_WORK(&tty->hangup_work, do_tty_hangup); mutex_init(&tty->atomic_write_lock); - spin_lock_init(&tty->ctrl_lock); - spin_lock_init(&tty->flow_lock); + spin_lock_init(&tty->ctrl.lock); + spin_lock_init(&tty->flow.lock); spin_lock_init(&tty->files_lock); INIT_LIST_HEAD(&tty->tty_files); INIT_WORK(&tty->SAK_work, do_SAK_work); @@ -3317,11 +3317,11 @@ err_put: EXPORT_SYMBOL_GPL(tty_register_device_attr); /** - * tty_unregister_device - unregister a tty device - * @driver: the tty driver that describes the tty device - * @index: the index in the tty driver for this tty device + * tty_unregister_device - unregister a tty device + * @driver: the tty driver that describes the tty device + * @index: the index in the tty driver for this tty device * - * If a tty device is registered with a call to tty_register_device() then + * If a tty device is registered with a call to tty_register_device() then * this function must be called when the tty device is gone. * * Locking: ?? diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 41f7449d0464..507a25d692bb 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -54,7 +54,7 @@ * to be no queue on the device. */ -int tty_chars_in_buffer(struct tty_struct *tty) +unsigned int tty_chars_in_buffer(struct tty_struct *tty) { if (tty->ops->chars_in_buffer) return tty->ops->chars_in_buffer(tty); @@ -73,7 +73,7 @@ EXPORT_SYMBOL(tty_chars_in_buffer); * returned and data may be lost as there will be no flow control. */ -int tty_write_room(struct tty_struct *tty) +unsigned int tty_write_room(struct tty_struct *tty) { if (tty->ops->write_room) return tty->ops->write_room(tty); @@ -97,28 +97,6 @@ void tty_driver_flush_buffer(struct tty_struct *tty) EXPORT_SYMBOL(tty_driver_flush_buffer); /** - * tty_throttle - flow control - * @tty: terminal - * - * Indicate that a tty should stop transmitting data down the stack. - * Takes the termios rwsem to protect against parallel throttle/unthrottle - * and also to ensure the driver can consistently reference its own - * termios data at this point when implementing software flow control. - */ - -void tty_throttle(struct tty_struct *tty) -{ - down_write(&tty->termios_rwsem); - /* check TTY_THROTTLED first so it indicates our state */ - if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) && - tty->ops->throttle) - tty->ops->throttle(tty); - tty->flow_change = 0; - up_write(&tty->termios_rwsem); -} -EXPORT_SYMBOL(tty_throttle); - -/** * tty_unthrottle - flow control * @tty: terminal * @@ -146,10 +124,11 @@ EXPORT_SYMBOL(tty_unthrottle); * tty_throttle_safe - flow control * @tty: terminal * - * Similar to tty_throttle() but will only attempt throttle - * if tty->flow_change is TTY_THROTTLE_SAFE. Prevents an accidental - * throttle due to race conditions when throttling is conditional - * on factors evaluated prior to throttling. + * Indicate that a tty should stop transmitting data down the stack. + * tty_throttle_safe will only attempt throttle if tty->flow_change is + * TTY_THROTTLE_SAFE. Prevents an accidental throttle due to race + * conditions when throttling is conditional on factors evaluated prior to + * throttling. * * Returns 0 if tty is throttled (or was already throttled) */ @@ -301,6 +280,51 @@ int tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b) EXPORT_SYMBOL(tty_termios_hw_change); /** + * tty_get_char_size - get size of a character + * @cflag: termios cflag value + * + * Get the size (in bits) of a character depending on @cflag's %CSIZE + * setting. + */ +unsigned char tty_get_char_size(unsigned int cflag) +{ + switch (cflag & CSIZE) { + case CS5: + return 5; + case CS6: + return 6; + case CS7: + return 7; + case CS8: + default: + return 8; + } +} +EXPORT_SYMBOL_GPL(tty_get_char_size); + +/** + * tty_get_frame_size - get size of a frame + * @cflag: termios cflag value + * + * Get the size (in bits) of a frame depending on @cflag's %CSIZE, %CSTOPB, + * and %PARENB setting. The result is a sum of character size, start and + * stop bits -- one bit each -- second stop bit (if set), and parity bit + * (if set). + */ +unsigned char tty_get_frame_size(unsigned int cflag) +{ + unsigned char bits = 2 + tty_get_char_size(cflag); + + if (cflag & CSTOPB) + bits++; + if (cflag & PARENB) + bits++; + + return bits; +} +EXPORT_SYMBOL_GPL(tty_get_frame_size); + +/** * tty_set_termios - update termios values * @tty: tty to update * @new_termios: desired new value @@ -846,20 +870,20 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, return retval; switch (arg) { case TCOOFF: - spin_lock_irq(&tty->flow_lock); - if (!tty->flow_stopped) { - tty->flow_stopped = 1; + spin_lock_irq(&tty->flow.lock); + if (!tty->flow.tco_stopped) { + tty->flow.tco_stopped = true; __stop_tty(tty); } - spin_unlock_irq(&tty->flow_lock); + spin_unlock_irq(&tty->flow.lock); break; case TCOON: - spin_lock_irq(&tty->flow_lock); - if (tty->flow_stopped) { - tty->flow_stopped = 0; + spin_lock_irq(&tty->flow.lock); + if (tty->flow.tco_stopped) { + tty->flow.tco_stopped = false; __start_tty(tty); } - spin_unlock_irq(&tty->flow_lock); + spin_unlock_irq(&tty->flow.lock); break; case TCIOFF: if (STOP_CHAR(tty) != __DISABLED_CHAR) diff --git a/drivers/tty/tty_jobctrl.c b/drivers/tty/tty_jobctrl.c index 7813dc910a19..80b86a7992b5 100644 --- a/drivers/tty/tty_jobctrl.c +++ b/drivers/tty/tty_jobctrl.c @@ -20,7 +20,7 @@ static int is_ignored(int sig) } /** - * tty_check_change - check for POSIX terminal changes + * __tty_check_change - check for POSIX terminal changes * @tty: tty to check * @sig: signal to send * @@ -28,7 +28,7 @@ static int is_ignored(int sig) * not in the foreground, send a SIGTTOU. If the signal is blocked or * ignored, go ahead and perform the operation. (POSIX 7.2) * - * Locking: ctrl_lock + * Locking: ctrl.lock */ int __tty_check_change(struct tty_struct *tty, int sig) { @@ -42,9 +42,9 @@ int __tty_check_change(struct tty_struct *tty, int sig) rcu_read_lock(); pgrp = task_pgrp(current); - spin_lock_irqsave(&tty->ctrl_lock, flags); - tty_pgrp = tty->pgrp; - spin_unlock_irqrestore(&tty->ctrl_lock, flags); + spin_lock_irqsave(&tty->ctrl.lock, flags); + tty_pgrp = tty->ctrl.pgrp; + spin_unlock_irqrestore(&tty->ctrl.lock, flags); if (tty_pgrp && pgrp != tty_pgrp) { if (is_ignored(sig)) { @@ -85,7 +85,7 @@ void proc_clear_tty(struct task_struct *p) } /** - * proc_set_tty - set the controlling terminal + * __proc_set_tty - set the controlling terminal * @tty: tty structure * * Only callable by the session leader and only if it does not already have @@ -99,16 +99,16 @@ static void __proc_set_tty(struct tty_struct *tty) { unsigned long flags; - spin_lock_irqsave(&tty->ctrl_lock, flags); + spin_lock_irqsave(&tty->ctrl.lock, flags); /* * The session and fg pgrp references will be non-NULL if * tiocsctty() is stealing the controlling tty */ - put_pid(tty->session); - put_pid(tty->pgrp); - tty->pgrp = get_pid(task_pgrp(current)); - tty->session = get_pid(task_session(current)); - spin_unlock_irqrestore(&tty->ctrl_lock, flags); + put_pid(tty->ctrl.session); + put_pid(tty->ctrl.pgrp); + tty->ctrl.pgrp = get_pid(task_pgrp(current)); + tty->ctrl.session = get_pid(task_session(current)); + spin_unlock_irqrestore(&tty->ctrl.lock, flags); if (current->signal->tty) { tty_debug(tty, "current tty %s not NULL!!\n", current->signal->tty->name); @@ -135,7 +135,7 @@ void tty_open_proc_set_tty(struct file *filp, struct tty_struct *tty) spin_lock_irq(¤t->sighand->siglock); if (current->signal->leader && !current->signal->tty && - tty->session == NULL) { + tty->ctrl.session == NULL) { /* * Don't let a process that only has write access to the tty * obtain the privileges associated with having a tty as @@ -200,8 +200,8 @@ int tty_signal_session_leader(struct tty_struct *tty, int exit_session) struct pid *tty_pgrp = NULL; read_lock(&tasklist_lock); - if (tty->session) { - do_each_pid_task(tty->session, PIDTYPE_SID, p) { + if (tty->ctrl.session) { + do_each_pid_task(tty->ctrl.session, PIDTYPE_SID, p) { spin_lock_irq(&p->sighand->siglock); if (p->signal->tty == tty) { p->signal->tty = NULL; @@ -218,13 +218,14 @@ int tty_signal_session_leader(struct tty_struct *tty, int exit_session) __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); put_pid(p->signal->tty_old_pgrp); /* A noop */ - spin_lock(&tty->ctrl_lock); - tty_pgrp = get_pid(tty->pgrp); - if (tty->pgrp) - p->signal->tty_old_pgrp = get_pid(tty->pgrp); - spin_unlock(&tty->ctrl_lock); + spin_lock(&tty->ctrl.lock); + tty_pgrp = get_pid(tty->ctrl.pgrp); + if (tty->ctrl.pgrp) + p->signal->tty_old_pgrp = + get_pid(tty->ctrl.pgrp); + spin_unlock(&tty->ctrl.lock); spin_unlock_irq(&p->sighand->siglock); - } while_each_pid_task(tty->session, PIDTYPE_SID, p); + } while_each_pid_task(tty->ctrl.session, PIDTYPE_SID, p); } read_unlock(&tasklist_lock); @@ -309,12 +310,12 @@ void disassociate_ctty(int on_exit) unsigned long flags; tty_lock(tty); - spin_lock_irqsave(&tty->ctrl_lock, flags); - put_pid(tty->session); - put_pid(tty->pgrp); - tty->session = NULL; - tty->pgrp = NULL; - spin_unlock_irqrestore(&tty->ctrl_lock, flags); + spin_lock_irqsave(&tty->ctrl.lock, flags); + put_pid(tty->ctrl.session); + put_pid(tty->ctrl.pgrp); + tty->ctrl.session = NULL; + tty->ctrl.pgrp = NULL; + spin_unlock_irqrestore(&tty->ctrl.lock, flags); tty_unlock(tty); tty_kref_put(tty); } @@ -363,7 +364,8 @@ static int tiocsctty(struct tty_struct *tty, struct file *file, int arg) tty_lock(tty); read_lock(&tasklist_lock); - if (current->signal->leader && (task_session(current) == tty->session)) + if (current->signal->leader && + task_session(current) == tty->ctrl.session) goto unlock; /* @@ -375,7 +377,7 @@ static int tiocsctty(struct tty_struct *tty, struct file *file, int arg) goto unlock; } - if (tty->session) { + if (tty->ctrl.session) { /* * This tty is already the controlling * tty for another session group! @@ -384,7 +386,7 @@ static int tiocsctty(struct tty_struct *tty, struct file *file, int arg) /* * Steal it away */ - session_clear_tty(tty->session); + session_clear_tty(tty->ctrl.session); } else { ret = -EPERM; goto unlock; @@ -416,9 +418,9 @@ struct pid *tty_get_pgrp(struct tty_struct *tty) unsigned long flags; struct pid *pgrp; - spin_lock_irqsave(&tty->ctrl_lock, flags); - pgrp = get_pid(tty->pgrp); - spin_unlock_irqrestore(&tty->ctrl_lock, flags); + spin_lock_irqsave(&tty->ctrl.lock, flags); + pgrp = get_pid(tty->ctrl.pgrp); + spin_unlock_irqrestore(&tty->ctrl.lock, flags); return pgrp; } @@ -499,10 +501,10 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t if (pgrp_nr < 0) return -EINVAL; - spin_lock_irq(&real_tty->ctrl_lock); + spin_lock_irq(&real_tty->ctrl.lock); if (!current->signal->tty || (current->signal->tty != real_tty) || - (real_tty->session != task_session(current))) { + (real_tty->ctrl.session != task_session(current))) { retval = -ENOTTY; goto out_unlock_ctrl; } @@ -515,12 +517,12 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t if (session_of_pgrp(pgrp) != task_session(current)) goto out_unlock; retval = 0; - put_pid(real_tty->pgrp); - real_tty->pgrp = get_pid(pgrp); + put_pid(real_tty->ctrl.pgrp); + real_tty->ctrl.pgrp = get_pid(pgrp); out_unlock: rcu_read_unlock(); out_unlock_ctrl: - spin_unlock_irq(&real_tty->ctrl_lock); + spin_unlock_irq(&real_tty->ctrl.lock); return retval; } @@ -545,16 +547,16 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _ if (tty == real_tty && current->signal->tty != real_tty) return -ENOTTY; - spin_lock_irqsave(&real_tty->ctrl_lock, flags); - if (!real_tty->session) + spin_lock_irqsave(&real_tty->ctrl.lock, flags); + if (!real_tty->ctrl.session) goto err; - sid = pid_vnr(real_tty->session); - spin_unlock_irqrestore(&real_tty->ctrl_lock, flags); + sid = pid_vnr(real_tty->ctrl.session); + spin_unlock_irqrestore(&real_tty->ctrl.lock, flags); return put_user(sid, p); err: - spin_unlock_irqrestore(&real_tty->ctrl_lock, flags); + spin_unlock_irqrestore(&real_tty->ctrl.lock, flags); return -ENOTTY; } diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 03f414172f34..756a4bfa6a69 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -48,7 +48,6 @@ static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; /** * tty_register_ldisc - install a line discipline - * @disc: ldisc number * @new_ldisc: pointer to the ldisc object * * Installs a new line discipline into the kernel. The discipline @@ -59,18 +58,16 @@ static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; * takes tty_ldiscs_lock to guard against ldisc races */ -int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc) +int tty_register_ldisc(struct tty_ldisc_ops *new_ldisc) { unsigned long flags; int ret = 0; - if (disc < N_TTY || disc >= NR_LDISCS) + if (new_ldisc->num < N_TTY || new_ldisc->num >= NR_LDISCS) return -EINVAL; raw_spin_lock_irqsave(&tty_ldiscs_lock, flags); - tty_ldiscs[disc] = new_ldisc; - new_ldisc->num = disc; - new_ldisc->refcount = 0; + tty_ldiscs[new_ldisc->num] = new_ldisc; raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags); return ret; @@ -79,7 +76,7 @@ EXPORT_SYMBOL(tty_register_ldisc); /** * tty_unregister_ldisc - unload a line discipline - * @disc: ldisc number + * @ldisc: ldisc number * * Remove a line discipline from the kernel providing it is not * currently in use. @@ -88,22 +85,13 @@ EXPORT_SYMBOL(tty_register_ldisc); * takes tty_ldiscs_lock to guard against ldisc races */ -int tty_unregister_ldisc(int disc) +void tty_unregister_ldisc(struct tty_ldisc_ops *ldisc) { unsigned long flags; - int ret = 0; - - if (disc < N_TTY || disc >= NR_LDISCS) - return -EINVAL; raw_spin_lock_irqsave(&tty_ldiscs_lock, flags); - if (tty_ldiscs[disc]->refcount) - ret = -EBUSY; - else - tty_ldiscs[disc] = NULL; + tty_ldiscs[ldisc->num] = NULL; raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags); - - return ret; } EXPORT_SYMBOL(tty_unregister_ldisc); @@ -117,10 +105,8 @@ static struct tty_ldisc_ops *get_ldops(int disc) ldops = tty_ldiscs[disc]; if (ldops) { ret = ERR_PTR(-EAGAIN); - if (try_module_get(ldops->owner)) { - ldops->refcount++; + if (try_module_get(ldops->owner)) ret = ldops; - } } raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags); return ret; @@ -131,7 +117,6 @@ static void put_ldops(struct tty_ldisc_ops *ldops) unsigned long flags; raw_spin_lock_irqsave(&tty_ldiscs_lock, flags); - ldops->refcount--; module_put(ldops->owner); raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags); } diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 303c198fbf5c..2f1061a9d926 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -468,7 +468,8 @@ int tty_port_block_til_ready(struct tty_port *port, DEFINE_WAIT(wait); /* if non-blocking mode is set we can pass directly to open unless - the port has just hung up or is in another error state */ + * the port has just hung up or is in another error state. + */ if (tty_io_error(tty)) { tty_port_set_active(port, 1); return 0; @@ -485,8 +486,9 @@ int tty_port_block_til_ready(struct tty_port *port, do_clocal = 1; /* Block waiting until we can proceed. We may need to wait for the - carrier, but we must also wait for any close that is in progress - before the next open may complete */ + * carrier, but we must also wait for any close that is in progress + * before the next open may complete. + */ retval = 0; @@ -503,7 +505,8 @@ int tty_port_block_til_ready(struct tty_port *port, prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE); /* Check for a hangup or uninitialised port. - Return accordingly */ + * Return accordingly. + */ if (tty_hung_up_p(filp) || !tty_port_initialized(port)) { if (port->flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; @@ -530,7 +533,8 @@ int tty_port_block_til_ready(struct tty_port *port, finish_wait(&port->open_wait, &wait); /* Update counts. A parallel hangup will have set count to zero and - we must not mess that up further */ + * we must not mess that up further. + */ spin_lock_irqsave(&port->lock, flags); if (!tty_hung_up_p(filp)) port->count++; @@ -587,7 +591,7 @@ int tty_port_close_start(struct tty_port *port, if (tty_port_initialized(port)) { /* Don't block on a stalled port, just pull the chain */ - if (tty->flow_stopped) + if (tty->flow.tco_stopped) tty_driver_flush_buffer(tty); if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, port->closing_wait); @@ -688,6 +692,7 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty, clear_bit(TTY_IO_ERROR, &tty->flags); if (port->ops->activate) { int retval = port->ops->activate(port, tty); + if (retval) { mutex_unlock(&port->mutex); return retval; @@ -698,5 +703,4 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty, mutex_unlock(&port->mutex); return tty_port_block_til_ready(port, tty, filp); } - EXPORT_SYMBOL(tty_port_open); diff --git a/drivers/tty/ttynull.c b/drivers/tty/ttynull.c index 17f05b7eb6d3..af3311a24917 100644 --- a/drivers/tty/ttynull.c +++ b/drivers/tty/ttynull.c @@ -35,7 +35,7 @@ static int ttynull_write(struct tty_struct *tty, const unsigned char *buf, return count; } -static int ttynull_write_room(struct tty_struct *tty) +static unsigned int ttynull_write_room(struct tty_struct *tty) { return 65536; } diff --git a/drivers/tty/vcc.c b/drivers/tty/vcc.c index 0c9b291ef307..d06bcc3b4c07 100644 --- a/drivers/tty/vcc.c +++ b/drivers/tty/vcc.c @@ -473,9 +473,9 @@ static struct vio_version vcc_versions[] = { static struct tty_port_operations vcc_port_ops = { 0 }; -static ssize_t vcc_sysfs_domain_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t domain_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct vcc_port *port; int rv; @@ -505,9 +505,9 @@ static int vcc_send_ctl(struct vcc_port *port, int ctl) return rv; } -static ssize_t vcc_sysfs_break_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t break_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct vcc_port *port; unsigned long flags; @@ -530,8 +530,8 @@ static ssize_t vcc_sysfs_break_store(struct device *dev, return rv; } -static DEVICE_ATTR(domain, 0400, vcc_sysfs_domain_show, NULL); -static DEVICE_ATTR(break, 0200, NULL, vcc_sysfs_break_store); +static DEVICE_ATTR_ADMIN_RO(domain); +static DEVICE_ATTR_WO(break); static struct attribute *vcc_sysfs_entries[] = { &dev_attr_domain.attr, @@ -868,10 +868,10 @@ static int vcc_write(struct tty_struct *tty, const unsigned char *buf, return total_sent ? total_sent : rv; } -static int vcc_write_room(struct tty_struct *tty) +static unsigned int vcc_write_room(struct tty_struct *tty) { struct vcc_port *port; - u64 num; + unsigned int num; port = vcc_get_ne(tty->index); if (unlikely(!port)) { @@ -886,10 +886,10 @@ static int vcc_write_room(struct tty_struct *tty) return num; } -static int vcc_chars_in_buffer(struct tty_struct *tty) +static unsigned int vcc_chars_in_buffer(struct tty_struct *tty) { struct vcc_port *port; - u64 num; + unsigned int num; port = vcc_get_ne(tty->index); if (unlikely(!port)) { diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 5d2309742718..4b0d69042ceb 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -515,7 +515,7 @@ static void fn_hold(struct vc_data *vc) * these routines are also activated by ^S/^Q. * (And SCROLLOCK can also be set by the ioctl KDSKBLED.) */ - if (tty->stopped) + if (tty->flow.stopped) start_tty(tty); else stop_tty(tty); diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index f245a5acf7e9..f7755e73696e 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -33,7 +33,7 @@ #include <linux/sched/signal.h> /* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */ -#define isspace(c) ((c) == ' ') +#define is_space_on_vt(c) ((c) == ' ') /* FIXME: all this needs locking */ static struct vc_selection { @@ -109,7 +109,7 @@ static inline int inword(const u32 c) } /** - * set loadlut - load the LUT table + * sel_loadlut() - load the LUT table * @p: user table * * Load the LUT table from user space. The caller must hold the console @@ -209,7 +209,7 @@ static int vc_selection_store_chars(struct vc_data *vc, bool unicode) bp += store_utf8(c, bp); else *bp++ = c; - if (!isspace(c)) + if (!is_space_on_vt(c)) obp = bp; if (!((i + 2) % vc->vc_size_row)) { /* strip trailing blanks from line and add newline, @@ -238,9 +238,9 @@ static int vc_do_selection(struct vc_data *vc, unsigned short mode, int ps, new_sel_end = pe; break; case TIOCL_SELWORD: /* word-by-word selection */ - spc = isspace(sel_pos(ps, unicode)); + spc = is_space_on_vt(sel_pos(ps, unicode)); for (new_sel_start = ps; ; ps -= 2) { - if ((spc && !isspace(sel_pos(ps, unicode))) || + if ((spc && !is_space_on_vt(sel_pos(ps, unicode))) || (!spc && !inword(sel_pos(ps, unicode)))) break; new_sel_start = ps; @@ -248,9 +248,9 @@ static int vc_do_selection(struct vc_data *vc, unsigned short mode, int ps, break; } - spc = isspace(sel_pos(pe, unicode)); + spc = is_space_on_vt(sel_pos(pe, unicode)); for (new_sel_end = pe; ; pe += 2) { - if ((spc && !isspace(sel_pos(pe, unicode))) || + if ((spc && !is_space_on_vt(sel_pos(pe, unicode))) || (!spc && !inword(sel_pos(pe, unicode)))) break; new_sel_end = pe; @@ -276,12 +276,12 @@ static int vc_do_selection(struct vc_data *vc, unsigned short mode, int ps, /* select to end of line if on trailing space */ if (new_sel_end > new_sel_start && !atedge(new_sel_end, vc->vc_size_row) && - isspace(sel_pos(new_sel_end, unicode))) { + is_space_on_vt(sel_pos(new_sel_end, unicode))) { for (pe = new_sel_end + 2; ; pe += 2) - if (!isspace(sel_pos(pe, unicode)) || + if (!is_space_on_vt(sel_pos(pe, unicode)) || atedge(pe, vc->vc_size_row)) break; - if (isspace(sel_pos(pe, unicode))) + if (is_space_on_vt(sel_pos(pe, unicode))) new_sel_end = pe; } if (vc_sel.start == -1) /* no current selection */ diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index fa1548d4f94b..ef981d3b7bb4 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1189,7 +1189,7 @@ static inline int resize_screen(struct vc_data *vc, int width, int height, * information and perform any necessary signal handling. * * Caller must hold the console semaphore. Takes the termios rwsem and - * ctrl_lock of the tty IFF a tty is passed. + * ctrl.lock of the tty IFF a tty is passed. */ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, @@ -1355,7 +1355,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows) * the actual work. * * Takes the console sem and the called methods then take the tty - * termios_rwsem and the tty ctrl_lock in that order. + * termios_rwsem and the tty ctrl.lock in that order. */ static int vt_resize(struct tty_struct *tty, struct winsize *ws) { @@ -2888,7 +2888,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co param.vc = vc; - while (!tty->stopped && count) { + while (!tty->flow.stopped && count) { int orig = *buf; buf++; n++; @@ -3260,23 +3260,16 @@ static int con_write(struct tty_struct *tty, const unsigned char *buf, int count static int con_put_char(struct tty_struct *tty, unsigned char ch) { - if (in_interrupt()) - return 0; /* n_r3964 calls put_char() from interrupt context */ return do_con_write(tty, &ch, 1); } -static int con_write_room(struct tty_struct *tty) +static unsigned int con_write_room(struct tty_struct *tty) { - if (tty->stopped) + if (tty->flow.stopped) return 0; return 32768; /* No limit, really; we're not buffering */ } -static int con_chars_in_buffer(struct tty_struct *tty) -{ - return 0; /* we're not buffering */ -} - /* * con_throttle and con_unthrottle are only used for * paste_selection(), which has to stuff in a large number of @@ -3523,7 +3516,6 @@ static const struct tty_operations con_ops = { .write_room = con_write_room, .put_char = con_put_char, .flush_chars = con_flush_chars, - .chars_in_buffer = con_chars_in_buffer, .ioctl = vt_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = vt_compat_ioctl, |