|
@@ -14,15 +14,15 @@
|
|
*/
|
|
*/
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/kernel.h>
|
|
-#include <linux/sched.h> /* For jiffies, task states */
|
|
|
|
-#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */
|
|
|
|
-#include <linux/delay.h> /* For udelay */
|
|
|
|
-#include <linux/io.h> /* For read[bwl]/write[bwl] */
|
|
|
|
-#include <linux/serial.h> /* For struct async_serial */
|
|
|
|
-#include <linux/serial_reg.h> /* For the various UART offsets */
|
|
|
|
-
|
|
|
|
-#include "dgnc_driver.h" /* Driver main header file */
|
|
|
|
-#include "dgnc_neo.h" /* Our header file */
|
|
|
|
|
|
+#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 "dgnc_driver.h"
|
|
|
|
+#include "dgnc_neo.h"
|
|
#include "dgnc_tty.h"
|
|
#include "dgnc_tty.h"
|
|
|
|
|
|
static inline void neo_parse_lsr(struct dgnc_board *brd, uint port);
|
|
static inline void neo_parse_lsr(struct dgnc_board *brd, uint port);
|
|
@@ -358,20 +358,17 @@ static inline void neo_set_new_start_stop_chars(struct channel_t *ch)
|
|
}
|
|
}
|
|
|
|
|
|
/* No locks are assumed to be held when calling this function. */
|
|
/* No locks are assumed to be held when calling this function. */
|
|
-
|
|
|
|
static inline void neo_clear_break(struct channel_t *ch, int force)
|
|
static inline void neo_clear_break(struct channel_t *ch, int force)
|
|
{
|
|
{
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
|
|
|
|
spin_lock_irqsave(&ch->ch_lock, flags);
|
|
spin_lock_irqsave(&ch->ch_lock, flags);
|
|
|
|
|
|
- /* Bail if we aren't currently sending a break. */
|
|
|
|
if (!ch->ch_stop_sending_break) {
|
|
if (!ch->ch_stop_sending_break) {
|
|
spin_unlock_irqrestore(&ch->ch_lock, flags);
|
|
spin_unlock_irqrestore(&ch->ch_lock, flags);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- /* Turn break off, and unset some variables */
|
|
|
|
if (ch->ch_flags & CH_BREAK_SENDING) {
|
|
if (ch->ch_flags & CH_BREAK_SENDING) {
|
|
if (force ||
|
|
if (force ||
|
|
time_after_eq(jiffies, ch->ch_stop_sending_break)) {
|
|
time_after_eq(jiffies, ch->ch_stop_sending_break)) {
|
|
@@ -387,7 +384,6 @@ static inline void neo_clear_break(struct channel_t *ch, int force)
|
|
}
|
|
}
|
|
|
|
|
|
/* Parse the ISR register. */
|
|
/* Parse the ISR register. */
|
|
-
|
|
|
|
static inline void neo_parse_isr(struct dgnc_board *brd, uint port)
|
|
static inline void neo_parse_isr(struct dgnc_board *brd, uint port)
|
|
{
|
|
{
|
|
struct channel_t *ch;
|
|
struct channel_t *ch;
|
|
@@ -403,7 +399,6 @@ static inline void neo_parse_isr(struct dgnc_board *brd, uint port)
|
|
while (1) {
|
|
while (1) {
|
|
isr = readb(&ch->ch_neo_uart->isr_fcr);
|
|
isr = readb(&ch->ch_neo_uart->isr_fcr);
|
|
|
|
|
|
- /* Bail if no pending interrupt */
|
|
|
|
if (isr & UART_IIR_NO_INT)
|
|
if (isr & UART_IIR_NO_INT)
|
|
break;
|
|
break;
|
|
|
|
|
|
@@ -426,7 +421,6 @@ static inline void neo_parse_isr(struct dgnc_board *brd, uint port)
|
|
}
|
|
}
|
|
|
|
|
|
if (isr & UART_IIR_THRI) {
|
|
if (isr & UART_IIR_THRI) {
|
|
- /* Transfer data (if any) from Write Queue -> UART. */
|
|
|
|
spin_lock_irqsave(&ch->ch_lock, flags);
|
|
spin_lock_irqsave(&ch->ch_lock, flags);
|
|
ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
|
|
ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
|
|
spin_unlock_irqrestore(&ch->ch_lock, flags);
|
|
spin_unlock_irqrestore(&ch->ch_lock, flags);
|
|
@@ -442,10 +436,7 @@ static inline void neo_parse_isr(struct dgnc_board *brd, uint port)
|
|
* one it was, so we can suspend or resume data flow.
|
|
* one it was, so we can suspend or resume data flow.
|
|
*/
|
|
*/
|
|
if (cause == UART_17158_XON_DETECT) {
|
|
if (cause == UART_17158_XON_DETECT) {
|
|
- /*
|
|
|
|
- * Is output stopped right now, if so,
|
|
|
|
- * resume it
|
|
|
|
- */
|
|
|
|
|
|
+ /* resume output if stopped */
|
|
if (brd->channels[port]->ch_flags & CH_STOP) {
|
|
if (brd->channels[port]->ch_flags & CH_STOP) {
|
|
spin_lock_irqsave(&ch->ch_lock,
|
|
spin_lock_irqsave(&ch->ch_lock,
|
|
flags);
|
|
flags);
|
|
@@ -504,7 +495,6 @@ static inline void neo_parse_isr(struct dgnc_board *brd, uint port)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- /* Parse any modem signal changes */
|
|
|
|
neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
|
|
neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -515,10 +505,6 @@ static inline void neo_parse_lsr(struct dgnc_board *brd, uint port)
|
|
int linestatus;
|
|
int linestatus;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
|
|
|
|
- /*
|
|
|
|
- * Check to make sure it didn't receive interrupt with a null board
|
|
|
|
- * associated or a board pointer that wasn't ours.
|
|
|
|
- */
|
|
|
|
if (!brd || brd->magic != DGNC_BOARD_MAGIC)
|
|
if (!brd || brd->magic != DGNC_BOARD_MAGIC)
|
|
return;
|
|
return;
|
|
|
|
|
|
@@ -534,7 +520,6 @@ static inline void neo_parse_lsr(struct dgnc_board *brd, uint port)
|
|
ch->ch_cached_lsr |= linestatus;
|
|
ch->ch_cached_lsr |= linestatus;
|
|
|
|
|
|
if (ch->ch_cached_lsr & UART_LSR_DR) {
|
|
if (ch->ch_cached_lsr & UART_LSR_DR) {
|
|
- /* Read data from uart -> queue */
|
|
|
|
neo_copy_data_from_uart_to_queue(ch);
|
|
neo_copy_data_from_uart_to_queue(ch);
|
|
spin_lock_irqsave(&ch->ch_lock, flags);
|
|
spin_lock_irqsave(&ch->ch_lock, flags);
|
|
dgnc_check_queue_flow_control(ch);
|
|
dgnc_check_queue_flow_control(ch);
|
|
@@ -571,22 +556,17 @@ static inline void neo_parse_lsr(struct dgnc_board *brd, uint port)
|
|
ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
|
|
ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
|
|
spin_unlock_irqrestore(&ch->ch_lock, flags);
|
|
spin_unlock_irqrestore(&ch->ch_lock, flags);
|
|
|
|
|
|
- /* Transfer data (if any) from Write Queue -> UART. */
|
|
|
|
neo_copy_data_from_queue_to_uart(ch);
|
|
neo_copy_data_from_queue_to_uart(ch);
|
|
} else if (linestatus & UART_17158_TX_AND_FIFO_CLR) {
|
|
} else if (linestatus & UART_17158_TX_AND_FIFO_CLR) {
|
|
spin_lock_irqsave(&ch->ch_lock, flags);
|
|
spin_lock_irqsave(&ch->ch_lock, flags);
|
|
ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
|
|
ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
|
|
spin_unlock_irqrestore(&ch->ch_lock, flags);
|
|
spin_unlock_irqrestore(&ch->ch_lock, flags);
|
|
|
|
|
|
- /* Transfer data (if any) from Write Queue -> UART. */
|
|
|
|
neo_copy_data_from_queue_to_uart(ch);
|
|
neo_copy_data_from_queue_to_uart(ch);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-/*
|
|
|
|
- * neo_param()
|
|
|
|
- * Send any/all changes to the line to the UART.
|
|
|
|
- */
|
|
|
|
|
|
+/* Send any/all changes to the line to the UART. */
|
|
static void neo_param(struct tty_struct *tty)
|
|
static void neo_param(struct tty_struct *tty)
|
|
{
|
|
{
|
|
unsigned char lcr = 0;
|
|
unsigned char lcr = 0;
|
|
@@ -615,7 +595,6 @@ static void neo_param(struct tty_struct *tty)
|
|
return;
|
|
return;
|
|
|
|
|
|
/* If baud rate is zero, flush queues, and set mval to drop DTR. */
|
|
/* If baud rate is zero, flush queues, and set mval to drop DTR. */
|
|
-
|
|
|
|
if ((ch->ch_c_cflag & (CBAUD)) == 0) {
|
|
if ((ch->ch_c_cflag & (CBAUD)) == 0) {
|
|
ch->ch_r_head = 0;
|
|
ch->ch_r_head = 0;
|
|
ch->ch_r_tail = 0;
|
|
ch->ch_r_tail = 0;
|
|
@@ -724,10 +703,6 @@ static void neo_param(struct tty_struct *tty)
|
|
if (!(ch->ch_c_cflag & PARODD))
|
|
if (!(ch->ch_c_cflag & PARODD))
|
|
lcr |= UART_LCR_EPAR;
|
|
lcr |= UART_LCR_EPAR;
|
|
|
|
|
|
- /*
|
|
|
|
- * Not all platforms support mark/space parity,
|
|
|
|
- * so this will hide behind an ifdef.
|
|
|
|
- */
|
|
|
|
#ifdef CMSPAR
|
|
#ifdef CMSPAR
|
|
if (ch->ch_c_cflag & CMSPAR)
|
|
if (ch->ch_c_cflag & CMSPAR)
|
|
lcr |= UART_LCR_SPAR;
|
|
lcr |= UART_LCR_SPAR;
|
|
@@ -796,16 +771,11 @@ static void neo_param(struct tty_struct *tty)
|
|
if (ier != uart_ier)
|
|
if (ier != uart_ier)
|
|
writeb(ier, &ch->ch_neo_uart->ier);
|
|
writeb(ier, &ch->ch_neo_uart->ier);
|
|
|
|
|
|
- /* Set new start/stop chars */
|
|
|
|
neo_set_new_start_stop_chars(ch);
|
|
neo_set_new_start_stop_chars(ch);
|
|
|
|
|
|
if (ch->ch_digi.digi_flags & CTSPACE || ch->ch_c_cflag & CRTSCTS) {
|
|
if (ch->ch_digi.digi_flags & CTSPACE || ch->ch_c_cflag & CRTSCTS) {
|
|
neo_set_cts_flow_control(ch);
|
|
neo_set_cts_flow_control(ch);
|
|
} else if (ch->ch_c_iflag & IXON) {
|
|
} else if (ch->ch_c_iflag & IXON) {
|
|
- /*
|
|
|
|
- * If start/stop is set to disable, then we should
|
|
|
|
- * disable flow control
|
|
|
|
- */
|
|
|
|
if ((ch->ch_startc == _POSIX_VDISABLE) ||
|
|
if ((ch->ch_startc == _POSIX_VDISABLE) ||
|
|
(ch->ch_stopc == _POSIX_VDISABLE))
|
|
(ch->ch_stopc == _POSIX_VDISABLE))
|
|
neo_set_no_output_flow_control(ch);
|
|
neo_set_no_output_flow_control(ch);
|
|
@@ -818,10 +788,6 @@ static void neo_param(struct tty_struct *tty)
|
|
if (ch->ch_digi.digi_flags & RTSPACE || ch->ch_c_cflag & CRTSCTS) {
|
|
if (ch->ch_digi.digi_flags & RTSPACE || ch->ch_c_cflag & CRTSCTS) {
|
|
neo_set_rts_flow_control(ch);
|
|
neo_set_rts_flow_control(ch);
|
|
} else if (ch->ch_c_iflag & IXOFF) {
|
|
} else if (ch->ch_c_iflag & IXOFF) {
|
|
- /*
|
|
|
|
- * If start/stop is set to disable, then we should
|
|
|
|
- * disable flow control
|
|
|
|
- */
|
|
|
|
if ((ch->ch_startc == _POSIX_VDISABLE) ||
|
|
if ((ch->ch_startc == _POSIX_VDISABLE) ||
|
|
(ch->ch_stopc == _POSIX_VDISABLE))
|
|
(ch->ch_stopc == _POSIX_VDISABLE))
|
|
neo_set_no_input_flow_control(ch);
|
|
neo_set_no_input_flow_control(ch);
|
|
@@ -843,12 +809,10 @@ static void neo_param(struct tty_struct *tty)
|
|
|
|
|
|
neo_assert_modem_signals(ch);
|
|
neo_assert_modem_signals(ch);
|
|
|
|
|
|
- /* Get current status of the modem signals now */
|
|
|
|
neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
|
|
neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
|
|
}
|
|
}
|
|
|
|
|
|
-/* Our board poller function. */
|
|
|
|
-
|
|
|
|
|
|
+/* Board poller function. */
|
|
static void neo_tasklet(unsigned long data)
|
|
static void neo_tasklet(unsigned long data)
|
|
{
|
|
{
|
|
struct dgnc_board *bd = (struct dgnc_board *)data;
|
|
struct dgnc_board *bd = (struct dgnc_board *)data;
|
|
@@ -861,7 +825,6 @@ static void neo_tasklet(unsigned long data)
|
|
if (!bd || bd->magic != DGNC_BOARD_MAGIC)
|
|
if (!bd || bd->magic != DGNC_BOARD_MAGIC)
|
|
return;
|
|
return;
|
|
|
|
|
|
- /* Cache a couple board values */
|
|
|
|
spin_lock_irqsave(&bd->bd_lock, flags);
|
|
spin_lock_irqsave(&bd->bd_lock, flags);
|
|
state = bd->state;
|
|
state = bd->state;
|
|
ports = bd->nasync;
|
|
ports = bd->nasync;
|
|
@@ -873,10 +836,7 @@ static void neo_tasklet(unsigned long data)
|
|
*/
|
|
*/
|
|
spin_lock_irqsave(&bd->bd_intr_lock, flags);
|
|
spin_lock_irqsave(&bd->bd_intr_lock, flags);
|
|
|
|
|
|
- /* If board is ready, parse deeper to see if there is anything to do. */
|
|
|
|
-
|
|
|
|
if ((state == BOARD_READY) && (ports > 0)) {
|
|
if ((state == BOARD_READY) && (ports > 0)) {
|
|
- /* Loop on each port */
|
|
|
|
for (i = 0; i < ports; i++) {
|
|
for (i = 0; i < ports; i++) {
|
|
ch = bd->channels[i];
|
|
ch = bd->channels[i];
|
|
|
|
|
|
@@ -903,10 +863,6 @@ static void neo_tasklet(unsigned long data)
|
|
neo_copy_data_from_queue_to_uart(ch);
|
|
neo_copy_data_from_queue_to_uart(ch);
|
|
dgnc_wakeup_writes(ch);
|
|
dgnc_wakeup_writes(ch);
|
|
|
|
|
|
- /*
|
|
|
|
- * Call carrier carrier function, in case something
|
|
|
|
- * has changed.
|
|
|
|
- */
|
|
|
|
dgnc_carrier(ch);
|
|
dgnc_carrier(ch);
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -918,15 +874,10 @@ static void neo_tasklet(unsigned long data)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- /* Allow interrupt routine to access the interrupt register again */
|
|
|
|
spin_unlock_irqrestore(&bd->bd_intr_lock, flags);
|
|
spin_unlock_irqrestore(&bd->bd_intr_lock, flags);
|
|
}
|
|
}
|
|
|
|
|
|
-/*
|
|
|
|
- * dgnc_neo_intr()
|
|
|
|
- *
|
|
|
|
- * Neo specific interrupt handler.
|
|
|
|
- */
|
|
|
|
|
|
+/* Neo specific interrupt handler. */
|
|
static irqreturn_t neo_intr(int irq, void *voidbrd)
|
|
static irqreturn_t neo_intr(int irq, void *voidbrd)
|
|
{
|
|
{
|
|
struct dgnc_board *brd = voidbrd;
|
|
struct dgnc_board *brd = voidbrd;
|
|
@@ -937,10 +888,6 @@ static irqreturn_t neo_intr(int irq, void *voidbrd)
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
unsigned long flags2;
|
|
unsigned long flags2;
|
|
|
|
|
|
- /*
|
|
|
|
- * Check to make sure it didn't receive interrupt with a null board
|
|
|
|
- * associated or a board pointer that wasn't ours.
|
|
|
|
- */
|
|
|
|
if (!brd || brd->magic != DGNC_BOARD_MAGIC)
|
|
if (!brd || brd->magic != DGNC_BOARD_MAGIC)
|
|
return IRQ_NONE;
|
|
return IRQ_NONE;
|
|
|
|
|
|
@@ -964,19 +911,12 @@ static irqreturn_t neo_intr(int irq, void *voidbrd)
|
|
return IRQ_NONE;
|
|
return IRQ_NONE;
|
|
}
|
|
}
|
|
|
|
|
|
- /*
|
|
|
|
- * At this point, we have at least SOMETHING to service, dig
|
|
|
|
- * further...
|
|
|
|
- */
|
|
|
|
-
|
|
|
|
- /* Loop on each port */
|
|
|
|
while ((uart_poll & 0xff) != 0) {
|
|
while ((uart_poll & 0xff) != 0) {
|
|
type = uart_poll >> (8 + (port * 3));
|
|
type = uart_poll >> (8 + (port * 3));
|
|
type &= 0x7;
|
|
type &= 0x7;
|
|
|
|
|
|
uart_poll &= ~(0x01 << port);
|
|
uart_poll &= ~(0x01 << port);
|
|
|
|
|
|
- /* Switch on type of interrupt we have */
|
|
|
|
switch (type) {
|
|
switch (type) {
|
|
case UART_17158_RXRDY_TIMEOUT:
|
|
case UART_17158_RXRDY_TIMEOUT:
|
|
/*
|
|
/*
|
|
@@ -984,7 +924,6 @@ static irqreturn_t neo_intr(int irq, void *voidbrd)
|
|
* RX FIFO until it falls below the trigger level.
|
|
* RX FIFO until it falls below the trigger level.
|
|
*/
|
|
*/
|
|
|
|
|
|
- /* Verify the port is in range. */
|
|
|
|
if (port >= brd->nasync)
|
|
if (port >= brd->nasync)
|
|
break;
|
|
break;
|
|
|
|
|
|
@@ -1027,27 +966,17 @@ static irqreturn_t neo_intr(int irq, void *voidbrd)
|
|
break;
|
|
break;
|
|
|
|
|
|
case UART_17158_MSR:
|
|
case UART_17158_MSR:
|
|
-
|
|
|
|
/* MSR or flow control was seen. */
|
|
/* MSR or flow control was seen. */
|
|
-
|
|
|
|
neo_parse_isr(brd, port);
|
|
neo_parse_isr(brd, port);
|
|
break;
|
|
break;
|
|
|
|
|
|
default:
|
|
default:
|
|
- /*
|
|
|
|
- * The UART triggered us with a bogus interrupt type.
|
|
|
|
- * It appears the Exar chip, when REALLY bogged down,
|
|
|
|
- * will throw these once and awhile.
|
|
|
|
- * Its harmless, just ignore it and move on.
|
|
|
|
- */
|
|
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
port++;
|
|
port++;
|
|
}
|
|
}
|
|
|
|
|
|
- /* Schedule tasklet to more in-depth servicing at a better time. */
|
|
|
|
-
|
|
|
|
tasklet_schedule(&brd->helper_tasklet);
|
|
tasklet_schedule(&brd->helper_tasklet);
|
|
|
|
|
|
spin_unlock_irqrestore(&brd->bd_intr_lock, flags);
|
|
spin_unlock_irqrestore(&brd->bd_intr_lock, flags);
|
|
@@ -1099,27 +1028,18 @@ static void neo_copy_data_from_uart_to_queue(struct channel_t *ch)
|
|
|
|
|
|
spin_lock_irqsave(&ch->ch_lock, flags);
|
|
spin_lock_irqsave(&ch->ch_lock, flags);
|
|
|
|
|
|
- /* cache head and tail of queue */
|
|
|
|
head = ch->ch_r_head & RQUEUEMASK;
|
|
head = ch->ch_r_head & RQUEUEMASK;
|
|
tail = ch->ch_r_tail & RQUEUEMASK;
|
|
tail = ch->ch_r_tail & RQUEUEMASK;
|
|
|
|
|
|
- /* Get our cached LSR */
|
|
|
|
linestatus = ch->ch_cached_lsr;
|
|
linestatus = ch->ch_cached_lsr;
|
|
ch->ch_cached_lsr = 0;
|
|
ch->ch_cached_lsr = 0;
|
|
|
|
|
|
- /* Store how much space we have left in the queue */
|
|
|
|
qleft = tail - head - 1;
|
|
qleft = tail - head - 1;
|
|
if (qleft < 0)
|
|
if (qleft < 0)
|
|
qleft += RQUEUEMASK + 1;
|
|
qleft += RQUEUEMASK + 1;
|
|
|
|
|
|
- /*
|
|
|
|
- * If the UART is not in FIFO mode, force the FIFO copy to
|
|
|
|
- * NOT be run, by setting total to 0.
|
|
|
|
- *
|
|
|
|
- * On the other hand, if the UART IS in FIFO mode, then ask
|
|
|
|
- * the UART to give us an approximation of data it has RX'ed.
|
|
|
|
- */
|
|
|
|
if (!(ch->ch_flags & CH_FIFO_ENABLED)) {
|
|
if (!(ch->ch_flags & CH_FIFO_ENABLED)) {
|
|
|
|
+ /* force the FIFO copy to NOT be run */
|
|
total = 0;
|
|
total = 0;
|
|
} else {
|
|
} else {
|
|
total = readb(&ch->ch_neo_uart->rfifo);
|
|
total = readb(&ch->ch_neo_uart->rfifo);
|
|
@@ -1138,26 +1058,11 @@ static void neo_copy_data_from_uart_to_queue(struct channel_t *ch)
|
|
total -= 3;
|
|
total -= 3;
|
|
}
|
|
}
|
|
|
|
|
|
- /*
|
|
|
|
- * Finally, bound the copy to make sure we don't overflow
|
|
|
|
- * our own queue...
|
|
|
|
- * The byte by byte copy loop below this loop this will
|
|
|
|
- * deal with the queue overflow possibility.
|
|
|
|
- */
|
|
|
|
total = min(total, qleft);
|
|
total = min(total, qleft);
|
|
|
|
|
|
while (total > 0) {
|
|
while (total > 0) {
|
|
- /*
|
|
|
|
- * Grab the linestatus register, we need to check
|
|
|
|
- * to see if there are any errors in the FIFO.
|
|
|
|
- */
|
|
|
|
linestatus = readb(&ch->ch_neo_uart->lsr);
|
|
linestatus = readb(&ch->ch_neo_uart->lsr);
|
|
|
|
|
|
- /*
|
|
|
|
- * Break out if there is a FIFO error somewhere.
|
|
|
|
- * This will allow us to go byte by byte down below,
|
|
|
|
- * finding the exact location of the error.
|
|
|
|
- */
|
|
|
|
if (linestatus & UART_17158_RX_FIFO_DATA_ERROR)
|
|
if (linestatus & UART_17158_RX_FIFO_DATA_ERROR)
|
|
break;
|
|
break;
|
|
|
|
|
|
@@ -1182,7 +1087,6 @@ static void neo_copy_data_from_uart_to_queue(struct channel_t *ch)
|
|
|
|
|
|
linestatus = 0;
|
|
linestatus = 0;
|
|
|
|
|
|
- /* Copy data from uart to the queue */
|
|
|
|
memcpy_fromio(ch->ch_rqueue + head,
|
|
memcpy_fromio(ch->ch_rqueue + head,
|
|
&ch->ch_neo_uart->txrxburst, n);
|
|
&ch->ch_neo_uart->txrxburst, n);
|
|
|
|
|
|
@@ -1193,7 +1097,6 @@ static void neo_copy_data_from_uart_to_queue(struct channel_t *ch)
|
|
*/
|
|
*/
|
|
memset(ch->ch_equeue + head, 0, n);
|
|
memset(ch->ch_equeue + head, 0, n);
|
|
|
|
|
|
- /* Add to and flip head if needed */
|
|
|
|
head = (head + n) & RQUEUEMASK;
|
|
head = (head + n) & RQUEUEMASK;
|
|
total -= n;
|
|
total -= n;
|
|
qleft -= n;
|
|
qleft -= n;
|
|
@@ -1242,8 +1145,6 @@ static void neo_copy_data_from_uart_to_queue(struct channel_t *ch)
|
|
ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
|
|
ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
|
|
}
|
|
}
|
|
|
|
|
|
- /* Discard character if we are ignoring the error mask. */
|
|
|
|
-
|
|
|
|
if (linestatus & error_mask) {
|
|
if (linestatus & error_mask) {
|
|
unsigned char discard;
|
|
unsigned char discard;
|
|
|
|
|
|
@@ -1253,13 +1154,10 @@ static void neo_copy_data_from_uart_to_queue(struct channel_t *ch)
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
- * 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.
|
|
|
|
- *
|
|
|
|
- * I decided that I wanted to ditch the oldest data first,
|
|
|
|
- * I hope thats okay with everyone? Yes? Good.
|
|
|
|
|
|
+ * 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) {
|
|
while (qleft < 1) {
|
|
tail = (tail + 1) & RQUEUEMASK;
|
|
tail = (tail + 1) & RQUEUEMASK;
|
|
@@ -1272,18 +1170,14 @@ static void neo_copy_data_from_uart_to_queue(struct channel_t *ch)
|
|
&ch->ch_neo_uart->txrxburst, 1);
|
|
&ch->ch_neo_uart->txrxburst, 1);
|
|
ch->ch_equeue[head] = (unsigned char)linestatus;
|
|
ch->ch_equeue[head] = (unsigned char)linestatus;
|
|
|
|
|
|
- /* Ditch any remaining linestatus value. */
|
|
|
|
linestatus = 0;
|
|
linestatus = 0;
|
|
|
|
|
|
- /* Add to and flip head if needed */
|
|
|
|
head = (head + 1) & RQUEUEMASK;
|
|
head = (head + 1) & RQUEUEMASK;
|
|
|
|
|
|
qleft--;
|
|
qleft--;
|
|
ch->ch_rxcount++;
|
|
ch->ch_rxcount++;
|
|
}
|
|
}
|
|
|
|
|
|
- /* Write new final heads to channel structure. */
|
|
|
|
-
|
|
|
|
ch->ch_r_head = head & RQUEUEMASK;
|
|
ch->ch_r_head = head & RQUEUEMASK;
|
|
ch->ch_e_head = head & EQUEUEMASK;
|
|
ch->ch_e_head = head & EQUEUEMASK;
|
|
|
|
|
|
@@ -1316,10 +1210,6 @@ static int neo_drain(struct tty_struct *tty, uint seconds)
|
|
un->un_flags |= UN_EMPTY;
|
|
un->un_flags |= UN_EMPTY;
|
|
spin_unlock_irqrestore(&ch->ch_lock, flags);
|
|
spin_unlock_irqrestore(&ch->ch_lock, flags);
|
|
|
|
|
|
- /*
|
|
|
|
- * Go to sleep waiting for the tty layer to wake me back up when
|
|
|
|
- * the empty flag goes away.
|
|
|
|
- */
|
|
|
|
rc = wait_event_interruptible_timeout(un->un_flags_wait,
|
|
rc = wait_event_interruptible_timeout(un->un_flags_wait,
|
|
((un->un_flags & UN_EMPTY) == 0),
|
|
((un->un_flags & UN_EMPTY) == 0),
|
|
msecs_to_jiffies(seconds * 1000));
|
|
msecs_to_jiffies(seconds * 1000));
|
|
@@ -1330,8 +1220,7 @@ static int neo_drain(struct tty_struct *tty, uint seconds)
|
|
|
|
|
|
/*
|
|
/*
|
|
* Flush the WRITE FIFO on the Neo.
|
|
* Flush the WRITE FIFO on the Neo.
|
|
- *
|
|
|
|
- * NOTE: Channel lock MUST be held before calling this function!
|
|
|
|
|
|
+ * Channel lock MUST be held before calling this function!
|
|
*/
|
|
*/
|
|
static void neo_flush_uart_write(struct channel_t *ch)
|
|
static void neo_flush_uart_write(struct channel_t *ch)
|
|
{
|
|
{
|
|
@@ -1347,7 +1236,7 @@ static void neo_flush_uart_write(struct channel_t *ch)
|
|
|
|
|
|
for (i = 0; i < 10; i++) {
|
|
for (i = 0; i < 10; i++) {
|
|
/*
|
|
/*
|
|
- * Check to see if the UART feels it completely flushed the
|
|
|
|
|
|
+ * Check to see if the UART completely flushed the FIFO
|
|
* FIFO.
|
|
* FIFO.
|
|
*/
|
|
*/
|
|
tmp = readb(&ch->ch_neo_uart->isr_fcr);
|
|
tmp = readb(&ch->ch_neo_uart->isr_fcr);
|
|
@@ -1362,8 +1251,7 @@ static void neo_flush_uart_write(struct channel_t *ch)
|
|
|
|
|
|
/*
|
|
/*
|
|
* Flush the READ FIFO on the Neo.
|
|
* Flush the READ FIFO on the Neo.
|
|
- *
|
|
|
|
- * NOTE: Channel lock MUST be held before calling this function!
|
|
|
|
|
|
+ * Channel lock MUST be held before calling this function!
|
|
*/
|
|
*/
|
|
static void neo_flush_uart_read(struct channel_t *ch)
|
|
static void neo_flush_uart_read(struct channel_t *ch)
|
|
{
|
|
{
|
|
@@ -1405,7 +1293,6 @@ static void neo_copy_data_from_queue_to_uart(struct channel_t *ch)
|
|
|
|
|
|
spin_lock_irqsave(&ch->ch_lock, flags);
|
|
spin_lock_irqsave(&ch->ch_lock, flags);
|
|
|
|
|
|
- /* No data to write to the UART */
|
|
|
|
if (ch->ch_w_tail == ch->ch_w_head)
|
|
if (ch->ch_w_tail == ch->ch_w_head)
|
|
goto exit_unlock;
|
|
goto exit_unlock;
|
|
|
|
|
|
@@ -1414,12 +1301,10 @@ static void neo_copy_data_from_queue_to_uart(struct channel_t *ch)
|
|
(ch->ch_flags & CH_BREAK_SENDING))
|
|
(ch->ch_flags & CH_BREAK_SENDING))
|
|
goto exit_unlock;
|
|
goto exit_unlock;
|
|
|
|
|
|
- /* If FIFOs are disabled. Send data directly to txrx register */
|
|
|
|
-
|
|
|
|
if (!(ch->ch_flags & CH_FIFO_ENABLED)) {
|
|
if (!(ch->ch_flags & CH_FIFO_ENABLED)) {
|
|
|
|
+ /* Send data directly to txrx register */
|
|
unsigned char lsrbits = readb(&ch->ch_neo_uart->lsr);
|
|
unsigned char lsrbits = readb(&ch->ch_neo_uart->lsr);
|
|
|
|
|
|
- /* Cache the LSR bits for later parsing */
|
|
|
|
ch->ch_cached_lsr |= lsrbits;
|
|
ch->ch_cached_lsr |= lsrbits;
|
|
if (ch->ch_cached_lsr & UART_LSR_THRE) {
|
|
if (ch->ch_cached_lsr & UART_LSR_THRE) {
|
|
ch->ch_cached_lsr &= ~(UART_LSR_THRE);
|
|
ch->ch_cached_lsr &= ~(UART_LSR_THRE);
|
|
@@ -1477,12 +1362,10 @@ static void neo_copy_data_from_queue_to_uart(struct channel_t *ch)
|
|
n = UART_17158_TX_FIFOSIZE - readb(&ch->ch_neo_uart->tfifo);
|
|
n = UART_17158_TX_FIFOSIZE - readb(&ch->ch_neo_uart->tfifo);
|
|
}
|
|
}
|
|
|
|
|
|
- /* cache head and tail of queue */
|
|
|
|
head = ch->ch_w_head & WQUEUEMASK;
|
|
head = ch->ch_w_head & WQUEUEMASK;
|
|
tail = ch->ch_w_tail & WQUEUEMASK;
|
|
tail = ch->ch_w_tail & WQUEUEMASK;
|
|
qlen = (head - tail) & WQUEUEMASK;
|
|
qlen = (head - tail) & WQUEUEMASK;
|
|
|
|
|
|
- /* Find minimum of the FIFO space, versus queue length */
|
|
|
|
n = min(n, qlen);
|
|
n = min(n, qlen);
|
|
|
|
|
|
while (n > 0) {
|
|
while (n > 0) {
|
|
@@ -1521,14 +1404,12 @@ static void neo_copy_data_from_queue_to_uart(struct channel_t *ch)
|
|
memcpy_toio(&ch->ch_neo_uart->txrxburst,
|
|
memcpy_toio(&ch->ch_neo_uart->txrxburst,
|
|
ch->ch_wqueue + tail, s);
|
|
ch->ch_wqueue + tail, s);
|
|
|
|
|
|
- /* Add and flip queue if needed */
|
|
|
|
tail = (tail + s) & WQUEUEMASK;
|
|
tail = (tail + s) & WQUEUEMASK;
|
|
n -= s;
|
|
n -= s;
|
|
ch->ch_txcount += s;
|
|
ch->ch_txcount += s;
|
|
len_written += s;
|
|
len_written += s;
|
|
}
|
|
}
|
|
|
|
|
|
- /* Update the final tail */
|
|
|
|
ch->ch_w_tail = tail & WQUEUEMASK;
|
|
ch->ch_w_tail = tail & WQUEUEMASK;
|
|
|
|
|
|
if (len_written > 0) {
|
|
if (len_written > 0) {
|
|
@@ -1572,10 +1453,7 @@ static void neo_parse_modem(struct channel_t *ch, unsigned char signals)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- /*
|
|
|
|
- * Scrub off lower bits. They signify delta's, which I don't care
|
|
|
|
- * about
|
|
|
|
- */
|
|
|
|
|
|
+ /* Scrub off lower bits. They signify delta's */
|
|
msignals &= 0xf0;
|
|
msignals &= 0xf0;
|
|
|
|
|
|
if (msignals & UART_MSR_DCD)
|
|
if (msignals & UART_MSR_DCD)
|
|
@@ -1668,7 +1546,6 @@ static void neo_uart_init(struct channel_t *ch)
|
|
}
|
|
}
|
|
|
|
|
|
/* Make the UART completely turn off. */
|
|
/* Make the UART completely turn off. */
|
|
-
|
|
|
|
static void neo_uart_off(struct channel_t *ch)
|
|
static void neo_uart_off(struct channel_t *ch)
|
|
{
|
|
{
|
|
/* Turn off UART enhanced bits */
|
|
/* Turn off UART enhanced bits */
|
|
@@ -1735,8 +1612,6 @@ static void neo_send_break(struct channel_t *ch, int msecs)
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
- * neo_send_immediate_char.
|
|
|
|
- *
|
|
|
|
* Sends a specific character as soon as possible to the UART,
|
|
* Sends a specific character as soon as possible to the UART,
|
|
* jumping over any bytes that might be in the write queue.
|
|
* jumping over any bytes that might be in the write queue.
|
|
*
|
|
*
|