// SPDX-License-Identifier: GPL-2.0/* * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1998-1999 Pete Zaitcev (zaitcev@yahoo.com) * * This is mainly a variation of 8250.c, credits go to authors mentioned * therein. In fact this driver should be merged into the generic 8250.c * infrastructure perhaps using a 8250_sparc.c module. * * Fixed to use tty_get_baud_rate(). * Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12 * * Converted to new 2.5.x UART layer. * David S. Miller (davem@davemloft.net), 2002-Jul-29 */ #include <linux/module.h>#include <linux/kernel.h>#include <linux/spinlock.h>#include <linux/errno.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/major.h>#include <linux/string.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/circ_buf.h>#include <linux/serial.h>#include <linux/sysrq.h>#include <linux/console.h>#include <linux/slab.h>#ifdef CONFIG_SERIO#include <linux/serio.h>#endif#include <linux/serial_reg.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/of.h>#include <linux/platform_device.h> #include <linux/io.h>#include <asm/irq.h>#include <asm/setup.h> #include <linux/serial_core.h>#include <linux/sunserialcore.h> /* We are on a NS PC87303 clocked with 24.0 MHz, which results * in a UART clock of 1.8462 MHz. */#define SU_BASE_BAUD (1846200 / 16) enum su_type { SU_PORT_NONE, SU_PORT_MS, SU_PORT_KBD, SU_PORT_PORT };static char *su_typev[] = { "su(???)", "su(mouse)", "su(kbd)", "su(serial)" }; struct serial_uart_config { char *name; int dfl_xmit_fifo_size; int flags;}; /* * Here we define the default xmit fifo size used for each type of UART. */static const struct serial_uart_config uart_config[] = { { "unknown", 1, 0 }, { "8250", 1, 0 }, { "16450", 1, 0 }, { "16550", 1, 0 }, { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, { "Cirrus", 1, 0 }, { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO }, { "Startech", 1, 0 }, { "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO }, { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO }}; struct uart_sunsu_port { struct uart_port port; unsigned char acr; unsigned char ier; unsigned short rev; unsigned char lcr; unsigned int lsr_break_flag; unsigned int cflag; /* Probing information. */ enum su_type su_type; unsigned int type_probed; /* XXX Stupid */ unsigned long reg_size; #ifdef CONFIG_SERIO struct serio serio; int serio_open;#endif}; static unsigned int serial_in(struct uart_sunsu_port *up, int offset){ offset <<= up->port.regshift; switch (up->port.iotype) { case UPIO_HUB6: outb(up->port.hub6 - 1 + offset, up->port.iobase); return inb(up->port.iobase + 1); case UPIO_MEM: return readb(up->port.membase + offset); default: return inb(up->port.iobase + offset); }} static void serial_out(struct uart_sunsu_port *up, int offset, int value){#ifndef CONFIG_SPARC64 /* * MrCoffee has weird schematics: IRQ4 & P10(?) pins of SuperIO are * connected with a gate then go to SlavIO. When IRQ4 goes tristated * gate outputs a logical one. Since we use level triggered interrupts * we have lockup and watchdog reset. We cannot mask IRQ because * keyboard shares IRQ with us (Word has it as Bob Smelik's design). * This problem is similar to what Alpha people suffer, see * 8250_alpha.c. */ if (offset == UART_MCR) value |= UART_MCR_OUT2;#endif offset <<= up->port.regshift; switch (up->port.iotype) { case UPIO_HUB6: outb(up->port.hub6 - 1 + offset, up->port.iobase); outb(value, up->port.iobase + 1); break; case UPIO_MEM: writeb(value, up->port.membase + offset); break; default: outb(value, up->port.iobase + offset); }} /* * For the 16C950 */static void serial_icr_write(struct uart_sunsu_port *up, int offset, int value){ serial_out(up, UART_SCR, offset); serial_out(up, UART_ICR, value);} #ifdef CONFIG_SERIAL_8250_RSA/* * Attempts to turn on the RSA FIFO. Returns zero on failure. * We set the port uart clock rate if we succeed. */static int __enable_rsa(struct uart_sunsu_port *up){ unsigned char mode; int result; mode = serial_in(up, UART_RSA_MSR); result = mode & UART_RSA_MSR_FIFO; if (!result) { serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); mode = serial_in(up, UART_RSA_MSR); result = mode & UART_RSA_MSR_FIFO; } if (result) up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16; return result;} static void enable_rsa(struct uart_sunsu_port *up){ if (up->port.type == PORT_RSA) { if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { uart_port_lock_irq(&up->port); __enable_rsa(up); uart_port_unlock_irq(&up->port); } if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) serial_out(up, UART_RSA_FRR, 0); }} /* * Attempts to turn off the RSA FIFO. Returns zero on failure. * It is unknown why interrupts were disabled in here. However, * the caller is expected to preserve this behaviour by grabbing * the spinlock before calling this function. */static void disable_rsa(struct uart_sunsu_port *up){ unsigned char mode; int result; if (up->port.type == PORT_RSA && up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { uart_port_lock_irq(&up->port); mode = serial_in(up, UART_RSA_MSR); result = !(mode & UART_RSA_MSR_FIFO); if (!result) { serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); mode = serial_in(up, UART_RSA_MSR); result = !(mode & UART_RSA_MSR_FIFO); } if (result) up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; uart_port_unlock_irq(&up->port); }}#endif /* CONFIG_SERIAL_8250_RSA */ static inline void __stop_tx(struct uart_sunsu_port *p){ if (p->ier & UART_IER_THRI) { p->ier &= ~UART_IER_THRI; serial_out(p, UART_IER, p->ier); }} static void sunsu_stop_tx(struct uart_port *port){ struct uart_sunsu_port *up = container_of(port, struct uart_sunsu_port, port); __stop_tx(up); /* * We really want to stop the transmitter from sending. */ if (up->port.type == PORT_16C950) { up->acr |= UART_ACR_TXDIS; serial_icr_write(up, UART_ACR, up->acr); }} static void sunsu_start_tx(struct uart_port *port){ struct uart_sunsu_port *up = container_of(port, struct uart_sunsu_port, port); if (!(up->ier & UART_IER_THRI)) { up->ier |= UART_IER_THRI; serial_out(up, UART_IER, up->ier); } /* * Re-enable the transmitter if we disabled it. */ if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) { up->acr &= ~UART_ACR_TXDIS; serial_icr_write(up, UART_ACR, up->acr); }} static void sunsu_stop_rx(struct uart_port *port){ struct uart_sunsu_port *up = container_of(port, struct uart_sunsu_port, port); up->ier &= ~UART_IER_RLSI; up->port.read_status_mask &= ~UART_LSR_DR; serial_out(up, UART_IER, up->ier);} static void sunsu_enable_ms(struct uart_port *port){ struct uart_sunsu_port *up = container_of(port, struct uart_sunsu_port, port); unsigned long flags; uart_port_lock_irqsave(&up->port, &flags); up->ier |= UART_IER_MSI; serial_out(up, UART_IER, up->ier); uart_port_unlock_irqrestore(&up->port, flags);} static voidreceive_chars(struct uart_sunsu_port *up, unsigned char *status){ struct tty_port *port = &up->port.state->port; unsigned char ch, flag; int max_count = 256; int saw_console_brk = 0; do { ch = serial_in(up, UART_RX); flag = TTY_NORMAL; up->port.icount.rx++; if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | UART_LSR_FE | UART_LSR_OE))) { /* * For statistics only */ if (*status & UART_LSR_BI) { *status &= ~(UART_LSR_FE | UART_LSR_PE); up->port.icount.brk++; if (up->port.cons != NULL && up->port.line == up->port.cons->index) saw_console_brk = 1; /* * We do the SysRQ and SAK checking * here because otherwise the break * may get masked by ignore_status_mask * or read_status_mask. */ if (uart_handle_break(&up->port)) goto ignore_char; } else if (*status & UART_LSR_PE) up->port.icount.parity++; else if (*status & UART_LSR_FE) up->port.icount.frame++; if (*status & UART_LSR_OE) up->port.icount.overrun++; /* * Mask off conditions which should be ingored. */ *status &= up->port.read_status_mask; if (up->port.cons != NULL && up->port.line == up->port.cons->index) { /* Recover the break flag from console xmit */ *status |= up->lsr_break_flag; up->lsr_break_flag = 0; } if (*status & UART_LSR_BI) { flag = TTY_BREAK; } else if (*status & UART_LSR_PE) flag = TTY_PARITY; else if (*status & UART_LSR_FE) flag = TTY_FRAME; } if (uart_handle_sysrq_char(&up->port, ch)) goto ignore_char; if ((*status & up->port.ignore_status_mask) == 0) tty_insert_flip_char(port, ch, flag); if (*status & UART_LSR_OE) /* * Overrun is special, since it's reported * immediately, and doesn't affect the current * character. */ tty_insert_flip_char(port, 0, TTY_OVERRUN); ignore_char: *status = serial_in(up, UART_LSR); } while ((*status & UART_LSR_DR) && (max_count-- > 0)); if (saw_console_brk) sun_do_break();} static void transmit_chars(struct uart_sunsu_port *up){ struct tty_port *tport = &up->port.state->port; unsigned char ch; int count; if (up->port.x_char) { serial_out(up, UART_TX, up->port.x_char); up->port.icount.tx++; up->port.x_char = 0; return; } if (uart_tx_stopped(&up->port)) { sunsu_stop_tx(&up->port); return; } if (kfifo_is_empty(&tport->xmit_fifo)) { __stop_tx(up); return; } count = up->port.fifosize; do { if (!uart_fifo_get(&up->port, &ch)) break; serial_out(up, UART_TX, ch); } while (--count > 0); if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&up->port); if (kfifo_is_empty(&tport->xmit_fifo)) __stop_tx(up);} static void check_modem_status(struct uart_sunsu_port *up){ int status; status = serial_in(up, UART_MSR); if ((status & UART_MSR_ANY_DELTA) == 0) return; if (status & UART_MSR_TERI) up->port.icount.rng++; if (status & UART_MSR_DDSR) up->port.icount.dsr++; if (status & UART_MSR_DDCD) uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); if (status & UART_MSR_DCTS) uart_handle_cts_change(&up->port, status & UART_MSR_CTS); wake_up_interruptible(&up->port.state->port.delta_msr_wait);} static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id){ struct uart_sunsu_port *up = dev_id; unsigned long flags; unsigned char status; uart_port_lock_irqsave(&up->port, &flags); do { status = serial_in(up, UART_LSR); if (status & UART_LSR_DR) receive_chars(up, &status); check_modem_status(up); if (status & UART_LSR_THRE) transmit_chars(up); tty_flip_buffer_push(&up->port.state->port); } while (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)); uart_port_unlock_irqrestore(&up->port, flags); return IRQ_HANDLED;} /* Separate interrupt handling path for keyboard/mouse ports. */ static voidsunsu_change_speed(struct uart_port *port, unsigned int cflag, unsigned int iflag, unsigned int quot); static void sunsu_change_mouse_baud(struct uart_sunsu_port *up){ unsigned int cur_cflag = up->cflag; int quot, new_baud; up->cflag &= ~CBAUD; up->cflag |= suncore_mouse_baud_cflag_next(cur_cflag, &new_baud); quot = up->port.uartclk / (16 * new_baud); sunsu_change_speed(&up->port, up->cflag, 0, quot);} static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break){ do { unsigned char ch = serial_in(up, UART_RX); /* Stop-A is handled by drivers/char/keyboard.c now. */ if (up->su_type == SU_PORT_KBD) {#ifdef CONFIG_SERIO serio_interrupt(&up->serio, ch, 0);#endif } else if (up->su_type == SU_PORT_MS) { int ret = suncore_mouse_baud_detection(ch, is_break); switch (ret) { case 2: sunsu_change_mouse_baud(up); fallthrough; case 1: break; case 0:#ifdef CONFIG_SERIO serio_interrupt(&up->serio, ch, 0);#endif break; } }Lines 1–500 of 1584. Load more
// SPDX-License-Identifier: GPL-2.0 /* * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1998-1999 Pete Zaitcev (zaitcev@yahoo.com) * * This is mainly a variation of 8250.c, credits go to authors mentioned * therein. In fact this driver should be merged into the generic 8250.c * infrastructure perhaps using a 8250_sparc.c module. * * Fixed to use tty_get_baud_rate(). * Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12 * * Converted to new 2.5.x UART layer. * David S. Miller (davem@davemloft.net), 2002-Jul-29 */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/spinlock.h> #include <linux/errno.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/major.h> #include <linux/string.h> #include <linux/ptrace.h> #include <linux/ioport.h> #include <linux/circ_buf.h> #include <linux/serial.h> #include <linux/sysrq.h> #include <linux/console.h> #include <linux/slab.h> #ifdef CONFIG_SERIO #include <linux/serio.h> #endif #include <linux/serial_reg.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/io.h> #include <asm/irq.h> #include <asm/setup.h> #include <linux/serial_core.h> #include <linux/sunserialcore.h> /* We are on a NS PC87303 clocked with 24.0 MHz, which results * in a UART clock of 1.8462 MHz. */ #define SU_BASE_BAUD (1846200 / 16) enum su_type { SU_PORT_NONE, SU_PORT_MS, SU_PORT_KBD, SU_PORT_PORT }; static char *su_typev[] = { "su(???)", "su(mouse)", "su(kbd)", "su(serial)" }; struct serial_uart_config { char *name; int dfl_xmit_fifo_size; int flags; }; /* * Here we define the default xmit fifo size used for each type of UART. */ static const struct serial_uart_config uart_config[] = { { "unknown", 1, 0 }, { "8250", 1, 0 }, { "16450", 1, 0 }, { "16550", 1, 0 }, { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, { "Cirrus", 1, 0 }, { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO }, { "Startech", 1, 0 }, { "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO }, { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO } }; struct uart_sunsu_port { struct uart_port port; unsigned char acr; unsigned char ier; unsigned short rev; unsigned char lcr; unsigned int lsr_break_flag; unsigned int cflag; /* Probing information. */ enum su_type su_type; unsigned int type_probed; /* XXX Stupid */ unsigned long reg_size; #ifdef CONFIG_SERIO struct serio serio; int serio_open; #endif }; static unsigned int serial_in(struct uart_sunsu_port *up, int offset) { offset <<= up->port.regshift; switch (up->port.iotype) { case UPIO_HUB6: outb(up->port.hub6 - 1 + offset, up->port.iobase); return inb(up->port.iobase + 1); case UPIO_MEM: return readb(up->port.membase + offset); default: return inb(up->port.iobase + offset); } } static void serial_out(struct uart_sunsu_port *up, int offset, int value) { #ifndef CONFIG_SPARC64 /* * MrCoffee has weird schematics: IRQ4 & P10(?) pins of SuperIO are * connected with a gate then go to SlavIO. When IRQ4 goes tristated * gate outputs a logical one. Since we use level triggered interrupts * we have lockup and watchdog reset. We cannot mask IRQ because * keyboard shares IRQ with us (Word has it as Bob Smelik's design). * This problem is similar to what Alpha people suffer, see * 8250_alpha.c. */ if (offset == UART_MCR) value |= UART_MCR_OUT2; #endif offset <<= up->port.regshift; switch (up->port.iotype) { case UPIO_HUB6: outb(up->port.hub6 - 1 + offset, up->port.iobase); outb(value, up->port.iobase + 1); break; case UPIO_MEM: writeb(value, up->port.membase + offset); break; default: outb(value, up->port.iobase + offset); } } /* * For the 16C950 */ static void serial_icr_write(struct uart_sunsu_port *up, int offset, int value) { serial_out(up, UART_SCR, offset); serial_out(up, UART_ICR, value); } #ifdef CONFIG_SERIAL_8250_RSA /* * Attempts to turn on the RSA FIFO. Returns zero on failure. * We set the port uart clock rate if we succeed. */ static int __enable_rsa(struct uart_sunsu_port *up) { unsigned char mode; int result; mode = serial_in(up, UART_RSA_MSR); result = mode & UART_RSA_MSR_FIFO; if (!result) { serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); mode = serial_in(up, UART_RSA_MSR); result = mode & UART_RSA_MSR_FIFO; } if (result) up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16; return result; } static void enable_rsa(struct uart_sunsu_port *up) { if (up->port.type == PORT_RSA) { if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { uart_port_lock_irq(&up->port); __enable_rsa(up); uart_port_unlock_irq(&up->port); } if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) serial_out(up, UART_RSA_FRR, 0); } } /* * Attempts to turn off the RSA FIFO. Returns zero on failure. * It is unknown why interrupts were disabled in here. However, * the caller is expected to preserve this behaviour by grabbing * the spinlock before calling this function. */ static void disable_rsa(struct uart_sunsu_port *up) { unsigned char mode; int result; if (up->port.type == PORT_RSA && up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { uart_port_lock_irq(&up->port); mode = serial_in(up, UART_RSA_MSR); result = !(mode & UART_RSA_MSR_FIFO); if (!result) { serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); mode = serial_in(up, UART_RSA_MSR); result = !(mode & UART_RSA_MSR_FIFO); } if (result) up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; uart_port_unlock_irq(&up->port); } } #endif /* CONFIG_SERIAL_8250_RSA */ static inline void __stop_tx(struct uart_sunsu_port *p) { if (p->ier & UART_IER_THRI) { p->ier &= ~UART_IER_THRI; serial_out(p, UART_IER, p->ier); } } static void sunsu_stop_tx(struct uart_port *port) { struct uart_sunsu_port *up = container_of(port, struct uart_sunsu_port, port); __stop_tx(up); /* * We really want to stop the transmitter from sending. */ if (up->port.type == PORT_16C950) { up->acr |= UART_ACR_TXDIS; serial_icr_write(up, UART_ACR, up->acr); } } static void sunsu_start_tx(struct uart_port *port) { struct uart_sunsu_port *up = container_of(port, struct uart_sunsu_port, port); if (!(up->ier & UART_IER_THRI)) { up->ier |= UART_IER_THRI; serial_out(up, UART_IER, up->ier); } /* * Re-enable the transmitter if we disabled it. */ if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) { up->acr &= ~UART_ACR_TXDIS; serial_icr_write(up, UART_ACR, up->acr); } } static void sunsu_stop_rx(struct uart_port *port) { struct uart_sunsu_port *up = container_of(port, struct uart_sunsu_port, port); up->ier &= ~UART_IER_RLSI; up->port.read_status_mask &= ~UART_LSR_DR; serial_out(up, UART_IER, up->ier); } static void sunsu_enable_ms(struct uart_port *port) { struct uart_sunsu_port *up = container_of(port, struct uart_sunsu_port, port); unsigned long flags; uart_port_lock_irqsave(&up->port, &flags); up->ier |= UART_IER_MSI; serial_out(up, UART_IER, up->ier); uart_port_unlock_irqrestore(&up->port, flags); } static void receive_chars(struct uart_sunsu_port *up, unsigned char *status) { struct tty_port *port = &up->port.state->port; unsigned char ch, flag; int max_count = 256; int saw_console_brk = 0; do { ch = serial_in(up, UART_RX); flag = TTY_NORMAL; up->port.icount.rx++; if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | UART_LSR_FE | UART_LSR_OE))) { /* * For statistics only */ if (*status & UART_LSR_BI) { *status &= ~(UART_LSR_FE | UART_LSR_PE); up->port.icount.brk++; if (up->port.cons != NULL && up->port.line == up->port.cons->index) saw_console_brk = 1; /* * We do the SysRQ and SAK checking * here because otherwise the break * may get masked by ignore_status_mask * or read_status_mask. */ if (uart_handle_break(&up->port)) goto ignore_char; } else if (*status & UART_LSR_PE) up->port.icount.parity++; else if (*status & UART_LSR_FE) up->port.icount.frame++; if (*status & UART_LSR_OE) up->port.icount.overrun++; /* * Mask off conditions which should be ingored. */ *status &= up->port.read_status_mask; if (up->port.cons != NULL && up->port.line == up->port.cons->index) { /* Recover the break flag from console xmit */ *status |= up->lsr_break_flag; up->lsr_break_flag = 0; } if (*status & UART_LSR_BI) { flag = TTY_BREAK; } else if (*status & UART_LSR_PE) flag = TTY_PARITY; else if (*status & UART_LSR_FE) flag = TTY_FRAME; } if (uart_handle_sysrq_char(&up->port, ch)) goto ignore_char; if ((*status & up->port.ignore_status_mask) == 0) tty_insert_flip_char(port, ch, flag); if (*status & UART_LSR_OE) /* * Overrun is special, since it's reported * immediately, and doesn't affect the current * character. */ tty_insert_flip_char(port, 0, TTY_OVERRUN); ignore_char: *status = serial_in(up, UART_LSR); } while ((*status & UART_LSR_DR) && (max_count-- > 0)); if (saw_console_brk) sun_do_break(); } static void transmit_chars(struct uart_sunsu_port *up) { struct tty_port *tport = &up->port.state->port; unsigned char ch; int count; if (up->port.x_char) { serial_out(up, UART_TX, up->port.x_char); up->port.icount.tx++; up->port.x_char = 0; return; } if (uart_tx_stopped(&up->port)) { sunsu_stop_tx(&up->port); return; } if (kfifo_is_empty(&tport->xmit_fifo)) { __stop_tx(up); return; } count = up->port.fifosize; do { if (!uart_fifo_get(&up->port, &ch)) break; serial_out(up, UART_TX, ch); } while (--count > 0); if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&up->port); if (kfifo_is_empty(&tport->xmit_fifo)) __stop_tx(up); } static void check_modem_status(struct uart_sunsu_port *up) { int status; status = serial_in(up, UART_MSR); if ((status & UART_MSR_ANY_DELTA) == 0) return; if (status & UART_MSR_TERI) up->port.icount.rng++; if (status & UART_MSR_DDSR) up->port.icount.dsr++; if (status & UART_MSR_DDCD) uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); if (status & UART_MSR_DCTS) uart_handle_cts_change(&up->port, status & UART_MSR_CTS); wake_up_interruptible(&up->port.state->port.delta_msr_wait); } static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id) { struct uart_sunsu_port *up = dev_id; unsigned long flags; unsigned char status; uart_port_lock_irqsave(&up->port, &flags); do { status = serial_in(up, UART_LSR); if (status & UART_LSR_DR) receive_chars(up, &status); check_modem_status(up); if (status & UART_LSR_THRE) transmit_chars(up); tty_flip_buffer_push(&up->port.state->port); } while (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)); uart_port_unlock_irqrestore(&up->port, flags); return IRQ_HANDLED; } /* Separate interrupt handling path for keyboard/mouse ports. */ static void sunsu_change_speed(struct uart_port *port, unsigned int cflag, unsigned int iflag, unsigned int quot); static void sunsu_change_mouse_baud(struct uart_sunsu_port *up) { unsigned int cur_cflag = up->cflag; int quot, new_baud; up->cflag &= ~CBAUD; up->cflag |= suncore_mouse_baud_cflag_next(cur_cflag, &new_baud); quot = up->port.uartclk / (16 * new_baud); sunsu_change_speed(&up->port, up->cflag, 0, quot); } static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break) { do { unsigned char ch = serial_in(up, UART_RX); /* Stop-A is handled by drivers/char/keyboard.c now. */ if (up->su_type == SU_PORT_KBD) { #ifdef CONFIG_SERIO serio_interrupt(&up->serio, ch, 0); #endif } else if (up->su_type == SU_PORT_MS) { int ret = suncore_mouse_baud_detection(ch, is_break); switch (ret) { case 2: sunsu_change_mouse_baud(up); fallthrough; case 1: break; case 0: #ifdef CONFIG_SERIO serio_interrupt(&up->serio, ch, 0); #endif break; } }