TTY/Serial driver update for 4.8-rc1

Here is the big tty and serial driver update for 4.8-rc1.
 
 Lots of good cleanups from Jiri on a number of vt and other tty related
 things, and the normal driver updates.  Full details are in the
 shortlog.
 
 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-----
 Version: GnuPG v2
 
 iFYEABECABYFAleVPbQPHGdyZWdAa3JvYWguY29tAAoJEDFH1A3bLfspWXgAn046
 QCMeFya4J1zjYjcGXJzNfGMUAKCHxha8Xe65cc0LDz8mNB0MgzjHEg==
 =ED8v
 -----END PGP SIGNATURE-----

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

Pull tty/serial driver updates from Greg KH:
 "Here is the big tty and serial driver update for 4.8-rc1.

  Lots of good cleanups from Jiri on a number of vt and other tty
  related things, and the normal driver updates.  Full details are in
  the shortlog.

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

* tag 'tty-4.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (90 commits)
  tty/serial: atmel: enforce tasklet init and termination sequences
  serial: sh-sci: Stop transfers in sci_shutdown()
  serial: 8250_ingenic: drop #if conditional surrounding earlycon code
  serial: 8250_mtk: drop !defined(MODULE) conditional
  serial: 8250_uniphier: drop !defined(MODULE) conditional
  earlycon: mark earlycon code as __used iif the caller is built-in
  tty/serial/8250: use mctrl_gpio helpers
  serial: mctrl_gpio: enable API usage only for initialized mctrl_gpios struct
  serial: mctrl_gpio: add modem control read routine
  tty/serial/8250: make UART_MCR register access consistent
  serial: 8250_mid: Read RX buffer on RX DMA timeout for DNV
  serial: 8250_dma: Export serial8250_rx_dma_flush()
  dmaengine: hsu: Export hsu_dma_get_status()
  tty: serial: 8250: add CON_CONSDEV to flags
  tty: serial: samsung: add byte-order aware bit functions
  tty: serial: samsung: fixup accessors for endian
  serial: sirf: make fifo functions static
  serial: mps2-uart: make driver explicitly non-modular
  serial: mvebu-uart: free the IRQ in ->shutdown()
  serial/bcm63xx_uart: use correct alias naming
  ...
This commit is contained in:
Linus Torvalds 2016-07-24 17:14:37 -07:00
commit 721413aff2
68 changed files with 1393 additions and 1139 deletions

View file

@ -42,6 +42,9 @@ Optional properties:
- auto-flow-control: one way to enable automatic flow control support. The - auto-flow-control: one way to enable automatic flow control support. The
driver is allowed to detect support for the capability even without this driver is allowed to detect support for the capability even without this
property. property.
- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD
line respectively. It will use specified GPIO instead of the peripheral
function pin for the UART feature. If unsure, don't specify this property.
Note: Note:
* fsl,ns16550: * fsl,ns16550:
@ -63,3 +66,19 @@ Example:
interrupts = <10>; interrupts = <10>;
reg-shift = <2>; reg-shift = <2>;
}; };
Example for OMAP UART using GPIO-based modem control signals:
uart4: serial@49042000 {
compatible = "ti,omap3-uart";
reg = <0x49042000 0x400>;
interrupts = <80>;
ti,hwmods = "uart4";
clock-frequency = <48000000>;
cts-gpios = <&gpio3 5 GPIO_ACTIVE_LOW>;
rts-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
dtr-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
dsr-gpios = <&gpio1 13 GPIO_ACTIVE_LOW>;
dcd-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
rng-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
};

View file

@ -31,6 +31,8 @@ Required properties:
- "renesas,hscif-r8a7794" for R8A7794 (R-Car E2) HSCIF compatible UART. - "renesas,hscif-r8a7794" for R8A7794 (R-Car E2) HSCIF compatible UART.
- "renesas,scif-r8a7795" for R8A7795 (R-Car H3) SCIF compatible UART. - "renesas,scif-r8a7795" for R8A7795 (R-Car H3) SCIF compatible UART.
- "renesas,hscif-r8a7795" for R8A7795 (R-Car H3) HSCIF compatible UART. - "renesas,hscif-r8a7795" for R8A7795 (R-Car H3) HSCIF compatible UART.
- "renesas,scif-r8a7796" for R8A7796 (R-Car M3-W) SCIF compatible UART.
- "renesas,hscif-r8a7796" for R8A7796 (R-Car M3-W) HSCIF compatible UART.
- "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART. - "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART.
- "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART. - "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART.
- "renesas,rcar-gen1-scif" for R-Car Gen1 SCIF compatible UART, - "renesas,rcar-gen1-scif" for R-Car Gen1 SCIF compatible UART,
@ -76,6 +78,10 @@ Optional properties:
- dmas: Must contain a list of two references to DMA specifiers, one for - dmas: Must contain a list of two references to DMA specifiers, one for
transmission, and one for reception. transmission, and one for reception.
- dma-names: Must contain a list of two DMA names, "tx" and "rx". - dma-names: Must contain a list of two DMA names, "tx" and "rx".
- {cts,dsr,dcd,rng,rts,dtr}-gpios: Specify GPIOs for modem lines, cfr. the
generic serial DT bindings in serial.txt.
- uart-has-rtscts: Indicates dedicated lines for RTS/CTS hardware flow
control, cfr. the generic serial DT bindings in serial.txt.
Example: Example:
aliases { aliases {

View file

@ -10003,6 +10003,7 @@ SERIAL DRIVERS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
L: linux-serial@vger.kernel.org L: linux-serial@vger.kernel.org
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/serial/
F: drivers/tty/serial/ F: drivers/tty/serial/
SYNOPSYS DESIGNWARE DMAC DRIVER SYNOPSYS DESIGNWARE DMAC DRIVER

View file

@ -12,7 +12,3 @@
* the base baud is derived from the clock speed and so is variable * the base baud is derived from the clock speed and so is variable
*/ */
#define BASE_BAUD 0 #define BASE_BAUD 0
#define STD_COM_FLAGS UPF_BOOT_AUTOCONF
#define SERIAL_PORT_DFNS

View file

@ -113,7 +113,6 @@ void platform_heartbeat(void)
} }
//#define RS_TABLE_SIZE 2 //#define RS_TABLE_SIZE 2
//#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF|UPF_SKIP_TEST)
#define _SERIAL_PORT(_base,_irq) \ #define _SERIAL_PORT(_base,_irq) \
{ \ { \

View file

@ -126,28 +126,33 @@ static void hsu_dma_start_transfer(struct hsu_dma_chan *hsuc)
hsu_dma_start_channel(hsuc); hsu_dma_start_channel(hsuc);
} }
static u32 hsu_dma_chan_get_sr(struct hsu_dma_chan *hsuc) /*
{ * hsu_dma_get_status() - get DMA channel status
unsigned long flags; * @chip: HSUART DMA chip
u32 sr; * @nr: DMA channel number
* @status: pointer for DMA Channel Status Register value
spin_lock_irqsave(&hsuc->vchan.lock, flags); *
sr = hsu_chan_readl(hsuc, HSU_CH_SR); * Description:
spin_unlock_irqrestore(&hsuc->vchan.lock, flags); * The function reads and clears the DMA Channel Status Register, checks
* if it was a timeout interrupt and returns a corresponding value.
return sr & ~(HSU_CH_SR_DESCE_ANY | HSU_CH_SR_CDESC_ANY); *
} * Caller should provide a valid pointer for the DMA Channel Status
* Register value that will be returned in @status.
irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr) *
* Return:
* 1 for DMA timeout status, 0 for other DMA status, or error code for
* invalid parameters or no interrupt pending.
*/
int hsu_dma_get_status(struct hsu_dma_chip *chip, unsigned short nr,
u32 *status)
{ {
struct hsu_dma_chan *hsuc; struct hsu_dma_chan *hsuc;
struct hsu_dma_desc *desc;
unsigned long flags; unsigned long flags;
u32 sr; u32 sr;
/* Sanity check */ /* Sanity check */
if (nr >= chip->hsu->nr_channels) if (nr >= chip->hsu->nr_channels)
return IRQ_NONE; return -EINVAL;
hsuc = &chip->hsu->chan[nr]; hsuc = &chip->hsu->chan[nr];
@ -155,22 +160,65 @@ irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr)
* No matter what situation, need read clear the IRQ status * No matter what situation, need read clear the IRQ status
* There is a bug, see Errata 5, HSD 2900918 * There is a bug, see Errata 5, HSD 2900918
*/ */
sr = hsu_dma_chan_get_sr(hsuc); spin_lock_irqsave(&hsuc->vchan.lock, flags);
sr = hsu_chan_readl(hsuc, HSU_CH_SR);
spin_unlock_irqrestore(&hsuc->vchan.lock, flags);
/* Check if any interrupt is pending */
sr &= ~(HSU_CH_SR_DESCE_ANY | HSU_CH_SR_CDESC_ANY);
if (!sr) if (!sr)
return IRQ_NONE; return -EIO;
/* Timeout IRQ, need wait some time, see Errata 2 */ /* Timeout IRQ, need wait some time, see Errata 2 */
if (sr & HSU_CH_SR_DESCTO_ANY) if (sr & HSU_CH_SR_DESCTO_ANY)
udelay(2); udelay(2);
/*
* At this point, at least one of Descriptor Time Out, Channel Error
* or Descriptor Done bits must be set. Clear the Descriptor Time Out
* bits and if sr is still non-zero, it must be channel error or
* descriptor done which are higher priority than timeout and handled
* in hsu_dma_do_irq(). Else, it must be a timeout.
*/
sr &= ~HSU_CH_SR_DESCTO_ANY; sr &= ~HSU_CH_SR_DESCTO_ANY;
if (!sr)
return IRQ_HANDLED; *status = sr;
return sr ? 0 : 1;
}
EXPORT_SYMBOL_GPL(hsu_dma_get_status);
/*
* hsu_dma_do_irq() - DMA interrupt handler
* @chip: HSUART DMA chip
* @nr: DMA channel number
* @status: Channel Status Register value
*
* Description:
* This function handles Channel Error and Descriptor Done interrupts.
* This function should be called after determining that the DMA interrupt
* is not a normal timeout interrupt, ie. hsu_dma_get_status() returned 0.
*
* Return:
* IRQ_NONE for invalid channel number, IRQ_HANDLED otherwise.
*/
irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr,
u32 status)
{
struct hsu_dma_chan *hsuc;
struct hsu_dma_desc *desc;
unsigned long flags;
/* Sanity check */
if (nr >= chip->hsu->nr_channels)
return IRQ_NONE;
hsuc = &chip->hsu->chan[nr];
spin_lock_irqsave(&hsuc->vchan.lock, flags); spin_lock_irqsave(&hsuc->vchan.lock, flags);
desc = hsuc->desc; desc = hsuc->desc;
if (desc) { if (desc) {
if (sr & HSU_CH_SR_CHE) { if (status & HSU_CH_SR_CHE) {
desc->status = DMA_ERROR; desc->status = DMA_ERROR;
} else if (desc->active < desc->nents) { } else if (desc->active < desc->nents) {
hsu_dma_start_channel(hsuc); hsu_dma_start_channel(hsuc);
@ -184,7 +232,7 @@ irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
EXPORT_SYMBOL_GPL(hsu_dma_irq); EXPORT_SYMBOL_GPL(hsu_dma_do_irq);
static struct hsu_dma_desc *hsu_dma_alloc_desc(unsigned int nents) static struct hsu_dma_desc *hsu_dma_alloc_desc(unsigned int nents)
{ {

View file

@ -27,13 +27,20 @@ static irqreturn_t hsu_pci_irq(int irq, void *dev)
{ {
struct hsu_dma_chip *chip = dev; struct hsu_dma_chip *chip = dev;
u32 dmaisr; u32 dmaisr;
u32 status;
unsigned short i; unsigned short i;
irqreturn_t ret = IRQ_NONE; irqreturn_t ret = IRQ_NONE;
int err;
dmaisr = readl(chip->regs + HSU_PCI_DMAISR); dmaisr = readl(chip->regs + HSU_PCI_DMAISR);
for (i = 0; i < chip->hsu->nr_channels; i++) { for (i = 0; i < chip->hsu->nr_channels; i++) {
if (dmaisr & 0x1) if (dmaisr & 0x1) {
ret |= hsu_dma_irq(chip, i); err = hsu_dma_get_status(chip, i, &status);
if (err > 0)
ret |= IRQ_HANDLED;
else if (err == 0)
ret |= hsu_dma_do_irq(chip, i, status);
}
dmaisr >>= 1; dmaisr >>= 1;
} }

View file

@ -93,8 +93,6 @@ static void cy_send_xchar(struct tty_struct *tty, char ch);
#define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096)) #define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096))
#endif #endif
#define STD_COM_FLAGS (0)
/* firmware stuff */ /* firmware stuff */
#define ZL_MAX_BLOCKS 16 #define ZL_MAX_BLOCKS 16
#define DRIVER_VERSION 0x02010203 #define DRIVER_VERSION 0x02010203
@ -2288,7 +2286,6 @@ static int cy_get_serial_info(struct cyclades_port *info,
.closing_wait = info->port.closing_wait, .closing_wait = info->port.closing_wait,
.baud_base = info->baud, .baud_base = info->baud,
.custom_divisor = info->custom_divisor, .custom_divisor = info->custom_divisor,
.hub6 = 0, /*!!! */
}; };
return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
} }
@ -3084,7 +3081,6 @@ static int cy_init_card(struct cyclades_card *cinfo)
info->port.closing_wait = CLOSING_WAIT_DELAY; info->port.closing_wait = CLOSING_WAIT_DELAY;
info->port.close_delay = 5 * HZ / 10; info->port.close_delay = 5 * HZ / 10;
info->port.flags = STD_COM_FLAGS;
init_completion(&info->shutdown_wait); init_completion(&info->shutdown_wait);
if (cy_is_Z(cinfo)) { if (cy_is_Z(cinfo)) {

View file

@ -252,20 +252,11 @@ static int ipwireless_get_serial_info(struct ipw_tty *tty,
{ {
struct serial_struct tmp; struct serial_struct tmp;
if (!retinfo)
return (-EFAULT);
memset(&tmp, 0, sizeof(tmp)); memset(&tmp, 0, sizeof(tmp));
tmp.type = PORT_UNKNOWN; tmp.type = PORT_UNKNOWN;
tmp.line = tty->index; tmp.line = tty->index;
tmp.port = 0;
tmp.irq = 0;
tmp.flags = 0;
tmp.baud_base = 115200; tmp.baud_base = 115200;
tmp.close_delay = 0;
tmp.closing_wait = 0;
tmp.custom_divisor = 0;
tmp.hub6 = 0;
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT; return -EFAULT;

View file

@ -1219,7 +1219,6 @@ static int mxser_get_serial_info(struct tty_struct *tty,
.close_delay = info->port.close_delay, .close_delay = info->port.close_delay,
.closing_wait = info->port.closing_wait, .closing_wait = info->port.closing_wait,
.custom_divisor = info->custom_divisor, .custom_divisor = info->custom_divisor,
.hub6 = 0
}; };
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT; return -EFAULT;

View file

@ -15,6 +15,8 @@
#include <linux/serial_reg.h> #include <linux/serial_reg.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include "../serial_mctrl_gpio.h"
struct uart_8250_dma { struct uart_8250_dma {
int (*tx_dma)(struct uart_8250_port *p); int (*tx_dma)(struct uart_8250_port *p);
int (*rx_dma)(struct uart_8250_port *p); int (*rx_dma)(struct uart_8250_port *p);
@ -53,11 +55,9 @@ struct old_serial_port {
unsigned int port; unsigned int port;
unsigned int irq; unsigned int irq;
upf_t flags; upf_t flags;
unsigned char hub6;
unsigned char io_type; unsigned char io_type;
unsigned char __iomem *iomem_base; unsigned char __iomem *iomem_base;
unsigned short iomem_reg_shift; unsigned short iomem_reg_shift;
unsigned long irqflags;
}; };
struct serial8250_config { struct serial8250_config {
@ -131,6 +131,47 @@ void serial8250_rpm_put(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);
static inline void serial8250_out_MCR(struct uart_8250_port *up, int value)
{
int mctrl_gpio = 0;
serial_out(up, UART_MCR, value);
if (value & UART_MCR_RTS)
mctrl_gpio |= TIOCM_RTS;
if (value & UART_MCR_DTR)
mctrl_gpio |= TIOCM_DTR;
mctrl_gpio_set(up->gpios, mctrl_gpio);
}
static inline int serial8250_in_MCR(struct uart_8250_port *up)
{
int mctrl, mctrl_gpio = 0;
mctrl = serial_in(up, UART_MCR);
/* save current MCR values */
if (mctrl & UART_MCR_RTS)
mctrl_gpio |= TIOCM_RTS;
if (mctrl & UART_MCR_DTR)
mctrl_gpio |= TIOCM_DTR;
mctrl_gpio = mctrl_gpio_get_outputs(up->gpios, &mctrl_gpio);
if (mctrl_gpio & TIOCM_RTS)
mctrl |= UART_MCR_RTS;
else
mctrl &= ~UART_MCR_RTS;
if (mctrl_gpio & TIOCM_DTR)
mctrl |= UART_MCR_DTR;
else
mctrl &= ~UART_MCR_DTR;
return mctrl;
}
#if defined(__alpha__) && !defined(CONFIG_PCI) #if defined(__alpha__) && !defined(CONFIG_PCI)
/* /*
* Digital did something really horribly wrong with the OUT1 and OUT2 * Digital did something really horribly wrong with the OUT1 and OUT2
@ -237,9 +278,3 @@ static inline int serial_index(struct uart_port *port)
{ {
return port->minor - 64; return port->minor - 64;
} }
#if 0
#define DEBUG_INTR(fmt...) printk(fmt)
#else
#define DEBUG_INTR(fmt...) do { } while (0)
#endif

View file

@ -114,7 +114,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
struct list_head *l, *end = NULL; struct list_head *l, *end = NULL;
int pass_counter = 0, handled = 0; int pass_counter = 0, handled = 0;
DEBUG_INTR("serial8250_interrupt(%d)...", irq); pr_debug("%s(%d): start\n", __func__, irq);
spin_lock(&i->lock); spin_lock(&i->lock);
@ -144,7 +144,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
spin_unlock(&i->lock); spin_unlock(&i->lock);
DEBUG_INTR("end.\n"); pr_debug("%s(%d): end\n", __func__, irq);
return IRQ_RETVAL(handled); return IRQ_RETVAL(handled);
} }
@ -546,10 +546,10 @@ static void __init serial8250_isa_init_ports(void)
port->iobase = old_serial_port[i].port; port->iobase = old_serial_port[i].port;
port->irq = irq_canonicalize(old_serial_port[i].irq); port->irq = irq_canonicalize(old_serial_port[i].irq);
port->irqflags = old_serial_port[i].irqflags; port->irqflags = 0;
port->uartclk = old_serial_port[i].baud_base * 16; port->uartclk = old_serial_port[i].baud_base * 16;
port->flags = old_serial_port[i].flags; port->flags = old_serial_port[i].flags;
port->hub6 = old_serial_port[i].hub6; port->hub6 = 0;
port->membase = old_serial_port[i].iomem_base; port->membase = old_serial_port[i].iomem_base;
port->iotype = old_serial_port[i].io_type; port->iotype = old_serial_port[i].io_type;
port->regshift = old_serial_port[i].iomem_reg_shift; port->regshift = old_serial_port[i].iomem_reg_shift;
@ -675,7 +675,7 @@ static struct console univ8250_console = {
.device = uart_console_device, .device = uart_console_device,
.setup = univ8250_console_setup, .setup = univ8250_console_setup,
.match = univ8250_console_match, .match = univ8250_console_match,
.flags = CON_PRINTBUFFER | CON_ANYTIME, .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_CONSDEV,
.index = -1, .index = -1,
.data = &serial8250_reg, .data = &serial8250_reg,
}; };
@ -974,6 +974,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart = serial8250_find_match_or_unused(&up->port); uart = serial8250_find_match_or_unused(&up->port);
if (uart && uart->port.type != PORT_8250_CIR) { if (uart && uart->port.type != PORT_8250_CIR) {
struct mctrl_gpios *gpios;
if (uart->port.dev) if (uart->port.dev)
uart_remove_one_port(&serial8250_reg, &uart->port); uart_remove_one_port(&serial8250_reg, &uart->port);
@ -1011,6 +1013,13 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
if (up->port.flags & UPF_FIXED_TYPE) if (up->port.flags & UPF_FIXED_TYPE)
uart->port.type = up->port.type; uart->port.type = up->port.type;
gpios = mctrl_gpio_init(&uart->port, 0);
if (IS_ERR(gpios)) {
if (PTR_ERR(gpios) != -ENOSYS)
return PTR_ERR(gpios);
} else
uart->gpios = gpios;
serial8250_set_defaults(uart); serial8250_set_defaults(uart);
/* Possibly override default I/O functions. */ /* Possibly override default I/O functions. */

View file

@ -145,6 +145,7 @@ void serial8250_rx_dma_flush(struct uart_8250_port *p)
dmaengine_terminate_all(dma->rxchan); dmaengine_terminate_all(dma->rxchan);
} }
} }
EXPORT_SYMBOL_GPL(serial8250_rx_dma_flush);
int serial8250_request_dma(struct uart_8250_port *p) int serial8250_request_dma(struct uart_8250_port *p)
{ {

View file

@ -150,6 +150,7 @@ EARLYCON_DECLARE(uart, early_serial8250_setup);
OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup); OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup);
OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup); OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup);
OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup); OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup);
OF_EARLYCON_DECLARE(uart, "snps,dw-apb-uart", early_serial8250_setup);
#ifdef CONFIG_SERIAL_8250_OMAP #ifdef CONFIG_SERIAL_8250_OMAP

View file

@ -13,6 +13,7 @@
#include <linux/pnp.h> #include <linux/pnp.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/irq.h>
#include "8250.h" #include "8250.h"
#define ADDR_PORT 0 #define ADDR_PORT 0
@ -30,6 +31,12 @@
#define IO_ADDR2 0x60 #define IO_ADDR2 0x60
#define LDN 0x7 #define LDN 0x7
#define IRQ_MODE 0x70
#define IRQ_SHARE BIT(4)
#define IRQ_MODE_MASK (BIT(6) | BIT(5))
#define IRQ_LEVEL_LOW 0
#define IRQ_EDGE_HIGH BIT(5)
#define RS485 0xF0 #define RS485 0xF0
#define RTS_INVERT BIT(5) #define RTS_INVERT BIT(5)
#define RS485_URA BIT(4) #define RS485_URA BIT(4)
@ -176,10 +183,37 @@ 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)
{
int status;
u8 tmp;
status = fintek_8250_enter_key(pdata->base_port, pdata->key);
if (status)
return status;
outb(LDN, pdata->base_port + ADDR_PORT);
outb(pdata->index, pdata->base_port + DATA_PORT);
outb(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 (find_base_port(&probe_data, uart->port.iobase))
return -ENODEV; return -ENODEV;
@ -192,5 +226,5 @@ int fintek_8250_probe(struct uart_8250_port *uart)
uart->port.rs485_config = fintek_8250_rs485_config; uart->port.rs485_config = fintek_8250_rs485_config;
uart->port.private_data = pdata; uart->port.private_data = pdata;
return 0; return fintek_8250_set_irq_mode(pdata, level_mode);
} }

View file

@ -48,7 +48,6 @@ static const struct of_device_id of_match[];
#define UART_MCR_MDCE BIT(7) #define UART_MCR_MDCE BIT(7)
#define UART_MCR_FCM BIT(6) #define UART_MCR_FCM BIT(6)
#if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE)
static struct earlycon_device *early_device; static struct earlycon_device *early_device;
static uint8_t __init early_in(struct uart_port *port, int offset) static uint8_t __init early_in(struct uart_port *port, int offset)
@ -141,7 +140,6 @@ OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart",
EARLYCON_DECLARE(jz4780_uart, ingenic_early_console_setup); EARLYCON_DECLARE(jz4780_uart, ingenic_early_console_setup);
OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart", OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart",
ingenic_early_console_setup); ingenic_early_console_setup);
#endif /* CONFIG_SERIAL_EARLYCON */
static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value) static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
{ {

View file

@ -96,13 +96,27 @@ static int tng_setup(struct mid8250 *mid, struct uart_port *p)
static int dnv_handle_irq(struct uart_port *p) static int dnv_handle_irq(struct uart_port *p)
{ {
struct mid8250 *mid = p->private_data; struct mid8250 *mid = p->private_data;
struct uart_8250_port *up = up_to_u8250p(p);
unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR); unsigned int fisr = serial_port_in(p, INTEL_MID_UART_DNV_FISR);
u32 status;
int ret = IRQ_NONE; int ret = IRQ_NONE;
int err;
if (fisr & BIT(2)) if (fisr & BIT(2)) {
ret |= hsu_dma_irq(&mid->dma_chip, 1); err = hsu_dma_get_status(&mid->dma_chip, 1, &status);
if (fisr & BIT(1)) if (err > 0) {
ret |= hsu_dma_irq(&mid->dma_chip, 0); serial8250_rx_dma_flush(up);
ret |= IRQ_HANDLED;
} else if (err == 0)
ret |= hsu_dma_do_irq(&mid->dma_chip, 1, status);
}
if (fisr & BIT(1)) {
err = hsu_dma_get_status(&mid->dma_chip, 0, &status);
if (err > 0)
ret |= IRQ_HANDLED;
else if (err == 0)
ret |= hsu_dma_do_irq(&mid->dma_chip, 0, status);
}
if (fisr & BIT(0)) if (fisr & BIT(0))
ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR)); ret |= serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
return ret; return ret;

View file

@ -301,7 +301,7 @@ static struct platform_driver mtk8250_platform_driver = {
}; };
module_platform_driver(mtk8250_platform_driver); module_platform_driver(mtk8250_platform_driver);
#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE) #ifdef CONFIG_SERIAL_8250_CONSOLE
static int __init early_mtk8250_setup(struct earlycon_device *device, static int __init early_mtk8250_setup(struct earlycon_device *device,
const char *options) const char *options)
{ {

View file

@ -134,18 +134,21 @@ static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
serial8250_do_set_mctrl(port, mctrl); serial8250_do_set_mctrl(port, mctrl);
/* if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(up->gpios,
* Turn off autoRTS if RTS is lowered and restore autoRTS setting UART_GPIO_RTS))) {
* if RTS is raised /*
*/ * Turn off autoRTS if RTS is lowered and restore autoRTS
lcr = serial_in(up, UART_LCR); * setting if RTS is raised
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); */
if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS)) lcr = serial_in(up, UART_LCR);
priv->efr |= UART_EFR_RTS; serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
else if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
priv->efr &= ~UART_EFR_RTS; priv->efr |= UART_EFR_RTS;
serial_out(up, UART_EFR, priv->efr); else
serial_out(up, UART_LCR, lcr); priv->efr &= ~UART_EFR_RTS;
serial_out(up, UART_EFR, priv->efr);
serial_out(up, UART_LCR, lcr);
}
} }
/* /*
@ -280,7 +283,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
serial_out(up, UART_EFR, UART_EFR_ECB); serial_out(up, UART_EFR, UART_EFR_ECB);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
serial_out(up, UART_MCR, UART_MCR_TCRTLR); serial8250_out_MCR(up, UART_MCR_TCRTLR);
serial_out(up, UART_FCR, up->fcr); serial_out(up, UART_FCR, up->fcr);
omap8250_update_scr(up, priv); omap8250_update_scr(up, priv);
@ -296,7 +299,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
serial_out(up, UART_LCR, 0); serial_out(up, UART_LCR, 0);
/* drop TCR + TLR access, we setup XON/XOFF later */ /* drop TCR + TLR access, we setup XON/XOFF later */
serial_out(up, UART_MCR, up->mcr); serial8250_out_MCR(up, up->mcr);
serial_out(up, UART_IER, up->ier); serial_out(up, UART_IER, up->ier);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
@ -446,7 +449,9 @@ static void omap_8250_set_termios(struct uart_port *port,
priv->efr = 0; priv->efr = 0;
up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF); up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) { if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW
&& IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(up->gpios,
UART_GPIO_RTS))) {
/* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */ /* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */
up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS; up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
priv->efr |= UART_EFR_CTS; priv->efr |= UART_EFR_CTS;

View file

@ -1136,11 +1136,11 @@ static int pci_quatech_rqopr(struct uart_8250_port *port)
static void pci_quatech_wqopr(struct uart_8250_port *port, u8 qopr) static void pci_quatech_wqopr(struct uart_8250_port *port, u8 qopr)
{ {
unsigned long base = port->port.iobase; unsigned long base = port->port.iobase;
u8 LCR, val; u8 LCR;
LCR = inb(base + UART_LCR); LCR = inb(base + UART_LCR);
outb(0xBF, base + UART_LCR); outb(0xBF, base + UART_LCR);
val = inb(base + UART_SCR); inb(base + UART_SCR);
outb(qopr, base + UART_SCR); outb(qopr, base + UART_SCR);
outb(LCR, base + UART_LCR); outb(LCR, base + UART_LCR);
} }
@ -1864,6 +1864,16 @@ pci_wch_ch353_setup(struct serial_private *priv,
return pci_default_setup(priv, board, port, idx); return pci_default_setup(priv, board, port, idx);
} }
static int
pci_wch_ch355_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_8250_port *port, int idx)
{
port->port.flags |= UPF_FIXED_TYPE;
port->port.type = PORT_16550A;
return pci_default_setup(priv, board, port, idx);
}
static int static int
pci_wch_ch38x_setup(struct serial_private *priv, pci_wch_ch38x_setup(struct serial_private *priv,
const struct pciserial_board *board, const struct pciserial_board *board,
@ -1915,6 +1925,7 @@ pci_wch_ch38x_setup(struct serial_private *priv,
#define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046 #define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046
#define PCI_DEVICE_ID_WCH_CH353_1S1P 0x5053 #define PCI_DEVICE_ID_WCH_CH353_1S1P 0x5053
#define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053 #define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053
#define PCI_DEVICE_ID_WCH_CH355_4S 0x7173
#define PCI_VENDOR_ID_AGESTAR 0x5372 #define PCI_VENDOR_ID_AGESTAR 0x5372
#define PCI_DEVICE_ID_AGESTAR_9375 0x6872 #define PCI_DEVICE_ID_AGESTAR_9375 0x6872
#define PCI_VENDOR_ID_ASIX 0x9710 #define PCI_VENDOR_ID_ASIX 0x9710
@ -2618,6 +2629,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID, .subdevice = PCI_ANY_ID,
.setup = pci_wch_ch353_setup, .setup = pci_wch_ch353_setup,
}, },
/* WCH CH355 4S card (16550 clone) */
{
.vendor = PCI_VENDOR_ID_WCH,
.device = PCI_DEVICE_ID_WCH_CH355_4S,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_wch_ch355_setup,
},
/* WCH CH382 2S card (16850 clone) */ /* WCH CH382 2S card (16850 clone) */
{ {
.vendor = PCIE_VENDOR_ID_WCH, .vendor = PCIE_VENDOR_ID_WCH,
@ -3812,6 +3831,7 @@ static const struct pci_device_id blacklist[] = {
/* multi-io cards handled by parport_serial */ /* multi-io cards handled by parport_serial */
{ PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */ { PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */
{ PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */ { PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */
{ PCI_DEVICE(0x4348, 0x7173), }, /* WCH CH355 4S */
{ PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */ { PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */
{ PCI_DEVICE(0x1c00, 0x3470), }, /* WCH CH384 4S */ { PCI_DEVICE(0x1c00, 0x3470), }, /* WCH CH384 4S */
@ -5567,6 +5587,10 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_b0_bt_2_115200 }, 0, 0, pbn_b0_bt_2_115200 },
{ PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH355_4S,
PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_b0_bt_4_115200 },
{ PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH382_2S, { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH382_2S,
PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_wch382_2 }, 0, 0, pbn_wch382_2 },

View file

@ -527,13 +527,13 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
static inline void serial8250_em485_rts_after_send(struct uart_8250_port *p) static inline void serial8250_em485_rts_after_send(struct uart_8250_port *p)
{ {
unsigned char mcr = serial_in(p, UART_MCR); unsigned char mcr = serial8250_in_MCR(p);
if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND) if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
mcr |= UART_MCR_RTS; mcr |= UART_MCR_RTS;
else else
mcr &= ~UART_MCR_RTS; mcr &= ~UART_MCR_RTS;
serial_out(p, UART_MCR, mcr); serial8250_out_MCR(p, mcr);
} }
static void serial8250_em485_handle_start_tx(unsigned long arg); static void serial8250_em485_handle_start_tx(unsigned long arg);
@ -785,10 +785,10 @@ static int size_fifo(struct uart_8250_port *up)
old_lcr = serial_in(up, UART_LCR); old_lcr = serial_in(up, UART_LCR);
serial_out(up, UART_LCR, 0); serial_out(up, UART_LCR, 0);
old_fcr = serial_in(up, UART_FCR); old_fcr = serial_in(up, UART_FCR);
old_mcr = serial_in(up, UART_MCR); old_mcr = serial8250_in_MCR(up);
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
serial_out(up, UART_MCR, UART_MCR_LOOP); serial8250_out_MCR(up, UART_MCR_LOOP);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
old_dl = serial_dl_read(up); old_dl = serial_dl_read(up);
serial_dl_write(up, 0x0001); serial_dl_write(up, 0x0001);
@ -800,7 +800,7 @@ static int size_fifo(struct uart_8250_port *up)
(count < 256); count++) (count < 256); count++)
serial_in(up, UART_RX); serial_in(up, UART_RX);
serial_out(up, UART_FCR, old_fcr); serial_out(up, UART_FCR, old_fcr);
serial_out(up, UART_MCR, old_mcr); serial8250_out_MCR(up, old_mcr);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
serial_dl_write(up, old_dl); serial_dl_write(up, old_dl);
serial_out(up, UART_LCR, old_lcr); serial_out(up, UART_LCR, old_lcr);
@ -1040,17 +1040,17 @@ static void autoconfig_16550a(struct uart_8250_port *up)
* it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2 * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2
*/ */
serial_out(up, UART_LCR, 0); serial_out(up, UART_LCR, 0);
status1 = serial_in(up, UART_MCR); status1 = serial8250_in_MCR(up);
serial_out(up, UART_LCR, 0xE0); serial_out(up, UART_LCR, 0xE0);
status2 = serial_in(up, 0x02); /* EXCR1 */ status2 = serial_in(up, 0x02); /* EXCR1 */
if (!((status2 ^ status1) & UART_MCR_LOOP)) { if (!((status2 ^ status1) & UART_MCR_LOOP)) {
serial_out(up, UART_LCR, 0); serial_out(up, UART_LCR, 0);
serial_out(up, UART_MCR, status1 ^ UART_MCR_LOOP); serial8250_out_MCR(up, status1 ^ UART_MCR_LOOP);
serial_out(up, UART_LCR, 0xE0); serial_out(up, UART_LCR, 0xE0);
status2 = serial_in(up, 0x02); /* EXCR1 */ status2 = serial_in(up, 0x02); /* EXCR1 */
serial_out(up, UART_LCR, 0); serial_out(up, UART_LCR, 0);
serial_out(up, UART_MCR, status1); serial8250_out_MCR(up, status1);
if ((status2 ^ status1) & UART_MCR_LOOP) { if ((status2 ^ status1) & UART_MCR_LOOP) {
unsigned short quot; unsigned short quot;
@ -1224,7 +1224,7 @@ static void autoconfig(struct uart_8250_port *up)
} }
} }
save_mcr = serial_in(up, UART_MCR); save_mcr = serial8250_in_MCR(up);
save_lcr = serial_in(up, UART_LCR); save_lcr = serial_in(up, UART_LCR);
/* /*
@ -1237,9 +1237,9 @@ static void autoconfig(struct uart_8250_port *up)
* that conflicts with COM 1-4 --- we hope! * that conflicts with COM 1-4 --- we hope!
*/ */
if (!(port->flags & UPF_SKIP_TEST)) { if (!(port->flags & UPF_SKIP_TEST)) {
serial_out(up, UART_MCR, UART_MCR_LOOP | 0x0A); serial8250_out_MCR(up, UART_MCR_LOOP | 0x0A);
status1 = serial_in(up, UART_MSR) & 0xF0; status1 = serial_in(up, UART_MSR) & 0xF0;
serial_out(up, UART_MCR, save_mcr); serial8250_out_MCR(up, save_mcr);
if (status1 != 0x90) { if (status1 != 0x90) {
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
DEBUG_AUTOCONF("LOOP test failed (%02x) ", DEBUG_AUTOCONF("LOOP test failed (%02x) ",
@ -1305,7 +1305,7 @@ static void autoconfig(struct uart_8250_port *up)
if (port->type == PORT_RSA) if (port->type == PORT_RSA)
serial_out(up, UART_RSA_FRR, 0); serial_out(up, UART_RSA_FRR, 0);
#endif #endif
serial_out(up, UART_MCR, save_mcr); serial8250_out_MCR(up, save_mcr);
serial8250_clear_fifos(up); serial8250_clear_fifos(up);
serial_in(up, UART_RX); serial_in(up, UART_RX);
if (up->capabilities & UART_CAP_UUE) if (up->capabilities & UART_CAP_UUE)
@ -1353,19 +1353,18 @@ static void autoconfig_irq(struct uart_8250_port *up)
/* forget possible initially masked and pending IRQ */ /* forget possible initially masked and pending IRQ */
probe_irq_off(probe_irq_on()); probe_irq_off(probe_irq_on());
save_mcr = serial_in(up, UART_MCR); save_mcr = serial8250_in_MCR(up);
save_ier = serial_in(up, UART_IER); save_ier = serial_in(up, UART_IER);
serial_out(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); serial8250_out_MCR(up, UART_MCR_OUT1 | UART_MCR_OUT2);
irqs = probe_irq_on(); irqs = probe_irq_on();
serial_out(up, UART_MCR, 0); serial8250_out_MCR(up, 0);
udelay(10); udelay(10);
if (port->flags & UPF_FOURPORT) { if (port->flags & UPF_FOURPORT) {
serial_out(up, UART_MCR, serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS);
UART_MCR_DTR | UART_MCR_RTS);
} else { } else {
serial_out(up, UART_MCR, serial8250_out_MCR(up,
UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
} }
serial_out(up, UART_IER, 0x0f); /* enable all intrs */ serial_out(up, UART_IER, 0x0f); /* enable all intrs */
serial_in(up, UART_LSR); serial_in(up, UART_LSR);
@ -1376,7 +1375,7 @@ static void autoconfig_irq(struct uart_8250_port *up)
udelay(20); udelay(20);
irq = probe_irq_off(irqs); irq = probe_irq_off(irqs);
serial_out(up, UART_MCR, save_mcr); serial8250_out_MCR(up, save_mcr);
serial_out(up, UART_IER, save_ier); serial_out(up, UART_IER, save_ier);
if (port->flags & UPF_FOURPORT) if (port->flags & UPF_FOURPORT)
@ -1549,14 +1548,14 @@ static inline void start_tx_rs485(struct uart_port *port)
del_timer(&em485->stop_tx_timer); del_timer(&em485->stop_tx_timer);
em485->active_timer = NULL; em485->active_timer = NULL;
mcr = serial_in(up, UART_MCR); mcr = serial8250_in_MCR(up);
if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) != if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) !=
!!(mcr & UART_MCR_RTS)) { !!(mcr & UART_MCR_RTS)) {
if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND) if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
mcr |= UART_MCR_RTS; mcr |= UART_MCR_RTS;
else else
mcr &= ~UART_MCR_RTS; mcr &= ~UART_MCR_RTS;
serial_out(up, UART_MCR, mcr); serial8250_out_MCR(up, mcr);
if (up->port.rs485.delay_rts_before_send > 0) { if (up->port.rs485.delay_rts_before_send > 0) {
em485->active_timer = &em485->start_tx_timer; em485->active_timer = &em485->start_tx_timer;
@ -1619,6 +1618,8 @@ static void serial8250_disable_ms(struct uart_port *port)
if (up->bugs & UART_BUG_NOMSR) if (up->bugs & UART_BUG_NOMSR)
return; return;
mctrl_gpio_disable_ms(up->gpios);
up->ier &= ~UART_IER_MSI; up->ier &= ~UART_IER_MSI;
serial_port_out(port, UART_IER, up->ier); serial_port_out(port, UART_IER, up->ier);
} }
@ -1631,6 +1632,8 @@ static void serial8250_enable_ms(struct uart_port *port)
if (up->bugs & UART_BUG_NOMSR) if (up->bugs & UART_BUG_NOMSR)
return; return;
mctrl_gpio_enable_ms(up->gpios);
up->ier |= UART_IER_MSI; up->ier |= UART_IER_MSI;
serial8250_rpm_get(up); serial8250_rpm_get(up);
@ -1686,7 +1689,7 @@ static void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr)
lsr &= port->read_status_mask; lsr &= port->read_status_mask;
if (lsr & UART_LSR_BI) { if (lsr & UART_LSR_BI) {
DEBUG_INTR("handling break...."); pr_debug("%s: handling break\n", __func__);
flag = TTY_BREAK; flag = TTY_BREAK;
} else if (lsr & UART_LSR_PE) } else if (lsr & UART_LSR_PE)
flag = TTY_PARITY; flag = TTY_PARITY;
@ -1757,7 +1760,7 @@ void serial8250_tx_chars(struct uart_8250_port *up)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port); uart_write_wakeup(port);
DEBUG_INTR("THRE..."); pr_debug("%s: THRE\n", __func__);
/* /*
* With RPM enabled, we have to wait until the FIFO is empty before the * With RPM enabled, we have to wait until the FIFO is empty before the
@ -1823,7 +1826,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
status = serial_port_in(port, UART_LSR); status = serial_port_in(port, UART_LSR);
DEBUG_INTR("status = %x...", status); pr_debug("%s: status = %x\n", __func__, status);
if (status & (UART_LSR_DR | UART_LSR_BI)) { if (status & (UART_LSR_DR | UART_LSR_BI)) {
if (!up->dma || handle_rx_dma(up, iir)) if (!up->dma || handle_rx_dma(up, iir))
@ -1861,7 +1864,6 @@ static int serial8250_default_handle_irq(struct uart_port *port)
*/ */
static int exar_handle_irq(struct uart_port *port) static int exar_handle_irq(struct uart_port *port)
{ {
unsigned char int0, int1, int2, int3;
unsigned int iir = serial_port_in(port, UART_IIR); unsigned int iir = serial_port_in(port, UART_IIR);
int ret; int ret;
@ -1869,10 +1871,10 @@ static int exar_handle_irq(struct uart_port *port)
if ((port->type == PORT_XR17V35X) || if ((port->type == PORT_XR17V35X) ||
(port->type == PORT_XR17D15X)) { (port->type == PORT_XR17D15X)) {
int0 = serial_port_in(port, 0x80); serial_port_in(port, 0x80);
int1 = serial_port_in(port, 0x81); serial_port_in(port, 0x81);
int2 = serial_port_in(port, 0x82); serial_port_in(port, 0x82);
int3 = serial_port_in(port, 0x83); serial_port_in(port, 0x83);
} }
return ret; return ret;
@ -1915,7 +1917,8 @@ unsigned int serial8250_do_get_mctrl(struct uart_port *port)
ret |= TIOCM_DSR; ret |= TIOCM_DSR;
if (status & UART_MSR_CTS) if (status & UART_MSR_CTS)
ret |= TIOCM_CTS; ret |= TIOCM_CTS;
return ret;
return mctrl_gpio_get(up->gpios, &ret);
} }
EXPORT_SYMBOL_GPL(serial8250_do_get_mctrl); EXPORT_SYMBOL_GPL(serial8250_do_get_mctrl);
@ -1944,7 +1947,7 @@ void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
serial_port_out(port, UART_MCR, mcr); serial8250_out_MCR(up, mcr);
} }
EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl); EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl);
@ -1994,8 +1997,6 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
/* Wait up to 1s for flow control if necessary */ /* Wait up to 1s for flow control if necessary */
if (up->port.flags & UPF_CONS_FLOW) { if (up->port.flags & UPF_CONS_FLOW) {
unsigned int tmout;
for (tmout = 1000000; tmout; tmout--) { for (tmout = 1000000; tmout; tmout--) {
unsigned int msr = serial_in(up, UART_MSR); unsigned int msr = serial_in(up, UART_MSR);
up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
@ -3093,7 +3094,7 @@ static void serial8250_console_restore(struct uart_8250_port *up)
serial8250_set_divisor(port, baud, quot, frac); serial8250_set_divisor(port, baud, quot, frac);
serial_port_out(port, UART_LCR, up->lcr); serial_port_out(port, UART_LCR, up->lcr);
serial_port_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS);
} }
/* /*

View file

@ -35,7 +35,7 @@ struct uniphier8250_priv {
spinlock_t atomic_write_lock; spinlock_t atomic_write_lock;
}; };
#if defined(CONFIG_SERIAL_8250_CONSOLE) && !defined(MODULE) #ifdef CONFIG_SERIAL_8250_CONSOLE
static int __init uniphier_early_console_setup(struct earlycon_device *device, static int __init uniphier_early_console_setup(struct earlycon_device *device,
const char *options) const char *options)
{ {

View file

@ -6,6 +6,7 @@
config SERIAL_8250 config SERIAL_8250
tristate "8250/16550 and compatible serial support" tristate "8250/16550 and compatible serial support"
select SERIAL_CORE select SERIAL_CORE
select SERIAL_MCTRL_GPIO if GPIOLIB
---help--- ---help---
This selects whether you want to include the driver for the standard This selects whether you want to include the driver for the standard
serial ports. The standard answer is Y. People who might say N serial ports. The standard answer is Y. People who might say N
@ -387,7 +388,8 @@ config SERIAL_8250_MT6577
config SERIAL_8250_UNIPHIER config SERIAL_8250_UNIPHIER
tristate "Support for UniPhier on-chip UART" tristate "Support for UniPhier on-chip UART"
depends on SERIAL_8250 && ARCH_UNIPHIER depends on SERIAL_8250
depends on ARCH_UNIPHIER || COMPILE_TEST
help help
If you have a UniPhier based board and want to use the on-chip If you have a UniPhier based board and want to use the on-chip
serial ports, say Y to this option. If unsure, say N. serial ports, say Y to this option. If unsure, say N.
@ -395,7 +397,7 @@ config SERIAL_8250_UNIPHIER
config SERIAL_8250_INGENIC config SERIAL_8250_INGENIC
tristate "Support for Ingenic SoC serial ports" tristate "Support for Ingenic SoC serial ports"
depends on SERIAL_8250 depends on SERIAL_8250
depends on (OF_FLATTREE && SERIAL_8250_CONSOLE) || !SERIAL_EARLYCON depends on OF_FLATTREE
depends on MIPS || COMPILE_TEST depends on MIPS || COMPILE_TEST
help help
If you have a system using an Ingenic SoC and wish to make use of If you have a system using an Ingenic SoC and wish to make use of

View file

@ -736,6 +736,7 @@ config SERIAL_SH_SCI
tristate "SuperH SCI(F) serial port support" tristate "SuperH SCI(F) serial port support"
depends on SUPERH || ARCH_RENESAS || H8300 || COMPILE_TEST depends on SUPERH || ARCH_RENESAS || H8300 || COMPILE_TEST
select SERIAL_CORE select SERIAL_CORE
select SERIAL_MCTRL_GPIO if GPIOLIB
config SERIAL_SH_SCI_NR_UARTS config SERIAL_SH_SCI_NR_UARTS
int "Maximum number of SCI(F) serial ports" int "Maximum number of SCI(F) serial ports"
@ -1477,7 +1478,7 @@ config SERIAL_MPS2_UART_CONSOLE
config SERIAL_MPS2_UART config SERIAL_MPS2_UART
bool "MPS2 UART port" bool "MPS2 UART port"
depends on ARM || COMPILE_TEST depends on ARCH_MPS2 || COMPILE_TEST
select SERIAL_CORE select SERIAL_CORE
help help
This driver support the UART ports on ARM MPS2. This driver support the UART ports on ARM MPS2.

View file

@ -2553,11 +2553,17 @@ static int sbsa_uart_probe(struct platform_device *pdev)
if (!uap) if (!uap)
return -ENOMEM; return -ENOMEM;
ret = platform_get_irq(pdev, 0);
if (ret < 0) {
dev_err(&pdev->dev, "cannot obtain irq\n");
return ret;
}
uap->port.irq = ret;
uap->reg_offset = vendor_sbsa.reg_offset; uap->reg_offset = vendor_sbsa.reg_offset;
uap->vendor = &vendor_sbsa; uap->vendor = &vendor_sbsa;
uap->fifosize = 32; uap->fifosize = 32;
uap->port.iotype = vendor_sbsa.access_32b ? UPIO_MEM32 : UPIO_MEM; uap->port.iotype = vendor_sbsa.access_32b ? UPIO_MEM32 : UPIO_MEM;
uap->port.irq = platform_get_irq(pdev, 0);
uap->port.ops = &sbsa_uart_pops; uap->port.ops = &sbsa_uart_pops;
uap->fixed_baud = baudrate; uap->fixed_baud = baudrate;

View file

@ -108,6 +108,12 @@ struct atmel_uart_char {
u16 ch; u16 ch;
}; };
/*
* Be careful, the real size of the ring buffer is
* sizeof(atmel_uart_char) * ATMEL_SERIAL_RINGSIZE. It means that ring buffer
* can contain up to 1024 characters in PIO mode and up to 4096 characters in
* DMA mode.
*/
#define ATMEL_SERIAL_RINGSIZE 1024 #define ATMEL_SERIAL_RINGSIZE 1024
/* /*
@ -145,10 +151,10 @@ struct atmel_uart_port {
dma_cookie_t cookie_rx; dma_cookie_t cookie_rx;
struct scatterlist sg_tx; struct scatterlist sg_tx;
struct scatterlist sg_rx; struct scatterlist sg_rx;
struct tasklet_struct tasklet; struct tasklet_struct tasklet_rx;
unsigned int irq_status; struct tasklet_struct tasklet_tx;
atomic_t tasklet_shutdown;
unsigned int irq_status_prev; unsigned int irq_status_prev;
unsigned int status_change;
unsigned int tx_len; unsigned int tx_len;
struct circ_buf rx_ring; struct circ_buf rx_ring;
@ -281,6 +287,13 @@ static bool atmel_use_fifo(struct uart_port *port)
return atmel_port->fifo_size; return atmel_port->fifo_size;
} }
static void atmel_tasklet_schedule(struct atmel_uart_port *atmel_port,
struct tasklet_struct *t)
{
if (!atomic_read(&atmel_port->tasklet_shutdown))
tasklet_schedule(t);
}
static unsigned int atmel_get_lines_status(struct uart_port *port) static unsigned int atmel_get_lines_status(struct uart_port *port)
{ {
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
@ -482,19 +495,21 @@ static void atmel_start_tx(struct uart_port *port)
{ {
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
if (atmel_use_pdc_tx(port)) { if (atmel_use_pdc_tx(port) && (atmel_uart_readl(port, ATMEL_PDC_PTSR)
if (atmel_uart_readl(port, ATMEL_PDC_PTSR) & ATMEL_PDC_TXTEN) & ATMEL_PDC_TXTEN))
/* The transmitter is already running. Yes, we /* The transmitter is already running. Yes, we
really need this.*/ really need this.*/
return; return;
if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port))
if ((port->rs485.flags & SER_RS485_ENABLED) && if ((port->rs485.flags & SER_RS485_ENABLED) &&
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) !(port->rs485.flags & SER_RS485_RX_DURING_TX))
atmel_stop_rx(port); atmel_stop_rx(port);
if (atmel_use_pdc_tx(port))
/* re-enable PDC transmit */ /* re-enable PDC transmit */
atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
}
/* Enable interrupts */ /* Enable interrupts */
atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask); atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);
} }
@ -710,7 +725,7 @@ static void atmel_rx_chars(struct uart_port *port)
status = atmel_uart_readl(port, ATMEL_US_CSR); status = atmel_uart_readl(port, ATMEL_US_CSR);
} }
tasklet_schedule(&atmel_port->tasklet); atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_rx);
} }
/* /*
@ -781,7 +796,7 @@ static void atmel_complete_tx_dma(void *arg)
* remaining data from the beginning of xmit->buf to xmit->head. * remaining data from the beginning of xmit->buf to xmit->head.
*/ */
if (!uart_circ_empty(xmit)) if (!uart_circ_empty(xmit))
tasklet_schedule(&atmel_port->tasklet); atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
} }
@ -966,7 +981,7 @@ static void atmel_complete_rx_dma(void *arg)
struct uart_port *port = arg; struct uart_port *port = arg;
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
tasklet_schedule(&atmel_port->tasklet); atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_rx);
} }
static void atmel_release_rx_dma(struct uart_port *port) static void atmel_release_rx_dma(struct uart_port *port)
@ -1006,7 +1021,7 @@ static void atmel_rx_from_dma(struct uart_port *port)
if (dmastat == DMA_ERROR) { if (dmastat == DMA_ERROR) {
dev_dbg(port->dev, "Get residue error, restart tasklet\n"); dev_dbg(port->dev, "Get residue error, restart tasklet\n");
atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT); atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT);
tasklet_schedule(&atmel_port->tasklet); atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_rx);
return; return;
} }
@ -1160,8 +1175,11 @@ static void atmel_uart_timer_callback(unsigned long data)
struct uart_port *port = (void *)data; struct uart_port *port = (void *)data;
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
tasklet_schedule(&atmel_port->tasklet); if (!atomic_read(&atmel_port->tasklet_shutdown)) {
mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port)); tasklet_schedule(&atmel_port->tasklet_rx);
mod_timer(&atmel_port->uart_timer,
jiffies + uart_poll_timeout(port));
}
} }
/* /*
@ -1183,7 +1201,8 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending)
if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) { if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) {
atmel_uart_writel(port, ATMEL_US_IDR, atmel_uart_writel(port, ATMEL_US_IDR,
(ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)); (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT));
tasklet_schedule(&atmel_port->tasklet); atmel_tasklet_schedule(atmel_port,
&atmel_port->tasklet_rx);
} }
if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE | if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE |
@ -1195,7 +1214,8 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending)
if (pending & ATMEL_US_TIMEOUT) { if (pending & ATMEL_US_TIMEOUT) {
atmel_uart_writel(port, ATMEL_US_IDR, atmel_uart_writel(port, ATMEL_US_IDR,
ATMEL_US_TIMEOUT); ATMEL_US_TIMEOUT);
tasklet_schedule(&atmel_port->tasklet); atmel_tasklet_schedule(atmel_port,
&atmel_port->tasklet_rx);
} }
} }
@ -1225,7 +1245,7 @@ atmel_handle_transmit(struct uart_port *port, unsigned int pending)
/* Either PDC or interrupt transmission */ /* Either PDC or interrupt transmission */
atmel_uart_writel(port, ATMEL_US_IDR, atmel_uart_writel(port, ATMEL_US_IDR,
atmel_port->tx_done_mask); atmel_port->tx_done_mask);
tasklet_schedule(&atmel_port->tasklet); atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
} }
} }
@ -1237,14 +1257,27 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
unsigned int status) unsigned int status)
{ {
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned int status_change;
if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC
| ATMEL_US_CTSIC)) { | ATMEL_US_CTSIC)) {
atmel_port->irq_status = status; status_change = status ^ atmel_port->irq_status_prev;
atmel_port->status_change = atmel_port->irq_status ^
atmel_port->irq_status_prev;
atmel_port->irq_status_prev = status; atmel_port->irq_status_prev = status;
tasklet_schedule(&atmel_port->tasklet);
if (status_change & (ATMEL_US_RI | ATMEL_US_DSR
| ATMEL_US_DCD | ATMEL_US_CTS)) {
/* TODO: All reads to CSR will clear these interrupts! */
if (status_change & ATMEL_US_RI)
port->icount.rng++;
if (status_change & ATMEL_US_DSR)
port->icount.dsr++;
if (status_change & ATMEL_US_DCD)
uart_handle_dcd_change(port, !(status & ATMEL_US_DCD));
if (status_change & ATMEL_US_CTS)
uart_handle_cts_change(port, !(status & ATMEL_US_CTS));
wake_up_interruptible(&port->state->port.delta_msr_wait);
}
} }
} }
@ -1571,37 +1604,25 @@ static int atmel_prepare_rx_pdc(struct uart_port *port)
/* /*
* tasklet handling tty stuff outside the interrupt handler. * tasklet handling tty stuff outside the interrupt handler.
*/ */
static void atmel_tasklet_func(unsigned long data) static void atmel_tasklet_rx_func(unsigned long data)
{ {
struct uart_port *port = (struct uart_port *)data; struct uart_port *port = (struct uart_port *)data;
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned int status = atmel_port->irq_status;
unsigned int status_change = atmel_port->status_change;
/* The interrupt handler does not take the lock */ /* The interrupt handler does not take the lock */
spin_lock(&port->lock); spin_lock(&port->lock);
atmel_port->schedule_tx(port);
if (status_change & (ATMEL_US_RI | ATMEL_US_DSR
| ATMEL_US_DCD | ATMEL_US_CTS)) {
/* TODO: All reads to CSR will clear these interrupts! */
if (status_change & ATMEL_US_RI)
port->icount.rng++;
if (status_change & ATMEL_US_DSR)
port->icount.dsr++;
if (status_change & ATMEL_US_DCD)
uart_handle_dcd_change(port, !(status & ATMEL_US_DCD));
if (status_change & ATMEL_US_CTS)
uart_handle_cts_change(port, !(status & ATMEL_US_CTS));
wake_up_interruptible(&port->state->port.delta_msr_wait);
atmel_port->status_change = 0;
}
atmel_port->schedule_rx(port); atmel_port->schedule_rx(port);
spin_unlock(&port->lock);
}
static void atmel_tasklet_tx_func(unsigned long data)
{
struct uart_port *port = (struct uart_port *)data;
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
/* The interrupt handler does not take the lock */
spin_lock(&port->lock);
atmel_port->schedule_tx(port);
spin_unlock(&port->lock); spin_unlock(&port->lock);
} }
@ -1785,7 +1806,11 @@ static int atmel_startup(struct uart_port *port)
return retval; return retval;
} }
tasklet_enable(&atmel_port->tasklet); atomic_set(&atmel_port->tasklet_shutdown, 0);
tasklet_init(&atmel_port->tasklet_rx, atmel_tasklet_rx_func,
(unsigned long)port);
tasklet_init(&atmel_port->tasklet_tx, atmel_tasklet_tx_func,
(unsigned long)port);
/* /*
* Initialize DMA (if necessary) * Initialize DMA (if necessary)
@ -1833,7 +1858,6 @@ static int atmel_startup(struct uart_port *port)
/* Save current CSR for comparison in atmel_tasklet_func() */ /* Save current CSR for comparison in atmel_tasklet_func() */
atmel_port->irq_status_prev = atmel_get_lines_status(port); atmel_port->irq_status_prev = atmel_get_lines_status(port);
atmel_port->irq_status = atmel_port->irq_status_prev;
/* /*
* Finally, enable the serial port * Finally, enable the serial port
@ -1905,29 +1929,36 @@ static void atmel_shutdown(struct uart_port *port)
{ {
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
/* Disable interrupts at device level */
atmel_uart_writel(port, ATMEL_US_IDR, -1);
/* Prevent spurious interrupts from scheduling the tasklet */
atomic_inc(&atmel_port->tasklet_shutdown);
/* /*
* Prevent any tasklets being scheduled during * Prevent any tasklets being scheduled during
* cleanup * cleanup
*/ */
del_timer_sync(&atmel_port->uart_timer); del_timer_sync(&atmel_port->uart_timer);
/* Make sure that no interrupt is on the fly */
synchronize_irq(port->irq);
/* /*
* Clear out any scheduled tasklets before * Clear out any scheduled tasklets before
* we destroy the buffers * we destroy the buffers
*/ */
tasklet_disable(&atmel_port->tasklet); tasklet_kill(&atmel_port->tasklet_rx);
tasklet_kill(&atmel_port->tasklet); tasklet_kill(&atmel_port->tasklet_tx);
/* /*
* Ensure everything is stopped and * Ensure everything is stopped and
* disable all interrupts, port and break condition. * disable port and break condition.
*/ */
atmel_stop_rx(port); atmel_stop_rx(port);
atmel_stop_tx(port); atmel_stop_tx(port);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA);
atmel_uart_writel(port, ATMEL_US_IDR, -1);
/* /*
* Shut-down the DMA. * Shut-down the DMA.
@ -2311,10 +2342,6 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
port->irq = pdev->resource[1].start; port->irq = pdev->resource[1].start;
port->rs485_config = atmel_config_rs485; port->rs485_config = atmel_config_rs485;
tasklet_init(&atmel_port->tasklet, atmel_tasklet_func,
(unsigned long)port);
tasklet_disable(&atmel_port->tasklet);
memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
if (pdata && pdata->regs) { if (pdata && pdata->regs) {
@ -2699,6 +2726,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
atmel_port->uart.line = ret; atmel_port->uart.line = ret;
atmel_serial_probe_fifos(atmel_port, pdev); atmel_serial_probe_fifos(atmel_port, pdev);
atomic_set(&atmel_port->tasklet_shutdown, 0);
spin_lock_init(&atmel_port->lock_suspended); spin_lock_init(&atmel_port->lock_suspended);
ret = atmel_init_port(atmel_port, pdev); ret = atmel_init_port(atmel_port, pdev);
@ -2795,7 +2823,8 @@ static int atmel_serial_remove(struct platform_device *pdev)
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
int ret = 0; int ret = 0;
tasklet_kill(&atmel_port->tasklet); tasklet_kill(&atmel_port->tasklet_rx);
tasklet_kill(&atmel_port->tasklet_tx);
device_init_wakeup(&pdev->dev, 0); device_init_wakeup(&pdev->dev, 0);

View file

@ -813,8 +813,12 @@ static int bcm_uart_probe(struct platform_device *pdev)
struct clk *clk; struct clk *clk;
int ret; int ret;
if (pdev->dev.of_node) if (pdev->dev.of_node) {
pdev->id = of_alias_get_id(pdev->dev.of_node, "uart"); pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
if (pdev->id < 0)
pdev->id = of_alias_get_id(pdev->dev.of_node, "uart");
}
if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS) if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS)
return -EINVAL; return -EINVAL;

View file

@ -1830,7 +1830,13 @@ static int lpuart_probe(struct platform_device *pdev)
sport->port.dev = &pdev->dev; sport->port.dev = &pdev->dev;
sport->port.type = PORT_LPUART; sport->port.type = PORT_LPUART;
sport->port.iotype = UPIO_MEM; sport->port.iotype = UPIO_MEM;
sport->port.irq = platform_get_irq(pdev, 0); ret = platform_get_irq(pdev, 0);
if (ret < 0) {
dev_err(&pdev->dev, "cannot obtain irq\n");
return ret;
}
sport->port.irq = ret;
if (sport->lpuart32) if (sport->lpuart32)
sport->port.ops = &lpuart32_pops; sport->port.ops = &lpuart32_pops;
else else

View file

@ -30,7 +30,6 @@
#define SUPPORT_SYSRQ #define SUPPORT_SYSRQ
#endif #endif
#include <linux/module.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/tty_flip.h> #include <linux/tty_flip.h>
#include <linux/ioport.h> #include <linux/ioport.h>
@ -51,9 +50,6 @@
#define PASS_LIMIT 256 #define PASS_LIMIT 256
/* Standard COM flags */
#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
static const struct { static const struct {
unsigned int port; unsigned int port;
unsigned int irq; unsigned int irq;
@ -892,7 +888,7 @@ static void __init m32r_sio_init_ports(void)
up->port.iobase = old_serial_port[i].port; up->port.iobase = old_serial_port[i].port;
up->port.irq = irq_canonicalize(old_serial_port[i].irq); up->port.irq = irq_canonicalize(old_serial_port[i].irq);
up->port.uartclk = BAUD_RATE * 16; up->port.uartclk = BAUD_RATE * 16;
up->port.flags = STD_COM_FLAGS; up->port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
up->port.membase = 0; up->port.membase = 0;
up->port.iotype = 0; up->port.iotype = 0;
up->port.regshift = 0; up->port.regshift = 0;
@ -1060,19 +1056,4 @@ static int __init m32r_sio_init(void)
return ret; return ret;
} }
device_initcall(m32r_sio_init);
static void __exit m32r_sio_exit(void)
{
int i;
for (i = 0; i < UART_NR; i++)
uart_remove_one_port(&m32r_sio_reg, &m32r_sio_ports[i].port);
uart_unregister_driver(&m32r_sio_reg);
}
module_init(m32r_sio_init);
module_exit(m32r_sio_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic M32R SIO serial driver");

View file

@ -1,7 +1,7 @@
/* /*
* Maxim (Dallas) MAX3107/8/9, MAX14830 serial driver * Maxim (Dallas) MAX3107/8/9, MAX14830 serial driver
* *
* Copyright (C) 2012-2014 Alexander Shiyan <shc_work@mail.ru> * Copyright (C) 2012-2016 Alexander Shiyan <shc_work@mail.ru>
* *
* Based on max3100.c, by Christian Pellegrin <chripell@evolware.org> * Based on max3100.c, by Christian Pellegrin <chripell@evolware.org>
* Based on max3110.c, by Feng Tang <feng.tang@intel.com> * Based on max3110.c, by Feng Tang <feng.tang@intel.com>
@ -32,6 +32,7 @@
#define MAX310X_NAME "max310x" #define MAX310X_NAME "max310x"
#define MAX310X_MAJOR 204 #define MAX310X_MAJOR 204
#define MAX310X_MINOR 209 #define MAX310X_MINOR 209
#define MAX310X_UART_NRMAX 16
/* MAX310X register definitions */ /* MAX310X register definitions */
#define MAX310X_RHR_REG (0x00) /* RX FIFO */ #define MAX310X_RHR_REG (0x00) /* RX FIFO */
@ -155,10 +156,6 @@
#define MAX310X_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */ #define MAX310X_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */
#define MAX310X_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */ #define MAX310X_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */
#define MAX310X_LCR_RTS_BIT (1 << 7) /* RTS pin control */ #define MAX310X_LCR_RTS_BIT (1 << 7) /* RTS pin control */
#define MAX310X_LCR_WORD_LEN_5 (0x00)
#define MAX310X_LCR_WORD_LEN_6 (0x01)
#define MAX310X_LCR_WORD_LEN_7 (0x02)
#define MAX310X_LCR_WORD_LEN_8 (0x03)
/* IRDA register bits */ /* IRDA register bits */
#define MAX310X_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */ #define MAX310X_IRDA_IRDAEN_BIT (1 << 0) /* IRDA mode enable */
@ -262,10 +259,10 @@ struct max310x_one {
struct uart_port port; struct uart_port port;
struct work_struct tx_work; struct work_struct tx_work;
struct work_struct md_work; struct work_struct md_work;
struct work_struct rs_work;
}; };
struct max310x_port { struct max310x_port {
struct uart_driver uart;
struct max310x_devtype *devtype; struct max310x_devtype *devtype;
struct regmap *regmap; struct regmap *regmap;
struct mutex mutex; struct mutex mutex;
@ -276,6 +273,17 @@ struct max310x_port {
struct max310x_one p[0]; struct max310x_one p[0];
}; };
static struct uart_driver max310x_uart = {
.owner = THIS_MODULE,
.driver_name = MAX310X_NAME,
.dev_name = "ttyMAX",
.major = MAX310X_MAJOR,
.minor = MAX310X_MINOR,
.nr = MAX310X_UART_NRMAX,
};
static DECLARE_BITMAP(max310x_lines, MAX310X_UART_NRMAX);
static u8 max310x_port_read(struct uart_port *port, u8 reg) static u8 max310x_port_read(struct uart_port *port, u8 reg)
{ {
struct max310x_port *s = dev_get_drvdata(port->dev); struct max310x_port *s = dev_get_drvdata(port->dev);
@ -594,9 +602,7 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
unsigned int sts, ch, flag; unsigned int sts, ch, flag;
if (unlikely(rxlen >= port->fifosize)) { if (unlikely(rxlen >= port->fifosize)) {
dev_warn_ratelimited(port->dev, dev_warn_ratelimited(port->dev, "Possible RX FIFO overrun\n");
"Port %i: Possible RX FIFO overrun\n",
port->line);
port->icount.buf_overrun++; port->icount.buf_overrun++;
/* Ensure sanity of RX level */ /* Ensure sanity of RX level */
rxlen = port->fifosize; rxlen = port->fifosize;
@ -715,13 +721,13 @@ static irqreturn_t max310x_ist(int irq, void *dev_id)
{ {
struct max310x_port *s = (struct max310x_port *)dev_id; struct max310x_port *s = (struct max310x_port *)dev_id;
if (s->uart.nr > 1) { if (s->devtype->nr > 1) {
do { do {
unsigned int val = ~0; unsigned int val = ~0;
WARN_ON_ONCE(regmap_read(s->regmap, WARN_ON_ONCE(regmap_read(s->regmap,
MAX310X_GLOBALIRQ_REG, &val)); MAX310X_GLOBALIRQ_REG, &val));
val = ((1 << s->uart.nr) - 1) & ~val; val = ((1 << s->devtype->nr) - 1) & ~val;
if (!val) if (!val)
break; break;
max310x_port_irq(s, fls(val) - 1); max310x_port_irq(s, fls(val) - 1);
@ -796,7 +802,7 @@ static void max310x_set_termios(struct uart_port *port,
struct ktermios *termios, struct ktermios *termios,
struct ktermios *old) struct ktermios *old)
{ {
unsigned int lcr, flow = 0; unsigned int lcr = 0, flow = 0;
int baud; int baud;
/* Mask termios capabilities we don't support */ /* Mask termios capabilities we don't support */
@ -805,17 +811,16 @@ static void max310x_set_termios(struct uart_port *port,
/* Word size */ /* Word size */
switch (termios->c_cflag & CSIZE) { switch (termios->c_cflag & CSIZE) {
case CS5: case CS5:
lcr = MAX310X_LCR_WORD_LEN_5;
break; break;
case CS6: case CS6:
lcr = MAX310X_LCR_WORD_LEN_6; lcr = MAX310X_LCR_LENGTH0_BIT;
break; break;
case CS7: case CS7:
lcr = MAX310X_LCR_WORD_LEN_7; lcr = MAX310X_LCR_LENGTH1_BIT;
break; break;
case CS8: case CS8:
default: default:
lcr = MAX310X_LCR_WORD_LEN_8; lcr = MAX310X_LCR_LENGTH1_BIT | MAX310X_LCR_LENGTH0_BIT;
break; break;
} }
@ -877,36 +882,45 @@ static void max310x_set_termios(struct uart_port *port,
uart_update_timeout(port, termios->c_cflag, baud); uart_update_timeout(port, termios->c_cflag, baud);
} }
static int max310x_rs485_config(struct uart_port *port, static void max310x_rs_proc(struct work_struct *ws)
struct serial_rs485 *rs485)
{ {
struct max310x_one *one = container_of(ws, struct max310x_one, rs_work);
unsigned int val; unsigned int val;
if (rs485->delay_rts_before_send > 0x0f || val = (one->port.rs485.delay_rts_before_send << 4) |
rs485->delay_rts_after_send > 0x0f) one->port.rs485.delay_rts_after_send;
return -ERANGE; max310x_port_write(&one->port, MAX310X_HDPIXDELAY_REG, val);
val = (rs485->delay_rts_before_send << 4) | if (one->port.rs485.flags & SER_RS485_ENABLED) {
rs485->delay_rts_after_send; max310x_port_update(&one->port, MAX310X_MODE1_REG,
max310x_port_write(port, MAX310X_HDPIXDELAY_REG, val);
if (rs485->flags & SER_RS485_ENABLED) {
max310x_port_update(port, MAX310X_MODE1_REG,
MAX310X_MODE1_TRNSCVCTRL_BIT, MAX310X_MODE1_TRNSCVCTRL_BIT,
MAX310X_MODE1_TRNSCVCTRL_BIT); MAX310X_MODE1_TRNSCVCTRL_BIT);
max310x_port_update(port, MAX310X_MODE2_REG, max310x_port_update(&one->port, MAX310X_MODE2_REG,
MAX310X_MODE2_ECHOSUPR_BIT, MAX310X_MODE2_ECHOSUPR_BIT,
MAX310X_MODE2_ECHOSUPR_BIT); MAX310X_MODE2_ECHOSUPR_BIT);
} else { } else {
max310x_port_update(port, MAX310X_MODE1_REG, max310x_port_update(&one->port, MAX310X_MODE1_REG,
MAX310X_MODE1_TRNSCVCTRL_BIT, 0); MAX310X_MODE1_TRNSCVCTRL_BIT, 0);
max310x_port_update(port, MAX310X_MODE2_REG, max310x_port_update(&one->port, MAX310X_MODE2_REG,
MAX310X_MODE2_ECHOSUPR_BIT, 0); MAX310X_MODE2_ECHOSUPR_BIT, 0);
} }
}
static int max310x_rs485_config(struct uart_port *port,
struct serial_rs485 *rs485)
{
struct max310x_one *one = container_of(port, struct max310x_one, port);
if ((rs485->delay_rts_before_send > 0x0f) ||
(rs485->delay_rts_after_send > 0x0f))
return -ERANGE;
rs485->flags &= SER_RS485_RTS_ON_SEND | SER_RS485_ENABLED; rs485->flags &= SER_RS485_RTS_ON_SEND | SER_RS485_ENABLED;
memset(rs485->padding, 0, sizeof(rs485->padding)); memset(rs485->padding, 0, sizeof(rs485->padding));
port->rs485 = *rs485; port->rs485 = *rs485;
schedule_work(&one->rs_work);
return 0; return 0;
} }
@ -1009,8 +1023,8 @@ static int __maybe_unused max310x_suspend(struct device *dev)
struct max310x_port *s = dev_get_drvdata(dev); struct max310x_port *s = dev_get_drvdata(dev);
int i; int i;
for (i = 0; i < s->uart.nr; i++) { for (i = 0; i < s->devtype->nr; i++) {
uart_suspend_port(&s->uart, &s->p[i].port); uart_suspend_port(&max310x_uart, &s->p[i].port);
s->devtype->power(&s->p[i].port, 0); s->devtype->power(&s->p[i].port, 0);
} }
@ -1022,9 +1036,9 @@ static int __maybe_unused max310x_resume(struct device *dev)
struct max310x_port *s = dev_get_drvdata(dev); struct max310x_port *s = dev_get_drvdata(dev);
int i; int i;
for (i = 0; i < s->uart.nr; i++) { for (i = 0; i < s->devtype->nr; i++) {
s->devtype->power(&s->p[i].port, 1); s->devtype->power(&s->p[i].port, 1);
uart_resume_port(&s->uart, &s->p[i].port); uart_resume_port(&max310x_uart, &s->p[i].port);
} }
return 0; return 0;
@ -1159,18 +1173,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
uartclk = max310x_set_ref_clk(s, freq, xtal); uartclk = max310x_set_ref_clk(s, freq, xtal);
dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk); dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk);
/* Register UART driver */
s->uart.owner = THIS_MODULE;
s->uart.dev_name = "ttyMAX";
s->uart.major = MAX310X_MAJOR;
s->uart.minor = MAX310X_MINOR;
s->uart.nr = devtype->nr;
ret = uart_register_driver(&s->uart);
if (ret) {
dev_err(dev, "Registering UART driver failed\n");
goto out_clk;
}
#ifdef CONFIG_GPIOLIB #ifdef CONFIG_GPIOLIB
/* Setup GPIO cotroller */ /* Setup GPIO cotroller */
s->gpio.owner = THIS_MODULE; s->gpio.owner = THIS_MODULE;
@ -1183,16 +1185,24 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
s->gpio.base = -1; s->gpio.base = -1;
s->gpio.ngpio = devtype->nr * 4; s->gpio.ngpio = devtype->nr * 4;
s->gpio.can_sleep = 1; s->gpio.can_sleep = 1;
ret = gpiochip_add_data(&s->gpio, s); ret = devm_gpiochip_add_data(dev, &s->gpio, s);
if (ret) if (ret)
goto out_uart; goto out_clk;
#endif #endif
mutex_init(&s->mutex); mutex_init(&s->mutex);
for (i = 0; i < devtype->nr; i++) { for (i = 0; i < devtype->nr; i++) {
unsigned int line;
line = find_first_zero_bit(max310x_lines, MAX310X_UART_NRMAX);
if (line == MAX310X_UART_NRMAX) {
ret = -ERANGE;
goto out_uart;
}
/* Initialize port data */ /* Initialize port data */
s->p[i].port.line = i; s->p[i].port.line = line;
s->p[i].port.dev = dev; s->p[i].port.dev = dev;
s->p[i].port.irq = irq; s->p[i].port.irq = irq;
s->p[i].port.type = PORT_MAX310X; s->p[i].port.type = PORT_MAX310X;
@ -1214,10 +1224,19 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
MAX310X_MODE1_IRQSEL_BIT); MAX310X_MODE1_IRQSEL_BIT);
/* Initialize queue for start TX */ /* Initialize queue for start TX */
INIT_WORK(&s->p[i].tx_work, max310x_wq_proc); INIT_WORK(&s->p[i].tx_work, max310x_wq_proc);
/* Initialize queue for changing mode */ /* Initialize queue for changing LOOPBACK mode */
INIT_WORK(&s->p[i].md_work, max310x_md_proc); INIT_WORK(&s->p[i].md_work, max310x_md_proc);
/* Initialize queue for changing RS485 mode */
INIT_WORK(&s->p[i].rs_work, max310x_rs_proc);
/* Register port */ /* Register port */
uart_add_one_port(&s->uart, &s->p[i].port); ret = uart_add_one_port(&max310x_uart, &s->p[i].port);
if (ret) {
s->p[i].port.dev = NULL;
goto out_uart;
}
set_bit(line, max310x_lines);
/* Go to suspend mode */ /* Go to suspend mode */
devtype->power(&s->p[i].port, 0); devtype->power(&s->p[i].port, 0);
} }
@ -1230,14 +1249,15 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
dev_err(dev, "Unable to reguest IRQ %i\n", irq); dev_err(dev, "Unable to reguest IRQ %i\n", irq);
mutex_destroy(&s->mutex);
#ifdef CONFIG_GPIOLIB
gpiochip_remove(&s->gpio);
out_uart: out_uart:
#endif for (i = 0; i < devtype->nr; i++) {
uart_unregister_driver(&s->uart); if (s->p[i].port.dev) {
uart_remove_one_port(&max310x_uart, &s->p[i].port);
clear_bit(s->p[i].port.line, max310x_lines);
}
}
mutex_destroy(&s->mutex);
out_clk: out_clk:
clk_disable_unprepare(s->clk); clk_disable_unprepare(s->clk);
@ -1250,19 +1270,16 @@ static int max310x_remove(struct device *dev)
struct max310x_port *s = dev_get_drvdata(dev); struct max310x_port *s = dev_get_drvdata(dev);
int i; int i;
#ifdef CONFIG_GPIOLIB for (i = 0; i < s->devtype->nr; i++) {
gpiochip_remove(&s->gpio);
#endif
for (i = 0; i < s->uart.nr; i++) {
cancel_work_sync(&s->p[i].tx_work); cancel_work_sync(&s->p[i].tx_work);
cancel_work_sync(&s->p[i].md_work); cancel_work_sync(&s->p[i].md_work);
uart_remove_one_port(&s->uart, &s->p[i].port); cancel_work_sync(&s->p[i].rs_work);
uart_remove_one_port(&max310x_uart, &s->p[i].port);
clear_bit(s->p[i].port.line, max310x_lines);
s->devtype->power(&s->p[i].port, 0); s->devtype->power(&s->p[i].port, 0);
} }
mutex_destroy(&s->mutex); mutex_destroy(&s->mutex);
uart_unregister_driver(&s->uart);
clk_disable_unprepare(s->clk); clk_disable_unprepare(s->clk);
return 0; return 0;
@ -1335,7 +1352,7 @@ static const struct spi_device_id max310x_id_table[] = {
}; };
MODULE_DEVICE_TABLE(spi, max310x_id_table); MODULE_DEVICE_TABLE(spi, max310x_id_table);
static struct spi_driver max310x_uart_driver = { static struct spi_driver max310x_spi_driver = {
.driver = { .driver = {
.name = MAX310X_NAME, .name = MAX310X_NAME,
.of_match_table = of_match_ptr(max310x_dt_ids), .of_match_table = of_match_ptr(max310x_dt_ids),
@ -1345,9 +1362,36 @@ static struct spi_driver max310x_uart_driver = {
.remove = max310x_spi_remove, .remove = max310x_spi_remove,
.id_table = max310x_id_table, .id_table = max310x_id_table,
}; };
module_spi_driver(max310x_uart_driver);
#endif #endif
static int __init max310x_uart_init(void)
{
int ret;
bitmap_zero(max310x_lines, MAX310X_UART_NRMAX);
ret = uart_register_driver(&max310x_uart);
if (ret)
return ret;
#ifdef CONFIG_SPI_MASTER
spi_register_driver(&max310x_spi_driver);
#endif
return 0;
}
module_init(max310x_uart_init);
static void __exit max310x_uart_exit(void)
{
#ifdef CONFIG_SPI_MASTER
spi_unregister_driver(&max310x_spi_driver);
#endif
uart_unregister_driver(&max310x_uart);
}
module_exit(max310x_uart_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
MODULE_DESCRIPTION("MAX310X serial driver"); MODULE_DESCRIPTION("MAX310X serial driver");

View file

@ -1,4 +1,6 @@
/* /*
* MPS2 UART driver
*
* Copyright (C) 2015 ARM Limited * Copyright (C) 2015 ARM Limited
* *
* Author: Vladimir Murzin <vladimir.murzin@arm.com> * Author: Vladimir Murzin <vladimir.murzin@arm.com>
@ -17,7 +19,6 @@
#include <linux/console.h> #include <linux/console.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
@ -569,30 +570,20 @@ static int mps2_serial_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int mps2_serial_remove(struct platform_device *pdev)
{
struct mps2_uart_port *mps_port = platform_get_drvdata(pdev);
uart_remove_one_port(&mps2_uart_driver, &mps_port->port);
return 0;
}
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id mps2_match[] = { static const struct of_device_id mps2_match[] = {
{ .compatible = "arm,mps2-uart", }, { .compatible = "arm,mps2-uart", },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, mps2_match);
#endif #endif
static struct platform_driver mps2_serial_driver = { static struct platform_driver mps2_serial_driver = {
.probe = mps2_serial_probe, .probe = mps2_serial_probe,
.remove = mps2_serial_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.of_match_table = of_match_ptr(mps2_match), .of_match_table = of_match_ptr(mps2_match),
.suppress_bind_attrs = true,
}, },
}; };
@ -610,16 +601,4 @@ static int __init mps2_uart_init(void)
return ret; return ret;
} }
module_init(mps2_uart_init); arch_initcall(mps2_uart_init);
static void __exit mps2_uart_exit(void)
{
platform_driver_unregister(&mps2_serial_driver);
uart_unregister_driver(&mps2_uart_driver);
}
module_exit(mps2_uart_exit);
MODULE_AUTHOR("Vladimir Murzin <vladimir.murzin@arm.com>");
MODULE_DESCRIPTION("MPS2 UART driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRIVER_NAME);

View file

@ -19,33 +19,147 @@
# define SUPPORT_SYSRQ # define SUPPORT_SYSRQ
#endif #endif
#include <linux/kernel.h>
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/hrtimer.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/irq.h> #include <linux/interrupt.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/tty_flip.h> #include <linux/tty_flip.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/wait.h>
#include "msm_serial.h" #define UART_MR1 0x0000
#define UARTDM_BURST_SIZE 16 /* in bytes */ #define UART_MR1_AUTO_RFR_LEVEL0 0x3F
#define UARTDM_TX_AIGN(x) ((x) & ~0x3) /* valid for > 1p3 */ #define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00
#define UARTDM_TX_MAX 256 /* in bytes, valid for <= 1p3 */ #define UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00
#define UARTDM_RX_SIZE (UART_XMIT_SIZE / 4) #define UART_MR1_RX_RDY_CTL BIT(7)
#define UART_MR1_CTS_CTL BIT(6)
#define UART_MR2 0x0004
#define UART_MR2_ERROR_MODE BIT(6)
#define UART_MR2_BITS_PER_CHAR 0x30
#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4)
#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4)
#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4)
#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4)
#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2)
#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2)
#define UART_MR2_PARITY_MODE_NONE 0x0
#define UART_MR2_PARITY_MODE_ODD 0x1
#define UART_MR2_PARITY_MODE_EVEN 0x2
#define UART_MR2_PARITY_MODE_SPACE 0x3
#define UART_MR2_PARITY_MODE 0x3
#define UART_CSR 0x0008
#define UART_TF 0x000C
#define UARTDM_TF 0x0070
#define UART_CR 0x0010
#define UART_CR_CMD_NULL (0 << 4)
#define UART_CR_CMD_RESET_RX (1 << 4)
#define UART_CR_CMD_RESET_TX (2 << 4)
#define UART_CR_CMD_RESET_ERR (3 << 4)
#define UART_CR_CMD_RESET_BREAK_INT (4 << 4)
#define UART_CR_CMD_START_BREAK (5 << 4)
#define UART_CR_CMD_STOP_BREAK (6 << 4)
#define UART_CR_CMD_RESET_CTS (7 << 4)
#define UART_CR_CMD_RESET_STALE_INT (8 << 4)
#define UART_CR_CMD_PACKET_MODE (9 << 4)
#define UART_CR_CMD_MODE_RESET (12 << 4)
#define UART_CR_CMD_SET_RFR (13 << 4)
#define UART_CR_CMD_RESET_RFR (14 << 4)
#define UART_CR_CMD_PROTECTION_EN (16 << 4)
#define UART_CR_CMD_STALE_EVENT_DISABLE (6 << 8)
#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4)
#define UART_CR_CMD_FORCE_STALE (4 << 8)
#define UART_CR_CMD_RESET_TX_READY (3 << 8)
#define UART_CR_TX_DISABLE BIT(3)
#define UART_CR_TX_ENABLE BIT(2)
#define UART_CR_RX_DISABLE BIT(1)
#define UART_CR_RX_ENABLE BIT(0)
#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4))
#define UART_IMR 0x0014
#define UART_IMR_TXLEV BIT(0)
#define UART_IMR_RXSTALE BIT(3)
#define UART_IMR_RXLEV BIT(4)
#define UART_IMR_DELTA_CTS BIT(5)
#define UART_IMR_CURRENT_CTS BIT(6)
#define UART_IMR_RXBREAK_START BIT(10)
#define UART_IPR_RXSTALE_LAST 0x20
#define UART_IPR_STALE_LSB 0x1F
#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80
#define UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80
#define UART_IPR 0x0018
#define UART_TFWR 0x001C
#define UART_RFWR 0x0020
#define UART_HCR 0x0024
#define UART_MREG 0x0028
#define UART_NREG 0x002C
#define UART_DREG 0x0030
#define UART_MNDREG 0x0034
#define UART_IRDA 0x0038
#define UART_MISR_MODE 0x0040
#define UART_MISR_RESET 0x0044
#define UART_MISR_EXPORT 0x0048
#define UART_MISR_VAL 0x004C
#define UART_TEST_CTRL 0x0050
#define UART_SR 0x0008
#define UART_SR_HUNT_CHAR BIT(7)
#define UART_SR_RX_BREAK BIT(6)
#define UART_SR_PAR_FRAME_ERR BIT(5)
#define UART_SR_OVERRUN BIT(4)
#define UART_SR_TX_EMPTY BIT(3)
#define UART_SR_TX_READY BIT(2)
#define UART_SR_RX_FULL BIT(1)
#define UART_SR_RX_READY BIT(0)
#define UART_RF 0x000C
#define UARTDM_RF 0x0070
#define UART_MISR 0x0010
#define UART_ISR 0x0014
#define UART_ISR_TX_READY BIT(7)
#define UARTDM_RXFS 0x50
#define UARTDM_RXFS_BUF_SHIFT 0x7
#define UARTDM_RXFS_BUF_MASK 0x7
#define UARTDM_DMEN 0x3C
#define UARTDM_DMEN_RX_SC_ENABLE BIT(5)
#define UARTDM_DMEN_TX_SC_ENABLE BIT(4)
#define UARTDM_DMEN_TX_BAM_ENABLE BIT(2) /* UARTDM_1P4 */
#define UARTDM_DMEN_TX_DM_ENABLE BIT(0) /* < UARTDM_1P4 */
#define UARTDM_DMEN_RX_BAM_ENABLE BIT(3) /* UARTDM_1P4 */
#define UARTDM_DMEN_RX_DM_ENABLE BIT(1) /* < UARTDM_1P4 */
#define UARTDM_DMRX 0x34
#define UARTDM_NCF_TX 0x40
#define UARTDM_RX_TOTAL_SNAP 0x38
#define UARTDM_BURST_SIZE 16 /* in bytes */
#define UARTDM_TX_AIGN(x) ((x) & ~0x3) /* valid for > 1p3 */
#define UARTDM_TX_MAX 256 /* in bytes, valid for <= 1p3 */
#define UARTDM_RX_SIZE (UART_XMIT_SIZE / 4)
enum { enum {
UARTDM_1P1 = 1, UARTDM_1P1 = 1,
@ -78,10 +192,65 @@ struct msm_port {
struct msm_dma rx_dma; struct msm_dma rx_dma;
}; };
#define UART_TO_MSM(uart_port) container_of(uart_port, struct msm_port, uart)
static
void msm_write(struct uart_port *port, unsigned int val, unsigned int off)
{
writel_relaxed(val, port->membase + off);
}
static
unsigned int msm_read(struct uart_port *port, unsigned int off)
{
return readl_relaxed(port->membase + off);
}
/*
* Setup the MND registers to use the TCXO clock.
*/
static void msm_serial_set_mnd_regs_tcxo(struct uart_port *port)
{
msm_write(port, 0x06, UART_MREG);
msm_write(port, 0xF1, UART_NREG);
msm_write(port, 0x0F, UART_DREG);
msm_write(port, 0x1A, UART_MNDREG);
port->uartclk = 1843200;
}
/*
* Setup the MND registers to use the TCXO clock divided by 4.
*/
static void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port)
{
msm_write(port, 0x18, UART_MREG);
msm_write(port, 0xF6, UART_NREG);
msm_write(port, 0x0F, UART_DREG);
msm_write(port, 0x0A, UART_MNDREG);
port->uartclk = 1843200;
}
static void msm_serial_set_mnd_regs(struct uart_port *port)
{
struct msm_port *msm_port = UART_TO_MSM(port);
/*
* These registers don't exist so we change the clk input rate
* on uartdm hardware instead
*/
if (msm_port->is_uartdm)
return;
if (port->uartclk == 19200000)
msm_serial_set_mnd_regs_tcxo(port);
else if (port->uartclk == 4800000)
msm_serial_set_mnd_regs_tcxoby4(port);
}
static void msm_handle_tx(struct uart_port *port); static void msm_handle_tx(struct uart_port *port);
static void msm_start_rx_dma(struct msm_port *msm_port); static void msm_start_rx_dma(struct msm_port *msm_port);
void msm_stop_dma(struct uart_port *port, struct msm_dma *dma) static void msm_stop_dma(struct uart_port *port, struct msm_dma *dma)
{ {
struct device *dev = port->dev; struct device *dev = port->dev;
unsigned int mapped; unsigned int mapped;
@ -388,10 +557,6 @@ static void msm_complete_rx_dma(void *args)
val &= ~dma->enable_bit; val &= ~dma->enable_bit;
msm_write(port, val, UARTDM_DMEN); msm_write(port, val, UARTDM_DMEN);
/* Restore interrupts */
msm_port->imr |= UART_IMR_RXLEV | UART_IMR_RXSTALE;
msm_write(port, msm_port->imr, UART_IMR);
if (msm_read(port, UART_SR) & UART_SR_OVERRUN) { if (msm_read(port, UART_SR) & UART_SR_OVERRUN) {
port->icount.overrun++; port->icount.overrun++;
tty_insert_flip_char(tport, 0, TTY_OVERRUN); tty_insert_flip_char(tport, 0, TTY_OVERRUN);
@ -726,7 +891,7 @@ static void msm_handle_tx(struct uart_port *port)
return; return;
} }
pio_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE); pio_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
dma_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); dma_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
dma_min = 1; /* Always DMA */ dma_min = 1; /* Always DMA */

View file

@ -1,184 +0,0 @@
/*
* Copyright (C) 2007 Google, Inc.
* Author: Robert Love <rlove@google.com>
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __DRIVERS_SERIAL_MSM_SERIAL_H
#define __DRIVERS_SERIAL_MSM_SERIAL_H
#define UART_MR1 0x0000
#define UART_MR1_AUTO_RFR_LEVEL0 0x3F
#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00
#define UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00
#define UART_MR1_RX_RDY_CTL BIT(7)
#define UART_MR1_CTS_CTL BIT(6)
#define UART_MR2 0x0004
#define UART_MR2_ERROR_MODE BIT(6)
#define UART_MR2_BITS_PER_CHAR 0x30
#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4)
#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4)
#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4)
#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4)
#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2)
#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2)
#define UART_MR2_PARITY_MODE_NONE 0x0
#define UART_MR2_PARITY_MODE_ODD 0x1
#define UART_MR2_PARITY_MODE_EVEN 0x2
#define UART_MR2_PARITY_MODE_SPACE 0x3
#define UART_MR2_PARITY_MODE 0x3
#define UART_CSR 0x0008
#define UART_TF 0x000C
#define UARTDM_TF 0x0070
#define UART_CR 0x0010
#define UART_CR_CMD_NULL (0 << 4)
#define UART_CR_CMD_RESET_RX (1 << 4)
#define UART_CR_CMD_RESET_TX (2 << 4)
#define UART_CR_CMD_RESET_ERR (3 << 4)
#define UART_CR_CMD_RESET_BREAK_INT (4 << 4)
#define UART_CR_CMD_START_BREAK (5 << 4)
#define UART_CR_CMD_STOP_BREAK (6 << 4)
#define UART_CR_CMD_RESET_CTS (7 << 4)
#define UART_CR_CMD_RESET_STALE_INT (8 << 4)
#define UART_CR_CMD_PACKET_MODE (9 << 4)
#define UART_CR_CMD_MODE_RESET (12 << 4)
#define UART_CR_CMD_SET_RFR (13 << 4)
#define UART_CR_CMD_RESET_RFR (14 << 4)
#define UART_CR_CMD_PROTECTION_EN (16 << 4)
#define UART_CR_CMD_STALE_EVENT_DISABLE (6 << 8)
#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4)
#define UART_CR_CMD_FORCE_STALE (4 << 8)
#define UART_CR_CMD_RESET_TX_READY (3 << 8)
#define UART_CR_TX_DISABLE BIT(3)
#define UART_CR_TX_ENABLE BIT(2)
#define UART_CR_RX_DISABLE BIT(1)
#define UART_CR_RX_ENABLE BIT(0)
#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4))
#define UART_IMR 0x0014
#define UART_IMR_TXLEV BIT(0)
#define UART_IMR_RXSTALE BIT(3)
#define UART_IMR_RXLEV BIT(4)
#define UART_IMR_DELTA_CTS BIT(5)
#define UART_IMR_CURRENT_CTS BIT(6)
#define UART_IMR_RXBREAK_START BIT(10)
#define UART_IPR_RXSTALE_LAST 0x20
#define UART_IPR_STALE_LSB 0x1F
#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80
#define UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80
#define UART_IPR 0x0018
#define UART_TFWR 0x001C
#define UART_RFWR 0x0020
#define UART_HCR 0x0024
#define UART_MREG 0x0028
#define UART_NREG 0x002C
#define UART_DREG 0x0030
#define UART_MNDREG 0x0034
#define UART_IRDA 0x0038
#define UART_MISR_MODE 0x0040
#define UART_MISR_RESET 0x0044
#define UART_MISR_EXPORT 0x0048
#define UART_MISR_VAL 0x004C
#define UART_TEST_CTRL 0x0050
#define UART_SR 0x0008
#define UART_SR_HUNT_CHAR BIT(7)
#define UART_SR_RX_BREAK BIT(6)
#define UART_SR_PAR_FRAME_ERR BIT(5)
#define UART_SR_OVERRUN BIT(4)
#define UART_SR_TX_EMPTY BIT(3)
#define UART_SR_TX_READY BIT(2)
#define UART_SR_RX_FULL BIT(1)
#define UART_SR_RX_READY BIT(0)
#define UART_RF 0x000C
#define UARTDM_RF 0x0070
#define UART_MISR 0x0010
#define UART_ISR 0x0014
#define UART_ISR_TX_READY BIT(7)
#define UARTDM_RXFS 0x50
#define UARTDM_RXFS_BUF_SHIFT 0x7
#define UARTDM_RXFS_BUF_MASK 0x7
#define UARTDM_DMEN 0x3C
#define UARTDM_DMEN_RX_SC_ENABLE BIT(5)
#define UARTDM_DMEN_TX_SC_ENABLE BIT(4)
#define UARTDM_DMEN_TX_BAM_ENABLE BIT(2) /* UARTDM_1P4 */
#define UARTDM_DMEN_TX_DM_ENABLE BIT(0) /* < UARTDM_1P4 */
#define UARTDM_DMEN_RX_BAM_ENABLE BIT(3) /* UARTDM_1P4 */
#define UARTDM_DMEN_RX_DM_ENABLE BIT(1) /* < UARTDM_1P4 */
#define UARTDM_DMRX 0x34
#define UARTDM_NCF_TX 0x40
#define UARTDM_RX_TOTAL_SNAP 0x38
#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port)
static inline
void msm_write(struct uart_port *port, unsigned int val, unsigned int off)
{
writel_relaxed(val, port->membase + off);
}
static inline
unsigned int msm_read(struct uart_port *port, unsigned int off)
{
return readl_relaxed(port->membase + off);
}
/*
* Setup the MND registers to use the TCXO clock.
*/
static inline void msm_serial_set_mnd_regs_tcxo(struct uart_port *port)
{
msm_write(port, 0x06, UART_MREG);
msm_write(port, 0xF1, UART_NREG);
msm_write(port, 0x0F, UART_DREG);
msm_write(port, 0x1A, UART_MNDREG);
port->uartclk = 1843200;
}
/*
* Setup the MND registers to use the TCXO clock divided by 4.
*/
static inline void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port)
{
msm_write(port, 0x18, UART_MREG);
msm_write(port, 0xF6, UART_NREG);
msm_write(port, 0x0F, UART_DREG);
msm_write(port, 0x0A, UART_MNDREG);
port->uartclk = 1843200;
}
static inline
void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port)
{
if (port->uartclk == 19200000)
msm_serial_set_mnd_regs_tcxo(port);
else if (port->uartclk == 4800000)
msm_serial_set_mnd_regs_tcxoby4(port);
}
#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_from_uartclk
#endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */

View file

@ -300,6 +300,8 @@ static int mvebu_uart_startup(struct uart_port *port)
static void mvebu_uart_shutdown(struct uart_port *port) static void mvebu_uart_shutdown(struct uart_port *port)
{ {
writel(0, port->membase + UART_CTRL); writel(0, port->membase + UART_CTRL);
free_irq(port->irq, port);
} }
static void mvebu_uart_set_termios(struct uart_port *port, static void mvebu_uart_set_termios(struct uart_port *port,

View file

@ -445,7 +445,6 @@ static int pic32_uart_startup(struct uart_port *port)
sport->idx); sport->idx);
if (!sport->irq_rx_name) { if (!sport->irq_rx_name) {
dev_err(port->dev, "%s: kasprintf err!", __func__); dev_err(port->dev, "%s: kasprintf err!", __func__);
kfree(sport->irq_fault_name);
ret = -ENOMEM; ret = -ENOMEM;
goto out_f; goto out_f;
} }

View file

@ -1720,7 +1720,7 @@ static int __init pmz_init_port(struct uart_pmac_port *uap)
r_ports = platform_get_resource(uap->pdev, IORESOURCE_MEM, 0); r_ports = platform_get_resource(uap->pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(uap->pdev, 0); irq = platform_get_irq(uap->pdev, 0);
if (!r_ports || !irq) if (!r_ports || irq <= 0)
return -ENODEV; return -ENODEV;
uap->port.mapbase = r_ports->start; uap->port.mapbase = r_ports->start;

View file

@ -27,7 +27,6 @@
#define SUPPORT_SYSRQ #define SUPPORT_SYSRQ
#endif #endif
#include <linux/module.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/console.h> #include <linux/console.h>
@ -829,7 +828,6 @@ static const struct of_device_id serial_pxa_dt_ids[] = {
{ .compatible = "mrvl,mmp-uart", }, { .compatible = "mrvl,mmp-uart", },
{} {}
}; };
MODULE_DEVICE_TABLE(of, serial_pxa_dt_ids);
static int serial_pxa_probe_dt(struct platform_device *pdev, static int serial_pxa_probe_dt(struct platform_device *pdev,
struct uart_pxa_port *sport) struct uart_pxa_port *sport)
@ -914,28 +912,15 @@ static int serial_pxa_probe(struct platform_device *dev)
return ret; return ret;
} }
static int serial_pxa_remove(struct platform_device *dev)
{
struct uart_pxa_port *sport = platform_get_drvdata(dev);
uart_remove_one_port(&serial_pxa_reg, &sport->port);
clk_unprepare(sport->clk);
clk_put(sport->clk);
kfree(sport);
return 0;
}
static struct platform_driver serial_pxa_driver = { static struct platform_driver serial_pxa_driver = {
.probe = serial_pxa_probe, .probe = serial_pxa_probe,
.remove = serial_pxa_remove,
.driver = { .driver = {
.name = "pxa2xx-uart", .name = "pxa2xx-uart",
#ifdef CONFIG_PM #ifdef CONFIG_PM
.pm = &serial_pxa_pm_ops, .pm = &serial_pxa_pm_ops,
#endif #endif
.suppress_bind_attrs = true,
.of_match_table = serial_pxa_dt_ids, .of_match_table = serial_pxa_dt_ids,
}, },
}; };
@ -954,15 +939,4 @@ static int __init serial_pxa_init(void)
return ret; return ret;
} }
device_initcall(serial_pxa_init);
static void __exit serial_pxa_exit(void)
{
platform_driver_unregister(&serial_pxa_driver);
uart_unregister_driver(&serial_pxa_reg);
}
module_init(serial_pxa_init);
module_exit(serial_pxa_exit);
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:pxa2xx-uart");

View file

@ -169,8 +169,7 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
return; return;
if (s3c24xx_serial_has_interrupt_mask(port)) if (s3c24xx_serial_has_interrupt_mask(port))
__set_bit(S3C64XX_UINTM_TXD, s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM);
portaddrl(port, S3C64XX_UINTM));
else else
disable_irq_nosync(ourport->tx_irq); disable_irq_nosync(ourport->tx_irq);
@ -235,8 +234,7 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
/* Mask Tx interrupt */ /* Mask Tx interrupt */
if (s3c24xx_serial_has_interrupt_mask(port)) if (s3c24xx_serial_has_interrupt_mask(port))
__set_bit(S3C64XX_UINTM_TXD, s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM);
portaddrl(port, S3C64XX_UINTM));
else else
disable_irq_nosync(ourport->tx_irq); disable_irq_nosync(ourport->tx_irq);
@ -269,8 +267,8 @@ static void enable_tx_pio(struct s3c24xx_uart_port *ourport)
/* Unmask Tx interrupt */ /* Unmask Tx interrupt */
if (s3c24xx_serial_has_interrupt_mask(port)) if (s3c24xx_serial_has_interrupt_mask(port))
__clear_bit(S3C64XX_UINTM_TXD, s3c24xx_clear_bit(port, S3C64XX_UINTM_TXD,
portaddrl(port, S3C64XX_UINTM)); S3C64XX_UINTM);
else else
enable_irq(ourport->tx_irq); enable_irq(ourport->tx_irq);
@ -397,8 +395,8 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port)
if (rx_enabled(port)) { if (rx_enabled(port)) {
dbg("s3c24xx_serial_stop_rx: port=%p\n", port); dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
if (s3c24xx_serial_has_interrupt_mask(port)) if (s3c24xx_serial_has_interrupt_mask(port))
__set_bit(S3C64XX_UINTM_RXD, s3c24xx_set_bit(port, S3C64XX_UINTM_RXD,
portaddrl(port, S3C64XX_UINTM)); S3C64XX_UINTM);
else else
disable_irq_nosync(ourport->rx_irq); disable_irq_nosync(ourport->rx_irq);
rx_enabled(port) = 0; rx_enabled(port) = 0;
@ -1069,7 +1067,7 @@ static int s3c64xx_serial_startup(struct uart_port *port)
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
/* Enable Rx Interrupt */ /* Enable Rx Interrupt */
__clear_bit(S3C64XX_UINTM_RXD, portaddrl(port, S3C64XX_UINTM)); s3c24xx_clear_bit(port, S3C64XX_UINTM_RXD, S3C64XX_UINTM);
dbg("s3c64xx_serial_startup ok\n"); dbg("s3c64xx_serial_startup ok\n");
return ret; return ret;
@ -1684,7 +1682,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
return -ENODEV; return -ENODEV;
if (port->mapbase != 0) if (port->mapbase != 0)
return 0; return -EINVAL;
/* setup info for port */ /* setup info for port */
port->dev = &platdev->dev; port->dev = &platdev->dev;
@ -1738,22 +1736,25 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
ourport->dma = devm_kzalloc(port->dev, ourport->dma = devm_kzalloc(port->dev,
sizeof(*ourport->dma), sizeof(*ourport->dma),
GFP_KERNEL); GFP_KERNEL);
if (!ourport->dma) if (!ourport->dma) {
return -ENOMEM; ret = -ENOMEM;
goto err;
}
} }
ourport->clk = clk_get(&platdev->dev, "uart"); ourport->clk = clk_get(&platdev->dev, "uart");
if (IS_ERR(ourport->clk)) { if (IS_ERR(ourport->clk)) {
pr_err("%s: Controller clock not found\n", pr_err("%s: Controller clock not found\n",
dev_name(&platdev->dev)); dev_name(&platdev->dev));
return PTR_ERR(ourport->clk); ret = PTR_ERR(ourport->clk);
goto err;
} }
ret = clk_prepare_enable(ourport->clk); ret = clk_prepare_enable(ourport->clk);
if (ret) { if (ret) {
pr_err("uart: clock failed to prepare+enable: %d\n", ret); pr_err("uart: clock failed to prepare+enable: %d\n", ret);
clk_put(ourport->clk); clk_put(ourport->clk);
return ret; goto err;
} }
/* Keep all interrupts masked and cleared */ /* Keep all interrupts masked and cleared */
@ -1769,7 +1770,12 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
/* reset the fifos (and setup the uart) */ /* reset the fifos (and setup the uart) */
s3c24xx_serial_resetport(port, cfg); s3c24xx_serial_resetport(port, cfg);
return 0; return 0;
err:
port->mapbase = 0;
return ret;
} }
/* Device driver serial port probe */ /* Device driver serial port probe */
@ -1836,8 +1842,6 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
ourport->min_dma_size = max_t(int, ourport->port.fifosize, ourport->min_dma_size = max_t(int, ourport->port.fifosize,
dma_get_cache_alignment()); dma_get_cache_alignment());
probe_index++;
dbg("%s: initialising port %p...\n", __func__, ourport); dbg("%s: initialising port %p...\n", __func__, ourport);
ret = s3c24xx_serial_init_port(ourport, pdev); ret = s3c24xx_serial_init_port(ourport, pdev);
@ -1867,6 +1871,8 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
if (ret < 0) if (ret < 0)
dev_err(&pdev->dev, "failed to add cpufreq notifier\n"); dev_err(&pdev->dev, "failed to add cpufreq notifier\n");
probe_index++;
return 0; return 0;
} }

View file

@ -117,10 +117,38 @@ struct s3c24xx_uart_port {
#define portaddrl(port, reg) \ #define portaddrl(port, reg) \
((unsigned long *)(unsigned long)((port)->membase + (reg))) ((unsigned long *)(unsigned long)((port)->membase + (reg)))
#define rd_regb(port, reg) (__raw_readb(portaddr(port, reg))) #define rd_regb(port, reg) (readb_relaxed(portaddr(port, reg)))
#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg))) #define rd_regl(port, reg) (readl_relaxed(portaddr(port, reg)))
#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg)) #define wr_regb(port, reg, val) writeb_relaxed(val, portaddr(port, reg))
#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg)) #define wr_regl(port, reg, val) writel_relaxed(val, portaddr(port, reg))
/* Byte-order aware bit setting/clearing functions. */
static inline void s3c24xx_set_bit(struct uart_port *port, int idx,
unsigned int reg)
{
unsigned long flags;
u32 val;
local_irq_save(flags);
val = rd_regl(port, reg);
val |= (1 << idx);
wr_regl(port, reg, val);
local_irq_restore(flags);
}
static inline void s3c24xx_clear_bit(struct uart_port *port, int idx,
unsigned int reg)
{
unsigned long flags;
u32 val;
local_irq_save(flags);
val = rd_regl(port, reg);
val &= ~(1 << idx);
wr_regl(port, reg, val);
local_irq_restore(flags);
}
#endif #endif

View file

@ -1317,7 +1317,12 @@ static int tegra_uart_probe(struct platform_device *pdev)
} }
u->iotype = UPIO_MEM32; u->iotype = UPIO_MEM32;
u->irq = platform_get_irq(pdev, 0); ret = platform_get_irq(pdev, 0);
if (ret < 0) {
dev_err(&pdev->dev, "Couldn't get IRQ\n");
return ret;
}
u->irq = ret;
u->regshift = 2; u->regshift = 2;
ret = uart_add_one_port(&tegra_uart_driver, u); ret = uart_add_one_port(&tegra_uart_driver, u);
if (ret < 0) { if (ret < 0) {

View file

@ -887,7 +887,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
/* /*
* Free and release old regions * Free and release old regions
*/ */
if (old_type != PORT_UNKNOWN) if (old_type != PORT_UNKNOWN && uport->ops->release_port)
uport->ops->release_port(uport); uport->ops->release_port(uport);
uport->iobase = new_port; uport->iobase = new_port;
@ -900,7 +900,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
/* /*
* Claim and map the new regions * Claim and map the new regions
*/ */
if (uport->type != PORT_UNKNOWN) { if (uport->type != PORT_UNKNOWN && uport->ops->request_port) {
retval = uport->ops->request_port(uport); retval = uport->ops->request_port(uport);
} else { } else {
/* Always success - Jean II */ /* Always success - Jean II */
@ -1125,7 +1125,7 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
* If we already have a port type configured, * If we already have a port type configured,
* we must release its resources. * we must release its resources.
*/ */
if (uport->type != PORT_UNKNOWN) if (uport->type != PORT_UNKNOWN && uport->ops->release_port)
uport->ops->release_port(uport); uport->ops->release_port(uport);
flags = UART_CONFIG_TYPE; flags = UART_CONFIG_TYPE;
@ -2897,7 +2897,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
/* /*
* Free the port IO and memory resources, if any. * Free the port IO and memory resources, if any.
*/ */
if (uport->type != PORT_UNKNOWN) if (uport->type != PORT_UNKNOWN && uport->ops->release_port)
uport->ops->release_port(uport); uport->ops->release_port(uport);
kfree(uport->tty_groups); kfree(uport->tty_groups);

View file

@ -52,6 +52,9 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
int value_array[UART_GPIO_MAX]; int value_array[UART_GPIO_MAX];
unsigned int count = 0; unsigned int count = 0;
if (gpios == NULL)
return;
for (i = 0; i < UART_GPIO_MAX; i++) for (i = 0; i < UART_GPIO_MAX; i++)
if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) { if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) {
desc_array[count] = gpios->gpio[i]; desc_array[count] = gpios->gpio[i];
@ -73,6 +76,9 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
{ {
enum mctrl_gpio_idx i; enum mctrl_gpio_idx i;
if (gpios == NULL)
return *mctrl;
for (i = 0; i < UART_GPIO_MAX; i++) { for (i = 0; i < UART_GPIO_MAX; i++) {
if (gpios->gpio[i] && !mctrl_gpios_desc[i].dir_out) { if (gpios->gpio[i] && !mctrl_gpios_desc[i].dir_out) {
if (gpiod_get_value(gpios->gpio[i])) if (gpiod_get_value(gpios->gpio[i]))
@ -86,6 +92,27 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
} }
EXPORT_SYMBOL_GPL(mctrl_gpio_get); EXPORT_SYMBOL_GPL(mctrl_gpio_get);
unsigned int
mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl)
{
enum mctrl_gpio_idx i;
if (gpios == NULL)
return *mctrl;
for (i = 0; i < UART_GPIO_MAX; i++) {
if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) {
if (gpiod_get_value(gpios->gpio[i]))
*mctrl |= mctrl_gpios_desc[i].mctrl;
else
*mctrl &= ~mctrl_gpios_desc[i].mctrl;
}
}
return *mctrl;
}
EXPORT_SYMBOL_GPL(mctrl_gpio_get_outputs);
struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx) struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
{ {
struct mctrl_gpios *gpios; struct mctrl_gpios *gpios;
@ -203,6 +230,9 @@ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
{ {
enum mctrl_gpio_idx i; enum mctrl_gpio_idx i;
if (gpios == NULL)
return;
for (i = 0; i < UART_GPIO_MAX; i++) { for (i = 0; i < UART_GPIO_MAX; i++) {
if (gpios->irq[i]) if (gpios->irq[i])
devm_free_irq(gpios->port->dev, gpios->irq[i], gpios); devm_free_irq(gpios->port->dev, gpios->irq[i], gpios);
@ -218,6 +248,9 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
{ {
enum mctrl_gpio_idx i; enum mctrl_gpio_idx i;
if (gpios == NULL)
return;
/* .enable_ms may be called multiple times */ /* .enable_ms may be called multiple times */
if (gpios->mctrl_on) if (gpios->mctrl_on)
return; return;
@ -240,6 +273,9 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
{ {
enum mctrl_gpio_idx i; enum mctrl_gpio_idx i;
if (gpios == NULL)
return;
if (!gpios->mctrl_on) if (!gpios->mctrl_on)
return; return;

View file

@ -48,11 +48,18 @@ struct mctrl_gpios;
void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl); void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl);
/* /*
* Get state of the modem control output lines from GPIOs. * Get state of the modem control input lines from GPIOs.
* The mctrl flags are updated and returned. * The mctrl flags are updated and returned.
*/ */
unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl); unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl);
/*
* Get state of the modem control output lines from GPIOs.
* The mctrl flags are updated and returned.
*/
unsigned int
mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl);
/* /*
* Returns the associated struct gpio_desc to the modem line gidx * Returns the associated struct gpio_desc to the modem line gidx
*/ */
@ -107,6 +114,12 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
return *mctrl; return *mctrl;
} }
static inline unsigned int
mctrl_gpio_get_outputs(struct mctrl_gpios *gpios, unsigned int *mctrl)
{
return *mctrl;
}
static inline static inline
struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
enum mctrl_gpio_idx gidx) enum mctrl_gpio_idx gidx)

View file

@ -57,6 +57,7 @@
#include <asm/sh_bios.h> #include <asm/sh_bios.h>
#endif #endif
#include "serial_mctrl_gpio.h"
#include "sh-sci.h" #include "sh-sci.h"
/* Offsets into the sci_port->irqs array */ /* Offsets into the sci_port->irqs array */
@ -111,6 +112,7 @@ struct sci_port {
unsigned int error_clear; unsigned int error_clear;
unsigned int sampling_rate_mask; unsigned int sampling_rate_mask;
resource_size_t reg_size; resource_size_t reg_size;
struct mctrl_gpios *gpios;
/* Break timer */ /* Break timer */
struct timer_list break_timer; struct timer_list break_timer;
@ -139,6 +141,8 @@ struct sci_port {
struct timer_list rx_timer; struct timer_list rx_timer;
unsigned int rx_timeout; unsigned int rx_timeout;
#endif #endif
bool autorts;
}; };
#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
@ -701,7 +705,6 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
static void sci_init_pins(struct uart_port *port, unsigned int cflag) static void sci_init_pins(struct uart_port *port, unsigned int cflag)
{ {
struct sci_port *s = to_sci_port(port); struct sci_port *s = to_sci_port(port);
const struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
/* /*
* Use port-specific handler if provided. * Use port-specific handler if provided.
@ -711,21 +714,28 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
return; return;
} }
/* if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
* For the generic path SCSPTR is necessary. Bail out if that's u16 ctrl = serial_port_in(port, SCPCR);
* unavailable, too.
*/
if (!reg->size)
return;
if ((s->cfg->capabilities & SCIx_HAVE_RTSCTS) && /* Enable RXD and TXD pin functions */
((!(cflag & CRTSCTS)))) { ctrl &= ~(SCPCR_RXDC | SCPCR_TXDC);
unsigned short status; if (to_sci_port(port)->cfg->capabilities & SCIx_HAVE_RTSCTS) {
/* RTS# is output, driven 1 */
ctrl |= SCPCR_RTSC;
serial_port_out(port, SCPDR,
serial_port_in(port, SCPDR) | SCPDR_RTSD);
/* Enable CTS# pin function */
ctrl &= ~SCPCR_CTSC;
}
serial_port_out(port, SCPCR, ctrl);
} else if (sci_getreg(port, SCSPTR)->size) {
u16 status = serial_port_in(port, SCSPTR);
status = serial_port_in(port, SCSPTR); /* RTS# is output, driven 1 */
status &= ~SCSPTR_CTSIO; status |= SCSPTR_RTSIO | SCSPTR_RTSDT;
status |= SCSPTR_RTSIO; /* CTS# and SCK are inputs */
serial_port_out(port, SCSPTR, status); /* Set RTS = 1 */ status &= ~(SCSPTR_CTSIO | SCSPTR_SCKIO);
serial_port_out(port, SCSPTR, status);
} }
} }
@ -1803,6 +1813,46 @@ static unsigned int sci_tx_empty(struct uart_port *port)
return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0; return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
} }
static void sci_set_rts(struct uart_port *port, bool state)
{
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
u16 data = serial_port_in(port, SCPDR);
/* Active low */
if (state)
data &= ~SCPDR_RTSD;
else
data |= SCPDR_RTSD;
serial_port_out(port, SCPDR, data);
/* RTS# is output */
serial_port_out(port, SCPCR,
serial_port_in(port, SCPCR) | SCPCR_RTSC);
} else if (sci_getreg(port, SCSPTR)->size) {
u16 ctrl = serial_port_in(port, SCSPTR);
/* Active low */
if (state)
ctrl &= ~SCSPTR_RTSDT;
else
ctrl |= SCSPTR_RTSDT;
serial_port_out(port, SCSPTR, ctrl);
}
}
static bool sci_get_cts(struct uart_port *port)
{
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
/* Active low */
return !(serial_port_in(port, SCPDR) & SCPDR_CTSD);
} else if (sci_getreg(port, SCSPTR)->size) {
/* Active low */
return !(serial_port_in(port, SCSPTR) & SCSPTR_CTSDT);
}
return true;
}
/* /*
* Modem control is a bit of a mixed bag for SCI(F) ports. Generally * Modem control is a bit of a mixed bag for SCI(F) ports. Generally
* CTS/RTS is supported in hardware by at least one port and controlled * CTS/RTS is supported in hardware by at least one port and controlled
@ -1817,6 +1867,8 @@ static unsigned int sci_tx_empty(struct uart_port *port)
*/ */
static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
{ {
struct sci_port *s = to_sci_port(port);
if (mctrl & TIOCM_LOOP) { if (mctrl & TIOCM_LOOP) {
const struct plat_sci_reg *reg; const struct plat_sci_reg *reg;
@ -1829,25 +1881,72 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
serial_port_in(port, SCFCR) | serial_port_in(port, SCFCR) |
SCFCR_LOOP); SCFCR_LOOP);
} }
mctrl_gpio_set(s->gpios, mctrl);
if (!(s->cfg->capabilities & SCIx_HAVE_RTSCTS))
return;
if (!(mctrl & TIOCM_RTS)) {
/* Disable Auto RTS */
serial_port_out(port, SCFCR,
serial_port_in(port, SCFCR) & ~SCFCR_MCE);
/* Clear RTS */
sci_set_rts(port, 0);
} else if (s->autorts) {
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
/* Enable RTS# pin function */
serial_port_out(port, SCPCR,
serial_port_in(port, SCPCR) & ~SCPCR_RTSC);
}
/* Enable Auto RTS */
serial_port_out(port, SCFCR,
serial_port_in(port, SCFCR) | SCFCR_MCE);
} else {
/* Set RTS */
sci_set_rts(port, 1);
}
} }
static unsigned int sci_get_mctrl(struct uart_port *port) static unsigned int sci_get_mctrl(struct uart_port *port)
{ {
struct sci_port *s = to_sci_port(port);
struct mctrl_gpios *gpios = s->gpios;
unsigned int mctrl = 0;
mctrl_gpio_get(gpios, &mctrl);
/* /*
* CTS/RTS is handled in hardware when supported, while nothing * CTS/RTS is handled in hardware when supported, while nothing
* else is wired up. Keep it simple and simply assert DSR/CAR. * else is wired up.
*/ */
return TIOCM_DSR | TIOCM_CAR; if (s->autorts) {
if (sci_get_cts(port))
mctrl |= TIOCM_CTS;
} else if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_CTS))) {
mctrl |= TIOCM_CTS;
}
if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_DSR)))
mctrl |= TIOCM_DSR;
if (IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(gpios, UART_GPIO_DCD)))
mctrl |= TIOCM_CAR;
return mctrl;
}
static void sci_enable_ms(struct uart_port *port)
{
mctrl_gpio_enable_ms(to_sci_port(port)->gpios);
} }
static void sci_break_ctl(struct uart_port *port, int break_state) static void sci_break_ctl(struct uart_port *port, int break_state)
{ {
struct sci_port *s = to_sci_port(port);
const struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
unsigned short scscr, scsptr; unsigned short scscr, scsptr;
/* check wheter the port has SCSPTR */ /* check wheter the port has SCSPTR */
if (!reg->size) { if (!sci_getreg(port, SCSPTR)->size) {
/* /*
* Not supported by hardware. Most parts couple break and rx * Not supported by hardware. Most parts couple break and rx
* interrupts together, with break detection always enabled. * interrupts together, with break detection always enabled.
@ -1873,7 +1972,6 @@ static void sci_break_ctl(struct uart_port *port, int break_state)
static int sci_startup(struct uart_port *port) static int sci_startup(struct uart_port *port)
{ {
struct sci_port *s = to_sci_port(port); struct sci_port *s = to_sci_port(port);
unsigned long flags;
int ret; int ret;
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
@ -1884,11 +1982,6 @@ static int sci_startup(struct uart_port *port)
sci_request_dma(port); sci_request_dma(port);
spin_lock_irqsave(&port->lock, flags);
sci_start_tx(port);
sci_start_rx(port);
spin_unlock_irqrestore(&port->lock, flags);
return 0; return 0;
} }
@ -1896,12 +1989,19 @@ static void sci_shutdown(struct uart_port *port)
{ {
struct sci_port *s = to_sci_port(port); struct sci_port *s = to_sci_port(port);
unsigned long flags; unsigned long flags;
u16 scr;
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
s->autorts = false;
mctrl_gpio_disable_ms(to_sci_port(port)->gpios);
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
sci_stop_rx(port); sci_stop_rx(port);
sci_stop_tx(port); sci_stop_tx(port);
/* Stop RX and TX, disable related interrupts, keep clock source */
scr = serial_port_in(port, SCSCR);
serial_port_out(port, SCSCR, scr & (SCSCR_CKE1 | SCSCR_CKE0));
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
#ifdef CONFIG_SERIAL_SH_SCI_DMA #ifdef CONFIG_SERIAL_SH_SCI_DMA
@ -2056,6 +2156,15 @@ static void sci_reset(struct uart_port *port)
reg = sci_getreg(port, SCFCR); reg = sci_getreg(port, SCFCR);
if (reg->size) if (reg->size)
serial_port_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); serial_port_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
sci_clear_SCxSR(port,
SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) &
SCxSR_BREAK_CLEAR(port));
if (sci_getreg(port, SCLSR)->size) {
status = serial_port_in(port, SCLSR);
status &= ~(SCLSR_TO | SCLSR_ORER);
serial_port_out(port, SCLSR, status);
}
} }
static void sci_set_termios(struct uart_port *port, struct ktermios *termios, static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
@ -2218,15 +2327,18 @@ done:
sci_init_pins(port, termios->c_cflag); sci_init_pins(port, termios->c_cflag);
port->status &= ~UPSTAT_AUTOCTS;
s->autorts = false;
reg = sci_getreg(port, SCFCR); reg = sci_getreg(port, SCFCR);
if (reg->size) { if (reg->size) {
unsigned short ctrl = serial_port_in(port, SCFCR); unsigned short ctrl = serial_port_in(port, SCFCR);
if (s->cfg->capabilities & SCIx_HAVE_RTSCTS) { if ((port->flags & UPF_HARD_FLOW) &&
if (termios->c_cflag & CRTSCTS) (termios->c_cflag & CRTSCTS)) {
ctrl |= SCFCR_MCE; /* There is no CTS interrupt to restart the hardware */
else port->status |= UPSTAT_AUTOCTS;
ctrl &= ~SCFCR_MCE; /* MCE is enabled when RTS is raised */
s->autorts = true;
} }
/* /*
@ -2300,6 +2412,9 @@ done:
sci_start_rx(port); sci_start_rx(port);
sci_port_disable(s); sci_port_disable(s);
if (UART_ENABLE_MS(port, termios->c_cflag))
sci_enable_ms(port);
} }
static void sci_pm(struct uart_port *port, unsigned int state, static void sci_pm(struct uart_port *port, unsigned int state,
@ -2425,6 +2540,7 @@ static struct uart_ops sci_uart_ops = {
.start_tx = sci_start_tx, .start_tx = sci_start_tx,
.stop_tx = sci_stop_tx, .stop_tx = sci_stop_tx,
.stop_rx = sci_stop_rx, .stop_rx = sci_stop_rx,
.enable_ms = sci_enable_ms,
.break_ctl = sci_break_ctl, .break_ctl = sci_break_ctl,
.startup = sci_startup, .startup = sci_startup,
.shutdown = sci_shutdown, .shutdown = sci_shutdown,
@ -2890,6 +3006,9 @@ sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id)
p->regtype = SCI_OF_REGTYPE(match->data); p->regtype = SCI_OF_REGTYPE(match->data);
p->scscr = SCSCR_RE | SCSCR_TE; p->scscr = SCSCR_RE | SCSCR_TE;
if (of_find_property(np, "uart-has-rtscts", NULL))
p->capabilities |= SCIx_HAVE_RTSCTS;
return p; return p;
} }
@ -2912,6 +3031,21 @@ static int sci_probe_single(struct platform_device *dev,
if (ret) if (ret)
return ret; return ret;
sciport->gpios = mctrl_gpio_init(&sciport->port, 0);
if (IS_ERR(sciport->gpios) && PTR_ERR(sciport->gpios) != -ENOSYS)
return PTR_ERR(sciport->gpios);
if (p->capabilities & SCIx_HAVE_RTSCTS) {
if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(sciport->gpios,
UART_GPIO_CTS)) ||
!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(sciport->gpios,
UART_GPIO_RTS))) {
dev_err(&dev->dev, "Conflicting RTS/CTS config\n");
return -EINVAL;
}
sciport->port.flags |= UPF_HARD_FLOW;
}
ret = uart_add_one_port(&sci_uart_driver, &sciport->port); ret = uart_add_one_port(&sci_uart_driver, &sciport->port);
if (ret) { if (ret) {
sci_cleanup_single(sciport); sci_cleanup_single(sciport);

View file

@ -105,13 +105,16 @@ enum {
#define SCFCR_LOOP BIT(0) /* Loopback Test */ #define SCFCR_LOOP BIT(0) /* Loopback Test */
/* SCLSR (Line Status Register) on (H)SCIF */ /* SCLSR (Line Status Register) on (H)SCIF */
#define SCLSR_TO BIT(2) /* Timeout */
#define SCLSR_ORER BIT(0) /* Overrun Error */ #define SCLSR_ORER BIT(0) /* Overrun Error */
/* SCSPTR (Serial Port Register), optional */ /* SCSPTR (Serial Port Register), optional */
#define SCSPTR_RTSIO BIT(7) /* Serial Port RTS Pin Input/Output */ #define SCSPTR_RTSIO BIT(7) /* Serial Port RTS# Pin Input/Output */
#define SCSPTR_RTSDT BIT(6) /* Serial Port RTS Pin Data */ #define SCSPTR_RTSDT BIT(6) /* Serial Port RTS# Pin Data */
#define SCSPTR_CTSIO BIT(5) /* Serial Port CTS Pin Input/Output */ #define SCSPTR_CTSIO BIT(5) /* Serial Port CTS# Pin Input/Output */
#define SCSPTR_CTSDT BIT(4) /* Serial Port CTS Pin Data */ #define SCSPTR_CTSDT BIT(4) /* Serial Port CTS# Pin Data */
#define SCSPTR_SCKIO BIT(3) /* Serial Port Clock Pin Input/Output */
#define SCSPTR_SCKDT BIT(2) /* Serial Port Clock Pin Data */
#define SCSPTR_SPB2IO BIT(1) /* Serial Port Break Input/Output */ #define SCSPTR_SPB2IO BIT(1) /* Serial Port Break Input/Output */
#define SCSPTR_SPB2DT BIT(0) /* Serial Port Break Data */ #define SCSPTR_SPB2DT BIT(0) /* Serial Port Break Data */
@ -119,12 +122,18 @@ enum {
#define HSCIF_SRE BIT(15) /* Sampling Rate Register Enable */ #define HSCIF_SRE BIT(15) /* Sampling Rate Register Enable */
/* SCPCR (Serial Port Control Register), SCIFA/SCIFB only */ /* SCPCR (Serial Port Control Register), SCIFA/SCIFB only */
#define SCPCR_RTSC BIT(4) /* Serial Port RTS Pin / Output Pin */ #define SCPCR_RTSC BIT(4) /* Serial Port RTS# Pin / Output Pin */
#define SCPCR_CTSC BIT(3) /* Serial Port CTS Pin / Input Pin */ #define SCPCR_CTSC BIT(3) /* Serial Port CTS# Pin / Input Pin */
#define SCPCR_SCKC BIT(2) /* Serial Port SCK Pin / Output Pin */
#define SCPCR_RXDC BIT(1) /* Serial Port RXD Pin / Input Pin */
#define SCPCR_TXDC BIT(0) /* Serial Port TXD Pin / Output Pin */
/* SCPDR (Serial Port Data Register), SCIFA/SCIFB only */ /* SCPDR (Serial Port Data Register), SCIFA/SCIFB only */
#define SCPDR_RTSD BIT(4) /* Serial Port RTS Output Pin Data */ #define SCPDR_RTSD BIT(4) /* Serial Port RTS# Output Pin Data */
#define SCPDR_CTSD BIT(3) /* Serial Port CTS Input Pin Data */ #define SCPDR_CTSD BIT(3) /* Serial Port CTS# Input Pin Data */
#define SCPDR_SCKD BIT(2) /* Serial Port SCK Output Pin Data */
#define SCPDR_RXDD BIT(1) /* Serial Port RXD Input Pin Data */
#define SCPDR_TXDD BIT(0) /* Serial Port TXD Output Pin Data */
/* /*
* BRG Clock Select Register (Some SCIF and HSCIF) * BRG Clock Select Register (Some SCIF and HSCIF)

View file

@ -106,7 +106,7 @@ struct sirfsoc_uart_register {
enum sirfsoc_uart_type uart_type; enum sirfsoc_uart_type uart_type;
}; };
u32 uart_usp_ff_full_mask(struct uart_port *port) static u32 uart_usp_ff_full_mask(struct uart_port *port)
{ {
u32 full_bit; u32 full_bit;
@ -114,7 +114,7 @@ u32 uart_usp_ff_full_mask(struct uart_port *port)
return (1 << full_bit); return (1 << full_bit);
} }
u32 uart_usp_ff_empty_mask(struct uart_port *port) static u32 uart_usp_ff_empty_mask(struct uart_port *port)
{ {
u32 empty_bit; u32 empty_bit;

View file

@ -21,7 +21,6 @@
#include <linux/hrtimer.h> #include <linux/hrtimer.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/module.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/irq.h> #include <linux/irq.h>
@ -730,22 +729,12 @@ static int vt8500_serial_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int vt8500_serial_remove(struct platform_device *pdev)
{
struct vt8500_port *vt8500_port = platform_get_drvdata(pdev);
clk_disable_unprepare(vt8500_port->clk);
uart_remove_one_port(&vt8500_uart_driver, &vt8500_port->uart);
return 0;
}
static struct platform_driver vt8500_platform_driver = { static struct platform_driver vt8500_platform_driver = {
.probe = vt8500_serial_probe, .probe = vt8500_serial_probe,
.remove = vt8500_serial_remove,
.driver = { .driver = {
.name = "vt8500_serial", .name = "vt8500_serial",
.of_match_table = wmt_dt_ids, .of_match_table = wmt_dt_ids,
.suppress_bind_attrs = true,
}, },
}; };
@ -764,19 +753,4 @@ static int __init vt8500_serial_init(void)
return ret; return ret;
} }
device_initcall(vt8500_serial_init);
static void __exit vt8500_serial_exit(void)
{
#ifdef CONFIG_SERIAL_VT8500_CONSOLE
unregister_console(&vt8500_console);
#endif
platform_driver_unregister(&vt8500_platform_driver);
uart_unregister_driver(&vt8500_uart_driver);
}
module_init(vt8500_serial_init);
module_exit(vt8500_serial_exit);
MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>");
MODULE_DESCRIPTION("Driver for vt8500 serial device");
MODULE_LICENSE("GPL v2");

View file

@ -976,6 +976,23 @@ static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c)
} }
#endif #endif
static void cdns_uart_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
struct cdns_uart *cdns_uart = port->private_data;
switch (state) {
case UART_PM_STATE_OFF:
clk_disable(cdns_uart->uartclk);
clk_disable(cdns_uart->pclk);
break;
default:
clk_enable(cdns_uart->pclk);
clk_enable(cdns_uart->uartclk);
break;
}
}
static struct uart_ops cdns_uart_ops = { static struct uart_ops cdns_uart_ops = {
.set_mctrl = cdns_uart_set_mctrl, .set_mctrl = cdns_uart_set_mctrl,
.get_mctrl = cdns_uart_get_mctrl, .get_mctrl = cdns_uart_get_mctrl,
@ -987,6 +1004,7 @@ static struct uart_ops cdns_uart_ops = {
.set_termios = cdns_uart_set_termios, .set_termios = cdns_uart_set_termios,
.startup = cdns_uart_startup, .startup = cdns_uart_startup,
.shutdown = cdns_uart_shutdown, .shutdown = cdns_uart_shutdown,
.pm = cdns_uart_pm,
.type = cdns_uart_type, .type = cdns_uart_type,
.verify_port = cdns_uart_verify_port, .verify_port = cdns_uart_verify_port,
.request_port = cdns_uart_request_port, .request_port = cdns_uart_request_port,
@ -1350,12 +1368,12 @@ static int cdns_uart_probe(struct platform_device *pdev)
return PTR_ERR(cdns_uart_data->uartclk); return PTR_ERR(cdns_uart_data->uartclk);
} }
rc = clk_prepare_enable(cdns_uart_data->pclk); rc = clk_prepare(cdns_uart_data->pclk);
if (rc) { if (rc) {
dev_err(&pdev->dev, "Unable to enable pclk clock.\n"); dev_err(&pdev->dev, "Unable to enable pclk clock.\n");
return rc; return rc;
} }
rc = clk_prepare_enable(cdns_uart_data->uartclk); rc = clk_prepare(cdns_uart_data->uartclk);
if (rc) { if (rc) {
dev_err(&pdev->dev, "Unable to enable device clock.\n"); dev_err(&pdev->dev, "Unable to enable device clock.\n");
goto err_out_clk_dis_pclk; goto err_out_clk_dis_pclk;
@ -1422,9 +1440,9 @@ err_out_notif_unreg:
&cdns_uart_data->clk_rate_change_nb); &cdns_uart_data->clk_rate_change_nb);
#endif #endif
err_out_clk_disable: err_out_clk_disable:
clk_disable_unprepare(cdns_uart_data->uartclk); clk_unprepare(cdns_uart_data->uartclk);
err_out_clk_dis_pclk: err_out_clk_dis_pclk:
clk_disable_unprepare(cdns_uart_data->pclk); clk_unprepare(cdns_uart_data->pclk);
return rc; return rc;
} }
@ -1448,8 +1466,8 @@ static int cdns_uart_remove(struct platform_device *pdev)
#endif #endif
rc = uart_remove_one_port(&cdns_uart_uart_driver, port); rc = uart_remove_one_port(&cdns_uart_uart_driver, port);
port->mapbase = 0; port->mapbase = 0;
clk_disable_unprepare(cdns_uart_data->uartclk); clk_unprepare(cdns_uart_data->uartclk);
clk_disable_unprepare(cdns_uart_data->pclk); clk_unprepare(cdns_uart_data->pclk);
return rc; return rc;
} }

View file

@ -499,9 +499,8 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
return 0; return 0;
} }
/* ui is a leftover from using a hashtable, but might be used again /* Caller must hold the lock */
Caller must hold the lock */ static int con_do_clear_unimap(struct vc_data *vc)
static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
{ {
struct uni_pagedir *p, *q; struct uni_pagedir *p, *q;
@ -524,11 +523,11 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
return 0; return 0;
} }
int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) int con_clear_unimap(struct vc_data *vc)
{ {
int ret; int ret;
console_lock(); console_lock();
ret = con_do_clear_unimap(vc, ui); ret = con_do_clear_unimap(vc);
console_unlock(); console_unlock();
return ret; return ret;
} }
@ -556,7 +555,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
int j, k; int j, k;
u16 **p1, *p2, l; u16 **p1, *p2, l;
err1 = con_do_clear_unimap(vc, NULL); err1 = con_do_clear_unimap(vc);
if (err1) { if (err1) {
console_unlock(); console_unlock();
return err1; return err1;
@ -677,7 +676,7 @@ int con_set_default_unimap(struct vc_data *vc)
/* The default font is always 256 characters */ /* The default font is always 256 characters */
err = con_do_clear_unimap(vc, NULL); err = con_do_clear_unimap(vc);
if (err) if (err)
return err; return err;

View file

@ -567,7 +567,7 @@ static void fn_scroll_forw(struct vc_data *vc)
static void fn_scroll_back(struct vc_data *vc) static void fn_scroll_back(struct vc_data *vc)
{ {
scrollback(vc, 0); scrollback(vc);
} }
static void fn_show_mem(struct vc_data *vc) static void fn_show_mem(struct vc_data *vc)
@ -1733,16 +1733,10 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
return -EINVAL; return -EINVAL;
if (ct) { if (ct) {
buf = kmalloc(ct * sizeof(struct kbdiacruc), buf = memdup_user(a->kbdiacruc,
GFP_KERNEL); ct * sizeof(struct kbdiacruc));
if (buf == NULL) if (IS_ERR(buf))
return -ENOMEM; return PTR_ERR(buf);
if (copy_from_user(buf, a->kbdiacruc,
ct * sizeof(struct kbdiacruc))) {
kfree(buf);
return -EFAULT;
}
} }
spin_lock_irqsave(&kbd_event_lock, flags); spin_lock_irqsave(&kbd_event_lock, flags);
if (ct) if (ct)

View file

@ -277,13 +277,15 @@ static void notify_update(struct vc_data *vc)
* Low-Level Functions * Low-Level Functions
*/ */
#define IS_FG(vc) ((vc)->vc_num == fg_console) static inline bool con_is_fg(const struct vc_data *vc)
{
return vc->vc_num == fg_console;
}
#ifdef VT_BUF_VRAM_ONLY static inline bool con_should_update(const struct vc_data *vc)
#define DO_UPDATE(vc) 0 {
#else return con_is_visible(vc) && !console_blanked;
#define DO_UPDATE(vc) (CON_IS_VISIBLE(vc) && !console_blanked) }
#endif
static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed) static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed)
{ {
@ -321,7 +323,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
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, SM_UP, nr))
return; return;
d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr)); s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
@ -339,7 +341,7 @@ static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
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_DOWN, nr)) if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr))
return; return;
s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
step = vc->vc_cols * nr; step = vc->vc_cols * nr;
@ -349,7 +351,6 @@ static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
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)
{ {
#ifndef VT_BUF_VRAM_ONLY
unsigned int xx, yy, offset; unsigned int xx, yy, offset;
u16 *p; u16 *p;
@ -390,14 +391,13 @@ static void do_update_region(struct vc_data *vc, unsigned long start, int count)
start = vc->vc_sw->con_getxy(vc, start, NULL, NULL); start = vc->vc_sw->con_getxy(vc, start, NULL, NULL);
} }
} }
#endif
} }
void update_region(struct vc_data *vc, unsigned long start, int count) void update_region(struct vc_data *vc, unsigned long start, int count)
{ {
WARN_CONSOLE_UNLOCKED(); WARN_CONSOLE_UNLOCKED();
if (DO_UPDATE(vc)) { if (con_should_update(vc)) {
hide_cursor(vc); hide_cursor(vc);
do_update_region(vc, start, count); do_update_region(vc, start, count);
set_cursor(vc); set_cursor(vc);
@ -413,7 +413,6 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
return vc->vc_sw->con_build_attr(vc, _color, _intensity, return vc->vc_sw->con_build_attr(vc, _color, _intensity,
_blink, _underline, _reverse, _italic); _blink, _underline, _reverse, _italic);
#ifndef VT_BUF_VRAM_ONLY
/* /*
* ++roman: I completely changed the attribute format for monochrome * ++roman: I completely changed the attribute format for monochrome
* mode (!can_do_color). The formerly used MDA (monochrome display * mode (!can_do_color). The formerly used MDA (monochrome display
@ -448,9 +447,6 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
a <<= 1; a <<= 1;
return a; return a;
} }
#else
return 0;
#endif
} }
static void update_attr(struct vc_data *vc) static void update_attr(struct vc_data *vc)
@ -470,10 +466,9 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
count /= 2; count /= 2;
p = screenpos(vc, offset, viewed); p = screenpos(vc, offset, viewed);
if (vc->vc_sw->con_invert_region) if (vc->vc_sw->con_invert_region) {
vc->vc_sw->con_invert_region(vc, p, count); vc->vc_sw->con_invert_region(vc, p, count);
#ifndef VT_BUF_VRAM_ONLY } else {
else {
u16 *q = p; u16 *q = p;
int cnt = count; int cnt = count;
u16 a; u16 a;
@ -501,8 +496,8 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
} }
} }
} }
#endif
if (DO_UPDATE(vc)) if (con_should_update(vc))
do_update_region(vc, (unsigned long) p, count); do_update_region(vc, (unsigned long) p, count);
notify_update(vc); notify_update(vc);
} }
@ -519,7 +514,7 @@ void complement_pos(struct vc_data *vc, int offset)
if (old_offset != -1 && old_offset >= 0 && if (old_offset != -1 && old_offset >= 0 &&
old_offset < vc->vc_screenbuf_size) { old_offset < vc->vc_screenbuf_size) {
scr_writew(old, screenpos(vc, old_offset, 1)); scr_writew(old, screenpos(vc, old_offset, 1));
if (DO_UPDATE(vc)) if (con_should_update(vc))
vc->vc_sw->con_putc(vc, old, oldy, oldx); vc->vc_sw->con_putc(vc, old, oldy, oldx);
notify_update(vc); notify_update(vc);
} }
@ -534,7 +529,7 @@ void complement_pos(struct vc_data *vc, int offset)
old = scr_readw(p); old = scr_readw(p);
new = old ^ vc->vc_complement_mask; new = old ^ vc->vc_complement_mask;
scr_writew(new, p); scr_writew(new, p);
if (DO_UPDATE(vc)) { if (con_should_update(vc)) {
oldx = (offset >> 1) % vc->vc_cols; oldx = (offset >> 1) % vc->vc_cols;
oldy = (offset >> 1) / vc->vc_cols; oldy = (offset >> 1) / vc->vc_cols;
vc->vc_sw->con_putc(vc, new, oldy, oldx); vc->vc_sw->con_putc(vc, new, oldy, oldx);
@ -550,7 +545,7 @@ static void insert_char(struct vc_data *vc, unsigned int nr)
scr_memmovew(p + nr, p, (vc->vc_cols - vc->vc_x - nr) * 2); scr_memmovew(p + nr, p, (vc->vc_cols - vc->vc_x - nr) * 2);
scr_memsetw(p, vc->vc_video_erase_char, nr * 2); scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
vc->vc_need_wrap = 0; vc->vc_need_wrap = 0;
if (DO_UPDATE(vc)) if (con_should_update(vc))
do_update_region(vc, (unsigned long) p, do_update_region(vc, (unsigned long) p,
vc->vc_cols - vc->vc_x); vc->vc_cols - vc->vc_x);
} }
@ -563,7 +558,7 @@ static void delete_char(struct vc_data *vc, unsigned int nr)
scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char, scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char,
nr * 2); nr * 2);
vc->vc_need_wrap = 0; vc->vc_need_wrap = 0;
if (DO_UPDATE(vc)) if (con_should_update(vc))
do_update_region(vc, (unsigned long) p, do_update_region(vc, (unsigned long) p,
vc->vc_cols - vc->vc_x); vc->vc_cols - vc->vc_x);
} }
@ -583,7 +578,7 @@ static void add_softcursor(struct vc_data *vc)
if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000; if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700; if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
scr_writew(i, (u16 *) vc->vc_pos); scr_writew(i, (u16 *) vc->vc_pos);
if (DO_UPDATE(vc)) if (con_should_update(vc))
vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x); vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x);
} }
@ -591,7 +586,7 @@ static void hide_softcursor(struct vc_data *vc)
{ {
if (softcursor_original != -1) { if (softcursor_original != -1) {
scr_writew(softcursor_original, (u16 *)vc->vc_pos); scr_writew(softcursor_original, (u16 *)vc->vc_pos);
if (DO_UPDATE(vc)) if (con_should_update(vc))
vc->vc_sw->con_putc(vc, softcursor_original, vc->vc_sw->con_putc(vc, softcursor_original,
vc->vc_y, vc->vc_x); vc->vc_y, vc->vc_x);
softcursor_original = -1; softcursor_original = -1;
@ -608,8 +603,7 @@ static void hide_cursor(struct vc_data *vc)
static void set_cursor(struct vc_data *vc) static void set_cursor(struct vc_data *vc)
{ {
if (!IS_FG(vc) || console_blanked || if (!con_is_fg(vc) || console_blanked || vc->vc_mode == KD_GRAPHICS)
vc->vc_mode == KD_GRAPHICS)
return; return;
if (vc->vc_deccm) { if (vc->vc_deccm) {
if (vc == sel_cons) if (vc == sel_cons)
@ -625,7 +619,7 @@ static void set_origin(struct vc_data *vc)
{ {
WARN_CONSOLE_UNLOCKED(); WARN_CONSOLE_UNLOCKED();
if (!CON_IS_VISIBLE(vc) || if (!con_is_visible(vc) ||
!vc->vc_sw->con_set_origin || !vc->vc_sw->con_set_origin ||
!vc->vc_sw->con_set_origin(vc)) !vc->vc_sw->con_set_origin(vc))
vc->vc_origin = (unsigned long)vc->vc_screenbuf; vc->vc_origin = (unsigned long)vc->vc_screenbuf;
@ -673,12 +667,12 @@ void redraw_screen(struct vc_data *vc, int is_switch)
struct vc_data *old_vc = vc_cons[fg_console].d; struct vc_data *old_vc = vc_cons[fg_console].d;
if (old_vc == vc) if (old_vc == vc)
return; return;
if (!CON_IS_VISIBLE(vc)) if (!con_is_visible(vc))
redraw = 1; redraw = 1;
*vc->vc_display_fg = vc; *vc->vc_display_fg = vc;
fg_console = vc->vc_num; fg_console = vc->vc_num;
hide_cursor(old_vc); hide_cursor(old_vc);
if (!CON_IS_VISIBLE(old_vc)) { if (!con_is_visible(old_vc)) {
save_screen(old_vc); save_screen(old_vc);
set_origin(old_vc); set_origin(old_vc);
} }
@ -954,7 +948,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
tty_do_resize(tty, &ws); tty_do_resize(tty, &ws);
} }
if (CON_IS_VISIBLE(vc)) if (con_is_visible(vc))
update_screen(vc); update_screen(vc);
vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num); vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num);
return err; return err;
@ -1103,11 +1097,9 @@ static void gotoxay(struct vc_data *vc, int new_x, int new_y)
gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y); gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y);
} }
void scrollback(struct vc_data *vc, int lines) void scrollback(struct vc_data *vc)
{ {
if (!lines) scrolldelta(-(vc->vc_rows / 2));
lines = vc->vc_rows / 2;
scrolldelta(-lines);
} }
void scrollfront(struct vc_data *vc, int lines) void scrollfront(struct vc_data *vc, int lines)
@ -1186,7 +1178,7 @@ static void csi_J(struct vc_data *vc, int vpar)
scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char, scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char,
vc->vc_screenbuf_size >> 1); vc->vc_screenbuf_size >> 1);
set_origin(vc); set_origin(vc);
if (CON_IS_VISIBLE(vc)) if (con_is_visible(vc))
update_screen(vc); update_screen(vc);
/* fall through */ /* fall through */
case 2: /* erase whole display */ case 2: /* erase whole display */
@ -1197,7 +1189,7 @@ static void csi_J(struct vc_data *vc, int vpar)
return; return;
} }
scr_memsetw(start, vc->vc_video_erase_char, 2 * count); scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
if (DO_UPDATE(vc)) if (con_should_update(vc))
do_update_region(vc, (unsigned long) start, count); do_update_region(vc, (unsigned long) start, count);
vc->vc_need_wrap = 0; vc->vc_need_wrap = 0;
} }
@ -1225,7 +1217,7 @@ static void csi_K(struct vc_data *vc, int vpar)
} }
scr_memsetw(start, vc->vc_video_erase_char, 2 * count); scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
vc->vc_need_wrap = 0; vc->vc_need_wrap = 0;
if (DO_UPDATE(vc)) if (con_should_update(vc))
do_update_region(vc, (unsigned long) start, count); do_update_region(vc, (unsigned long) start, count);
} }
@ -1238,7 +1230,7 @@ static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar posi
count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar; count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar;
scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count); scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count);
if (DO_UPDATE(vc)) if (con_should_update(vc))
vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count); vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count);
vc->vc_need_wrap = 0; vc->vc_need_wrap = 0;
} }
@ -1255,48 +1247,87 @@ static void default_attr(struct vc_data *vc)
struct rgb { u8 r; u8 g; u8 b; }; struct rgb { u8 r; u8 g; u8 b; };
static struct rgb rgb_from_256(int i) static void rgb_from_256(int i, struct rgb *c)
{ {
struct rgb c;
if (i < 8) { /* Standard colours. */ if (i < 8) { /* Standard colours. */
c.r = i&1 ? 0xaa : 0x00; c->r = i&1 ? 0xaa : 0x00;
c.g = i&2 ? 0xaa : 0x00; c->g = i&2 ? 0xaa : 0x00;
c.b = i&4 ? 0xaa : 0x00; c->b = i&4 ? 0xaa : 0x00;
} else if (i < 16) { } else if (i < 16) {
c.r = i&1 ? 0xff : 0x55; c->r = i&1 ? 0xff : 0x55;
c.g = i&2 ? 0xff : 0x55; c->g = i&2 ? 0xff : 0x55;
c.b = i&4 ? 0xff : 0x55; c->b = i&4 ? 0xff : 0x55;
} else if (i < 232) { /* 6x6x6 colour cube. */ } else if (i < 232) { /* 6x6x6 colour cube. */
c.r = (i - 16) / 36 * 85 / 2; c->r = (i - 16) / 36 * 85 / 2;
c.g = (i - 16) / 6 % 6 * 85 / 2; c->g = (i - 16) / 6 % 6 * 85 / 2;
c.b = (i - 16) % 6 * 85 / 2; c->b = (i - 16) % 6 * 85 / 2;
} else /* Grayscale ramp. */ } else /* Grayscale ramp. */
c.r = c.g = c.b = i * 10 - 2312; c->r = c->g = c->b = i * 10 - 2312;
return c;
} }
static void rgb_foreground(struct vc_data *vc, struct rgb c) static void rgb_foreground(struct vc_data *vc, const struct rgb *c)
{ {
u8 hue, max = c.r; u8 hue = 0, max = max3(c->r, c->g, c->b);
if (c.g > max)
max = c.g; if (c->r > max / 2)
if (c.b > max) hue |= 4;
max = c.b; if (c->g > max / 2)
hue = (c.r > max/2 ? 4 : 0) hue |= 2;
| (c.g > max/2 ? 2 : 0) if (c->b > max / 2)
| (c.b > max/2 ? 1 : 0); hue |= 1;
if (hue == 7 && max <= 0x55)
hue = 0, vc->vc_intensity = 2; if (hue == 7 && max <= 0x55) {
hue = 0;
vc->vc_intensity = 2;
} else if (max > 0xaa)
vc->vc_intensity = 2;
else else
vc->vc_intensity = (max > 0xaa) + 1; vc->vc_intensity = 1;
vc->vc_color = (vc->vc_color & 0xf0) | hue; vc->vc_color = (vc->vc_color & 0xf0) | hue;
} }
static void rgb_background(struct vc_data *vc, struct rgb c) static void rgb_background(struct vc_data *vc, const struct rgb *c)
{ {
/* For backgrounds, err on the dark side. */ /* For backgrounds, err on the dark side. */
vc->vc_color = (vc->vc_color & 0x0f) vc->vc_color = (vc->vc_color & 0x0f)
| (c.r&0x80) >> 1 | (c.g&0x80) >> 2 | (c.b&0x80) >> 3; | (c->r&0x80) >> 1 | (c->g&0x80) >> 2 | (c->b&0x80) >> 3;
}
/*
* ITU T.416 Higher colour modes. They break the usual properties of SGR codes
* and thus need to be detected and ignored by hand. Strictly speaking, that
* standard also wants : rather than ; as separators, contrary to ECMA-48, but
* no one produces such codes and almost no one accepts them.
*
* Subcommands 3 (CMY) and 4 (CMYK) are so insane there's no point in
* supporting them.
*/
static int vc_t416_color(struct vc_data *vc, int i,
void(*set_color)(struct vc_data *vc, const struct rgb *c))
{
struct rgb c;
i++;
if (i > vc->vc_npar)
return i;
if (vc->vc_par[i] == 5 && i < vc->vc_npar) {
/* 256 colours -- ubiquitous */
i++;
rgb_from_256(vc->vc_par[i], &c);
} else if (vc->vc_par[i] == 2 && i <= vc->vc_npar + 3) {
/* 24 bit -- extremely rare */
c.r = vc->vc_par[i + 1];
c.g = vc->vc_par[i + 2];
c.b = vc->vc_par[i + 3];
i += 3;
} else
return i;
set_color(vc, &c);
return i;
} }
/* console_lock is held */ /* console_lock is held */
@ -1306,135 +1337,91 @@ static void csi_m(struct vc_data *vc)
for (i = 0; i <= vc->vc_npar; i++) for (i = 0; i <= vc->vc_npar; i++)
switch (vc->vc_par[i]) { switch (vc->vc_par[i]) {
case 0: /* all attributes off */ case 0: /* all attributes off */
default_attr(vc); default_attr(vc);
break; break;
case 1: case 1:
vc->vc_intensity = 2; vc->vc_intensity = 2;
break; break;
case 2: case 2:
vc->vc_intensity = 0; vc->vc_intensity = 0;
break; break;
case 3: case 3:
vc->vc_italic = 1; vc->vc_italic = 1;
break; break;
case 4: case 4:
vc->vc_underline = 1; vc->vc_underline = 1;
break; break;
case 5: case 5:
vc->vc_blink = 1; vc->vc_blink = 1;
break; break;
case 7: case 7:
vc->vc_reverse = 1; vc->vc_reverse = 1;
break; break;
case 10: /* ANSI X3.64-1979 (SCO-ish?) case 10: /* ANSI X3.64-1979 (SCO-ish?)
* Select primary font, don't display * Select primary font, don't display control chars if
* control chars if defined, don't set * defined, don't set bit 8 on output.
* bit 8 on output. */
*/ vc->vc_translate = set_translate(vc->vc_charset == 0
vc->vc_translate = set_translate(vc->vc_charset == 0 ? vc->vc_G0_charset
? vc->vc_G0_charset : vc->vc_G1_charset, vc);
: vc->vc_G1_charset, vc); vc->vc_disp_ctrl = 0;
vc->vc_disp_ctrl = 0; vc->vc_toggle_meta = 0;
vc->vc_toggle_meta = 0; break;
break; case 11: /* ANSI X3.64-1979 (SCO-ish?)
case 11: /* ANSI X3.64-1979 (SCO-ish?) * Select first alternate font, lets chars < 32 be
* Select first alternate font, lets * displayed as ROM chars.
* chars < 32 be displayed as ROM chars. */
*/ vc->vc_translate = set_translate(IBMPC_MAP, vc);
vc->vc_translate = set_translate(IBMPC_MAP, vc); vc->vc_disp_ctrl = 1;
vc->vc_disp_ctrl = 1; vc->vc_toggle_meta = 0;
vc->vc_toggle_meta = 0; break;
break; case 12: /* ANSI X3.64-1979 (SCO-ish?)
case 12: /* ANSI X3.64-1979 (SCO-ish?) * Select second alternate font, toggle high bit
* Select second alternate font, toggle * before displaying as ROM char.
* high bit before displaying as ROM char. */
*/ vc->vc_translate = set_translate(IBMPC_MAP, vc);
vc->vc_translate = set_translate(IBMPC_MAP, vc); vc->vc_disp_ctrl = 1;
vc->vc_disp_ctrl = 1; vc->vc_toggle_meta = 1;
vc->vc_toggle_meta = 1; break;
break; case 21:
case 21: case 22:
case 22: vc->vc_intensity = 1;
vc->vc_intensity = 1; break;
break; case 23:
case 23: vc->vc_italic = 0;
vc->vc_italic = 0; break;
break; case 24:
case 24: vc->vc_underline = 0;
vc->vc_underline = 0; break;
break; case 25:
case 25: vc->vc_blink = 0;
vc->vc_blink = 0; break;
break; case 27:
case 27: vc->vc_reverse = 0;
vc->vc_reverse = 0; break;
break; case 38:
case 38: /* ITU T.416 i = vc_t416_color(vc, i, rgb_foreground);
* Higher colour modes. break;
* They break the usual properties of SGR codes case 48:
* and thus need to be detected and ignored by i = vc_t416_color(vc, i, rgb_background);
* hand. Strictly speaking, that standard also break;
* wants : rather than ; as separators, contrary case 39:
* to ECMA-48, but no one produces such codes vc->vc_color = (vc->vc_def_color & 0x0f) |
* and almost no one accepts them. (vc->vc_color & 0xf0);
*/ break;
i++; case 49:
if (i > vc->vc_npar) vc->vc_color = (vc->vc_def_color & 0xf0) |
break; (vc->vc_color & 0x0f);
if (vc->vc_par[i] == 5 && /* 256 colours */ break;
i < vc->vc_npar) { /* ubiquitous */ default:
i++; if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
rgb_foreground(vc, vc->vc_color = color_table[vc->vc_par[i] - 30]
rgb_from_256(vc->vc_par[i])); | (vc->vc_color & 0xf0);
} else if (vc->vc_par[i] == 2 && /* 24 bit */ else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47)
i <= vc->vc_npar + 3) {/* extremely rare */ vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4)
struct rgb c = { | (vc->vc_color & 0x0f);
.r = vc->vc_par[i + 1], break;
.g = vc->vc_par[i + 2],
.b = vc->vc_par[i + 3],
};
rgb_foreground(vc, c);
i += 3;
}
/* Subcommands 3 (CMY) and 4 (CMYK) are so insane
* there's no point in supporting them.
*/
break;
case 48:
i++;
if (i > vc->vc_npar)
break;
if (vc->vc_par[i] == 5 && /* 256 colours */
i < vc->vc_npar) {
i++;
rgb_background(vc,
rgb_from_256(vc->vc_par[i]));
} else if (vc->vc_par[i] == 2 && /* 24 bit */
i <= vc->vc_npar + 3) {
struct rgb c = {
.r = vc->vc_par[i + 1],
.g = vc->vc_par[i + 2],
.b = vc->vc_par[i + 3],
};
rgb_background(vc, c);
i += 3;
}
break;
case 39:
vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
break;
case 49:
vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f);
break;
default:
if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
vc->vc_color = color_table[vc->vc_par[i] - 30]
| (vc->vc_color & 0xf0);
else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47)
vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4)
| (vc->vc_color & 0x0f);
break;
} }
update_attr(vc); update_attr(vc);
} }
@ -1496,7 +1483,6 @@ static void set_mode(struct vc_data *vc, int on_off)
clr_kbd(vc, decckm); clr_kbd(vc, decckm);
break; break;
case 3: /* 80/132 mode switch unimplemented */ case 3: /* 80/132 mode switch unimplemented */
vc->vc_deccolm = on_off;
#if 0 #if 0
vc_resize(deccolm ? 132 : 80, vc->vc_rows); vc_resize(deccolm ? 132 : 80, vc->vc_rows);
/* this alone does not suffice; some user mode /* this alone does not suffice; some user mode
@ -2178,18 +2164,20 @@ static int is_double_width(uint32_t ucs)
return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1); return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1);
} }
static void con_flush(struct vc_data *vc, unsigned long draw_from,
unsigned long draw_to, int *draw_x)
{
if (*draw_x < 0)
return;
vc->vc_sw->con_putcs(vc, (u16 *)draw_from,
(u16 *)draw_to - (u16 *)draw_from, vc->vc_y, *draw_x);
*draw_x = -1;
}
/* acquires console_lock */ /* acquires console_lock */
static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count) static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
{ {
#ifdef VT_BUF_VRAM_ONLY
#define FLUSH do { } while(0);
#else
#define FLUSH if (draw_x >= 0) { \
vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, draw_x); \
draw_x = -1; \
}
#endif
int c, tc, ok, n = 0, draw_x = -1; int c, tc, ok, n = 0, draw_x = -1;
unsigned int currcons; unsigned int currcons;
unsigned long draw_from = 0, draw_to = 0; unsigned long draw_from = 0, draw_to = 0;
@ -2226,7 +2214,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
charmask = himask ? 0x1ff : 0xff; charmask = himask ? 0x1ff : 0xff;
/* undraw cursor first */ /* undraw cursor first */
if (IS_FG(vc)) if (con_is_fg(vc))
hide_cursor(vc); hide_cursor(vc);
param.vc = vc; param.vc = vc;
@ -2381,12 +2369,13 @@ rescan_last_byte:
} else { } else {
vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4); vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4);
} }
FLUSH con_flush(vc, draw_from, draw_to, &draw_x);
} }
while (1) { while (1) {
if (vc->vc_need_wrap || vc->vc_decim) if (vc->vc_need_wrap || vc->vc_decim)
FLUSH con_flush(vc, draw_from, draw_to,
&draw_x);
if (vc->vc_need_wrap) { if (vc->vc_need_wrap) {
cr(vc); cr(vc);
lf(vc); lf(vc);
@ -2397,7 +2386,7 @@ rescan_last_byte:
((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) : ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
(vc_attr << 8) + tc, (vc_attr << 8) + tc,
(u16 *) vc->vc_pos); (u16 *) vc->vc_pos);
if (DO_UPDATE(vc) && draw_x < 0) { if (con_should_update(vc) && draw_x < 0) {
draw_x = vc->vc_x; draw_x = vc->vc_x;
draw_from = vc->vc_pos; draw_from = vc->vc_pos;
} }
@ -2416,9 +2405,8 @@ rescan_last_byte:
} }
notify_write(vc, c); notify_write(vc, c);
if (inverse) { if (inverse)
FLUSH con_flush(vc, draw_from, draw_to, &draw_x);
}
if (rescan) { if (rescan) {
rescan = 0; rescan = 0;
@ -2429,15 +2417,14 @@ rescan_last_byte:
} }
continue; continue;
} }
FLUSH con_flush(vc, draw_from, draw_to, &draw_x);
do_con_trol(tty, vc, orig); do_con_trol(tty, vc, orig);
} }
FLUSH con_flush(vc, draw_from, draw_to, &draw_x);
console_conditional_schedule(); console_conditional_schedule();
console_unlock(); console_unlock();
notify_update(vc); notify_update(vc);
return n; return n;
#undef FLUSH
} }
/* /*
@ -2471,7 +2458,7 @@ static void console_callback(struct work_struct *ignored)
if (scrollback_delta) { if (scrollback_delta) {
struct vc_data *vc = vc_cons[fg_console].d; struct vc_data *vc = vc_cons[fg_console].d;
clear_selection(); clear_selection();
if (vc->vc_mode == KD_TEXT) if (vc->vc_mode == KD_TEXT && vc->vc_sw->con_scrolldelta)
vc->vc_sw->con_scrolldelta(vc, scrollback_delta); vc->vc_sw->con_scrolldelta(vc, scrollback_delta);
scrollback_delta = 0; scrollback_delta = 0;
} }
@ -2583,7 +2570,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
goto quit; goto quit;
/* undraw cursor first */ /* undraw cursor first */
if (IS_FG(vc)) if (con_is_fg(vc))
hide_cursor(vc); hide_cursor(vc);
start = (ushort *)vc->vc_pos; start = (ushort *)vc->vc_pos;
@ -2594,7 +2581,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
c = *b++; c = *b++;
if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) { if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
if (cnt > 0) { if (cnt > 0) {
if (CON_IS_VISIBLE(vc)) if (con_is_visible(vc))
vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x); vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
vc->vc_x += cnt; vc->vc_x += cnt;
if (vc->vc_need_wrap) if (vc->vc_need_wrap)
@ -2626,7 +2613,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
myx++; myx++;
} }
if (cnt > 0) { if (cnt > 0) {
if (CON_IS_VISIBLE(vc)) if (con_is_visible(vc))
vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x); vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
vc->vc_x += cnt; vc->vc_x += cnt;
if (vc->vc_x == vc->vc_cols) { if (vc->vc_x == vc->vc_cols) {
@ -3173,7 +3160,7 @@ static int do_bind_con_driver(const struct consw *csw, int first, int last,
j = i; j = i;
if (CON_IS_VISIBLE(vc)) { if (con_is_visible(vc)) {
k = i; k = i;
save_screen(vc); save_screen(vc);
} }
@ -3981,7 +3968,7 @@ static void set_palette(struct vc_data *vc)
{ {
WARN_CONSOLE_UNLOCKED(); WARN_CONSOLE_UNLOCKED();
if (vc->vc_mode != KD_GRAPHICS) if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_set_palette)
vc->vc_sw->con_set_palette(vc, color_table); vc->vc_sw->con_set_palette(vc, color_table);
} }

View file

@ -1006,16 +1006,10 @@ int vt_ioctl(struct tty_struct *tty,
break; break;
case PIO_UNIMAPCLR: case PIO_UNIMAPCLR:
{ struct unimapinit ui;
if (!perm) if (!perm)
return -EPERM; return -EPERM;
ret = copy_from_user(&ui, up, sizeof(struct unimapinit)); con_clear_unimap(vc);
if (ret)
ret = -EFAULT;
else
con_clear_unimap(vc, &ui);
break; break;
}
case PIO_UNIMAP: case PIO_UNIMAP:
case GIO_UNIMAP: case GIO_UNIMAP:

View file

@ -1285,18 +1285,22 @@ int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
} }
int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
u32 dest, int length, size_t *bytes_written) u32 dest, int length)
{ {
size_t dummy;
return sisusb_write_mem_bulk(sisusb, dest, src, length, return sisusb_write_mem_bulk(sisusb, dest, src, length,
NULL, 0, bytes_written); NULL, 0, &dummy);
} }
#ifdef SISUSBENDIANTEST #ifdef SISUSBENDIANTEST
int sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest, static int sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest,
u32 src, int length, size_t *bytes_written) u32 src, int length)
{ {
size_t dummy;
return sisusb_read_mem_bulk(sisusb, src, dest, length, return sisusb_read_mem_bulk(sisusb, src, dest, length,
NULL, bytes_written); NULL, &dummy);
} }
#endif #endif
#endif #endif
@ -1306,16 +1310,14 @@ static void sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
{ {
static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
char destbuffer[10]; char destbuffer[10];
size_t dummy;
int i, j; int i, j;
sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy); sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7);
for (i = 1; i <= 7; i++) { for (i = 1; i <= 7; i++) {
dev_dbg(&sisusb->sisusb_dev->dev, dev_dbg(&sisusb->sisusb_dev->dev,
"sisusb: rwtest %d bytes\n", i); "sisusb: rwtest %d bytes\n", i);
sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i);
i, &dummy);
for (j = 0; j < i; j++) { for (j = 0; j < i; j++) {
dev_dbg(&sisusb->sisusb_dev->dev, dev_dbg(&sisusb->sisusb_dev->dev,
"rwtest read[%d] = %x\n", "rwtest read[%d] = %x\n",
@ -2276,7 +2278,6 @@ int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
const struct font_desc *myfont; const struct font_desc *myfont;
u8 *tempbuf; u8 *tempbuf;
u16 *tempbufb; u16 *tempbufb;
size_t written;
static const char bootstring[] = static const char bootstring[] =
"SiSUSB VGA text console, (C) 2005 Thomas Winischhofer."; "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer.";
static const char bootlogo[] = "(o_ //\\ V_/_"; static const char bootlogo[] = "(o_ //\\ V_/_";
@ -2343,18 +2344,15 @@ int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
*(tempbufb++) = 0x0700 | bootstring[i++]; *(tempbufb++) = 0x0700 | bootstring[i++];
ret |= sisusb_copy_memory(sisusb, tempbuf, ret |= sisusb_copy_memory(sisusb, tempbuf,
sisusb->vrambase, 8192, &written); sisusb->vrambase, 8192);
vfree(tempbuf); vfree(tempbuf);
} }
} else if (sisusb->scrbuf) { } else if (sisusb->scrbuf) {
ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf, ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf,
sisusb->vrambase, sisusb->scrbuf_size, sisusb->vrambase, sisusb->scrbuf_size);
&written);
} }
if (sisusb->sisusb_cursor_size_from >= 0 && if (sisusb->sisusb_cursor_size_from >= 0 &&

View file

@ -370,7 +370,6 @@ static void
sisusbcon_putc(struct vc_data *c, int ch, int y, int x) sisusbcon_putc(struct vc_data *c, int ch, int y, int x)
{ {
struct sisusb_usb_data *sisusb; struct sisusb_usb_data *sisusb;
ssize_t written;
sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
if (!sisusb) if (!sisusb)
@ -384,7 +383,7 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x)
sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y),
(long)SISUSB_HADDR(x, y), 2, &written); (long)SISUSB_HADDR(x, y), 2);
mutex_unlock(&sisusb->lock); mutex_unlock(&sisusb->lock);
} }
@ -395,7 +394,6 @@ sisusbcon_putcs(struct vc_data *c, const unsigned short *s,
int count, int y, int x) int count, int y, int x)
{ {
struct sisusb_usb_data *sisusb; struct sisusb_usb_data *sisusb;
ssize_t written;
u16 *dest; u16 *dest;
int i; int i;
@ -420,7 +418,7 @@ sisusbcon_putcs(struct vc_data *c, const unsigned short *s,
} }
sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y),
(long)SISUSB_HADDR(x, y), count * 2, &written); (long)SISUSB_HADDR(x, y), count * 2);
mutex_unlock(&sisusb->lock); mutex_unlock(&sisusb->lock);
} }
@ -431,7 +429,6 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width)
{ {
struct sisusb_usb_data *sisusb; struct sisusb_usb_data *sisusb;
u16 eattr = c->vc_video_erase_char; u16 eattr = c->vc_video_erase_char;
ssize_t written;
int i, length, cols; int i, length, cols;
u16 *dest; u16 *dest;
@ -475,41 +472,7 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width)
sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y), sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y),
(long)SISUSB_HADDR(x, y), length, &written); (long)SISUSB_HADDR(x, y), length);
mutex_unlock(&sisusb->lock);
}
/* Interface routine */
static void
sisusbcon_bmove(struct vc_data *c, int sy, int sx,
int dy, int dx, int height, int width)
{
struct sisusb_usb_data *sisusb;
ssize_t written;
int cols, length;
if (width <= 0 || height <= 0)
return;
sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
if (!sisusb)
return;
/* sisusb->lock is down */
cols = sisusb->sisusb_num_columns;
if (sisusb_is_inactive(c, sisusb)) {
mutex_unlock(&sisusb->lock);
return;
}
length = ((height * cols) - dx - (cols - width - dx)) * 2;
sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(dx, dy),
(long)SISUSB_HADDR(dx, dy), length, &written);
mutex_unlock(&sisusb->lock); mutex_unlock(&sisusb->lock);
} }
@ -519,7 +482,6 @@ static int
sisusbcon_switch(struct vc_data *c) sisusbcon_switch(struct vc_data *c)
{ {
struct sisusb_usb_data *sisusb; struct sisusb_usb_data *sisusb;
ssize_t written;
int length; int length;
/* Returnvalue 0 means we have fully restored screen, /* Returnvalue 0 means we have fully restored screen,
@ -559,7 +521,7 @@ sisusbcon_switch(struct vc_data *c)
sisusb_copy_memory(sisusb, (unsigned char *)c->vc_origin, sisusb_copy_memory(sisusb, (unsigned char *)c->vc_origin,
(long)SISUSB_HADDR(0, 0), (long)SISUSB_HADDR(0, 0),
length, &written); length);
mutex_unlock(&sisusb->lock); mutex_unlock(&sisusb->lock);
@ -600,7 +562,7 @@ sisusbcon_save_screen(struct vc_data *c)
} }
/* interface routine */ /* interface routine */
static int static void
sisusbcon_set_palette(struct vc_data *c, const unsigned char *table) sisusbcon_set_palette(struct vc_data *c, const unsigned char *table)
{ {
struct sisusb_usb_data *sisusb; struct sisusb_usb_data *sisusb;
@ -608,18 +570,18 @@ sisusbcon_set_palette(struct vc_data *c, const unsigned char *table)
/* Return value not used by vt */ /* Return value not used by vt */
if (!CON_IS_VISIBLE(c)) if (!con_is_visible(c))
return -EINVAL; return;
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 -EINVAL; return;
/* 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 -EINVAL; return;
} }
for (i = j = 0; i < 16; i++) { for (i = j = 0; i < 16; i++) {
@ -634,8 +596,6 @@ sisusbcon_set_palette(struct vc_data *c, const unsigned char *table)
} }
mutex_unlock(&sisusb->lock); mutex_unlock(&sisusb->lock);
return 0;
} }
/* interface routine */ /* interface routine */
@ -644,7 +604,6 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch)
{ {
struct sisusb_usb_data *sisusb; struct sisusb_usb_data *sisusb;
u8 sr1, cr17, pmreg, cr63; u8 sr1, cr17, pmreg, cr63;
ssize_t written;
int ret = 0; int ret = 0;
sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num); sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num);
@ -672,7 +631,7 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch)
(unsigned char *)c->vc_origin, (unsigned char *)c->vc_origin,
(u32)(sisusb->vrambase + (u32)(sisusb->vrambase +
(c->vc_origin - sisusb->scrbuf)), (c->vc_origin - sisusb->scrbuf)),
c->vc_screenbuf_size, &written); c->vc_screenbuf_size);
sisusb->con_blanked = 1; sisusb->con_blanked = 1;
ret = 1; ret = 1;
break; break;
@ -723,24 +682,22 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch)
} }
/* interface routine */ /* interface routine */
static int 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 margin = c->vc_size_row * 4;
int ul, we, p, st; int ul, we, p, st;
/* The return value does not seem to be used */
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;
/* 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;
} }
if (!lines) /* Turn scrollback off */ if (!lines) /* Turn scrollback off */
@ -780,8 +737,6 @@ sisusbcon_scrolldelta(struct vc_data *c, int lines)
sisusbcon_set_start_address(sisusb, c); sisusbcon_set_start_address(sisusb, c);
mutex_unlock(&sisusb->lock); mutex_unlock(&sisusb->lock);
return 1;
} }
/* Interface routine */ /* Interface routine */
@ -860,7 +815,6 @@ sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb,
int cols = sisusb->sisusb_num_columns; int cols = sisusb->sisusb_num_columns;
int length = ((b - t) * cols) * 2; int length = ((b - t) * cols) * 2;
u16 eattr = c->vc_video_erase_char; u16 eattr = c->vc_video_erase_char;
ssize_t written;
/* sisusb->lock is down */ /* sisusb->lock is down */
@ -890,7 +844,7 @@ sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb,
} }
sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t), sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t),
(long)SISUSB_HADDR(0, t), length, &written); (long)SISUSB_HADDR(0, t), length);
mutex_unlock(&sisusb->lock); mutex_unlock(&sisusb->lock);
@ -903,7 +857,6 @@ sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, 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;
ssize_t written;
int copyall = 0; int copyall = 0;
unsigned long oldorigin; unsigned long oldorigin;
unsigned int delta = lines * c->vc_size_row; unsigned int delta = lines * c->vc_size_row;
@ -996,18 +949,18 @@ sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
sisusb_copy_memory(sisusb, sisusb_copy_memory(sisusb,
(char *)c->vc_origin, (char *)c->vc_origin,
(u32)(sisusb->vrambase + originoffset), (u32)(sisusb->vrambase + originoffset),
c->vc_screenbuf_size, &written); c->vc_screenbuf_size);
else if (dir == SM_UP) else if (dir == SM_UP)
sisusb_copy_memory(sisusb, sisusb_copy_memory(sisusb,
(char *)c->vc_origin + c->vc_screenbuf_size - delta, (char *)c->vc_origin + c->vc_screenbuf_size - delta,
(u32)sisusb->vrambase + originoffset + (u32)sisusb->vrambase + originoffset +
c->vc_screenbuf_size - delta, c->vc_screenbuf_size - delta,
delta, &written); delta);
else else
sisusb_copy_memory(sisusb, sisusb_copy_memory(sisusb,
(char *)c->vc_origin, (char *)c->vc_origin,
(u32)(sisusb->vrambase + originoffset), (u32)(sisusb->vrambase + originoffset),
delta, &written); delta);
c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
c->vc_visible_origin = c->vc_origin; c->vc_visible_origin = c->vc_origin;
@ -1273,7 +1226,7 @@ sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
struct vc_data *vc = vc_cons[i].d; struct vc_data *vc = vc_cons[i].d;
if (vc && vc->vc_sw == &sisusb_con) { if (vc && vc->vc_sw == &sisusb_con) {
if (CON_IS_VISIBLE(vc)) { if (con_is_visible(vc)) {
vc->vc_sw->con_cursor(vc, CM_DRAW); vc->vc_sw->con_cursor(vc, CM_DRAW);
} }
vc->vc_font.height = fh; vc->vc_font.height = fh;
@ -1385,7 +1338,6 @@ static const struct consw sisusb_con = {
.con_putcs = sisusbcon_putcs, .con_putcs = sisusbcon_putcs,
.con_cursor = sisusbcon_cursor, .con_cursor = sisusbcon_cursor,
.con_scroll = sisusbcon_scroll, .con_scroll = sisusbcon_scroll,
.con_bmove = sisusbcon_bmove,
.con_switch = sisusbcon_switch, .con_switch = sisusbcon_switch,
.con_blank = sisusbcon_blank, .con_blank = sisusbcon_blank,
.con_font_set = sisusbcon_font_set, .con_font_set = sisusbcon_font_set,
@ -1433,15 +1385,12 @@ static const struct consw sisusb_dummy_con = {
.con_putcs = SISUSBCONDUMMY, .con_putcs = SISUSBCONDUMMY,
.con_cursor = SISUSBCONDUMMY, .con_cursor = SISUSBCONDUMMY,
.con_scroll = SISUSBCONDUMMY, .con_scroll = SISUSBCONDUMMY,
.con_bmove = SISUSBCONDUMMY,
.con_switch = SISUSBCONDUMMY, .con_switch = SISUSBCONDUMMY,
.con_blank = SISUSBCONDUMMY, .con_blank = SISUSBCONDUMMY,
.con_font_set = SISUSBCONDUMMY, .con_font_set = SISUSBCONDUMMY,
.con_font_get = SISUSBCONDUMMY, .con_font_get = SISUSBCONDUMMY,
.con_font_default = SISUSBCONDUMMY, .con_font_default = SISUSBCONDUMMY,
.con_font_copy = SISUSBCONDUMMY, .con_font_copy = SISUSBCONDUMMY,
.con_set_palette = SISUSBCONDUMMY,
.con_scrolldelta = SISUSBCONDUMMY,
}; };
int int

View file

@ -828,7 +828,7 @@ void sisusb_delete(struct kref *kref);
int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data); int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data);
int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 * data); int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 * data);
int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
u32 dest, int length, size_t * bytes_written); u32 dest, int length);
int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init); int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init);
int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
u8 * arg, int cmapsz, int ch512, int dorecalc, u8 * arg, int cmapsz, int ch512, int dorecalc,

View file

@ -64,14 +64,11 @@ const struct consw dummy_con = {
.con_putcs = DUMMY, .con_putcs = DUMMY,
.con_cursor = DUMMY, .con_cursor = DUMMY,
.con_scroll = DUMMY, .con_scroll = DUMMY,
.con_bmove = DUMMY,
.con_switch = DUMMY, .con_switch = DUMMY,
.con_blank = DUMMY, .con_blank = DUMMY,
.con_font_set = DUMMY, .con_font_set = DUMMY,
.con_font_get = DUMMY, .con_font_get = DUMMY,
.con_font_default = DUMMY, .con_font_default = DUMMY,
.con_font_copy = DUMMY, .con_font_copy = DUMMY,
.con_set_palette = DUMMY,
.con_scrolldelta = DUMMY,
}; };
EXPORT_SYMBOL_GPL(dummy_con); EXPORT_SYMBOL_GPL(dummy_con);

View file

@ -170,8 +170,7 @@ 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);
static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch); static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch);
static int fbcon_set_palette(struct vc_data *vc, const unsigned char *table); static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table);
static int fbcon_scrolldelta(struct vc_data *vc, int lines);
/* /*
* Internal routines * Internal routines
@ -381,7 +380,7 @@ static void fb_flashcursor(struct work_struct *work)
if (ops && ops->currcon != -1) if (ops && ops->currcon != -1)
vc = vc_cons[ops->currcon].d; vc = vc_cons[ops->currcon].d;
if (!vc || !CON_IS_VISIBLE(vc) || if (!vc || !con_is_visible(vc) ||
registered_fb[con2fb_map[vc->vc_num]] != info || registered_fb[con2fb_map[vc->vc_num]] != info ||
vc->vc_deccm != 1) { vc->vc_deccm != 1) {
console_unlock(); console_unlock();
@ -619,7 +618,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
erase, erase,
vc->vc_size_row * logo_lines); vc->vc_size_row * logo_lines);
if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) { if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) {
fbcon_clear_margins(vc, 0); fbcon_clear_margins(vc, 0);
update_screen(vc); update_screen(vc);
} }
@ -1113,7 +1112,7 @@ static void fbcon_init(struct vc_data *vc, int init)
* *
* We need to do it in fbcon_init() to prevent screen corruption. * We need to do it in fbcon_init() to prevent screen corruption.
*/ */
if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) { if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) {
if (info->fbops->fb_set_par && if (info->fbops->fb_set_par &&
!(ops->flags & FBCON_FLAGS_INIT)) { !(ops->flags & FBCON_FLAGS_INIT)) {
ret = info->fbops->fb_set_par(info); ret = info->fbops->fb_set_par(info);
@ -1193,7 +1192,7 @@ static void fbcon_deinit(struct vc_data *vc)
if (!ops) if (!ops)
goto finished; goto finished;
if (CON_IS_VISIBLE(vc)) if (con_is_visible(vc))
fbcon_del_cursor_timer(info); fbcon_del_cursor_timer(info);
ops->flags &= ~FBCON_FLAGS_INIT; ops->flags &= ~FBCON_FLAGS_INIT;
@ -1398,7 +1397,7 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
rows /= vc->vc_font.height; rows /= vc->vc_font.height;
vc_resize(vc, cols, rows); vc_resize(vc, cols, rows);
if (CON_IS_VISIBLE(vc)) { if (con_is_visible(vc)) {
update_screen(vc); update_screen(vc);
if (softback_buf) if (softback_buf)
fbcon_update_softback(vc); fbcon_update_softback(vc);
@ -2146,7 +2145,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
return -EINVAL; return -EINVAL;
DPRINTK("resize now %ix%i\n", var.xres, var.yres); DPRINTK("resize now %ix%i\n", var.xres, var.yres);
if (CON_IS_VISIBLE(vc)) { if (con_is_visible(vc)) {
var.activate = FB_ACTIVATE_NOW | var.activate = FB_ACTIVATE_NOW |
FB_ACTIVATE_FORCE; FB_ACTIVATE_FORCE;
fb_set_var(info, &var); fb_set_var(info, &var);
@ -2449,7 +2448,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
int cnt; int cnt;
char *old_data = NULL; char *old_data = NULL;
if (CON_IS_VISIBLE(vc) && softback_lines) if (con_is_visible(vc) && softback_lines)
fbcon_set_origin(vc); fbcon_set_origin(vc);
resize = (w != vc->vc_font.width) || (h != vc->vc_font.height); resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
@ -2530,9 +2529,9 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
cols /= w; cols /= w;
rows /= h; rows /= h;
vc_resize(vc, cols, rows); vc_resize(vc, cols, rows);
if (CON_IS_VISIBLE(vc) && softback_buf) if (con_is_visible(vc) && softback_buf)
fbcon_update_softback(vc); fbcon_update_softback(vc);
} else if (CON_IS_VISIBLE(vc) } else if (con_is_visible(vc)
&& vc->vc_mode == KD_TEXT) { && vc->vc_mode == KD_TEXT) {
fbcon_clear_margins(vc, 0); fbcon_clear_margins(vc, 0);
update_screen(vc); update_screen(vc);
@ -2652,17 +2651,17 @@ static struct fb_cmap palette_cmap = {
0, 16, palette_red, palette_green, palette_blue, NULL 0, 16, palette_red, palette_green, palette_blue, NULL
}; };
static int fbcon_set_palette(struct vc_data *vc, const unsigned char *table) static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table)
{ {
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
int i, j, k, depth; int i, j, k, depth;
u8 val; u8 val;
if (fbcon_is_inactive(vc, info)) if (fbcon_is_inactive(vc, info))
return -EINVAL; return;
if (!CON_IS_VISIBLE(vc)) if (!con_is_visible(vc))
return 0; return;
depth = fb_get_color_depth(&info->var, &info->fix); depth = fb_get_color_depth(&info->var, &info->fix);
if (depth > 3) { if (depth > 3) {
@ -2684,7 +2683,7 @@ static int fbcon_set_palette(struct vc_data *vc, const unsigned char *table)
} else } else
fb_copy_cmap(fb_default_cmap(1 << depth), &palette_cmap); fb_copy_cmap(fb_default_cmap(1 << depth), &palette_cmap);
return fb_set_cmap(&palette_cmap, info); fb_set_cmap(&palette_cmap, info);
} }
static u16 *fbcon_screen_pos(struct vc_data *vc, int offset) static u16 *fbcon_screen_pos(struct vc_data *vc, int offset)
@ -2765,7 +2764,7 @@ static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt)
} }
} }
static int fbcon_scrolldelta(struct vc_data *vc, int lines) static void fbcon_scrolldelta(struct vc_data *vc, int lines)
{ {
struct fb_info *info = registered_fb[con2fb_map[fg_console]]; struct fb_info *info = registered_fb[con2fb_map[fg_console]];
struct fbcon_ops *ops = info->fbcon_par; struct fbcon_ops *ops = info->fbcon_par;
@ -2774,9 +2773,9 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines)
if (softback_top) { if (softback_top) {
if (vc->vc_num != fg_console) if (vc->vc_num != fg_console)
return 0; return;
if (vc->vc_mode != KD_TEXT || !lines) if (vc->vc_mode != KD_TEXT || !lines)
return 0; return;
if (logo_shown >= 0) { if (logo_shown >= 0) {
struct vc_data *conp2 = vc_cons[logo_shown].d; struct vc_data *conp2 = vc_cons[logo_shown].d;
@ -2809,11 +2808,11 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines)
fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK); fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK);
fbcon_redraw_softback(vc, disp, lines); fbcon_redraw_softback(vc, disp, lines);
fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK); fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK);
return 0; return;
} }
if (!scrollback_phys_max) if (!scrollback_phys_max)
return -ENOSYS; return;
scrollback_old = scrollback_current; scrollback_old = scrollback_current;
scrollback_current -= lines; scrollback_current -= lines;
@ -2822,10 +2821,10 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines)
else if (scrollback_current > scrollback_max) else if (scrollback_current > scrollback_max)
scrollback_current = scrollback_max; scrollback_current = scrollback_max;
if (scrollback_current == scrollback_old) if (scrollback_current == scrollback_old)
return 0; return;
if (fbcon_is_inactive(vc, info)) if (fbcon_is_inactive(vc, info))
return 0; return;
fbcon_cursor(vc, CM_ERASE); fbcon_cursor(vc, CM_ERASE);
@ -2852,7 +2851,6 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines)
if (!scrollback_current) if (!scrollback_current)
fbcon_cursor(vc, CM_DRAW); fbcon_cursor(vc, CM_DRAW);
return 0;
} }
static int fbcon_set_origin(struct vc_data *vc) static int fbcon_set_origin(struct vc_data *vc)
@ -2904,7 +2902,7 @@ static void fbcon_modechanged(struct fb_info *info)
p = &fb_display[vc->vc_num]; p = &fb_display[vc->vc_num];
set_blitting_type(vc, info); set_blitting_type(vc, info);
if (CON_IS_VISIBLE(vc)) { if (con_is_visible(vc)) {
var_to_display(p, &info->var, info); var_to_display(p, &info->var, info);
cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
@ -2943,7 +2941,7 @@ static void fbcon_set_all_vcs(struct fb_info *info)
registered_fb[con2fb_map[i]] != info) registered_fb[con2fb_map[i]] != info)
continue; continue;
if (CON_IS_VISIBLE(vc)) { if (con_is_visible(vc)) {
fg = i; fg = i;
continue; continue;
} }
@ -3182,7 +3180,7 @@ static void fbcon_fb_blanked(struct fb_info *info, int blank)
registered_fb[con2fb_map[ops->currcon]] != info) registered_fb[con2fb_map[ops->currcon]] != info)
return; return;
if (CON_IS_VISIBLE(vc)) { if (con_is_visible(vc)) {
if (blank) if (blank)
do_blank_screen(0); do_blank_screen(0);
else else
@ -3336,7 +3334,6 @@ static const struct consw fb_con = {
.con_putcs = fbcon_putcs, .con_putcs = fbcon_putcs,
.con_cursor = fbcon_cursor, .con_cursor = fbcon_cursor,
.con_scroll = fbcon_scroll, .con_scroll = fbcon_scroll,
.con_bmove = fbcon_bmove,
.con_switch = fbcon_switch, .con_switch = fbcon_switch,
.con_blank = fbcon_blank, .con_blank = fbcon_blank,
.con_font_set = fbcon_set_font, .con_font_set = fbcon_set_font,

View file

@ -444,48 +444,11 @@ static void mdacon_clear(struct vc_data *c, int y, int x,
} }
} }
static void mdacon_bmove(struct vc_data *c, int sy, int sx,
int dy, int dx, int height, int width)
{
u16 *src, *dest;
if (width <= 0 || height <= 0)
return;
if (sx==0 && dx==0 && width==mda_num_columns) {
scr_memmovew(MDA_ADDR(0,dy), MDA_ADDR(0,sy), height*width*2);
} else if (dy < sy || (dy == sy && dx < sx)) {
src = MDA_ADDR(sx, sy);
dest = MDA_ADDR(dx, dy);
for (; height > 0; height--) {
scr_memmovew(dest, src, width*2);
src += mda_num_columns;
dest += mda_num_columns;
}
} else {
src = MDA_ADDR(sx, sy+height-1);
dest = MDA_ADDR(dx, dy+height-1);
for (; height > 0; height--) {
scr_memmovew(dest, src, width*2);
src -= mda_num_columns;
dest -= mda_num_columns;
}
}
}
static int mdacon_switch(struct vc_data *c) static int mdacon_switch(struct vc_data *c)
{ {
return 1; /* redrawing needed */ return 1; /* redrawing needed */
} }
static int mdacon_set_palette(struct vc_data *c, const unsigned char *table)
{
return -EINVAL;
}
static int mdacon_blank(struct vc_data *c, int blank, int mode_switch) static int mdacon_blank(struct vc_data *c, int blank, int mode_switch)
{ {
if (mda_type == TYPE_MDA) { if (mda_type == TYPE_MDA) {
@ -505,11 +468,6 @@ static int mdacon_blank(struct vc_data *c, int blank, int mode_switch)
} }
} }
static int mdacon_scrolldelta(struct vc_data *c, int lines)
{
return 0;
}
static void mdacon_cursor(struct vc_data *c, int mode) static void mdacon_cursor(struct vc_data *c, int mode)
{ {
if (mode == CM_ERASE) { if (mode == CM_ERASE) {
@ -574,11 +532,8 @@ static const struct consw mda_con = {
.con_putcs = mdacon_putcs, .con_putcs = mdacon_putcs,
.con_cursor = mdacon_cursor, .con_cursor = mdacon_cursor,
.con_scroll = mdacon_scroll, .con_scroll = mdacon_scroll,
.con_bmove = mdacon_bmove,
.con_switch = mdacon_switch, .con_switch = mdacon_switch,
.con_blank = mdacon_blank, .con_blank = mdacon_blank,
.con_set_palette = mdacon_set_palette,
.con_scrolldelta = mdacon_scrolldelta,
.con_build_attr = mdacon_build_attr, .con_build_attr = mdacon_build_attr,
.con_invert_region = mdacon_invert_region, .con_invert_region = mdacon_invert_region,
}; };

View file

@ -574,17 +574,6 @@ 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_set_palette(struct vc_data *vc, const unsigned char *table)
{
return -EINVAL;
}
static int newport_scrolldelta(struct vc_data *vc, int lines)
{
/* there is (nearly) no off-screen memory, so we can't scroll back */
return 0;
}
static int newport_scroll(struct vc_data *vc, int t, int b, int dir, static int newport_scroll(struct vc_data *vc, int t, int b, int dir,
int lines) int lines)
{ {
@ -684,34 +673,6 @@ static int newport_scroll(struct vc_data *vc, int t, int b, int dir,
return 1; return 1;
} }
static void newport_bmove(struct vc_data *vc, int sy, int sx, int dy,
int dx, int h, int w)
{
short xs, ys, xe, ye, xoffs, yoffs;
xs = sx << 3;
xe = ((sx + w) << 3) - 1;
/*
* as bmove is only used to move stuff around in the same line
* (h == 1), we don't care about wrap arounds caused by topscan != 0
*/
ys = ((sy << 4) + topscan) & 0x3ff;
ye = (((sy + h) << 4) - 1 + topscan) & 0x3ff;
xoffs = (dx - sx) << 3;
yoffs = (dy - sy) << 4;
if (xoffs > 0) {
/* move to the right, exchange starting points */
swap(xe, xs);
}
newport_wait(npregs);
npregs->set.drawmode0 = (NPORT_DMODE0_S2S | NPORT_DMODE0_BLOCK |
NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX
| NPORT_DMODE0_STOPY);
npregs->set.xystarti = (xs << 16) | ys;
npregs->set.xyendi = (xe << 16) | ye;
npregs->go.xymove = (xoffs << 16) | yoffs;
}
static int newport_dummy(struct vc_data *c) static int newport_dummy(struct vc_data *c)
{ {
return 0; return 0;
@ -729,13 +690,10 @@ const struct consw newport_con = {
.con_putcs = newport_putcs, .con_putcs = newport_putcs,
.con_cursor = newport_cursor, .con_cursor = newport_cursor,
.con_scroll = newport_scroll, .con_scroll = newport_scroll,
.con_bmove = newport_bmove,
.con_switch = newport_switch, .con_switch = newport_switch,
.con_blank = newport_blank, .con_blank = newport_blank,
.con_font_set = newport_font_set, .con_font_set = newport_font_set,
.con_font_default = newport_font_default, .con_font_default = newport_font_default,
.con_set_palette = newport_set_palette,
.con_scrolldelta = newport_scrolldelta,
.con_set_origin = DUMMY, .con_set_origin = DUMMY,
.con_save_screen = DUMMY .con_save_screen = DUMMY
}; };

View file

@ -79,11 +79,6 @@ static const char *sticon_startup(void)
return "STI console"; return "STI console";
} }
static int sticon_set_palette(struct vc_data *c, const unsigned char *table)
{
return -EINVAL;
}
static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos) static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos)
{ {
int redraw_cursor = 0; int redraw_cursor = 0;
@ -182,22 +177,6 @@ static int sticon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
return 0; return 0;
} }
static void sticon_bmove(struct vc_data *conp, int sy, int sx,
int dy, int dx, int height, int width)
{
if (!width || !height)
return;
#if 0
if (((sy <= p->cursor_y) && (p->cursor_y < sy+height) &&
(sx <= p->cursor_x) && (p->cursor_x < sx+width)) ||
((dy <= p->cursor_y) && (p->cursor_y < dy+height) &&
(dx <= p->cursor_x) && (p->cursor_x < dx+width)))
sticon_cursor(p, CM_ERASE /*|CM_SOFTBACK*/);
#endif
sti_bmove(sticon_sti, sy, sx, dy, dx, height, width);
}
static void sticon_init(struct vc_data *c, int init) static void sticon_init(struct vc_data *c, int init)
{ {
struct sti_struct *sti = sticon_sti; struct sti_struct *sti = sticon_sti;
@ -256,11 +235,6 @@ static int sticon_blank(struct vc_data *c, int blank, int mode_switch)
return 1; return 1;
} }
static int sticon_scrolldelta(struct vc_data *conp, int lines)
{
return 0;
}
static u16 *sticon_screen_pos(struct vc_data *conp, int offset) static u16 *sticon_screen_pos(struct vc_data *conp, int offset)
{ {
int line; int line;
@ -355,11 +329,8 @@ static const struct consw sti_con = {
.con_putcs = sticon_putcs, .con_putcs = sticon_putcs,
.con_cursor = sticon_cursor, .con_cursor = sticon_cursor,
.con_scroll = sticon_scroll, .con_scroll = sticon_scroll,
.con_bmove = sticon_bmove,
.con_switch = sticon_switch, .con_switch = sticon_switch,
.con_blank = sticon_blank, .con_blank = sticon_blank,
.con_set_palette = sticon_set_palette,
.con_scrolldelta = sticon_scrolldelta,
.con_set_origin = sticon_set_origin, .con_set_origin = sticon_set_origin,
.con_save_screen = sticon_save_screen, .con_save_screen = sticon_save_screen,
.con_build_attr = sticon_build_attr, .con_build_attr = sticon_build_attr,

View file

@ -80,7 +80,7 @@ static void vgacon_deinit(struct vc_data *c);
static void vgacon_cursor(struct vc_data *c, int mode); static void vgacon_cursor(struct vc_data *c, int mode);
static int vgacon_switch(struct vc_data *c); static int vgacon_switch(struct vc_data *c);
static int vgacon_blank(struct vc_data *c, int blank, int mode_switch); static int vgacon_blank(struct vc_data *c, int blank, int mode_switch);
static int 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, static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
@ -248,18 +248,18 @@ static void vgacon_restore_screen(struct vc_data *c)
} }
} }
static int vgacon_scrolldelta(struct vc_data *c, int lines) static void vgacon_scrolldelta(struct vc_data *c, int lines)
{ {
int start, end, count, soff; int start, end, count, soff;
if (!lines) { if (!lines) {
c->vc_visible_origin = c->vc_origin; c->vc_visible_origin = c->vc_origin;
vga_set_mem_top(c); vga_set_mem_top(c);
return 1; return;
} }
if (!vgacon_scrollback) if (!vgacon_scrollback)
return 1; return;
if (!vgacon_scrollback_save) { if (!vgacon_scrollback_save) {
vgacon_cursor(c, CM_ERASE); vgacon_cursor(c, CM_ERASE);
@ -320,8 +320,6 @@ static int vgacon_scrolldelta(struct vc_data *c, int lines)
scr_memcpyw(d, s, diff * c->vc_size_row); scr_memcpyw(d, s, diff * c->vc_size_row);
} else } else
vgacon_cursor(c, CM_MOVE); vgacon_cursor(c, CM_MOVE);
return 1;
} }
#else #else
#define vgacon_scrollback_startup(...) do { } while (0) #define vgacon_scrollback_startup(...) do { } while (0)
@ -334,7 +332,7 @@ static void vgacon_restore_screen(struct vc_data *c)
vgacon_scrolldelta(c, 0); vgacon_scrolldelta(c, 0);
} }
static int vgacon_scrolldelta(struct vc_data *c, int lines) static void vgacon_scrolldelta(struct vc_data *c, int lines)
{ {
if (!lines) /* Turn scrollback off */ if (!lines) /* Turn scrollback off */
c->vc_visible_origin = c->vc_origin; c->vc_visible_origin = c->vc_origin;
@ -362,7 +360,6 @@ static int vgacon_scrolldelta(struct vc_data *c, int lines)
c->vc_visible_origin = vga_vram_base + (p + ul) % we; c->vc_visible_origin = vga_vram_base + (p + ul) % we;
} }
vga_set_mem_top(c); vga_set_mem_top(c);
return 1;
} }
#endif /* CONFIG_VGACON_SOFT_SCROLLBACK */ #endif /* CONFIG_VGACON_SOFT_SCROLLBACK */
@ -592,7 +589,7 @@ static void vgacon_init(struct vc_data *c, int init)
static void vgacon_deinit(struct vc_data *c) static void vgacon_deinit(struct vc_data *c)
{ {
/* When closing the active console, reset video origin */ /* When closing the active console, reset video origin */
if (CON_IS_VISIBLE(c)) { if (con_is_visible(c)) {
c->vc_visible_origin = vga_vram_base; c->vc_visible_origin = vga_vram_base;
vga_set_mem_top(c); vga_set_mem_top(c);
} }
@ -859,16 +856,13 @@ static void vga_set_palette(struct vc_data *vc, const unsigned char *table)
} }
} }
static int 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 #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 -EINVAL; return;
vga_set_palette(vc, table); vga_set_palette(vc, table);
return 0;
#else
return -EINVAL;
#endif #endif
} }
@ -1254,7 +1248,7 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
struct vc_data *c = vc_cons[i].d; struct vc_data *c = vc_cons[i].d;
if (c && c->vc_sw == &vga_con) { if (c && c->vc_sw == &vga_con) {
if (CON_IS_VISIBLE(c)) { if (con_is_visible(c)) {
/* void size to cause regs to be rewritten */ /* void size to cause regs to be rewritten */
cursor_size_lastfrom = 0; cursor_size_lastfrom = 0;
cursor_size_lastto = 0; cursor_size_lastto = 0;
@ -1318,7 +1312,7 @@ static int vgacon_resize(struct vc_data *c, unsigned int width,
return success */ return success */
return (user) ? 0 : -EINVAL; return (user) ? 0 : -EINVAL;
if (CON_IS_VISIBLE(c) && !vga_is_gfx) /* who knows */ if (con_is_visible(c) && !vga_is_gfx) /* who knows */
vgacon_doresize(c, width, height); vgacon_doresize(c, width, height);
return 0; return 0;
} }
@ -1427,7 +1421,6 @@ const struct consw vga_con = {
.con_putcs = DUMMY, .con_putcs = DUMMY,
.con_cursor = vgacon_cursor, .con_cursor = vgacon_cursor,
.con_scroll = vgacon_scroll, .con_scroll = vgacon_scroll,
.con_bmove = DUMMY,
.con_switch = vgacon_switch, .con_switch = vgacon_switch,
.con_blank = vgacon_blank, .con_blank = vgacon_blank,
.con_font_set = vgacon_font_set, .con_font_set = vgacon_font_set,

View file

@ -28,6 +28,13 @@ struct tty_struct;
#define VT100ID "\033[?1;2c" #define VT100ID "\033[?1;2c"
#define VT102ID "\033[?6c" #define VT102ID "\033[?6c"
/**
* struct consw - callbacks for consoles
*
* @con_set_palette: sets the palette of the console to @table (optional)
* @con_scrolldelta: the contents of the console should be scrolled by @lines.
* Invoked by user. (optional)
*/
struct consw { struct consw {
struct module *owner; struct module *owner;
const char *(*con_startup)(void); const char *(*con_startup)(void);
@ -38,7 +45,6 @@ struct consw {
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); int (*con_scroll)(struct vc_data *, int, int, int, int);
void (*con_bmove)(struct vc_data *, int, int, int, int, int, int);
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);
@ -47,8 +53,9 @@ struct consw {
int (*con_font_copy)(struct vc_data *, int); int (*con_font_copy)(struct vc_data *, int);
int (*con_resize)(struct vc_data *, unsigned int, unsigned int, int (*con_resize)(struct vc_data *, unsigned int, unsigned int,
unsigned int); unsigned int);
int (*con_set_palette)(struct vc_data *, const unsigned char *); void (*con_set_palette)(struct vc_data *,
int (*con_scrolldelta)(struct vc_data *, int); const unsigned char *table);
void (*con_scrolldelta)(struct vc_data *, int lines);
int (*con_set_origin)(struct vc_data *); int (*con_set_origin)(struct vc_data *);
void (*con_save_screen)(struct vc_data *); void (*con_save_screen)(struct vc_data *);
u8 (*con_build_attr)(struct vc_data *, u8, u8, u8, u8, u8, u8); u8 (*con_build_attr)(struct vc_data *, u8, u8, u8, u8, u8, u8);

View file

@ -21,6 +21,38 @@ struct uni_pagedir;
#define NPAR 16 #define NPAR 16
/*
* Example: vc_data of a console that was scrolled 3 lines down.
*
* Console buffer
* vc_screenbuf ---------> +----------------------+-.
* | initializing W | \
* | initializing X | |
* | initializing Y | > scroll-back area
* | initializing Z | |
* | | /
* vc_visible_origin ---> ^+----------------------+-:
* (changes by scroll) || Welcome to linux | \
* || | |
* vc_rows --->< | login: root | | visible on console
* || password: | > (vc_screenbuf_size is
* vc_origin -----------> || | | vc_size_row * vc_rows)
* (start when no scroll) || Last login: 12:28 | /
* v+----------------------+-:
* | Have a lot of fun... | \
* vc_pos -----------------|--------v | > scroll-front area
* | ~ # cat_ | /
* vc_scr_end -----------> +----------------------+-:
* (vc_origin + | | \ EMPTY, to be filled by
* vc_screenbuf_size) | | / vc_video_erase_char
* +----------------------+-'
* <---- 2 * vc_cols ----->
* <---- vc_size_row ----->
*
* Note that every character in the console buffer is accompanied with an
* attribute in the buffer right after the character. This is not depicted
* in the figure.
*/
struct vc_data { struct vc_data {
struct tty_port port; /* Upper level data */ struct tty_port port; /* Upper level data */
@ -74,7 +106,6 @@ struct vc_data {
unsigned int vc_decawm : 1; /* Autowrap Mode */ unsigned int vc_decawm : 1; /* Autowrap Mode */
unsigned int vc_deccm : 1; /* Cursor Visible */ unsigned int vc_deccm : 1; /* Cursor Visible */
unsigned int vc_decim : 1; /* Insert Mode */ unsigned int vc_decim : 1; /* Insert Mode */
unsigned int vc_deccolm : 1; /* 80/132 Column Mode */
/* attribute flags */ /* attribute flags */
unsigned int vc_intensity : 2; /* 0=half-bright, 1=normal, 2=bold */ unsigned int vc_intensity : 2; /* 0=half-bright, 1=normal, 2=bold */
unsigned int vc_italic:1; unsigned int vc_italic:1;
@ -136,6 +167,9 @@ extern void vc_SAK(struct work_struct *work);
#define CUR_DEFAULT CUR_UNDERLINE #define CUR_DEFAULT CUR_UNDERLINE
#define CON_IS_VISIBLE(conp) (*conp->vc_display_fg == conp) static inline bool con_is_visible(const struct vc_data *vc)
{
return *vc->vc_display_fg == vc;
}
#endif /* _LINUX_CONSOLE_STRUCT_H */ #endif /* _LINUX_CONSOLE_STRUCT_H */

View file

@ -39,14 +39,22 @@ struct hsu_dma_chip {
#if IS_ENABLED(CONFIG_HSU_DMA) #if IS_ENABLED(CONFIG_HSU_DMA)
/* Export to the internal users */ /* Export to the internal users */
irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr); int hsu_dma_get_status(struct hsu_dma_chip *chip, unsigned short nr,
u32 *status);
irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip, unsigned short nr,
u32 status);
/* Export to the platform drivers */ /* Export to the platform drivers */
int hsu_dma_probe(struct hsu_dma_chip *chip); int hsu_dma_probe(struct hsu_dma_chip *chip);
int hsu_dma_remove(struct hsu_dma_chip *chip); int hsu_dma_remove(struct hsu_dma_chip *chip);
#else #else
static inline irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, static inline int hsu_dma_get_status(struct hsu_dma_chip *chip,
unsigned short nr) unsigned short nr, u32 *status)
{
return 0;
}
static inline irqreturn_t hsu_dma_do_irq(struct hsu_dma_chip *chip,
unsigned short nr, u32 status)
{ {
return IRQ_NONE; return IRQ_NONE;
} }

View file

@ -111,6 +111,7 @@ struct uart_8250_port {
* if no_console_suspend * if no_console_suspend
*/ */
unsigned char probe; unsigned char probe;
struct mctrl_gpios *gpios;
#define UART_PROBE_RSA (1 << 0) #define UART_PROBE_RSA (1 << 0)
/* /*

View file

@ -352,9 +352,15 @@ struct earlycon_id {
extern const struct earlycon_id __earlycon_table[]; extern const struct earlycon_id __earlycon_table[];
extern const struct earlycon_id __earlycon_table_end[]; extern const struct earlycon_id __earlycon_table_end[];
#if defined(CONFIG_SERIAL_EARLYCON) && !defined(MODULE)
#define EARLYCON_USED_OR_UNUSED __used
#else
#define EARLYCON_USED_OR_UNUSED __maybe_unused
#endif
#define OF_EARLYCON_DECLARE(_name, compat, fn) \ #define OF_EARLYCON_DECLARE(_name, compat, fn) \
static const struct earlycon_id __UNIQUE_ID(__earlycon_##_name) \ static const struct earlycon_id __UNIQUE_ID(__earlycon_##_name) \
__used __section(__earlycon_table) \ EARLYCON_USED_OR_UNUSED __section(__earlycon_table) \
= { .name = __stringify(_name), \ = { .name = __stringify(_name), \
.compatible = compat, \ .compatible = compat, \
.setup = fn } .setup = fn }

View file

@ -45,7 +45,7 @@ void poke_blanked_console(void);
int con_font_op(struct vc_data *vc, struct console_font_op *op); int con_font_op(struct vc_data *vc, struct console_font_op *op);
int con_set_cmap(unsigned char __user *cmap); int con_set_cmap(unsigned char __user *cmap);
int con_get_cmap(unsigned char __user *cmap); int con_get_cmap(unsigned char __user *cmap);
void scrollback(struct vc_data *vc, int lines); void scrollback(struct vc_data *vc);
void scrollfront(struct vc_data *vc, int lines); void scrollfront(struct vc_data *vc, int lines);
void clear_buffer_attributes(struct vc_data *vc); void clear_buffer_attributes(struct vc_data *vc);
void update_region(struct vc_data *vc, unsigned long start, int count); void update_region(struct vc_data *vc, unsigned long start, int count);
@ -59,14 +59,13 @@ int tioclinux(struct tty_struct *tty, unsigned long arg);
#ifdef CONFIG_CONSOLE_TRANSLATIONS #ifdef CONFIG_CONSOLE_TRANSLATIONS
/* consolemap.c */ /* consolemap.c */
struct unimapinit;
struct unipair; struct unipair;
int con_set_trans_old(unsigned char __user * table); int con_set_trans_old(unsigned char __user * table);
int con_get_trans_old(unsigned char __user * table); int con_get_trans_old(unsigned char __user * table);
int con_set_trans_new(unsigned short __user * table); int con_set_trans_new(unsigned short __user * table);
int con_get_trans_new(unsigned short __user * table); int con_get_trans_new(unsigned short __user * table);
int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui); int con_clear_unimap(struct vc_data *vc);
int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list); int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list);
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 con_set_default_unimap(struct vc_data *vc); int con_set_default_unimap(struct vc_data *vc);
@ -92,7 +91,7 @@ static inline int con_get_trans_new(unsigned short __user *table)
{ {
return -EINVAL; return -EINVAL;
} }
static inline int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) static inline int con_clear_unimap(struct vc_data *vc)
{ {
return 0; return 0;
} }

View file

@ -246,9 +246,6 @@ static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self,
{ {
struct serial_struct info; struct serial_struct info;
if (!retinfo)
return -EFAULT;
memset(&info, 0, sizeof(info)); memset(&info, 0, sizeof(info));
info.line = self->line; info.line = self->line;
info.flags = self->port.flags; info.flags = self->port.flags;
@ -258,11 +255,6 @@ static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self,
/* For compatibility */ /* For compatibility */
info.type = PORT_16550A; info.type = PORT_16550A;
info.port = 0;
info.irq = 0;
info.xmit_fifo_size = 0;
info.hub6 = 0;
info.custom_divisor = 0;
if (copy_to_user(retinfo, &info, sizeof(*retinfo))) if (copy_to_user(retinfo, &info, sizeof(*retinfo)))
return -EFAULT; return -EFAULT;