Merge tag 'tty-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty and serial driver updates from Greg KH: "Here's the large TTY and Serial driver update for 4.7-rc1. A few new serial drivers are added here, and Peter has fixed a bunch of long-standing bugs in the tty layer and serial drivers as normal. Full details in the shortlog. All of these have been in linux-next for a while with no reported issues" * tag 'tty-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (88 commits) MAINTAINERS: 8250: remove website reference serial: core: Fix port mutex assert if lockdep disabled serial: 8250_dw: fix wrong logic in dw8250_check_lcr() tty: vt, finish looping on duplicate tty: vt, return error when con_startup fails QE-UART: add "fsl,t1040-ucc-uart" to of_device_id serial: mctrl_gpio: Drop support for out1-gpios and out2-gpios serial: 8250dw: Add device HID for future AMD UART controller Fix OpenSSH pty regression on close serial: mctrl_gpio: add IRQ locking serial: 8250: Integrate Fintek into 8250_base serial: mps2-uart: add support for early console serial: mps2-uart: add MPS2 UART driver dt-bindings: document the MPS2 UART bindings serial: sirf: Use generic uart-has-rtscts DT property serial: sirf: Introduce helper variable struct device_node *np serial: mxs-auart: Use generic uart-has-rtscts DT property serial: imx: Use generic uart-has-rtscts DT property doc: DT: Add Generic Serial Device Tree Bindings serial: 8250: of: Make tegra_serial_handle_break() static ...
This commit is contained in:
@@ -398,7 +398,7 @@ static void check_modem_status(struct serial_state *info)
|
||||
wake_up_interruptible(&port->delta_msr_wait);
|
||||
}
|
||||
|
||||
if ((port->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) {
|
||||
if (tty_port_check_carrier(port) && (dstatus & SER_DCD)) {
|
||||
#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
|
||||
printk("ttyS%d CD now %s...", info->line,
|
||||
(!(status & SER_DCD)) ? "on" : "off");
|
||||
@@ -525,7 +525,7 @@ static int startup(struct tty_struct *tty, struct serial_state *info)
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
if (port->flags & ASYNC_INITIALIZED) {
|
||||
if (tty_port_initialized(port)) {
|
||||
free_page(page);
|
||||
goto errout;
|
||||
}
|
||||
@@ -586,7 +586,7 @@ static int startup(struct tty_struct *tty, struct serial_state *info)
|
||||
*/
|
||||
change_speed(tty, info, NULL);
|
||||
|
||||
port->flags |= ASYNC_INITIALIZED;
|
||||
tty_port_set_initialized(port, 1);
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
|
||||
@@ -604,7 +604,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info)
|
||||
unsigned long flags;
|
||||
struct serial_state *state;
|
||||
|
||||
if (!(info->tport.flags & ASYNC_INITIALIZED))
|
||||
if (!tty_port_initialized(&info->tport))
|
||||
return;
|
||||
|
||||
state = info;
|
||||
@@ -645,7 +645,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info)
|
||||
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
|
||||
info->tport.flags &= ~ASYNC_INITIALIZED;
|
||||
tty_port_set_initialized(&info->tport, 0);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
@@ -727,17 +727,12 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
|
||||
info->IER &= ~UART_IER_MSI;
|
||||
if (port->flags & ASYNC_HARDPPS_CD)
|
||||
info->IER |= UART_IER_MSI;
|
||||
if (cflag & CRTSCTS) {
|
||||
port->flags |= ASYNC_CTS_FLOW;
|
||||
tty_port_set_cts_flow(port, cflag & CRTSCTS);
|
||||
if (cflag & CRTSCTS)
|
||||
info->IER |= UART_IER_MSI;
|
||||
} else
|
||||
port->flags &= ~ASYNC_CTS_FLOW;
|
||||
if (cflag & CLOCAL)
|
||||
port->flags &= ~ASYNC_CHECK_CD;
|
||||
else {
|
||||
port->flags |= ASYNC_CHECK_CD;
|
||||
tty_port_set_check_carrier(port, ~cflag & CLOCAL);
|
||||
if (~cflag & CLOCAL)
|
||||
info->IER |= UART_IER_MSI;
|
||||
}
|
||||
/* TBD:
|
||||
* Does clearing IER_MSI imply that we should disable the VBL interrupt ?
|
||||
*/
|
||||
@@ -1089,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
|
||||
port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
check_and_exit:
|
||||
if (port->flags & ASYNC_INITIALIZED) {
|
||||
if (tty_port_initialized(port)) {
|
||||
if (change_spd) {
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
|
||||
tty->alt_speed = 57600;
|
||||
@@ -1143,7 +1138,7 @@ static int rs_tiocmget(struct tty_struct *tty)
|
||||
|
||||
if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
|
||||
return -ENODEV;
|
||||
if (tty->flags & (1 << TTY_IO_ERROR))
|
||||
if (tty_io_error(tty))
|
||||
return -EIO;
|
||||
|
||||
control = info->MCR;
|
||||
@@ -1165,7 +1160,7 @@ static int rs_tiocmset(struct tty_struct *tty, unsigned int set,
|
||||
|
||||
if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
|
||||
return -ENODEV;
|
||||
if (tty->flags & (1 << TTY_IO_ERROR))
|
||||
if (tty_io_error(tty))
|
||||
return -EIO;
|
||||
|
||||
local_irq_save(flags);
|
||||
@@ -1250,7 +1245,7 @@ static int rs_ioctl(struct tty_struct *tty,
|
||||
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
|
||||
(cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
|
||||
(cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
|
||||
if (tty->flags & (1 << TTY_IO_ERROR))
|
||||
if (tty_io_error(tty))
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -1342,7 +1337,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
||||
/* Handle transition away from B0 status */
|
||||
if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
|
||||
info->MCR |= SER_DTR;
|
||||
if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
|
||||
if (!C_CRTSCTS(tty) || !tty_throttled(tty))
|
||||
info->MCR |= SER_RTS;
|
||||
local_irq_save(flags);
|
||||
rtsdtr_ctrl(info->MCR);
|
||||
@@ -1395,7 +1390,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
|
||||
* line status register.
|
||||
*/
|
||||
state->read_status_mask &= ~UART_LSR_DR;
|
||||
if (port->flags & ASYNC_INITIALIZED) {
|
||||
if (tty_port_initialized(port)) {
|
||||
/* disable receive interrupts */
|
||||
custom.intena = IF_RBF;
|
||||
mb();
|
||||
@@ -1495,7 +1490,7 @@ static void rs_hangup(struct tty_struct *tty)
|
||||
rs_flush_buffer(tty);
|
||||
shutdown(tty, info);
|
||||
info->tport.count = 0;
|
||||
info->tport.flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
tty_port_set_active(&info->tport, 0);
|
||||
info->tport.tty = NULL;
|
||||
wake_up_interruptible(&info->tport.open_wait);
|
||||
}
|
||||
@@ -1543,7 +1538,7 @@ static inline void line_info(struct seq_file *m, int line,
|
||||
|
||||
local_irq_save(flags);
|
||||
status = ciab.pra;
|
||||
control = (state->tport.flags & ASYNC_INITIALIZED) ? state->MCR : status;
|
||||
control = tty_port_initialized(&state->tport) ? state->MCR : status;
|
||||
local_irq_restore(flags);
|
||||
|
||||
stat_buf[0] = 0;
|
||||
|
@@ -714,7 +714,7 @@ static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
|
||||
wake_up_interruptible(&info->port.delta_msr_wait);
|
||||
}
|
||||
|
||||
if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) {
|
||||
if ((mdm_change & CyDCD) && tty_port_check_carrier(&info->port)) {
|
||||
if (mdm_status & CyDCD)
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
else
|
||||
@@ -1119,7 +1119,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
|
||||
case C_CM_MDCD:
|
||||
info->icount.dcd++;
|
||||
delta_count++;
|
||||
if (info->port.flags & ASYNC_CHECK_CD) {
|
||||
if (tty_port_check_carrier(&info->port)) {
|
||||
u32 dcd = fw_ver > 241 ? param :
|
||||
readl(&info->u.cyz.ch_ctrl->rs_status);
|
||||
if (dcd & C_RS_DCD)
|
||||
@@ -1279,7 +1279,7 @@ static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
|
||||
|
||||
spin_lock_irqsave(&card->card_lock, flags);
|
||||
|
||||
if (info->port.flags & ASYNC_INITIALIZED)
|
||||
if (tty_port_initialized(&info->port))
|
||||
goto errout;
|
||||
|
||||
if (!info->type) {
|
||||
@@ -1364,7 +1364,7 @@ static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
|
||||
/* enable send, recv, modem !!! */
|
||||
}
|
||||
|
||||
info->port.flags |= ASYNC_INITIALIZED;
|
||||
tty_port_set_initialized(&info->port, 1);
|
||||
|
||||
clear_bit(TTY_IO_ERROR, &tty->flags);
|
||||
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
|
||||
@@ -1424,7 +1424,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
|
||||
struct cyclades_card *card;
|
||||
unsigned long flags;
|
||||
|
||||
if (!(info->port.flags & ASYNC_INITIALIZED))
|
||||
if (!tty_port_initialized(&info->port))
|
||||
return;
|
||||
|
||||
card = info->card;
|
||||
@@ -1448,7 +1448,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
|
||||
some later date (after testing)!!! */
|
||||
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
info->port.flags &= ~ASYNC_INITIALIZED;
|
||||
tty_port_set_initialized(&info->port, 0);
|
||||
spin_unlock_irqrestore(&card->card_lock, flags);
|
||||
} else {
|
||||
#ifdef CY_DEBUG_OPEN
|
||||
@@ -1473,7 +1473,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
|
||||
tty_port_lower_dtr_rts(&info->port);
|
||||
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
info->port.flags &= ~ASYNC_INITIALIZED;
|
||||
tty_port_set_initialized(&info->port, 0);
|
||||
|
||||
spin_unlock_irqrestore(&card->card_lock, flags);
|
||||
}
|
||||
@@ -1711,7 +1711,7 @@ static void cy_do_close(struct tty_port *port)
|
||||
/* Stop accepting input */
|
||||
cyy_writeb(info, CyCAR, channel & 0x03);
|
||||
cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData);
|
||||
if (info->port.flags & ASYNC_INITIALIZED) {
|
||||
if (tty_port_initialized(&info->port)) {
|
||||
/* Waiting for on-board buffers to be empty before
|
||||
closing the port */
|
||||
spin_unlock_irqrestore(&card->card_lock, flags);
|
||||
@@ -2083,17 +2083,12 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
|
||||
info->cor1 |= CyPARITY_NONE;
|
||||
|
||||
/* CTS flow control flag */
|
||||
if (cflag & CRTSCTS) {
|
||||
info->port.flags |= ASYNC_CTS_FLOW;
|
||||
tty_port_set_cts_flow(&info->port, cflag & CRTSCTS);
|
||||
if (cflag & CRTSCTS)
|
||||
info->cor2 |= CyCtsAE;
|
||||
} else {
|
||||
info->port.flags &= ~ASYNC_CTS_FLOW;
|
||||
info->cor2 &= ~CyCtsAE;
|
||||
}
|
||||
if (cflag & CLOCAL)
|
||||
info->port.flags &= ~ASYNC_CHECK_CD;
|
||||
else
|
||||
info->port.flags |= ASYNC_CHECK_CD;
|
||||
info->cor2 &= ~CyCtsAE;
|
||||
tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
|
||||
|
||||
/***********************************************
|
||||
The hardware option, CyRtsAO, presents RTS when
|
||||
@@ -2234,7 +2229,7 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
|
||||
}
|
||||
/* As the HW flow control is done in firmware, the driver
|
||||
doesn't need to care about it */
|
||||
info->port.flags &= ~ASYNC_CTS_FLOW;
|
||||
tty_port_set_cts_flow(&info->port, 0);
|
||||
|
||||
/* XON/XOFF/XANY flow control flags */
|
||||
sw_flow = 0;
|
||||
@@ -2252,10 +2247,7 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
|
||||
}
|
||||
|
||||
/* CD sensitivity */
|
||||
if (cflag & CLOCAL)
|
||||
info->port.flags &= ~ASYNC_CHECK_CD;
|
||||
else
|
||||
info->port.flags |= ASYNC_CHECK_CD;
|
||||
tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
|
||||
|
||||
if (baud == 0) { /* baud rate is zero, turn off line */
|
||||
cy_writel(&ch_ctrl->rs_control,
|
||||
@@ -2342,7 +2334,7 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
|
||||
info->port.closing_wait = new_serial.closing_wait * HZ / 100;
|
||||
|
||||
check_and_exit:
|
||||
if (info->port.flags & ASYNC_INITIALIZED) {
|
||||
if (tty_port_initialized(&info->port)) {
|
||||
cy_set_line_char(info, tty);
|
||||
ret = 0;
|
||||
} else {
|
||||
|
@@ -632,7 +632,7 @@ int hvc_poll(struct hvc_struct *hp)
|
||||
goto bail;
|
||||
|
||||
/* Now check if we can get data (are we throttled ?) */
|
||||
if (test_bit(TTY_THROTTLED, &tty->flags))
|
||||
if (tty_throttled(tty))
|
||||
goto throttled;
|
||||
|
||||
/* If we aren't notifier driven and aren't throttled, we always
|
||||
@@ -814,7 +814,7 @@ static int hvc_poll_get_char(struct tty_driver *driver, int line)
|
||||
|
||||
n = hp->ops->get_chars(hp->vtermno, &ch, 1);
|
||||
|
||||
if (n == 0)
|
||||
if (n <= 0)
|
||||
return NO_POLL_CHAR;
|
||||
|
||||
return ch;
|
||||
|
@@ -600,7 +600,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
|
||||
|
||||
hvcs_try_write(hvcsd);
|
||||
|
||||
if (!tty || test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
if (!tty || tty_throttled(tty)) {
|
||||
hvcsd->todo_mask &= ~(HVCS_READ_MASK);
|
||||
goto bail;
|
||||
} else if (!(hvcsd->todo_mask & (HVCS_READ_MASK)))
|
||||
|
@@ -509,7 +509,7 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg)
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
if (tty && hp->n_throttle && !tty_throttled(tty)) {
|
||||
/* we weren't hung up and we weren't throttled, so we can
|
||||
* deliver the rest now */
|
||||
hvsi_send_overflow(hp);
|
||||
|
@@ -1572,6 +1572,11 @@ static void handle_received_SETUP_packet(struct ipw_hardware *hw,
|
||||
sizeof(struct ipw_setup_reboot_msg_ack),
|
||||
ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP,
|
||||
TL_SETUP_SIGNO_REBOOT_MSG_ACK);
|
||||
if (!packet) {
|
||||
pr_err(IPWIRELESS_PCCARD_NAME
|
||||
": Not enough memory to send reboot packet");
|
||||
break;
|
||||
}
|
||||
packet->header.length =
|
||||
sizeof(struct TlSetupRebootMsgAck);
|
||||
send_packet(hw, PRIO_SETUP, &packet->header);
|
||||
|
@@ -438,8 +438,8 @@ static void isicom_tx(unsigned long _data)
|
||||
|
||||
for (; count > 0; count--, port++) {
|
||||
/* port not active or tx disabled to force flow control */
|
||||
if (!(port->port.flags & ASYNC_INITIALIZED) ||
|
||||
!(port->status & ISI_TXOK))
|
||||
if (!tty_port_initialized(&port->port) ||
|
||||
!(port->status & ISI_TXOK))
|
||||
continue;
|
||||
|
||||
txcount = min_t(short, TX_SIZE, port->xmit_cnt);
|
||||
@@ -553,7 +553,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
port = card->ports + channel;
|
||||
if (!(port->port.flags & ASYNC_INITIALIZED)) {
|
||||
if (!tty_port_initialized(&port->port)) {
|
||||
outw(0x0000, base+0x04); /* enable interrupts */
|
||||
spin_unlock(&card->card_lock);
|
||||
return IRQ_HANDLED;
|
||||
@@ -577,7 +577,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
|
||||
header = inw(base);
|
||||
switch (header & 0xff) {
|
||||
case 0: /* Change in EIA signals */
|
||||
if (port->port.flags & ASYNC_CHECK_CD) {
|
||||
if (tty_port_check_carrier(&port->port)) {
|
||||
if (port->status & ISI_DCD) {
|
||||
if (!(header & ISI_DCD)) {
|
||||
/* Carrier has been lost */
|
||||
@@ -758,18 +758,13 @@ static void isicom_config_port(struct tty_struct *tty)
|
||||
outw(channel_setup, base);
|
||||
InterruptTheCard(base);
|
||||
}
|
||||
if (C_CLOCAL(tty))
|
||||
port->port.flags &= ~ASYNC_CHECK_CD;
|
||||
else
|
||||
port->port.flags |= ASYNC_CHECK_CD;
|
||||
tty_port_set_check_carrier(&port->port, !C_CLOCAL(tty));
|
||||
|
||||
/* flow control settings ...*/
|
||||
flow_ctrl = 0;
|
||||
port->port.flags &= ~ASYNC_CTS_FLOW;
|
||||
if (C_CRTSCTS(tty)) {
|
||||
port->port.flags |= ASYNC_CTS_FLOW;
|
||||
tty_port_set_cts_flow(&port->port, C_CRTSCTS(tty));
|
||||
if (C_CRTSCTS(tty))
|
||||
flow_ctrl |= ISICOM_CTSRTS;
|
||||
}
|
||||
if (I_IXON(tty))
|
||||
flow_ctrl |= ISICOM_RESPOND_XONXOFF;
|
||||
if (I_IXOFF(tty))
|
||||
|
@@ -912,7 +912,7 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
|
||||
|
||||
/* pci hot-un-plug support */
|
||||
for (a = 0; a < brd->numPorts; a++)
|
||||
if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
|
||||
if (tty_port_initialized(&brd->ports[a].port))
|
||||
tty_port_tty_hangup(&brd->ports[a].port, false);
|
||||
|
||||
for (a = 0; a < MAX_PORTS_PER_BOARD; a++)
|
||||
@@ -921,7 +921,7 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
|
||||
while (1) {
|
||||
opened = 0;
|
||||
for (a = 0; a < brd->numPorts; a++)
|
||||
if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
|
||||
if (tty_port_initialized(&brd->ports[a].port))
|
||||
opened++;
|
||||
mutex_unlock(&moxa_openlock);
|
||||
if (!opened)
|
||||
@@ -1192,13 +1192,13 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
|
||||
tty->driver_data = ch;
|
||||
tty_port_tty_set(&ch->port, tty);
|
||||
mutex_lock(&ch->port.mutex);
|
||||
if (!(ch->port.flags & ASYNC_INITIALIZED)) {
|
||||
if (!tty_port_initialized(&ch->port)) {
|
||||
ch->statusflags = 0;
|
||||
moxa_set_tty_param(tty, &tty->termios);
|
||||
MoxaPortLineCtrl(ch, 1, 1);
|
||||
MoxaPortEnable(ch);
|
||||
MoxaSetFifo(ch, ch->type == PORT_16550A);
|
||||
ch->port.flags |= ASYNC_INITIALIZED;
|
||||
tty_port_set_initialized(&ch->port, 1);
|
||||
}
|
||||
mutex_unlock(&ch->port.mutex);
|
||||
mutex_unlock(&moxa_openlock);
|
||||
@@ -1379,7 +1379,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(&p->port);
|
||||
void __iomem *ofsAddr;
|
||||
unsigned int inited = p->port.flags & ASYNC_INITIALIZED;
|
||||
unsigned int inited = tty_port_initialized(&p->port);
|
||||
u16 intr;
|
||||
|
||||
if (tty) {
|
||||
@@ -1394,7 +1394,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
|
||||
tty_wakeup(tty);
|
||||
}
|
||||
|
||||
if (inited && !test_bit(TTY_THROTTLED, &tty->flags) &&
|
||||
if (inited && !tty_throttled(tty) &&
|
||||
MoxaPortRxQueue(p) > 0) { /* RX */
|
||||
MoxaPortReadData(p);
|
||||
tty_schedule_flip(&p->port);
|
||||
|
@@ -711,8 +711,8 @@ static int mxser_change_speed(struct tty_struct *tty,
|
||||
/* CTS flow control flag and modem status interrupts */
|
||||
info->IER &= ~UART_IER_MSI;
|
||||
info->MCR &= ~UART_MCR_AFE;
|
||||
tty_port_set_cts_flow(&info->port, cflag & CRTSCTS);
|
||||
if (cflag & CRTSCTS) {
|
||||
info->port.flags |= ASYNC_CTS_FLOW;
|
||||
info->IER |= UART_IER_MSI;
|
||||
if ((info->type == PORT_16550A) || (info->board->chip_flag)) {
|
||||
info->MCR |= UART_MCR_AFE;
|
||||
@@ -744,16 +744,11 @@ static int mxser_change_speed(struct tty_struct *tty,
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
info->port.flags &= ~ASYNC_CTS_FLOW;
|
||||
}
|
||||
outb(info->MCR, info->ioaddr + UART_MCR);
|
||||
if (cflag & CLOCAL) {
|
||||
info->port.flags &= ~ASYNC_CHECK_CD;
|
||||
} else {
|
||||
info->port.flags |= ASYNC_CHECK_CD;
|
||||
tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
|
||||
if (~cflag & CLOCAL)
|
||||
info->IER |= UART_IER_MSI;
|
||||
}
|
||||
outb(info->IER, info->ioaddr + UART_IER);
|
||||
|
||||
/*
|
||||
@@ -826,7 +821,7 @@ static void mxser_check_modem_status(struct tty_struct *tty,
|
||||
port->mon_data.modem_status = status;
|
||||
wake_up_interruptible(&port->port.delta_msr_wait);
|
||||
|
||||
if ((port->port.flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
|
||||
if (tty_port_check_carrier(&port->port) && (status & UART_MSR_DDCD)) {
|
||||
if (status & UART_MSR_DCD)
|
||||
wake_up_interruptible(&port->port.open_wait);
|
||||
}
|
||||
@@ -1086,12 +1081,10 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
|
||||
mutex_lock(&port->mutex);
|
||||
mxser_close_port(port);
|
||||
mxser_flush_buffer(tty);
|
||||
if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
|
||||
if (C_HUPCL(tty))
|
||||
tty_port_lower_dtr_rts(port);
|
||||
}
|
||||
if (tty_port_initialized(port) && C_HUPCL(tty))
|
||||
tty_port_lower_dtr_rts(port);
|
||||
mxser_shutdown_port(port);
|
||||
clear_bit(ASYNCB_INITIALIZED, &port->flags);
|
||||
tty_port_set_initialized(port, 0);
|
||||
mutex_unlock(&port->mutex);
|
||||
info->closing = 0;
|
||||
/* Right now the tty_port set is done outside of the close_end helper
|
||||
@@ -1287,7 +1280,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
|
||||
|
||||
process_txrx_fifo(info);
|
||||
|
||||
if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
|
||||
if (tty_port_initialized(port)) {
|
||||
if (flags != (port->flags & ASYNC_SPD_MASK)) {
|
||||
spin_lock_irqsave(&info->slock, sl_flags);
|
||||
mxser_change_speed(tty, NULL);
|
||||
@@ -1296,7 +1289,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
|
||||
} else {
|
||||
retval = mxser_activate(port, tty);
|
||||
if (retval == 0)
|
||||
set_bit(ASYNCB_INITIALIZED, &port->flags);
|
||||
tty_port_set_initialized(port, 1);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
@@ -1334,7 +1327,7 @@ static int mxser_tiocmget(struct tty_struct *tty)
|
||||
|
||||
if (tty->index == MXSER_PORTS)
|
||||
return -ENOIOCTLCMD;
|
||||
if (test_bit(TTY_IO_ERROR, &tty->flags))
|
||||
if (tty_io_error(tty))
|
||||
return -EIO;
|
||||
|
||||
control = info->MCR;
|
||||
@@ -1361,7 +1354,7 @@ static int mxser_tiocmset(struct tty_struct *tty,
|
||||
|
||||
if (tty->index == MXSER_PORTS)
|
||||
return -ENOIOCTLCMD;
|
||||
if (test_bit(TTY_IO_ERROR, &tty->flags))
|
||||
if (tty_io_error(tty))
|
||||
return -EIO;
|
||||
|
||||
spin_lock_irqsave(&info->slock, flags);
|
||||
@@ -1715,8 +1708,7 @@ static int mxser_ioctl(struct tty_struct *tty,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT &&
|
||||
test_bit(TTY_IO_ERROR, &tty->flags))
|
||||
if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && tty_io_error(tty))
|
||||
return -EIO;
|
||||
|
||||
switch (cmd) {
|
||||
@@ -2257,7 +2249,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
|
||||
iir &= MOXA_MUST_IIR_MASK;
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (!tty || port->closing ||
|
||||
!(port->port.flags & ASYNC_INITIALIZED)) {
|
||||
!tty_port_initialized(&port->port)) {
|
||||
status = inb(port->ioaddr + UART_LSR);
|
||||
outb(0x27, port->ioaddr + UART_FCR);
|
||||
inb(port->ioaddr + UART_MSR);
|
||||
@@ -2400,7 +2392,6 @@ static int mxser_initbrd(struct mxser_board *brd,
|
||||
if (brd->chip_flag != MOXA_OTHER_UART)
|
||||
mxser_enable_must_enchance_mode(info->ioaddr);
|
||||
|
||||
info->port.flags = ASYNC_SHARE_IRQ;
|
||||
info->type = brd->uart_type;
|
||||
|
||||
process_txrx_fifo(info);
|
||||
|
@@ -2045,7 +2045,9 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm)
|
||||
}
|
||||
}
|
||||
spin_unlock(&gsm_mux_lock);
|
||||
WARN_ON(i == MAX_MUX);
|
||||
/* open failed before registering => nothing to do */
|
||||
if (i == MAX_MUX)
|
||||
return;
|
||||
|
||||
/* In theory disconnecting DLCI 0 is sufficient but for some
|
||||
modems this is apparently not the case. */
|
||||
@@ -2947,7 +2949,7 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)
|
||||
dlci->modem_rx = 0;
|
||||
/* We could in theory open and close before we wait - eg if we get
|
||||
a DM straight back. This is ok as that will have caused a hangup */
|
||||
set_bit(ASYNCB_INITIALIZED, &port->flags);
|
||||
tty_port_set_initialized(port, 1);
|
||||
/* Start sending off SABM messages */
|
||||
gsm_dlci_begin_open(dlci);
|
||||
/* And wait for virtual carrier */
|
||||
@@ -2970,10 +2972,8 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)
|
||||
if (tty_port_close_start(&dlci->port, tty, filp) == 0)
|
||||
return;
|
||||
gsm_dlci_begin_close(dlci);
|
||||
if (test_bit(ASYNCB_INITIALIZED, &dlci->port.flags)) {
|
||||
if (C_HUPCL(tty))
|
||||
tty_port_lower_dtr_rts(&dlci->port);
|
||||
}
|
||||
if (tty_port_initialized(&dlci->port) && C_HUPCL(tty))
|
||||
tty_port_lower_dtr_rts(&dlci->port);
|
||||
tty_port_close_end(&dlci->port, tty);
|
||||
tty_port_tty_set(&dlci->port, NULL);
|
||||
return;
|
||||
|
@@ -599,7 +599,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
|
||||
add_wait_queue(&tty->read_wait, &wait);
|
||||
|
||||
for (;;) {
|
||||
if (test_bit(TTY_OTHER_DONE, &tty->flags)) {
|
||||
if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
@@ -827,7 +827,7 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
|
||||
/* set bits for operations that won't block */
|
||||
if (n_hdlc->rx_buf_list.head)
|
||||
mask |= POLLIN | POLLRDNORM; /* readable */
|
||||
if (test_bit(TTY_OTHER_DONE, &tty->flags))
|
||||
if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
|
||||
mask |= POLLHUP;
|
||||
if (tty_hung_up_p(filp))
|
||||
mask |= POLLHUP;
|
||||
|
@@ -1917,18 +1917,6 @@ static inline int input_available_p(struct tty_struct *tty, int poll)
|
||||
return ldata->commit_head - ldata->read_tail >= amt;
|
||||
}
|
||||
|
||||
static inline int check_other_done(struct tty_struct *tty)
|
||||
{
|
||||
int done = test_bit(TTY_OTHER_DONE, &tty->flags);
|
||||
if (done) {
|
||||
/* paired with cmpxchg() in check_other_closed(); ensures
|
||||
* read buffer head index is not stale
|
||||
*/
|
||||
smp_mb__after_atomic();
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
/**
|
||||
* copy_from_read_buf - copy read data directly
|
||||
* @tty: terminal device
|
||||
@@ -2124,7 +2112,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
||||
struct n_tty_data *ldata = tty->disc_data;
|
||||
unsigned char __user *b = buf;
|
||||
DEFINE_WAIT_FUNC(wait, woken_wake_function);
|
||||
int c, done;
|
||||
int c;
|
||||
int minimum, time;
|
||||
ssize_t retval = 0;
|
||||
long timeout;
|
||||
@@ -2183,32 +2171,35 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
||||
break;
|
||||
}
|
||||
|
||||
done = check_other_done(tty);
|
||||
|
||||
if (!input_available_p(tty, 0)) {
|
||||
if (done) {
|
||||
retval = -EIO;
|
||||
break;
|
||||
}
|
||||
if (tty_hung_up_p(file))
|
||||
break;
|
||||
if (!timeout)
|
||||
break;
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
retval = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
if (signal_pending(current)) {
|
||||
retval = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
up_read(&tty->termios_rwsem);
|
||||
|
||||
timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
|
||||
timeout);
|
||||
|
||||
tty_buffer_flush_work(tty->port);
|
||||
down_read(&tty->termios_rwsem);
|
||||
continue;
|
||||
if (!input_available_p(tty, 0)) {
|
||||
if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
|
||||
retval = -EIO;
|
||||
break;
|
||||
}
|
||||
if (tty_hung_up_p(file))
|
||||
break;
|
||||
if (!timeout)
|
||||
break;
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
retval = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
if (signal_pending(current)) {
|
||||
retval = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
up_read(&tty->termios_rwsem);
|
||||
|
||||
timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
|
||||
timeout);
|
||||
|
||||
down_read(&tty->termios_rwsem);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (ldata->icanon && !L_EXTPROC(tty)) {
|
||||
@@ -2386,12 +2377,17 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
|
||||
|
||||
poll_wait(file, &tty->read_wait, wait);
|
||||
poll_wait(file, &tty->write_wait, wait);
|
||||
if (check_other_done(tty))
|
||||
mask |= POLLHUP;
|
||||
if (input_available_p(tty, 1))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
else {
|
||||
tty_buffer_flush_work(tty->port);
|
||||
if (input_available_p(tty, 1))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
}
|
||||
if (tty->packet && tty->link->ctrl_status)
|
||||
mask |= POLLPRI | POLLIN | POLLRDNORM;
|
||||
if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
|
||||
mask |= POLLHUP;
|
||||
if (tty_hung_up_p(file))
|
||||
mask |= POLLHUP;
|
||||
if (tty->ops->write && !tty_is_writelocked(tty) &&
|
||||
|
@@ -826,7 +826,7 @@ static int receive_data(enum port_type index, struct nozomi *dc)
|
||||
size = __le32_to_cpu(readl(addr));
|
||||
/* DBG1( "%d bytes port: %d", size, index); */
|
||||
|
||||
if (tty && test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
if (tty && tty_throttled(tty)) {
|
||||
DBG1("No room in tty, don't read data, don't ack interrupt, "
|
||||
"disable interrupt");
|
||||
|
||||
|
@@ -44,7 +44,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
|
||||
if (tty->driver->subtype == PTY_TYPE_MASTER)
|
||||
WARN_ON(tty->count > 1);
|
||||
else {
|
||||
if (test_bit(TTY_IO_ERROR, &tty->flags))
|
||||
if (tty_io_error(tty))
|
||||
return;
|
||||
if (tty->count > 2)
|
||||
return;
|
||||
@@ -59,7 +59,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
|
||||
if (!tty->link)
|
||||
return;
|
||||
set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
|
||||
tty_flip_buffer_push(tty->link->port);
|
||||
wake_up_interruptible(&tty->link->read_wait);
|
||||
wake_up_interruptible(&tty->link->write_wait);
|
||||
if (tty->driver->subtype == PTY_TYPE_MASTER) {
|
||||
set_bit(TTY_OTHER_CLOSED, &tty->flags);
|
||||
@@ -247,9 +247,7 @@ static int pty_open(struct tty_struct *tty, struct file *filp)
|
||||
goto out;
|
||||
|
||||
clear_bit(TTY_IO_ERROR, &tty->flags);
|
||||
/* TTY_OTHER_CLOSED must be cleared before TTY_OTHER_DONE */
|
||||
clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
|
||||
clear_bit(TTY_OTHER_DONE, &tty->link->flags);
|
||||
set_bit(TTY_THROTTLED, &tty->flags);
|
||||
return 0;
|
||||
|
||||
|
@@ -495,7 +495,7 @@ static void rp_handle_port(struct r_port *info)
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
if ((info->port.flags & ASYNC_INITIALIZED) == 0) {
|
||||
if (!tty_port_initialized(&info->port)) {
|
||||
printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
|
||||
"info->flags & NOT_INIT\n");
|
||||
return;
|
||||
@@ -615,7 +615,8 @@ static void rp_do_poll(unsigned long dummy)
|
||||
* the board.
|
||||
* Inputs: board, aiop, chan numbers
|
||||
*/
|
||||
static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
|
||||
static void __init
|
||||
init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
|
||||
{
|
||||
unsigned rocketMode;
|
||||
struct r_port *info;
|
||||
@@ -920,7 +921,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
|
||||
/*
|
||||
* Info->count is now 1; so it's safe to sleep now.
|
||||
*/
|
||||
if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
|
||||
if (!tty_port_initialized(port)) {
|
||||
cp = &info->channel;
|
||||
sSetRxTrigger(cp, TRIG_1);
|
||||
if (sGetChanStatus(cp) & CD_ACT)
|
||||
@@ -944,7 +945,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
|
||||
sEnRxFIFO(cp);
|
||||
sEnTransmit(cp);
|
||||
|
||||
set_bit(ASYNCB_INITIALIZED, &info->port.flags);
|
||||
tty_port_set_initialized(&info->port, 1);
|
||||
|
||||
/*
|
||||
* Set up the tty->alt_speed kludge
|
||||
@@ -1042,9 +1043,10 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
|
||||
}
|
||||
}
|
||||
spin_lock_irq(&port->lock);
|
||||
info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_NORMAL_ACTIVE);
|
||||
tty->closing = 0;
|
||||
spin_unlock_irq(&port->lock);
|
||||
tty_port_set_initialized(port, 0);
|
||||
tty_port_set_active(port, 0);
|
||||
mutex_unlock(&port->mutex);
|
||||
tty_port_tty_set(port, NULL);
|
||||
|
||||
@@ -1512,7 +1514,7 @@ static void rp_hangup(struct tty_struct *tty)
|
||||
sDisCTSFlowCtl(cp);
|
||||
sDisTxSoftFlowCtl(cp);
|
||||
sClrTxXOFF(cp);
|
||||
clear_bit(ASYNCB_INITIALIZED, &info->port.flags);
|
||||
tty_port_set_initialized(&info->port, 0);
|
||||
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
}
|
||||
@@ -1624,7 +1626,7 @@ static int rp_write(struct tty_struct *tty,
|
||||
/* Write remaining data into the port's xmit_buf */
|
||||
while (1) {
|
||||
/* Hung up ? */
|
||||
if (!test_bit(ASYNCB_NORMAL_ACTIVE, &info->port.flags))
|
||||
if (!tty_port_active(&info->port))
|
||||
goto end;
|
||||
c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
|
||||
c = min(c, XMIT_BUF_SIZE - info->xmit_head);
|
||||
|
@@ -17,7 +17,7 @@
|
||||
|
||||
struct uart_8250_dma {
|
||||
int (*tx_dma)(struct uart_8250_port *p);
|
||||
int (*rx_dma)(struct uart_8250_port *p, unsigned int iir);
|
||||
int (*rx_dma)(struct uart_8250_port *p);
|
||||
|
||||
/* Filter function */
|
||||
dma_filter_fn fn;
|
||||
@@ -84,7 +84,6 @@ struct serial8250_config {
|
||||
#define UART_BUG_THRE (1 << 3) /* UART has buggy THRE reassertion */
|
||||
#define UART_BUG_PARITY (1 << 4) /* UART mishandles parity if FIFO enabled */
|
||||
|
||||
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_SHARE_IRQ
|
||||
#define SERIAL8250_SHARE_IRQS 1
|
||||
@@ -151,6 +150,12 @@ static inline int serial8250_pnp_init(void) { return 0; }
|
||||
static inline void serial8250_pnp_exit(void) { }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_FINTEK
|
||||
int fintek_8250_probe(struct uart_8250_port *uart);
|
||||
#else
|
||||
static inline int fintek_8250_probe(struct uart_8250_port *uart) { return 0; }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP1
|
||||
static inline int is_omap1_8250(struct uart_8250_port *pt)
|
||||
{
|
||||
@@ -190,7 +195,8 @@ static inline int is_omap1510_8250(struct uart_8250_port *pt)
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
extern int serial8250_tx_dma(struct uart_8250_port *);
|
||||
extern int serial8250_rx_dma(struct uart_8250_port *, unsigned int iir);
|
||||
extern int serial8250_rx_dma(struct uart_8250_port *);
|
||||
extern void serial8250_rx_dma_flush(struct uart_8250_port *);
|
||||
extern int serial8250_request_dma(struct uart_8250_port *);
|
||||
extern void serial8250_release_dma(struct uart_8250_port *);
|
||||
#else
|
||||
@@ -198,10 +204,11 @@ static inline int serial8250_tx_dma(struct uart_8250_port *p)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
static inline int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
||||
static inline int serial8250_rx_dma(struct uart_8250_port *p)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
static inline void serial8250_rx_dma_flush(struct uart_8250_port *p) { }
|
||||
static inline int serial8250_request_dma(struct uart_8250_port *p)
|
||||
{
|
||||
return -1;
|
||||
|
@@ -830,6 +830,7 @@ static int serial8250_probe(struct platform_device *dev)
|
||||
uart.port.handle_irq = p->handle_irq;
|
||||
uart.port.handle_break = p->handle_break;
|
||||
uart.port.set_termios = p->set_termios;
|
||||
uart.port.get_mctrl = p->get_mctrl;
|
||||
uart.port.pm = p->pm;
|
||||
uart.port.dev = &dev->dev;
|
||||
uart.port.irqflags |= irqflag;
|
||||
@@ -1022,6 +1023,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
||||
/* Possibly override set_termios call */
|
||||
if (up->port.set_termios)
|
||||
uart->port.set_termios = up->port.set_termios;
|
||||
if (up->port.get_mctrl)
|
||||
uart->port.get_mctrl = up->port.get_mctrl;
|
||||
if (up->port.set_mctrl)
|
||||
uart->port.set_mctrl = up->port.set_mctrl;
|
||||
if (up->port.startup)
|
||||
|
@@ -110,30 +110,11 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
||||
int serial8250_rx_dma(struct uart_8250_port *p)
|
||||
{
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
|
||||
switch (iir & 0x3f) {
|
||||
case UART_IIR_RLSI:
|
||||
/* 8250_core handles errors and break interrupts */
|
||||
return -EIO;
|
||||
case UART_IIR_RX_TIMEOUT:
|
||||
/*
|
||||
* If RCVR FIFO trigger level was not reached, complete the
|
||||
* transfer and let 8250_core copy the remaining data.
|
||||
*/
|
||||
if (dma->rx_running) {
|
||||
dmaengine_pause(dma->rxchan);
|
||||
__dma_rx_complete(p);
|
||||
dmaengine_terminate_all(dma->rxchan);
|
||||
}
|
||||
return -ETIMEDOUT;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (dma->rx_running)
|
||||
return 0;
|
||||
|
||||
@@ -154,10 +135,23 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void serial8250_rx_dma_flush(struct uart_8250_port *p)
|
||||
{
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
|
||||
if (dma->rx_running) {
|
||||
dmaengine_pause(dma->rxchan);
|
||||
__dma_rx_complete(p);
|
||||
dmaengine_terminate_all(dma->rxchan);
|
||||
}
|
||||
}
|
||||
|
||||
int serial8250_request_dma(struct uart_8250_port *p)
|
||||
{
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
dma_cap_mask_t mask;
|
||||
struct dma_slave_caps caps;
|
||||
int ret;
|
||||
|
||||
/* Default slave configuration parameters */
|
||||
dma->rxconf.direction = DMA_DEV_TO_MEM;
|
||||
@@ -178,6 +172,16 @@ int serial8250_request_dma(struct uart_8250_port *p)
|
||||
if (!dma->rxchan)
|
||||
return -ENODEV;
|
||||
|
||||
/* 8250 rx dma requires dmaengine driver to support pause/terminate */
|
||||
ret = dma_get_slave_caps(dma->rxchan, &caps);
|
||||
if (ret)
|
||||
goto release_rx;
|
||||
if (!caps.cmd_pause || !caps.cmd_terminate ||
|
||||
caps.residue_granularity == DMA_RESIDUE_GRANULARITY_DESCRIPTOR) {
|
||||
ret = -EINVAL;
|
||||
goto release_rx;
|
||||
}
|
||||
|
||||
dmaengine_slave_config(dma->rxchan, &dma->rxconf);
|
||||
|
||||
/* Get a channel for TX */
|
||||
@@ -185,8 +189,17 @@ int serial8250_request_dma(struct uart_8250_port *p)
|
||||
dma->fn, dma->tx_param,
|
||||
p->port.dev, "tx");
|
||||
if (!dma->txchan) {
|
||||
dma_release_channel(dma->rxchan);
|
||||
return -ENODEV;
|
||||
ret = -ENODEV;
|
||||
goto release_rx;
|
||||
}
|
||||
|
||||
/* 8250 tx dma requires dmaengine driver to support terminate */
|
||||
ret = dma_get_slave_caps(dma->txchan, &caps);
|
||||
if (ret)
|
||||
goto err;
|
||||
if (!caps.cmd_terminate) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
dmaengine_slave_config(dma->txchan, &dma->txconf);
|
||||
@@ -197,8 +210,10 @@ int serial8250_request_dma(struct uart_8250_port *p)
|
||||
|
||||
dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,
|
||||
&dma->rx_addr, GFP_KERNEL);
|
||||
if (!dma->rx_buf)
|
||||
if (!dma->rx_buf) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* TX buffer */
|
||||
dma->tx_addr = dma_map_single(dma->txchan->device->dev,
|
||||
@@ -208,6 +223,7 @@ int serial8250_request_dma(struct uart_8250_port *p)
|
||||
if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) {
|
||||
dma_free_coherent(dma->rxchan->device->dev, dma->rx_size,
|
||||
dma->rx_buf, dma->rx_addr);
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -215,10 +231,10 @@ int serial8250_request_dma(struct uart_8250_port *p)
|
||||
|
||||
return 0;
|
||||
err:
|
||||
dma_release_channel(dma->rxchan);
|
||||
dma_release_channel(dma->txchan);
|
||||
|
||||
return -ENOMEM;
|
||||
release_rx:
|
||||
dma_release_channel(dma->rxchan);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_request_dma);
|
||||
|
||||
|
@@ -104,15 +104,16 @@ static void dw8250_check_lcr(struct uart_port *p, int value)
|
||||
dw8250_force_idle(p);
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
__raw_writeq(value & 0xff, offset);
|
||||
#else
|
||||
if (p->type == PORT_OCTEON)
|
||||
__raw_writeq(value & 0xff, offset);
|
||||
else
|
||||
#endif
|
||||
if (p->iotype == UPIO_MEM32)
|
||||
writel(value, offset);
|
||||
else if (p->iotype == UPIO_MEM32BE)
|
||||
iowrite32be(value, offset);
|
||||
else
|
||||
writeb(value, offset);
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
* FIXME: this deadlocks if port->lock is already held
|
||||
@@ -617,6 +618,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = {
|
||||
{ "8086228A", 0 },
|
||||
{ "APMC0D08", 0},
|
||||
{ "AMD0020", 0 },
|
||||
{ "AMDI0020", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
|
||||
|
@@ -1,9 +1,7 @@
|
||||
/*
|
||||
* Probe for F81216A LPC to 4 UART
|
||||
*
|
||||
* Based on drivers/tty/serial/8250_pnp.c, by Russell King, et al
|
||||
*
|
||||
* Copyright (C) 2014 Ricardo Ribalda, Qtechnology A/S
|
||||
* Copyright (C) 2014-2016 Ricardo Ribalda, Qtechnology A/S
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -38,19 +36,15 @@
|
||||
#define RXW4C_IRA BIT(3)
|
||||
#define TXW4C_IRA BIT(2)
|
||||
|
||||
#define DRIVER_NAME "8250_fintek"
|
||||
|
||||
struct fintek_8250 {
|
||||
u16 base_port;
|
||||
u8 index;
|
||||
u8 key;
|
||||
long line;
|
||||
};
|
||||
|
||||
static int fintek_8250_enter_key(u16 base_port, u8 key)
|
||||
{
|
||||
|
||||
if (!request_muxed_region(base_port, 2, DRIVER_NAME))
|
||||
if (!request_muxed_region(base_port, 2, "8250_fintek"))
|
||||
return -EBUSY;
|
||||
|
||||
outb(key, base_port + ADDR_PORT);
|
||||
@@ -138,7 +132,7 @@ static int fintek_8250_rs485_config(struct uart_port *port,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index)
|
||||
static int find_base_port(struct fintek_8250 *pdata, u16 io_address)
|
||||
{
|
||||
static const u16 addr[] = {0x4e, 0x2e};
|
||||
static const u8 keys[] = {0x77, 0xa0, 0x87, 0x67};
|
||||
@@ -168,10 +162,13 @@ static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index)
|
||||
continue;
|
||||
|
||||
fintek_8250_exit_key(addr[i]);
|
||||
*key = keys[j];
|
||||
*index = k;
|
||||
return addr[i];
|
||||
pdata->key = keys[j];
|
||||
pdata->base_port = addr[i];
|
||||
pdata->index = k;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fintek_8250_exit_key(addr[i]);
|
||||
}
|
||||
}
|
||||
@@ -179,104 +176,21 @@ static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int
|
||||
fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
|
||||
int fintek_8250_probe(struct uart_8250_port *uart)
|
||||
{
|
||||
struct uart_8250_port uart;
|
||||
struct fintek_8250 *pdata;
|
||||
int base_port;
|
||||
u8 key;
|
||||
u8 index;
|
||||
struct fintek_8250 probe_data;
|
||||
|
||||
if (!pnp_port_valid(dev, 0))
|
||||
if (find_base_port(&probe_data, uart->port.iobase))
|
||||
return -ENODEV;
|
||||
|
||||
base_port = fintek_8250_base_port(pnp_port_start(dev, 0), &key, &index);
|
||||
if (base_port < 0)
|
||||
return -ENODEV;
|
||||
|
||||
memset(&uart, 0, sizeof(uart));
|
||||
|
||||
pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
pdata = devm_kzalloc(uart->port.dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
uart.port.private_data = pdata;
|
||||
|
||||
if (!pnp_irq_valid(dev, 0))
|
||||
return -ENODEV;
|
||||
uart.port.irq = pnp_irq(dev, 0);
|
||||
uart.port.iobase = pnp_port_start(dev, 0);
|
||||
uart.port.iotype = UPIO_PORT;
|
||||
uart.port.rs485_config = fintek_8250_rs485_config;
|
||||
memcpy(pdata, &probe_data, sizeof(probe_data));
|
||||
uart->port.rs485_config = fintek_8250_rs485_config;
|
||||
uart->port.private_data = pdata;
|
||||
|
||||
uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
|
||||
if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
|
||||
uart.port.flags |= UPF_SHARE_IRQ;
|
||||
uart.port.uartclk = 1843200;
|
||||
uart.port.dev = &dev->dev;
|
||||
|
||||
pdata->key = key;
|
||||
pdata->base_port = base_port;
|
||||
pdata->index = index;
|
||||
pdata->line = serial8250_register_8250_port(&uart);
|
||||
if (pdata->line < 0)
|
||||
return -ENODEV;
|
||||
|
||||
pnp_set_drvdata(dev, pdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fintek_8250_remove(struct pnp_dev *dev)
|
||||
{
|
||||
struct fintek_8250 *pdata = pnp_get_drvdata(dev);
|
||||
|
||||
if (pdata)
|
||||
serial8250_unregister_port(pdata->line);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int fintek_8250_suspend(struct pnp_dev *dev, pm_message_t state)
|
||||
{
|
||||
struct fintek_8250 *pdata = pnp_get_drvdata(dev);
|
||||
|
||||
if (!pdata)
|
||||
return -ENODEV;
|
||||
serial8250_suspend_port(pdata->line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fintek_8250_resume(struct pnp_dev *dev)
|
||||
{
|
||||
struct fintek_8250 *pdata = pnp_get_drvdata(dev);
|
||||
|
||||
if (!pdata)
|
||||
return -ENODEV;
|
||||
serial8250_resume_port(pdata->line);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define fintek_8250_suspend NULL
|
||||
#define fintek_8250_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct pnp_device_id fintek_dev_table[] = {
|
||||
/* Qtechnology Panel PC / IO1000 */
|
||||
{ "PNP0501"},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pnp, fintek_dev_table);
|
||||
|
||||
static struct pnp_driver fintek_8250_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe = fintek_8250_probe,
|
||||
.remove = fintek_8250_remove,
|
||||
.suspend = fintek_8250_suspend,
|
||||
.resume = fintek_8250_resume,
|
||||
.id_table = fintek_dev_table,
|
||||
};
|
||||
|
||||
module_pnp_driver(fintek_8250_driver);
|
||||
MODULE_DESCRIPTION("Fintek F812164 module");
|
||||
MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@@ -9,11 +9,13 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/rational.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/rational.h>
|
||||
|
||||
#include <linux/dma/hsu.h>
|
||||
#include <linux/8250_pci.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
@@ -24,6 +26,7 @@
|
||||
#define PCI_DEVICE_ID_INTEL_DNV_UART 0x19d8
|
||||
|
||||
/* Intel MID Specific registers */
|
||||
#define INTEL_MID_UART_DNV_FISR 0x08
|
||||
#define INTEL_MID_UART_PS 0x30
|
||||
#define INTEL_MID_UART_MUL 0x34
|
||||
#define INTEL_MID_UART_DIV 0x38
|
||||
@@ -31,6 +34,7 @@
|
||||
struct mid8250;
|
||||
|
||||
struct mid8250_board {
|
||||
unsigned int flags;
|
||||
unsigned long freq;
|
||||
unsigned int base_baud;
|
||||
int (*setup)(struct mid8250 *, struct uart_port *p);
|
||||
@@ -76,7 +80,11 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p)
|
||||
struct pci_dev *pdev = to_pci_dev(p->dev);
|
||||
int index = PCI_FUNC(pdev->devfn);
|
||||
|
||||
/* Currently no support for HSU port0 */
|
||||
/*
|
||||
* Device 0000:00:04.0 is not a real HSU port. It provides a global
|
||||
* register set for all HSU ports, although it has the same PCI ID.
|
||||
* Skip it here.
|
||||
*/
|
||||
if (index-- == 0)
|
||||
return -ENODEV;
|
||||
|
||||
@@ -88,16 +96,16 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p)
|
||||
static int dnv_handle_irq(struct uart_port *p)
|
||||
{
|
||||
struct mid8250 *mid = p->private_data;
|
||||
int ret;
|
||||
unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR);
|
||||
int ret = IRQ_NONE;
|
||||
|
||||
ret = hsu_dma_irq(&mid->dma_chip, 0);
|
||||
ret |= hsu_dma_irq(&mid->dma_chip, 1);
|
||||
|
||||
/* For now, letting the HW generate separate interrupt for the UART */
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
|
||||
if (fisr & BIT(2))
|
||||
ret |= hsu_dma_irq(&mid->dma_chip, 1);
|
||||
if (fisr & BIT(1))
|
||||
ret |= hsu_dma_irq(&mid->dma_chip, 0);
|
||||
if (fisr & BIT(0))
|
||||
ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define DNV_DMA_CHAN_OFFSET 0x80
|
||||
@@ -106,12 +114,13 @@ static int dnv_setup(struct mid8250 *mid, struct uart_port *p)
|
||||
{
|
||||
struct hsu_dma_chip *chip = &mid->dma_chip;
|
||||
struct pci_dev *pdev = to_pci_dev(p->dev);
|
||||
unsigned int bar = FL_GET_BASE(mid->board->flags);
|
||||
int ret;
|
||||
|
||||
chip->dev = &pdev->dev;
|
||||
chip->irq = pdev->irq;
|
||||
chip->regs = p->membase;
|
||||
chip->length = pci_resource_len(pdev, 0);
|
||||
chip->length = pci_resource_len(pdev, bar);
|
||||
chip->offset = DNV_DMA_CHAN_OFFSET;
|
||||
|
||||
/* Falling back to PIO mode if DMA probing fails */
|
||||
@@ -217,6 +226,7 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
struct uart_8250_port uart;
|
||||
struct mid8250 *mid;
|
||||
unsigned int bar;
|
||||
int ret;
|
||||
|
||||
ret = pcim_enable_device(pdev);
|
||||
@@ -230,6 +240,7 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
return -ENOMEM;
|
||||
|
||||
mid->board = (struct mid8250_board *)id->driver_data;
|
||||
bar = FL_GET_BASE(mid->board->flags);
|
||||
|
||||
memset(&uart, 0, sizeof(struct uart_8250_port));
|
||||
|
||||
@@ -242,8 +253,8 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE;
|
||||
uart.port.set_termios = mid8250_set_termios;
|
||||
|
||||
uart.port.mapbase = pci_resource_start(pdev, 0);
|
||||
uart.port.membase = pcim_iomap(pdev, 0, 0);
|
||||
uart.port.mapbase = pci_resource_start(pdev, bar);
|
||||
uart.port.membase = pcim_iomap(pdev, bar, 0);
|
||||
if (!uart.port.membase)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -282,18 +293,21 @@ static void mid8250_remove(struct pci_dev *pdev)
|
||||
}
|
||||
|
||||
static const struct mid8250_board pnw_board = {
|
||||
.flags = FL_BASE0,
|
||||
.freq = 50000000,
|
||||
.base_baud = 115200,
|
||||
.setup = pnw_setup,
|
||||
};
|
||||
|
||||
static const struct mid8250_board tng_board = {
|
||||
.flags = FL_BASE0,
|
||||
.freq = 38400000,
|
||||
.base_baud = 1843200,
|
||||
.setup = tng_setup,
|
||||
};
|
||||
|
||||
static const struct mid8250_board dnv_board = {
|
||||
.flags = FL_BASE1,
|
||||
.freq = 133333333,
|
||||
.base_baud = 115200,
|
||||
.setup = dnv_setup,
|
||||
|
@@ -29,7 +29,7 @@ struct of_serial_info {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA
|
||||
void tegra_serial_handle_break(struct uart_port *p)
|
||||
static void tegra_serial_handle_break(struct uart_port *p)
|
||||
{
|
||||
unsigned int status, tmout = 10000;
|
||||
|
||||
|
@@ -115,6 +115,12 @@ struct omap8250_priv {
|
||||
bool rx_dma_broken;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
static void omap_8250_rx_dma_flush(struct uart_8250_port *p);
|
||||
#else
|
||||
static inline void omap_8250_rx_dma_flush(struct uart_8250_port *p) { }
|
||||
#endif
|
||||
|
||||
static u32 uart_read(struct uart_8250_port *up, u32 reg)
|
||||
{
|
||||
return readl(up->port.membase + (reg << up->port.regshift));
|
||||
@@ -635,7 +641,7 @@ static int omap_8250_startup(struct uart_port *port)
|
||||
serial_out(up, UART_OMAP_WER, priv->wer);
|
||||
|
||||
if (up->dma)
|
||||
up->dma->rx_dma(up, 0);
|
||||
up->dma->rx_dma(up);
|
||||
|
||||
pm_runtime_mark_last_busy(port->dev);
|
||||
pm_runtime_put_autosuspend(port->dev);
|
||||
@@ -654,7 +660,7 @@ static void omap_8250_shutdown(struct uart_port *port)
|
||||
|
||||
flush_work(&priv->qos_work);
|
||||
if (up->dma)
|
||||
up->dma->rx_dma(up, UART_IIR_RX_TIMEOUT);
|
||||
omap_8250_rx_dma_flush(up);
|
||||
|
||||
pm_runtime_get_sync(port->dev);
|
||||
|
||||
@@ -742,9 +748,9 @@ static void omap_8250_unthrottle(struct uart_port *port)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir);
|
||||
static int omap_8250_rx_dma(struct uart_8250_port *p);
|
||||
|
||||
static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
|
||||
static void __dma_rx_do_complete(struct uart_8250_port *p)
|
||||
{
|
||||
struct omap8250_priv *priv = p->port.private_data;
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
@@ -754,9 +760,6 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
|
||||
dma->rx_size, DMA_FROM_DEVICE);
|
||||
|
||||
spin_lock_irqsave(&priv->rx_dma_lock, flags);
|
||||
|
||||
if (!dma->rx_running)
|
||||
@@ -764,7 +767,6 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
|
||||
|
||||
dma->rx_running = 0;
|
||||
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
||||
dmaengine_terminate_all(dma->rxchan);
|
||||
|
||||
count = dma->rx_size - state.residue;
|
||||
|
||||
@@ -775,15 +777,13 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
|
||||
|
||||
if (!error)
|
||||
omap_8250_rx_dma(p, 0);
|
||||
|
||||
tty_flip_buffer_push(tty_port);
|
||||
}
|
||||
|
||||
static void __dma_rx_complete(void *param)
|
||||
{
|
||||
__dma_rx_do_complete(param, false);
|
||||
__dma_rx_do_complete(param);
|
||||
omap_8250_rx_dma(param);
|
||||
}
|
||||
|
||||
static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
|
||||
@@ -806,10 +806,11 @@ static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
|
||||
|
||||
spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
|
||||
|
||||
__dma_rx_do_complete(p, true);
|
||||
__dma_rx_do_complete(p);
|
||||
dmaengine_terminate_all(dma->rxchan);
|
||||
}
|
||||
|
||||
static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
||||
static int omap_8250_rx_dma(struct uart_8250_port *p)
|
||||
{
|
||||
struct omap8250_priv *priv = p->port.private_data;
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
@@ -817,35 +818,6 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
unsigned long flags;
|
||||
|
||||
switch (iir & 0x3f) {
|
||||
case UART_IIR_RLSI:
|
||||
/* 8250_core handles errors and break interrupts */
|
||||
omap_8250_rx_dma_flush(p);
|
||||
return -EIO;
|
||||
case UART_IIR_RX_TIMEOUT:
|
||||
/*
|
||||
* If RCVR FIFO trigger level was not reached, complete the
|
||||
* transfer and let 8250_core copy the remaining data.
|
||||
*/
|
||||
omap_8250_rx_dma_flush(p);
|
||||
return -ETIMEDOUT;
|
||||
case UART_IIR_RDI:
|
||||
/*
|
||||
* The OMAP UART is a special BEAST. If we receive RDI we _have_
|
||||
* a DMA transfer programmed but it didn't work. One reason is
|
||||
* that we were too slow and there were too many bytes in the
|
||||
* FIFO, the UART counted wrong and never kicked the DMA engine
|
||||
* to do anything. That means once we receive RDI on OMAP then
|
||||
* the DMA won't do anything soon so we have to cancel the DMA
|
||||
* transfer and purge the FIFO manually.
|
||||
*/
|
||||
omap_8250_rx_dma_flush(p);
|
||||
return -ETIMEDOUT;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (priv->rx_dma_broken)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -868,9 +840,6 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
||||
|
||||
dma->rx_cookie = dmaengine_submit(desc);
|
||||
|
||||
dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr,
|
||||
dma->rx_size, DMA_FROM_DEVICE);
|
||||
|
||||
dma_async_issue_pending(dma->rxchan);
|
||||
out:
|
||||
spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
|
||||
@@ -1022,6 +991,18 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
|
||||
{
|
||||
switch (iir & 0x3f) {
|
||||
case UART_IIR_RLSI:
|
||||
case UART_IIR_RX_TIMEOUT:
|
||||
case UART_IIR_RDI:
|
||||
omap_8250_rx_dma_flush(up);
|
||||
return true;
|
||||
}
|
||||
return omap_8250_rx_dma(up);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is mostly serial8250_handle_irq(). We have a slightly different DMA
|
||||
* hoook for RX/TX and need different logic for them in the ISR. Therefore we
|
||||
@@ -1033,7 +1014,6 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
|
||||
unsigned char status;
|
||||
unsigned long flags;
|
||||
u8 iir;
|
||||
int dma_err = 0;
|
||||
|
||||
serial8250_rpm_get(up);
|
||||
|
||||
@@ -1048,11 +1028,9 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
|
||||
status = serial_port_in(port, UART_LSR);
|
||||
|
||||
if (status & (UART_LSR_DR | UART_LSR_BI)) {
|
||||
|
||||
dma_err = omap_8250_rx_dma(up, iir);
|
||||
if (dma_err) {
|
||||
if (handle_rx_dma(up, iir)) {
|
||||
status = serial8250_rx_chars(up, status);
|
||||
omap_8250_rx_dma(up, 0);
|
||||
omap_8250_rx_dma(up);
|
||||
}
|
||||
}
|
||||
serial8250_modem_status(up);
|
||||
@@ -1066,8 +1044,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
|
||||
* try again due to an earlier failer which
|
||||
* might have been resolved by now.
|
||||
*/
|
||||
dma_err = omap_8250_tx_dma(up);
|
||||
if (dma_err)
|
||||
if (omap_8250_tx_dma(up))
|
||||
serial8250_tx_chars(up);
|
||||
}
|
||||
}
|
||||
@@ -1084,7 +1061,7 @@ static bool the_no_dma_filter_fn(struct dma_chan *chan, void *param)
|
||||
|
||||
#else
|
||||
|
||||
static inline int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
||||
static inline int omap_8250_rx_dma(struct uart_8250_port *p)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1395,7 +1372,7 @@ static int omap8250_runtime_suspend(struct device *dev)
|
||||
}
|
||||
|
||||
if (up->dma && up->dma->rxchan)
|
||||
omap_8250_rx_dma(up, UART_IIR_RX_TIMEOUT);
|
||||
omap_8250_rx_dma_flush(up);
|
||||
|
||||
priv->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
|
||||
schedule_work(&priv->qos_work);
|
||||
@@ -1407,20 +1384,18 @@ static int omap8250_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct omap8250_priv *priv = dev_get_drvdata(dev);
|
||||
struct uart_8250_port *up;
|
||||
int loss_cntx;
|
||||
|
||||
/* In case runtime-pm tries this before we are setup */
|
||||
if (!priv)
|
||||
return 0;
|
||||
|
||||
up = serial8250_get_port(priv->line);
|
||||
loss_cntx = omap8250_lost_context(up);
|
||||
|
||||
if (loss_cntx)
|
||||
if (omap8250_lost_context(up))
|
||||
omap8250_restore_regs(up);
|
||||
|
||||
if (up->dma && up->dma->rxchan)
|
||||
omap_8250_rx_dma(up, 0);
|
||||
omap_8250_rx_dma(up);
|
||||
|
||||
priv->latency = priv->calc_latency;
|
||||
schedule_work(&priv->qos_work);
|
||||
|
@@ -1377,6 +1377,9 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios,
|
||||
unsigned long m, n;
|
||||
u32 reg;
|
||||
|
||||
/* Gracefully handle the B0 case: fall back to B9600 */
|
||||
fuart = fuart ? fuart : 9600 * 16;
|
||||
|
||||
/* Get Fuart closer to Fref */
|
||||
fuart *= rounddown_pow_of_two(fref / fuart);
|
||||
|
||||
@@ -1413,6 +1416,17 @@ static bool byt_dma_filter(struct dma_chan *chan, void *param)
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
byt_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
unsigned int ret = serial8250_do_get_mctrl(port);
|
||||
|
||||
/* Force DCD and DSR signals to permanently be reported as active. */
|
||||
ret |= TIOCM_CAR | TIOCM_DSR;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
byt_serial_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
@@ -1477,6 +1491,7 @@ byt_serial_setup(struct serial_private *priv,
|
||||
port->port.type = PORT_16550A;
|
||||
port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
|
||||
port->port.set_termios = byt_set_termios;
|
||||
port->port.get_mctrl = byt_get_mctrl;
|
||||
port->port.fifosize = 64;
|
||||
port->tx_loadsz = 64;
|
||||
port->dma = dma;
|
||||
|
@@ -1315,6 +1315,13 @@ static void autoconfig(struct uart_8250_port *up)
|
||||
|
||||
out_lock:
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
/*
|
||||
* Check if the device is a Fintek F81216A
|
||||
*/
|
||||
if (port->type == PORT_16550A)
|
||||
fintek_8250_probe(up);
|
||||
|
||||
if (up->capabilities != old_capabilities) {
|
||||
pr_warn("ttyS%d: detected caps %08x should be %08x\n",
|
||||
serial_index(port), old_capabilities,
|
||||
@@ -1788,6 +1795,18 @@ unsigned int serial8250_modem_status(struct uart_8250_port *up)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_modem_status);
|
||||
|
||||
static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
|
||||
{
|
||||
switch (iir & 0x3f) {
|
||||
case UART_IIR_RX_TIMEOUT:
|
||||
serial8250_rx_dma_flush(up);
|
||||
/* fall-through */
|
||||
case UART_IIR_RLSI:
|
||||
return true;
|
||||
}
|
||||
return up->dma->rx_dma(up);
|
||||
}
|
||||
|
||||
/*
|
||||
* This handles the interrupt from one port.
|
||||
*/
|
||||
@@ -1796,7 +1815,6 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
|
||||
unsigned char status;
|
||||
unsigned long flags;
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
int dma_err = 0;
|
||||
|
||||
if (iir & UART_IIR_NO_INT)
|
||||
return 0;
|
||||
@@ -1808,15 +1826,11 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
|
||||
DEBUG_INTR("status = %x...", status);
|
||||
|
||||
if (status & (UART_LSR_DR | UART_LSR_BI)) {
|
||||
if (up->dma)
|
||||
dma_err = up->dma->rx_dma(up, iir);
|
||||
|
||||
if (!up->dma || dma_err)
|
||||
if (!up->dma || handle_rx_dma(up, iir))
|
||||
status = serial8250_rx_chars(up, status);
|
||||
}
|
||||
serial8250_modem_status(up);
|
||||
if ((!up->dma || (up->dma && up->dma->tx_err)) &&
|
||||
(status & UART_LSR_THRE))
|
||||
if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE))
|
||||
serial8250_tx_chars(up);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
@@ -1882,7 +1896,7 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
|
||||
return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0;
|
||||
}
|
||||
|
||||
static unsigned int serial8250_get_mctrl(struct uart_port *port)
|
||||
unsigned int serial8250_do_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
unsigned int status;
|
||||
@@ -1903,6 +1917,14 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port)
|
||||
ret |= TIOCM_CTS;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_do_get_mctrl);
|
||||
|
||||
static unsigned int serial8250_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
if (port->get_mctrl)
|
||||
return port->get_mctrl(port);
|
||||
return serial8250_do_get_mctrl(port);
|
||||
}
|
||||
|
||||
void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
|
@@ -209,7 +209,7 @@ static int uniphier_uart_probe(struct platform_device *pdev)
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "failed to get IRQ number");
|
||||
dev_err(dev, "failed to get IRQ number\n");
|
||||
return irq;
|
||||
}
|
||||
|
||||
|
@@ -57,6 +57,18 @@ config SERIAL_8250_PNP
|
||||
This builds standard PNP serial support. You may be able to
|
||||
disable this feature if you only need legacy serial support.
|
||||
|
||||
config SERIAL_8250_FINTEK
|
||||
bool "Support for Fintek F81216A LPC to 4 UART RS485 API"
|
||||
depends on SERIAL_8250
|
||||
---help---
|
||||
Selecting this option will add support for the RS485 capabilities
|
||||
of the Fintek F81216A LPC to 4 UART.
|
||||
|
||||
If this option is not selected the device will be configured as a
|
||||
standard 16550A serial port.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SERIAL_8250_CONSOLE
|
||||
bool "Console on 8250/16550 and compatible serial port"
|
||||
depends on SERIAL_8250=y
|
||||
@@ -358,14 +370,6 @@ config SERIAL_8250_OMAP_TTYO_FIXUP
|
||||
not booting kernel because the serial console remains silent in case
|
||||
they forgot to update the command line.
|
||||
|
||||
config SERIAL_8250_FINTEK
|
||||
tristate "Support for Fintek F81216A LPC to 4 UART"
|
||||
depends on SERIAL_8250 && PNP
|
||||
help
|
||||
Selecting this option will add support for the Fintek F81216A
|
||||
LPC to 4 UART. This device has some RS485 functionality not available
|
||||
through the PNP driver. If unsure, say N.
|
||||
|
||||
config SERIAL_8250_LPC18XX
|
||||
tristate "NXP LPC18xx/43xx serial port support"
|
||||
depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST)
|
||||
@@ -398,8 +402,10 @@ config SERIAL_8250_INGENIC
|
||||
its UARTs, say Y to this option. If unsure, say N.
|
||||
|
||||
config SERIAL_8250_MID
|
||||
tristate "Support for serial ports on Intel MID platforms"
|
||||
tristate "Support for serial ports on Intel MID platforms" if EXPERT
|
||||
default SERIAL_8250
|
||||
depends on SERIAL_8250 && PCI
|
||||
depends on X86 || COMPILE_TEST
|
||||
select HSU_DMA if SERIAL_8250_DMA
|
||||
select HSU_DMA_PCI if (HSU_DMA && X86_INTEL_MID)
|
||||
select RATIONAL
|
||||
|
@@ -7,6 +7,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o
|
||||
8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
|
||||
8250_base-y := 8250_port.o
|
||||
8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o
|
||||
8250_base-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o
|
||||
obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
|
||||
obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
|
||||
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
|
||||
@@ -23,7 +24,6 @@ obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
|
||||
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
|
||||
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
|
||||
obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o
|
||||
obj-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o
|
||||
obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o
|
||||
obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
|
||||
obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o
|
||||
|
@@ -213,6 +213,7 @@ config SERIAL_MESON_CONSOLE
|
||||
bool "Support for console on meson"
|
||||
depends on SERIAL_MESON=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON
|
||||
help
|
||||
Say Y here if you wish to use a Amlogic MesonX UART as the
|
||||
system console (the system console is the device which
|
||||
@@ -1404,11 +1405,12 @@ config SERIAL_PCH_UART_CONSOLE
|
||||
config SERIAL_MXS_AUART
|
||||
tristate "MXS AUART support"
|
||||
depends on HAS_DMA
|
||||
depends on ARCH_MXS || COMPILE_TEST
|
||||
depends on ARCH_MXS || MACH_ASM9260 || COMPILE_TEST
|
||||
select SERIAL_CORE
|
||||
select SERIAL_MCTRL_GPIO if GPIOLIB
|
||||
help
|
||||
This driver supports the MXS Application UART (AUART) port.
|
||||
This driver supports the MXS and Alphascale ASM9260 Application
|
||||
UART (AUART) port.
|
||||
|
||||
config SERIAL_MXS_AUART_CONSOLE
|
||||
bool "MXS AUART console support"
|
||||
@@ -1467,6 +1469,19 @@ config SERIAL_EFM32_UART
|
||||
This driver support the USART and UART ports on
|
||||
Energy Micro's efm32 SoCs.
|
||||
|
||||
config SERIAL_MPS2_UART_CONSOLE
|
||||
bool "MPS2 UART console support"
|
||||
depends on SERIAL_MPS2_UART
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON
|
||||
|
||||
config SERIAL_MPS2_UART
|
||||
bool "MPS2 UART port"
|
||||
depends on ARM || COMPILE_TEST
|
||||
select SERIAL_CORE
|
||||
help
|
||||
This driver support the UART ports on ARM MPS2.
|
||||
|
||||
config SERIAL_EFM32_UART_CONSOLE
|
||||
bool "EFM32 UART/USART console support"
|
||||
depends on SERIAL_EFM32_UART=y
|
||||
@@ -1625,6 +1640,7 @@ config SERIAL_STM32_CONSOLE
|
||||
|
||||
config SERIAL_MVEBU_UART
|
||||
bool "Marvell EBU serial port support"
|
||||
depends on ARCH_MVEBU || COMPILE_TEST
|
||||
select SERIAL_CORE
|
||||
help
|
||||
This driver is for Marvell EBU SoC's UART. If you have a machine
|
||||
|
@@ -92,6 +92,7 @@ obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
|
||||
obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o
|
||||
obj-$(CONFIG_SERIAL_MVEBU_UART) += mvebu-uart.o
|
||||
obj-$(CONFIG_SERIAL_PIC32) += pic32_uart.o
|
||||
obj-$(CONFIG_SERIAL_MPS2_UART) += mps2-uart.o
|
||||
|
||||
# GPIOLIB helpers for modem control lines
|
||||
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
|
||||
|
@@ -121,6 +121,7 @@ static struct vendor_data vendor_arm = {
|
||||
|
||||
static struct vendor_data vendor_sbsa = {
|
||||
.reg_offset = pl011_std_offsets,
|
||||
.access_32b = true,
|
||||
.oversampling = false,
|
||||
.dma_threshold = false,
|
||||
.cts_event_workaround = false,
|
||||
|
@@ -274,6 +274,13 @@ static bool atmel_use_dma_rx(struct uart_port *port)
|
||||
return atmel_port->use_dma_rx;
|
||||
}
|
||||
|
||||
static bool atmel_use_fifo(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
|
||||
return atmel_port->fifo_size;
|
||||
}
|
||||
|
||||
static unsigned int atmel_get_lines_status(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
@@ -2090,7 +2097,12 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
mode |= ATMEL_US_USMODE_RS485;
|
||||
} else if (termios->c_cflag & CRTSCTS) {
|
||||
/* RS232 with hardware handshake (RTS/CTS) */
|
||||
mode |= ATMEL_US_USMODE_HWHS;
|
||||
if (atmel_use_dma_rx(port) && !atmel_use_fifo(port)) {
|
||||
dev_info(port->dev, "not enabling hardware flow control because DMA is used");
|
||||
termios->c_cflag &= ~CRTSCTS;
|
||||
} else {
|
||||
mode |= ATMEL_US_USMODE_HWHS;
|
||||
}
|
||||
} else {
|
||||
/* RS232 without hadware handshake */
|
||||
mode |= ATMEL_US_USMODE_NORMAL;
|
||||
|
@@ -2599,7 +2599,7 @@ startup(struct e100_serial * info)
|
||||
|
||||
/* if it was already initialized, skip this */
|
||||
|
||||
if (info->port.flags & ASYNC_INITIALIZED) {
|
||||
if (tty_port_initialized(&info->port)) {
|
||||
local_irq_restore(flags);
|
||||
free_page(xmit_page);
|
||||
return 0;
|
||||
@@ -2703,7 +2703,7 @@ startup(struct e100_serial * info)
|
||||
e100_rts(info, 1);
|
||||
e100_dtr(info, 1);
|
||||
|
||||
info->port.flags |= ASYNC_INITIALIZED;
|
||||
tty_port_set_initialized(&info->port, 1);
|
||||
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
@@ -2745,7 +2745,7 @@ shutdown(struct e100_serial * info)
|
||||
info->tr_running = 0;
|
||||
}
|
||||
|
||||
if (!(info->port.flags & ASYNC_INITIALIZED))
|
||||
if (!tty_port_initialized(&info->port))
|
||||
return;
|
||||
|
||||
#ifdef SERIAL_DEBUG_OPEN
|
||||
@@ -2776,7 +2776,7 @@ shutdown(struct e100_serial * info)
|
||||
if (info->port.tty)
|
||||
set_bit(TTY_IO_ERROR, &info->port.tty->flags);
|
||||
|
||||
info->port.flags &= ~ASYNC_INITIALIZED;
|
||||
tty_port_set_initialized(&info->port, 0);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
@@ -3273,9 +3273,9 @@ set_serial_info(struct e100_serial *info,
|
||||
info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
check_and_exit:
|
||||
if (info->port.flags & ASYNC_INITIALIZED) {
|
||||
if (tty_port_initialized(&info->port))
|
||||
change_speed(info);
|
||||
} else
|
||||
else
|
||||
retval = startup(info);
|
||||
return retval;
|
||||
}
|
||||
@@ -3445,7 +3445,7 @@ rs_ioctl(struct tty_struct *tty,
|
||||
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
|
||||
(cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
|
||||
(cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
|
||||
if (tty->flags & (1 << TTY_IO_ERROR))
|
||||
if (tty_io_error(tty))
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -3628,7 +3628,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
|
||||
e100_disable_rx(info);
|
||||
e100_disable_rx_irq(info);
|
||||
|
||||
if (info->port.flags & ASYNC_INITIALIZED) {
|
||||
if (tty_port_initialized(&info->port)) {
|
||||
/*
|
||||
* Before we drop DTR, make sure the UART transmitter
|
||||
* has completely drained; this is especially
|
||||
@@ -3648,8 +3648,8 @@ rs_close(struct tty_struct *tty, struct file * filp)
|
||||
schedule_timeout_interruptible(info->port.close_delay);
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
}
|
||||
info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
local_irq_restore(flags);
|
||||
tty_port_set_active(&info->port, 0);
|
||||
|
||||
/* port closed */
|
||||
|
||||
@@ -3732,7 +3732,7 @@ rs_hangup(struct tty_struct *tty)
|
||||
shutdown(info);
|
||||
info->event = 0;
|
||||
info->port.count = 0;
|
||||
info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
tty_port_set_active(&info->port, 0);
|
||||
info->port.tty = NULL;
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
}
|
||||
@@ -3755,9 +3755,8 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||
* If non-blocking mode is set, or the port is not enabled,
|
||||
* then make the check up front and then exit.
|
||||
*/
|
||||
if ((filp->f_flags & O_NONBLOCK) ||
|
||||
(tty->flags & (1 << TTY_IO_ERROR))) {
|
||||
info->port.flags |= ASYNC_NORMAL_ACTIVE;
|
||||
if ((filp->f_flags & O_NONBLOCK) || tty_io_error(tty)) {
|
||||
tty_port_set_active(&info->port, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3788,8 +3787,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||
e100_dtr(info, 1);
|
||||
local_irq_restore(flags);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (tty_hung_up_p(filp) ||
|
||||
!(info->port.flags & ASYNC_INITIALIZED)) {
|
||||
if (tty_hung_up_p(filp) || !tty_port_initialized(&info->port)) {
|
||||
#ifdef SERIAL_DO_RESTART
|
||||
if (info->port.flags & ASYNC_HUP_NOTIFY)
|
||||
retval = -EAGAIN;
|
||||
@@ -3826,7 +3824,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||
#endif
|
||||
if (retval)
|
||||
return retval;
|
||||
info->port.flags |= ASYNC_NORMAL_ACTIVE;
|
||||
tty_port_set_active(&info->port, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -651,7 +651,7 @@ static void ifx_spi_complete(void *ctx)
|
||||
struct ifx_spi_device *ifx_dev = ctx;
|
||||
int length;
|
||||
int actual_length;
|
||||
unsigned char more;
|
||||
unsigned char more = 0;
|
||||
unsigned char cts;
|
||||
int local_write_pending = 0;
|
||||
int queue_length;
|
||||
|
@@ -114,6 +114,7 @@
|
||||
#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */
|
||||
#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */
|
||||
#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */
|
||||
#define UCR3_DTRDEN (1<<3) /* Data Terminal Ready Delta Enable. */
|
||||
#define IMX21_UCR3_RXDMUXSEL (1<<2) /* RXD Muxed Input Select */
|
||||
#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */
|
||||
#define UCR3_BPEN (1<<0) /* Preset registers enable */
|
||||
@@ -142,7 +143,7 @@
|
||||
#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */
|
||||
#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */
|
||||
#define USR1_AGTIM (1<<8) /* Ageing timer interrupt flag */
|
||||
#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */
|
||||
#define USR1_DTRD (1<<7) /* DTR Delta */
|
||||
#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */
|
||||
#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */
|
||||
#define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */
|
||||
@@ -361,6 +362,7 @@ static void imx_stop_tx(struct uart_port *port)
|
||||
imx_port_rts_inactive(sport, &temp);
|
||||
else
|
||||
imx_port_rts_active(sport, &temp);
|
||||
temp |= UCR2_RXEN;
|
||||
writel(temp, port->membase + UCR2);
|
||||
|
||||
temp = readl(port->membase + UCR4);
|
||||
@@ -568,6 +570,8 @@ static void imx_start_tx(struct uart_port *port)
|
||||
imx_port_rts_inactive(sport, &temp);
|
||||
else
|
||||
imx_port_rts_active(sport, &temp);
|
||||
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
temp &= ~UCR2_RXEN;
|
||||
writel(temp, port->membase + UCR2);
|
||||
|
||||
/* enable transmitter and shifter empty irq */
|
||||
@@ -729,11 +733,61 @@ static void imx_dma_rxint(struct imx_port *sport)
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have a modem side uart, so the meanings of RTS and CTS are inverted.
|
||||
*/
|
||||
static unsigned int imx_get_hwmctrl(struct imx_port *sport)
|
||||
{
|
||||
unsigned int tmp = TIOCM_DSR;
|
||||
unsigned usr1 = readl(sport->port.membase + USR1);
|
||||
|
||||
if (usr1 & USR1_RTSS)
|
||||
tmp |= TIOCM_CTS;
|
||||
|
||||
/* in DCE mode DCDIN is always 0 */
|
||||
if (!(usr1 & USR2_DCDIN))
|
||||
tmp |= TIOCM_CAR;
|
||||
|
||||
if (sport->dte_mode)
|
||||
if (!(readl(sport->port.membase + USR2) & USR2_RIIN))
|
||||
tmp |= TIOCM_RI;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle any change of modem status signal since we were last called.
|
||||
*/
|
||||
static void imx_mctrl_check(struct imx_port *sport)
|
||||
{
|
||||
unsigned int status, changed;
|
||||
|
||||
status = imx_get_hwmctrl(sport);
|
||||
changed = status ^ sport->old_status;
|
||||
|
||||
if (changed == 0)
|
||||
return;
|
||||
|
||||
sport->old_status = status;
|
||||
|
||||
if (changed & TIOCM_RI && status & TIOCM_RI)
|
||||
sport->port.icount.rng++;
|
||||
if (changed & TIOCM_DSR)
|
||||
sport->port.icount.dsr++;
|
||||
if (changed & TIOCM_CAR)
|
||||
uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
|
||||
if (changed & TIOCM_CTS)
|
||||
uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
|
||||
|
||||
wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
|
||||
}
|
||||
|
||||
static irqreturn_t imx_int(int irq, void *dev_id)
|
||||
{
|
||||
struct imx_port *sport = dev_id;
|
||||
unsigned int sts;
|
||||
unsigned int sts2;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
|
||||
sts = readl(sport->port.membase + USR1);
|
||||
sts2 = readl(sport->port.membase + USR2);
|
||||
@@ -743,26 +797,47 @@ static irqreturn_t imx_int(int irq, void *dev_id)
|
||||
imx_dma_rxint(sport);
|
||||
else
|
||||
imx_rxint(irq, dev_id);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if ((sts & USR1_TRDY &&
|
||||
readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) ||
|
||||
(sts2 & USR2_TXDC &&
|
||||
readl(sport->port.membase + UCR4) & UCR4_TCEN))
|
||||
readl(sport->port.membase + UCR4) & UCR4_TCEN)) {
|
||||
imx_txint(irq, dev_id);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (sts & USR1_RTSD)
|
||||
if (sts & USR1_DTRD) {
|
||||
unsigned long flags;
|
||||
|
||||
if (sts & USR1_DTRD)
|
||||
writel(USR1_DTRD, sport->port.membase + USR1);
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
imx_mctrl_check(sport);
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (sts & USR1_RTSD) {
|
||||
imx_rtsint(irq, dev_id);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (sts & USR1_AWAKE)
|
||||
if (sts & USR1_AWAKE) {
|
||||
writel(USR1_AWAKE, sport->port.membase + USR1);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (sts2 & USR2_ORE) {
|
||||
sport->port.icount.overrun++;
|
||||
writel(USR2_ORE, sport->port.membase + USR2);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -782,28 +857,6 @@ static unsigned int imx_tx_empty(struct uart_port *port)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have a modem side uart, so the meanings of RTS and CTS are inverted.
|
||||
*/
|
||||
static unsigned int imx_get_hwmctrl(struct imx_port *sport)
|
||||
{
|
||||
unsigned int tmp = TIOCM_DSR;
|
||||
unsigned usr1 = readl(sport->port.membase + USR1);
|
||||
|
||||
if (usr1 & USR1_RTSS)
|
||||
tmp |= TIOCM_CTS;
|
||||
|
||||
/* in DCE mode DCDIN is always 0 */
|
||||
if (!(usr1 & USR2_DCDIN))
|
||||
tmp |= TIOCM_CAR;
|
||||
|
||||
/* in DCE mode RIIN is always 0 */
|
||||
if (readl(sport->port.membase + USR2) & USR2_RIIN)
|
||||
tmp |= TIOCM_RI;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static unsigned int imx_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
struct imx_port *sport = (struct imx_port *)port;
|
||||
@@ -860,33 +913,6 @@ static void imx_break_ctl(struct uart_port *port, int break_state)
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle any change of modem status signal since we were last called.
|
||||
*/
|
||||
static void imx_mctrl_check(struct imx_port *sport)
|
||||
{
|
||||
unsigned int status, changed;
|
||||
|
||||
status = imx_get_hwmctrl(sport);
|
||||
changed = status ^ sport->old_status;
|
||||
|
||||
if (changed == 0)
|
||||
return;
|
||||
|
||||
sport->old_status = status;
|
||||
|
||||
if (changed & TIOCM_RI)
|
||||
sport->port.icount.rng++;
|
||||
if (changed & TIOCM_DSR)
|
||||
sport->port.icount.dsr++;
|
||||
if (changed & TIOCM_CAR)
|
||||
uart_handle_dcd_change(&sport->port, status & TIOCM_CAR);
|
||||
if (changed & TIOCM_CTS)
|
||||
uart_handle_cts_change(&sport->port, status & TIOCM_CTS);
|
||||
|
||||
wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is our per-port timeout handler, for checking the
|
||||
* modem status signals.
|
||||
@@ -1193,7 +1219,7 @@ static int imx_startup(struct uart_port *port)
|
||||
/*
|
||||
* Finally, clear and enable interrupts
|
||||
*/
|
||||
writel(USR1_RTSD, sport->port.membase + USR1);
|
||||
writel(USR1_RTSD | USR1_DTRD, sport->port.membase + USR1);
|
||||
writel(USR2_ORE, sport->port.membase + USR2);
|
||||
|
||||
if (sport->dma_is_inited && !sport->dma_is_enabled)
|
||||
@@ -1212,11 +1238,32 @@ static int imx_startup(struct uart_port *port)
|
||||
temp |= (UCR2_RXEN | UCR2_TXEN);
|
||||
if (!sport->have_rtscts)
|
||||
temp |= UCR2_IRTS;
|
||||
/*
|
||||
* make sure the edge sensitive RTS-irq is disabled,
|
||||
* we're using RTSD instead.
|
||||
*/
|
||||
if (!is_imx1_uart(sport))
|
||||
temp &= ~UCR2_RTSEN;
|
||||
writel(temp, sport->port.membase + UCR2);
|
||||
|
||||
if (!is_imx1_uart(sport)) {
|
||||
temp = readl(sport->port.membase + UCR3);
|
||||
temp |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP;
|
||||
|
||||
/*
|
||||
* The effect of RI and DCD differs depending on the UFCR_DCEDTE
|
||||
* bit. In DCE mode they control the outputs, in DTE mode they
|
||||
* enable the respective irqs. At least the DCD irq cannot be
|
||||
* cleared on i.MX25 at least, so it's not usable and must be
|
||||
* disabled. I don't have test hardware to check if RI has the
|
||||
* same problem but I consider this likely so it's disabled for
|
||||
* now, too.
|
||||
*/
|
||||
temp |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP |
|
||||
UCR3_DTRDEN | UCR3_RI | UCR3_DCD;
|
||||
|
||||
if (sport->dte_mode)
|
||||
temp &= ~(UCR3_RI | UCR3_DCD);
|
||||
|
||||
writel(temp, sport->port.membase + UCR3);
|
||||
}
|
||||
|
||||
@@ -1610,19 +1657,17 @@ static int imx_rs485_config(struct uart_port *port,
|
||||
struct serial_rs485 *rs485conf)
|
||||
{
|
||||
struct imx_port *sport = (struct imx_port *)port;
|
||||
unsigned long temp;
|
||||
|
||||
/* unimplemented */
|
||||
rs485conf->delay_rts_before_send = 0;
|
||||
rs485conf->delay_rts_after_send = 0;
|
||||
rs485conf->flags |= SER_RS485_RX_DURING_TX;
|
||||
|
||||
/* RTS is required to control the transmitter */
|
||||
if (!sport->have_rtscts)
|
||||
rs485conf->flags &= ~SER_RS485_ENABLED;
|
||||
|
||||
if (rs485conf->flags & SER_RS485_ENABLED) {
|
||||
unsigned long temp;
|
||||
|
||||
/* disable transmitter */
|
||||
temp = readl(sport->port.membase + UCR2);
|
||||
if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
|
||||
@@ -1632,6 +1677,14 @@ static int imx_rs485_config(struct uart_port *port,
|
||||
writel(temp, sport->port.membase + UCR2);
|
||||
}
|
||||
|
||||
/* Make sure Rx is enabled in case Tx is active with Rx disabled */
|
||||
if (!(rs485conf->flags & SER_RS485_ENABLED) ||
|
||||
rs485conf->flags & SER_RS485_RX_DURING_TX) {
|
||||
temp = readl(sport->port.membase + UCR2);
|
||||
temp |= UCR2_RXEN;
|
||||
writel(temp, sport->port.membase + UCR2);
|
||||
}
|
||||
|
||||
port->rs485 = *rs485conf;
|
||||
|
||||
return 0;
|
||||
@@ -1927,7 +1980,8 @@ static int serial_imx_probe_dt(struct imx_port *sport,
|
||||
}
|
||||
sport->port.line = ret;
|
||||
|
||||
if (of_get_property(np, "fsl,uart-has-rtscts", NULL))
|
||||
if (of_get_property(np, "uart-has-rtscts", NULL) ||
|
||||
of_get_property(np, "fsl,uart-has-rtscts", NULL) /* deprecated */)
|
||||
sport->have_rtscts = 1;
|
||||
|
||||
if (of_get_property(np, "fsl,dte-mode", NULL))
|
||||
|
@@ -481,18 +481,13 @@ static void meson_console_putchar(struct uart_port *port, int ch)
|
||||
writel(ch, port->membase + AML_UART_WFIFO);
|
||||
}
|
||||
|
||||
static void meson_serial_console_write(struct console *co, const char *s,
|
||||
u_int count)
|
||||
static void meson_serial_port_write(struct uart_port *port, const char *s,
|
||||
u_int count)
|
||||
{
|
||||
struct uart_port *port;
|
||||
unsigned long flags;
|
||||
int locked;
|
||||
u32 val, tmp;
|
||||
|
||||
port = meson_ports[co->index];
|
||||
if (!port)
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
if (port->sysrq) {
|
||||
locked = 0;
|
||||
@@ -516,6 +511,18 @@ static void meson_serial_console_write(struct console *co, const char *s,
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static void meson_serial_console_write(struct console *co, const char *s,
|
||||
u_int count)
|
||||
{
|
||||
struct uart_port *port;
|
||||
|
||||
port = meson_ports[co->index];
|
||||
if (!port)
|
||||
return;
|
||||
|
||||
meson_serial_port_write(port, s, count);
|
||||
}
|
||||
|
||||
static int meson_serial_console_setup(struct console *co, char *options)
|
||||
{
|
||||
struct uart_port *port;
|
||||
@@ -554,6 +561,27 @@ static int __init meson_serial_console_init(void)
|
||||
}
|
||||
console_initcall(meson_serial_console_init);
|
||||
|
||||
static void meson_serial_early_console_write(struct console *co,
|
||||
const char *s,
|
||||
u_int count)
|
||||
{
|
||||
struct earlycon_device *dev = co->data;
|
||||
|
||||
meson_serial_port_write(&dev->port, s, count);
|
||||
}
|
||||
|
||||
static int __init
|
||||
meson_serial_early_console_setup(struct earlycon_device *device, const char *opt)
|
||||
{
|
||||
if (!device->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
device->con->write = meson_serial_early_console_write;
|
||||
return 0;
|
||||
}
|
||||
OF_EARLYCON_DECLARE(meson, "amlogic,meson-uart",
|
||||
meson_serial_early_console_setup);
|
||||
|
||||
#define MESON_SERIAL_CONSOLE (&meson_serial_console)
|
||||
#else
|
||||
#define MESON_SERIAL_CONSOLE NULL
|
||||
|
625
drivers/tty/serial/mps2-uart.c
Normal file
625
drivers/tty/serial/mps2-uart.c
Normal file
@@ -0,0 +1,625 @@
|
||||
/*
|
||||
* Copyright (C) 2015 ARM Limited
|
||||
*
|
||||
* Author: Vladimir Murzin <vladimir.murzin@arm.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* TODO: support for SysRq
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define SERIAL_NAME "ttyMPS"
|
||||
#define DRIVER_NAME "mps2-uart"
|
||||
#define MAKE_NAME(x) (DRIVER_NAME # x)
|
||||
|
||||
#define UARTn_DATA 0x00
|
||||
|
||||
#define UARTn_STATE 0x04
|
||||
#define UARTn_STATE_TX_FULL BIT(0)
|
||||
#define UARTn_STATE_RX_FULL BIT(1)
|
||||
#define UARTn_STATE_TX_OVERRUN BIT(2)
|
||||
#define UARTn_STATE_RX_OVERRUN BIT(3)
|
||||
|
||||
#define UARTn_CTRL 0x08
|
||||
#define UARTn_CTRL_TX_ENABLE BIT(0)
|
||||
#define UARTn_CTRL_RX_ENABLE BIT(1)
|
||||
#define UARTn_CTRL_TX_INT_ENABLE BIT(2)
|
||||
#define UARTn_CTRL_RX_INT_ENABLE BIT(3)
|
||||
#define UARTn_CTRL_TX_OVERRUN_INT_ENABLE BIT(4)
|
||||
#define UARTn_CTRL_RX_OVERRUN_INT_ENABLE BIT(5)
|
||||
|
||||
#define UARTn_INT 0x0c
|
||||
#define UARTn_INT_TX BIT(0)
|
||||
#define UARTn_INT_RX BIT(1)
|
||||
#define UARTn_INT_TX_OVERRUN BIT(2)
|
||||
#define UARTn_INT_RX_OVERRUN BIT(3)
|
||||
|
||||
#define UARTn_BAUDDIV 0x10
|
||||
#define UARTn_BAUDDIV_MASK GENMASK(20, 0)
|
||||
|
||||
/*
|
||||
* Helpers to make typical enable/disable operations more readable.
|
||||
*/
|
||||
#define UARTn_CTRL_TX_GRP (UARTn_CTRL_TX_ENABLE |\
|
||||
UARTn_CTRL_TX_INT_ENABLE |\
|
||||
UARTn_CTRL_TX_OVERRUN_INT_ENABLE)
|
||||
|
||||
#define UARTn_CTRL_RX_GRP (UARTn_CTRL_RX_ENABLE |\
|
||||
UARTn_CTRL_RX_INT_ENABLE |\
|
||||
UARTn_CTRL_RX_OVERRUN_INT_ENABLE)
|
||||
|
||||
#define MPS2_MAX_PORTS 3
|
||||
|
||||
struct mps2_uart_port {
|
||||
struct uart_port port;
|
||||
struct clk *clk;
|
||||
unsigned int tx_irq;
|
||||
unsigned int rx_irq;
|
||||
};
|
||||
|
||||
static inline struct mps2_uart_port *to_mps2_port(struct uart_port *port)
|
||||
{
|
||||
return container_of(port, struct mps2_uart_port, port);
|
||||
}
|
||||
|
||||
static void mps2_uart_write8(struct uart_port *port, u8 val, unsigned int off)
|
||||
{
|
||||
struct mps2_uart_port *mps_port = to_mps2_port(port);
|
||||
|
||||
writeb(val, mps_port->port.membase + off);
|
||||
}
|
||||
|
||||
static u8 mps2_uart_read8(struct uart_port *port, unsigned int off)
|
||||
{
|
||||
struct mps2_uart_port *mps_port = to_mps2_port(port);
|
||||
|
||||
return readb(mps_port->port.membase + off);
|
||||
}
|
||||
|
||||
static void mps2_uart_write32(struct uart_port *port, u32 val, unsigned int off)
|
||||
{
|
||||
struct mps2_uart_port *mps_port = to_mps2_port(port);
|
||||
|
||||
writel_relaxed(val, mps_port->port.membase + off);
|
||||
}
|
||||
|
||||
static unsigned int mps2_uart_tx_empty(struct uart_port *port)
|
||||
{
|
||||
u8 status = mps2_uart_read8(port, UARTn_STATE);
|
||||
|
||||
return (status & UARTn_STATE_TX_FULL) ? 0 : TIOCSER_TEMT;
|
||||
}
|
||||
|
||||
static void mps2_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
}
|
||||
|
||||
static unsigned int mps2_uart_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR;
|
||||
}
|
||||
|
||||
static void mps2_uart_stop_tx(struct uart_port *port)
|
||||
{
|
||||
u8 control = mps2_uart_read8(port, UARTn_CTRL);
|
||||
|
||||
control &= ~UARTn_CTRL_TX_INT_ENABLE;
|
||||
|
||||
mps2_uart_write8(port, control, UARTn_CTRL);
|
||||
}
|
||||
|
||||
static void mps2_uart_tx_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
|
||||
while (!(mps2_uart_read8(port, UARTn_STATE) & UARTn_STATE_TX_FULL)) {
|
||||
if (port->x_char) {
|
||||
mps2_uart_write8(port, port->x_char, UARTn_DATA);
|
||||
port->x_char = 0;
|
||||
port->icount.tx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port))
|
||||
break;
|
||||
|
||||
mps2_uart_write8(port, xmit->buf[xmit->tail], UARTn_DATA);
|
||||
xmit->tail = (xmit->tail + 1) % UART_XMIT_SIZE;
|
||||
port->icount.tx++;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
mps2_uart_stop_tx(port);
|
||||
}
|
||||
|
||||
static void mps2_uart_start_tx(struct uart_port *port)
|
||||
{
|
||||
u8 control = mps2_uart_read8(port, UARTn_CTRL);
|
||||
|
||||
control |= UARTn_CTRL_TX_INT_ENABLE;
|
||||
|
||||
mps2_uart_write8(port, control, UARTn_CTRL);
|
||||
|
||||
/*
|
||||
* We've just unmasked the TX IRQ and now slow-starting via
|
||||
* polling; if there is enough data to fill up the internal
|
||||
* write buffer in one go, the TX IRQ should assert, at which
|
||||
* point we switch to fully interrupt-driven TX.
|
||||
*/
|
||||
|
||||
mps2_uart_tx_chars(port);
|
||||
}
|
||||
|
||||
static void mps2_uart_stop_rx(struct uart_port *port)
|
||||
{
|
||||
u8 control = mps2_uart_read8(port, UARTn_CTRL);
|
||||
|
||||
control &= ~UARTn_CTRL_RX_GRP;
|
||||
|
||||
mps2_uart_write8(port, control, UARTn_CTRL);
|
||||
}
|
||||
|
||||
static void mps2_uart_break_ctl(struct uart_port *port, int ctl)
|
||||
{
|
||||
}
|
||||
|
||||
static void mps2_uart_rx_chars(struct uart_port *port)
|
||||
{
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
||||
while (mps2_uart_read8(port, UARTn_STATE) & UARTn_STATE_RX_FULL) {
|
||||
u8 rxdata = mps2_uart_read8(port, UARTn_DATA);
|
||||
|
||||
port->icount.rx++;
|
||||
tty_insert_flip_char(&port->state->port, rxdata, TTY_NORMAL);
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(tport);
|
||||
}
|
||||
|
||||
static irqreturn_t mps2_uart_rxirq(int irq, void *data)
|
||||
{
|
||||
struct uart_port *port = data;
|
||||
u8 irqflag = mps2_uart_read8(port, UARTn_INT);
|
||||
|
||||
if (unlikely(!(irqflag & UARTn_INT_RX)))
|
||||
return IRQ_NONE;
|
||||
|
||||
spin_lock(&port->lock);
|
||||
|
||||
mps2_uart_write8(port, UARTn_INT_RX, UARTn_INT);
|
||||
mps2_uart_rx_chars(port);
|
||||
|
||||
spin_unlock(&port->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t mps2_uart_txirq(int irq, void *data)
|
||||
{
|
||||
struct uart_port *port = data;
|
||||
u8 irqflag = mps2_uart_read8(port, UARTn_INT);
|
||||
|
||||
if (unlikely(!(irqflag & UARTn_INT_TX)))
|
||||
return IRQ_NONE;
|
||||
|
||||
spin_lock(&port->lock);
|
||||
|
||||
mps2_uart_write8(port, UARTn_INT_TX, UARTn_INT);
|
||||
mps2_uart_tx_chars(port);
|
||||
|
||||
spin_unlock(&port->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t mps2_uart_oerrirq(int irq, void *data)
|
||||
{
|
||||
irqreturn_t handled = IRQ_NONE;
|
||||
struct uart_port *port = data;
|
||||
u8 irqflag = mps2_uart_read8(port, UARTn_INT);
|
||||
|
||||
spin_lock(&port->lock);
|
||||
|
||||
if (irqflag & UARTn_INT_RX_OVERRUN) {
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
||||
mps2_uart_write8(port, UARTn_INT_RX_OVERRUN, UARTn_INT);
|
||||
port->icount.overrun++;
|
||||
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
|
||||
tty_flip_buffer_push(tport);
|
||||
handled = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* It's never been seen in practice and it never *should* happen since
|
||||
* we check if there is enough room in TX buffer before sending data.
|
||||
* So we keep this check in case something suspicious has happened.
|
||||
*/
|
||||
if (irqflag & UARTn_INT_TX_OVERRUN) {
|
||||
mps2_uart_write8(port, UARTn_INT_TX_OVERRUN, UARTn_INT);
|
||||
handled = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
spin_unlock(&port->lock);
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
static int mps2_uart_startup(struct uart_port *port)
|
||||
{
|
||||
struct mps2_uart_port *mps_port = to_mps2_port(port);
|
||||
u8 control = mps2_uart_read8(port, UARTn_CTRL);
|
||||
int ret;
|
||||
|
||||
control &= ~(UARTn_CTRL_RX_GRP | UARTn_CTRL_TX_GRP);
|
||||
|
||||
mps2_uart_write8(port, control, UARTn_CTRL);
|
||||
|
||||
ret = request_irq(mps_port->rx_irq, mps2_uart_rxirq, 0,
|
||||
MAKE_NAME(-rx), mps_port);
|
||||
if (ret) {
|
||||
dev_err(port->dev, "failed to register rxirq (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = request_irq(mps_port->tx_irq, mps2_uart_txirq, 0,
|
||||
MAKE_NAME(-tx), mps_port);
|
||||
if (ret) {
|
||||
dev_err(port->dev, "failed to register txirq (%d)\n", ret);
|
||||
goto err_free_rxirq;
|
||||
}
|
||||
|
||||
ret = request_irq(port->irq, mps2_uart_oerrirq, IRQF_SHARED,
|
||||
MAKE_NAME(-overrun), mps_port);
|
||||
|
||||
if (ret) {
|
||||
dev_err(port->dev, "failed to register oerrirq (%d)\n", ret);
|
||||
goto err_free_txirq;
|
||||
}
|
||||
|
||||
control |= UARTn_CTRL_RX_GRP | UARTn_CTRL_TX_GRP;
|
||||
|
||||
mps2_uart_write8(port, control, UARTn_CTRL);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_txirq:
|
||||
free_irq(mps_port->tx_irq, mps_port);
|
||||
err_free_rxirq:
|
||||
free_irq(mps_port->rx_irq, mps_port);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mps2_uart_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct mps2_uart_port *mps_port = to_mps2_port(port);
|
||||
u8 control = mps2_uart_read8(port, UARTn_CTRL);
|
||||
|
||||
control &= ~(UARTn_CTRL_RX_GRP | UARTn_CTRL_TX_GRP);
|
||||
|
||||
mps2_uart_write8(port, control, UARTn_CTRL);
|
||||
|
||||
free_irq(mps_port->rx_irq, mps_port);
|
||||
free_irq(mps_port->tx_irq, mps_port);
|
||||
free_irq(port->irq, mps_port);
|
||||
}
|
||||
|
||||
static void
|
||||
mps2_uart_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int baud, bauddiv;
|
||||
|
||||
termios->c_cflag &= ~(CRTSCTS | CMSPAR);
|
||||
termios->c_cflag &= ~CSIZE;
|
||||
termios->c_cflag |= CS8;
|
||||
termios->c_cflag &= ~PARENB;
|
||||
termios->c_cflag &= ~CSTOPB;
|
||||
|
||||
baud = uart_get_baud_rate(port, termios, old,
|
||||
DIV_ROUND_CLOSEST(port->uartclk, UARTn_BAUDDIV_MASK),
|
||||
DIV_ROUND_CLOSEST(port->uartclk, 16));
|
||||
|
||||
bauddiv = DIV_ROUND_CLOSEST(port->uartclk, baud);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
mps2_uart_write32(port, bauddiv, UARTn_BAUDDIV);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
if (tty_termios_baud_rate(termios))
|
||||
tty_termios_encode_baud_rate(termios, baud, baud);
|
||||
}
|
||||
|
||||
static const char *mps2_uart_type(struct uart_port *port)
|
||||
{
|
||||
return (port->type == PORT_MPS2UART) ? DRIVER_NAME : NULL;
|
||||
}
|
||||
|
||||
static void mps2_uart_release_port(struct uart_port *port)
|
||||
{
|
||||
}
|
||||
|
||||
static int mps2_uart_request_port(struct uart_port *port)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mps2_uart_config_port(struct uart_port *port, int type)
|
||||
{
|
||||
if (type & UART_CONFIG_TYPE && !mps2_uart_request_port(port))
|
||||
port->type = PORT_MPS2UART;
|
||||
}
|
||||
|
||||
static int mps2_uart_verify_port(struct uart_port *port, struct serial_struct *serinfo)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct uart_ops mps2_uart_pops = {
|
||||
.tx_empty = mps2_uart_tx_empty,
|
||||
.set_mctrl = mps2_uart_set_mctrl,
|
||||
.get_mctrl = mps2_uart_get_mctrl,
|
||||
.stop_tx = mps2_uart_stop_tx,
|
||||
.start_tx = mps2_uart_start_tx,
|
||||
.stop_rx = mps2_uart_stop_rx,
|
||||
.break_ctl = mps2_uart_break_ctl,
|
||||
.startup = mps2_uart_startup,
|
||||
.shutdown = mps2_uart_shutdown,
|
||||
.set_termios = mps2_uart_set_termios,
|
||||
.type = mps2_uart_type,
|
||||
.release_port = mps2_uart_release_port,
|
||||
.request_port = mps2_uart_request_port,
|
||||
.config_port = mps2_uart_config_port,
|
||||
.verify_port = mps2_uart_verify_port,
|
||||
};
|
||||
|
||||
static struct mps2_uart_port mps2_uart_ports[MPS2_MAX_PORTS];
|
||||
|
||||
#ifdef CONFIG_SERIAL_MPS2_UART_CONSOLE
|
||||
static void mps2_uart_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
while (mps2_uart_read8(port, UARTn_STATE) & UARTn_STATE_TX_FULL)
|
||||
cpu_relax();
|
||||
|
||||
mps2_uart_write8(port, ch, UARTn_DATA);
|
||||
}
|
||||
|
||||
static void mps2_uart_console_write(struct console *co, const char *s, unsigned int cnt)
|
||||
{
|
||||
struct uart_port *port = &mps2_uart_ports[co->index].port;
|
||||
|
||||
uart_console_write(port, s, cnt, mps2_uart_console_putchar);
|
||||
}
|
||||
|
||||
static int mps2_uart_console_setup(struct console *co, char *options)
|
||||
{
|
||||
struct mps2_uart_port *mps_port;
|
||||
int baud = 9600;
|
||||
int bits = 8;
|
||||
int parity = 'n';
|
||||
int flow = 'n';
|
||||
|
||||
if (co->index < 0 || co->index >= MPS2_MAX_PORTS)
|
||||
return -ENODEV;
|
||||
|
||||
mps_port = &mps2_uart_ports[co->index];
|
||||
|
||||
if (options)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
|
||||
return uart_set_options(&mps_port->port, co, baud, parity, bits, flow);
|
||||
}
|
||||
|
||||
static struct uart_driver mps2_uart_driver;
|
||||
|
||||
static struct console mps2_uart_console = {
|
||||
.name = SERIAL_NAME,
|
||||
.device = uart_console_device,
|
||||
.write = mps2_uart_console_write,
|
||||
.setup = mps2_uart_console_setup,
|
||||
.flags = CON_PRINTBUFFER,
|
||||
.index = -1,
|
||||
.data = &mps2_uart_driver,
|
||||
};
|
||||
|
||||
#define MPS2_SERIAL_CONSOLE (&mps2_uart_console)
|
||||
|
||||
static void mps2_early_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
while (readb(port->membase + UARTn_STATE) & UARTn_STATE_TX_FULL)
|
||||
cpu_relax();
|
||||
|
||||
writeb((unsigned char)ch, port->membase + UARTn_DATA);
|
||||
}
|
||||
|
||||
static void mps2_early_write(struct console *con, const char *s, unsigned int n)
|
||||
{
|
||||
struct earlycon_device *dev = con->data;
|
||||
|
||||
uart_console_write(&dev->port, s, n, mps2_early_putchar);
|
||||
}
|
||||
|
||||
static int __init mps2_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
if (!device->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
device->con->write = mps2_early_write;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
OF_EARLYCON_DECLARE(mps2, "arm,mps2-uart", mps2_early_console_setup);
|
||||
|
||||
#else
|
||||
#define MPS2_SERIAL_CONSOLE NULL
|
||||
#endif
|
||||
|
||||
static struct uart_driver mps2_uart_driver = {
|
||||
.driver_name = DRIVER_NAME,
|
||||
.dev_name = SERIAL_NAME,
|
||||
.nr = MPS2_MAX_PORTS,
|
||||
.cons = MPS2_SERIAL_CONSOLE,
|
||||
};
|
||||
|
||||
static struct mps2_uart_port *mps2_of_get_port(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int id;
|
||||
|
||||
if (!np)
|
||||
return NULL;
|
||||
|
||||
id = of_alias_get_id(np, "serial");
|
||||
if (id < 0)
|
||||
id = 0;
|
||||
|
||||
if (WARN_ON(id >= MPS2_MAX_PORTS))
|
||||
return NULL;
|
||||
|
||||
mps2_uart_ports[id].port.line = id;
|
||||
return &mps2_uart_ports[id];
|
||||
}
|
||||
|
||||
static int mps2_init_port(struct mps2_uart_port *mps_port,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
mps_port->port.membase = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(mps_port->port.membase))
|
||||
return PTR_ERR(mps_port->port.membase);
|
||||
|
||||
mps_port->port.mapbase = res->start;
|
||||
mps_port->port.mapsize = resource_size(res);
|
||||
|
||||
mps_port->rx_irq = platform_get_irq(pdev, 0);
|
||||
mps_port->tx_irq = platform_get_irq(pdev, 1);
|
||||
mps_port->port.irq = platform_get_irq(pdev, 2);
|
||||
|
||||
mps_port->port.iotype = UPIO_MEM;
|
||||
mps_port->port.flags = UPF_BOOT_AUTOCONF;
|
||||
mps_port->port.fifosize = 1;
|
||||
mps_port->port.ops = &mps2_uart_pops;
|
||||
mps_port->port.dev = &pdev->dev;
|
||||
|
||||
mps_port->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(mps_port->clk))
|
||||
return PTR_ERR(mps_port->clk);
|
||||
|
||||
ret = clk_prepare_enable(mps_port->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mps_port->port.uartclk = clk_get_rate(mps_port->clk);
|
||||
|
||||
clk_disable_unprepare(mps_port->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mps2_serial_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mps2_uart_port *mps_port;
|
||||
int ret;
|
||||
|
||||
mps_port = mps2_of_get_port(pdev);
|
||||
if (!mps_port)
|
||||
return -ENODEV;
|
||||
|
||||
ret = mps2_init_port(mps_port, pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = uart_add_one_port(&mps2_uart_driver, &mps_port->port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, mps_port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mps2_serial_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mps2_uart_port *mps_port = platform_get_drvdata(pdev);
|
||||
|
||||
uart_remove_one_port(&mps2_uart_driver, &mps_port->port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id mps2_match[] = {
|
||||
{ .compatible = "arm,mps2-uart", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mps2_match);
|
||||
#endif
|
||||
|
||||
static struct platform_driver mps2_serial_driver = {
|
||||
.probe = mps2_serial_probe,
|
||||
.remove = mps2_serial_remove,
|
||||
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = of_match_ptr(mps2_match),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init mps2_uart_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = uart_register_driver(&mps2_uart_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = platform_driver_register(&mps2_serial_driver);
|
||||
if (ret)
|
||||
uart_unregister_driver(&mps2_uart_driver);
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(mps2_uart_init);
|
||||
|
||||
static void __exit mps2_uart_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&mps2_serial_driver);
|
||||
uart_unregister_driver(&mps2_uart_driver);
|
||||
}
|
||||
module_exit(mps2_uart_exit);
|
||||
|
||||
MODULE_AUTHOR("Vladimir Murzin <vladimir.murzin@arm.com>");
|
||||
MODULE_DESCRIPTION("MPS2 UART driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:" DRIVER_NAME);
|
@@ -861,37 +861,72 @@ struct msm_baud_map {
|
||||
};
|
||||
|
||||
static const struct msm_baud_map *
|
||||
msm_find_best_baud(struct uart_port *port, unsigned int baud)
|
||||
msm_find_best_baud(struct uart_port *port, unsigned int baud,
|
||||
unsigned long *rate)
|
||||
{
|
||||
unsigned int i, divisor;
|
||||
const struct msm_baud_map *entry;
|
||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||
unsigned int divisor, result;
|
||||
unsigned long target, old, best_rate = 0, diff, best_diff = ULONG_MAX;
|
||||
const struct msm_baud_map *entry, *end, *best;
|
||||
static const struct msm_baud_map table[] = {
|
||||
{ 1536, 0x00, 1 },
|
||||
{ 768, 0x11, 1 },
|
||||
{ 384, 0x22, 1 },
|
||||
{ 192, 0x33, 1 },
|
||||
{ 96, 0x44, 1 },
|
||||
{ 48, 0x55, 1 },
|
||||
{ 32, 0x66, 1 },
|
||||
{ 24, 0x77, 1 },
|
||||
{ 16, 0x88, 1 },
|
||||
{ 12, 0x99, 6 },
|
||||
{ 8, 0xaa, 6 },
|
||||
{ 6, 0xbb, 6 },
|
||||
{ 4, 0xcc, 6 },
|
||||
{ 3, 0xdd, 8 },
|
||||
{ 2, 0xee, 16 },
|
||||
{ 1, 0xff, 31 },
|
||||
{ 0, 0xff, 31 },
|
||||
{ 2, 0xee, 16 },
|
||||
{ 3, 0xdd, 8 },
|
||||
{ 4, 0xcc, 6 },
|
||||
{ 6, 0xbb, 6 },
|
||||
{ 8, 0xaa, 6 },
|
||||
{ 12, 0x99, 6 },
|
||||
{ 16, 0x88, 1 },
|
||||
{ 24, 0x77, 1 },
|
||||
{ 32, 0x66, 1 },
|
||||
{ 48, 0x55, 1 },
|
||||
{ 96, 0x44, 1 },
|
||||
{ 192, 0x33, 1 },
|
||||
{ 384, 0x22, 1 },
|
||||
{ 768, 0x11, 1 },
|
||||
{ 1536, 0x00, 1 },
|
||||
};
|
||||
|
||||
divisor = uart_get_divisor(port, baud);
|
||||
best = table; /* Default to smallest divider */
|
||||
target = clk_round_rate(msm_port->clk, 16 * baud);
|
||||
divisor = DIV_ROUND_CLOSEST(target, 16 * baud);
|
||||
|
||||
for (i = 0, entry = table; i < ARRAY_SIZE(table); i++, entry++)
|
||||
if (entry->divisor <= divisor)
|
||||
break;
|
||||
end = table + ARRAY_SIZE(table);
|
||||
entry = table;
|
||||
while (entry < end) {
|
||||
if (entry->divisor <= divisor) {
|
||||
result = target / entry->divisor / 16;
|
||||
diff = abs(result - baud);
|
||||
|
||||
return entry; /* Default to smallest divider */
|
||||
/* Keep track of best entry */
|
||||
if (diff < best_diff) {
|
||||
best_diff = diff;
|
||||
best = entry;
|
||||
best_rate = target;
|
||||
}
|
||||
|
||||
if (result == baud)
|
||||
break;
|
||||
} else if (entry->divisor > divisor) {
|
||||
old = target;
|
||||
target = clk_round_rate(msm_port->clk, old + 1);
|
||||
/*
|
||||
* The rate didn't get any faster so we can't do
|
||||
* better at dividing it down
|
||||
*/
|
||||
if (target == old)
|
||||
break;
|
||||
|
||||
/* Start the divisor search over at this new rate */
|
||||
entry = table;
|
||||
divisor = DIV_ROUND_CLOSEST(target, 16 * baud);
|
||||
continue;
|
||||
}
|
||||
entry++;
|
||||
}
|
||||
|
||||
*rate = best_rate;
|
||||
return best;
|
||||
}
|
||||
|
||||
static int msm_set_baud_rate(struct uart_port *port, unsigned int baud,
|
||||
@@ -900,22 +935,20 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud,
|
||||
unsigned int rxstale, watermark, mask;
|
||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||
const struct msm_baud_map *entry;
|
||||
unsigned long flags;
|
||||
|
||||
entry = msm_find_best_baud(port, baud);
|
||||
|
||||
msm_write(port, entry->code, UART_CSR);
|
||||
|
||||
if (baud > 460800)
|
||||
port->uartclk = baud * 16;
|
||||
unsigned long flags, rate;
|
||||
|
||||
flags = *saved_flags;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
clk_set_rate(msm_port->clk, port->uartclk);
|
||||
entry = msm_find_best_baud(port, baud, &rate);
|
||||
clk_set_rate(msm_port->clk, rate);
|
||||
baud = rate / 16 / entry->divisor;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
*saved_flags = flags;
|
||||
port->uartclk = rate;
|
||||
|
||||
msm_write(port, entry->code, UART_CSR);
|
||||
|
||||
/* RX stale watermark */
|
||||
rxstale = entry->rxstale;
|
||||
@@ -1577,8 +1610,6 @@ static int msm_serial_probe(struct platform_device *pdev)
|
||||
msm_port->pclk = devm_clk_get(&pdev->dev, "iface");
|
||||
if (IS_ERR(msm_port->pclk))
|
||||
return PTR_ERR(msm_port->pclk);
|
||||
|
||||
clk_set_rate(msm_port->clk, 1843200);
|
||||
}
|
||||
|
||||
port->uartclk = clk_get_rate(msm_port->clk);
|
||||
|
@@ -1,5 +1,7 @@
|
||||
/*
|
||||
* ***************************************************************************
|
||||
* Marvell Armada-3700 Serial Driver
|
||||
* Author: Wilson Ding <dingwei@marvell.com>
|
||||
* Copyright (C) 2015 Marvell International Ltd.
|
||||
* ***************************************************************************
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
@@ -23,7 +25,6 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
@@ -594,30 +595,18 @@ static int mvebu_uart_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvebu_uart_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mvebu_uart_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
uart_remove_one_port(&mvebu_uart_driver, data->port);
|
||||
data->port->private_data = NULL;
|
||||
data->port->mapbase = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Match table for of_platform binding */
|
||||
static const struct of_device_id mvebu_uart_of_match[] = {
|
||||
{ .compatible = "marvell,armada-3700-uart", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mvebu_uart_of_match);
|
||||
|
||||
static struct platform_driver mvebu_uart_platform_driver = {
|
||||
.probe = mvebu_uart_probe,
|
||||
.remove = mvebu_uart_remove,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "mvebu-uart",
|
||||
.of_match_table = of_match_ptr(mvebu_uart_of_match),
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -635,16 +624,4 @@ static int __init mvebu_uart_init(void)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit mvebu_uart_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&mvebu_uart_platform_driver);
|
||||
uart_unregister_driver(&mvebu_uart_driver);
|
||||
}
|
||||
|
||||
arch_initcall(mvebu_uart_init);
|
||||
module_exit(mvebu_uart_exit);
|
||||
|
||||
MODULE_AUTHOR("Wilson Ding <dingwei@marvell.com>");
|
||||
MODULE_DESCRIPTION("Marvell Armada-3700 Serial Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1271,6 +1271,8 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
|
||||
/* check to see if we need to change clock source */
|
||||
|
||||
if (ourport->baudclk != clk) {
|
||||
clk_prepare_enable(clk);
|
||||
|
||||
s3c24xx_serial_setsource(port, clk_sel);
|
||||
|
||||
if (!IS_ERR(ourport->baudclk)) {
|
||||
@@ -1278,8 +1280,6 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
|
||||
ourport->baudclk = ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
clk_prepare_enable(clk);
|
||||
|
||||
ourport->baudclk = clk;
|
||||
ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
|
||||
}
|
||||
|
@@ -666,7 +666,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
|
||||
struct uart_port *port = &s->p[portno].port;
|
||||
|
||||
do {
|
||||
unsigned int iir, msr, rxlen;
|
||||
unsigned int iir, rxlen;
|
||||
|
||||
iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
|
||||
if (iir & SC16IS7XX_IIR_NO_INT_BIT)
|
||||
@@ -683,12 +683,6 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
|
||||
if (rxlen)
|
||||
sc16is7xx_handle_rx(port, rxlen, iir);
|
||||
break;
|
||||
|
||||
case SC16IS7XX_IIR_CTSRTS_SRC:
|
||||
msr = sc16is7xx_port_read(port, SC16IS7XX_MSR_REG);
|
||||
uart_handle_cts_change(port,
|
||||
!!(msr & SC16IS7XX_MSR_DCTS_BIT));
|
||||
break;
|
||||
case SC16IS7XX_IIR_THRI_SRC:
|
||||
sc16is7xx_handle_tx(port);
|
||||
break;
|
||||
@@ -1014,9 +1008,8 @@ static int sc16is7xx_startup(struct uart_port *port)
|
||||
SC16IS7XX_EFCR_TXDISABLE_BIT,
|
||||
0);
|
||||
|
||||
/* Enable RX, TX, CTS change interrupts */
|
||||
val = SC16IS7XX_IER_RDI_BIT | SC16IS7XX_IER_THRI_BIT |
|
||||
SC16IS7XX_IER_CTSI_BIT;
|
||||
/* Enable RX, TX interrupts */
|
||||
val = SC16IS7XX_IER_RDI_BIT | SC16IS7XX_IER_THRI_BIT;
|
||||
sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val);
|
||||
|
||||
return 0;
|
||||
|
@@ -206,10 +206,8 @@ static void set_dtr(struct tegra_uart_port *tup, bool active)
|
||||
static void tegra_uart_set_mctrl(struct uart_port *u, unsigned int mctrl)
|
||||
{
|
||||
struct tegra_uart_port *tup = to_tegra_uport(u);
|
||||
unsigned long mcr;
|
||||
int dtr_enable;
|
||||
|
||||
mcr = tup->mcr_shadow;
|
||||
tup->rts_active = !!(mctrl & TIOCM_RTS);
|
||||
set_rts(tup, tup->rts_active);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -43,8 +43,6 @@ static const struct {
|
||||
{ "rng", TIOCM_RNG, false, },
|
||||
{ "rts", TIOCM_RTS, true, },
|
||||
{ "dtr", TIOCM_DTR, true, },
|
||||
{ "out1", TIOCM_OUT1, true, },
|
||||
{ "out2", TIOCM_OUT2, true, },
|
||||
};
|
||||
|
||||
void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
|
||||
@@ -125,9 +123,12 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
|
||||
struct uart_port *port = gpios->port;
|
||||
u32 mctrl = gpios->mctrl_prev;
|
||||
u32 mctrl_diff;
|
||||
unsigned long flags;
|
||||
|
||||
mctrl_gpio_get(gpios, &mctrl);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
mctrl_diff = mctrl ^ gpios->mctrl_prev;
|
||||
gpios->mctrl_prev = mctrl;
|
||||
|
||||
@@ -147,6 +148,8 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
|
||||
wake_up_interruptible(&port->state->port.delta_msr_wait);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@@ -32,8 +32,6 @@ enum mctrl_gpio_idx {
|
||||
UART_GPIO_RI = UART_GPIO_RNG,
|
||||
UART_GPIO_RTS,
|
||||
UART_GPIO_DTR,
|
||||
UART_GPIO_OUT1,
|
||||
UART_GPIO_OUT2,
|
||||
UART_GPIO_MAX,
|
||||
};
|
||||
|
||||
|
@@ -1264,6 +1264,7 @@ MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids);
|
||||
|
||||
static int sirfsoc_uart_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct sirfsoc_uart_port *sirfport;
|
||||
struct uart_port *port;
|
||||
struct resource *res;
|
||||
@@ -1276,13 +1277,13 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
|
||||
};
|
||||
const struct of_device_id *match;
|
||||
|
||||
match = of_match_node(sirfsoc_uart_ids, pdev->dev.of_node);
|
||||
match = of_match_node(sirfsoc_uart_ids, np);
|
||||
sirfport = devm_kzalloc(&pdev->dev, sizeof(*sirfport), GFP_KERNEL);
|
||||
if (!sirfport) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
sirfport->port.line = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
sirfport->port.line = of_alias_get_id(np, "serial");
|
||||
sirf_ports[sirfport->port.line] = sirfport;
|
||||
sirfport->port.iotype = UPIO_MEM;
|
||||
sirfport->port.flags = UPF_BOOT_AUTOCONF;
|
||||
@@ -1291,25 +1292,25 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
|
||||
port->private_data = sirfport;
|
||||
sirfport->uart_reg = (struct sirfsoc_uart_register *)match->data;
|
||||
|
||||
sirfport->hw_flow_ctrl = of_property_read_bool(pdev->dev.of_node,
|
||||
"sirf,uart-has-rtscts");
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart") ||
|
||||
of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart"))
|
||||
sirfport->hw_flow_ctrl =
|
||||
of_property_read_bool(np, "uart-has-rtscts") ||
|
||||
of_property_read_bool(np, "sirf,uart-has-rtscts") /* deprecated */;
|
||||
if (of_device_is_compatible(np, "sirf,prima2-uart") ||
|
||||
of_device_is_compatible(np, "sirf,atlas7-uart"))
|
||||
sirfport->uart_reg->uart_type = SIRF_REAL_UART;
|
||||
if (of_device_is_compatible(pdev->dev.of_node,
|
||||
"sirf,prima2-usp-uart") || of_device_is_compatible(
|
||||
pdev->dev.of_node, "sirf,atlas7-usp-uart")) {
|
||||
if (of_device_is_compatible(np, "sirf,prima2-usp-uart") ||
|
||||
of_device_is_compatible(np, "sirf,atlas7-usp-uart")) {
|
||||
sirfport->uart_reg->uart_type = SIRF_USP_UART;
|
||||
if (!sirfport->hw_flow_ctrl)
|
||||
goto usp_no_flow_control;
|
||||
if (of_find_property(pdev->dev.of_node, "cts-gpios", NULL))
|
||||
sirfport->cts_gpio = of_get_named_gpio(
|
||||
pdev->dev.of_node, "cts-gpios", 0);
|
||||
if (of_find_property(np, "cts-gpios", NULL))
|
||||
sirfport->cts_gpio =
|
||||
of_get_named_gpio(np, "cts-gpios", 0);
|
||||
else
|
||||
sirfport->cts_gpio = -1;
|
||||
if (of_find_property(pdev->dev.of_node, "rts-gpios", NULL))
|
||||
sirfport->rts_gpio = of_get_named_gpio(
|
||||
pdev->dev.of_node, "rts-gpios", 0);
|
||||
if (of_find_property(np, "rts-gpios", NULL))
|
||||
sirfport->rts_gpio =
|
||||
of_get_named_gpio(np, "rts-gpios", 0);
|
||||
else
|
||||
sirfport->rts_gpio = -1;
|
||||
|
||||
@@ -1336,13 +1337,11 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
|
||||
gpio_direction_output(sirfport->rts_gpio, 1);
|
||||
}
|
||||
usp_no_flow_control:
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart") ||
|
||||
of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-usp-uart"))
|
||||
if (of_device_is_compatible(np, "sirf,atlas7-uart") ||
|
||||
of_device_is_compatible(np, "sirf,atlas7-usp-uart"))
|
||||
sirfport->is_atlas7 = true;
|
||||
|
||||
if (of_property_read_u32(pdev->dev.of_node,
|
||||
"fifosize",
|
||||
&port->fifosize)) {
|
||||
if (of_property_read_u32(np, "fifosize", &port->fifosize)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Unable to find fifosize in uart node.\n");
|
||||
ret = -EFAULT;
|
||||
|
@@ -72,7 +72,7 @@ static void uartlite_outbe32(u32 val, void __iomem *addr)
|
||||
iowrite32be(val, addr);
|
||||
}
|
||||
|
||||
static struct uartlite_reg_ops uartlite_be = {
|
||||
static const struct uartlite_reg_ops uartlite_be = {
|
||||
.in = uartlite_inbe32,
|
||||
.out = uartlite_outbe32,
|
||||
};
|
||||
@@ -87,21 +87,21 @@ static void uartlite_outle32(u32 val, void __iomem *addr)
|
||||
iowrite32(val, addr);
|
||||
}
|
||||
|
||||
static struct uartlite_reg_ops uartlite_le = {
|
||||
static const struct uartlite_reg_ops uartlite_le = {
|
||||
.in = uartlite_inle32,
|
||||
.out = uartlite_outle32,
|
||||
};
|
||||
|
||||
static inline u32 uart_in32(u32 offset, struct uart_port *port)
|
||||
{
|
||||
struct uartlite_reg_ops *reg_ops = port->private_data;
|
||||
const struct uartlite_reg_ops *reg_ops = port->private_data;
|
||||
|
||||
return reg_ops->in(port->membase + offset);
|
||||
}
|
||||
|
||||
static inline void uart_out32(u32 val, u32 offset, struct uart_port *port)
|
||||
{
|
||||
struct uartlite_reg_ops *reg_ops = port->private_data;
|
||||
const struct uartlite_reg_ops *reg_ops = port->private_data;
|
||||
|
||||
reg_ops->out(val, port->membase + offset);
|
||||
}
|
||||
@@ -345,13 +345,13 @@ static int ulite_request_port(struct uart_port *port)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
port->private_data = &uartlite_be;
|
||||
port->private_data = (void *)&uartlite_be;
|
||||
ret = uart_in32(ULITE_CONTROL, port);
|
||||
uart_out32(ULITE_CONTROL_RST_TX, ULITE_CONTROL, port);
|
||||
ret = uart_in32(ULITE_STATUS, port);
|
||||
/* Endianess detection */
|
||||
if ((ret & ULITE_STATUS_TXEMPTY) != ULITE_STATUS_TXEMPTY)
|
||||
port->private_data = &uartlite_le;
|
||||
port->private_data = (void *)&uartlite_le;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -1478,6 +1478,9 @@ static const struct of_device_id ucc_uart_match[] = {
|
||||
.type = "serial",
|
||||
.compatible = "ucc_uart",
|
||||
},
|
||||
{
|
||||
.compatible = "fsl,t1040-ucc-uart",
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ucc_uart_match);
|
||||
|
@@ -1340,7 +1340,7 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info )
|
||||
wake_up_interruptible(&info->status_event_wait_q);
|
||||
wake_up_interruptible(&info->event_wait_q);
|
||||
|
||||
if ( (info->port.flags & ASYNC_CHECK_CD) &&
|
||||
if (tty_port_check_carrier(&info->port) &&
|
||||
(status & MISCSTATUS_DCD_LATCHED) ) {
|
||||
if ( debug_level >= DEBUG_LEVEL_ISR )
|
||||
printk("%s CD now %s...", info->device_name,
|
||||
@@ -1361,8 +1361,7 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info )
|
||||
if (status & MISCSTATUS_CTS) {
|
||||
if ( debug_level >= DEBUG_LEVEL_ISR )
|
||||
printk("CTS tx start...");
|
||||
if (info->port.tty)
|
||||
info->port.tty->hw_stopped = 0;
|
||||
info->port.tty->hw_stopped = 0;
|
||||
usc_start_transmitter(info);
|
||||
info->pending_bh |= BH_TRANSMIT;
|
||||
return;
|
||||
@@ -1749,13 +1748,13 @@ static irqreturn_t mgsl_interrupt(int dummy, void *dev_id)
|
||||
static int startup(struct mgsl_struct * info)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
|
||||
if ( debug_level >= DEBUG_LEVEL_INFO )
|
||||
printk("%s(%d):mgsl_startup(%s)\n",__FILE__,__LINE__,info->device_name);
|
||||
|
||||
if (info->port.flags & ASYNC_INITIALIZED)
|
||||
|
||||
if (tty_port_initialized(&info->port))
|
||||
return 0;
|
||||
|
||||
|
||||
if (!info->xmit_buf) {
|
||||
/* allocate a page of memory for a transmit buffer */
|
||||
info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
|
||||
@@ -1788,14 +1787,13 @@ static int startup(struct mgsl_struct * info)
|
||||
|
||||
/* program hardware for current parameters */
|
||||
mgsl_change_params(info);
|
||||
|
||||
|
||||
if (info->port.tty)
|
||||
clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
|
||||
|
||||
info->port.flags |= ASYNC_INITIALIZED;
|
||||
|
||||
tty_port_set_initialized(&info->port, 1);
|
||||
|
||||
return 0;
|
||||
|
||||
} /* end of startup() */
|
||||
|
||||
/* shutdown()
|
||||
@@ -1808,8 +1806,8 @@ static int startup(struct mgsl_struct * info)
|
||||
static void shutdown(struct mgsl_struct * info)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!(info->port.flags & ASYNC_INITIALIZED))
|
||||
|
||||
if (!tty_port_initialized(&info->port))
|
||||
return;
|
||||
|
||||
if (debug_level >= DEBUG_LEVEL_INFO)
|
||||
@@ -1853,13 +1851,12 @@ static void shutdown(struct mgsl_struct * info)
|
||||
|
||||
spin_unlock_irqrestore(&info->irq_spinlock,flags);
|
||||
|
||||
mgsl_release_resources(info);
|
||||
|
||||
mgsl_release_resources(info);
|
||||
|
||||
if (info->port.tty)
|
||||
set_bit(TTY_IO_ERROR, &info->port.tty->flags);
|
||||
|
||||
info->port.flags &= ~ASYNC_INITIALIZED;
|
||||
|
||||
tty_port_set_initialized(&info->port, 0);
|
||||
} /* end of shutdown() */
|
||||
|
||||
static void mgsl_program_hw(struct mgsl_struct *info)
|
||||
@@ -1966,15 +1963,8 @@ static void mgsl_change_params(struct mgsl_struct *info)
|
||||
}
|
||||
info->timeout += HZ/50; /* Add .02 seconds of slop */
|
||||
|
||||
if (cflag & CRTSCTS)
|
||||
info->port.flags |= ASYNC_CTS_FLOW;
|
||||
else
|
||||
info->port.flags &= ~ASYNC_CTS_FLOW;
|
||||
|
||||
if (cflag & CLOCAL)
|
||||
info->port.flags &= ~ASYNC_CHECK_CD;
|
||||
else
|
||||
info->port.flags |= ASYNC_CHECK_CD;
|
||||
tty_port_set_cts_flow(&info->port, cflag & CRTSCTS);
|
||||
tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
|
||||
|
||||
/* process tty input control flags */
|
||||
|
||||
@@ -2972,7 +2962,7 @@ static int mgsl_ioctl(struct tty_struct *tty,
|
||||
|
||||
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
|
||||
(cmd != TIOCMIWAIT)) {
|
||||
if (tty->flags & (1 << TTY_IO_ERROR))
|
||||
if (tty_io_error(tty))
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -3049,7 +3039,7 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio
|
||||
/* Handle transition away from B0 status */
|
||||
if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
|
||||
info->serial_signals |= SerialSignal_DTR;
|
||||
if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
|
||||
if (!C_CRTSCTS(tty) || !tty_throttled(tty))
|
||||
info->serial_signals |= SerialSignal_RTS;
|
||||
spin_lock_irqsave(&info->irq_spinlock,flags);
|
||||
usc_set_serial_signals(info);
|
||||
@@ -3091,7 +3081,7 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp)
|
||||
goto cleanup;
|
||||
|
||||
mutex_lock(&info->port.mutex);
|
||||
if (info->port.flags & ASYNC_INITIALIZED)
|
||||
if (tty_port_initialized(&info->port))
|
||||
mgsl_wait_until_sent(tty, info->timeout);
|
||||
mgsl_flush_buffer(tty);
|
||||
tty_ldisc_flush(tty);
|
||||
@@ -3129,15 +3119,15 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout)
|
||||
if (debug_level >= DEBUG_LEVEL_INFO)
|
||||
printk("%s(%d):mgsl_wait_until_sent(%s) entry\n",
|
||||
__FILE__,__LINE__, info->device_name );
|
||||
|
||||
|
||||
if (mgsl_paranoia_check(info, tty->name, "mgsl_wait_until_sent"))
|
||||
return;
|
||||
|
||||
if (!(info->port.flags & ASYNC_INITIALIZED))
|
||||
if (!tty_port_initialized(&info->port))
|
||||
goto exit;
|
||||
|
||||
|
||||
orig_jiffies = jiffies;
|
||||
|
||||
|
||||
/* Set check interval to 1/5 of estimated time to
|
||||
* send a character, and make it at least 1. The check
|
||||
* interval should also be less than the timeout.
|
||||
@@ -3204,7 +3194,7 @@ static void mgsl_hangup(struct tty_struct *tty)
|
||||
shutdown(info);
|
||||
|
||||
info->port.count = 0;
|
||||
info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
tty_port_set_active(&info->port, 0);
|
||||
info->port.tty = NULL;
|
||||
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
@@ -3270,9 +3260,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||
printk("%s(%d):block_til_ready on %s\n",
|
||||
__FILE__,__LINE__, tty->driver->name );
|
||||
|
||||
if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
|
||||
if (filp->f_flags & O_NONBLOCK || tty_io_error(tty)) {
|
||||
/* nonblock mode is set or port is not enabled */
|
||||
port->flags |= ASYNC_NORMAL_ACTIVE;
|
||||
tty_port_set_active(port, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3297,14 +3287,14 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||
port->count--;
|
||||
spin_unlock_irqrestore(&info->irq_spinlock, flags);
|
||||
port->blocked_open++;
|
||||
|
||||
|
||||
while (1) {
|
||||
if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
|
||||
if (C_BAUD(tty) && tty_port_initialized(port))
|
||||
tty_port_raise_dtr_rts(port);
|
||||
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){
|
||||
|
||||
if (tty_hung_up_p(filp) || !tty_port_initialized(port)) {
|
||||
retval = (port->flags & ASYNC_HUP_NOTIFY) ?
|
||||
-EAGAIN : -ERESTARTSYS;
|
||||
break;
|
||||
@@ -3341,7 +3331,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||
__FILE__,__LINE__, tty->driver->name, port->count );
|
||||
|
||||
if (!retval)
|
||||
port->flags |= ASYNC_NORMAL_ACTIVE;
|
||||
tty_port_set_active(port, 1);
|
||||
|
||||
return retval;
|
||||
|
||||
|
@@ -726,7 +726,7 @@ static void close(struct tty_struct *tty, struct file *filp)
|
||||
goto cleanup;
|
||||
|
||||
mutex_lock(&info->port.mutex);
|
||||
if (info->port.flags & ASYNC_INITIALIZED)
|
||||
if (tty_port_initialized(&info->port))
|
||||
wait_until_sent(tty, info->timeout);
|
||||
flush_buffer(tty);
|
||||
tty_ldisc_flush(tty);
|
||||
@@ -756,9 +756,9 @@ static void hangup(struct tty_struct *tty)
|
||||
|
||||
spin_lock_irqsave(&info->port.lock, flags);
|
||||
info->port.count = 0;
|
||||
info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
info->port.tty = NULL;
|
||||
spin_unlock_irqrestore(&info->port.lock, flags);
|
||||
tty_port_set_active(&info->port, 0);
|
||||
mutex_unlock(&info->port.mutex);
|
||||
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
@@ -784,7 +784,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
||||
/* Handle transition away from B0 status */
|
||||
if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
|
||||
info->signals |= SerialSignal_DTR;
|
||||
if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
|
||||
if (!C_CRTSCTS(tty) || !tty_throttled(tty))
|
||||
info->signals |= SerialSignal_RTS;
|
||||
spin_lock_irqsave(&info->lock,flags);
|
||||
set_signals(info);
|
||||
@@ -893,7 +893,7 @@ static void wait_until_sent(struct tty_struct *tty, int timeout)
|
||||
if (sanity_check(info, tty->name, "wait_until_sent"))
|
||||
return;
|
||||
DBGINFO(("%s wait_until_sent entry\n", info->device_name));
|
||||
if (!(info->port.flags & ASYNC_INITIALIZED))
|
||||
if (!tty_port_initialized(&info->port))
|
||||
goto exit;
|
||||
|
||||
orig_jiffies = jiffies;
|
||||
@@ -1032,7 +1032,7 @@ static int ioctl(struct tty_struct *tty,
|
||||
|
||||
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
|
||||
(cmd != TIOCMIWAIT)) {
|
||||
if (tty->flags & (1 << TTY_IO_ERROR))
|
||||
if (tty_io_error(tty))
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -2080,7 +2080,7 @@ static void dcd_change(struct slgt_info *info, unsigned short status)
|
||||
wake_up_interruptible(&info->event_wait_q);
|
||||
info->pending_bh |= BH_STATUS;
|
||||
|
||||
if (info->port.flags & ASYNC_CHECK_CD) {
|
||||
if (tty_port_check_carrier(&info->port)) {
|
||||
if (info->signals & SerialSignal_DCD)
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
else {
|
||||
@@ -2421,7 +2421,7 @@ static int startup(struct slgt_info *info)
|
||||
{
|
||||
DBGINFO(("%s startup\n", info->device_name));
|
||||
|
||||
if (info->port.flags & ASYNC_INITIALIZED)
|
||||
if (tty_port_initialized(&info->port))
|
||||
return 0;
|
||||
|
||||
if (!info->tx_buf) {
|
||||
@@ -2442,7 +2442,7 @@ static int startup(struct slgt_info *info)
|
||||
if (info->port.tty)
|
||||
clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
|
||||
|
||||
info->port.flags |= ASYNC_INITIALIZED;
|
||||
tty_port_set_initialized(&info->port, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2454,7 +2454,7 @@ static void shutdown(struct slgt_info *info)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!(info->port.flags & ASYNC_INITIALIZED))
|
||||
if (!tty_port_initialized(&info->port))
|
||||
return;
|
||||
|
||||
DBGINFO(("%s shutdown\n", info->device_name));
|
||||
@@ -2489,7 +2489,7 @@ static void shutdown(struct slgt_info *info)
|
||||
if (info->port.tty)
|
||||
set_bit(TTY_IO_ERROR, &info->port.tty->flags);
|
||||
|
||||
info->port.flags &= ~ASYNC_INITIALIZED;
|
||||
tty_port_set_initialized(&info->port, 0);
|
||||
}
|
||||
|
||||
static void program_hw(struct slgt_info *info)
|
||||
@@ -2576,15 +2576,8 @@ static void change_params(struct slgt_info *info)
|
||||
}
|
||||
info->timeout += HZ/50; /* Add .02 seconds of slop */
|
||||
|
||||
if (cflag & CRTSCTS)
|
||||
info->port.flags |= ASYNC_CTS_FLOW;
|
||||
else
|
||||
info->port.flags &= ~ASYNC_CTS_FLOW;
|
||||
|
||||
if (cflag & CLOCAL)
|
||||
info->port.flags &= ~ASYNC_CHECK_CD;
|
||||
else
|
||||
info->port.flags |= ASYNC_CHECK_CD;
|
||||
tty_port_set_cts_flow(&info->port, cflag & CRTSCTS);
|
||||
tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
|
||||
|
||||
/* process tty input control flags */
|
||||
|
||||
@@ -3269,9 +3262,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
|
||||
|
||||
DBGINFO(("%s block_til_ready\n", tty->driver->name));
|
||||
|
||||
if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
|
||||
if (filp->f_flags & O_NONBLOCK || tty_io_error(tty)) {
|
||||
/* nonblock mode is set or port is not enabled */
|
||||
port->flags |= ASYNC_NORMAL_ACTIVE;
|
||||
tty_port_set_active(port, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3294,12 +3287,12 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
|
||||
port->blocked_open++;
|
||||
|
||||
while (1) {
|
||||
if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
|
||||
if (C_BAUD(tty) && tty_port_initialized(port))
|
||||
tty_port_raise_dtr_rts(port);
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){
|
||||
if (tty_hung_up_p(filp) || !tty_port_initialized(port)) {
|
||||
retval = (port->flags & ASYNC_HUP_NOTIFY) ?
|
||||
-EAGAIN : -ERESTARTSYS;
|
||||
break;
|
||||
@@ -3328,7 +3321,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
|
||||
port->blocked_open--;
|
||||
|
||||
if (!retval)
|
||||
port->flags |= ASYNC_NORMAL_ACTIVE;
|
||||
tty_port_set_active(port, 1);
|
||||
|
||||
DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval));
|
||||
return retval;
|
||||
|
@@ -812,7 +812,7 @@ static void close(struct tty_struct *tty, struct file *filp)
|
||||
goto cleanup;
|
||||
|
||||
mutex_lock(&info->port.mutex);
|
||||
if (info->port.flags & ASYNC_INITIALIZED)
|
||||
if (tty_port_initialized(&info->port))
|
||||
wait_until_sent(tty, info->timeout);
|
||||
|
||||
flush_buffer(tty);
|
||||
@@ -849,9 +849,9 @@ static void hangup(struct tty_struct *tty)
|
||||
|
||||
spin_lock_irqsave(&info->port.lock, flags);
|
||||
info->port.count = 0;
|
||||
info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
info->port.tty = NULL;
|
||||
spin_unlock_irqrestore(&info->port.lock, flags);
|
||||
tty_port_set_active(&info->port, 1);
|
||||
mutex_unlock(&info->port.mutex);
|
||||
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
@@ -881,7 +881,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
||||
/* Handle transition away from B0 status */
|
||||
if (!(old_termios->c_cflag & CBAUD) && C_BAUD(tty)) {
|
||||
info->serial_signals |= SerialSignal_DTR;
|
||||
if (!C_CRTSCTS(tty) || !test_bit(TTY_THROTTLED, &tty->flags))
|
||||
if (!C_CRTSCTS(tty) || !tty_throttled(tty))
|
||||
info->serial_signals |= SerialSignal_RTS;
|
||||
spin_lock_irqsave(&info->lock,flags);
|
||||
set_signals(info);
|
||||
@@ -1061,7 +1061,7 @@ static void wait_until_sent(struct tty_struct *tty, int timeout)
|
||||
if (sanity_check(info, tty->name, "wait_until_sent"))
|
||||
return;
|
||||
|
||||
if (!test_bit(ASYNCB_INITIALIZED, &info->port.flags))
|
||||
if (!tty_port_initialized(&info->port))
|
||||
goto exit;
|
||||
|
||||
orig_jiffies = jiffies;
|
||||
@@ -1261,7 +1261,7 @@ static int ioctl(struct tty_struct *tty,
|
||||
|
||||
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
|
||||
(cmd != TIOCMIWAIT)) {
|
||||
if (tty->flags & (1 << TTY_IO_ERROR))
|
||||
if (tty_io_error(tty))
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@@ -2463,7 +2463,7 @@ static void isr_io_pin( SLMP_INFO *info, u16 status )
|
||||
wake_up_interruptible(&info->status_event_wait_q);
|
||||
wake_up_interruptible(&info->event_wait_q);
|
||||
|
||||
if ( (info->port.flags & ASYNC_CHECK_CD) &&
|
||||
if (tty_port_check_carrier(&info->port) &&
|
||||
(status & MISCSTATUS_DCD_LATCHED) ) {
|
||||
if ( debug_level >= DEBUG_LEVEL_ISR )
|
||||
printk("%s CD now %s...", info->device_name,
|
||||
@@ -2636,7 +2636,7 @@ static int startup(SLMP_INFO * info)
|
||||
if ( debug_level >= DEBUG_LEVEL_INFO )
|
||||
printk("%s(%d):%s tx_releaseup()\n",__FILE__,__LINE__,info->device_name);
|
||||
|
||||
if (info->port.flags & ASYNC_INITIALIZED)
|
||||
if (tty_port_initialized(&info->port))
|
||||
return 0;
|
||||
|
||||
if (!info->tx_buf) {
|
||||
@@ -2662,7 +2662,7 @@ static int startup(SLMP_INFO * info)
|
||||
if (info->port.tty)
|
||||
clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
|
||||
|
||||
info->port.flags |= ASYNC_INITIALIZED;
|
||||
tty_port_set_initialized(&info->port, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2673,7 +2673,7 @@ static void shutdown(SLMP_INFO * info)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!(info->port.flags & ASYNC_INITIALIZED))
|
||||
if (!tty_port_initialized(&info->port))
|
||||
return;
|
||||
|
||||
if (debug_level >= DEBUG_LEVEL_INFO)
|
||||
@@ -2705,7 +2705,7 @@ static void shutdown(SLMP_INFO * info)
|
||||
if (info->port.tty)
|
||||
set_bit(TTY_IO_ERROR, &info->port.tty->flags);
|
||||
|
||||
info->port.flags &= ~ASYNC_INITIALIZED;
|
||||
tty_port_set_initialized(&info->port, 0);
|
||||
}
|
||||
|
||||
static void program_hw(SLMP_INFO *info)
|
||||
@@ -2813,15 +2813,8 @@ static void change_params(SLMP_INFO *info)
|
||||
}
|
||||
info->timeout += HZ/50; /* Add .02 seconds of slop */
|
||||
|
||||
if (cflag & CRTSCTS)
|
||||
info->port.flags |= ASYNC_CTS_FLOW;
|
||||
else
|
||||
info->port.flags &= ~ASYNC_CTS_FLOW;
|
||||
|
||||
if (cflag & CLOCAL)
|
||||
info->port.flags &= ~ASYNC_CHECK_CD;
|
||||
else
|
||||
info->port.flags |= ASYNC_CHECK_CD;
|
||||
tty_port_set_cts_flow(&info->port, cflag & CRTSCTS);
|
||||
tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
|
||||
|
||||
/* process tty input control flags */
|
||||
|
||||
@@ -3285,10 +3278,10 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
|
||||
printk("%s(%d):%s block_til_ready()\n",
|
||||
__FILE__,__LINE__, tty->driver->name );
|
||||
|
||||
if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
|
||||
if (filp->f_flags & O_NONBLOCK || tty_io_error(tty)) {
|
||||
/* nonblock mode is set or port is not enabled */
|
||||
/* just verify that callout device is not active */
|
||||
port->flags |= ASYNC_NORMAL_ACTIVE;
|
||||
tty_port_set_active(port, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3315,12 +3308,12 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
|
||||
port->blocked_open++;
|
||||
|
||||
while (1) {
|
||||
if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
|
||||
if (C_BAUD(tty) && tty_port_initialized(port))
|
||||
tty_port_raise_dtr_rts(port);
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)){
|
||||
if (tty_hung_up_p(filp) || !tty_port_initialized(port)) {
|
||||
retval = (port->flags & ASYNC_HUP_NOTIFY) ?
|
||||
-EAGAIN : -ERESTARTSYS;
|
||||
break;
|
||||
@@ -3355,7 +3348,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
|
||||
__FILE__,__LINE__, tty->driver->name, port->count );
|
||||
|
||||
if (!retval)
|
||||
port->flags |= ASYNC_NORMAL_ACTIVE;
|
||||
tty_port_set_active(port, 1);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@@ -37,29 +37,6 @@
|
||||
|
||||
#define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF)
|
||||
|
||||
/*
|
||||
* If all tty flip buffers have been processed by flush_to_ldisc() or
|
||||
* dropped by tty_buffer_flush(), check if the linked pty has been closed.
|
||||
* If so, wake the reader/poll to process
|
||||
*/
|
||||
static inline void check_other_closed(struct tty_struct *tty)
|
||||
{
|
||||
unsigned long flags, old;
|
||||
|
||||
/* transition from TTY_OTHER_CLOSED => TTY_OTHER_DONE must be atomic */
|
||||
for (flags = ACCESS_ONCE(tty->flags);
|
||||
test_bit(TTY_OTHER_CLOSED, &flags);
|
||||
) {
|
||||
old = flags;
|
||||
__set_bit(TTY_OTHER_DONE, &flags);
|
||||
flags = cmpxchg(&tty->flags, old, flags);
|
||||
if (old == flags) {
|
||||
wake_up_interruptible(&tty->read_wait);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_buffer_lock_exclusive - gain exclusive access to buffer
|
||||
* tty_buffer_unlock_exclusive - release exclusive access
|
||||
@@ -254,8 +231,6 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld)
|
||||
if (ld && ld->ops->flush_buffer)
|
||||
ld->ops->flush_buffer(tty);
|
||||
|
||||
check_other_closed(tty);
|
||||
|
||||
atomic_dec(&buf->priority);
|
||||
mutex_unlock(&buf->lock);
|
||||
}
|
||||
@@ -522,10 +497,8 @@ static void flush_to_ldisc(struct work_struct *work)
|
||||
*/
|
||||
count = smp_load_acquire(&head->commit) - head->read;
|
||||
if (!count) {
|
||||
if (next == NULL) {
|
||||
check_other_closed(tty);
|
||||
if (next == NULL)
|
||||
break;
|
||||
}
|
||||
buf->head = next;
|
||||
tty_buffer_free(port, head);
|
||||
continue;
|
||||
@@ -614,3 +587,8 @@ bool tty_buffer_cancel_work(struct tty_port *port)
|
||||
{
|
||||
return cancel_work_sync(&port->buf.work);
|
||||
}
|
||||
|
||||
void tty_buffer_flush_work(struct tty_port *port)
|
||||
{
|
||||
flush_work(&port->buf.work);
|
||||
}
|
||||
|
@@ -230,9 +230,6 @@ static void tty_del_file(struct file *file)
|
||||
tty_free_file(file);
|
||||
}
|
||||
|
||||
|
||||
#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base)
|
||||
|
||||
/**
|
||||
* tty_name - return tty naming
|
||||
* @tty: tty structure
|
||||
@@ -1070,7 +1067,7 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
|
||||
|
||||
if (tty_paranoia_check(tty, inode, "tty_read"))
|
||||
return -EIO;
|
||||
if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
|
||||
if (!tty || tty_io_error(tty))
|
||||
return -EIO;
|
||||
|
||||
/* We want to wait for the line discipline to sort out in this
|
||||
@@ -1245,8 +1242,7 @@ static ssize_t tty_write(struct file *file, const char __user *buf,
|
||||
|
||||
if (tty_paranoia_check(tty, file_inode(file), "tty_write"))
|
||||
return -EIO;
|
||||
if (!tty || !tty->ops->write ||
|
||||
(test_bit(TTY_IO_ERROR, &tty->flags)))
|
||||
if (!tty || !tty->ops->write || tty_io_error(tty))
|
||||
return -EIO;
|
||||
/* Short term debug to catch buggy drivers */
|
||||
if (tty->ops->write_room == NULL)
|
||||
@@ -1964,7 +1960,6 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
|
||||
* tty_lookup_driver - lookup a tty driver for a given device file
|
||||
* @device: device number
|
||||
* @filp: file pointer to tty
|
||||
* @noctty: set if the device should not become a controlling tty
|
||||
* @index: index for the device in the @return driver
|
||||
* @return: driver for this inode (with increased refcount)
|
||||
*
|
||||
|
@@ -158,7 +158,7 @@ int tty_throttle_safe(struct tty_struct *tty)
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&tty->throttle_mutex);
|
||||
if (!test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
if (!tty_throttled(tty)) {
|
||||
if (tty->flow_change != TTY_THROTTLE_SAFE)
|
||||
ret = 1;
|
||||
else {
|
||||
@@ -189,7 +189,7 @@ int tty_unthrottle_safe(struct tty_struct *tty)
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&tty->throttle_mutex);
|
||||
if (test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
if (tty_throttled(tty)) {
|
||||
if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
|
||||
ret = 1;
|
||||
else {
|
||||
|
@@ -204,7 +204,8 @@ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
|
||||
if (port->console)
|
||||
goto out;
|
||||
|
||||
if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) {
|
||||
if (tty_port_initialized(port)) {
|
||||
tty_port_set_initialized(port, 0);
|
||||
/*
|
||||
* Drop DTR/RTS if HUPCL is set. This causes any attached
|
||||
* modem to hang up the line.
|
||||
@@ -236,12 +237,12 @@ void tty_port_hangup(struct tty_port *port)
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
port->count = 0;
|
||||
port->flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
tty = port->tty;
|
||||
if (tty)
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
port->tty = NULL;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
tty_port_set_active(port, 0);
|
||||
tty_port_shutdown(port, tty);
|
||||
tty_kref_put(tty);
|
||||
wake_up_interruptible(&port->open_wait);
|
||||
@@ -364,15 +365,15 @@ int tty_port_block_til_ready(struct tty_port *port,
|
||||
|
||||
/* if non-blocking mode is set we can pass directly to open unless
|
||||
the port has just hung up or is in another error state */
|
||||
if (tty->flags & (1 << TTY_IO_ERROR)) {
|
||||
port->flags |= ASYNC_NORMAL_ACTIVE;
|
||||
if (tty_io_error(tty)) {
|
||||
tty_port_set_active(port, 1);
|
||||
return 0;
|
||||
}
|
||||
if (filp->f_flags & O_NONBLOCK) {
|
||||
/* Indicate we are open */
|
||||
if (C_BAUD(tty))
|
||||
tty_port_raise_dtr_rts(port);
|
||||
port->flags |= ASYNC_NORMAL_ACTIVE;
|
||||
tty_port_set_active(port, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -393,13 +394,13 @@ int tty_port_block_til_ready(struct tty_port *port,
|
||||
|
||||
while (1) {
|
||||
/* Indicate we are open */
|
||||
if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
|
||||
if (C_BAUD(tty) && tty_port_initialized(port))
|
||||
tty_port_raise_dtr_rts(port);
|
||||
|
||||
prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
|
||||
/* Check for a hangup or uninitialised port.
|
||||
Return accordingly */
|
||||
if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
|
||||
if (tty_hung_up_p(filp) || !tty_port_initialized(port)) {
|
||||
if (port->flags & ASYNC_HUP_NOTIFY)
|
||||
retval = -EAGAIN;
|
||||
else
|
||||
@@ -430,9 +431,9 @@ int tty_port_block_til_ready(struct tty_port *port,
|
||||
if (!tty_hung_up_p(filp))
|
||||
port->count++;
|
||||
port->blocked_open--;
|
||||
if (retval == 0)
|
||||
port->flags |= ASYNC_NORMAL_ACTIVE;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
if (retval == 0)
|
||||
tty_port_set_active(port, 1);
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_block_til_ready);
|
||||
@@ -480,7 +481,7 @@ int tty_port_close_start(struct tty_port *port,
|
||||
|
||||
tty->closing = 1;
|
||||
|
||||
if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
|
||||
if (tty_port_initialized(port)) {
|
||||
/* Don't block on a stalled port, just pull the chain */
|
||||
if (tty->flow_stopped)
|
||||
tty_driver_flush_buffer(tty);
|
||||
@@ -514,8 +515,8 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
wake_up_interruptible(&port->open_wait);
|
||||
}
|
||||
port->flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
tty_port_set_active(port, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_close_end);
|
||||
|
||||
@@ -578,7 +579,7 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty,
|
||||
|
||||
mutex_lock(&port->mutex);
|
||||
|
||||
if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
|
||||
if (!tty_port_initialized(port)) {
|
||||
clear_bit(TTY_IO_ERROR, &tty->flags);
|
||||
if (port->ops->activate) {
|
||||
int retval = port->ops->activate(port, tty);
|
||||
@@ -587,7 +588,7 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty,
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
set_bit(ASYNCB_INITIALIZED, &port->flags);
|
||||
tty_port_set_initialized(port, 1);
|
||||
}
|
||||
mutex_unlock(&port->mutex);
|
||||
return tty_port_block_til_ready(port, tty, filp);
|
||||
|
@@ -354,7 +354,7 @@ int paste_selection(struct tty_struct *tty)
|
||||
add_wait_queue(&vc->paste_wait, &wait);
|
||||
while (sel_buffer && sel_buffer_lth > pasted) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
if (tty_throttled(tty)) {
|
||||
schedule();
|
||||
continue;
|
||||
}
|
||||
|
@@ -760,50 +760,54 @@ static void visual_init(struct vc_data *vc, int num, int init)
|
||||
|
||||
int vc_allocate(unsigned int currcons) /* return 0 on success */
|
||||
{
|
||||
struct vt_notifier_param param;
|
||||
struct vc_data *vc;
|
||||
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
if (currcons >= MAX_NR_CONSOLES)
|
||||
return -ENXIO;
|
||||
if (!vc_cons[currcons].d) {
|
||||
struct vc_data *vc;
|
||||
struct vt_notifier_param param;
|
||||
|
||||
/* prevent users from taking too much memory */
|
||||
if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
|
||||
return -EPERM;
|
||||
if (vc_cons[currcons].d)
|
||||
return 0;
|
||||
|
||||
/* due to the granularity of kmalloc, we waste some memory here */
|
||||
/* the alloc is done in two steps, to optimize the common situation
|
||||
of a 25x80 console (structsize=216, screenbuf_size=4000) */
|
||||
/* although the numbers above are not valid since long ago, the
|
||||
point is still up-to-date and the comment still has its value
|
||||
even if only as a historical artifact. --mj, July 1998 */
|
||||
param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
|
||||
if (!vc)
|
||||
/* due to the granularity of kmalloc, we waste some memory here */
|
||||
/* the alloc is done in two steps, to optimize the common situation
|
||||
of a 25x80 console (structsize=216, screenbuf_size=4000) */
|
||||
/* although the numbers above are not valid since long ago, the
|
||||
point is still up-to-date and the comment still has its value
|
||||
even if only as a historical artifact. --mj, July 1998 */
|
||||
param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
|
||||
if (!vc)
|
||||
return -ENOMEM;
|
||||
vc_cons[currcons].d = vc;
|
||||
tty_port_init(&vc->port);
|
||||
INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
|
||||
visual_init(vc, currcons, 1);
|
||||
if (!*vc->vc_uni_pagedir_loc)
|
||||
|
||||
vc_cons[currcons].d = vc;
|
||||
tty_port_init(&vc->port);
|
||||
INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
|
||||
|
||||
visual_init(vc, currcons, 1);
|
||||
|
||||
if (!*vc->vc_uni_pagedir_loc)
|
||||
con_set_default_unimap(vc);
|
||||
vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
|
||||
if (!vc->vc_screenbuf) {
|
||||
kfree(vc);
|
||||
vc_cons[currcons].d = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* If no drivers have overridden us and the user didn't pass a
|
||||
boot option, default to displaying the cursor */
|
||||
if (global_cursor_default == -1)
|
||||
global_cursor_default = 1;
|
||||
vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
|
||||
if (!vc->vc_screenbuf)
|
||||
goto err_free;
|
||||
|
||||
/* If no drivers have overridden us and the user didn't pass a
|
||||
boot option, default to displaying the cursor */
|
||||
if (global_cursor_default == -1)
|
||||
global_cursor_default = 1;
|
||||
|
||||
vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
|
||||
vcs_make_sysfs(currcons);
|
||||
atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, ¶m);
|
||||
|
||||
vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
|
||||
vcs_make_sysfs(currcons);
|
||||
atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, ¶m);
|
||||
}
|
||||
return 0;
|
||||
err_free:
|
||||
kfree(vc);
|
||||
vc_cons[currcons].d = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static inline int resize_screen(struct vc_data *vc, int width, int height,
|
||||
@@ -1035,20 +1039,27 @@ struct vc_data *vc_deallocate(unsigned int currcons)
|
||||
#define VT100ID "\033[?1;2c"
|
||||
#define VT102ID "\033[?6c"
|
||||
|
||||
unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
|
||||
const unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
|
||||
8,12,10,14, 9,13,11,15 };
|
||||
|
||||
/* the default colour table, for VGA+ colour systems */
|
||||
int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
|
||||
0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
|
||||
int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
|
||||
0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
|
||||
int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
|
||||
0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
|
||||
unsigned char default_red[] = {
|
||||
0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
|
||||
0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff
|
||||
};
|
||||
module_param_array(default_red, byte, NULL, S_IRUGO | S_IWUSR);
|
||||
|
||||
module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR);
|
||||
module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR);
|
||||
module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR);
|
||||
unsigned char default_grn[] = {
|
||||
0x00, 0x00, 0xaa, 0x55, 0x00, 0x00, 0xaa, 0xaa,
|
||||
0x55, 0x55, 0xff, 0xff, 0x55, 0x55, 0xff, 0xff
|
||||
};
|
||||
module_param_array(default_grn, byte, NULL, S_IRUGO | S_IWUSR);
|
||||
|
||||
unsigned char default_blu[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
module_param_array(default_blu, byte, NULL, S_IRUGO | S_IWUSR);
|
||||
|
||||
/*
|
||||
* gotoxy() must verify all boundaries, because the arguments
|
||||
@@ -3564,7 +3575,7 @@ static int do_register_con_driver(const struct consw *csw, int first, int last)
|
||||
struct module *owner = csw->owner;
|
||||
struct con_driver *con_driver;
|
||||
const char *desc;
|
||||
int i, retval = 0;
|
||||
int i, retval;
|
||||
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
@@ -3575,17 +3586,17 @@ static int do_register_con_driver(const struct consw *csw, int first, int last)
|
||||
con_driver = ®istered_con_driver[i];
|
||||
|
||||
/* already registered */
|
||||
if (con_driver->con == csw)
|
||||
if (con_driver->con == csw) {
|
||||
retval = -EBUSY;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (retval)
|
||||
goto err;
|
||||
|
||||
desc = csw->con_startup();
|
||||
|
||||
if (!desc)
|
||||
if (!desc) {
|
||||
retval = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
retval = -EINVAL;
|
||||
|
||||
|
Reference in New Issue
Block a user