TTY/Serial patches for 4.10-rc1

Here's the tty/serial patchset for 4.10-rc1.
 
 It's been a quiet kernel cycle for this subsystem, just a small number
 of changes.  A few new serial drivers, and some cleanups to the old
 vgacon logic, and other minor serial driver changes as well.
 
 All of these have been in linux-next for a while with no reported
 issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWFAwDQ8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ylcngCgko5+aPLnHENLNIaHhHlfdMbhy+EAn2H8wkzY
 bEf+BG4CJDb6nZWERcUQ
 =STpQ
 -----END PGP SIGNATURE-----

Merge tag 'tty-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty/serial updates from Greg KH:
 "Here's the tty/serial patchset for 4.10-rc1.

  It's been a quiet kernel cycle for this subsystem, just a small number
  of changes. A few new serial drivers, and some cleanups to the old
  vgacon logic, and other minor serial driver changes as well.

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

* tag 'tty-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (54 commits)
  serial: 8250_mid fix calltrace when hotplug 8250 serial controller
  console: Move userspace I/O out of console_lock to fix lockdep warning
  tty: nozomi: avoid sprintf buffer overflow
  serial: 8250_pci: Detach low-level driver during PCI error recovery
  serial: core: don't check port twice in a row
  mxs-auart: count FIFO overrun errors
  serial: 8250_dw: Add support for IrDA SIR mode
  serial: 8250: Expose set_ldisc function
  serial: 8250: Add IrDA to UART capabilities
  serial: 8250_dma: power off device after TX is done
  serial: 8250_port: export serial8250_rpm_{get|put}_tx()
  serial: sunsu: Free memory when probe fails
  serial: sunhv: Free memory when remove() is called
  vt: fix Scroll Lock LED trigger name
  tty: typo in comments in drivers/tty/vt/keyboard.c
  tty: amba-pl011: Add earlycon support for SBSA UART
  tty: nozomi: use permission-specific DEVICE_ATTR variants
  tty: serial: Make the STM32 serial port depend on it's arch
  serial: ifx6x60: Free memory when probe fails
  serial: ioc4_serial: Free memory when kzalloc fails during probe
  ...
This commit is contained in:
Linus Torvalds 2016-12-13 11:18:24 -08:00
commit 5266e70335
46 changed files with 919 additions and 427 deletions

View File

@ -4,15 +4,13 @@ Software cursor for VGA
by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz> by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>
and Martin Mares <mj@atrey.karlin.mff.cuni.cz> and Martin Mares <mj@atrey.karlin.mff.cuni.cz>
Linux now has some ability to manipulate cursor appearance. Normally, you Linux now has some ability to manipulate cursor appearance. Normally,
can set the size of hardware cursor (and also work around some ugly bugs in you can set the size of hardware cursor. You can now play a few new
those miserable Trident cards [#f1]_. You can now play a few new tricks: tricks: you can make your cursor look like a non-blinking red block,
you can make your cursor look make it inverse background of the character it's over or to highlight
that character and still choose whether the original hardware cursor
like a non-blinking red block, make it inverse background of the character it's should remain visible or not. There may be other things I have never
over or to highlight that character and still choose whether the original thought of.
hardware cursor should remain visible or not. There may be other things I have
never thought of.
The cursor appearance is controlled by a ``<ESC>[?1;2;3c`` escape sequence The cursor appearance is controlled by a ``<ESC>[?1;2;3c`` escape sequence
where 1, 2 and 3 are parameters described below. If you omit any of them, where 1, 2 and 3 are parameters described below. If you omit any of them,
@ -48,8 +46,6 @@ third parameter
Bit setting takes place before bit toggling, so you can simply clear a Bit setting takes place before bit toggling, so you can simply clear a
bit by including it in both the set mask and the toggle mask. bit by including it in both the set mask and the toggle mask.
.. [#f1] see ``#define TRIDENT_GLITCH`` in ``drivers/video/vgacon.c``.
Examples Examples
-------- --------

View File

@ -89,7 +89,7 @@ static void ce4100_mem_serial_out(struct uart_port *p, int offset, int value)
} }
static void ce4100_serial_fixup(int port, struct uart_port *up, static void ce4100_serial_fixup(int port, struct uart_port *up,
unsigned short *capabilites) u32 *capabilites)
{ {
#ifdef CONFIG_EARLY_PRINTK #ifdef CONFIG_EARLY_PRINTK
/* /*

View File

@ -1012,8 +1012,6 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
{ {
struct serial_struct tmp; struct serial_struct tmp;
if (!retinfo)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp)); memset(&tmp, 0, sizeof(tmp));
tty_lock(tty); tty_lock(tty);
tmp.line = tty->index; tmp.line = tty->index;

View File

@ -63,44 +63,23 @@
#define VERSION_STRING DRIVER_DESC " 2.1d" #define VERSION_STRING DRIVER_DESC " 2.1d"
/* Macros definitions */
/* Default debug printout level */ /* Default debug printout level */
#define NOZOMI_DEBUG_LEVEL 0x00 #define NOZOMI_DEBUG_LEVEL 0x00
static int debug = NOZOMI_DEBUG_LEVEL;
module_param(debug, int, S_IRUGO | S_IWUSR);
#define P_BUF_SIZE 128 /* Macros definitions */
#define NFO(_err_flag_, args...) \ #define DBG_(lvl, fmt, args...) \
do { \ do { \
char tmp[P_BUF_SIZE]; \ if (lvl & debug) \
snprintf(tmp, sizeof(tmp), ##args); \ pr_debug("[%d] %s(): " fmt "\n", \
printk(_err_flag_ "[%d] %s(): %s\n", __LINE__, \ __LINE__, __func__, ##args); \
__func__, tmp); \
} while (0) } while (0)
#define DBG1(args...) D_(0x01, ##args) #define DBG1(args...) DBG_(0x01, ##args)
#define DBG2(args...) D_(0x02, ##args) #define DBG2(args...) DBG_(0x02, ##args)
#define DBG3(args...) D_(0x04, ##args) #define DBG3(args...) DBG_(0x04, ##args)
#define DBG4(args...) D_(0x08, ##args) #define DBG4(args...) DBG_(0x08, ##args)
#define DBG5(args...) D_(0x10, ##args)
#define DBG6(args...) D_(0x20, ##args)
#define DBG7(args...) D_(0x40, ##args)
#define DBG8(args...) D_(0x80, ##args)
#ifdef DEBUG
/* Do we need this settable at runtime? */
static int debug = NOZOMI_DEBUG_LEVEL;
#define D(lvl, args...) do \
{if (lvl & debug) NFO(KERN_DEBUG, ##args); } \
while (0)
#define D_(lvl, args...) D(lvl, ##args)
/* These printouts are always printed */
#else
static int debug;
#define D_(lvl, args...)
#endif
/* TODO: rewrite to optimize macros... */ /* TODO: rewrite to optimize macros... */
@ -1320,7 +1299,7 @@ static ssize_t card_type_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%d\n", dc->card_type); return sprintf(buf, "%d\n", dc->card_type);
} }
static DEVICE_ATTR(card_type, S_IRUGO, card_type_show, NULL); static DEVICE_ATTR_RO(card_type);
static ssize_t open_ttys_show(struct device *dev, struct device_attribute *attr, static ssize_t open_ttys_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
@ -1329,7 +1308,7 @@ static ssize_t open_ttys_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%u\n", dc->open_ttys); return sprintf(buf, "%u\n", dc->open_ttys);
} }
static DEVICE_ATTR(open_ttys, S_IRUGO, open_ttys_show, NULL); static DEVICE_ATTR_RO(open_ttys);
static void make_sysfs_files(struct nozomi *dc) static void make_sysfs_files(struct nozomi *dc)
{ {
@ -1943,7 +1922,5 @@ static __exit void nozomi_exit(void)
module_init(nozomi_init); module_init(nozomi_init);
module_exit(nozomi_exit); module_exit(nozomi_exit);
module_param(debug, int, S_IRUGO | S_IWUSR);
MODULE_LICENSE("Dual BSD/GPL"); MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION(DRIVER_DESC); MODULE_DESCRIPTION(DRIVER_DESC);

View File

@ -1189,8 +1189,6 @@ static int get_config(struct r_port *info, struct rocket_config __user *retinfo)
{ {
struct rocket_config tmp; struct rocket_config tmp;
if (!retinfo)
return -EFAULT;
memset(&tmp, 0, sizeof (tmp)); memset(&tmp, 0, sizeof (tmp));
mutex_lock(&info->port.mutex); mutex_lock(&info->port.mutex);
tmp.line = info->line; tmp.line = info->line;
@ -1255,8 +1253,6 @@ static int get_ports(struct r_port *info, struct rocket_ports __user *retports)
struct rocket_ports tmp; struct rocket_ports tmp;
int board; int board;
if (!retports)
return -EFAULT;
memset(&tmp, 0, sizeof (tmp)); memset(&tmp, 0, sizeof (tmp));
tmp.tty_major = rocket_driver->major; tmp.tty_major = rocket_driver->major;

View File

@ -80,6 +80,7 @@ struct serial8250_config {
#define UART_CAP_RTOIE (1 << 13) /* UART needs IER bit 4 set (Xscale, Tegra) */ #define UART_CAP_RTOIE (1 << 13) /* UART needs IER bit 4 set (Xscale, Tegra) */
#define UART_CAP_HFIFO (1 << 14) /* UART has a "hidden" FIFO */ #define UART_CAP_HFIFO (1 << 14) /* UART has a "hidden" FIFO */
#define UART_CAP_RPM (1 << 15) /* Runtime PM is active while idle */ #define UART_CAP_RPM (1 << 15) /* Runtime PM is active while idle */
#define UART_CAP_IRDA (1 << 16) /* UART supports IrDA line discipline */
#define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */ #define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */
#define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */ #define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */
@ -129,8 +130,13 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value)
} }
struct uart_8250_port *serial8250_get_port(int line); struct uart_8250_port *serial8250_get_port(int line);
void serial8250_rpm_get(struct uart_8250_port *p); void serial8250_rpm_get(struct uart_8250_port *p);
void serial8250_rpm_put(struct uart_8250_port *p); void serial8250_rpm_put(struct uart_8250_port *p);
void serial8250_rpm_get_tx(struct uart_8250_port *p);
void serial8250_rpm_put_tx(struct uart_8250_port *p);
int serial8250_em485_init(struct uart_8250_port *p); int serial8250_em485_init(struct uart_8250_port *p);
void serial8250_em485_destroy(struct uart_8250_port *p); void serial8250_em485_destroy(struct uart_8250_port *p);

View File

@ -425,10 +425,10 @@ struct uart_8250_port *serial8250_get_port(int line)
EXPORT_SYMBOL_GPL(serial8250_get_port); EXPORT_SYMBOL_GPL(serial8250_get_port);
static void (*serial8250_isa_config)(int port, struct uart_port *up, static void (*serial8250_isa_config)(int port, struct uart_port *up,
unsigned short *capabilities); u32 *capabilities);
void serial8250_set_isa_configurator( void serial8250_set_isa_configurator(
void (*v)(int port, struct uart_port *up, unsigned short *capabilities)) void (*v)(int port, struct uart_port *up, u32 *capabilities))
{ {
serial8250_isa_config = v; serial8250_isa_config = v;
} }
@ -830,6 +830,7 @@ static int serial8250_probe(struct platform_device *dev)
uart.port.handle_irq = p->handle_irq; uart.port.handle_irq = p->handle_irq;
uart.port.handle_break = p->handle_break; uart.port.handle_break = p->handle_break;
uart.port.set_termios = p->set_termios; uart.port.set_termios = p->set_termios;
uart.port.set_ldisc = p->set_ldisc;
uart.port.get_mctrl = p->get_mctrl; uart.port.get_mctrl = p->get_mctrl;
uart.port.pm = p->pm; uart.port.pm = p->pm;
uart.port.dev = &dev->dev; uart.port.dev = &dev->dev;
@ -1023,6 +1024,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
/* Possibly override set_termios call */ /* Possibly override set_termios call */
if (up->port.set_termios) if (up->port.set_termios)
uart->port.set_termios = up->port.set_termios; uart->port.set_termios = up->port.set_termios;
if (up->port.set_ldisc)
uart->port.set_ldisc = up->port.set_ldisc;
if (up->port.get_mctrl) if (up->port.get_mctrl)
uart->port.get_mctrl = up->port.get_mctrl; uart->port.get_mctrl = up->port.get_mctrl;
if (up->port.set_mctrl) if (up->port.set_mctrl)

View File

@ -72,10 +72,15 @@ int serial8250_tx_dma(struct uart_8250_port *p)
struct dma_async_tx_descriptor *desc; struct dma_async_tx_descriptor *desc;
int ret; int ret;
if (uart_tx_stopped(&p->port) || dma->tx_running || if (dma->tx_running)
uart_circ_empty(xmit))
return 0; return 0;
if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) {
/* We have been called from __dma_tx_complete() */
serial8250_rpm_put_tx(p);
return 0;
}
dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
desc = dmaengine_prep_slave_single(dma->txchan, desc = dmaengine_prep_slave_single(dma->txchan,

View File

@ -53,6 +53,8 @@
/* Helper for fifo size calculation */ /* Helper for fifo size calculation */
#define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16) #define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16)
/* DesignWare specific register fields */
#define DW_UART_MCR_SIRE BIT(6)
struct dw8250_data { struct dw8250_data {
u8 usr_reg; u8 usr_reg;
@ -254,6 +256,22 @@ out:
serial8250_do_set_termios(p, termios, old); serial8250_do_set_termios(p, termios, old);
} }
static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios)
{
struct uart_8250_port *up = up_to_u8250p(p);
unsigned int mcr = p->serial_in(p, UART_MCR);
if (up->capabilities & UART_CAP_IRDA) {
if (termios->c_line == N_IRDA)
mcr |= DW_UART_MCR_SIRE;
else
mcr &= ~DW_UART_MCR_SIRE;
p->serial_out(p, UART_MCR, mcr);
}
serial8250_do_set_ldisc(p, termios);
}
/* /*
* dw8250_fallback_dma_filter will prevent the UART from getting just any free * dw8250_fallback_dma_filter will prevent the UART from getting just any free
* channel on platforms that have DMA engines, but don't have any channels * channel on platforms that have DMA engines, but don't have any channels
@ -357,6 +375,9 @@ static void dw8250_setup_port(struct uart_port *p)
if (reg & DW_UART_CPR_AFCE_MODE) if (reg & DW_UART_CPR_AFCE_MODE)
up->capabilities |= UART_CAP_AFE; up->capabilities |= UART_CAP_AFE;
if (reg & DW_UART_CPR_SIR_MODE)
up->capabilities |= UART_CAP_IRDA;
} }
static int dw8250_probe(struct platform_device *pdev) static int dw8250_probe(struct platform_device *pdev)
@ -392,6 +413,7 @@ static int dw8250_probe(struct platform_device *pdev)
p->iotype = UPIO_MEM; p->iotype = UPIO_MEM;
p->serial_in = dw8250_serial_in; p->serial_in = dw8250_serial_in;
p->serial_out = dw8250_serial_out; p->serial_out = dw8250_serial_out;
p->set_ldisc = dw8250_set_ldisc;
p->membase = devm_ioremap(dev, regs->start, resource_size(regs)); p->membase = devm_ioremap(dev, regs->start, resource_size(regs));
if (!p->membase) if (!p->membase)

View File

@ -21,8 +21,11 @@
#define EXIT_KEY 0xAA #define EXIT_KEY 0xAA
#define CHIP_ID1 0x20 #define CHIP_ID1 0x20
#define CHIP_ID2 0x21 #define CHIP_ID2 0x21
#define CHIP_ID_0 0x1602 #define CHIP_ID_F81865 0x0407
#define CHIP_ID_1 0x0501 #define CHIP_ID_F81866 0x1010
#define CHIP_ID_F81216AD 0x1602
#define CHIP_ID_F81216H 0x0501
#define CHIP_ID_F81216 0x0802
#define VENDOR_ID1 0x23 #define VENDOR_ID1 0x23
#define VENDOR_ID1_VAL 0x19 #define VENDOR_ID1_VAL 0x19
#define VENDOR_ID2 0x24 #define VENDOR_ID2 0x24
@ -43,12 +46,60 @@
#define RXW4C_IRA BIT(3) #define RXW4C_IRA BIT(3)
#define TXW4C_IRA BIT(2) #define TXW4C_IRA BIT(2)
#define FIFO_CTRL 0xF6
#define FIFO_MODE_MASK (BIT(1) | BIT(0))
#define FIFO_MODE_128 (BIT(1) | BIT(0))
#define RXFTHR_MODE_MASK (BIT(5) | BIT(4))
#define RXFTHR_MODE_4X BIT(5)
#define F81216_LDN_LOW 0x0
#define F81216_LDN_HIGH 0x4
/*
* F81866 registers
*
* The IRQ setting mode of F81866 is not the same with F81216 series.
* Level/Low: IRQ_MODE0:0, IRQ_MODE1:0
* Edge/High: IRQ_MODE0:1, IRQ_MODE1:0
*/
#define F81866_IRQ_MODE 0xf0
#define F81866_IRQ_SHARE BIT(0)
#define F81866_IRQ_MODE0 BIT(1)
#define F81866_FIFO_CTRL FIFO_CTRL
#define F81866_IRQ_MODE1 BIT(3)
#define F81866_LDN_LOW 0x10
#define F81866_LDN_HIGH 0x16
struct fintek_8250 { struct fintek_8250 {
u16 pid;
u16 base_port; u16 base_port;
u8 index; u8 index;
u8 key; u8 key;
}; };
static u8 sio_read_reg(struct fintek_8250 *pdata, u8 reg)
{
outb(reg, pdata->base_port + ADDR_PORT);
return inb(pdata->base_port + DATA_PORT);
}
static void sio_write_reg(struct fintek_8250 *pdata, u8 reg, u8 data)
{
outb(reg, pdata->base_port + ADDR_PORT);
outb(data, pdata->base_port + DATA_PORT);
}
static void sio_write_mask_reg(struct fintek_8250 *pdata, u8 reg, u8 mask,
u8 data)
{
u8 tmp;
tmp = (sio_read_reg(pdata, reg) & ~mask) | (mask & data);
sio_write_reg(pdata, reg, tmp);
}
static int fintek_8250_enter_key(u16 base_port, u8 key) static int fintek_8250_enter_key(u16 base_port, u8 key)
{ {
if (!request_muxed_region(base_port, 2, "8250_fintek")) if (!request_muxed_region(base_port, 2, "8250_fintek"))
@ -66,29 +117,55 @@ static void fintek_8250_exit_key(u16 base_port)
release_region(base_port + ADDR_PORT, 2); release_region(base_port + ADDR_PORT, 2);
} }
static int fintek_8250_check_id(u16 base_port) static int fintek_8250_check_id(struct fintek_8250 *pdata)
{ {
u16 chip; u16 chip;
outb(VENDOR_ID1, base_port + ADDR_PORT); if (sio_read_reg(pdata, VENDOR_ID1) != VENDOR_ID1_VAL)
if (inb(base_port + DATA_PORT) != VENDOR_ID1_VAL)
return -ENODEV; return -ENODEV;
outb(VENDOR_ID2, base_port + ADDR_PORT); if (sio_read_reg(pdata, VENDOR_ID2) != VENDOR_ID2_VAL)
if (inb(base_port + DATA_PORT) != VENDOR_ID2_VAL)
return -ENODEV; return -ENODEV;
outb(CHIP_ID1, base_port + ADDR_PORT); chip = sio_read_reg(pdata, CHIP_ID1);
chip = inb(base_port + DATA_PORT); chip |= sio_read_reg(pdata, CHIP_ID2) << 8;
outb(CHIP_ID2, base_port + ADDR_PORT);
chip |= inb(base_port + DATA_PORT) << 8;
if (chip != CHIP_ID_0 && chip != CHIP_ID_1) switch (chip) {
case CHIP_ID_F81865:
case CHIP_ID_F81866:
case CHIP_ID_F81216AD:
case CHIP_ID_F81216H:
case CHIP_ID_F81216:
break;
default:
return -ENODEV; return -ENODEV;
}
pdata->pid = chip;
return 0; return 0;
} }
static int fintek_8250_get_ldn_range(struct fintek_8250 *pdata, int *min,
int *max)
{
switch (pdata->pid) {
case CHIP_ID_F81865:
case CHIP_ID_F81866:
*min = F81866_LDN_LOW;
*max = F81866_LDN_HIGH;
return 0;
case CHIP_ID_F81216AD:
case CHIP_ID_F81216H:
case CHIP_ID_F81216:
*min = F81216_LDN_LOW;
*max = F81216_LDN_HIGH;
return 0;
}
return -ENODEV;
}
static int fintek_8250_rs485_config(struct uart_port *port, static int fintek_8250_rs485_config(struct uart_port *port,
struct serial_rs485 *rs485) struct serial_rs485 *rs485)
{ {
@ -128,10 +205,8 @@ static int fintek_8250_rs485_config(struct uart_port *port,
if (fintek_8250_enter_key(pdata->base_port, pdata->key)) if (fintek_8250_enter_key(pdata->base_port, pdata->key))
return -EBUSY; return -EBUSY;
outb(LDN, pdata->base_port + ADDR_PORT); sio_write_reg(pdata, LDN, pdata->index);
outb(pdata->index, pdata->base_port + DATA_PORT); sio_write_reg(pdata, RS485, config);
outb(RS485, pdata->base_port + ADDR_PORT);
outb(config, pdata->base_port + DATA_PORT);
fintek_8250_exit_key(pdata->base_port); fintek_8250_exit_key(pdata->base_port);
port->rs485 = *rs485; port->rs485 = *rs485;
@ -139,40 +214,90 @@ static int fintek_8250_rs485_config(struct uart_port *port,
return 0; return 0;
} }
static int find_base_port(struct fintek_8250 *pdata, u16 io_address) static void fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool is_level)
{
sio_write_reg(pdata, LDN, pdata->index);
switch (pdata->pid) {
case CHIP_ID_F81866:
sio_write_mask_reg(pdata, F81866_FIFO_CTRL, F81866_IRQ_MODE1,
0);
/* fall through */
case CHIP_ID_F81865:
sio_write_mask_reg(pdata, F81866_IRQ_MODE, F81866_IRQ_SHARE,
F81866_IRQ_SHARE);
sio_write_mask_reg(pdata, F81866_IRQ_MODE, F81866_IRQ_MODE0,
is_level ? 0 : F81866_IRQ_MODE0);
break;
case CHIP_ID_F81216AD:
case CHIP_ID_F81216H:
case CHIP_ID_F81216:
sio_write_mask_reg(pdata, FINTEK_IRQ_MODE, IRQ_SHARE,
IRQ_SHARE);
sio_write_mask_reg(pdata, FINTEK_IRQ_MODE, IRQ_MODE_MASK,
is_level ? IRQ_LEVEL_LOW : IRQ_EDGE_HIGH);
break;
}
}
static void fintek_8250_set_max_fifo(struct fintek_8250 *pdata)
{
switch (pdata->pid) {
case CHIP_ID_F81216H: /* 128Bytes FIFO */
case CHIP_ID_F81866:
sio_write_mask_reg(pdata, FIFO_CTRL,
FIFO_MODE_MASK | RXFTHR_MODE_MASK,
FIFO_MODE_128 | RXFTHR_MODE_4X);
break;
default: /* Default 16Bytes FIFO */
break;
}
}
static int probe_setup_port(struct fintek_8250 *pdata, u16 io_address,
unsigned int irq)
{ {
static const u16 addr[] = {0x4e, 0x2e}; static const u16 addr[] = {0x4e, 0x2e};
static const u8 keys[] = {0x77, 0xa0, 0x87, 0x67}; static const u8 keys[] = {0x77, 0xa0, 0x87, 0x67};
int i, j, k; struct irq_data *irq_data;
bool level_mode = false;
int i, j, k, min, max;
for (i = 0; i < ARRAY_SIZE(addr); i++) { for (i = 0; i < ARRAY_SIZE(addr); i++) {
for (j = 0; j < ARRAY_SIZE(keys); j++) { for (j = 0; j < ARRAY_SIZE(keys); j++) {
pdata->base_port = addr[i];
pdata->key = keys[j];
if (fintek_8250_enter_key(addr[i], keys[j])) if (fintek_8250_enter_key(addr[i], keys[j]))
continue; continue;
if (fintek_8250_check_id(addr[i])) { if (fintek_8250_check_id(pdata) ||
fintek_8250_get_ldn_range(pdata, &min, &max)) {
fintek_8250_exit_key(addr[i]); fintek_8250_exit_key(addr[i]);
continue; continue;
} }
for (k = 0; k < 4; k++) { for (k = min; k < max; k++) {
u16 aux; u16 aux;
outb(LDN, addr[i] + ADDR_PORT); sio_write_reg(pdata, LDN, k);
outb(k, addr[i] + DATA_PORT); aux = sio_read_reg(pdata, IO_ADDR1);
aux |= sio_read_reg(pdata, IO_ADDR2) << 8;
outb(IO_ADDR1, addr[i] + ADDR_PORT);
aux = inb(addr[i] + DATA_PORT);
outb(IO_ADDR2, addr[i] + ADDR_PORT);
aux |= inb(addr[i] + DATA_PORT) << 8;
if (aux != io_address) if (aux != io_address)
continue; continue;
fintek_8250_exit_key(addr[i]);
pdata->key = keys[j];
pdata->base_port = addr[i];
pdata->index = k; pdata->index = k;
irq_data = irq_get_irq_data(irq);
if (irq_data)
level_mode =
irqd_is_level_type(irq_data);
fintek_8250_set_irq_mode(pdata, level_mode);
fintek_8250_set_max_fifo(pdata);
fintek_8250_exit_key(addr[i]);
return 0; return 0;
} }
@ -183,39 +308,29 @@ static int find_base_port(struct fintek_8250 *pdata, u16 io_address)
return -ENODEV; return -ENODEV;
} }
static int fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool level_mode) static void fintek_8250_set_rs485_handler(struct uart_8250_port *uart)
{ {
int status; struct fintek_8250 *pdata = uart->port.private_data;
u8 tmp;
status = fintek_8250_enter_key(pdata->base_port, pdata->key); switch (pdata->pid) {
if (status) case CHIP_ID_F81216AD:
return status; case CHIP_ID_F81216H:
case CHIP_ID_F81866:
case CHIP_ID_F81865:
uart->port.rs485_config = fintek_8250_rs485_config;
break;
outb(LDN, pdata->base_port + ADDR_PORT); default: /* No RS485 Auto direction functional */
outb(pdata->index, pdata->base_port + DATA_PORT); break;
}
outb(FINTEK_IRQ_MODE, pdata->base_port + ADDR_PORT);
tmp = inb(pdata->base_port + DATA_PORT);
tmp &= ~IRQ_MODE_MASK;
tmp |= IRQ_SHARE;
if (!level_mode)
tmp |= IRQ_EDGE_HIGH;
outb(tmp, pdata->base_port + DATA_PORT);
fintek_8250_exit_key(pdata->base_port);
return 0;
} }
int fintek_8250_probe(struct uart_8250_port *uart) int fintek_8250_probe(struct uart_8250_port *uart)
{ {
struct fintek_8250 *pdata; struct fintek_8250 *pdata;
struct fintek_8250 probe_data; struct fintek_8250 probe_data;
struct irq_data *irq_data = irq_get_irq_data(uart->port.irq);
bool level_mode = irqd_is_level_type(irq_data);
if (find_base_port(&probe_data, uart->port.iobase)) if (probe_setup_port(&probe_data, uart->port.iobase, uart->port.irq))
return -ENODEV; return -ENODEV;
pdata = devm_kzalloc(uart->port.dev, sizeof(*pdata), GFP_KERNEL); pdata = devm_kzalloc(uart->port.dev, sizeof(*pdata), GFP_KERNEL);
@ -223,8 +338,8 @@ int fintek_8250_probe(struct uart_8250_port *uart)
return -ENOMEM; return -ENOMEM;
memcpy(pdata, &probe_data, sizeof(probe_data)); memcpy(pdata, &probe_data, sizeof(probe_data));
uart->port.rs485_config = fintek_8250_rs485_config;
uart->port.private_data = pdata; uart->port.private_data = pdata;
fintek_8250_set_rs485_handler(uart);
return fintek_8250_set_irq_mode(pdata, level_mode); return 0;
} }

View File

@ -174,7 +174,7 @@ static void qrk_serial_setup_dma(struct lpss8250 *lpss, struct uart_port *port)
int ret; int ret;
chip->dev = &pdev->dev; chip->dev = &pdev->dev;
chip->irq = pdev->irq; chip->irq = pci_irq_vector(pdev, 0);
chip->regs = pci_ioremap_bar(pdev, 1); chip->regs = pci_ioremap_bar(pdev, 1);
chip->pdata = &qrk_serial_dma_pdata; chip->pdata = &qrk_serial_dma_pdata;
@ -183,6 +183,9 @@ static void qrk_serial_setup_dma(struct lpss8250 *lpss, struct uart_port *port)
if (ret) if (ret)
return; return;
pci_set_master(pdev);
pci_try_set_mwi(pdev);
/* Special DMA address for UART */ /* Special DMA address for UART */
dma->rx_dma_addr = 0xfffff000; dma->rx_dma_addr = 0xfffff000;
dma->tx_dma_addr = 0xfffff000; dma->tx_dma_addr = 0xfffff000;
@ -280,8 +283,6 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret) if (ret)
return ret; return ret;
pci_set_master(pdev);
lpss = devm_kzalloc(&pdev->dev, sizeof(*lpss), GFP_KERNEL); lpss = devm_kzalloc(&pdev->dev, sizeof(*lpss), GFP_KERNEL);
if (!lpss) if (!lpss)
return -ENOMEM; return -ENOMEM;

View File

@ -303,10 +303,10 @@ static void mid8250_remove(struct pci_dev *pdev)
{ {
struct mid8250 *mid = pci_get_drvdata(pdev); struct mid8250 *mid = pci_get_drvdata(pdev);
serial8250_unregister_port(mid->line);
if (mid->board->exit) if (mid->board->exit)
mid->board->exit(mid); mid->board->exit(mid);
serial8250_unregister_port(mid->line);
} }
static const struct mid8250_board pnw_board = { static const struct mid8250_board pnw_board = {

View File

@ -332,8 +332,6 @@ static const struct of_device_id of_platform_serial_table[] = {
.data = (void *)PORT_ALTR_16550_F128, }, .data = (void *)PORT_ALTR_16550_F128, },
{ .compatible = "mrvl,mmp-uart", { .compatible = "mrvl,mmp-uart",
.data = (void *)PORT_XSCALE, }, .data = (void *)PORT_XSCALE, },
{ .compatible = "mrvl,pxa-uart",
.data = (void *)PORT_XSCALE, },
{ /* end of list */ }, { /* end of list */ },
}; };
MODULE_DEVICE_TABLE(of, of_platform_serial_table); MODULE_DEVICE_TABLE(of, of_platform_serial_table);

View File

@ -52,6 +52,7 @@ struct serial_private {
struct pci_dev *dev; struct pci_dev *dev;
unsigned int nr; unsigned int nr;
struct pci_serial_quirk *quirk; struct pci_serial_quirk *quirk;
const struct pciserial_board *board;
int line[0]; int line[0];
}; };
@ -1329,6 +1330,30 @@ static int pci_default_setup(struct serial_private *priv,
return setup_port(priv, port, bar, offset, board->reg_shift); return setup_port(priv, port, bar, offset, board->reg_shift);
} }
static int pci_pericom_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_8250_port *port, int idx)
{
unsigned int bar, offset = board->first_offset, maxnr;
bar = FL_GET_BASE(board->flags);
if (board->flags & FL_BASE_BARS)
bar += idx;
else
offset += idx * board->uart_offset;
if (idx==3)
offset = 0x38;
maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >>
(board->reg_shift + 3);
if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
return 1;
return setup_port(priv, port, bar, offset, board->reg_shift);
}
static int static int
ce4100_serial_setup(struct serial_private *priv, ce4100_serial_setup(struct serial_private *priv,
const struct pciserial_board *board, const struct pciserial_board *board,
@ -2095,6 +2120,16 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.setup = pci_default_setup, .setup = pci_default_setup,
.exit = pci_plx9050_exit, .exit = pci_plx9050_exit,
}, },
/*
* Pericom (Only 7954 - It have a offset jump for port 4)
*/
{
.vendor = PCI_VENDOR_ID_PERICOM,
.device = PCI_DEVICE_ID_PERICOM_PI7C9X7954,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_pericom_setup,
},
/* /*
* PLX * PLX
*/ */
@ -3862,6 +3897,7 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
} }
} }
priv->nr = i; priv->nr = i;
priv->board = board;
return priv; return priv;
err_deinit: err_deinit:
@ -3872,7 +3908,7 @@ err_out:
} }
EXPORT_SYMBOL_GPL(pciserial_init_ports); EXPORT_SYMBOL_GPL(pciserial_init_ports);
void pciserial_remove_ports(struct serial_private *priv) void pciserial_detach_ports(struct serial_private *priv)
{ {
struct pci_serial_quirk *quirk; struct pci_serial_quirk *quirk;
int i; int i;
@ -3886,7 +3922,11 @@ void pciserial_remove_ports(struct serial_private *priv)
quirk = find_quirk(priv->dev); quirk = find_quirk(priv->dev);
if (quirk->exit) if (quirk->exit)
quirk->exit(priv->dev); quirk->exit(priv->dev);
}
void pciserial_remove_ports(struct serial_private *priv)
{
pciserial_detach_ports(priv);
kfree(priv); kfree(priv);
} }
EXPORT_SYMBOL_GPL(pciserial_remove_ports); EXPORT_SYMBOL_GPL(pciserial_remove_ports);
@ -5577,7 +5617,7 @@ static pci_ers_result_t serial8250_io_error_detected(struct pci_dev *dev,
return PCI_ERS_RESULT_DISCONNECT; return PCI_ERS_RESULT_DISCONNECT;
if (priv) if (priv)
pciserial_suspend_ports(priv); pciserial_detach_ports(priv);
pci_disable_device(dev); pci_disable_device(dev);
@ -5602,9 +5642,18 @@ static pci_ers_result_t serial8250_io_slot_reset(struct pci_dev *dev)
static void serial8250_io_resume(struct pci_dev *dev) static void serial8250_io_resume(struct pci_dev *dev)
{ {
struct serial_private *priv = pci_get_drvdata(dev); struct serial_private *priv = pci_get_drvdata(dev);
const struct pciserial_board *board;
if (priv) if (!priv)
pciserial_resume_ports(priv); return;
board = priv->board;
kfree(priv);
priv = pciserial_init_ports(dev, board);
if (!IS_ERR(priv)) {
pci_set_drvdata(dev, priv);
}
} }
static const struct pci_error_handlers serial8250_err_handler = { static const struct pci_error_handlers serial8250_err_handler = {

View File

@ -636,7 +636,7 @@ EXPORT_SYMBOL_GPL(serial8250_em485_destroy);
* once and disable_runtime_pm_tx() will still disable RPM because the fifo is * once and disable_runtime_pm_tx() will still disable RPM because the fifo is
* empty and the HW can idle again. * empty and the HW can idle again.
*/ */
static void serial8250_rpm_get_tx(struct uart_8250_port *p) void serial8250_rpm_get_tx(struct uart_8250_port *p)
{ {
unsigned char rpm_active; unsigned char rpm_active;
@ -648,8 +648,9 @@ static void serial8250_rpm_get_tx(struct uart_8250_port *p)
return; return;
pm_runtime_get_sync(p->port.dev); pm_runtime_get_sync(p->port.dev);
} }
EXPORT_SYMBOL_GPL(serial8250_rpm_get_tx);
static void serial8250_rpm_put_tx(struct uart_8250_port *p) void serial8250_rpm_put_tx(struct uart_8250_port *p)
{ {
unsigned char rpm_active; unsigned char rpm_active;
@ -662,6 +663,7 @@ static void serial8250_rpm_put_tx(struct uart_8250_port *p)
pm_runtime_mark_last_busy(p->port.dev); pm_runtime_mark_last_busy(p->port.dev);
pm_runtime_put_autosuspend(p->port.dev); pm_runtime_put_autosuspend(p->port.dev);
} }
EXPORT_SYMBOL_GPL(serial8250_rpm_put_tx);
/* /*
* IER sleep support. UARTs which have EFRs need the "extended * IER sleep support. UARTs which have EFRs need the "extended
@ -2691,8 +2693,7 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
serial8250_do_set_termios(port, termios, old); serial8250_do_set_termios(port, termios, old);
} }
static void void serial8250_do_set_ldisc(struct uart_port *port, struct ktermios *termios)
serial8250_set_ldisc(struct uart_port *port, struct ktermios *termios)
{ {
if (termios->c_line == N_PPS) { if (termios->c_line == N_PPS) {
port->flags |= UPF_HARDPPS_CD; port->flags |= UPF_HARDPPS_CD;
@ -2708,7 +2709,16 @@ serial8250_set_ldisc(struct uart_port *port, struct ktermios *termios)
} }
} }
} }
EXPORT_SYMBOL_GPL(serial8250_do_set_ldisc);
static void
serial8250_set_ldisc(struct uart_port *port, struct ktermios *termios)
{
if (port->set_ldisc)
port->set_ldisc(port, termios);
else
serial8250_do_set_ldisc(port, termios);
}
void serial8250_do_pm(struct uart_port *port, unsigned int state, void serial8250_do_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate) unsigned int oldstate)

View File

@ -0,0 +1,190 @@
/*
* drivers/tty/serial/8250/8250_pxa.c -- driver for PXA on-board UARTS
* Copyright: (C) 2013 Sergei Ianovich <ynvich@gmail.com>
*
* replaces drivers/serial/pxa.c by Nicolas Pitre
* Created: Feb 20, 2003
* Copyright: (C) 2003 Monta Vista Software, Inc.
*
* Based on drivers/serial/8250.c by Russell King.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#include <linux/device.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/serial_8250.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include "8250.h"
struct pxa8250_data {
int line;
struct clk *clk;
};
static int __maybe_unused serial_pxa_suspend(struct device *dev)
{
struct pxa8250_data *data = dev_get_drvdata(dev);
serial8250_suspend_port(data->line);
return 0;
}
static int __maybe_unused serial_pxa_resume(struct device *dev)
{
struct pxa8250_data *data = dev_get_drvdata(dev);
serial8250_resume_port(data->line);
return 0;
}
static const struct dev_pm_ops serial_pxa_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(serial_pxa_suspend, serial_pxa_resume)
};
static const struct of_device_id serial_pxa_dt_ids[] = {
{ .compatible = "mrvl,pxa-uart", },
{ .compatible = "mrvl,mmp-uart", },
{}
};
MODULE_DEVICE_TABLE(of, serial_pxa_dt_ids);
/* Uart divisor latch write */
static void serial_pxa_dl_write(struct uart_8250_port *up, int value)
{
unsigned int dll;
serial_out(up, UART_DLL, value & 0xff);
/*
* work around Erratum #74 according to Marvel(R) PXA270M Processor
* Specification Update (April 19, 2010)
*/
dll = serial_in(up, UART_DLL);
WARN_ON(dll != (value & 0xff));
serial_out(up, UART_DLM, value >> 8 & 0xff);
}
static void serial_pxa_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
struct pxa8250_data *data = port->private_data;
if (!state)
clk_prepare_enable(data->clk);
else
clk_disable_unprepare(data->clk);
}
static int serial_pxa_probe(struct platform_device *pdev)
{
struct uart_8250_port uart = {};
struct pxa8250_data *data;
struct resource *mmres, *irqres;
int ret;
mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!mmres || !irqres)
return -ENODEV;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(data->clk))
return PTR_ERR(data->clk);
ret = clk_prepare(data->clk);
if (ret)
return ret;
uart.port.type = PORT_XSCALE;
uart.port.iotype = UPIO_MEM32;
uart.port.mapbase = mmres->start;
uart.port.regshift = 2;
uart.port.irq = irqres->start;
uart.port.fifosize = 64;
uart.port.flags = UPF_IOREMAP | UPF_SKIP_TEST;
uart.port.dev = &pdev->dev;
uart.port.uartclk = clk_get_rate(data->clk);
uart.port.pm = serial_pxa_pm;
uart.port.private_data = data;
uart.dl_write = serial_pxa_dl_write;
ret = serial8250_register_8250_port(&uart);
if (ret < 0)
goto err_clk;
data->line = ret;
platform_set_drvdata(pdev, data);
return 0;
err_clk:
clk_unprepare(data->clk);
return ret;
}
static int serial_pxa_remove(struct platform_device *pdev)
{
struct pxa8250_data *data = platform_get_drvdata(pdev);
serial8250_unregister_port(data->line);
clk_unprepare(data->clk);
return 0;
}
static struct platform_driver serial_pxa_driver = {
.probe = serial_pxa_probe,
.remove = serial_pxa_remove,
.driver = {
.name = "pxa2xx-uart",
.pm = &serial_pxa_pm_ops,
.of_match_table = serial_pxa_dt_ids,
},
};
module_platform_driver(serial_pxa_driver);
#ifdef CONFIG_SERIAL_8250_CONSOLE
static int __init early_serial_pxa_setup(struct earlycon_device *device,
const char *options)
{
struct uart_port *port = &device->port;
if (!(device->port.membase || device->port.iobase))
return -ENODEV;
port->regshift = 2;
return early_serial8250_setup(device, NULL);
}
OF_EARLYCON_DECLARE(early_pxa, "mrvl,pxa-uart", early_serial_pxa_setup);
#endif
MODULE_AUTHOR("Sergei Ianovich");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:pxa2xx-uart");

View File

@ -24,10 +24,22 @@
/* Most (but not all) of UniPhier UART devices have 64-depth FIFO. */ /* Most (but not all) of UniPhier UART devices have 64-depth FIFO. */
#define UNIPHIER_UART_DEFAULT_FIFO_SIZE 64 #define UNIPHIER_UART_DEFAULT_FIFO_SIZE 64
#define UNIPHIER_UART_CHAR_FCR 3 /* Character / FIFO Control Register */ /*
#define UNIPHIER_UART_LCR_MCR 4 /* Line/Modem Control Register */ * This hardware is similar to 8250, but its register map is a bit different:
#define UNIPHIER_UART_LCR_SHIFT 8 * - MMIO32 (regshift = 2)
#define UNIPHIER_UART_DLR 9 /* Divisor Latch Register */ * - FCR is not at 2, but 3
* - LCR and MCR are not at 3 and 4, they share 4
* - Divisor latch at 9, no divisor latch access bit
*/
#define UNIPHIER_UART_REGSHIFT 2
/* bit[15:8] = CHAR (not used), bit[7:0] = FCR */
#define UNIPHIER_UART_CHAR_FCR (3 << (UNIPHIER_UART_REGSHIFT))
/* bit[15:8] = LCR, bit[7:0] = MCR */
#define UNIPHIER_UART_LCR_MCR (4 << (UNIPHIER_UART_REGSHIFT))
/* Divisor Latch Register */
#define UNIPHIER_UART_DLR (9 << (UNIPHIER_UART_REGSHIFT))
struct uniphier8250_priv { struct uniphier8250_priv {
int line; int line;
@ -44,7 +56,7 @@ static int __init uniphier_early_console_setup(struct earlycon_device *device,
/* This hardware always expects MMIO32 register interface. */ /* This hardware always expects MMIO32 register interface. */
device->port.iotype = UPIO_MEM32; device->port.iotype = UPIO_MEM32;
device->port.regshift = 2; device->port.regshift = UNIPHIER_UART_REGSHIFT;
/* /*
* Do not touch the divisor register in early_serial8250_setup(); * Do not touch the divisor register in early_serial8250_setup();
@ -68,17 +80,16 @@ static unsigned int uniphier_serial_in(struct uart_port *p, int offset)
switch (offset) { switch (offset) {
case UART_LCR: case UART_LCR:
valshift = UNIPHIER_UART_LCR_SHIFT; valshift = 8;
/* fall through */ /* fall through */
case UART_MCR: case UART_MCR:
offset = UNIPHIER_UART_LCR_MCR; offset = UNIPHIER_UART_LCR_MCR;
break; break;
default: default:
offset <<= UNIPHIER_UART_REGSHIFT;
break; break;
} }
offset <<= p->regshift;
/* /*
* The return value must be masked with 0xff because LCR and MCR reside * The return value must be masked with 0xff because LCR and MCR reside
* in the same register that must be accessed by 32-bit write/read. * in the same register that must be accessed by 32-bit write/read.
@ -90,27 +101,26 @@ static unsigned int uniphier_serial_in(struct uart_port *p, int offset)
static void uniphier_serial_out(struct uart_port *p, int offset, int value) static void uniphier_serial_out(struct uart_port *p, int offset, int value)
{ {
unsigned int valshift = 0; unsigned int valshift = 0;
bool normal = false; bool normal = true;
switch (offset) { switch (offset) {
case UART_FCR: case UART_FCR:
offset = UNIPHIER_UART_CHAR_FCR; offset = UNIPHIER_UART_CHAR_FCR;
break; break;
case UART_LCR: case UART_LCR:
valshift = UNIPHIER_UART_LCR_SHIFT; valshift = 8;
/* Divisor latch access bit does not exist. */ /* Divisor latch access bit does not exist. */
value &= ~UART_LCR_DLAB; value &= ~UART_LCR_DLAB;
/* fall through */ /* fall through */
case UART_MCR: case UART_MCR:
offset = UNIPHIER_UART_LCR_MCR; offset = UNIPHIER_UART_LCR_MCR;
normal = false;
break; break;
default: default:
normal = true; offset <<= UNIPHIER_UART_REGSHIFT;
break; break;
} }
offset <<= p->regshift;
if (normal) { if (normal) {
writel(value, p->membase + offset); writel(value, p->membase + offset);
} else { } else {
@ -139,16 +149,12 @@ static void uniphier_serial_out(struct uart_port *p, int offset, int value)
*/ */
static int uniphier_serial_dl_read(struct uart_8250_port *up) static int uniphier_serial_dl_read(struct uart_8250_port *up)
{ {
int offset = UNIPHIER_UART_DLR << up->port.regshift; return readl(up->port.membase + UNIPHIER_UART_DLR);
return readl(up->port.membase + offset);
} }
static void uniphier_serial_dl_write(struct uart_8250_port *up, int value) static void uniphier_serial_dl_write(struct uart_8250_port *up, int value)
{ {
int offset = UNIPHIER_UART_DLR << up->port.regshift; writel(value, up->port.membase + UNIPHIER_UART_DLR);
writel(value, up->port.membase + offset);
} }
static int uniphier_of_serial_setup(struct device *dev, struct uart_port *port, static int uniphier_of_serial_setup(struct device *dev, struct uart_port *port,
@ -234,7 +240,7 @@ static int uniphier_uart_probe(struct platform_device *pdev)
up.port.type = PORT_16550A; up.port.type = PORT_16550A;
up.port.iotype = UPIO_MEM32; up.port.iotype = UPIO_MEM32;
up.port.regshift = 2; up.port.regshift = UNIPHIER_UART_REGSHIFT;
up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE; up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE;
up.capabilities = UART_CAP_FIFO; up.capabilities = UART_CAP_FIFO;

View File

@ -439,6 +439,16 @@ config SERIAL_8250_MOXA
This driver can also be built as a module. The module will be called This driver can also be built as a module. The module will be called
8250_moxa. If you want to do that, say M here. 8250_moxa. If you want to do that, say M here.
config SERIAL_8250_PXA
tristate "PXA serial port support"
depends on SERIAL_8250
depends on ARCH_PXA || ARCH_MMP
help
If you have a machine based on an Intel XScale PXA2xx CPU you can
enable its onboard serial ports by enabling this option. The option is
applicable to both devicetree and legacy boards, and early console is
part of its support.
config SERIAL_OF_PLATFORM config SERIAL_OF_PLATFORM
tristate "Devicetree based probing for 8250 ports" tristate "Devicetree based probing for 8250 ports"
depends on SERIAL_8250 && OF depends on SERIAL_8250 && OF

View File

@ -31,6 +31,7 @@ obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o
obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o
obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o
obj-$(CONFIG_SERIAL_8250_MOXA) += 8250_moxa.o obj-$(CONFIG_SERIAL_8250_MOXA) += 8250_moxa.o
obj-$(CONFIG_SERIAL_8250_PXA) += 8250_pxa.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o
CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt

View File

@ -438,17 +438,27 @@ config SERIAL_MPSC_CONSOLE
Say Y here if you want to support a serial console on a Marvell MPSC. Say Y here if you want to support a serial console on a Marvell MPSC.
config SERIAL_PXA config SERIAL_PXA
bool "PXA serial port support" bool "PXA serial port support (DEPRECATED)"
depends on ARCH_PXA || ARCH_MMP depends on ARCH_PXA || ARCH_MMP
select SERIAL_CORE select SERIAL_CORE
select SERIAL_8250_PXA if SERIAL_8250=y
select SERIAL_PXA_NON8250 if !SERIAL_8250=y
help help
If you have a machine based on an Intel XScale PXA2xx CPU you If you have a machine based on an Intel XScale PXA2xx CPU you
can enable its onboard serial ports by enabling this option. can enable its onboard serial ports by enabling this option.
Unless you have a specific need, you should use SERIAL_8250_PXA
instead of this.
config SERIAL_PXA_NON8250
bool
depends on !SERIAL_8250
config SERIAL_PXA_CONSOLE config SERIAL_PXA_CONSOLE
bool "Console on PXA serial port" bool "Console on PXA serial port (DEPRECATED)"
depends on SERIAL_PXA depends on SERIAL_PXA
select SERIAL_CORE_CONSOLE select SERIAL_CORE_CONSOLE
select SERIAL_8250_CONSOLE if SERIAL_8250=y
help help
If you have enabled the serial port on the Intel XScale PXA If you have enabled the serial port on the Intel XScale PXA
CPU you can make it the console by answering Y to this option. CPU you can make it the console by answering Y to this option.
@ -460,6 +470,9 @@ config SERIAL_PXA_CONSOLE
your boot loader (lilo or loadlin) about how to pass options to the your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.) kernel at boot time.)
Unless you have a specific need, you should use SERIAL_8250_PXA
and SERIAL_8250_CONSOLE instead of this.
config SERIAL_SA1100 config SERIAL_SA1100
bool "SA1100 serial port support" bool "SA1100 serial port support"
depends on ARCH_SA1100 depends on ARCH_SA1100
@ -1626,7 +1639,7 @@ config SERIAL_STM32
tristate "STMicroelectronics STM32 serial port support" tristate "STMicroelectronics STM32 serial port support"
select SERIAL_CORE select SERIAL_CORE
depends on HAS_DMA depends on HAS_DMA
depends on ARM || COMPILE_TEST depends on ARCH_STM32 || COMPILE_TEST
help help
This driver is for the on-chip Serial Controller on This driver is for the on-chip Serial Controller on
STMicroelectronics STM32 MCUs. STMicroelectronics STM32 MCUs.

View File

@ -23,7 +23,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250/
obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
obj-$(CONFIG_SERIAL_PXA) += pxa.o obj-$(CONFIG_SERIAL_PXA_NON8250) += pxa.o
obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
obj-$(CONFIG_SERIAL_SA1100) += sa1100.o obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o
@ -62,13 +62,11 @@ obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
obj-$(CONFIG_SERIAL_MSM) += msm_serial.o obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
obj-$(CONFIG_SERIAL_KGDB_NMI) += kgdb_nmi.o
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
obj-$(CONFIG_SERIAL_ST_ASC) += st-asc.o obj-$(CONFIG_SERIAL_ST_ASC) += st-asc.o
obj-$(CONFIG_SERIAL_TILEGX) += tilegx.o obj-$(CONFIG_SERIAL_TILEGX) += tilegx.o
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
@ -96,3 +94,6 @@ obj-$(CONFIG_SERIAL_MPS2_UART) += mps2-uart.o
# GPIOLIB helpers for modem control lines # GPIOLIB helpers for modem control lines
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
obj-$(CONFIG_SERIAL_KGDB_NMI) += kgdb_nmi.o
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o

View File

@ -2315,12 +2315,67 @@ static int __init pl011_console_setup(struct console *co, char *options)
return uart_set_options(&uap->port, co, baud, parity, bits, flow); return uart_set_options(&uap->port, co, baud, parity, bits, flow);
} }
/**
* pl011_console_match - non-standard console matching
* @co: registering console
* @name: name from console command line
* @idx: index from console command line
* @options: ptr to option string from console command line
*
* Only attempts to match console command lines of the form:
* console=pl011,mmio|mmio32,<addr>[,<options>]
* console=pl011,0x<addr>[,<options>]
* This form is used to register an initial earlycon boot console and
* replace it with the amba_console at pl011 driver init.
*
* Performs console setup for a match (as required by interface)
* If no <options> are specified, then assume the h/w is already setup.
*
* Returns 0 if console matches; otherwise non-zero to use default matching
*/
static int __init pl011_console_match(struct console *co, char *name, int idx,
char *options)
{
unsigned char iotype;
resource_size_t addr;
int i;
if (strcmp(name, "pl011") != 0)
return -ENODEV;
if (uart_parse_earlycon(options, &iotype, &addr, &options))
return -ENODEV;
if (iotype != UPIO_MEM && iotype != UPIO_MEM32)
return -ENODEV;
/* try to match the port specified on the command line */
for (i = 0; i < ARRAY_SIZE(amba_ports); i++) {
struct uart_port *port;
if (!amba_ports[i])
continue;
port = &amba_ports[i]->port;
if (port->mapbase != addr)
continue;
co->index = i;
port->cons = co;
return pl011_console_setup(co, options);
}
return -ENODEV;
}
static struct uart_driver amba_reg; static struct uart_driver amba_reg;
static struct console amba_console = { static struct console amba_console = {
.name = "ttyAMA", .name = "ttyAMA",
.write = pl011_console_write, .write = pl011_console_write,
.device = uart_console_device, .device = uart_console_device,
.setup = pl011_console_setup, .setup = pl011_console_setup,
.match = pl011_console_match,
.flags = CON_PRINTBUFFER, .flags = CON_PRINTBUFFER,
.index = -1, .index = -1,
.data = &amba_reg, .data = &amba_reg,
@ -2357,6 +2412,7 @@ static int __init pl011_early_console_setup(struct earlycon_device *device,
return 0; return 0;
} }
OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup); OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup);
OF_EARLYCON_DECLARE(pl011, "arm,sbsa-uart", pl011_early_console_setup);
#else #else
#define AMBA_CONSOLE NULL #define AMBA_CONSOLE NULL

View File

@ -3213,8 +3213,6 @@ get_serial_info(struct e100_serial * info,
* should set them to something else than 0. * should set them to something else than 0.
*/ */
if (!retinfo)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp)); memset(&tmp, 0, sizeof(tmp));
tmp.type = info->type; tmp.type = info->type;
tmp.line = info->line; tmp.line = info->line;

View File

@ -430,6 +430,65 @@ static void lpuart_flush_buffer(struct uart_port *port)
} }
} }
#if defined(CONFIG_CONSOLE_POLL)
static int lpuart_poll_init(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
unsigned long flags;
unsigned char temp;
sport->port.fifosize = 0;
spin_lock_irqsave(&sport->port.lock, flags);
/* Disable Rx & Tx */
writeb(0, sport->port.membase + UARTCR2);
temp = readb(sport->port.membase + UARTPFIFO);
/* Enable Rx and Tx FIFO */
writeb(temp | UARTPFIFO_RXFE | UARTPFIFO_TXFE,
sport->port.membase + UARTPFIFO);
/* flush Tx and Rx FIFO */
writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH,
sport->port.membase + UARTCFIFO);
/* explicitly clear RDRF */
if (readb(sport->port.membase + UARTSR1) & UARTSR1_RDRF) {
readb(sport->port.membase + UARTDR);
writeb(UARTSFIFO_RXUF, sport->port.membase + UARTSFIFO);
}
writeb(0, sport->port.membase + UARTTWFIFO);
writeb(1, sport->port.membase + UARTRWFIFO);
/* Enable Rx and Tx */
writeb(UARTCR2_RE | UARTCR2_TE, sport->port.membase + UARTCR2);
spin_unlock_irqrestore(&sport->port.lock, flags);
return 0;
}
static void lpuart_poll_put_char(struct uart_port *port, unsigned char c)
{
/* drain */
while (!(readb(port->membase + UARTSR1) & UARTSR1_TDRE))
barrier();
writeb(c, port->membase + UARTDR);
}
static int lpuart_poll_get_char(struct uart_port *port)
{
if (!(readb(port->membase + UARTSR1) & UARTSR1_RDRF))
return NO_POLL_CHAR;
return readb(port->membase + UARTDR);
}
#endif
static inline void lpuart_transmit_buffer(struct lpuart_port *sport) static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
{ {
struct circ_buf *xmit = &sport->port.state->xmit; struct circ_buf *xmit = &sport->port.state->xmit;
@ -1595,6 +1654,11 @@ static const struct uart_ops lpuart_pops = {
.config_port = lpuart_config_port, .config_port = lpuart_config_port,
.verify_port = lpuart_verify_port, .verify_port = lpuart_verify_port,
.flush_buffer = lpuart_flush_buffer, .flush_buffer = lpuart_flush_buffer,
#if defined(CONFIG_CONSOLE_POLL)
.poll_init = lpuart_poll_init,
.poll_get_char = lpuart_poll_get_char,
.poll_put_char = lpuart_poll_put_char,
#endif
}; };
static const struct uart_ops lpuart32_pops = { static const struct uart_ops lpuart32_pops = {

View File

@ -1042,6 +1042,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
ret = spi_setup(spi); ret = spi_setup(spi);
if (ret) { if (ret) {
dev_err(&spi->dev, "SPI setup wasn't successful %d", ret); dev_err(&spi->dev, "SPI setup wasn't successful %d", ret);
kfree(ifx_dev);
return -ENODEV; return -ENODEV;
} }

View File

@ -1082,7 +1082,7 @@ static int inline ioc4_attach_local(struct ioc4_driver_data *idd)
if (!port) { if (!port) {
printk(KERN_WARNING printk(KERN_WARNING
"IOC4 serial memory not available for port\n"); "IOC4 serial memory not available for port\n");
return -ENOMEM; goto free;
} }
spin_lock_init(&port->ip_lock); spin_lock_init(&port->ip_lock);
@ -1190,6 +1190,11 @@ static int inline ioc4_attach_local(struct ioc4_driver_data *idd)
handle_dma_error_intr, port); handle_dma_error_intr, port);
} }
return 0; return 0;
free:
while (port_number)
kfree(ports[--port_number]);
return -ENOMEM;
} }
/** /**

View File

@ -1016,7 +1016,7 @@ static void mxs_auart_settermios(struct uart_port *u,
ctrl |= AUART_LINECTRL_EPS; ctrl |= AUART_LINECTRL_EPS;
} }
u->read_status_mask = 0; u->read_status_mask = AUART_STAT_OERR;
if (termios->c_iflag & INPCK) if (termios->c_iflag & INPCK)
u->read_status_mask |= AUART_STAT_PERR; u->read_status_mask |= AUART_STAT_PERR;

View File

@ -925,6 +925,8 @@ static struct platform_driver serial_pxa_driver = {
}, },
}; };
/* 8250 driver for PXA serial ports should be used */
static int __init serial_pxa_init(void) static int __init serial_pxa_init(void)
{ {
int ret; int ret;

View File

@ -1264,7 +1264,7 @@ static int sc16is7xx_probe(struct device *dev,
/* Setup interrupt */ /* Setup interrupt */
ret = devm_request_irq(dev, irq, sc16is7xx_irq, ret = devm_request_irq(dev, irq, sc16is7xx_irq,
IRQF_ONESHOT | flags, dev_name(dev), s); flags, dev_name(dev), s);
if (!ret) if (!ret)
return 0; return 0;

View File

@ -73,7 +73,7 @@ static inline struct uart_port *uart_port_ref(struct uart_state *state)
static inline void uart_port_deref(struct uart_port *uport) static inline void uart_port_deref(struct uart_port *uport)
{ {
if (uport && atomic_dec_and_test(&uport->state->refcount)) if (atomic_dec_and_test(&uport->state->refcount))
wake_up(&uport->state->remove_wait); wake_up(&uport->state->remove_wait);
} }
@ -88,9 +88,10 @@ static inline void uart_port_deref(struct uart_port *uport)
#define uart_port_unlock(uport, flags) \ #define uart_port_unlock(uport, flags) \
({ \ ({ \
struct uart_port *__uport = uport; \ struct uart_port *__uport = uport; \
if (__uport) \ if (__uport) { \
spin_unlock_irqrestore(&__uport->lock, flags); \ spin_unlock_irqrestore(&__uport->lock, flags); \
uart_port_deref(__uport); \ uart_port_deref(__uport); \
} \
}) })
static inline struct uart_port *uart_port_check(struct uart_state *state) static inline struct uart_port *uart_port_check(struct uart_state *state)
@ -1515,7 +1516,10 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
unsigned long char_time, expire; unsigned long char_time, expire;
port = uart_port_ref(state); port = uart_port_ref(state);
if (!port || port->type == PORT_UNKNOWN || port->fifosize == 0) { if (!port)
return;
if (port->type == PORT_UNKNOWN || port->fifosize == 0) {
uart_port_deref(port); uart_port_deref(port);
return; return;
} }
@ -2365,9 +2369,10 @@ static int uart_poll_get_char(struct tty_driver *driver, int line)
if (state) { if (state) {
port = uart_port_ref(state); port = uart_port_ref(state);
if (port) if (port) {
ret = port->ops->poll_get_char(port); ret = port->ops->poll_get_char(port);
uart_port_deref(port); uart_port_deref(port);
}
} }
return ret; return ret;
} }

View File

@ -1142,11 +1142,8 @@ static int sci_dma_rx_push(struct sci_port *s, void *buf, size_t count)
int copied; int copied;
copied = tty_insert_flip_string(tport, buf, count); copied = tty_insert_flip_string(tport, buf, count);
if (copied < count) { if (copied < count)
dev_warn(port->dev, "Rx overrun: dropping %zu bytes\n",
count - copied);
port->icount.buf_overrun++; port->icount.buf_overrun++;
}
port->icount.rx += copied; port->icount.rx += copied;
@ -1161,8 +1158,6 @@ static int sci_dma_rx_find_active(struct sci_port *s)
if (s->active_rx == s->cookie_rx[i]) if (s->active_rx == s->cookie_rx[i])
return i; return i;
dev_err(s->port.dev, "%s: Rx cookie %d not found!\n", __func__,
s->active_rx);
return -1; return -1;
} }
@ -1223,9 +1218,9 @@ static void sci_dma_rx_complete(void *arg)
dma_async_issue_pending(chan); dma_async_issue_pending(chan);
spin_unlock_irqrestore(&port->lock, flags);
dev_dbg(port->dev, "%s: cookie %d #%d, new active cookie %d\n", dev_dbg(port->dev, "%s: cookie %d #%d, new active cookie %d\n",
__func__, s->cookie_rx[active], active, s->active_rx); __func__, s->cookie_rx[active], active, s->active_rx);
spin_unlock_irqrestore(&port->lock, flags);
return; return;
fail: fail:
@ -1273,8 +1268,6 @@ static void sci_submit_rx(struct sci_port *s)
if (dma_submit_error(s->cookie_rx[i])) if (dma_submit_error(s->cookie_rx[i]))
goto fail; goto fail;
dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__,
s->cookie_rx[i], i);
} }
s->active_rx = s->cookie_rx[0]; s->active_rx = s->cookie_rx[0];
@ -1288,7 +1281,6 @@ fail:
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
s->cookie_rx[i] = -EINVAL; s->cookie_rx[i] = -EINVAL;
s->active_rx = -EINVAL; s->active_rx = -EINVAL;
dev_warn(s->port.dev, "Failed to re-start Rx DMA, using PIO\n");
sci_rx_dma_release(s, true); sci_rx_dma_release(s, true);
} }
@ -1358,10 +1350,10 @@ static void rx_timer_fn(unsigned long arg)
int active, count; int active, count;
u16 scr; u16 scr;
spin_lock_irqsave(&port->lock, flags);
dev_dbg(port->dev, "DMA Rx timed out\n"); dev_dbg(port->dev, "DMA Rx timed out\n");
spin_lock_irqsave(&port->lock, flags);
active = sci_dma_rx_find_active(s); active = sci_dma_rx_find_active(s);
if (active < 0) { if (active < 0) {
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
@ -1370,9 +1362,9 @@ static void rx_timer_fn(unsigned long arg)
status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state); status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state);
if (status == DMA_COMPLETE) { if (status == DMA_COMPLETE) {
spin_unlock_irqrestore(&port->lock, flags);
dev_dbg(port->dev, "Cookie %d #%d has already completed\n", dev_dbg(port->dev, "Cookie %d #%d has already completed\n",
s->active_rx, active); s->active_rx, active);
spin_unlock_irqrestore(&port->lock, flags);
/* Let packet complete handler take care of the packet */ /* Let packet complete handler take care of the packet */
return; return;
@ -1396,8 +1388,6 @@ static void rx_timer_fn(unsigned long arg)
/* Handle incomplete DMA receive */ /* Handle incomplete DMA receive */
dmaengine_terminate_all(s->chan_rx); dmaengine_terminate_all(s->chan_rx);
read = sg_dma_len(&s->sg_rx[active]) - state.residue; read = sg_dma_len(&s->sg_rx[active]) - state.residue;
dev_dbg(port->dev, "Read %u bytes with cookie %d\n", read,
s->active_rx);
if (read) { if (read) {
count = sci_dma_rx_push(s, s->rx_buf[active], read); count = sci_dma_rx_push(s, s->rx_buf[active], read);

View File

@ -598,7 +598,8 @@ static int hv_remove(struct platform_device *dev)
uart_remove_one_port(&sunhv_reg, port); uart_remove_one_port(&sunhv_reg, port);
sunserial_unregister_minors(&sunhv_reg, 1); sunserial_unregister_minors(&sunhv_reg, 1);
kfree(con_read_page);
kfree(con_write_page);
kfree(port); kfree(port);
sunhv_port = NULL; sunhv_port = NULL;

View File

@ -1500,6 +1500,7 @@ static int su_probe(struct platform_device *op)
out_unmap: out_unmap:
of_iounmap(&op->resource[0], up->port.membase, up->reg_size); of_iounmap(&op->resource[0], up->port.membase, up->reg_size);
kfree(up);
return err; return err;
} }

View File

@ -9,6 +9,17 @@
* Support for multiple unimaps by Jakub Jelinek <jj@ultra.linux.cz>, July 1998 * Support for multiple unimaps by Jakub Jelinek <jj@ultra.linux.cz>, July 1998
* *
* Fix bug in inverse translation. Stanislav Voronyi <stas@cnti.uanet.kharkov.ua>, Dec 1998 * Fix bug in inverse translation. Stanislav Voronyi <stas@cnti.uanet.kharkov.ua>, Dec 1998
*
* In order to prevent the following circular lock dependency:
* &mm->mmap_sem --> cpu_hotplug.lock --> console_lock --> &mm->mmap_sem
*
* We cannot allow page fault to happen while holding the console_lock.
* Therefore, all the userspace copy operations have to be done outside
* the console_lock critical sections.
*
* As all the affected functions are all called directly from vt_ioctl(), we
* can allocate some small buffers directly on stack without worrying about
* stack overflow.
*/ */
#include <linux/module.h> #include <linux/module.h>
@ -22,6 +33,7 @@
#include <linux/console.h> #include <linux/console.h>
#include <linux/consolemap.h> #include <linux/consolemap.h>
#include <linux/vt_kern.h> #include <linux/vt_kern.h>
#include <linux/string.h>
static unsigned short translations[][256] = { static unsigned short translations[][256] = {
/* 8-bit Latin-1 mapped to Unicode -- trivial mapping */ /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
@ -309,18 +321,19 @@ static void update_user_maps(void)
int con_set_trans_old(unsigned char __user * arg) int con_set_trans_old(unsigned char __user * arg)
{ {
int i; int i;
unsigned short *p = translations[USER_MAP]; unsigned short inbuf[E_TABSZ];
if (!access_ok(VERIFY_READ, arg, E_TABSZ)) if (!access_ok(VERIFY_READ, arg, E_TABSZ))
return -EFAULT; return -EFAULT;
console_lock(); for (i = 0; i < E_TABSZ ; i++) {
for (i=0; i<E_TABSZ ; i++) {
unsigned char uc; unsigned char uc;
__get_user(uc, arg+i); __get_user(uc, arg+i);
p[i] = UNI_DIRECT_BASE | uc; inbuf[i] = UNI_DIRECT_BASE | uc;
} }
console_lock();
memcpy(translations[USER_MAP], inbuf, sizeof(inbuf));
update_user_maps(); update_user_maps();
console_unlock(); console_unlock();
return 0; return 0;
@ -330,35 +343,37 @@ int con_get_trans_old(unsigned char __user * arg)
{ {
int i, ch; int i, ch;
unsigned short *p = translations[USER_MAP]; unsigned short *p = translations[USER_MAP];
unsigned char outbuf[E_TABSZ];
if (!access_ok(VERIFY_WRITE, arg, E_TABSZ)) if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
return -EFAULT; return -EFAULT;
console_lock(); console_lock();
for (i=0; i<E_TABSZ ; i++) for (i = 0; i < E_TABSZ ; i++)
{ {
ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]); ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
__put_user((ch & ~0xff) ? 0 : ch, arg+i); outbuf[i] = (ch & ~0xff) ? 0 : ch;
} }
console_unlock(); console_unlock();
for (i = 0; i < E_TABSZ ; i++)
__put_user(outbuf[i], arg+i);
return 0; return 0;
} }
int con_set_trans_new(ushort __user * arg) int con_set_trans_new(ushort __user * arg)
{ {
int i; int i;
unsigned short *p = translations[USER_MAP]; unsigned short inbuf[E_TABSZ];
if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short))) if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
return -EFAULT; return -EFAULT;
console_lock(); for (i = 0; i < E_TABSZ ; i++)
for (i=0; i<E_TABSZ ; i++) { __get_user(inbuf[i], arg+i);
unsigned short us;
__get_user(us, arg+i);
p[i] = us;
}
console_lock();
memcpy(translations[USER_MAP], inbuf, sizeof(inbuf));
update_user_maps(); update_user_maps();
console_unlock(); console_unlock();
return 0; return 0;
@ -367,16 +382,17 @@ int con_set_trans_new(ushort __user * arg)
int con_get_trans_new(ushort __user * arg) int con_get_trans_new(ushort __user * arg)
{ {
int i; int i;
unsigned short *p = translations[USER_MAP]; unsigned short outbuf[E_TABSZ];
if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short))) if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
return -EFAULT; return -EFAULT;
console_lock(); console_lock();
for (i=0; i<E_TABSZ ; i++) memcpy(outbuf, translations[USER_MAP], sizeof(outbuf));
__put_user(p[i], arg+i);
console_unlock(); console_unlock();
for (i = 0; i < E_TABSZ ; i++)
__put_user(outbuf[i], arg+i);
return 0; return 0;
} }
@ -536,10 +552,20 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
{ {
int err = 0, err1, i; int err = 0, err1, i;
struct uni_pagedir *p, *q; struct uni_pagedir *p, *q;
struct unipair *unilist, *plist;
if (!ct) if (!ct)
return 0; return 0;
unilist = kmalloc_array(ct, sizeof(struct unipair), GFP_KERNEL);
if (!unilist)
return -ENOMEM;
for (i = ct, plist = unilist; i; i--, plist++, list++) {
__get_user(plist->unicode, &list->unicode);
__get_user(plist->fontpos, &list->fontpos);
}
console_lock(); console_lock();
/* Save original vc_unipagdir_loc in case we allocate a new one */ /* Save original vc_unipagdir_loc in case we allocate a new one */
@ -557,8 +583,8 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
err1 = con_do_clear_unimap(vc); err1 = con_do_clear_unimap(vc);
if (err1) { if (err1) {
console_unlock(); err = err1;
return err1; goto out_unlock;
} }
/* /*
@ -592,8 +618,8 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
*vc->vc_uni_pagedir_loc = p; *vc->vc_uni_pagedir_loc = p;
con_release_unimap(q); con_release_unimap(q);
kfree(q); kfree(q);
console_unlock(); err = err1;
return err1; goto out_unlock;
} }
} }
} else { } else {
@ -617,22 +643,17 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
/* /*
* Insert user specified unicode pairs into new table. * Insert user specified unicode pairs into new table.
*/ */
while (ct--) { for (plist = unilist; ct; ct--, plist++) {
unsigned short unicode, fontpos; err1 = con_insert_unipair(p, plist->unicode, plist->fontpos);
__get_user(unicode, &list->unicode); if (err1)
__get_user(fontpos, &list->fontpos);
if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0)
err = err1; err = err1;
list++;
} }
/* /*
* Merge with fontmaps of any other virtual consoles. * Merge with fontmaps of any other virtual consoles.
*/ */
if (con_unify_unimap(vc, p)) { if (con_unify_unimap(vc, p))
console_unlock(); goto out_unlock;
return err;
}
for (i = 0; i <= 3; i++) for (i = 0; i <= 3; i++)
set_inverse_transl(vc, p, i); /* Update inverse translations */ set_inverse_transl(vc, p, i); /* Update inverse translations */
@ -640,6 +661,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
out_unlock: out_unlock:
console_unlock(); console_unlock();
kfree(unilist);
return err; return err;
} }
@ -735,9 +757,15 @@ EXPORT_SYMBOL(con_copy_unimap);
*/ */
int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list) int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
{ {
int i, j, k, ect; int i, j, k;
ushort ect;
u16 **p1, *p2; u16 **p1, *p2;
struct uni_pagedir *p; struct uni_pagedir *p;
struct unipair *unilist, *plist;
unilist = kmalloc_array(ct, sizeof(struct unipair), GFP_KERNEL);
if (!unilist)
return -ENOMEM;
console_lock(); console_lock();
@ -750,21 +778,26 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
for (j = 0; j < 32; j++) { for (j = 0; j < 32; j++) {
p2 = *(p1++); p2 = *(p1++);
if (p2) if (p2)
for (k = 0; k < 64; k++) { for (k = 0; k < 64; k++, p2++) {
if (*p2 < MAX_GLYPH && ect++ < ct) { if (*p2 >= MAX_GLYPH)
__put_user((u_short)((i<<11)+(j<<6)+k), continue;
&list->unicode); if (ect < ct) {
__put_user((u_short) *p2, unilist[ect].unicode =
&list->fontpos); (i<<11)+(j<<6)+k;
list++; unilist[ect].fontpos = *p2;
} }
p2++; ect++;
} }
} }
} }
} }
__put_user(ect, uct);
console_unlock(); console_unlock();
for (i = min(ect, ct), plist = unilist; i; i--, list++, plist++) {
__put_user(plist->unicode, &list->unicode);
__put_user(plist->fontpos, &list->fontpos);
}
__put_user(ect, uct);
kfree(unilist);
return ((ect <= ct) ? 0 : -ENOMEM); return ((ect <= ct) ? 0 : -ENOMEM);
} }

View File

@ -982,7 +982,7 @@ static void kbd_led_trigger_activate(struct led_classdev *cdev)
KBD_LED_TRIGGER((_led_bit) + 8, _name) KBD_LED_TRIGGER((_led_bit) + 8, _name)
static struct kbd_led_trigger kbd_led_triggers[] = { static struct kbd_led_trigger kbd_led_triggers[] = {
KBD_LED_TRIGGER(VC_SCROLLOCK, "kbd-scrollock"), KBD_LED_TRIGGER(VC_SCROLLOCK, "kbd-scrolllock"),
KBD_LED_TRIGGER(VC_NUMLOCK, "kbd-numlock"), KBD_LED_TRIGGER(VC_NUMLOCK, "kbd-numlock"),
KBD_LED_TRIGGER(VC_CAPSLOCK, "kbd-capslock"), KBD_LED_TRIGGER(VC_CAPSLOCK, "kbd-capslock"),
KBD_LED_TRIGGER(VC_KANALOCK, "kbd-kanalock"), KBD_LED_TRIGGER(VC_KANALOCK, "kbd-kanalock"),
@ -1256,7 +1256,7 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode,
case KEY_SYSRQ: case KEY_SYSRQ:
/* /*
* Real AT keyboards (that's what we're trying * Real AT keyboards (that's what we're trying
* to emulate here emit 0xe0 0x2a 0xe0 0x37 when * to emulate here) emit 0xe0 0x2a 0xe0 0x37 when
* pressing PrtSc/SysRq alone, but simply 0x54 * pressing PrtSc/SysRq alone, but simply 0x54
* when pressing Alt+PrtSc/SysRq. * when pressing Alt+PrtSc/SysRq.
*/ */

View File

@ -315,38 +315,27 @@ void schedule_console_callback(void)
schedule_work(&console_work); schedule_work(&console_work);
} }
static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr) static void con_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
enum con_scroll dir, unsigned int nr)
{ {
unsigned short *d, *s; u16 *clear, *d, *s;
if (t+nr >= b) if (t + nr >= b)
nr = b - t - 1; nr = b - t - 1;
if (b > vc->vc_rows || t >= b || nr < 1) if (b > vc->vc_rows || t >= b || nr < 1)
return; return;
if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr)) if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, dir, nr))
return; return;
d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr)); s = clear = (u16 *)(vc->vc_origin + vc->vc_size_row * t);
d = (u16 *)(vc->vc_origin + vc->vc_size_row * (t + nr));
if (dir == SM_UP) {
clear = s + (b - t - nr) * vc->vc_cols;
swap(s, d);
}
scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row); scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char, scr_memsetw(clear, vc->vc_video_erase_char, vc->vc_size_row * nr);
vc->vc_size_row * nr);
}
static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
{
unsigned short *s;
unsigned int step;
if (t+nr >= b)
nr = b - t - 1;
if (b > vc->vc_rows || t >= b || nr < 1)
return;
if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr))
return;
s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
step = vc->vc_cols * nr;
scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row);
scr_memsetw(s, vc->vc_video_erase_char, 2 * step);
} }
static void do_update_region(struct vc_data *vc, unsigned long start, int count) static void do_update_region(struct vc_data *vc, unsigned long start, int count)
@ -1120,7 +1109,7 @@ static void lf(struct vc_data *vc)
* if below scrolling region * if below scrolling region
*/ */
if (vc->vc_y + 1 == vc->vc_bottom) if (vc->vc_y + 1 == vc->vc_bottom)
scrup(vc, vc->vc_top, vc->vc_bottom, 1); con_scroll(vc, vc->vc_top, vc->vc_bottom, SM_UP, 1);
else if (vc->vc_y < vc->vc_rows - 1) { else if (vc->vc_y < vc->vc_rows - 1) {
vc->vc_y++; vc->vc_y++;
vc->vc_pos += vc->vc_size_row; vc->vc_pos += vc->vc_size_row;
@ -1135,7 +1124,7 @@ static void ri(struct vc_data *vc)
* if above scrolling region * if above scrolling region
*/ */
if (vc->vc_y == vc->vc_top) if (vc->vc_y == vc->vc_top)
scrdown(vc, vc->vc_top, vc->vc_bottom, 1); con_scroll(vc, vc->vc_top, vc->vc_bottom, SM_DOWN, 1);
else if (vc->vc_y > 0) { else if (vc->vc_y > 0) {
vc->vc_y--; vc->vc_y--;
vc->vc_pos -= vc->vc_size_row; vc->vc_pos -= vc->vc_size_row;
@ -1631,7 +1620,7 @@ static void csi_L(struct vc_data *vc, unsigned int nr)
nr = vc->vc_rows - vc->vc_y; nr = vc->vc_rows - vc->vc_y;
else if (!nr) else if (!nr)
nr = 1; nr = 1;
scrdown(vc, vc->vc_y, vc->vc_bottom, nr); con_scroll(vc, vc->vc_y, vc->vc_bottom, SM_DOWN, nr);
vc->vc_need_wrap = 0; vc->vc_need_wrap = 0;
} }
@ -1652,7 +1641,7 @@ static void csi_M(struct vc_data *vc, unsigned int nr)
nr = vc->vc_rows - vc->vc_y; nr = vc->vc_rows - vc->vc_y;
else if (!nr) else if (!nr)
nr=1; nr=1;
scrup(vc, vc->vc_y, vc->vc_bottom, nr); con_scroll(vc, vc->vc_y, vc->vc_bottom, SM_UP, nr);
vc->vc_need_wrap = 0; vc->vc_need_wrap = 0;
} }
@ -4295,6 +4284,46 @@ void vcs_scr_updated(struct vc_data *vc)
notify_update(vc); notify_update(vc);
} }
void vc_scrolldelta_helper(struct vc_data *c, int lines,
unsigned int rolled_over, void *base, unsigned int size)
{
unsigned long ubase = (unsigned long)base;
ptrdiff_t scr_end = (void *)c->vc_scr_end - base;
ptrdiff_t vorigin = (void *)c->vc_visible_origin - base;
ptrdiff_t origin = (void *)c->vc_origin - base;
int margin = c->vc_size_row * 4;
int from, wrap, from_off, avail;
/* Turn scrollback off */
if (!lines) {
c->vc_visible_origin = c->vc_origin;
return;
}
/* Do we have already enough to allow jumping from 0 to the end? */
if (rolled_over > scr_end + margin) {
from = scr_end;
wrap = rolled_over + c->vc_size_row;
} else {
from = 0;
wrap = size;
}
from_off = (vorigin - from + wrap) % wrap + lines * c->vc_size_row;
avail = (origin - from + wrap) % wrap;
/* Only a little piece would be left? Show all incl. the piece! */
if (avail < 2 * margin)
margin = 0;
if (from_off < margin)
from_off = 0;
if (from_off > avail - margin)
from_off = avail;
c->vc_visible_origin = ubase + (from + from_off) % wrap;
}
EXPORT_SYMBOL_GPL(vc_scrolldelta_helper);
/* /*
* Visible symbols for modules * Visible symbols for modules
*/ */

View File

@ -686,8 +686,6 @@ static void
sisusbcon_scrolldelta(struct vc_data *c, int lines) sisusbcon_scrolldelta(struct vc_data *c, int lines)
{ {
struct sisusb_usb_data *sisusb; struct sisusb_usb_data *sisusb;
int margin = c->vc_size_row * 4;
int ul, we, p, st;
sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
if (!sisusb) if (!sisusb)
@ -700,39 +698,8 @@ sisusbcon_scrolldelta(struct vc_data *c, int lines)
return; return;
} }
if (!lines) /* Turn scrollback off */ vc_scrolldelta_helper(c, lines, sisusb->con_rolled_over,
c->vc_visible_origin = c->vc_origin; (void *)sisusb->scrbuf, sisusb->scrbuf_size);
else {
if (sisusb->con_rolled_over >
(c->vc_scr_end - sisusb->scrbuf) + margin) {
ul = c->vc_scr_end - sisusb->scrbuf;
we = sisusb->con_rolled_over + c->vc_size_row;
} else {
ul = 0;
we = sisusb->scrbuf_size;
}
p = (c->vc_visible_origin - sisusb->scrbuf - ul + we) % we +
lines * c->vc_size_row;
st = (c->vc_origin - sisusb->scrbuf - ul + we) % we;
if (st < 2 * margin)
margin = 0;
if (p < margin)
p = 0;
if (p > st - margin)
p = st;
c->vc_visible_origin = sisusb->scrbuf + (p + ul) % we;
}
sisusbcon_set_start_address(sisusb, c); sisusbcon_set_start_address(sisusb, c);
@ -808,9 +775,10 @@ sisusbcon_cursor(struct vc_data *c, int mode)
mutex_unlock(&sisusb->lock); mutex_unlock(&sisusb->lock);
} }
static int static bool
sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb, sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb,
int t, int b, int dir, int lines) unsigned int t, unsigned int b, enum con_scroll dir,
unsigned int lines)
{ {
int cols = sisusb->sisusb_num_columns; int cols = sisusb->sisusb_num_columns;
int length = ((b - t) * cols) * 2; int length = ((b - t) * cols) * 2;
@ -852,8 +820,9 @@ sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb,
} }
/* Interface routine */ /* Interface routine */
static int static bool
sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, int lines) sisusbcon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
enum con_scroll dir, unsigned int lines)
{ {
struct sisusb_usb_data *sisusb; struct sisusb_usb_data *sisusb;
u16 eattr = c->vc_video_erase_char; u16 eattr = c->vc_video_erase_char;
@ -870,17 +839,17 @@ sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
*/ */
if (!lines) if (!lines)
return 1; return true;
sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
if (!sisusb) if (!sisusb)
return 0; return false;
/* sisusb->lock is down */ /* sisusb->lock is down */
if (sisusb_is_inactive(c, sisusb)) { if (sisusb_is_inactive(c, sisusb)) {
mutex_unlock(&sisusb->lock); mutex_unlock(&sisusb->lock);
return 0; return false;
} }
/* Special case */ /* Special case */
@ -971,7 +940,7 @@ sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
mutex_unlock(&sisusb->lock); mutex_unlock(&sisusb->lock);
return 1; return true;
} }
/* Interface routine */ /* Interface routine */

View File

@ -164,8 +164,6 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
int count, int ypos, int xpos); int count, int ypos, int xpos);
static void fbcon_clear_margins(struct vc_data *vc, int bottom_only); static void fbcon_clear_margins(struct vc_data *vc, int bottom_only);
static void fbcon_cursor(struct vc_data *vc, int mode); static void fbcon_cursor(struct vc_data *vc, int mode);
static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
int count);
static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
int height, int width); int height, int width);
static int fbcon_switch(struct vc_data *vc); static int fbcon_switch(struct vc_data *vc);
@ -1795,15 +1793,15 @@ static inline void fbcon_softback_note(struct vc_data *vc, int t,
softback_curr = softback_in; softback_curr = softback_in;
} }
static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
int count) enum con_scroll dir, unsigned int count)
{ {
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct display *p = &fb_display[vc->vc_num]; struct display *p = &fb_display[vc->vc_num];
int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK; int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
if (fbcon_is_inactive(vc, info)) if (fbcon_is_inactive(vc, info))
return -EINVAL; return true;
fbcon_cursor(vc, CM_ERASE); fbcon_cursor(vc, CM_ERASE);
@ -1831,7 +1829,7 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
(b - count)), (b - count)),
vc->vc_video_erase_char, vc->vc_video_erase_char,
vc->vc_size_row * count); vc->vc_size_row * count);
return 1; return true;
break; break;
case SCROLL_WRAP_MOVE: case SCROLL_WRAP_MOVE:
@ -1903,7 +1901,7 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
(b - count)), (b - count)),
vc->vc_video_erase_char, vc->vc_video_erase_char,
vc->vc_size_row * count); vc->vc_size_row * count);
return 1; return true;
} }
break; break;
@ -1922,7 +1920,7 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
t), t),
vc->vc_video_erase_char, vc->vc_video_erase_char,
vc->vc_size_row * count); vc->vc_size_row * count);
return 1; return true;
break; break;
case SCROLL_WRAP_MOVE: case SCROLL_WRAP_MOVE:
@ -1992,10 +1990,10 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
t), t),
vc->vc_video_erase_char, vc->vc_video_erase_char,
vc->vc_size_row * count); vc->vc_size_row * count);
return 1; return true;
} }
} }
return 0; return false;
} }

View File

@ -488,12 +488,13 @@ static void mdacon_cursor(struct vc_data *c, int mode)
} }
} }
static int mdacon_scroll(struct vc_data *c, int t, int b, int dir, int lines) static bool mdacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
enum con_scroll dir, unsigned int lines)
{ {
u16 eattr = mda_convert_attr(c->vc_video_erase_char); u16 eattr = mda_convert_attr(c->vc_video_erase_char);
if (!lines) if (!lines)
return 0; return false;
if (lines > c->vc_rows) /* maximum realistic size */ if (lines > c->vc_rows) /* maximum realistic size */
lines = c->vc_rows; lines = c->vc_rows;
@ -514,7 +515,7 @@ static int mdacon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
break; break;
} }
return 0; return false;
} }

View File

@ -574,8 +574,8 @@ static int newport_font_set(struct vc_data *vc, struct console_font *font, unsig
return newport_set_font(vc->vc_num, font); return newport_set_font(vc->vc_num, font);
} }
static int newport_scroll(struct vc_data *vc, int t, int b, int dir, static bool newport_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
int lines) enum con_scroll dir, unsigned int lines)
{ {
int count, x, y; int count, x, y;
unsigned short *s, *d; unsigned short *s, *d;
@ -595,7 +595,7 @@ static int newport_scroll(struct vc_data *vc, int t, int b, int dir,
(vc->vc_color & 0xf0) >> 4); (vc->vc_color & 0xf0) >> 4);
} }
npregs->cset.topscan = (topscan - 1) & 0x3ff; npregs->cset.topscan = (topscan - 1) & 0x3ff;
return 0; return false;
} }
count = (b - t - lines) * vc->vc_cols; count = (b - t - lines) * vc->vc_cols;
@ -670,7 +670,7 @@ static int newport_scroll(struct vc_data *vc, int t, int b, int dir,
} }
} }
} }
return 1; return true;
} }
static int newport_dummy(struct vc_data *c) static int newport_dummy(struct vc_data *c)

View File

@ -153,12 +153,13 @@ static void sticon_cursor(struct vc_data *conp, int mode)
} }
} }
static int sticon_scroll(struct vc_data *conp, int t, int b, int dir, int count) static bool sticon_scroll(struct vc_data *conp, unsigned int t,
unsigned int b, enum con_scroll dir, unsigned int count)
{ {
struct sti_struct *sti = sticon_sti; struct sti_struct *sti = sticon_sti;
if (vga_is_gfx) if (vga_is_gfx)
return 0; return false;
sticon_cursor(conp, CM_ERASE); sticon_cursor(conp, CM_ERASE);
@ -174,7 +175,7 @@ static int sticon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
break; break;
} }
return 0; return false;
} }
static void sticon_init(struct vc_data *c, int init) static void sticon_init(struct vc_data *c, int init)

View File

@ -60,15 +60,6 @@ static struct vgastate vgastate;
#define BLANK 0x0020 #define BLANK 0x0020
#define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */
#define CAN_LOAD_PALETTE /* undefine if the user must not do this */
/* You really do _NOT_ want to define this, unless you have buggy
* Trident VGA which will resize cursor when moving it between column
* 15 & 16. If you define this and your VGA is OK, inverse bug will
* appear.
*/
#undef TRIDENT_GLITCH
#define VGA_FONTWIDTH 8 /* VGA does not support fontwidths != 8 */ #define VGA_FONTWIDTH 8 /* VGA does not support fontwidths != 8 */
/* /*
* Interface used by the world * Interface used by the world
@ -83,14 +74,12 @@ static int vgacon_blank(struct vc_data *c, int blank, int mode_switch);
static void vgacon_scrolldelta(struct vc_data *c, int lines); static void vgacon_scrolldelta(struct vc_data *c, int lines);
static int vgacon_set_origin(struct vc_data *c); static int vgacon_set_origin(struct vc_data *c);
static void vgacon_save_screen(struct vc_data *c); static void vgacon_save_screen(struct vc_data *c);
static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
int lines);
static void vgacon_invert_region(struct vc_data *c, u16 * p, int count); static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
static struct uni_pagedir *vgacon_uni_pagedir; static struct uni_pagedir *vgacon_uni_pagedir;
static int vgacon_refcount; static int vgacon_refcount;
/* Description of the hardware situation */ /* Description of the hardware situation */
static int vga_init_done __read_mostly; static bool vga_init_done;
static unsigned long vga_vram_base __read_mostly; /* Base of video memory */ static unsigned long vga_vram_base __read_mostly; /* Base of video memory */
static unsigned long vga_vram_end __read_mostly; /* End of video memory */ static unsigned long vga_vram_end __read_mostly; /* End of video memory */
static unsigned int vga_vram_size __read_mostly; /* Size of video memory */ static unsigned int vga_vram_size __read_mostly; /* Size of video memory */
@ -98,31 +87,31 @@ static u16 vga_video_port_reg __read_mostly; /* Video register select port */
static u16 vga_video_port_val __read_mostly; /* Video register value port */ static u16 vga_video_port_val __read_mostly; /* Video register value port */
static unsigned int vga_video_num_columns; /* Number of text columns */ static unsigned int vga_video_num_columns; /* Number of text columns */
static unsigned int vga_video_num_lines; /* Number of text lines */ static unsigned int vga_video_num_lines; /* Number of text lines */
static int vga_can_do_color __read_mostly; /* Do we support colors? */ static bool vga_can_do_color; /* Do we support colors? */
static unsigned int vga_default_font_height __read_mostly; /* Height of default screen font */ static unsigned int vga_default_font_height __read_mostly; /* Height of default screen font */
static unsigned char vga_video_type __read_mostly; /* Card type */ static unsigned char vga_video_type __read_mostly; /* Card type */
static unsigned char vga_hardscroll_enabled __read_mostly; static bool vga_font_is_default = true;
static unsigned char vga_hardscroll_user_enable __read_mostly = 1;
static unsigned char vga_font_is_default = 1;
static int vga_vesa_blanked; static int vga_vesa_blanked;
static int vga_palette_blanked; static bool vga_palette_blanked;
static int vga_is_gfx; static bool vga_is_gfx;
static int vga_512_chars; static bool vga_512_chars;
static int vga_video_font_height; static int vga_video_font_height;
static int vga_scan_lines __read_mostly; static int vga_scan_lines __read_mostly;
static unsigned int vga_rolled_over; static unsigned int vga_rolled_over;
static int vgacon_text_mode_force; static bool vgacon_text_mode_force;
static bool vga_hardscroll_enabled;
static bool vga_hardscroll_user_enable = true;
bool vgacon_text_force(void) bool vgacon_text_force(void)
{ {
return vgacon_text_mode_force ? true : false; return vgacon_text_mode_force;
} }
EXPORT_SYMBOL(vgacon_text_force); EXPORT_SYMBOL(vgacon_text_force);
static int __init text_mode(char *str) static int __init text_mode(char *str)
{ {
vgacon_text_mode_force = 1; vgacon_text_mode_force = true;
return 1; return 1;
} }
@ -136,7 +125,7 @@ static int __init no_scroll(char *str)
* Braille reader made by F.H. Papenmeier (Germany). * Braille reader made by F.H. Papenmeier (Germany).
* Use the "no-scroll" bootflag. * Use the "no-scroll" bootflag.
*/ */
vga_hardscroll_user_enable = vga_hardscroll_enabled = 0; vga_hardscroll_user_enable = vga_hardscroll_enabled = false;
return 1; return 1;
} }
@ -159,18 +148,10 @@ static inline void write_vga(unsigned char reg, unsigned int val)
* handlers, thus the write has to be IRQ-atomic. * handlers, thus the write has to be IRQ-atomic.
*/ */
raw_spin_lock_irqsave(&vga_lock, flags); raw_spin_lock_irqsave(&vga_lock, flags);
#ifndef SLOW_VGA
v1 = reg + (val & 0xff00); v1 = reg + (val & 0xff00);
v2 = reg + 1 + ((val << 8) & 0xff00); v2 = reg + 1 + ((val << 8) & 0xff00);
outw(v1, vga_video_port_reg); outw(v1, vga_video_port_reg);
outw(v2, vga_video_port_reg); outw(v2, vga_video_port_reg);
#else
outb_p(reg, vga_video_port_reg);
outb_p(val >> 8, vga_video_port_val);
outb_p(reg + 1, vga_video_port_reg);
outb_p(val & 0xff, vga_video_port_val);
#endif
raw_spin_unlock_irqrestore(&vga_lock, flags); raw_spin_unlock_irqrestore(&vga_lock, flags);
} }
@ -334,31 +315,8 @@ static void vgacon_restore_screen(struct vc_data *c)
static void vgacon_scrolldelta(struct vc_data *c, int lines) static void vgacon_scrolldelta(struct vc_data *c, int lines)
{ {
if (!lines) /* Turn scrollback off */ vc_scrolldelta_helper(c, lines, vga_rolled_over, (void *)vga_vram_base,
c->vc_visible_origin = c->vc_origin; vga_vram_size);
else {
int margin = c->vc_size_row * 4;
int ul, we, p, st;
if (vga_rolled_over >
(c->vc_scr_end - vga_vram_base) + margin) {
ul = c->vc_scr_end - vga_vram_base;
we = vga_rolled_over + c->vc_size_row;
} else {
ul = 0;
we = vga_vram_size;
}
p = (c->vc_visible_origin - vga_vram_base - ul + we) % we +
lines * c->vc_size_row;
st = (c->vc_origin - vga_vram_base - ul + we) % we;
if (st < 2 * margin)
margin = 0;
if (p < margin)
p = 0;
if (p > st - margin)
p = st;
c->vc_visible_origin = vga_vram_base + (p + ul) % we;
}
vga_set_mem_top(c); vga_set_mem_top(c);
} }
#endif /* CONFIG_VGACON_SOFT_SCROLLBACK */ #endif /* CONFIG_VGACON_SOFT_SCROLLBACK */
@ -427,7 +385,7 @@ static const char *vgacon_startup(void)
} }
} else { } else {
/* If not, it is color. */ /* If not, it is color. */
vga_can_do_color = 1; vga_can_do_color = true;
vga_vram_base = 0xb8000; vga_vram_base = 0xb8000;
vga_video_port_reg = VGA_CRT_IC; vga_video_port_reg = VGA_CRT_IC;
vga_video_port_val = VGA_CRT_DC; vga_video_port_val = VGA_CRT_DC;
@ -451,18 +409,6 @@ static const char *vgacon_startup(void)
request_resource(&ioport_resource, request_resource(&ioport_resource,
&vga_console_resource); &vga_console_resource);
#ifdef VGA_CAN_DO_64KB
/*
* get 64K rather than 32K of video RAM.
* This doesn't actually work on all "VGA"
* controllers (it seems like setting MM=01
* and COE=1 isn't necessarily a good idea)
*/
vga_vram_base = 0xa0000;
vga_vram_size = 0x10000;
outb_p(6, VGA_GFX_I);
outb_p(6, VGA_GFX_D);
#endif
/* /*
* Normalise the palette registers, to point * Normalise the palette registers, to point
* the 16 screen colours to the first 16 * the 16 screen colours to the first 16
@ -542,7 +488,7 @@ static const char *vgacon_startup(void)
if (!vga_init_done) { if (!vga_init_done) {
vgacon_scrollback_startup(); vgacon_scrollback_startup();
vga_init_done = 1; vga_init_done = true;
} }
return display_desc; return display_desc;
@ -634,7 +580,7 @@ static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
static void vgacon_invert_region(struct vc_data *c, u16 * p, int count) static void vgacon_invert_region(struct vc_data *c, u16 * p, int count)
{ {
int col = vga_can_do_color; const bool col = vga_can_do_color;
while (count--) { while (count--) {
u16 a = scr_readw(p); u16 a = scr_readw(p);
@ -652,11 +598,6 @@ static void vgacon_set_cursor_size(int xpos, int from, int to)
unsigned long flags; unsigned long flags;
int curs, cure; int curs, cure;
#ifdef TRIDENT_GLITCH
if (xpos < 16)
from--, to--;
#endif
if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto)) if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto))
return; return;
cursor_size_lastfrom = from; cursor_size_lastfrom = from;
@ -858,12 +799,10 @@ static void vga_set_palette(struct vc_data *vc, const unsigned char *table)
static void vgacon_set_palette(struct vc_data *vc, const unsigned char *table) static void vgacon_set_palette(struct vc_data *vc, const unsigned char *table)
{ {
#ifdef CAN_LOAD_PALETTE
if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
|| !con_is_visible(vc)) || !con_is_visible(vc))
return; return;
vga_set_palette(vc, table); vga_set_palette(vc, table);
#endif
} }
/* structure holding original VGA register settings */ /* structure holding original VGA register settings */
@ -1006,24 +945,24 @@ static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
} }
if (vga_palette_blanked) { if (vga_palette_blanked) {
vga_set_palette(c, color_table); vga_set_palette(c, color_table);
vga_palette_blanked = 0; vga_palette_blanked = false;
return 0; return 0;
} }
vga_is_gfx = 0; vga_is_gfx = false;
/* Tell console.c that it has to restore the screen itself */ /* Tell console.c that it has to restore the screen itself */
return 1; return 1;
case 1: /* Normal blanking */ case 1: /* Normal blanking */
case -1: /* Obsolete */ case -1: /* Obsolete */
if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) { if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
vga_pal_blank(&vgastate); vga_pal_blank(&vgastate);
vga_palette_blanked = 1; vga_palette_blanked = true;
return 0; return 0;
} }
vgacon_set_origin(c); vgacon_set_origin(c);
scr_memsetw((void *) vga_vram_base, BLANK, scr_memsetw((void *) vga_vram_base, BLANK,
c->vc_screenbuf_size); c->vc_screenbuf_size);
if (mode_switch) if (mode_switch)
vga_is_gfx = 1; vga_is_gfx = true;
return 1; return 1;
default: /* VESA blanking */ default: /* VESA blanking */
if (vga_video_type == VIDEO_TYPE_VGAC) { if (vga_video_type == VIDEO_TYPE_VGAC) {
@ -1046,15 +985,14 @@ static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
* (sizif@botik.yaroslavl.su). * (sizif@botik.yaroslavl.su).
*/ */
#ifdef CAN_LOAD_EGA_FONTS
#define colourmap 0xa0000 #define colourmap 0xa0000
/* Pauline Middelink <middelin@polyware.iaf.nl> reports that we /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
should use 0xA0000 for the bwmap as well.. */ should use 0xA0000 for the bwmap as well.. */
#define blackwmap 0xa0000 #define blackwmap 0xa0000
#define cmapsz 8192 #define cmapsz 8192
static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512) static int vgacon_do_font_op(struct vgastate *state, char *arg, int set,
bool ch512)
{ {
unsigned short video_port_status = vga_video_port_reg + 6; unsigned short video_port_status = vga_video_port_reg + 6;
int font_select = 0x00, beg, i; int font_select = 0x00, beg, i;
@ -1063,10 +1001,6 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
if (vga_video_type != VIDEO_TYPE_EGAM) { if (vga_video_type != VIDEO_TYPE_EGAM) {
charmap = (char *) VGA_MAP_MEM(colourmap, 0); charmap = (char *) VGA_MAP_MEM(colourmap, 0);
beg = 0x0e; beg = 0x0e;
#ifdef VGA_CAN_DO_64KB
if (vga_video_type == VIDEO_TYPE_VGAC)
beg = 0x06;
#endif
} else { } else {
charmap = (char *) VGA_MAP_MEM(blackwmap, 0); charmap = (char *) VGA_MAP_MEM(blackwmap, 0);
beg = 0x0a; beg = 0x0a;
@ -1080,7 +1014,7 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
if (!arg) if (!arg)
return -EINVAL; /* Return to default font not supported */ return -EINVAL; /* Return to default font not supported */
vga_font_is_default = 0; vga_font_is_default = false;
font_select = ch512 ? 0x04 : 0x00; font_select = ch512 ? 0x04 : 0x00;
#else #else
/* /*
@ -1091,7 +1025,7 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
if (set) { if (set) {
vga_font_is_default = !arg; vga_font_is_default = !arg;
if (!arg) if (!arg)
ch512 = 0; /* Default font is always 256 */ ch512 = false; /* Default font is always 256 */
font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00; font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
} }
@ -1295,13 +1229,6 @@ static int vgacon_font_get(struct vc_data *c, struct console_font *font)
return vgacon_do_font_op(&vgastate, font->data, 0, vga_512_chars); return vgacon_do_font_op(&vgastate, font->data, 0, vga_512_chars);
} }
#else
#define vgacon_font_set NULL
#define vgacon_font_get NULL
#endif
static int vgacon_resize(struct vc_data *c, unsigned int width, static int vgacon_resize(struct vc_data *c, unsigned int width,
unsigned int height, unsigned int user) unsigned int height, unsigned int user)
{ {
@ -1350,17 +1277,17 @@ static void vgacon_save_screen(struct vc_data *c)
c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size); c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);
} }
static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
int lines) enum con_scroll dir, unsigned int lines)
{ {
unsigned long oldo; unsigned long oldo;
unsigned int delta; unsigned int delta;
if (t || b != c->vc_rows || vga_is_gfx || c->vc_mode != KD_TEXT) if (t || b != c->vc_rows || vga_is_gfx || c->vc_mode != KD_TEXT)
return 0; return false;
if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2) if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
return 0; return false;
vgacon_restore_screen(c); vgacon_restore_screen(c);
oldo = c->vc_origin; oldo = c->vc_origin;
@ -1396,7 +1323,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
c->vc_visible_origin = c->vc_origin; c->vc_visible_origin = c->vc_origin;
vga_set_mem_top(c); vga_set_mem_top(c);
c->vc_pos = (c->vc_pos - oldo) + c->vc_origin; c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
return 1; return true;
} }

View File

@ -28,9 +28,17 @@ struct tty_struct;
#define VT100ID "\033[?1;2c" #define VT100ID "\033[?1;2c"
#define VT102ID "\033[?6c" #define VT102ID "\033[?6c"
enum con_scroll {
SM_UP,
SM_DOWN,
};
/** /**
* struct consw - callbacks for consoles * struct consw - callbacks for consoles
* *
* @con_scroll: move lines from @top to @bottom in direction @dir by @lines.
* Return true if no generic handling should be done.
* Invoked by csi_M and printing to the console.
* @con_set_palette: sets the palette of the console to @table (optional) * @con_set_palette: sets the palette of the console to @table (optional)
* @con_scrolldelta: the contents of the console should be scrolled by @lines. * @con_scrolldelta: the contents of the console should be scrolled by @lines.
* Invoked by user. (optional) * Invoked by user. (optional)
@ -44,7 +52,9 @@ struct consw {
void (*con_putc)(struct vc_data *, int, int, int); void (*con_putc)(struct vc_data *, int, int, int);
void (*con_putcs)(struct vc_data *, const unsigned short *, int, int, int); void (*con_putcs)(struct vc_data *, const unsigned short *, int, int, int);
void (*con_cursor)(struct vc_data *, int); void (*con_cursor)(struct vc_data *, int);
int (*con_scroll)(struct vc_data *, int, int, int, int); bool (*con_scroll)(struct vc_data *, unsigned int top,
unsigned int bottom, enum con_scroll dir,
unsigned int lines);
int (*con_switch)(struct vc_data *); int (*con_switch)(struct vc_data *);
int (*con_blank)(struct vc_data *, int, int); int (*con_blank)(struct vc_data *, int, int);
int (*con_font_set)(struct vc_data *, struct console_font *, unsigned); int (*con_font_set)(struct vc_data *, struct console_font *, unsigned);
@ -99,10 +109,6 @@ static inline int con_debug_leave(void)
} }
#endif #endif
/* scroll */
#define SM_UP (1)
#define SM_DOWN (2)
/* cursor */ /* cursor */
#define CM_DRAW (1) #define CM_DRAW (1)
#define CM_ERASE (2) #define CM_ERASE (2)

View File

@ -36,6 +36,8 @@ struct plat_serial8250_port {
void (*set_termios)(struct uart_port *, void (*set_termios)(struct uart_port *,
struct ktermios *new, struct ktermios *new,
struct ktermios *old); struct ktermios *old);
void (*set_ldisc)(struct uart_port *,
struct ktermios *);
unsigned int (*get_mctrl)(struct uart_port *); unsigned int (*get_mctrl)(struct uart_port *);
int (*handle_irq)(struct uart_port *); int (*handle_irq)(struct uart_port *);
void (*pm)(struct uart_port *, unsigned int state, void (*pm)(struct uart_port *, unsigned int state,
@ -94,7 +96,7 @@ struct uart_8250_port {
struct uart_port port; struct uart_port port;
struct timer_list timer; /* "no irq" timer */ struct timer_list timer; /* "no irq" timer */
struct list_head list; /* ports on this IRQ */ struct list_head list; /* ports on this IRQ */
unsigned short capabilities; /* port capabilities */ u32 capabilities; /* port capabilities */
unsigned short bugs; /* port bugs */ unsigned short bugs; /* port bugs */
bool fifo_bug; /* min RX trigger if enabled */ bool fifo_bug; /* min RX trigger if enabled */
unsigned int tx_loadsz; /* transmit fifo load size */ unsigned int tx_loadsz; /* transmit fifo load size */
@ -149,6 +151,8 @@ extern int early_serial8250_setup(struct earlycon_device *device,
const char *options); const char *options);
extern void serial8250_do_set_termios(struct uart_port *port, extern void serial8250_do_set_termios(struct uart_port *port,
struct ktermios *termios, struct ktermios *old); struct ktermios *termios, struct ktermios *old);
extern void serial8250_do_set_ldisc(struct uart_port *port,
struct ktermios *termios);
extern unsigned int serial8250_do_get_mctrl(struct uart_port *port); extern unsigned int serial8250_do_get_mctrl(struct uart_port *port);
extern int serial8250_do_startup(struct uart_port *port); extern int serial8250_do_startup(struct uart_port *port);
extern void serial8250_do_shutdown(struct uart_port *port); extern void serial8250_do_shutdown(struct uart_port *port);
@ -168,6 +172,6 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe);
extern void serial8250_set_isa_configurator(void (*v) extern void serial8250_set_isa_configurator(void (*v)
(int port, struct uart_port *up, (int port, struct uart_port *up,
unsigned short *capabilities)); u32 *capabilities));
#endif #endif

View File

@ -123,6 +123,8 @@ struct uart_port {
void (*set_termios)(struct uart_port *, void (*set_termios)(struct uart_port *,
struct ktermios *new, struct ktermios *new,
struct ktermios *old); struct ktermios *old);
void (*set_ldisc)(struct uart_port *,
struct ktermios *);
unsigned int (*get_mctrl)(struct uart_port *); unsigned int (*get_mctrl)(struct uart_port *);
void (*set_mctrl)(struct uart_port *, unsigned int); void (*set_mctrl)(struct uart_port *, unsigned int);
int (*startup)(struct uart_port *port); int (*startup)(struct uart_port *port);

View File

@ -191,5 +191,7 @@ extern void vt_set_led_state(int console, int leds);
extern void vt_kbd_con_start(int console); extern void vt_kbd_con_start(int console);
extern void vt_kbd_con_stop(int console); extern void vt_kbd_con_stop(int console);
void vc_scrolldelta_helper(struct vc_data *c, int lines,
unsigned int rolled_over, void *_base, unsigned int size);
#endif /* _VT_KERN_H */ #endif /* _VT_KERN_H */