Commit 42b34a8d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull tty / serial driver fixes from Greg KH:
 "Here are some small tty and serial driver fixes for reported problems
  for 6.11-rc3. Included in here are:

   - sc16is7xx serial driver fixes

   - uartclk bugfix for a divide by zero issue

   - conmakehash userspace build issue fix

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'tty-6.11-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  tty: vt: conmakehash: cope with abs_srctree no longer in env
  serial: sc16is7xx: fix invalid FIFO access with special register set
  serial: sc16is7xx: fix TX fifo corruption
  serial: core: check uartclk for zero to avoid divide by zero
parents 84e6da57 6e20753d
Loading
Loading
Loading
Loading
+15 −10
Original line number Diff line number Diff line
@@ -327,6 +327,7 @@ struct sc16is7xx_one {
	struct kthread_work		reg_work;
	struct kthread_delayed_work	ms_work;
	struct sc16is7xx_one_config	config;
	unsigned char			buf[SC16IS7XX_FIFO_SIZE]; /* Rx buffer. */
	unsigned int			old_mctrl;
	u8				old_lcr; /* Value before EFR access. */
	bool				irda_mode;
@@ -340,7 +341,6 @@ struct sc16is7xx_port {
	unsigned long			gpio_valid_mask;
#endif
	u8				mctrl_mask;
	unsigned char			buf[SC16IS7XX_FIFO_SIZE];
	struct kthread_worker		kworker;
	struct task_struct		*kworker_task;
	struct sc16is7xx_one		p[];
@@ -592,6 +592,8 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
			      SC16IS7XX_MCR_CLKSEL_BIT,
			      prescaler == 1 ? 0 : SC16IS7XX_MCR_CLKSEL_BIT);

	mutex_lock(&one->efr_lock);

	/* Backup LCR and access special register set (DLL/DLH) */
	lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
	sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
@@ -606,24 +608,26 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
	/* Restore LCR and access to general register set */
	sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);

	mutex_unlock(&one->efr_lock);

	return DIV_ROUND_CLOSEST((clk / prescaler) / 16, div);
}

static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,
				unsigned int iir)
{
	struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
	struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
	unsigned int lsr = 0, bytes_read, i;
	bool read_lsr = (iir == SC16IS7XX_IIR_RLSE_SRC) ? true : false;
	u8 ch, flag;

	if (unlikely(rxlen >= sizeof(s->buf))) {
	if (unlikely(rxlen >= sizeof(one->buf))) {
		dev_warn_ratelimited(port->dev,
				     "ttySC%i: Possible RX FIFO overrun: %d\n",
				     port->line, rxlen);
		port->icount.buf_overrun++;
		/* Ensure sanity of RX level */
		rxlen = sizeof(s->buf);
		rxlen = sizeof(one->buf);
	}

	while (rxlen) {
@@ -636,10 +640,10 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,
			lsr = 0;

		if (read_lsr) {
			s->buf[0] = sc16is7xx_port_read(port, SC16IS7XX_RHR_REG);
			one->buf[0] = sc16is7xx_port_read(port, SC16IS7XX_RHR_REG);
			bytes_read = 1;
		} else {
			sc16is7xx_fifo_read(port, s->buf, rxlen);
			sc16is7xx_fifo_read(port, one->buf, rxlen);
			bytes_read = rxlen;
		}

@@ -672,7 +676,7 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,
		}

		for (i = 0; i < bytes_read; ++i) {
			ch = s->buf[i];
			ch = one->buf[i];
			if (uart_handle_sysrq_char(port, ch))
				continue;

@@ -690,10 +694,10 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,

static void sc16is7xx_handle_tx(struct uart_port *port)
{
	struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
	struct tty_port *tport = &port->state->port;
	unsigned long flags;
	unsigned int txlen;
	unsigned char *tail;

	if (unlikely(port->x_char)) {
		sc16is7xx_port_write(port, SC16IS7XX_THR_REG, port->x_char);
@@ -718,8 +722,9 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
		txlen = 0;
	}

	txlen = uart_fifo_out(port, s->buf, txlen);
	sc16is7xx_fifo_write(port, s->buf, txlen);
	txlen = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, txlen);
	sc16is7xx_fifo_write(port, tail, txlen);
	uart_xmit_advance(port, txlen);

	uart_port_lock_irqsave(port, &flags);
	if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
+8 −0
Original line number Diff line number Diff line
@@ -881,6 +881,14 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
	new_flags = (__force upf_t)new_info->flags;
	old_custom_divisor = uport->custom_divisor;

	if (!(uport->flags & UPF_FIXED_PORT)) {
		unsigned int uartclk = new_info->baud_base * 16;
		/* check needs to be done here before other settings made */
		if (uartclk == 0) {
			retval = -EINVAL;
			goto exit;
		}
	}
	if (!capable(CAP_SYS_ADMIN)) {
		retval = -EPERM;
		if (change_irq || change_port ||
+7 −13
Original line number Diff line number Diff line
@@ -11,6 +11,8 @@
 * Copyright (C) 1995-1997 H. Peter Anvin
 */

#include <libgen.h>
#include <linux/limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <sysexits.h>
@@ -76,8 +78,8 @@ static void addpair(int fp, int un)
int main(int argc, char *argv[])
{
  FILE *ctbl;
  const char *tblname, *rel_tblname;
  const char *abs_srctree;
  const char *tblname;
  char base_tblname[PATH_MAX];
  char buffer[65536];
  int fontlen;
  int i, nuni, nent;
@@ -102,16 +104,6 @@ int main(int argc, char *argv[])
	}
    }

  abs_srctree = getenv("abs_srctree");
  if (abs_srctree && !strncmp(abs_srctree, tblname, strlen(abs_srctree)))
    {
      rel_tblname = tblname + strlen(abs_srctree);
      while (*rel_tblname == '/')
	++rel_tblname;
    }
  else
    rel_tblname = tblname;

  /* For now we assume the default font is always 256 characters. */
  fontlen = 256;

@@ -253,6 +245,8 @@ int main(int argc, char *argv[])
  for ( i = 0 ; i < fontlen ; i++ )
    nuni += unicount[i];

  strncpy(base_tblname, tblname, PATH_MAX);
  base_tblname[PATH_MAX - 1] = 0;
  printf("\
/*\n\
 * Do not edit this file; it was automatically generated by\n\
@@ -264,7 +258,7 @@ int main(int argc, char *argv[])
#include <linux/types.h>\n\
\n\
u8 dfont_unicount[%d] = \n\
{\n\t", rel_tblname, fontlen);
{\n\t", basename(base_tblname), fontlen);

  for ( i = 0 ; i < fontlen ; i++ )
    {