diff options
-rw-r--r-- | MAINTAINERS | 7 | ||||
-rw-r--r-- | drivers/staging/Kconfig | 2 | ||||
-rw-r--r-- | drivers/staging/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/dgnc/Kconfig | 10 | ||||
-rw-r--r-- | drivers/staging/dgnc/Makefile | 4 | ||||
-rw-r--r-- | drivers/staging/dgnc/TODO | 6 | ||||
-rw-r--r-- | drivers/staging/dgnc/dgnc_cls.c | 1135 | ||||
-rw-r--r-- | drivers/staging/dgnc/dgnc_cls.h | 67 | ||||
-rw-r--r-- | drivers/staging/dgnc/dgnc_driver.c | 404 | ||||
-rw-r--r-- | drivers/staging/dgnc/dgnc_driver.h | 345 | ||||
-rw-r--r-- | drivers/staging/dgnc/dgnc_tty.c | 2590 | ||||
-rw-r--r-- | drivers/staging/dgnc/dgnc_tty.h | 24 | ||||
-rw-r--r-- | drivers/staging/dgnc/digi.h | 128 |
13 files changed, 0 insertions, 4723 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index b54266ac74f9..05268bc2fe81 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4359,13 +4359,6 @@ L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-gpio-mm.c -DIGI NEO AND CLASSIC PCI PRODUCTS -M: Lidza Louina <lidza.louina@gmail.com> -M: Mark Hounschell <markh@compro.net> -L: driverdev-devel@linuxdriverproject.org -S: Maintained -F: drivers/staging/dgnc/ - DIOLAN U2C-12 I2C DRIVER M: Guenter Roeck <linux@roeck-us.net> L: linux-i2c@vger.kernel.org diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 1abf76be2aa8..7c015536360d 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -80,8 +80,6 @@ source "drivers/staging/netlogic/Kconfig" source "drivers/staging/mt29f_spinand/Kconfig" -source "drivers/staging/dgnc/Kconfig" - source "drivers/staging/gs_fpgaboot/Kconfig" source "drivers/staging/unisys/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index ab0cbe8815b1..a79b3fe20cf0 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -29,7 +29,6 @@ obj-$(CONFIG_STAGING_BOARD) += board/ obj-$(CONFIG_LTE_GDM724X) += gdm724x/ obj-$(CONFIG_FIREWIRE_SERIAL) += fwserial/ obj-$(CONFIG_GOLDFISH) += goldfish/ -obj-$(CONFIG_DGNC) += dgnc/ obj-$(CONFIG_MTD_SPINAND_MT29F) += mt29f_spinand/ obj-$(CONFIG_GS_FPGABOOT) += gs_fpgaboot/ obj-$(CONFIG_UNISYSSPAR) += unisys/ diff --git a/drivers/staging/dgnc/Kconfig b/drivers/staging/dgnc/Kconfig deleted file mode 100644 index 9f4f52c9c27d..000000000000 --- a/drivers/staging/dgnc/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config DGNC - tristate "Digi Neo and Classic PCI Products" - default n - depends on TTY && PCI - help - Say Y here to enable support for the Digi International Neo and - Classic PCI based product line. - - To compile this driver as a module, say M here: the module will be - called dgnc diff --git a/drivers/staging/dgnc/Makefile b/drivers/staging/dgnc/Makefile deleted file mode 100644 index 49633042fcc9..000000000000 --- a/drivers/staging/dgnc/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -obj-$(CONFIG_DGNC) += dgnc.o - -dgnc-objs := dgnc_cls.o dgnc_driver.o\ - dgnc_tty.o diff --git a/drivers/staging/dgnc/TODO b/drivers/staging/dgnc/TODO deleted file mode 100644 index d4cc65770513..000000000000 --- a/drivers/staging/dgnc/TODO +++ /dev/null @@ -1,6 +0,0 @@ -* remove unnecessary comments -* there is a lot of unnecessary code in the driver. It was - originally a standalone driver. Remove unneeded code. - -Please send patches to Greg Kroah-Hartman <greg@kroah.com> and -Cc: Lidza Louina <lidza.louina@gmail.com> diff --git a/drivers/staging/dgnc/dgnc_cls.c b/drivers/staging/dgnc/dgnc_cls.c deleted file mode 100644 index a1e98ee7f9e0..000000000000 --- a/drivers/staging/dgnc/dgnc_cls.c +++ /dev/null @@ -1,1135 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - */ - -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/serial.h> -#include <linux/serial_reg.h> -#include <linux/pci.h> - -#include "dgnc_driver.h" -#include "dgnc_cls.h" -#include "dgnc_tty.h" - -static inline void cls_set_cts_flow_control(struct channel_t *ch) -{ - unsigned char lcrb = readb(&ch->ch_cls_uart->lcr); - unsigned char ier = readb(&ch->ch_cls_uart->ier); - unsigned char isr_fcr = 0; - - /* - * The Enhanced Register Set may only be accessed when - * the Line Control Register is set to 0xBFh. - */ - writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr); - - isr_fcr = readb(&ch->ch_cls_uart->isr_fcr); - - /* Turn on CTS flow control, turn off IXON flow control */ - isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_CTSDSR); - isr_fcr &= ~(UART_EXAR654_EFR_IXON); - - writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr); - - /* Write old LCR value back out, which turns enhanced access off */ - writeb(lcrb, &ch->ch_cls_uart->lcr); - - /* - * Enable interrupts for CTS flow, turn off interrupts for - * received XOFF chars - */ - ier |= (UART_EXAR654_IER_CTSDSR); - ier &= ~(UART_EXAR654_IER_XOFF); - writeb(ier, &ch->ch_cls_uart->ier); - - /* Set the usual FIFO values */ - writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr); - - writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 | - UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR), - &ch->ch_cls_uart->isr_fcr); - - ch->ch_t_tlevel = 16; -} - -static inline void cls_set_ixon_flow_control(struct channel_t *ch) -{ - unsigned char lcrb = readb(&ch->ch_cls_uart->lcr); - unsigned char ier = readb(&ch->ch_cls_uart->ier); - unsigned char isr_fcr = 0; - - /* - * The Enhanced Register Set may only be accessed when - * the Line Control Register is set to 0xBFh. - */ - writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr); - - isr_fcr = readb(&ch->ch_cls_uart->isr_fcr); - - /* Turn on IXON flow control, turn off CTS flow control */ - isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXON); - isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR); - - writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr); - - /* Now set our current start/stop chars while in enhanced mode */ - writeb(ch->ch_startc, &ch->ch_cls_uart->mcr); - writeb(0, &ch->ch_cls_uart->lsr); - writeb(ch->ch_stopc, &ch->ch_cls_uart->msr); - writeb(0, &ch->ch_cls_uart->spr); - - /* Write old LCR value back out, which turns enhanced access off */ - writeb(lcrb, &ch->ch_cls_uart->lcr); - - /* - * Disable interrupts for CTS flow, turn on interrupts for - * received XOFF chars - */ - ier &= ~(UART_EXAR654_IER_CTSDSR); - ier |= (UART_EXAR654_IER_XOFF); - writeb(ier, &ch->ch_cls_uart->ier); - - /* Set the usual FIFO values */ - writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr); - - writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 | - UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR), - &ch->ch_cls_uart->isr_fcr); -} - -static inline void cls_set_no_output_flow_control(struct channel_t *ch) -{ - unsigned char lcrb = readb(&ch->ch_cls_uart->lcr); - unsigned char ier = readb(&ch->ch_cls_uart->ier); - unsigned char isr_fcr = 0; - - /* - * The Enhanced Register Set may only be accessed when - * the Line Control Register is set to 0xBFh. - */ - writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr); - - isr_fcr = readb(&ch->ch_cls_uart->isr_fcr); - - /* Turn off IXON flow control, turn off CTS flow control */ - isr_fcr |= (UART_EXAR654_EFR_ECB); - isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR | UART_EXAR654_EFR_IXON); - - writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr); - - /* Write old LCR value back out, which turns enhanced access off */ - writeb(lcrb, &ch->ch_cls_uart->lcr); - - /* - * Disable interrupts for CTS flow, turn off interrupts for - * received XOFF chars - */ - ier &= ~(UART_EXAR654_IER_CTSDSR); - ier &= ~(UART_EXAR654_IER_XOFF); - writeb(ier, &ch->ch_cls_uart->ier); - - /* Set the usual FIFO values */ - writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr); - - writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 | - UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR), - &ch->ch_cls_uart->isr_fcr); - - ch->ch_r_watermark = 0; - ch->ch_t_tlevel = 16; - ch->ch_r_tlevel = 16; -} - -static inline void cls_set_rts_flow_control(struct channel_t *ch) -{ - unsigned char lcrb = readb(&ch->ch_cls_uart->lcr); - unsigned char ier = readb(&ch->ch_cls_uart->ier); - unsigned char isr_fcr = 0; - - /* - * The Enhanced Register Set may only be accessed when - * the Line Control Register is set to 0xBFh. - */ - writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr); - - isr_fcr = readb(&ch->ch_cls_uart->isr_fcr); - - /* Turn on RTS flow control, turn off IXOFF flow control */ - isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_RTSDTR); - isr_fcr &= ~(UART_EXAR654_EFR_IXOFF); - - writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr); - - /* Write old LCR value back out, which turns enhanced access off */ - writeb(lcrb, &ch->ch_cls_uart->lcr); - - /* Enable interrupts for RTS flow */ - ier |= (UART_EXAR654_IER_RTSDTR); - writeb(ier, &ch->ch_cls_uart->ier); - - /* Set the usual FIFO values */ - writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr); - - writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 | - UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR), - &ch->ch_cls_uart->isr_fcr); - - ch->ch_r_watermark = 4; - ch->ch_r_tlevel = 8; -} - -static inline void cls_set_ixoff_flow_control(struct channel_t *ch) -{ - unsigned char lcrb = readb(&ch->ch_cls_uart->lcr); - unsigned char ier = readb(&ch->ch_cls_uart->ier); - unsigned char isr_fcr = 0; - - /* - * The Enhanced Register Set may only be accessed when - * the Line Control Register is set to 0xBFh. - */ - writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr); - - isr_fcr = readb(&ch->ch_cls_uart->isr_fcr); - - /* Turn on IXOFF flow control, turn off RTS flow control */ - isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXOFF); - isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR); - - writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr); - - /* Now set our current start/stop chars while in enhanced mode */ - writeb(ch->ch_startc, &ch->ch_cls_uart->mcr); - writeb(0, &ch->ch_cls_uart->lsr); - writeb(ch->ch_stopc, &ch->ch_cls_uart->msr); - writeb(0, &ch->ch_cls_uart->spr); - - /* Write old LCR value back out, which turns enhanced access off */ - writeb(lcrb, &ch->ch_cls_uart->lcr); - - /* Disable interrupts for RTS flow */ - ier &= ~(UART_EXAR654_IER_RTSDTR); - writeb(ier, &ch->ch_cls_uart->ier); - - /* Set the usual FIFO values */ - writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr); - - writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 | - UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR), - &ch->ch_cls_uart->isr_fcr); -} - -static inline void cls_set_no_input_flow_control(struct channel_t *ch) -{ - unsigned char lcrb = readb(&ch->ch_cls_uart->lcr); - unsigned char ier = readb(&ch->ch_cls_uart->ier); - unsigned char isr_fcr = 0; - - /* - * The Enhanced Register Set may only be accessed when - * the Line Control Register is set to 0xBFh. - */ - writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr); - - isr_fcr = readb(&ch->ch_cls_uart->isr_fcr); - - /* Turn off IXOFF flow control, turn off RTS flow control */ - isr_fcr |= (UART_EXAR654_EFR_ECB); - isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR | UART_EXAR654_EFR_IXOFF); - - writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr); - - /* Write old LCR value back out, which turns enhanced access off */ - writeb(lcrb, &ch->ch_cls_uart->lcr); - - /* Disable interrupts for RTS flow */ - ier &= ~(UART_EXAR654_IER_RTSDTR); - writeb(ier, &ch->ch_cls_uart->ier); - - /* Set the usual FIFO values */ - writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr); - - writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 | - UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR), - &ch->ch_cls_uart->isr_fcr); - - ch->ch_t_tlevel = 16; - ch->ch_r_tlevel = 16; -} - -/* - * Determines whether its time to shut off break condition. - * - * No locks are assumed to be held when calling this function. - * channel lock is held and released in this function. - */ -static inline void cls_clear_break(struct channel_t *ch, int force) -{ - unsigned long flags; - - if (!ch) - return; - - spin_lock_irqsave(&ch->ch_lock, flags); - - if (!ch->ch_stop_sending_break) { - spin_unlock_irqrestore(&ch->ch_lock, flags); - return; - } - - /* Turn break off, and unset some variables */ - if (ch->ch_flags & CH_BREAK_SENDING) { - if (time_after(jiffies, ch->ch_stop_sending_break) || force) { - unsigned char temp = readb(&ch->ch_cls_uart->lcr); - - writeb((temp & ~UART_LCR_SBC), &ch->ch_cls_uart->lcr); - ch->ch_flags &= ~(CH_BREAK_SENDING); - ch->ch_stop_sending_break = 0; - } - } - spin_unlock_irqrestore(&ch->ch_lock, flags); -} - -static void cls_copy_data_from_uart_to_queue(struct channel_t *ch) -{ - int qleft = 0; - unsigned char linestatus = 0; - unsigned char error_mask = 0; - ushort head; - ushort tail; - unsigned long flags; - - if (!ch) - return; - - spin_lock_irqsave(&ch->ch_lock, flags); - - head = ch->ch_r_head; - tail = ch->ch_r_tail; - - qleft = tail - head - 1; - if (qleft < 0) - qleft += RQUEUEMASK + 1; - - /* - * Create a mask to determine whether we should - * insert the character (if any) into our queue. - */ - if (ch->ch_c_iflag & IGNBRK) - error_mask |= UART_LSR_BI; - - while (1) { - linestatus = readb(&ch->ch_cls_uart->lsr); - - if (!(linestatus & (UART_LSR_DR))) - break; - - /* Discard character if we are ignoring the error mask. */ - if (linestatus & error_mask) { - linestatus = 0; - readb(&ch->ch_cls_uart->txrx); - continue; - } - - /* - * If our queue is full, we have no choice but to drop some - * data. The assumption is that HWFLOW or SWFLOW should have - * stopped things way way before we got to this point. - */ - while (qleft < 1) { - tail = (tail + 1) & RQUEUEMASK; - ch->ch_r_tail = tail; - ch->ch_err_overrun++; - qleft++; - } - - ch->ch_equeue[head] = linestatus & (UART_LSR_BI | UART_LSR_PE - | UART_LSR_FE); - ch->ch_rqueue[head] = readb(&ch->ch_cls_uart->txrx); - - qleft--; - - if (ch->ch_equeue[head] & UART_LSR_PE) - ch->ch_err_parity++; - if (ch->ch_equeue[head] & UART_LSR_BI) - ch->ch_err_break++; - if (ch->ch_equeue[head] & UART_LSR_FE) - ch->ch_err_frame++; - - head = (head + 1) & RQUEUEMASK; - ch->ch_rxcount++; - } - - ch->ch_r_head = head & RQUEUEMASK; - ch->ch_e_head = head & EQUEUEMASK; - - spin_unlock_irqrestore(&ch->ch_lock, flags); -} - -/* Make the UART raise any of the output signals we want up */ -static void cls_assert_modem_signals(struct channel_t *ch) -{ - unsigned char out; - - if (!ch) - return; - - out = ch->ch_mostat; - - if (ch->ch_flags & CH_LOOPBACK) - out |= UART_MCR_LOOP; - - writeb(out, &ch->ch_cls_uart->mcr); - - /* Give time for the UART to actually drop the signals */ - udelay(20); -} - -static void cls_copy_data_from_queue_to_uart(struct channel_t *ch) -{ - ushort head; - ushort tail; - int n; - int qlen; - uint len_written = 0; - unsigned long flags; - - if (!ch) - return; - - spin_lock_irqsave(&ch->ch_lock, flags); - - if (ch->ch_w_tail == ch->ch_w_head) - goto exit_unlock; - - /* If port is "stopped", don't send any data to the UART */ - if ((ch->ch_flags & CH_FORCED_STOP) || - (ch->ch_flags & CH_BREAK_SENDING)) - goto exit_unlock; - - if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM))) - goto exit_unlock; - - n = 32; - - head = ch->ch_w_head & WQUEUEMASK; - tail = ch->ch_w_tail & WQUEUEMASK; - qlen = (head - tail) & WQUEUEMASK; - - n = min(n, qlen); - - while (n > 0) { - /* - * If RTS Toggle mode is on, turn on RTS now if not already set, - * and make sure we get an event when the data transfer has - * completed. - */ - if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) { - if (!(ch->ch_mostat & UART_MCR_RTS)) { - ch->ch_mostat |= (UART_MCR_RTS); - cls_assert_modem_signals(ch); - } - ch->ch_tun.un_flags |= (UN_EMPTY); - } - - /* - * If DTR Toggle mode is on, turn on DTR now if not already set, - * and make sure we get an event when the data transfer has - * completed. - */ - if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) { - if (!(ch->ch_mostat & UART_MCR_DTR)) { - ch->ch_mostat |= (UART_MCR_DTR); - cls_assert_modem_signals(ch); - } - ch->ch_tun.un_flags |= (UN_EMPTY); - } - writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_cls_uart->txrx); - ch->ch_w_tail++; - ch->ch_w_tail &= WQUEUEMASK; - ch->ch_txcount++; - len_written++; - n--; - } - - if (len_written > 0) - ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - -exit_unlock: - spin_unlock_irqrestore(&ch->ch_lock, flags); -} - -static void cls_parse_modem(struct channel_t *ch, unsigned char signals) -{ - unsigned char msignals = signals; - unsigned long flags; - - if (!ch) - return; - - /* - * Do altpin switching. Altpin switches DCD and DSR. - * This prolly breaks DSRPACE, so we should be more clever here. - */ - spin_lock_irqsave(&ch->ch_lock, flags); - if (ch->ch_digi.digi_flags & DIGI_ALTPIN) { - unsigned char mswap = signals; - - if (mswap & UART_MSR_DDCD) { - msignals &= ~UART_MSR_DDCD; - msignals |= UART_MSR_DDSR; - } - if (mswap & UART_MSR_DDSR) { - msignals &= ~UART_MSR_DDSR; - msignals |= UART_MSR_DDCD; - } - if (mswap & UART_MSR_DCD) { - msignals &= ~UART_MSR_DCD; - msignals |= UART_MSR_DSR; - } - if (mswap & UART_MSR_DSR) { - msignals &= ~UART_MSR_DSR; - msignals |= UART_MSR_DCD; - } - } - spin_unlock_irqrestore(&ch->ch_lock, flags); - - /* Scrub off lower bits. They signify delta's */ - signals &= 0xf0; - - spin_lock_irqsave(&ch->ch_lock, flags); - if (msignals & UART_MSR_DCD) - ch->ch_mistat |= UART_MSR_DCD; - else - ch->ch_mistat &= ~UART_MSR_DCD; - - if (msignals & UART_MSR_DSR) - ch->ch_mistat |= UART_MSR_DSR; - else - ch->ch_mistat &= ~UART_MSR_DSR; - - if (msignals & UART_MSR_RI) - ch->ch_mistat |= UART_MSR_RI; - else - ch->ch_mistat &= ~UART_MSR_RI; - - if (msignals & UART_MSR_CTS) - ch->ch_mistat |= UART_MSR_CTS; - else - ch->ch_mistat &= ~UART_MSR_CTS; - spin_unlock_irqrestore(&ch->ch_lock, flags); -} - -/* Parse the ISR register for the specific port */ -static inline void cls_parse_isr(struct dgnc_board *brd, uint port) -{ - struct channel_t *ch; - unsigned char isr = 0; - unsigned long flags; - - /* - * No need to verify board pointer, it was already - * verified in the interrupt routine. - */ - - if (port >= brd->nasync) - return; - - ch = brd->channels[port]; - - /* Here we try to figure out what caused the interrupt to happen */ - while (1) { - isr = readb(&ch->ch_cls_uart->isr_fcr); - - if (isr & UART_IIR_NO_INT) - break; - - /* Receive Interrupt pending */ - if (isr & (UART_IIR_RDI | UART_IIR_RDI_TIMEOUT)) { - cls_copy_data_from_uart_to_queue(ch); - dgnc_check_queue_flow_control(ch); - } - - /* Transmit Hold register empty pending */ - if (isr & UART_IIR_THRI) { - spin_lock_irqsave(&ch->ch_lock, flags); - ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - spin_unlock_irqrestore(&ch->ch_lock, flags); - cls_copy_data_from_queue_to_uart(ch); - } - - cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr)); - } -} - -/* Channel lock MUST be held before calling this function! */ -static void cls_flush_uart_write(struct channel_t *ch) -{ - if (!ch) - return; - - writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT), - &ch->ch_cls_uart->isr_fcr); - - /* Must use *delay family functions in atomic context */ - udelay(10); - - ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); -} - -/* Channel lock MUST be held before calling this function! */ -static void cls_flush_uart_read(struct channel_t *ch) -{ - if (!ch) - return; - - /* - * For complete POSIX compatibility, we should be purging the - * read FIFO in the UART here. - * - * However, clearing the read FIFO (UART_FCR_CLEAR_RCVR) also - * incorrectly flushes write data as well as just basically trashing the - * FIFO. - * - * Presumably, this is a bug in this UART. - */ - - udelay(10); -} - -/* Send any/all changes to the line to the UART. */ -static void cls_param(struct tty_struct *tty) -{ - unsigned char lcr = 0; - unsigned char uart_lcr = 0; - unsigned char ier = 0; - unsigned char uart_ier = 0; - uint baud = 9600; - int quot = 0; - struct dgnc_board *bd; - struct channel_t *ch; - struct un_t *un; - - if (!tty) - return; - - un = (struct un_t *)tty->driver_data; - if (!un) - return; - - ch = un->un_ch; - if (!ch) - return; - - bd = ch->ch_bd; - if (!bd) - return; - - /* If baud rate is zero, flush queues, and set mval to drop DTR. */ - if ((ch->ch_c_cflag & (CBAUD)) == 0) { - ch->ch_r_head = 0; - ch->ch_r_tail = 0; - ch->ch_e_head = 0; - ch->ch_e_tail = 0; - ch->ch_w_head = 0; - ch->ch_w_tail = 0; - - cls_flush_uart_write(ch); - cls_flush_uart_read(ch); - - /* The baudrate is B0 so all modem lines are to be dropped. */ - ch->ch_flags |= (CH_BAUD0); - ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR); - cls_assert_modem_signals(ch); - ch->ch_old_baud = 0; - return; - } else if (ch->ch_custom_speed) { - baud = ch->ch_custom_speed; - /* Handle transition from B0 */ - if (ch->ch_flags & CH_BAUD0) { - ch->ch_flags &= ~(CH_BAUD0); - - /* - * Bring back up RTS and DTR... - * Also handle RTS or DTR toggle if set. - */ - if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE)) - ch->ch_mostat |= (UART_MCR_RTS); - if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE)) - ch->ch_mostat |= (UART_MCR_DTR); - } - - } else { - int iindex = 0; - int jindex = 0; - - ulong bauds[4][16] = { - { /* slowbaud */ - 0, 50, 75, 110, - 134, 150, 200, 300, - 600, 1200, 1800, 2400, - 4800, 9600, 19200, 38400 }, - { /* slowbaud & CBAUDEX */ - 0, 57600, 115200, 230400, - 460800, 150, 200, 921600, - 600, 1200, 1800, 2400, - 4800, 9600, 19200, 38400 }, - { /* fastbaud */ - 0, 57600, 76800, 115200, - 131657, 153600, 230400, 460800, - 921600, 1200, 1800, 2400, - 4800, 9600, 19200, 38400 }, - { /* fastbaud & CBAUDEX */ - 0, 57600, 115200, 230400, - 460800, 150, 200, 921600, - 600, 1200, 1800, 2400, - 4800, 9600, 19200, 38400 } - }; - - /* - * Only use the TXPrint baud rate if the terminal - * unit is NOT open - */ - if (!(ch->ch_tun.un_flags & UN_ISOPEN) && - (un->un_type == DGNC_PRINT)) - baud = C_BAUD(ch->ch_pun.un_tty) & 0xff; - else - baud = C_BAUD(ch->ch_tun.un_tty) & 0xff; - - if (ch->ch_c_cflag & CBAUDEX) - iindex = 1; - - if (ch->ch_digi.digi_flags & DIGI_FAST) - iindex += 2; - - jindex = baud; - - if ((iindex >= 0) && (iindex < 4) && (jindex >= 0) && - (jindex < 16)) { - baud = bauds[iindex][jindex]; - } else { - baud = 0; - } - - if (baud == 0) - baud = 9600; - - /* Handle transition from B0 */ - if (ch->ch_flags & CH_BAUD0) { - ch->ch_flags &= ~(CH_BAUD0); - - /* - * Bring back up RTS and DTR... - * Also handle RTS or DTR toggle if set. - */ - if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE)) - ch->ch_mostat |= (UART_MCR_RTS); - if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE)) - ch->ch_mostat |= (UART_MCR_DTR); - } - } - - if (ch->ch_c_cflag & PARENB) - lcr |= UART_LCR_PARITY; - - if (!(ch->ch_c_cflag & PARODD)) - lcr |= UART_LCR_EPAR; - -#ifdef CMSPAR - if (ch->ch_c_cflag & CMSPAR) - lcr |= UART_LCR_SPAR; -#endif - - if (ch->ch_c_cflag & CSTOPB) - lcr |= UART_LCR_STOP; - - switch (ch->ch_c_cflag & CSIZE) { - case CS5: - lcr |= UART_LCR_WLEN5; - break; - case CS6: - lcr |= UART_LCR_WLEN6; - break; - case CS7: - lcr |= UART_LCR_WLEN7; - break; - case CS8: - default: - lcr |= UART_LCR_WLEN8; - break; - } - - uart_ier = readb(&ch->ch_cls_uart->ier); - ier = uart_ier; - uart_lcr = readb(&ch->ch_cls_uart->lcr); - - if (baud == 0) - baud = 9600; - - quot = ch->ch_bd->bd_dividend / baud; - - if (quot != 0 && ch->ch_old_baud != baud) { - ch->ch_old_baud = baud; - writeb(UART_LCR_DLAB, &ch->ch_cls_uart->lcr); - writeb((quot & 0xff), &ch->ch_cls_uart->txrx); - writeb((quot >> 8), &ch->ch_cls_uart->ier); - writeb(lcr, &ch->ch_cls_uart->lcr); - } - - if (uart_lcr != lcr) - writeb(lcr, &ch->ch_cls_uart->lcr); - - if (ch->ch_c_cflag & CREAD) - ier |= (UART_IER_RDI | UART_IER_RLSI); - else - ier &= ~(UART_IER_RDI | UART_IER_RLSI); - - /* - * Have the UART interrupt on modem signal changes ONLY when - * we are in hardware flow control mode, or CLOCAL/FORCEDCD is not set. - */ - if ((ch->ch_digi.digi_flags & CTSPACE) || - (ch->ch_digi.digi_flags & RTSPACE) || - (ch->ch_c_cflag & CRTSCTS) || - !(ch->ch_digi.digi_flags & DIGI_FORCEDCD) || - !(ch->ch_c_cflag & CLOCAL)) - ier |= UART_IER_MSI; - else - ier &= ~UART_IER_MSI; - - ier |= UART_IER_THRI; - - if (ier != uart_ier) - writeb(ier, &ch->ch_cls_uart->ier); - - if (ch->ch_digi.digi_flags & CTSPACE || ch->ch_c_cflag & CRTSCTS) { - cls_set_cts_flow_control(ch); - } else if (ch->ch_c_iflag & IXON) { - if ((ch->ch_startc == _POSIX_VDISABLE) || - (ch->ch_stopc == _POSIX_VDISABLE)) - cls_set_no_output_flow_control(ch); - else - cls_set_ixon_flow_control(ch); - } else { - cls_set_no_output_flow_control(ch); - } - - if (ch->ch_digi.digi_flags & RTSPACE || ch->ch_c_cflag & CRTSCTS) { - cls_set_rts_flow_control(ch); - } else if (ch->ch_c_iflag & IXOFF) { - if ((ch->ch_startc == _POSIX_VDISABLE) || - (ch->ch_stopc == _POSIX_VDISABLE)) - cls_set_no_input_flow_control(ch); - else - cls_set_ixoff_flow_control(ch); - } else { - cls_set_no_input_flow_control(ch); - } - - cls_assert_modem_signals(ch); - - cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr)); -} - -/* Board poller function. */ -static void cls_tasklet(unsigned long data) -{ - struct dgnc_board *bd = (struct dgnc_board *)data; - struct channel_t *ch; - unsigned long flags; - int i; - int state = 0; - int ports = 0; - - if (!bd) - return; - - spin_lock_irqsave(&bd->bd_lock, flags); - state = bd->state; - ports = bd->nasync; - spin_unlock_irqrestore(&bd->bd_lock, flags); - - /* - * Do NOT allow the interrupt routine to read the intr registers - * Until we release this lock. - */ - spin_lock_irqsave(&bd->bd_intr_lock, flags); - - if ((state == BOARD_READY) && (ports > 0)) { - for (i = 0; i < ports; i++) { - ch = bd->channels[i]; - - /* - * NOTE: Remember you CANNOT hold any channel - * locks when calling input. - * During input processing, its possible we - * will call ld, which might do callbacks back - * into us. - */ - dgnc_input(ch); - - /* - * Channel lock is grabbed and then released - * inside this routine. - */ - cls_copy_data_from_queue_to_uart(ch); - dgnc_wakeup_writes(ch); - - dgnc_carrier(ch); - - /* - * The timing check of turning off the break is done - * inside clear_break() - */ - if (ch->ch_stop_sending_break) - cls_clear_break(ch, 0); - } - } - - spin_unlock_irqrestore(&bd->bd_intr_lock, flags); -} - -/* Classic specific interrupt handler. */ -static irqreturn_t cls_intr(int irq, void *voidbrd) -{ - struct dgnc_board *brd = voidbrd; - uint i = 0; - unsigned char poll_reg; - unsigned long flags; - - if (!brd) - return IRQ_NONE; - - spin_lock_irqsave(&brd->bd_intr_lock, flags); - - poll_reg = readb(brd->re_map_membase + UART_CLASSIC_POLL_ADDR_OFFSET); - if (!poll_reg) { - spin_unlock_irqrestore(&brd->bd_intr_lock, flags); - return IRQ_NONE; - } - - for (i = 0; i < brd->nasync; i++) - cls_parse_isr(brd, i); - - tasklet_schedule(&brd->helper_tasklet); - - spin_unlock_irqrestore(&brd->bd_intr_lock, flags); - - return IRQ_HANDLED; -} - -static void cls_disable_receiver(struct channel_t *ch) -{ - unsigned char tmp = readb(&ch->ch_cls_uart->ier); - - tmp &= ~(UART_IER_RDI); - writeb(tmp, &ch->ch_cls_uart->ier); -} - -static void cls_enable_receiver(struct channel_t *ch) -{ - unsigned char tmp = readb(&ch->ch_cls_uart->ier); - - tmp |= (UART_IER_RDI); - writeb(tmp, &ch->ch_cls_uart->ier); -} - -/* - * This function basically goes to sleep for seconds, or until - * it gets signalled that the port has fully drained. - */ -static int cls_drain(struct tty_struct *tty, uint seconds) -{ - unsigned long flags; - struct channel_t *ch; - struct un_t *un; - - if (!tty) - return -ENXIO; - - un = (struct un_t *)tty->driver_data; - if (!un) - return -ENXIO; - - ch = un->un_ch; - if (!ch) - return -ENXIO; - - spin_lock_irqsave(&ch->ch_lock, flags); - un->un_flags |= UN_EMPTY; - spin_unlock_irqrestore(&ch->ch_lock, flags); - - /* NOTE: Do something with time passed in. */ - - /* If ret is non-zero, user ctrl-c'ed us */ - - return wait_event_interruptible(un->un_flags_wait, - ((un->un_flags & UN_EMPTY) == 0)); -} - -static void cls_send_start_character(struct channel_t *ch) -{ - if (!ch) - return; - - if (ch->ch_startc != _POSIX_VDISABLE) { - ch->ch_xon_sends++; - writeb(ch->ch_startc, &ch->ch_cls_uart->txrx); - } -} - -static void cls_send_stop_character(struct channel_t *ch) -{ - if (!ch) - return; - - if (ch->ch_stopc != _POSIX_VDISABLE) { - ch->ch_xoff_sends++; - writeb(ch->ch_stopc, &ch->ch_cls_uart->txrx); - } -} - -static void cls_uart_init(struct channel_t *ch) -{ - unsigned char lcrb = readb(&ch->ch_cls_uart->lcr); - unsigned char isr_fcr = 0; - - writeb(0, &ch->ch_cls_uart->ier); - - /* - * The Enhanced Register Set may only be accessed when - * the Line Control Register is set to 0xBFh. - */ - writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr); - - isr_fcr = readb(&ch->ch_cls_uart->isr_fcr); - - /* Turn on Enhanced/Extended controls */ - isr_fcr |= (UART_EXAR654_EFR_ECB); - - writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr); - - /* Write old LCR value back out, which turns enhanced access off */ - writeb(lcrb, &ch->ch_cls_uart->lcr); - - /* Clear out UART and FIFO */ - readb(&ch->ch_cls_uart->txrx); - - writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, - &ch->ch_cls_uart->isr_fcr); - usleep_range(10, 20); - - ch->ch_flags |= (CH_FIFO_ENABLED | CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - - readb(&ch->ch_cls_uart->lsr); - readb(&ch->ch_cls_uart->msr); -} - -static void cls_uart_off(struct channel_t *ch) -{ - writeb(0, &ch->ch_cls_uart->ier); -} - -/* - * The channel lock MUST be held by the calling function. - * Returns 0 is nothing left in the FIFO, returns 1 otherwise. - */ -static uint cls_get_uart_bytes_left(struct channel_t *ch) -{ - unsigned char left = 0; - unsigned char lsr = 0; - - if (!ch) - return 0; - - lsr = readb(&ch->ch_cls_uart->lsr); - - /* Determine whether the Transmitter is empty or not */ - if (!(lsr & UART_LSR_TEMT)) { - if (ch->ch_flags & CH_TX_FIFO_EMPTY) - tasklet_schedule(&ch->ch_bd->helper_tasklet); - left = 1; - } else { - ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - left = 0; - } - - return left; -} - -/* - * Starts sending a break thru the UART. - * The channel lock MUST be held by the calling function. - */ -static void cls_send_break(struct channel_t *ch, int msecs) -{ - if (!ch) - return; - - /* If we receive a time of 0, this means turn off the break. */ - if (msecs == 0) { - if (ch->ch_flags & CH_BREAK_SENDING) { - unsigned char temp = readb(&ch->ch_cls_uart->lcr); - - writeb((temp & ~UART_LCR_SBC), &ch->ch_cls_uart->lcr); - ch->ch_flags &= ~(CH_BREAK_SENDING); - ch->ch_stop_sending_break = 0; - } - return; - } - - /* - * Set the time we should stop sending the break. - * If we are already sending a break, toss away the existing - * time to stop, and use this new value instead. - */ - ch->ch_stop_sending_break = jiffies + dgnc_jiffies_from_ms(msecs); - - /* Tell the UART to start sending the break */ - if (!(ch->ch_flags & CH_BREAK_SENDING)) { - unsigned char temp = readb(&ch->ch_cls_uart->lcr); - - writeb((temp | UART_LCR_SBC), &ch->ch_cls_uart->lcr); - ch->ch_flags |= (CH_BREAK_SENDING); - } -} - -/* - * Sends a specific character as soon as possible to the UART, - * jumping over any bytes that might be in the write queue. - * - * The channel lock MUST be held by the calling function. - */ -static void cls_send_immediate_char(struct channel_t *ch, unsigned char c) -{ - if (!ch) - return; - - writeb(c, &ch->ch_cls_uart->txrx); -} - -struct board_ops dgnc_cls_ops = { - .tasklet = cls_tasklet, - .intr = cls_intr, - .uart_init = cls_uart_init, - .uart_off = cls_uart_off, - .drain = cls_drain, - .param = cls_param, - .assert_modem_signals = cls_assert_modem_signals, - .flush_uart_write = cls_flush_uart_write, - .flush_uart_read = cls_flush_uart_read, - .disable_receiver = cls_disable_receiver, - .enable_receiver = cls_enable_receiver, - .send_break = cls_send_break, - .send_start_character = cls_send_start_character, - .send_stop_character = cls_send_stop_character, - .copy_data_from_queue_to_uart = cls_copy_data_from_queue_to_uart, - .get_uart_bytes_left = cls_get_uart_bytes_left, - .send_immediate_char = cls_send_immediate_char -}; diff --git a/drivers/staging/dgnc/dgnc_cls.h b/drivers/staging/dgnc/dgnc_cls.h deleted file mode 100644 index d31508542261..000000000000 --- a/drivers/staging/dgnc/dgnc_cls.h +++ /dev/null @@ -1,67 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - */ - -#ifndef _DGNC_CLS_H -#define _DGNC_CLS_H - -/** - * struct cls_uart_struct - Per channel/port Classic UART. - * - * key - W = read write - * - R = read only - * - U = unused - * - * @txrx: (WR) Holding Register. - * @ier: (WR) Interrupt Enable Register. - * @isr_fcr: (WR) Interrupt Status Register/Fifo Control Register. - * @lcr: (WR) Line Control Register. - * @mcr: (WR) Modem Control Register. - * @lsr: (WR) Line Status Register. - * @msr: (WR) Modem Status Register. - * @spr: (WR) Scratch Pad Register. - */ -struct cls_uart_struct { - u8 txrx; - u8 ier; - u8 isr_fcr; - u8 lcr; - u8 mcr; - u8 lsr; - u8 msr; - u8 spr; -}; - -/* Where to read the interrupt register (8bits) */ -#define UART_CLASSIC_POLL_ADDR_OFFSET 0x40 - -#define UART_EXAR654_ENHANCED_REGISTER_SET 0xBF - -#define UART_16654_FCR_TXTRIGGER_16 0x10 -#define UART_16654_FCR_RXTRIGGER_16 0x40 -#define UART_16654_FCR_RXTRIGGER_56 0x80 - -/* Received CTS/RTS change of state */ -#define UART_IIR_CTSRTS 0x20 - -/* Receiver data TIMEOUT */ -#define UART_IIR_RDI_TIMEOUT 0x0C - -/* - * These are the EXTENDED definitions for the Exar 654's Interrupt - * Enable Register. - */ -#define UART_EXAR654_EFR_ECB 0x10 /* Enhanced control bit */ -#define UART_EXAR654_EFR_IXON 0x2 /* Receiver compares Xon1/Xoff1 */ -#define UART_EXAR654_EFR_IXOFF 0x8 /* Transmit Xon1/Xoff1 */ -#define UART_EXAR654_EFR_RTSDTR 0x40 /* Auto RTS/DTR Flow Control Enable */ -#define UART_EXAR654_EFR_CTSDSR 0x80 /* Auto CTS/DSR Flow Control Enable */ -#define UART_EXAR654_IER_XOFF 0x20 /* Xoff Interrupt Enable */ -#define UART_EXAR654_IER_RTSDTR 0x40 /* Output Interrupt Enable */ -#define UART_EXAR654_IER_CTSDSR 0x80 /* Input Interrupt Enable */ - -extern struct board_ops dgnc_cls_ops; - -#endif /* _DGNC_CLS_H */ diff --git a/drivers/staging/dgnc/dgnc_driver.c b/drivers/staging/dgnc/dgnc_driver.c deleted file mode 100644 index 5d8c2d995dcc..000000000000 --- a/drivers/staging/dgnc/dgnc_driver.c +++ /dev/null @@ -1,404 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/slab.h> -#include <linux/sched.h> -#include "dgnc_driver.h" -#include "dgnc_tty.h" -#include "dgnc_cls.h" - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Digi International, http://www.digi.com"); -MODULE_DESCRIPTION("Driver for the Digi International Neo and Classic PCI based product line"); -MODULE_SUPPORTED_DEVICE("dgnc"); - -static unsigned int dgnc_num_boards; -struct dgnc_board *dgnc_board[MAXBOARDS]; -static DEFINE_SPINLOCK(dgnc_poll_lock); /* Poll scheduling lock */ - -static int dgnc_poll_tick = 20; /* Poll interval - 20 ms */ -static ulong dgnc_poll_time; /* Time of next poll */ -static uint dgnc_poll_stop; /* Used to tell poller to stop */ -static struct timer_list dgnc_poll_timer; - -#define DIGI_VID 0x114F -#define PCI_DEVICE_CLASSIC_4_DID 0x0028 -#define PCI_DEVICE_CLASSIC_8_DID 0x0029 -#define PCI_DEVICE_CLASSIC_4_422_DID 0x00D0 -#define PCI_DEVICE_CLASSIC_8_422_DID 0x00D1 - -#define PCI_DEVICE_CLASSIC_4_PCI_NAME "ClassicBoard 4 PCI" -#define PCI_DEVICE_CLASSIC_8_PCI_NAME "ClassicBoard 8 PCI" -#define PCI_DEVICE_CLASSIC_4_422_PCI_NAME "ClassicBoard 4 422 PCI" -#define PCI_DEVICE_CLASSIC_8_422_PCI_NAME "ClassicBoard 8 422 PCI" - -static const struct pci_device_id dgnc_pci_tbl[] = { - {PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_4_DID), .driver_data = 0}, - {PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_4_422_DID), .driver_data = 1}, - {PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_8_DID), .driver_data = 2}, - {PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_8_422_DID), .driver_data = 3}, - {0,} -}; -MODULE_DEVICE_TABLE(pci, dgnc_pci_tbl); - -struct board_id { - unsigned char *name; - uint maxports; - unsigned int is_pci_express; -}; - -static const struct board_id dgnc_ids[] = { - { PCI_DEVICE_CLASSIC_4_PCI_NAME, 4, 0 }, - { PCI_DEVICE_CLASSIC_4_422_PCI_NAME, 4, 0 }, - { PCI_DEVICE_CLASSIC_8_PCI_NAME, 8, 0 }, - { PCI_DEVICE_CLASSIC_8_422_PCI_NAME, 8, 0 }, - { NULL, 0, 0 } -}; - -/* Remap PCI memory. */ -static int dgnc_do_remap(struct dgnc_board *brd) -{ - brd->re_map_membase = ioremap(brd->membase, 0x1000); - if (!brd->re_map_membase) - return -ENOMEM; - - return 0; -} - -/* A board has been found, initialize it. */ -static struct dgnc_board *dgnc_found_board(struct pci_dev *pdev, int id) -{ - struct dgnc_board *brd; - unsigned int pci_irq; - int rc = 0; - - brd = kzalloc(sizeof(*brd), GFP_KERNEL); - if (!brd) - return ERR_PTR(-ENOMEM); - - /* store the info for the board we've found */ - brd->boardnum = dgnc_num_boards; - brd->device = dgnc_pci_tbl[id].device; - brd->pdev = pdev; - brd->name = dgnc_ids[id].name; - brd->maxports = dgnc_ids[id].maxports; - init_waitqueue_head(&brd->state_wait); - - spin_lock_init(&brd->bd_lock); - spin_lock_init(&brd->bd_intr_lock); - - brd->state = BOARD_FOUND; - - pci_irq = pdev->irq; - brd->irq = pci_irq; - - switch (brd->device) { - case PCI_DEVICE_CLASSIC_4_DID: - case PCI_DEVICE_CLASSIC_8_DID: - case PCI_DEVICE_CLASSIC_4_422_DID: - case PCI_DEVICE_CLASSIC_8_422_DID: - /* - * For PCI ClassicBoards - * PCI Local Address (i.e. "resource" number) space - * 0 PLX Memory Mapped Config - * 1 PLX I/O Mapped Config - * 2 I/O Mapped UARTs and Status - * 3 Memory Mapped VPD - * 4 Memory Mapped UARTs and Status - */ - - brd->membase = pci_resource_start(pdev, 4); - - if (!brd->membase) { - dev_err(&brd->pdev->dev, - "Card has no PCI IO resources, failing.\n"); - rc = -ENODEV; - goto failed; - } - - brd->membase_end = pci_resource_end(pdev, 4); - - if (brd->membase & 1) - brd->membase &= ~3; - else - brd->membase &= ~15; - - brd->iobase = pci_resource_start(pdev, 1); - brd->iobase_end = pci_resource_end(pdev, 1); - brd->iobase = ((unsigned int)(brd->iobase)) & 0xFFFE; - - brd->bd_ops = &dgnc_cls_ops; - - brd->bd_uart_offset = 0x8; - brd->bd_dividend = 921600; - - rc = dgnc_do_remap(brd); - if (rc < 0) - goto failed; - - /* - * Enable Local Interrupt 1 (0x1), - * Local Interrupt 1 Polarity Active high (0x2), - * Enable PCI interrupt (0x40) - */ - outb(0x43, brd->iobase + 0x4c); - - break; - - default: - dev_err(&brd->pdev->dev, - "Didn't find any compatible Neo/Classic PCI boards.\n"); - rc = -ENXIO; - goto failed; - } - - tasklet_init(&brd->helper_tasklet, - brd->bd_ops->tasklet, - (unsigned long)brd); - - wake_up_interruptible(&brd->state_wait); - - return brd; - -failed: - kfree(brd); - - return ERR_PTR(rc); -} - -static int dgnc_request_irq(struct dgnc_board *brd) -{ - if (brd->irq) { - int rc = request_irq(brd->irq, brd->bd_ops->intr, - IRQF_SHARED, "DGNC", brd); - if (rc) { - dev_err(&brd->pdev->dev, - "Failed to hook IRQ %d\n", brd->irq); - brd->state = BOARD_FAILED; - return -ENODEV; - } - } - return 0; -} - -static void dgnc_free_irq(struct dgnc_board *brd) -{ - if (brd->irq) - free_irq(brd->irq, brd); -} - - /* - * As each timer expires, it determines (a) whether the "transmit" - * waiter needs to be woken up, and (b) whether the poller needs to - * be rescheduled. - */ -static void dgnc_poll_handler(struct timer_list *unused) -{ - struct dgnc_board *brd; - unsigned long flags; - int i; - unsigned long new_time; - - for (i = 0; i < dgnc_num_boards; i++) { - brd = dgnc_board[i]; - - spin_lock_irqsave(&brd->bd_lock, flags); - - if (brd->state == BOARD_FAILED) { - spin_unlock_irqrestore(&brd->bd_lock, flags); - continue; - } - - tasklet_schedule(&brd->helper_tasklet); - - spin_unlock_irqrestore(&brd->bd_lock, flags); - } - - /* Schedule ourself back at the nominal wakeup interval. */ - - spin_lock_irqsave(&dgnc_poll_lock, flags); - dgnc_poll_time += dgnc_jiffies_from_ms(dgnc_poll_tick); - - new_time = dgnc_poll_time - jiffies; - - if ((ulong)new_time >= 2 * dgnc_poll_tick) - dgnc_poll_time = jiffies + dgnc_jiffies_from_ms(dgnc_poll_tick); - - timer_setup(&dgnc_poll_timer, dgnc_poll_handler, 0); - dgnc_poll_timer.expires = dgnc_poll_time; - spin_unlock_irqrestore(&dgnc_poll_lock, flags); - - if (!dgnc_poll_stop) - add_timer(&dgnc_poll_timer); -} - -/* returns count (>= 0), or negative on error */ -static int dgnc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - int rc; - struct dgnc_board *brd; - - rc = pci_enable_device(pdev); - if (rc) - return -EIO; - - brd = dgnc_found_board(pdev, ent->driver_data); - if (IS_ERR(brd)) - return PTR_ERR(brd); - - rc = dgnc_tty_register(brd); - if (rc < 0) { - pr_err(DRVSTR ": Can't register tty devices (%d)\n", rc); - goto failed; - } - - rc = dgnc_request_irq(brd); - if (rc < 0) { - pr_err(DRVSTR ": Can't finalize board init (%d)\n", rc); - goto unregister_tty; - } - - rc = dgnc_tty_init(brd); - if (rc < 0) { - pr_err(DRVSTR ": Can't init tty devices (%d)\n", rc); - goto free_irq; - } - - brd->state = BOARD_READY; - - dgnc_board[dgnc_num_boards++] = brd; - - return 0; - -free_irq: - dgnc_free_irq(brd); -unregister_tty: - dgnc_tty_unregister(brd); -failed: - kfree(brd); - - return rc; -} - -static struct pci_driver dgnc_driver = { - .name = "dgnc", - .probe = dgnc_init_one, - .id_table = dgnc_pci_tbl, -}; - -static int dgnc_start(void) -{ - unsigned long flags; - - /* Start the poller */ - spin_lock_irqsave(&dgnc_poll_lock, flags); - timer_setup(&dgnc_poll_timer, dgnc_poll_handler, 0); - dgnc_poll_time = jiffies + dgnc_jiffies_from_ms(dgnc_poll_tick); - dgnc_poll_timer.expires = dgnc_poll_time; - spin_unlock_irqrestore(&dgnc_poll_lock, flags); - - add_timer(&dgnc_poll_timer); - - return 0; -} - -/* Free all the memory associated with a board */ -static void dgnc_cleanup_board(struct dgnc_board *brd) -{ - int i = 0; - - if (!brd) - return; - - switch (brd->device) { - case PCI_DEVICE_CLASSIC_4_DID: - case PCI_DEVICE_CLASSIC_8_DID: - case PCI_DEVICE_CLASSIC_4_422_DID: - case PCI_DEVICE_CLASSIC_8_422_DID: - - /* Tell card not to interrupt anymore. */ - outb(0, brd->iobase + 0x4c); - break; - - default: - break; - } - - if (brd->irq) - free_irq(brd->irq, brd); - - tasklet_kill(&brd->helper_tasklet); - - if (brd->re_map_membase) { - iounmap(brd->re_map_membase); - brd->re_map_membase = NULL; - } - - for (i = 0; i < MAXPORTS ; i++) { - if (brd->channels[i]) { - kfree(brd->channels[i]->ch_rqueue); - kfree(brd->channels[i]->ch_equeue); - kfree(brd->channels[i]->ch_wqueue); - kfree(brd->channels[i]); - brd->channels[i] = NULL; - } - } - - dgnc_board[brd->boardnum] = NULL; - - kfree(brd); -} - -/* Driver load/unload functions */ - -static void cleanup(void) -{ - int i; - unsigned long flags; - - spin_lock_irqsave(&dgnc_poll_lock, flags); - dgnc_poll_stop = 1; - spin_unlock_irqrestore(&dgnc_poll_lock, flags); - - /* Turn off poller right away. */ - del_timer_sync(&dgnc_poll_timer); - - for (i = 0; i < dgnc_num_boards; ++i) { - dgnc_cleanup_tty(dgnc_board[i]); - dgnc_cleanup_board(dgnc_board[i]); - } -} - -static void __exit dgnc_cleanup_module(void) -{ - cleanup(); - pci_unregister_driver(&dgnc_driver); -} - -static int __init dgnc_init_module(void) -{ - int rc; - - /* Initialize global stuff */ - rc = dgnc_start(); - if (rc < 0) - return rc; - - /* Find and configure all the cards */ - rc = pci_register_driver(&dgnc_driver); - if (rc) { - pr_warn("WARNING: dgnc driver load failed. No Digi Neo or Classic boards found.\n"); - cleanup(); - return rc; - } - return 0; -} - -module_init(dgnc_init_module); -module_exit(dgnc_cleanup_module); diff --git a/drivers/staging/dgnc/dgnc_driver.h b/drivers/staging/dgnc/dgnc_driver.h deleted file mode 100644 index b4d9f714c60a..000000000000 --- a/drivers/staging/dgnc/dgnc_driver.h +++ /dev/null @@ -1,345 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - */ - -#ifndef _DGNC_DRIVER_H -#define _DGNC_DRIVER_H - -#include <linux/types.h> -#include <linux/tty.h> -#include <linux/interrupt.h> - -#include "digi.h" /* Digi specific ioctl header */ - -/* Driver identification and error statements */ -#define PROCSTR "dgnc" /* /proc entries */ -#define DEVSTR "/dev/dg/dgnc" /* /dev entries */ -#define DRVSTR "dgnc" /* Driver name string */ -#define DG_PART "40002369_F" /* RPM part number */ - -#define TRC_TO_CONSOLE 1 - -/* Number of boards we support at once. */ -#define MAXBOARDS 20 -#define MAXPORTS 8 -#define MAXTTYNAMELEN 200 - -/* Serial port types */ -#define DGNC_SERIAL 0 -#define DGNC_PRINT 1 - -#define SERIAL_TYPE_NORMAL 1 - -#define PORT_NUM(dev) ((dev) & 0x7f) -#define IS_PRINT(dev) (((dev) & 0xff) >= 0x80) - -/* MAX number of stop characters sent when our read queue is getting full */ -#define MAX_STOPS_SENT 5 - -/* 4 extra for alignment play space */ -#define WRITEBUFLEN ((4096) + 4) - -#define dgnc_jiffies_from_ms(a) (((a) * HZ) / 1000) - -#ifndef _POSIX_VDISABLE -#define _POSIX_VDISABLE '\0' -#endif - -/* All the possible states the driver can be while being loaded. */ -enum { - DRIVER_INITIALIZED = 0, - DRIVER_READY -}; - -/* All the possible states the board can be while booting up. */ -enum { - BOARD_FAILED = 0, - BOARD_FOUND, - BOARD_READY -}; - -struct dgnc_board; -struct channel_t; - -/** - * struct board_ops - Per board operations. - */ -struct board_ops { - void (*tasklet)(unsigned long data); - irqreturn_t (*intr)(int irq, void *voidbrd); - void (*uart_init)(struct channel_t *ch); - void (*uart_off)(struct channel_t *ch); - int (*drain)(struct tty_struct *tty, uint seconds); - void (*param)(struct tty_struct *tty); - void (*assert_modem_signals)(struct channel_t *ch); - void (*flush_uart_write)(struct channel_t *ch); - void (*flush_uart_read)(struct channel_t *ch); - void (*disable_receiver)(struct channel_t *ch); - void (*enable_receiver)(struct channel_t *ch); - void (*send_break)(struct channel_t *ch, int msec); - void (*send_start_character)(struct channel_t *ch); - void (*send_stop_character)(struct channel_t *ch); - void (*copy_data_from_queue_to_uart)(struct channel_t *ch); - uint (*get_uart_bytes_left)(struct channel_t *ch); - void (*send_immediate_char)(struct channel_t *ch, unsigned char c); -}; - -/** - * struct dgnc_board - Per board information. - * @boardnum: Board number (0 - 32). - * - * @name: Product name. - * @pdev: Pointer to the pci_dev structure. - * @device: PCI device ID. - * @maxports: Maximum ports this board can handle. - * @bd_lock: Used to protect board. - * @bd_intr_lock: Protect poller tasklet and interrupt routine from each other. - * @state: State of the card. - * @state_wait: Queue to sleep on for state change. - * @helper_tasklet: Poll helper tasklet. - * @nasync: Number of ports on card. - * @irq: Interrupt request number. - * @membase: Start of base memory of the card. - * @membase_end: End of base memory of the card. - * @iobase: Start of IO base of the card. - * @iobase_end: End of IO base of the card. - * @bd_uart_offset: Space between each UART. - * @channels: array of pointers to our channels. - * @serial_driver: Pointer to the serial driver. - * @serial_name: Serial driver name. - * @print_dirver: Pointer to the print driver. - * @print_name: Print driver name. - * @bd_dividend: Board/UART's specific dividend. - * @bd_ops: Pointer to board operations structure. - */ -struct dgnc_board { - int boardnum; - char *name; - struct pci_dev *pdev; - u16 device; - uint maxports; - - /* used to protect the board */ - spinlock_t bd_lock; - - /* Protect poller tasklet and interrupt routine from each other. */ - spinlock_t bd_intr_lock; - - uint state; - wait_queue_head_t state_wait; - - struct tasklet_struct helper_tasklet; - - uint nasync; - - uint irq; - - ulong membase; - ulong membase_end; - - u8 __iomem *re_map_membase; - - ulong iobase; - ulong iobase_end; - - uint bd_uart_offset; - - struct channel_t *channels[MAXPORTS]; - - struct tty_driver *serial_driver; - char serial_name[200]; - struct tty_driver *print_driver; - char print_name[200]; - - uint bd_dividend; - - struct board_ops *bd_ops; -}; - -/* Unit flag definitions for un_flags. */ -#define UN_ISOPEN 0x0001 /* Device is open */ -#define UN_CLOSING 0x0002 /* Line is being closed */ -#define UN_IMM 0x0004 /* Service immediately */ -#define UN_BUSY 0x0008 /* Some work this channel */ -#define UN_BREAKI 0x0010 /* Input break received */ -#define UN_PWAIT 0x0020 /* Printer waiting for terminal */ -#define UN_TIME 0x0040 /* Waiting on time */ -#define UN_EMPTY 0x0080 /* Waiting output queue empty */ -#define UN_LOW 0x0100 /* Waiting output low water mark*/ -#define UN_EXCL_OPEN 0x0200 /* Open for exclusive use */ -#define UN_WOPEN 0x0400 /* Device waiting for open */ -#define UN_WIOCTL 0x0800 /* Device waiting for open */ -#define UN_HANGUP 0x8000 /* Carrier lost */ - -struct device; - -/** - * struct un_t - terminal or printer unit - * @un_open_count: Counter of opens to port. - * @un_tty: Pointer to unit tty structure. - * @un_flags: Unit flags. - * @un_flags_wait: Place to sleep to wait on unit. - * @un_dev: Minor device number. - */ -struct un_t { - struct channel_t *un_ch; - uint un_type; - uint un_open_count; - struct tty_struct *un_tty; - uint un_flags; - wait_queue_head_t un_flags_wait; - uint un_dev; - struct device *un_sysfs; -}; - -/* Device flag definitions for ch_flags. */ -#define CH_PRON 0x0001 /* Printer on string */ -#define CH_STOP 0x0002 /* Output is stopped */ -#define CH_STOPI 0x0004 /* Input is stopped */ -#define CH_CD 0x0008 /* Carrier is present */ -#define CH_FCAR 0x0010 /* Carrier forced on */ -#define CH_HANGUP 0x0020 /* Hangup received */ - -#define CH_RECEIVER_OFF 0x0040 /* Receiver is off */ -#define CH_OPENING 0x0080 /* Port in fragile open state */ -#define CH_CLOSING 0x0100 /* Port in fragile close state */ -#define CH_FIFO_ENABLED 0x0200 /* Port has FIFOs enabled */ -#define CH_TX_FIFO_EMPTY 0x0400 /* TX Fifo is completely empty */ -#define CH_TX_FIFO_LWM 0x0800 /* TX Fifo is below Low Water */ -#define CH_BREAK_SENDING 0x1000 /* Break is being sent */ -#define CH_LOOPBACK 0x2000 /* Channel is in lookback mode */ -#define CH_BAUD0 0x08000 /* Used for checking B0 transitions */ -#define CH_FORCED_STOP 0x20000 /* Output is forcibly stopped */ -#define CH_FORCED_STOPI 0x40000 /* Input is forcibly stopped */ - -/* Our Read/Error/Write queue sizes */ -#define RQUEUEMASK 0x1FFF /* 8 K - 1 */ -#define EQUEUEMASK 0x1FFF /* 8 K - 1 */ -#define WQUEUEMASK 0x0FFF /* 4 K - 1 */ -#define RQUEUESIZE (RQUEUEMASK + 1) -#define EQUEUESIZE RQUEUESIZE -#define WQUEUESIZE (WQUEUEMASK + 1) - -/** - * struct channel_t - Channel information. - * @dgnc_board: Pointer to board structure. - * @ch_bd: Transparent print structure. - * @ch_tun: Terminal unit information. - * @ch_pun: Printer unit information. - * @ch_lock: Provide for serialization. - * @ch_flags_wait: Channel flags wait queue. - * @ch_portnum: Port number, 0 offset. - * @ch_open_count: Open count. - * @ch_flags: Channel flags. - * @ch_close_delay: How long we should drop RTS/DTR for. - * @ch_cpstime: Time for CPS calculations. - * @ch_c_iflag: Channel iflags. - * @ch_c_cflag: Channel cflags. - * @ch_c_oflag: Channel oflags. - * @ch_c_lflag: Channel lflags. - * @ch_stopc: Stop character. - * @ch_startc: Start character. - * @ch_old_baud: Cache of the current baud rate. - * @ch_custom_speed: Custom baud rate, if set. - * @ch_wopen: Waiting for open process count. - * @ch_mostat: FEP output modem status. - * @ch_mistat: FEP input modem status. - * @ch_cls_uart: Pointer to the mapped cls UART struct - * @ch_cached_lsr: Cached value of the LSR register. - * @ch_rqueue: Read queue buffer, malloc'ed. - * @ch_r_head: Head location of the read queue. - * @ch_r_tail: Tail location of the read queue. - * @ch_equeue: Error queue buffer, malloc'ed. - * @ch_e_head: Head location of the error queue. - * @ch_e_tail: Tail location of the error queue. - * @ch_wqueue: Write queue buffer, malloc'ed. - * @ch_w_head: Head location of the write queue. - * @ch_w_tail: Tail location of the write queue. - * @ch_rxcount: Total of data received so far. - * @ch_txcount: Total of data transmitted so far. - * @ch_r_tlevel: Receive trigger level. - * @ch_t_tlevel: Transmit trigger level. - * @ch_r_watermark: Receive water mark. - * @ch_stop_sending_break: Time we should STOP sending a break. - * @ch_stops_sent: How many times I have send a stop character to try - * to stop the other guy sending. - * @ch_err_parity: Count of parity - * @ch_err_frame: Count of framing errors on channel. - * @ch_err_break: Count of breaks on channel. - * @ch_err_overrun: Count of overruns on channel. - * @ch_xon_sends: Count of xons transmitted. - * @ch_xoff_sends: Count of xoffs transmitted. - */ -struct channel_t { - struct dgnc_board *ch_bd; - struct digi_t ch_digi; - struct un_t ch_tun; - struct un_t ch_pun; - - spinlock_t ch_lock; /* provide for serialization */ - wait_queue_head_t ch_flags_wait; - - uint ch_portnum; - uint ch_open_count; - uint ch_flags; - - ulong ch_close_delay; - - ulong ch_cpstime; - - tcflag_t ch_c_iflag; - tcflag_t ch_c_cflag; - tcflag_t ch_c_oflag; - tcflag_t ch_c_lflag; - unsigned char ch_stopc; - unsigned char ch_startc; - - uint ch_old_baud; - uint ch_custom_speed; - - uint ch_wopen; - - unsigned char ch_mostat; - unsigned char ch_mistat; - - struct cls_uart_struct __iomem *ch_cls_uart; - - unsigned char ch_cached_lsr; - - unsigned char *ch_rqueue; - ushort ch_r_head; - ushort ch_r_tail; - - unsigned char *ch_equeue; - ushort ch_e_head; - ushort ch_e_tail; - - unsigned char *ch_wqueue; - ushort ch_w_head; - ushort ch_w_tail; - - ulong ch_rxcount; - ulong ch_txcount; - - unsigned char ch_r_tlevel; - unsigned char ch_t_tlevel; - - unsigned char ch_r_watermark; - - ulong ch_stop_sending_break; - uint ch_stops_sent; - - ulong ch_err_parity; - ulong ch_err_frame; - ulong ch_err_break; - ulong ch_err_overrun; - - ulong ch_xon_sends; - ulong ch_xoff_sends; -}; - -extern struct dgnc_board *dgnc_board[MAXBOARDS];/* Array of boards */ - -#endif /* _DGNC_DRIVER_H */ diff --git a/drivers/staging/dgnc/dgnc_tty.c b/drivers/staging/dgnc/dgnc_tty.c deleted file mode 100644 index f91eaa1c3b67..000000000000 --- a/drivers/staging/dgnc/dgnc_tty.c +++ /dev/null @@ -1,2590 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - */ - -/* - * This file implements the tty driver functionality for the - * Neo and ClassicBoard PCI based product lines. - */ - -#include <linux/kernel.h> -#include <linux/sched/signal.h> /* For jiffies, task states, etc. */ -#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */ -#include <linux/module.h> -#include <linux/ctype.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/types.h> -#include <linux/serial_reg.h> -#include <linux/slab.h> -#include <linux/delay.h> /* For udelay */ -#include <linux/uaccess.h> /* For copy_from_user/copy_to_user */ -#include <linux/pci.h> -#include "dgnc_driver.h" -#include "dgnc_tty.h" -#include "dgnc_cls.h" - -/* Default transparent print information. */ - -static const struct digi_t dgnc_digi_init = { - .digi_flags = DIGI_COOK, /* Flags */ - .digi_maxcps = 100, /* Max CPS */ - .digi_maxchar = 50, /* Max chars in print queue */ - .digi_bufsize = 100, /* Printer buffer size */ - .digi_onlen = 4, /* size of printer on string */ - .digi_offlen = 4, /* size of printer off string */ - .digi_onstr = "\033[5i", /* ANSI printer on string ] */ - .digi_offstr = "\033[4i", /* ANSI printer off string ] */ - .digi_term = "ansi" /* default terminal type */ -}; - -static int dgnc_tty_open(struct tty_struct *tty, struct file *file); -static void dgnc_tty_close(struct tty_struct *tty, struct file *file); -static int dgnc_block_til_ready(struct tty_struct *tty, struct file *file, - struct channel_t *ch); -static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, - unsigned long arg); -static int dgnc_tty_digigeta(struct tty_struct *tty, - struct digi_t __user *retinfo); -static int dgnc_tty_digiseta(struct tty_struct *tty, - struct digi_t __user *new_info); -static int dgnc_tty_write_room(struct tty_struct *tty); -static int dgnc_tty_put_char(struct tty_struct *tty, unsigned char c); -static int dgnc_tty_chars_in_buffer(struct tty_struct *tty); -static void dgnc_tty_start(struct tty_struct *tty); -static void dgnc_tty_stop(struct tty_struct *tty); -static void dgnc_tty_throttle(struct tty_struct *tty); -static void dgnc_tty_unthrottle(struct tty_struct *tty); -static void dgnc_tty_flush_chars(struct tty_struct *tty); -static void dgnc_tty_flush_buffer(struct tty_struct *tty); -static void dgnc_tty_hangup(struct tty_struct *tty); -static int dgnc_set_modem_info(struct channel_t *ch, unsigned int command, - unsigned int __user *value); -static int dgnc_get_modem_info(struct channel_t *ch, - unsigned int __user *value); -static int dgnc_tty_tiocmget(struct tty_struct *tty); -static int dgnc_tty_tiocmset(struct tty_struct *tty, unsigned int set, - unsigned int clear); -static int dgnc_tty_send_break(struct tty_struct *tty, int msec); -static void dgnc_tty_wait_until_sent(struct tty_struct *tty, int timeout); -static int dgnc_tty_write(struct tty_struct *tty, const unsigned char *buf, - int count); -static void dgnc_tty_set_termios(struct tty_struct *tty, - struct ktermios *old_termios); -static void dgnc_tty_send_xchar(struct tty_struct *tty, char ch); -static void dgnc_set_signal_low(struct channel_t *ch, const unsigned char line); -static void dgnc_wake_up_unit(struct un_t *unit); - -static const struct tty_operations dgnc_tty_ops = { - .open = dgnc_tty_open, - .close = dgnc_tty_close, - .write = dgnc_tty_write, - .write_room = dgnc_tty_write_room, - .flush_buffer = dgnc_tty_flush_buffer, - .chars_in_buffer = dgnc_tty_chars_in_buffer, - .flush_chars = dgnc_tty_flush_chars, - .ioctl = dgnc_tty_ioctl, - .set_termios = dgnc_tty_set_termios, - .stop = dgnc_tty_stop, - .start = dgnc_tty_start, - .throttle = dgnc_tty_throttle, - .unthrottle = dgnc_tty_unthrottle, - .hangup = dgnc_tty_hangup, - .put_char = dgnc_tty_put_char, - .tiocmget = dgnc_tty_tiocmget, - .tiocmset = dgnc_tty_tiocmset, - .break_ctl = dgnc_tty_send_break, - .wait_until_sent = dgnc_tty_wait_until_sent, - .send_xchar = dgnc_tty_send_xchar -}; - -/* TTY Initialization/Cleanup Functions */ - -static struct tty_driver *dgnc_tty_create(char *serial_name, uint maxports, - int major, int minor) -{ - int rc; - struct tty_driver *drv; - - drv = tty_alloc_driver(maxports, - TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV | - TTY_DRIVER_HARDWARE_BREAK); - if (IS_ERR(drv)) - return drv; - - drv->name = serial_name; - drv->name_base = 0; - drv->major = major; - drv->minor_start = minor; - drv->type = TTY_DRIVER_TYPE_SERIAL; - drv->subtype = SERIAL_TYPE_NORMAL; - drv->init_termios = tty_std_termios; - drv->init_termios.c_cflag = (B9600 | CS8 | CREAD | HUPCL | CLOCAL); - drv->init_termios.c_ispeed = 9600; - drv->init_termios.c_ospeed = 9600; - drv->driver_name = DRVSTR; - /* - * Entry points for driver. Called by the kernel from - * tty_io.c and n_tty.c. - */ - tty_set_operations(drv, &dgnc_tty_ops); - rc = tty_register_driver(drv); - if (rc < 0) { - put_tty_driver(drv); - return ERR_PTR(rc); - } - return drv; -} - -static void dgnc_tty_free(struct tty_driver *drv) -{ - tty_unregister_driver(drv); - put_tty_driver(drv); -} - -/** - * dgnc_tty_register() - Init the tty subsystem for this board. - */ -int dgnc_tty_register(struct dgnc_board *brd) -{ - int rc; - - snprintf(brd->serial_name, MAXTTYNAMELEN, "tty_dgnc_%d_", - brd->boardnum); - - brd->serial_driver = dgnc_tty_create(brd->serial_name, - brd->maxports, 0, 0); - if (IS_ERR(brd->serial_driver)) { - rc = PTR_ERR(brd->serial_driver); - dev_dbg(&brd->pdev->dev, "Can't register tty device (%d)\n", - rc); - return rc; - } - - snprintf(brd->print_name, MAXTTYNAMELEN, "pr_dgnc_%d_", brd->boardnum); - brd->print_driver = dgnc_tty_create(brd->print_name, brd->maxports, - 0x80, - brd->serial_driver->major); - if (IS_ERR(brd->print_driver)) { - rc = PTR_ERR(brd->print_driver); - dev_dbg(&brd->pdev->dev, - "Can't register Transparent Print device(%d)\n", rc); - dgnc_tty_free(brd->serial_driver); - return rc; - } - return 0; -} - -void dgnc_tty_unregister(struct dgnc_board *brd) -{ - dgnc_tty_free(brd->print_driver); - dgnc_tty_free(brd->serial_driver); -} - -/** - * dgnc_tty_init() - Initialize the tty subsystem. - * - * Called once per board after board has been downloaded and initialized. - */ -int dgnc_tty_init(struct dgnc_board *brd) -{ - int i; - int rc; - void __iomem *vaddr; - struct channel_t *ch; - - if (!brd) - return -ENXIO; - - /* Initialize board structure elements. */ - - vaddr = brd->re_map_membase; - - brd->nasync = brd->maxports; - - for (i = 0; i < brd->nasync; i++) { - brd->channels[i] = kzalloc(sizeof(*brd->channels[i]), - GFP_KERNEL); - if (!brd->channels[i]) { - rc = -ENOMEM; - goto err_free_channels; - } - } - - ch = brd->channels[0]; - vaddr = brd->re_map_membase; - - /* Set up channel variables */ - for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) { - spin_lock_init(&ch->ch_lock); - - ch->ch_tun.un_ch = ch; - ch->ch_tun.un_type = DGNC_SERIAL; - ch->ch_tun.un_dev = i; - - ch->ch_pun.un_ch = ch; - ch->ch_pun.un_type = DGNC_PRINT; - ch->ch_pun.un_dev = i + 128; - - ch->ch_cls_uart = vaddr + (brd->bd_uart_offset * i); - - ch->ch_bd = brd; - ch->ch_portnum = i; - ch->ch_digi = dgnc_digi_init; - - /* .25 second delay */ - ch->ch_close_delay = 250; - - init_waitqueue_head(&ch->ch_flags_wait); - init_waitqueue_head(&ch->ch_tun.un_flags_wait); - init_waitqueue_head(&ch->ch_pun.un_flags_wait); - - { - struct device *classp; - - classp = tty_register_device(brd->serial_driver, i, - &ch->ch_bd->pdev->dev); - ch->ch_tun.un_sysfs = classp; - - classp = tty_register_device(brd->print_driver, i, - &ch->ch_bd->pdev->dev); - ch->ch_pun.un_sysfs = classp; - } - } - - return 0; - -err_free_channels: - for (i = i - 1; i >= 0; --i) { - kfree(brd->channels[i]); - brd->channels[i] = NULL; - } - - return rc; -} - -/** - * dgnc_cleanup_tty() - Cleanup driver. - * - * Uninitialize the TTY portion of this driver. Free all memory and - * resources. - */ -void dgnc_cleanup_tty(struct dgnc_board *brd) -{ - int i = 0; - - for (i = 0; i < brd->nasync; i++) - tty_unregister_device(brd->serial_driver, i); - - tty_unregister_driver(brd->serial_driver); - - for (i = 0; i < brd->nasync; i++) - tty_unregister_device(brd->print_driver, i); - - tty_unregister_driver(brd->print_driver); - - put_tty_driver(brd->serial_driver); - put_tty_driver(brd->print_driver); -} - -/** - * dgnc_wmove() - Write data to transmit queue. - * @ch: Pointer to channel structure. - * @buf: Pointer to characters to be moved. - * @n: Number of characters to move. - */ -static void dgnc_wmove(struct channel_t *ch, char *buf, uint n) -{ - int remain; - uint head; - - if (!ch) - return; - - head = ch->ch_w_head & WQUEUEMASK; - - /* - * If the write wraps over the top of the circular buffer, - * move the portion up to the wrap point, and reset the - * pointers to the bottom. - */ - remain = WQUEUESIZE - head; - - if (n >= remain) { - n -= remain; - memcpy(ch->ch_wqueue + head, buf, remain); - head = 0; - buf += remain; - } - - if (n > 0) { - /* Move rest of data. */ - remain = n; - memcpy(ch->ch_wqueue + head, buf, remain); - head += remain; - } - - head &= WQUEUEMASK; - ch->ch_w_head = head; -} - -/** - * dgnc_input() - Process received data. - * @ch: Pointer to channel structure. - */ -void dgnc_input(struct channel_t *ch) -{ - struct dgnc_board *bd; - struct tty_struct *tp; - struct tty_ldisc *ld = NULL; - uint rmask; - ushort head; - ushort tail; - int data_len; - unsigned long flags; - int flip_len; - int len = 0; - int n = 0; - int s = 0; - int i = 0; - - if (!ch) - return; - - tp = ch->ch_tun.un_tty; - - bd = ch->ch_bd; - if (!bd) - return; - - spin_lock_irqsave(&ch->ch_lock, flags); - - rmask = RQUEUEMASK; - head = ch->ch_r_head & rmask; - tail = ch->ch_r_tail & rmask; - data_len = (head - tail) & rmask; - - if (data_len == 0) - goto exit_unlock; - - /* - * If the device is not open, or CREAD is off, - * flush input data and return immediately. - */ - if (!tp || - !(ch->ch_tun.un_flags & UN_ISOPEN) || - !C_CREAD(tp) || - (ch->ch_tun.un_flags & UN_CLOSING)) { - ch->ch_r_head = tail; - - /* Force queue flow control to be released, if needed */ - dgnc_check_queue_flow_control(ch); - - goto exit_unlock; - } - - if (ch->ch_flags & CH_FORCED_STOPI) - goto exit_unlock; - - flip_len = TTY_FLIPBUF_SIZE; - - len = min(data_len, flip_len); - len = min(len, (N_TTY_BUF_SIZE - 1)); - - ld = tty_ldisc_ref(tp); - if (!ld) { - len = 0; - } else { - if (!ld->ops->receive_buf) { - ch->ch_r_head = ch->ch_r_tail; - len = 0; - } - } - - if (len <= 0) - goto exit_unlock; - - /* - * The tty layer in the kernel has changed in 2.6.16+. - * - * The flip buffers in the tty structure are no longer exposed, - * and probably will be going away eventually. - * - * If we are completely raw, we don't need to go through a lot - * of the tty layers that exist. - * In this case, we take the shortest and fastest route we - * can to relay the data to the user. - * - * On the other hand, if we are not raw, we need to go through - * the new 2.6.16+ tty layer, which has its API more well defined. - */ - len = tty_buffer_request_room(tp->port, len); - n = len; - - /* - * n now contains the most amount of data we can copy, - * bounded either by how much the Linux tty layer can handle, - * or the amount of data the card actually has pending... - */ - while (n) { - unsigned char *ch_pos = ch->ch_equeue + tail; - - s = ((head >= tail) ? head : RQUEUESIZE) - tail; - s = min(s, n); - - if (s <= 0) - break; - - /* - * If conditions are such that ld needs to see all - * UART errors, we will have to walk each character - * and error byte and send them to the buffer one at - * a time. - */ - if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) { - for (i = 0; i < s; i++) { - unsigned char ch = *(ch_pos + i); - char flag = TTY_NORMAL; - - if (ch & UART_LSR_BI) - flag = TTY_BREAK; - else if (ch & UART_LSR_PE) - flag = TTY_PARITY; - else if (ch & UART_LSR_FE) - flag = TTY_FRAME; - - tty_insert_flip_char(tp->port, ch, flag); - } - } else { - tty_insert_flip_string(tp->port, ch_pos, s); - } - - tail += s; - n -= s; - /* Flip queue if needed */ - tail &= rmask; - } - - ch->ch_r_tail = tail & rmask; - ch->ch_e_tail = tail & rmask; - dgnc_check_queue_flow_control(ch); - spin_unlock_irqrestore(&ch->ch_lock, flags); - - /* Tell the tty layer its okay to "eat" the data now */ - tty_flip_buffer_push(tp->port); - - if (ld) - tty_ldisc_deref(ld); - return; - -exit_unlock: - spin_unlock_irqrestore(&ch->ch_lock, flags); - if (ld) - tty_ldisc_deref(ld); -} - -/** - * dgnc_carrier() - * - * Determines when CARRIER changes state and takes appropriate - * action. - */ -void dgnc_carrier(struct channel_t *ch) -{ - int virt_carrier = 0; - int phys_carrier = 0; - - if (!ch) - return; - - if (ch->ch_mistat & UART_MSR_DCD) - phys_carrier = 1; - - if (ch->ch_digi.digi_flags & DIGI_FORCEDCD) - virt_carrier = 1; - - if (ch->ch_c_cflag & CLOCAL) - virt_carrier = 1; - - /* Test for a VIRTUAL carrier transition to HIGH. */ - - if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) { - /* - * When carrier rises, wake any threads waiting - * for carrier in the open routine. - */ - if (waitqueue_active(&ch->ch_flags_wait)) - wake_up_interruptible(&ch->ch_flags_wait); - } - - /* Test for a PHYSICAL carrier transition to HIGH. */ - - if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) { - /* - * When carrier rises, wake any threads waiting - * for carrier in the open routine. - */ - if (waitqueue_active(&ch->ch_flags_wait)) - wake_up_interruptible(&ch->ch_flags_wait); - } - - /* - * Test for a PHYSICAL transition to low, so long as we aren't - * currently ignoring physical transitions (which is what "virtual - * carrier" indicates). - * - * The transition of the virtual carrier to low really doesn't - * matter... it really only means "ignore carrier state", not - * "make pretend that carrier is there". - */ - if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0) && - (phys_carrier == 0)) { - /* - * When carrier drops: - * - * Drop carrier on all open units. - * - * Flush queues, waking up any task waiting in the - * line discipline. - * - * Send a hangup to the control terminal. - * - * Enable all select calls. - */ - if (waitqueue_active(&ch->ch_flags_wait)) - wake_up_interruptible(&ch->ch_flags_wait); - - if (ch->ch_tun.un_open_count > 0) - tty_hangup(ch->ch_tun.un_tty); - - if (ch->ch_pun.un_open_count > 0) - tty_hangup(ch->ch_pun.un_tty); - } - - /* Make sure that our cached values reflect the current reality. */ - - if (virt_carrier == 1) - ch->ch_flags |= CH_FCAR; - else - ch->ch_flags &= ~CH_FCAR; - - if (phys_carrier == 1) - ch->ch_flags |= CH_CD; - else - ch->ch_flags &= ~CH_CD; -} - -/* Assign the custom baud rate to the channel structure */ -static void dgnc_set_custom_speed(struct channel_t *ch, uint newrate) -{ - int testdiv; - int testrate_high; - int testrate_low; - int deltahigh; - int deltalow; - - if (newrate <= 0) { - ch->ch_custom_speed = 0; - return; - } - - /* - * Since the divisor is stored in a 16-bit integer, we make sure - * we don't allow any rates smaller than a 16-bit integer would allow. - * And of course, rates above the dividend won't fly. - */ - if (newrate && newrate < ((ch->ch_bd->bd_dividend / 0xFFFF) + 1)) - newrate = (ch->ch_bd->bd_dividend / 0xFFFF) + 1; - - if (newrate && newrate > ch->ch_bd->bd_dividend) - newrate = ch->ch_bd->bd_dividend; - - if (newrate > 0) { - testdiv = ch->ch_bd->bd_dividend / newrate; - - /* - * If we try to figure out what rate the board would use - * with the test divisor, it will be either equal or higher - * than the requested baud rate. If we then determine the - * rate with a divisor one higher, we will get the next lower - * supported rate below the requested. - */ - testrate_high = ch->ch_bd->bd_dividend / testdiv; - testrate_low = ch->ch_bd->bd_dividend / (testdiv + 1); - - /* - * If the rate for the requested divisor is correct, just - * use it and be done. - */ - if (testrate_high != newrate) { - /* - * Otherwise, pick the rate that is closer - * (i.e. whichever rate has a smaller delta). - */ - deltahigh = testrate_high - newrate; - deltalow = newrate - testrate_low; - - if (deltahigh < deltalow) - newrate = testrate_high; - else - newrate = testrate_low; - } - } - - ch->ch_custom_speed = newrate; -} - -void dgnc_check_queue_flow_control(struct channel_t *ch) -{ - int qleft; - - qleft = ch->ch_r_tail - ch->ch_r_head - 1; - if (qleft < 0) - qleft += RQUEUEMASK + 1; - - /* - * Check to see if we should enforce flow control on our queue because - * the ld (or user) isn't reading data out of our queue fast enuf. - * - * NOTE: This is done based on what the current flow control of the - * port is set for. - * - * 1) HWFLOW (RTS) - Turn off the UART's Receive interrupt. - * This will cause the UART's FIFO to back up, and force - * the RTS signal to be dropped. - * 2) SWFLOW (IXOFF) - Keep trying to send a stop character to - * the other side, in hopes it will stop sending data to us. - * 3) NONE - Nothing we can do. We will simply drop any extra data - * that gets sent into us when the queue fills up. - */ - if (qleft < 256) { - /* HWFLOW */ - if (ch->ch_digi.digi_flags & CTSPACE || - ch->ch_c_cflag & CRTSCTS) { - if (!(ch->ch_flags & CH_RECEIVER_OFF)) { - ch->ch_bd->bd_ops->disable_receiver(ch); - ch->ch_flags |= (CH_RECEIVER_OFF); - } - } - /* SWFLOW */ - else if (ch->ch_c_iflag & IXOFF) { - if (ch->ch_stops_sent <= MAX_STOPS_SENT) { - ch->ch_bd->bd_ops->send_stop_character(ch); - ch->ch_stops_sent++; - } - } - } - - /* - * Check to see if we should unenforce flow control because - * ld (or user) finally read enuf data out of our queue. - * - * NOTE: This is done based on what the current flow control of the - * port is set for. - * - * 1) HWFLOW (RTS) - Turn back on the UART's Receive interrupt. - * This will cause the UART's FIFO to raise RTS back up, - * which will allow the other side to start sending data again. - * 2) SWFLOW (IXOFF) - Send a start character to - * the other side, so it will start sending data to us again. - * 3) NONE - Do nothing. Since we didn't do anything to turn off the - * other side, we don't need to do anything now. - */ - if (qleft > (RQUEUESIZE / 2)) { - /* HWFLOW */ - if (ch->ch_digi.digi_flags & RTSPACE || - ch->ch_c_cflag & CRTSCTS) { - if (ch->ch_flags & CH_RECEIVER_OFF) { - ch->ch_bd->bd_ops->enable_receiver(ch); - ch->ch_flags &= ~(CH_RECEIVER_OFF); - } - } - /* SWFLOW */ - else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) { - ch->ch_stops_sent = 0; - ch->ch_bd->bd_ops->send_start_character(ch); - } - } -} - -static void dgnc_set_signal_low(struct channel_t *ch, const unsigned char sig) -{ - ch->ch_mostat &= ~(sig); - ch->ch_bd->bd_ops->assert_modem_signals(ch); -} - -void dgnc_wakeup_writes(struct channel_t *ch) -{ - int qlen = 0; - unsigned long flags; - - if (!ch) - return; - - spin_lock_irqsave(&ch->ch_lock, flags); - - /* If channel now has space, wake up anyone waiting on the condition. */ - - qlen = ch->ch_w_head - ch->ch_w_tail; - if (qlen < 0) - qlen += WQUEUESIZE; - - if (qlen >= (WQUEUESIZE - 256)) { - spin_unlock_irqrestore(&ch->ch_lock, flags); - return; - } - - if (ch->ch_tun.un_flags & UN_ISOPEN) { - tty_wakeup(ch->ch_tun.un_tty); - - /* - * If unit is set to wait until empty, check to make sure - * the queue AND FIFO are both empty. - */ - if (ch->ch_tun.un_flags & UN_EMPTY) { - if ((qlen == 0) && - (ch->ch_bd->bd_ops->get_uart_bytes_left(ch) == 0)) { - ch->ch_tun.un_flags &= ~(UN_EMPTY); - - /* - * If RTS Toggle mode is on, whenever - * the queue and UART is empty, keep RTS low. - */ - if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) - dgnc_set_signal_low(ch, UART_MCR_RTS); - - /* - * If DTR Toggle mode is on, whenever - * the queue and UART is empty, keep DTR low. - */ - if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) - dgnc_set_signal_low(ch, UART_MCR_DTR); - } - } - - wake_up_interruptible(&ch->ch_tun.un_flags_wait); - } - - if (ch->ch_pun.un_flags & UN_ISOPEN) { - tty_wakeup(ch->ch_pun.un_tty); - - /* - * If unit is set to wait until empty, check to make sure - * the queue AND FIFO are both empty. - */ - if (ch->ch_pun.un_flags & UN_EMPTY) { - if ((qlen == 0) && - (ch->ch_bd->bd_ops->get_uart_bytes_left(ch) == 0)) - ch->ch_pun.un_flags &= ~(UN_EMPTY); - } - - wake_up_interruptible(&ch->ch_pun.un_flags_wait); - } - - spin_unlock_irqrestore(&ch->ch_lock, flags); -} - -static struct dgnc_board *find_board_by_major(unsigned int major) -{ - int i; - - for (i = 0; i < MAXBOARDS; i++) { - struct dgnc_board *brd = dgnc_board[i]; - - if (!brd) - return NULL; - - if (major == brd->serial_driver->major || - major == brd->print_driver->major) - return brd; - } - - return NULL; -} - -/* TTY Entry points and helper functions */ - -static int dgnc_tty_open(struct tty_struct *tty, struct file *file) -{ - struct dgnc_board *brd; - struct channel_t *ch; - struct un_t *un; - uint major = 0; - uint minor = 0; - int rc = 0; - unsigned long flags; - - rc = 0; - - major = MAJOR(tty_devnum(tty)); - minor = MINOR(tty_devnum(tty)); - - if (major > 255) - return -ENXIO; - - brd = find_board_by_major(major); - if (!brd) - return -ENXIO; - - rc = wait_event_interruptible(brd->state_wait, - (brd->state & BOARD_READY)); - if (rc) - return rc; - - spin_lock_irqsave(&brd->bd_lock, flags); - - if (PORT_NUM(minor) >= brd->nasync) { - rc = -ENXIO; - goto err_brd_unlock; - } - - ch = brd->channels[PORT_NUM(minor)]; - if (!ch) { - rc = -ENXIO; - goto err_brd_unlock; - } - - spin_unlock_irqrestore(&brd->bd_lock, flags); - - spin_lock_irqsave(&ch->ch_lock, flags); - - /* Figure out our type */ - if (!IS_PRINT(minor)) { - un = &brd->channels[PORT_NUM(minor)]->ch_tun; - un->un_type = DGNC_SERIAL; - } else if (IS_PRINT(minor)) { - un = &brd->channels[PORT_NUM(minor)]->ch_pun; - un->un_type = DGNC_PRINT; - } else { - rc = -ENXIO; - goto err_ch_unlock; - } - - /* - * If the port is still in a previous open, and in a state - * where we simply cannot safely keep going, wait until the - * state clears. - */ - spin_unlock_irqrestore(&ch->ch_lock, flags); - - rc = wait_event_interruptible(ch->ch_flags_wait, - ((ch->ch_flags & CH_OPENING) == 0)); - /* If ret is non-zero, user ctrl-c'ed us */ - if (rc) - return -EINTR; - - /* - * If either unit is in the middle of the fragile part of close, - * we just cannot touch the channel safely. - * Go to sleep, knowing that when the channel can be - * touched safely, the close routine will signal the - * ch_flags_wait to wake us back up. - */ - rc = wait_event_interruptible(ch->ch_flags_wait, - !((ch->ch_tun.un_flags | - ch->ch_pun.un_flags) & UN_CLOSING)); - /* If ret is non-zero, user ctrl-c'ed us */ - if (rc) - return -EINTR; - - spin_lock_irqsave(&ch->ch_lock, flags); - - tty->driver_data = un; - - /* Initialize tty's */ - - if (!(un->un_flags & UN_ISOPEN)) { - un->un_tty = tty; - - /* Maybe do something here to the TTY struct as well? */ - } - - /* - * Allocate channel buffers for read/write/error. - * Set flag, so we don't get trounced on. - */ - ch->ch_flags |= (CH_OPENING); - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - if (!ch->ch_rqueue) - ch->ch_rqueue = kzalloc(RQUEUESIZE, GFP_KERNEL); - if (!ch->ch_equeue) - ch->ch_equeue = kzalloc(EQUEUESIZE, GFP_KERNEL); - if (!ch->ch_wqueue) - ch->ch_wqueue = kzalloc(WQUEUESIZE, GFP_KERNEL); - - if (!ch->ch_rqueue || !ch->ch_equeue || !ch->ch_wqueue) { - kfree(ch->ch_rqueue); - kfree(ch->ch_equeue); - kfree(ch->ch_wqueue); - return -ENOMEM; - } - - spin_lock_irqsave(&ch->ch_lock, flags); - - ch->ch_flags &= ~(CH_OPENING); - wake_up_interruptible(&ch->ch_flags_wait); - - /* Initialize if neither terminal or printer is open. */ - - if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_ISOPEN)) { - /* Flush input queues. */ - ch->ch_r_head = 0; - ch->ch_r_tail = 0; - ch->ch_e_head = 0; - ch->ch_e_tail = 0; - ch->ch_w_head = 0; - ch->ch_w_tail = 0; - - brd->bd_ops->flush_uart_write(ch); - brd->bd_ops->flush_uart_read(ch); - - ch->ch_flags = 0; - ch->ch_cached_lsr = 0; - ch->ch_stop_sending_break = 0; - ch->ch_stops_sent = 0; - - ch->ch_c_cflag = tty->termios.c_cflag; - ch->ch_c_iflag = tty->termios.c_iflag; - ch->ch_c_oflag = tty->termios.c_oflag; - ch->ch_c_lflag = tty->termios.c_lflag; - ch->ch_startc = tty->termios.c_cc[VSTART]; - ch->ch_stopc = tty->termios.c_cc[VSTOP]; - - /* - * Bring up RTS and DTR... - * Also handle RTS or DTR toggle if set. - */ - if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE)) - ch->ch_mostat |= (UART_MCR_RTS); - if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE)) - ch->ch_mostat |= (UART_MCR_DTR); - - /* Tell UART to init itself */ - brd->bd_ops->uart_init(ch); - } - - brd->bd_ops->param(tty); - - dgnc_carrier(ch); - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - rc = dgnc_block_til_ready(tty, file, ch); - - spin_lock_irqsave(&ch->ch_lock, flags); - ch->ch_open_count++; - un->un_open_count++; - un->un_flags |= (UN_ISOPEN); - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return rc; - -err_brd_unlock: - spin_unlock_irqrestore(&brd->bd_lock, flags); - - return rc; -err_ch_unlock: - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return rc; -} - -/* Wait for DCD, if needed. */ -static int dgnc_block_til_ready(struct tty_struct *tty, - struct file *file, - struct channel_t *ch) -{ - int rc = 0; - struct un_t *un = tty->driver_data; - unsigned long flags; - uint old_flags = 0; - int sleep_on_un_flags = 0; - - if (!file) - return -ENXIO; - - spin_lock_irqsave(&ch->ch_lock, flags); - - ch->ch_wopen++; - - while (1) { - sleep_on_un_flags = 0; - - if (ch->ch_bd->state == BOARD_FAILED) { - rc = -ENXIO; - break; - } - - if (tty_hung_up_p(file)) { - rc = -EAGAIN; - break; - } - - /* - * If either unit is in the middle of the fragile part of close, - * we just cannot touch the channel safely. - * Go back to sleep, knowing that when the channel can be - * touched safely, the close routine will signal the - * ch_wait_flags to wake us back up. - */ - if (!((ch->ch_tun.un_flags | - ch->ch_pun.un_flags) & - UN_CLOSING)) { - /* - * Our conditions to leave cleanly and happily: - * 1) NONBLOCKING on the tty is set. - * 2) CLOCAL is set. - * 3) DCD (fake or real) is active. - */ - - if (file->f_flags & O_NONBLOCK) - break; - - if (tty_io_error(tty)) { - rc = -EIO; - break; - } - - if (ch->ch_flags & CH_CD) - break; - - if (ch->ch_flags & CH_FCAR) - break; - } else { - sleep_on_un_flags = 1; - } - - /* - * If there is a signal pending, the user probably - * interrupted (ctrl-c) us. - */ - if (signal_pending(current)) { - rc = -ERESTARTSYS; - break; - } - - if (sleep_on_un_flags) - old_flags = ch->ch_tun.un_flags | ch->ch_pun.un_flags; - else - old_flags = ch->ch_flags; - - /* - * Let go of channel lock before calling schedule. - * Our poller will get any FEP events and wake us up when DCD - * eventually goes active. - */ - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - /* - * Wait for something in the flags to change - * from the current value. - */ - if (sleep_on_un_flags) - rc = wait_event_interruptible - (un->un_flags_wait, - (old_flags != (ch->ch_tun.un_flags | - ch->ch_pun.un_flags))); - else - rc = wait_event_interruptible( - ch->ch_flags_wait, - (old_flags != ch->ch_flags)); - - /* - * We got woken up for some reason. - * Before looping around, grab our channel lock. - */ - spin_lock_irqsave(&ch->ch_lock, flags); - } - - ch->ch_wopen--; - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return rc; -} - -/* Hangup the port. Like a close, but don't wait for output to drain. */ -static void dgnc_tty_hangup(struct tty_struct *tty) -{ - if (!tty) - return; - - /* flush the transmit queues */ - dgnc_tty_flush_buffer(tty); -} - -static void dgnc_tty_close(struct tty_struct *tty, struct file *file) -{ - struct dgnc_board *bd; - struct channel_t *ch; - struct un_t *un; - unsigned long flags; - - if (!tty) - return; - - un = tty->driver_data; - if (!un) - return; - - ch = un->un_ch; - if (!ch) - return; - - bd = ch->ch_bd; - if (!bd) - return; - - spin_lock_irqsave(&ch->ch_lock, flags); - - /* - * Determine if this is the last close or not - and if we agree about - * which type of close it is with the Line Discipline - */ - if ((tty->count == 1) && (un->un_open_count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. un_open_count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - dev_dbg(tty->dev, - "tty->count is 1, un open count is %d\n", - un->un_open_count); - un->un_open_count = 1; - } - - if (un->un_open_count) - un->un_open_count--; - else - dev_dbg(tty->dev, - "bad serial port open count of %d\n", - un->un_open_count); - - ch->ch_open_count--; - - if (ch->ch_open_count && un->un_open_count) { - spin_unlock_irqrestore(&ch->ch_lock, flags); - return; - } - - /* OK, its the last close on the unit */ - un->un_flags |= UN_CLOSING; - - tty->closing = 1; - - /* - * Only officially close channel if count is 0 and - * DIGI_PRINTER bit is not set. - */ - if ((ch->ch_open_count == 0) && - !(ch->ch_digi.digi_flags & DIGI_PRINTER)) { - ch->ch_flags &= ~(CH_STOPI | CH_FORCED_STOPI); - - /* turn off print device when closing print device. */ - - if ((un->un_type == DGNC_PRINT) && (ch->ch_flags & CH_PRON)) { - dgnc_wmove(ch, ch->ch_digi.digi_offstr, - (int)ch->ch_digi.digi_offlen); - ch->ch_flags &= ~CH_PRON; - } - - spin_unlock_irqrestore(&ch->ch_lock, flags); - /* wait for output to drain */ - /* This will also return if we take an interrupt */ - - bd->bd_ops->drain(tty, 0); - - dgnc_tty_flush_buffer(tty); - tty_ldisc_flush(tty); - - spin_lock_irqsave(&ch->ch_lock, flags); - - tty->closing = 0; - - /* If we have HUPCL set, lower DTR and RTS */ - - if (ch->ch_c_cflag & HUPCL) { - /* Drop RTS/DTR */ - ch->ch_mostat &= ~(UART_MCR_DTR | UART_MCR_RTS); - bd->bd_ops->assert_modem_signals(ch); - - /* - * Go to sleep to ensure RTS/DTR - * have been dropped for modems to see it. - */ - if (ch->ch_close_delay) { - spin_unlock_irqrestore(&ch->ch_lock, - flags); - msleep_interruptible(ch->ch_close_delay); - spin_lock_irqsave(&ch->ch_lock, flags); - } - } - - ch->ch_old_baud = 0; - - /* Turn off UART interrupts for this port */ - ch->ch_bd->bd_ops->uart_off(ch); - } else { - /* turn off print device when closing print device. */ - - if ((un->un_type == DGNC_PRINT) && (ch->ch_flags & CH_PRON)) { - dgnc_wmove(ch, ch->ch_digi.digi_offstr, - (int)ch->ch_digi.digi_offlen); - ch->ch_flags &= ~CH_PRON; - } - } - - un->un_tty = NULL; - un->un_flags &= ~(UN_ISOPEN | UN_CLOSING); - - wake_up_interruptible(&ch->ch_flags_wait); - wake_up_interruptible(&un->un_flags_wait); - - spin_unlock_irqrestore(&ch->ch_lock, flags); -} - -/* - * Return number of characters that have not been transmitted yet. - * - * This routine is used by the line discipline to determine if there - * is data waiting to be transmitted/drained/flushed or not. - */ -static int dgnc_tty_chars_in_buffer(struct tty_struct *tty) -{ - struct channel_t *ch = NULL; - struct un_t *un = NULL; - ushort thead; - ushort ttail; - uint tmask; - uint chars; - unsigned long flags; - - if (!tty) - return 0; - - un = tty->driver_data; - if (!un) - return 0; - - ch = un->un_ch; - if (!ch) - return 0; - - spin_lock_irqsave(&ch->ch_lock, flags); - - tmask = WQUEUEMASK; - thead = ch->ch_w_head & tmask; - ttail = ch->ch_w_tail & tmask; - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - if (ttail == thead) - chars = 0; - else if (thead > ttail) - chars = thead - ttail; - else - chars = thead - ttail + WQUEUESIZE; - - return chars; -} - -/* - * Reduces bytes_available to the max number of characters - * that can be sent currently given the maxcps value, and - * returns the new bytes_available. This only affects printer - * output. - */ -static int dgnc_maxcps_room(struct channel_t *ch, int bytes_available) -{ - int rc = bytes_available; - - if (ch->ch_digi.digi_maxcps > 0 && ch->ch_digi.digi_bufsize > 0) { - int cps_limit = 0; - unsigned long current_time = jiffies; - unsigned long buffer_time = current_time + - (HZ * ch->ch_digi.digi_bufsize) / - ch->ch_digi.digi_maxcps; - - if (ch->ch_cpstime < current_time) { - /* buffer is empty */ - ch->ch_cpstime = current_time; /* reset ch_cpstime */ - cps_limit = ch->ch_digi.digi_bufsize; - } else if (ch->ch_cpstime < buffer_time) { - /* still room in the buffer */ - cps_limit = ((buffer_time - ch->ch_cpstime) * - ch->ch_digi.digi_maxcps) / HZ; - } else { - /* no room in the buffer */ - cps_limit = 0; - } - - rc = min(cps_limit, bytes_available); - } - - return rc; -} - -/* Return room available in Tx buffer */ -static int dgnc_tty_write_room(struct tty_struct *tty) -{ - struct channel_t *ch = NULL; - struct un_t *un = NULL; - ushort head; - ushort tail; - ushort tmask; - int room = 0; - unsigned long flags; - - if (!tty) - return 0; - - un = tty->driver_data; - if (!un) - return 0; - - ch = un->un_ch; - if (!ch) - return 0; - - spin_lock_irqsave(&ch->ch_lock, flags); - - tmask = WQUEUEMASK; - head = (ch->ch_w_head) & tmask; - tail = (ch->ch_w_tail) & tmask; - - room = tail - head - 1; - if (room < 0) - room += WQUEUESIZE; - - /* Limit printer to maxcps */ - if (un->un_type != DGNC_PRINT) - room = dgnc_maxcps_room(ch, room); - - /* - * If we are printer device, leave room for - * possibly both the on and off strings. - */ - if (un->un_type == DGNC_PRINT) { - if (!(ch->ch_flags & CH_PRON)) - room -= ch->ch_digi.digi_onlen; - room -= ch->ch_digi.digi_offlen; - } else { - if (ch->ch_flags & CH_PRON) - room -= ch->ch_digi.digi_offlen; - } - - if (room < 0) - room = 0; - - spin_unlock_irqrestore(&ch->ch_lock, flags); - return room; -} - -/* - * Put a character into ch->ch_buf - * Used by the line discipline for OPOST processing - */ -static int dgnc_tty_put_char(struct tty_struct *tty, unsigned char c) -{ - dgnc_tty_write(tty, &c, 1); - return 1; -} - -/* - * Take data from the user or kernel and send it out to the FEP. - * In here exists all the Transparent Print magic as well. - */ -static int dgnc_tty_write(struct tty_struct *tty, - const unsigned char *buf, int count) -{ - struct channel_t *ch = NULL; - struct un_t *un = NULL; - int bufcount = 0, n = 0; - unsigned long flags; - ushort head; - ushort tail; - ushort tmask; - uint remain; - - if (!tty) - return 0; - - un = tty->driver_data; - if (!un) - return 0; - - ch = un->un_ch; - if (!ch) - return 0; - - if (!count) - return 0; - - /* - * Store original amount of characters passed in. - * This helps to figure out if we should ask the FEP - * to send us an event when it has more space available. - */ - - spin_lock_irqsave(&ch->ch_lock, flags); - - tmask = WQUEUEMASK; - head = (ch->ch_w_head) & tmask; - tail = (ch->ch_w_tail) & tmask; - - bufcount = tail - head - 1; - if (bufcount < 0) - bufcount += WQUEUESIZE; - - /* - * Limit printer output to maxcps overall, with bursts allowed - * up to bufsize characters. - */ - if (un->un_type != DGNC_PRINT) - bufcount = dgnc_maxcps_room(ch, bufcount); - - count = min(count, bufcount); - if (count <= 0) - goto exit_retry; - - /* - * Output the printer ON string, if we are in terminal mode, but - * need to be in printer mode. - */ - if ((un->un_type == DGNC_PRINT) && !(ch->ch_flags & CH_PRON)) { - dgnc_wmove(ch, ch->ch_digi.digi_onstr, - (int)ch->ch_digi.digi_onlen); - head = (ch->ch_w_head) & tmask; - ch->ch_flags |= CH_PRON; - } - - /* - * On the other hand, output the printer OFF string, if we are - * currently in printer mode, but need to output to the terminal. - */ - if ((un->un_type != DGNC_PRINT) && (ch->ch_flags & CH_PRON)) { - dgnc_wmove(ch, ch->ch_digi.digi_offstr, - (int)ch->ch_digi.digi_offlen); - head = (ch->ch_w_head) & tmask; - ch->ch_flags &= ~CH_PRON; - } - - n = count; - - /* - * If the write wraps over the top of the circular buffer, - * move the portion up to the wrap point, and reset the - * pointers to the bottom. - */ - remain = WQUEUESIZE - head; - - if (n >= remain) { - n -= remain; - memcpy(ch->ch_wqueue + head, buf, remain); - head = 0; - buf += remain; - } - - if (n > 0) { - /* Move rest of data. */ - remain = n; - memcpy(ch->ch_wqueue + head, buf, remain); - head += remain; - } - - if (count) { - head &= tmask; - ch->ch_w_head = head; - } - - /* Update printer buffer empty time. */ - if ((un->un_type == DGNC_PRINT) && (ch->ch_digi.digi_maxcps > 0) && - (ch->ch_digi.digi_bufsize > 0)) { - ch->ch_cpstime += (HZ * count) / ch->ch_digi.digi_maxcps; - } - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - if (count) - ch->ch_bd->bd_ops->copy_data_from_queue_to_uart(ch); - - return count; - -exit_retry: - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return 0; -} - -/* Return modem signals to ld. */ -static int dgnc_tty_tiocmget(struct tty_struct *tty) -{ - struct channel_t *ch; - struct un_t *un; - int rc; - unsigned char mstat = 0; - unsigned long flags; - - if (!tty) - return -EIO; - - un = tty->driver_data; - if (!un) - return -EIO; - - ch = un->un_ch; - if (!ch) - return -EIO; - - spin_lock_irqsave(&ch->ch_lock, flags); - - mstat = ch->ch_mostat | ch->ch_mistat; - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - rc = 0; - - if (mstat & UART_MCR_DTR) - rc |= TIOCM_DTR; - if (mstat & UART_MCR_RTS) - rc |= TIOCM_RTS; - if (mstat & UART_MSR_CTS) - rc |= TIOCM_CTS; - if (mstat & UART_MSR_DSR) - rc |= TIOCM_DSR; - if (mstat & UART_MSR_RI) - rc |= TIOCM_RI; - if (mstat & UART_MSR_DCD) - rc |= TIOCM_CD; - - return rc; -} - -/* Set modem signals, called by ld. */ -static int dgnc_tty_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct dgnc_board *bd; - struct channel_t *ch; - struct un_t *un; - unsigned long flags; - - if (!tty) - return -EIO; - - un = tty->driver_data; - if (!un) - return -EIO; - - ch = un->un_ch; - if (!ch) - return -EIO; - - bd = ch->ch_bd; - if (!bd) - return -EIO; - - spin_lock_irqsave(&ch->ch_lock, flags); - - if (set & TIOCM_RTS) - ch->ch_mostat |= UART_MCR_RTS; - - if (set & TIOCM_DTR) - ch->ch_mostat |= UART_MCR_DTR; - - if (clear & TIOCM_RTS) - ch->ch_mostat &= ~(UART_MCR_RTS); - - if (clear & TIOCM_DTR) - ch->ch_mostat &= ~(UART_MCR_DTR); - - bd->bd_ops->assert_modem_signals(ch); - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return 0; -} - -/* Send a Break, called by ld. */ -static int dgnc_tty_send_break(struct tty_struct *tty, int msec) -{ - struct dgnc_board *bd; - struct channel_t *ch; - struct un_t *un; - unsigned long flags; - - if (!tty) - return -EIO; - - un = tty->driver_data; - if (!un) - return -EIO; - - ch = un->un_ch; - if (!ch) - return -EIO; - - bd = ch->ch_bd; - if (!bd) - return -EIO; - - if (msec < 0) - msec = 0xFFFF; - - spin_lock_irqsave(&ch->ch_lock, flags); - - bd->bd_ops->send_break(ch, msec); - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return 0; -} - -/* wait until data has been transmitted, called by ld. */ -static void dgnc_tty_wait_until_sent(struct tty_struct *tty, int timeout) -{ - struct dgnc_board *bd; - struct channel_t *ch; - struct un_t *un; - - if (!tty) - return; - - un = tty->driver_data; - if (!un) - return; - - ch = un->un_ch; - if (!ch) - return; - - bd = ch->ch_bd; - if (!bd) - return; - - bd->bd_ops->drain(tty, 0); -} - -/* send a high priority character, called by ld. */ -static void dgnc_tty_send_xchar(struct tty_struct *tty, char c) -{ - struct dgnc_board *bd; - struct channel_t *ch; - struct un_t *un; - unsigned long flags; - - if (!tty) - return; - - un = tty->driver_data; - if (!un) - return; - - ch = un->un_ch; - if (!ch) - return; - - bd = ch->ch_bd; - if (!bd) - return; - - spin_lock_irqsave(&ch->ch_lock, flags); - bd->bd_ops->send_immediate_char(ch, c); - spin_unlock_irqrestore(&ch->ch_lock, flags); -} - -/* Return modem signals to ld. */ -static inline int dgnc_get_mstat(struct channel_t *ch) -{ - unsigned char mstat; - unsigned long flags; - int rc; - - if (!ch) - return -ENXIO; - - spin_lock_irqsave(&ch->ch_lock, flags); - - mstat = ch->ch_mostat | ch->ch_mistat; - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - rc = 0; - - if (mstat & UART_MCR_DTR) - rc |= TIOCM_DTR; - if (mstat & UART_MCR_RTS) - rc |= TIOCM_RTS; - if (mstat & UART_MSR_CTS) - rc |= TIOCM_CTS; - if (mstat & UART_MSR_DSR) - rc |= TIOCM_DSR; - if (mstat & UART_MSR_RI) - rc |= TIOCM_RI; - if (mstat & UART_MSR_DCD) - rc |= TIOCM_CD; - - return rc; -} - -/* Return modem signals to ld. */ -static int dgnc_get_modem_info(struct channel_t *ch, - unsigned int __user *value) -{ - return put_user(dgnc_get_mstat(ch), value); -} - -/* Set modem signals, called by ld. */ -static int dgnc_set_modem_info(struct channel_t *ch, - unsigned int command, - unsigned int __user *value) -{ - int rc; - unsigned int arg = 0; - unsigned long flags; - - rc = get_user(arg, value); - if (rc) - return rc; - - switch (command) { - case TIOCMBIS: - if (arg & TIOCM_RTS) - ch->ch_mostat |= UART_MCR_RTS; - - if (arg & TIOCM_DTR) - ch->ch_mostat |= UART_MCR_DTR; - - break; - - case TIOCMBIC: - if (arg & TIOCM_RTS) - ch->ch_mostat &= ~(UART_MCR_RTS); - - if (arg & TIOCM_DTR) - ch->ch_mostat &= ~(UART_MCR_DTR); - - break; - - case TIOCMSET: - - if (arg & TIOCM_RTS) - ch->ch_mostat |= UART_MCR_RTS; - else - ch->ch_mostat &= ~(UART_MCR_RTS); - - if (arg & TIOCM_DTR) - ch->ch_mostat |= UART_MCR_DTR; - else - ch->ch_mostat &= ~(UART_MCR_DTR); - - break; - - default: - return -EINVAL; - } - - spin_lock_irqsave(&ch->ch_lock, flags); - - ch->ch_bd->bd_ops->assert_modem_signals(ch); - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return 0; -} - -/* Ioctl to get the information for ditty. */ -static int dgnc_tty_digigeta(struct tty_struct *tty, - struct digi_t __user *retinfo) -{ - struct channel_t *ch; - struct un_t *un; - struct digi_t tmp; - unsigned long flags; - - if (!retinfo) - return -EFAULT; - - if (!tty) - return -EFAULT; - - un = tty->driver_data; - if (!un) - return -EFAULT; - - ch = un->un_ch; - if (!ch) - return -EFAULT; - - memset(&tmp, 0, sizeof(tmp)); - - spin_lock_irqsave(&ch->ch_lock, flags); - memcpy(&tmp, &ch->ch_digi, sizeof(tmp)); - spin_unlock_irqrestore(&ch->ch_lock, flags); - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - - return 0; -} - -/* Ioctl to set the information for ditty. */ -static int dgnc_tty_digiseta(struct tty_struct *tty, - struct digi_t __user *new_info) -{ - struct dgnc_board *bd; - struct channel_t *ch; - struct un_t *un; - struct digi_t new_digi; - unsigned long flags; - - if (!tty) - return -EFAULT; - - un = tty->driver_data; - if (!un) - return -EFAULT; - - ch = un->un_ch; - if (!ch) - return -EFAULT; - - bd = ch->ch_bd; - if (!bd) - return -EFAULT; - - if (copy_from_user(&new_digi, new_info, sizeof(new_digi))) - return -EFAULT; - - spin_lock_irqsave(&ch->ch_lock, flags); - - /* Handle transitions to and from RTS Toggle. */ - - if (!(ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) && - (new_digi.digi_flags & DIGI_RTS_TOGGLE)) - ch->ch_mostat &= ~(UART_MCR_RTS); - if ((ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) && - !(new_digi.digi_flags & DIGI_RTS_TOGGLE)) - ch->ch_mostat |= (UART_MCR_RTS); - - /* Handle transitions to and from DTR Toggle. */ - - if (!(ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) && - (new_digi.digi_flags & DIGI_DTR_TOGGLE)) - ch->ch_mostat &= ~(UART_MCR_DTR); - if ((ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) && - !(new_digi.digi_flags & DIGI_DTR_TOGGLE)) - ch->ch_mostat |= (UART_MCR_DTR); - - memcpy(&ch->ch_digi, &new_digi, sizeof(new_digi)); - - if (ch->ch_digi.digi_maxcps < 1) - ch->ch_digi.digi_maxcps = 1; - - if (ch->ch_digi.digi_maxcps > 10000) - ch->ch_digi.digi_maxcps = 10000; - - if (ch->ch_digi.digi_bufsize < 10) - ch->ch_digi.digi_bufsize = 10; - - if (ch->ch_digi.digi_maxchar < 1) - ch->ch_digi.digi_maxchar = 1; - - if (ch->ch_digi.digi_maxchar > ch->ch_digi.digi_bufsize) - ch->ch_digi.digi_maxchar = ch->ch_digi.digi_bufsize; - - if (ch->ch_digi.digi_onlen > DIGI_PLEN) - ch->ch_digi.digi_onlen = DIGI_PLEN; - - if (ch->ch_digi.digi_offlen > DIGI_PLEN) - ch->ch_digi.digi_offlen = DIGI_PLEN; - - bd->bd_ops->param(tty); - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return 0; -} - -static void dgnc_tty_set_termios(struct tty_struct *tty, - struct ktermios *old_termios) -{ - struct dgnc_board *bd; - struct channel_t *ch; - struct un_t *un; - unsigned long flags; - - if (!tty) - return; - - un = tty->driver_data; - if (!un) - return; - - ch = un->un_ch; - if (!ch) - return; - - bd = ch->ch_bd; - if (!bd) - return; - - spin_lock_irqsave(&ch->ch_lock, flags); - - ch->ch_c_cflag = tty->termios.c_cflag; - ch->ch_c_iflag = tty->termios.c_iflag; - ch->ch_c_oflag = tty->termios.c_oflag; - ch->ch_c_lflag = tty->termios.c_lflag; - ch->ch_startc = tty->termios.c_cc[VSTART]; - ch->ch_stopc = tty->termios.c_cc[VSTOP]; - - bd->bd_ops->param(tty); - dgnc_carrier(ch); - - spin_unlock_irqrestore(&ch->ch_lock, flags); -} - -static void dgnc_tty_throttle(struct tty_struct *tty) -{ - struct channel_t *ch; - struct un_t *un; - unsigned long flags; - - if (!tty) - return; - - un = tty->driver_data; - if (!un) - return; - - ch = un->un_ch; - if (!ch) - return; - - spin_lock_irqsave(&ch->ch_lock, flags); - - ch->ch_flags |= (CH_FORCED_STOPI); - - spin_unlock_irqrestore(&ch->ch_lock, flags); -} - -static void dgnc_tty_unthrottle(struct tty_struct *tty) -{ - struct channel_t *ch; - struct un_t *un; - unsigned long flags; - - if (!tty) - return; - - un = tty->driver_data; - if (!un) - return; - - ch = un->un_ch; - if (!ch) - return; - - spin_lock_irqsave(&ch->ch_lock, flags); - - ch->ch_flags &= ~(CH_FORCED_STOPI); - - spin_unlock_irqrestore(&ch->ch_lock, flags); -} - -static void dgnc_tty_start(struct tty_struct *tty) -{ - struct dgnc_board *bd; - struct channel_t *ch; - struct un_t *un; - unsigned long flags; - - if (!tty) - return; - - un = tty->driver_data; - if (!un) - return; - - ch = un->un_ch; - if (!ch) - return; - - bd = ch->ch_bd; - if (!bd) - return; - - spin_lock_irqsave(&ch->ch_lock, flags); - - ch->ch_flags &= ~(CH_FORCED_STOP); - - spin_unlock_irqrestore(&ch->ch_lock, flags); -} - -static void dgnc_tty_stop(struct tty_struct *tty) -{ - struct dgnc_board *bd; - struct channel_t *ch; - struct un_t *un; - unsigned long flags; - - if (!tty) - return; - - un = tty->driver_data; - if (!un) - return; - - ch = un->un_ch; - if (!ch) - return; - - bd = ch->ch_bd; - if (!bd) - return; - - spin_lock_irqsave(&ch->ch_lock, flags); - - ch->ch_flags |= (CH_FORCED_STOP); - - spin_unlock_irqrestore(&ch->ch_lock, flags); -} - -/* - * Flush the cook buffer - * - * Note to self, and any other poor souls who venture here: - * - * flush in this case DOES NOT mean dispose of the data. - * instead, it means "stop buffering and send it if you - * haven't already." Just guess how I figured that out... SRW 2-Jun-98 - * - * It is also always called in interrupt context - JAR 8-Sept-99 - */ -static void dgnc_tty_flush_chars(struct tty_struct *tty) -{ - struct dgnc_board *bd; - struct channel_t *ch; - struct un_t *un; - unsigned long flags; - - if (!tty) - return; - - un = tty->driver_data; - if (!un) - return; - - ch = un->un_ch; - if (!ch) - return; - - bd = ch->ch_bd; - if (!bd) - return; - - spin_lock_irqsave(&ch->ch_lock, flags); - - /* Do something maybe here */ - - spin_unlock_irqrestore(&ch->ch_lock, flags); -} - -/* Flush Tx buffer (make in == out) */ -static void dgnc_tty_flush_buffer(struct tty_struct *tty) -{ - struct channel_t *ch; - struct un_t *un; - unsigned long flags; - - if (!tty) - return; - - un = tty->driver_data; - if (!un) - return; - - ch = un->un_ch; - if (!ch) - return; - - spin_lock_irqsave(&ch->ch_lock, flags); - - ch->ch_flags &= ~CH_STOP; - - /* Flush our write queue */ - ch->ch_w_head = ch->ch_w_tail; - - /* Flush UARTs transmit FIFO */ - ch->ch_bd->bd_ops->flush_uart_write(ch); - - if (ch->ch_tun.un_flags & (UN_LOW | UN_EMPTY)) { - ch->ch_tun.un_flags &= ~(UN_LOW | UN_EMPTY); - wake_up_interruptible(&ch->ch_tun.un_flags_wait); - } - if (ch->ch_pun.un_flags & (UN_LOW | UN_EMPTY)) { - ch->ch_pun.un_flags &= ~(UN_LOW | UN_EMPTY); - wake_up_interruptible(&ch->ch_pun.un_flags_wait); - } - - spin_unlock_irqrestore(&ch->ch_lock, flags); -} - -/* Wakes up processes waiting in the unit's (teminal/printer) wait queue */ -static void dgnc_wake_up_unit(struct un_t *unit) -{ - unit->un_flags &= ~(UN_LOW | UN_EMPTY); - wake_up_interruptible(&unit->un_flags_wait); -} - -/* The IOCTL function and all of its helpers */ - -/* The usual assortment of ioctl's */ -static int dgnc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, - unsigned long arg) -{ - struct dgnc_board *bd; - struct board_ops *ch_bd_ops; - struct channel_t *ch; - struct un_t *un; - int rc; - unsigned long flags; - void __user *uarg = (void __user *)arg; - - if (!tty) - return -ENODEV; - - un = tty->driver_data; - if (!un) - return -ENODEV; - - ch = un->un_ch; - if (!ch) - return -ENODEV; - - bd = ch->ch_bd; - if (!bd) - return -ENODEV; - - ch_bd_ops = bd->bd_ops; - - spin_lock_irqsave(&ch->ch_lock, flags); - - if (un->un_open_count <= 0) { - rc = -EIO; - goto err_unlock; - } - - switch (cmd) { - /* Here are all the standard ioctl's that we MUST implement */ - - case TCSBRK: - /* - * TCSBRK is SVID version: non-zero arg --> no break - * this behaviour is exploited by tcdrain(). - * - * According to POSIX.1 spec (7.2.2.1.2) breaks should be - * between 0.25 and 0.5 seconds so we'll ask for something - * in the middle: 0.375 seconds. - */ - rc = tty_check_change(tty); - spin_unlock_irqrestore(&ch->ch_lock, flags); - if (rc) - return rc; - - rc = ch_bd_ops->drain(tty, 0); - if (rc) - return -EINTR; - - spin_lock_irqsave(&ch->ch_lock, flags); - - if (((cmd == TCSBRK) && (!arg)) || (cmd == TCSBRKP)) - ch_bd_ops->send_break(ch, 250); - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return 0; - - case TCSBRKP: - /* - * support for POSIX tcsendbreak() - * According to POSIX.1 spec (7.2.2.1.2) breaks should be - * between 0.25 and 0.5 seconds so we'll ask for something - * in the middle: 0.375 seconds. - */ - rc = tty_check_change(tty); - spin_unlock_irqrestore(&ch->ch_lock, flags); - if (rc) - return rc; - - rc = ch_bd_ops->drain(tty, 0); - if (rc) - return -EINTR; - - spin_lock_irqsave(&ch->ch_lock, flags); - - ch_bd_ops->send_break(ch, 250); - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return 0; - - case TIOCSBRK: - rc = tty_check_change(tty); - spin_unlock_irqrestore(&ch->ch_lock, flags); - if (rc) - return rc; - - rc = ch_bd_ops->drain(tty, 0); - if (rc) - return -EINTR; - - spin_lock_irqsave(&ch->ch_lock, flags); - - ch_bd_ops->send_break(ch, 250); - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return 0; - - case TIOCCBRK: - /* Do Nothing */ - spin_unlock_irqrestore(&ch->ch_lock, flags); - return 0; - - case TIOCGSOFTCAR: - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return put_user(C_CLOCAL(tty) ? 1 : 0, - (unsigned long __user *)arg); - - case TIOCSSOFTCAR: - - spin_unlock_irqrestore(&ch->ch_lock, flags); - rc = get_user(arg, (unsigned long __user *)arg); - if (rc) - return rc; - - spin_lock_irqsave(&ch->ch_lock, flags); - tty->termios.c_cflag = ((tty->termios.c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - ch_bd_ops->param(tty); - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return 0; - - case TIOCMGET: - spin_unlock_irqrestore(&ch->ch_lock, flags); - return dgnc_get_modem_info(ch, uarg); - - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - spin_unlock_irqrestore(&ch->ch_lock, flags); - return dgnc_set_modem_info(ch, cmd, uarg); - - /* Here are any additional ioctl's that we want to implement */ - - case TCFLSH: - /* - * The linux tty driver doesn't have a flush - * input routine for the driver, assuming all backed - * up data is in the line disc. buffers. However, - * we all know that's not the case. Here, we - * act on the ioctl, but then lie and say we didn't - * so the line discipline will process the flush - * also. - */ - rc = tty_check_change(tty); - if (rc) - goto err_unlock; - - if ((arg == TCIFLUSH) || (arg == TCIOFLUSH)) { - ch->ch_r_head = ch->ch_r_tail; - ch_bd_ops->flush_uart_read(ch); - /* Force queue flow control to be released, if needed */ - dgnc_check_queue_flow_control(ch); - } - - if ((arg == TCOFLUSH) || (arg == TCIOFLUSH)) { - if (!(un->un_type == DGNC_PRINT)) { - ch->ch_w_head = ch->ch_w_tail; - ch_bd_ops->flush_uart_write(ch); - - if (ch->ch_tun.un_flags & (UN_LOW | UN_EMPTY)) - dgnc_wake_up_unit(&ch->ch_tun); - - if (ch->ch_pun.un_flags & (UN_LOW | UN_EMPTY)) - dgnc_wake_up_unit(&ch->ch_pun); - } - } - - /* pretend we didn't recognize this IOCTL */ - spin_unlock_irqrestore(&ch->ch_lock, flags); - return -ENOIOCTLCMD; - case TCSETSF: - case TCSETSW: - /* - * The linux tty driver doesn't have a flush - * input routine for the driver, assuming all backed - * up data is in the line disc. buffers. However, - * we all know that's not the case. Here, we - * act on the ioctl, but then lie and say we didn't - * so the line discipline will process the flush - * also. - */ - if (cmd == TCSETSF) { - /* flush rx */ - ch->ch_flags &= ~CH_STOP; - ch->ch_r_head = ch->ch_r_tail; - ch_bd_ops->flush_uart_read(ch); - /* Force queue flow control to be released, if needed */ - dgnc_check_queue_flow_control(ch); - } - - /* now wait for all the output to drain */ - spin_unlock_irqrestore(&ch->ch_lock, flags); - rc = ch_bd_ops->drain(tty, 0); - if (rc) - return -EINTR; - - /* pretend we didn't recognize this */ - return -ENOIOCTLCMD; - - case TCSETAW: - - spin_unlock_irqrestore(&ch->ch_lock, flags); - rc = ch_bd_ops->drain(tty, 0); - if (rc) - return -EINTR; - - /* pretend we didn't recognize this */ - return -ENOIOCTLCMD; - - case TCXONC: - spin_unlock_irqrestore(&ch->ch_lock, flags); - /* Make the ld do it */ - return -ENOIOCTLCMD; - - case DIGI_GETA: - /* get information for ditty */ - spin_unlock_irqrestore(&ch->ch_lock, flags); - return dgnc_tty_digigeta(tty, uarg); - - case DIGI_SETAW: - case DIGI_SETAF: - - /* set information for ditty */ - if (cmd == (DIGI_SETAW)) { - spin_unlock_irqrestore(&ch->ch_lock, flags); - rc = ch_bd_ops->drain(tty, 0); - if (rc) - return -EINTR; - - spin_lock_irqsave(&ch->ch_lock, flags); - } else { - tty_ldisc_flush(tty); - } - /* fall thru */ - - case DIGI_SETA: - spin_unlock_irqrestore(&ch->ch_lock, flags); - return dgnc_tty_digiseta(tty, uarg); - - case DIGI_LOOPBACK: - { - uint loopback = 0; - /* - * Let go of locks when accessing user space, - * could sleep - */ - spin_unlock_irqrestore(&ch->ch_lock, flags); - rc = get_user(loopback, (unsigned int __user *)arg); - if (rc) - return rc; - spin_lock_irqsave(&ch->ch_lock, flags); - - /* Enable/disable internal loopback for this port */ - if (loopback) - ch->ch_flags |= CH_LOOPBACK; - else - ch->ch_flags &= ~(CH_LOOPBACK); - - ch_bd_ops->param(tty); - spin_unlock_irqrestore(&ch->ch_lock, flags); - return 0; - } - - case DIGI_GETCUSTOMBAUD: - spin_unlock_irqrestore(&ch->ch_lock, flags); - return put_user(ch->ch_custom_speed, - (unsigned int __user *)arg); - - case DIGI_SETCUSTOMBAUD: - { - int new_rate; - - spin_unlock_irqrestore(&ch->ch_lock, flags); - rc = get_user(new_rate, (int __user *)arg); - if (rc) - return rc; - spin_lock_irqsave(&ch->ch_lock, flags); - dgnc_set_custom_speed(ch, new_rate); - ch_bd_ops->param(tty); - spin_unlock_irqrestore(&ch->ch_lock, flags); - return 0; - } - - /* - * This ioctl allows insertion of a character into the front - * of any pending data to be transmitted. - * - * This ioctl is to satisfy the "Send Character Immediate" - * call that the RealPort protocol spec requires. - */ - case DIGI_REALPORT_SENDIMMEDIATE: - { - unsigned char c; - - spin_unlock_irqrestore(&ch->ch_lock, flags); - rc = get_user(c, (unsigned char __user *)arg); - if (rc) - return rc; - spin_lock_irqsave(&ch->ch_lock, flags); - ch_bd_ops->send_immediate_char(ch, c); - spin_unlock_irqrestore(&ch->ch_lock, flags); - return 0; - } - - /* - * This ioctl returns all the current counts for the port. - * - * This ioctl is to satisfy the "Line Error Counters" - * call that the RealPort protocol spec requires. - */ - case DIGI_REALPORT_GETCOUNTERS: - { - struct digi_getcounter buf; - - buf.norun = ch->ch_err_overrun; - buf.noflow = 0; /* The driver doesn't keep this stat */ - buf.nframe = ch->ch_err_frame; - buf.nparity = ch->ch_err_parity; - buf.nbreak = ch->ch_err_break; - buf.rbytes = ch->ch_rxcount; - buf.tbytes = ch->ch_txcount; - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - if (copy_to_user(uarg, &buf, sizeof(buf))) - return -EFAULT; - - return 0; - } - - /* - * This ioctl returns all current events. - * - * This ioctl is to satisfy the "Event Reporting" - * call that the RealPort protocol spec requires. - */ - case DIGI_REALPORT_GETEVENTS: - { - unsigned int events = 0; - - /* NOTE: MORE EVENTS NEEDS TO BE ADDED HERE */ - if (ch->ch_flags & CH_BREAK_SENDING) - events |= EV_TXB; - if ((ch->ch_flags & CH_STOP) || - (ch->ch_flags & CH_FORCED_STOP)) - events |= (EV_OPU | EV_OPS); - - if ((ch->ch_flags & CH_STOPI) || - (ch->ch_flags & CH_FORCED_STOPI)) - events |= (EV_IPU | EV_IPS); - - spin_unlock_irqrestore(&ch->ch_lock, flags); - return put_user(events, (unsigned int __user *)arg); - } - - /* - * This ioctl returns TOUT and TIN counters based - * upon the values passed in by the RealPort Server. - * It also passes back whether the UART Transmitter is - * empty as well. - */ - case DIGI_REALPORT_GETBUFFERS: - { - struct digi_getbuffer buf; - int tdist; - int count; - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - if (copy_from_user(&buf, uarg, sizeof(buf))) - return -EFAULT; - - spin_lock_irqsave(&ch->ch_lock, flags); - - /* Figure out how much data is in our RX and TX queues. */ - - buf.rxbuf = (ch->ch_r_head - ch->ch_r_tail) & RQUEUEMASK; - buf.txbuf = (ch->ch_w_head - ch->ch_w_tail) & WQUEUEMASK; - - /* - * Is the UART empty? - * Add that value to whats in our TX queue. - */ - - count = buf.txbuf + ch_bd_ops->get_uart_bytes_left(ch); - - /* - * Figure out how much data the RealPort Server believes should - * be in our TX queue. - */ - tdist = (buf.tx_in - buf.tx_out) & 0xffff; - - /* - * If we have more data than the RealPort Server believes we - * should have, reduce our count to its amount. - * - * This count difference CAN happen because the Linux LD can - * insert more characters into our queue for OPOST processing - * that the RealPort Server doesn't know about. - */ - if (buf.txbuf > tdist) - buf.txbuf = tdist; - - /* Report whether our queue and UART TX are completely empty. */ - - if (count) - buf.txdone = 0; - else - buf.txdone = 1; - - spin_unlock_irqrestore(&ch->ch_lock, flags); - - if (copy_to_user(uarg, &buf, sizeof(buf))) - return -EFAULT; - - return 0; - } - default: - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return -ENOIOCTLCMD; - } -err_unlock: - spin_unlock_irqrestore(&ch->ch_lock, flags); - - return rc; -} diff --git a/drivers/staging/dgnc/dgnc_tty.h b/drivers/staging/dgnc/dgnc_tty.h deleted file mode 100644 index 00e31035b83d..000000000000 --- a/drivers/staging/dgnc/dgnc_tty.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - */ - -#ifndef _DGNC_TTY_H -#define _DGNC_TTY_H - -#include "dgnc_driver.h" - -int dgnc_tty_register(struct dgnc_board *brd); -void dgnc_tty_unregister(struct dgnc_board *brd); - -int dgnc_tty_init(struct dgnc_board *brd); - -void dgnc_cleanup_tty(struct dgnc_board *brd); - -void dgnc_input(struct channel_t *ch); -void dgnc_carrier(struct channel_t *ch); -void dgnc_wakeup_writes(struct channel_t *ch); -void dgnc_check_queue_flow_control(struct channel_t *ch); - -#endif /* _DGNC_TTY_H */ diff --git a/drivers/staging/dgnc/digi.h b/drivers/staging/dgnc/digi.h deleted file mode 100644 index b414ee80db88..000000000000 --- a/drivers/staging/dgnc/digi.h +++ /dev/null @@ -1,128 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - */ - -#ifndef _DIGI_H -#define _DIGI_H - -#define DIGI_GETA (('e' << 8) | 94) /* Read params */ -#define DIGI_SETA (('e' << 8) | 95) /* Set params */ -#define DIGI_SETAW (('e' << 8) | 96) /* Drain & set params */ -#define DIGI_SETAF (('e' << 8) | 97) /* Drain, flush & set params */ -#define DIGI_LOOPBACK (('d' << 8) | 252) /* Enable/disable UART - * internal loopback - */ -#define DIGI_FAST 0x0002 /* Fast baud rates */ -#define RTSPACE 0x0004 /* RTS input flow control */ -#define CTSPACE 0x0008 /* CTS output flow control */ -#define DIGI_COOK 0x0080 /* Cooked processing done in FEP */ -#define DIGI_FORCEDCD 0x0100 /* Force carrier */ -#define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */ -#define DIGI_PRINTER 0x0800 /* Hold port open for flow cntrl*/ -#define DIGI_DTR_TOGGLE 0x2000 /* Support DTR Toggle */ -#define DIGI_RTS_TOGGLE 0x8000 /* Support RTS Toggle */ -#define DIGI_PLEN 28 /* String length */ -#define DIGI_TSIZ 10 /* Terminal string len */ - -/* - * Structure used with ioctl commands for DIGI parameters. - */ -/** - * struct digi_t - Ioctl commands for DIGI parameters. - * @digi_flags: Flags. - * @digi_maxcps: Maximum printer CPS. - * @digi_maxchar: Maximum characters in the print queue. - * @digi_bufsize: Buffer size. - * @digi_onlen: Length of ON string. - * @digi_offlen: Length of OFF string. - * @digi_onstr: Printer ON string. - * @digi_offstr: Printer OFF string. - * @digi_term: Terminal string. - */ -struct digi_t { - unsigned short digi_flags; - unsigned short digi_maxcps; - unsigned short digi_maxchar; - unsigned short digi_bufsize; - unsigned char digi_onlen; - unsigned char digi_offlen; - char digi_onstr[DIGI_PLEN]; - char digi_offstr[DIGI_PLEN]; - char digi_term[DIGI_TSIZ]; -}; - -/** - * struct digi_getbuffer - Holds buffer use counts. - */ -struct digi_getbuffer { - unsigned long tx_in; - unsigned long tx_out; - unsigned long rxbuf; - unsigned long txbuf; - unsigned long txdone; -}; - -/** - * struct digi_getcounter - * @norun: Number of UART overrun errors. - * @noflow: Number of buffer overflow errors. - * @nframe: Number of framing errors. - * @nparity: Number of parity errors. - * @nbreak: Number of breaks received. - * @rbytes: Number of received bytes. - * @tbytes: Number of transmitted bytes. - */ -struct digi_getcounter { - unsigned long norun; - unsigned long noflow; - unsigned long nframe; - unsigned long nparity; - unsigned long nbreak; - unsigned long rbytes; - unsigned long tbytes; -}; - -#define DIGI_SETCUSTOMBAUD _IOW('e', 106, int) /* Set integer baud rate */ -#define DIGI_GETCUSTOMBAUD _IOR('e', 107, int) /* Get integer baud rate */ - -#define DIGI_REALPORT_GETBUFFERS (('e' << 8) | 108) -#define DIGI_REALPORT_SENDIMMEDIATE (('e' << 8) | 109) -#define DIGI_REALPORT_GETCOUNTERS (('e' << 8) | 110) -#define DIGI_REALPORT_GETEVENTS (('e' << 8) | 111) - -#define EV_OPU 0x0001 /* Output paused by client */ -#define EV_OPS 0x0002 /* Output paused by regular sw flowctrl */ -#define EV_IPU 0x0010 /* Input paused unconditionally by user */ -#define EV_IPS 0x0020 /* Input paused by high/low water marks */ -#define EV_TXB 0x0040 /* Transmit break pending */ - -/** - * struct ni_info - intelligent <--> non-intelligent DPA translation. - */ -struct ni_info { - int board; - int channel; - int dtr; - int rts; - int cts; - int dsr; - int ri; - int dcd; - int curtx; - int currx; - unsigned short iflag; - unsigned short oflag; - unsigned short cflag; - unsigned short lflag; - unsigned int mstat; - unsigned char hflow; - unsigned char xmit_stopped; - unsigned char recv_stopped; - unsigned int baud; -}; - -#define TTY_FLIPBUF_SIZE 512 - -#endif /* _DIGI_H */ |