Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6: (25 commits)
  serial: Tidy REMOTE_DEBUG
  serial: isicomm: handle running out of slots
  serial: bfin_sport_uart: Use resource size to fix off-by-one error
  tty: fix obsolete comment on tty_insert_flip_string_fixed_flag
  serial: Add driver for the Altera UART
  serial: Add driver for the Altera JTAG UART
  serial: timbuart: make sure last byte is sent when port is closed
  serial: two branches the same in timbuart_set_mctrl()
  serial: uartlite: move from byte accesses to word accesses
  tty: n_gsm: depends on NET
  tty: n_gsm line discipline
  serial: TTY: new ldiscs for staging
  serial: bfin_sport_uart: drop redundant cpu depends
  serial: bfin_sport_uart: drop the experimental markings
  serial: bfin_sport_uart: pull in bfin_sport.h for SPORT defines
  serial: bfin_sport_uart: only enable SPORT TX if data is to be sent
  serial: bfin_sport_uart: drop useless status masks
  serial: bfin_sport_uart: zero sport_uart_port if allocated dynamically
  serial: bfin_sport_uart: protect changes to uart_port
  serial: bfin_sport_uart: add support for CTS/RTS via GPIOs
  ...
master
Linus Torvalds 13 years ago
commit 7f02ab3ce3
  1. 10
      drivers/char/Kconfig
  2. 1
      drivers/char/Makefile
  3. 8
      drivers/char/isicom.c
  4. 2763
      drivers/char/n_gsm.c
  5. 223
      drivers/char/serial167.c
  6. 2
      drivers/char/tty_buffer.c
  7. 82
      drivers/serial/Kconfig
  8. 2
      drivers/serial/Makefile
  9. 504
      drivers/serial/altera_jtaguart.c
  10. 570
      drivers/serial/altera_uart.c
  11. 209
      drivers/serial/bfin_sport_uart.c
  12. 27
      drivers/serial/bfin_sport_uart.h
  13. 25
      drivers/serial/timbuart.c
  14. 32
      drivers/serial/uartlite.c
  15. 16
      include/linux/altera_jtaguart.h
  16. 14
      include/linux/altera_uart.h
  17. 25
      include/linux/gsmmux.h
  18. 4
      include/linux/serial_core.h
  19. 3
      include/linux/tty.h

@ -276,11 +276,19 @@ config N_HDLC
Allows synchronous HDLC communications with tty device drivers that
support synchronous HDLC such as the Microgate SyncLink adapter.
This driver can only be built as a module ( = code which can be
This driver can be built as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called n_hdlc. If you want to do that, say M
here.
config N_GSM
tristate "GSM MUX line discipline support (EXPERIMENTAL)"
depends on EXPERIMENTAL
depends on NET
help
This line discipline provides support for the GSM MUX protocol and
presents the mux as a set of 61 individual tty devices.
config RISCOM8
tristate "SDL RISCom/8 card support"
depends on SERIAL_NONSTANDARD

@ -40,6 +40,7 @@ obj-$(CONFIG_SYNCLINK) += synclink.o
obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o
obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o
obj-$(CONFIG_N_HDLC) += n_hdlc.o
obj-$(CONFIG_N_GSM) += n_gsm.o
obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
obj-$(CONFIG_SX) += sx.o generic_serial.o
obj-$(CONFIG_RIO) += rio/ generic_serial.o

@ -1573,11 +1573,16 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
dev_info(&pdev->dev, "ISI PCI Card(Device ID 0x%x)\n", ent->device);
/* allot the first empty slot in the array */
for (index = 0; index < BOARD_COUNT; index++)
for (index = 0; index < BOARD_COUNT; index++) {
if (isi_card[index].base == 0) {
board = &isi_card[index];
break;
}
}
if (index == BOARD_COUNT) {
retval = -ENODEV;
goto err_disable;
}
board->index = index;
board->base = pci_resource_start(pdev, 3);
@ -1624,6 +1629,7 @@ errunrr:
errdec:
board->base = 0;
card_count--;
err_disable:
pci_disable_device(pdev);
err:
return retval;

File diff suppressed because it is too large Load Diff

@ -176,23 +176,6 @@ static void config_setup(struct cyclades_port *);
static void show_status(int);
#endif
#ifdef CONFIG_REMOTE_DEBUG
static void debug_setup(void);
void queueDebugChar(int c);
int getDebugChar(void);
#define DEBUG_PORT 1
#define DEBUG_LEN 256
typedef struct {
int in;
int out;
unsigned char buf[DEBUG_LEN];
} debugq;
debugq debugiq;
#endif
/*
* I have my own version of udelay(), as it is needed when initialising
* the chip, before the delay loop has been calibrated. Should probably
@ -515,11 +498,6 @@ static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id)
/* determine the channel and change to that context */
channel = (u_short) (base_addr[CyLICR] >> 2);
#ifdef CONFIG_REMOTE_DEBUG
if (channel == DEBUG_PORT) {
panic("TxInt on debug port!!!");
}
#endif
/* validate the port number (as configured and open) */
if ((channel < 0) || (NR_PORTS <= channel)) {
base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy);
@ -634,14 +612,6 @@ static irqreturn_t cd2401_rx_interrupt(int irq, void *dev_id)
info->last_active = jiffies;
save_cnt = char_count = base_addr[CyRFOC];
#ifdef CONFIG_REMOTE_DEBUG
if (channel == DEBUG_PORT) {
while (char_count--) {
data = base_addr[CyRDR];
queueDebugChar(data);
}
} else
#endif
/* if there is nowhere to put the data, discard it */
if (info->tty == 0) {
while (char_count--) {
@ -2195,9 +2165,7 @@ static int __init serial167_init(void)
port_num++;
info++;
}
#ifdef CONFIG_REMOTE_DEBUG
debug_setup();
#endif
ret = request_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt, 0,
"cd2401_errors", cd2401_rxerr_interrupt);
if (ret) {
@ -2518,193 +2486,4 @@ static int __init serial167_console_init(void)
console_initcall(serial167_console_init);
#ifdef CONFIG_REMOTE_DEBUG
void putDebugChar(int c)
{
volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
unsigned long flags;
volatile u_char sink;
u_char ier;
int port;
local_irq_save(flags);
/* Ensure transmitter is enabled! */
port = DEBUG_PORT;
base_addr[CyCAR] = (u_char) port;
while (base_addr[CyCCR])
;
base_addr[CyCCR] = CyENB_XMTR;
ier = base_addr[CyIER];
base_addr[CyIER] = CyTxMpty;
while (1) {
if (pcc2chip[PccSCCTICR] & 0x20) {
/* We have a Tx int. Acknowledge it */
sink = pcc2chip[PccTPIACKR];
if ((base_addr[CyLICR] >> 2) == port) {
base_addr[CyTDR] = c;
base_addr[CyTEOIR] = 0;
break;
} else
base_addr[CyTEOIR] = CyNOTRANS;
}
}
base_addr[CyIER] = ier;
local_irq_restore(flags);
}
int getDebugChar()
{
volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
unsigned long flags;
volatile u_char sink;
u_char ier;
int port;
int i, c;
i = debugiq.out;
if (i != debugiq.in) {
c = debugiq.buf[i];
if (++i == DEBUG_LEN)
i = 0;
debugiq.out = i;
return c;
}
/* OK, nothing in queue, wait in poll loop */
local_irq_save(flags);
/* Ensure receiver is enabled! */
port = DEBUG_PORT;
base_addr[CyCAR] = (u_char) port;
#if 0
while (base_addr[CyCCR])
;
base_addr[CyCCR] = CyENB_RCVR;
#endif
ier = base_addr[CyIER];
base_addr[CyIER] = CyRxData;
while (1) {
if (pcc2chip[PccSCCRICR] & 0x20) {
/* We have a Rx int. Acknowledge it */
sink = pcc2chip[PccRPIACKR];
if ((base_addr[CyLICR] >> 2) == port) {
int cnt = base_addr[CyRFOC];
while (cnt-- > 0) {
c = base_addr[CyRDR];
if (c == 0)
printk
("!! debug char is null (cnt=%d) !!",
cnt);
else
queueDebugChar(c);
}
base_addr[CyREOIR] = 0;
i = debugiq.out;
if (i == debugiq.in)
panic("Debug input queue empty!");
c = debugiq.buf[i];
if (++i == DEBUG_LEN)
i = 0;
debugiq.out = i;
break;
} else
base_addr[CyREOIR] = CyNOTRANS;
}
}
base_addr[CyIER] = ier;
local_irq_restore(flags);
return (c);
}
void queueDebugChar(int c)
{
int i;
i = debugiq.in;
debugiq.buf[i] = c;
if (++i == DEBUG_LEN)
i = 0;
if (i != debugiq.out)
debugiq.in = i;
}
static void debug_setup()
{
unsigned long flags;
volatile unsigned char *base_addr = (u_char *) BASE_ADDR;
int i, cflag;
cflag = B19200;
local_irq_save(flags);
for (i = 0; i < 4; i++) {
base_addr[CyCAR] = i;
base_addr[CyLICR] = i << 2;
}
debugiq.in = debugiq.out = 0;
base_addr[CyCAR] = DEBUG_PORT;
/* baud rate */
i = cflag & CBAUD;
base_addr[CyIER] = 0;
base_addr[CyCMR] = CyASYNC;
base_addr[CyLICR] = DEBUG_PORT << 2;
base_addr[CyLIVR] = 0x5c;
/* tx and rx baud rate */
base_addr[CyTCOR] = baud_co[i];
base_addr[CyTBPR] = baud_bpr[i];
base_addr[CyRCOR] = baud_co[i] >> 5;
base_addr[CyRBPR] = baud_bpr[i];
/* set line characteristics according configuration */
base_addr[CySCHR1] = 0;
base_addr[CySCHR2] = 0;
base_addr[CySCRL] = 0;
base_addr[CySCRH] = 0;
base_addr[CyCOR1] = Cy_8_BITS | CyPARITY_NONE;
base_addr[CyCOR2] = 0;
base_addr[CyCOR3] = Cy_1_STOP;
base_addr[CyCOR4] = baud_cor4[i];
base_addr[CyCOR5] = 0;
base_addr[CyCOR6] = 0;
base_addr[CyCOR7] = 0;
write_cy_cmd(base_addr, CyINIT_CHAN);
write_cy_cmd(base_addr, CyENB_RCVR);
base_addr[CyCAR] = DEBUG_PORT; /* !!! Is this needed? */
base_addr[CyRTPRL] = 2;
base_addr[CyRTPRH] = 0;
base_addr[CyMSVR1] = CyRTS;
base_addr[CyMSVR2] = CyDTR;
base_addr[CyIER] = CyRxData;
local_irq_restore(flags);
} /* debug_setup */
#endif
MODULE_LICENSE("GPL");

@ -238,7 +238,7 @@ EXPORT_SYMBOL_GPL(tty_buffer_request_room);
* @size: size
*
* Queue a series of bytes to the tty buffering. All the characters
* passed are marked as without error. Returns the number added.
* passed are marked with the supplied flag. Returns the number added.
*
* Locking: Called functions may take tty->buf.lock
*/

@ -1423,8 +1423,8 @@ config SERIAL_SC26XX_CONSOLE
Support for Console on SC2681/SC2692 serial ports.
config SERIAL_BFIN_SPORT
tristate "Blackfin SPORT emulate UART (EXPERIMENTAL)"
depends on BLACKFIN && EXPERIMENTAL
tristate "Blackfin SPORT emulate UART"
depends on BLACKFIN
select SERIAL_CORE
help
Enable SPORT emulate UART on Blackfin series.
@ -1439,28 +1439,52 @@ config SERIAL_BFIN_SPORT_CONSOLE
config SERIAL_BFIN_SPORT0_UART
bool "Enable UART over SPORT0"
depends on SERIAL_BFIN_SPORT && !(BF542 || BF542M || BF544 || BF544M)
depends on SERIAL_BFIN_SPORT && !(BF542 || BF544)
help
Enable UART over SPORT0
config SERIAL_BFIN_SPORT0_UART_CTSRTS
bool "Enable UART over SPORT0 hardware flow control"
depends on SERIAL_BFIN_SPORT0_UART
help
Enable hardware flow control in the driver.
config SERIAL_BFIN_SPORT1_UART
bool "Enable UART over SPORT1"
depends on SERIAL_BFIN_SPORT
help
Enable UART over SPORT1
config SERIAL_BFIN_SPORT1_UART_CTSRTS
bool "Enable UART over SPORT1 hardware flow control"
depends on SERIAL_BFIN_SPORT1_UART
help
Enable hardware flow control in the driver.
config SERIAL_BFIN_SPORT2_UART
bool "Enable UART over SPORT2"
depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
help
Enable UART over SPORT2
config SERIAL_BFIN_SPORT2_UART_CTSRTS
bool "Enable UART over SPORT2 hardware flow control"
depends on SERIAL_BFIN_SPORT2_UART
help
Enable hardware flow control in the driver.
config SERIAL_BFIN_SPORT3_UART
bool "Enable UART over SPORT3"
depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
help
Enable UART over SPORT3
config SERIAL_BFIN_SPORT3_UART_CTSRTS
bool "Enable UART over SPORT3 hardware flow control"
depends on SERIAL_BFIN_SPORT3_UART
help
Enable hardware flow control in the driver.
config SERIAL_TIMBERDALE
tristate "Support for timberdale UART"
select SERIAL_CORE
@ -1499,4 +1523,56 @@ config SERIAL_GRLIB_GAISLER_APBUART_CONSOLE
help
Support for running a console on the GRLIB APBUART
config SERIAL_ALTERA_JTAGUART
tristate "Altera JTAG UART support"
select SERIAL_CORE
help
This driver supports the Altera JTAG UART port.
config SERIAL_ALTERA_JTAGUART_CONSOLE
bool "Altera JTAG UART console support"
depends on SERIAL_ALTERA_JTAGUART=y
select SERIAL_CORE_CONSOLE
help
Enable a Altera JTAG UART port to be the system console.
config SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS
bool "Bypass output when no connection"
depends on SERIAL_ALTERA_JTAGUART_CONSOLE
select SERIAL_CORE_CONSOLE
help
Bypass console output and keep going even if there is no
JTAG terminal connection with the host.
config SERIAL_ALTERA_UART
tristate "Altera UART support"
select SERIAL_CORE
help
This driver supports the Altera softcore UART port.
config SERIAL_ALTERA_UART_MAXPORTS
int "Maximum number of Altera UART ports"
depends on SERIAL_ALTERA_UART
default 4
help
This setting lets you define the maximum number of the Altera
UART ports. The usual default varies from board to board, and
this setting is a way of catering for that.
config SERIAL_ALTERA_UART_BAUDRATE
int "Default baudrate for Altera UART ports"
depends on SERIAL_ALTERA_UART
default 115200
help
This setting lets you define what the default baudrate is for the
Altera UART ports. The usual default varies from board to board,
and this setting is a way of catering for that.
config SERIAL_ALTERA_UART_CONSOLE
bool "Altera UART console support"
depends on SERIAL_ALTERA_UART=y
select SERIAL_CORE_CONSOLE
help
Enable a Altera UART port to be the system console.
endmenu

@ -82,3 +82,5 @@ obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o

@ -0,0 +1,504 @@
/*
* altera_jtaguart.c -- Altera JTAG UART driver
*
* Based on mcf.c -- Freescale ColdFire UART driver
*
* (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
* (C) Copyright 2008, Thomas Chou <thomas@wytron.com.tw>
* (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/console.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/altera_jtaguart.h>
#define DRV_NAME "altera_jtaguart"
/*
* Altera JTAG UART register definitions according to the Altera JTAG UART
* datasheet: http://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf
*/
#define ALTERA_JTAGUART_SIZE 8
#define ALTERA_JTAGUART_DATA_REG 0
#define ALTERA_JTAGUART_DATA_DATA_MSK 0x000000FF
#define ALTERA_JTAGUART_DATA_RVALID_MSK 0x00008000
#define ALTERA_JTAGUART_DATA_RAVAIL_MSK 0xFFFF0000
#define ALTERA_JTAGUART_DATA_RAVAIL_OFF 16
#define ALTERA_JTAGUART_CONTROL_REG 4
#define ALTERA_JTAGUART_CONTROL_RE_MSK 0x00000001
#define ALTERA_JTAGUART_CONTROL_WE_MSK 0x00000002
#define ALTERA_JTAGUART_CONTROL_RI_MSK 0x00000100
#define ALTERA_JTAGUART_CONTROL_RI_OFF 8
#define ALTERA_JTAGUART_CONTROL_WI_MSK 0x00000200
#define ALTERA_JTAGUART_CONTROL_AC_MSK 0x00000400
#define ALTERA_JTAGUART_CONTROL_WSPACE_MSK 0xFFFF0000
#define ALTERA_JTAGUART_CONTROL_WSPACE_OFF 16
/*
* Local per-uart structure.
*/
struct altera_jtaguart {
struct uart_port port;
unsigned int sigs; /* Local copy of line sigs */
unsigned long imr; /* Local IMR mirror */
};
static unsigned int altera_jtaguart_tx_empty(struct uart_port *port)
{
return (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
ALTERA_JTAGUART_CONTROL_WSPACE_MSK) ? TIOCSER_TEMT : 0;
}
static unsigned int altera_jtaguart_get_mctrl(struct uart_port *port)
{
return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
}
static void altera_jtaguart_set_mctrl(struct uart_port *port, unsigned int sigs)
{
}
static void altera_jtaguart_start_tx(struct uart_port *port)
{
struct altera_jtaguart *pp =
container_of(port, struct altera_jtaguart, port);
pp->imr |= ALTERA_JTAGUART_CONTROL_WE_MSK;
writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
}
static void altera_jtaguart_stop_tx(struct uart_port *port)
{
struct altera_jtaguart *pp =
container_of(port, struct altera_jtaguart, port);
pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
}
static void altera_jtaguart_stop_rx(struct uart_port *port)
{
struct altera_jtaguart *pp =
container_of(port, struct altera_jtaguart, port);
pp->imr &= ~ALTERA_JTAGUART_CONTROL_RE_MSK;
writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
}
static void altera_jtaguart_break_ctl(struct uart_port *port, int break_state)
{
}
static void altera_jtaguart_enable_ms(struct uart_port *port)
{
}
static void altera_jtaguart_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
/* Just copy the old termios settings back */
if (old)
tty_termios_copy_hw(termios, old);
}
static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp)
{
struct uart_port *port = &pp->port;
unsigned char ch, flag;
unsigned long status;
while ((status = readl(port->membase + ALTERA_JTAGUART_DATA_REG)) &
ALTERA_JTAGUART_DATA_RVALID_MSK) {
ch = status & ALTERA_JTAGUART_DATA_DATA_MSK;
flag = TTY_NORMAL;
port->icount.rx++;
if (uart_handle_sysrq_char(port, ch))
continue;
uart_insert_char(port, 0, 0, ch, flag);
}
tty_flip_buffer_push(port->state->port.tty);
}
static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp)
{
struct uart_port *port = &pp->port;
struct circ_buf *xmit = &port->state->xmit;
unsigned int pending, count;
if (port->x_char) {
/* Send special char - probably flow control */
writel(port->x_char, port->membase + ALTERA_JTAGUART_DATA_REG);
port->x_char = 0;
port->icount.tx++;
return;
}
pending = uart_circ_chars_pending(xmit);
if (pending > 0) {
count = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
ALTERA_JTAGUART_CONTROL_WSPACE_MSK) >>
ALTERA_JTAGUART_CONTROL_WSPACE_OFF;
if (count > pending)
count = pending;
if (count > 0) {
pending -= count;
while (count--) {
writel(xmit->buf[xmit->tail],
port->membase + ALTERA_JTAGUART_DATA_REG);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
}
if (pending < WAKEUP_CHARS)
uart_write_wakeup(port);
}
}
if (pending == 0) {
pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
}
}
static irqreturn_t altera_jtaguart_interrupt(int irq, void *data)
{
struct uart_port *port = data;
struct altera_jtaguart *pp =
container_of(port, struct altera_jtaguart, port);
unsigned int isr;
isr = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) >>
ALTERA_JTAGUART_CONTROL_RI_OFF) & pp->imr;
spin_lock(&port->lock);
if (isr & ALTERA_JTAGUART_CONTROL_RE_MSK)
altera_jtaguart_rx_chars(pp);
if (isr & ALTERA_JTAGUART_CONTROL_WE_MSK)
altera_jtaguart_tx_chars(pp);
spin_unlock(&port->lock);
return IRQ_RETVAL(isr);
}
static void altera_jtaguart_config_port(struct uart_port *port, int flags)
{
port->type = PORT_ALTERA_JTAGUART;
/* Clear mask, so no surprise interrupts. */
writel(0, port->membase + ALTERA_JTAGUART_CONTROL_REG);
}
static int altera_jtaguart_startup(struct uart_port *port)
{
struct altera_jtaguart *pp =
container_of(port, struct altera_jtaguart, port);
unsigned long flags;
int ret;
ret = request_irq(port->irq, altera_jtaguart_interrupt, IRQF_DISABLED,
DRV_NAME, port);
if (ret) {
pr_err(DRV_NAME ": unable to attach Altera JTAG UART %d "
"interrupt vector=%d\n", port->line, port->irq);
return ret;
}
spin_lock_irqsave(&port->lock, flags);
/* Enable RX interrupts now */
pp->imr = ALTERA_JTAGUART_CONTROL_RE_MSK;
writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
return 0;
}
static void altera_jtaguart_shutdown(struct uart_port *port)
{
struct altera_jtaguart *pp =
container_of(port, struct altera_jtaguart, port);
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
/* Disable all interrupts now */
pp->imr = 0;
writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
free_irq(port->irq, port);
}
static const char *altera_jtaguart_type(struct uart_port *port)
{
return (port->type == PORT_ALTERA_JTAGUART) ? "Altera JTAG UART" : NULL;
}
static int altera_jtaguart_request_port(struct uart_port *port)
{
/* UARTs always present */
return 0;
}
static void altera_jtaguart_release_port(struct uart_port *port)
{
/* Nothing to release... */
}
static int altera_jtaguart_verify_port(struct uart_port *port,
struct serial_struct *ser)
{
if (ser->type != PORT_UNKNOWN && ser->type != PORT_ALTERA_JTAGUART)
return -EINVAL;
return 0;
}
/*
* Define the basic serial functions we support.
*/
static struct uart_ops altera_jtaguart_ops = {
.tx_empty = altera_jtaguart_tx_empty,
.get_mctrl = altera_jtaguart_get_mctrl,
.set_mctrl = altera_jtaguart_set_mctrl,
.start_tx = altera_jtaguart_start_tx,
.stop_tx = altera_jtaguart_stop_tx,
.stop_rx = altera_jtaguart_stop_rx,
.enable_ms = altera_jtaguart_enable_ms,
.break_ctl = altera_jtaguart_break_ctl,
.startup = altera_jtaguart_startup,
.shutdown = altera_jtaguart_shutdown,
.set_termios = altera_jtaguart_set_termios,
.type = altera_jtaguart_type,
.request_port = altera_jtaguart_request_port,
.release_port = altera_jtaguart_release_port,
.config_port = altera_jtaguart_config_port,
.verify_port = altera_jtaguart_verify_port,
};
#define ALTERA_JTAGUART_MAXPORTS 1
static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS];
#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE)
int __init early_altera_jtaguart_setup(struct altera_jtaguart_platform_uart
*platp)
{
struct uart_port *port;
int i;
for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) {
port = &altera_jtaguart_ports[i].port;
port->line = i;
port->type = PORT_ALTERA_JTAGUART;
port->mapbase = platp[i].mapbase;
port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
port->iotype = SERIAL_IO_MEM;
port->irq = platp[i].irq;
port->flags = ASYNC_BOOT_AUTOCONF;
port->ops = &altera_jtaguart_ops;
}
return 0;
}
#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS)
static void altera_jtaguart_console_putc(struct console *co, const char c)
{
struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
unsigned long status;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
while (((status = readl(port->membase + ALTERA_JTAGUART_CONTROL_REG)) &
ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
if ((status & ALTERA_JTAGUART_CONTROL_AC_MSK) == 0) {
spin_unlock_irqrestore(&port->lock, flags);
return; /* no connection activity */
}
spin_unlock_irqrestore(&port->lock, flags);
cpu_relax();
spin_lock_irqsave(&port->lock, flags);
}
writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
spin_unlock_irqrestore(&port->lock, flags);
}
#else
static void altera_jtaguart_console_putc(struct console *co, const char c)
{
struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
while ((readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) &
ALTERA_JTAGUART_CONTROL_WSPACE_MSK) == 0) {
spin_unlock_irqrestore(&port->lock, flags);
cpu_relax();
spin_lock_irqsave(&port->lock, flags);
}
writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
spin_unlock_irqrestore(&port->lock, flags);
}
#endif
static void altera_jtaguart_console_write(struct console *co, const char *s,
unsigned int count)
{
for (; count; count--, s++) {
altera_jtaguart_console_putc(co, *s);
if (*s == '\n')
altera_jtaguart_console_putc(co, '\r');
}
}
static int __init altera_jtaguart_console_setup(struct console *co,
char *options)
{
struct uart_port *port;
if (co->index < 0 || co->index >= ALTERA_JTAGUART_MAXPORTS)
return -EINVAL;
port = &altera_jtaguart_ports[co->index].port;
if (port->membase == 0)
return -ENODEV;
return 0;
}
static struct uart_driver altera_jtaguart_driver;
static struct console altera_jtaguart_console = {
.name = "ttyJ",
.write = altera_jtaguart_console_write,
.device = uart_console_device,
.setup = altera_jtaguart_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &altera_jtaguart_driver,
};
static int __init altera_jtaguart_console_init(void)
{
register_console(&altera_jtaguart_console);
return 0;
}
console_initcall(altera_jtaguart_console_init);
#define ALTERA_JTAGUART_CONSOLE (&altera_jtaguart_console)
#else
#define ALTERA_JTAGUART_CONSOLE NULL
#endif /* CONFIG_ALTERA_JTAGUART_CONSOLE */
static struct uart_driver altera_jtaguart_driver = {
.owner = THIS_MODULE,
.driver_name = "altera_jtaguart",
.dev_name = "ttyJ",
.major = ALTERA_JTAGUART_MAJOR,
.minor = ALTERA_JTAGUART_MINOR,
.nr = ALTERA_JTAGUART_MAXPORTS,
.cons = ALTERA_JTAGUART_CONSOLE,
};
static int __devinit altera_jtaguart_probe(struct platform_device *pdev)
{
struct altera_jtaguart_platform_uart *platp = pdev->dev.platform_data;
struct uart_port *port;
int i;
for (i = 0; i < ALTERA_JTAGUART_MAXPORTS && platp[i].mapbase; i++) {
port = &altera_jtaguart_ports[i].port;
port->line = i;
port->type = PORT_ALTERA_JTAGUART;
port->mapbase = platp[i].mapbase;
port->membase = ioremap(port->mapbase, ALTERA_JTAGUART_SIZE);
port->iotype = SERIAL_IO_MEM;
port->irq = platp[i].irq;
port->ops = &altera_jtaguart_ops;
port->flags = ASYNC_BOOT_AUTOCONF;
uart_add_one_port(&altera_jtaguart_driver, port);
}
return 0;
}
static int __devexit altera_jtaguart_remove(struct platform_device *pdev)
{
struct uart_port *port;
int i;
for (i = 0; i < ALTERA_JTAGUART_MAXPORTS; i++) {
port = &altera_jtaguart_ports[i].port;
if (port)
uart_remove_one_port(&altera_jtaguart_driver, port);
}
return 0;
}
static struct platform_driver altera_jtaguart_platform_driver = {
.probe = altera_jtaguart_probe,
.remove = __devexit_p(altera_jtaguart_remove),
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
};
static int __init altera_jtaguart_init(void)
{
int rc;
rc = uart_register_driver(&altera_jtaguart_driver);
if (rc)
return rc;
rc = platform_driver_register(&altera_jtaguart_platform_driver);
if (rc) {
uart_unregister_driver(&altera_jtaguart_driver);
return rc;
}
return 0;
}
static void __exit altera_jtaguart_exit(void)
{
platform_driver_unregister(&altera_jtaguart_platform_driver);
uart_unregister_driver(&altera_jtaguart_driver);
}
module_init(altera_jtaguart_init);
module_exit(altera_jtaguart_exit);
MODULE_DESCRIPTION("Altera JTAG UART driver");
MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRV_NAME);

@ -0,0 +1,570 @@
/*
* altera_uart.c -- Altera UART driver
*
* Based on mcf.c -- Freescale ColdFire UART driver
*
* (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
* (C) Copyright 2008, Thomas Chou <thomas@wytron.com.tw>
* (C) Copyright 2010, Tobias Klauser <tklauser@distanz.ch>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/console.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/altera_uart.h>
#define DRV_NAME "altera_uart"
/*
* Altera UART register definitions according to the Nios UART datasheet:
* http://www.altera.com/literature/ds/ds_nios_uart.pdf
*/
#define ALTERA_UART_SIZE 32
#define ALTERA_UART_RXDATA_REG 0
#define ALTERA_UART_TXDATA_REG 4
#define ALTERA_UART_STATUS_REG 8
#define ALTERA_UART_CONTROL_REG 12
#define ALTERA_UART_DIVISOR_REG 16
#define ALTERA_UART_EOP_REG 20
#define ALTERA_UART_STATUS_PE_MSK 0x0001 /* parity error */
#define ALTERA_UART_STATUS_FE_MSK 0x0002 /* framing error */
#define ALTERA_UART_STATUS_BRK_MSK 0x0004 /* break */
#define ALTERA_UART_STATUS_ROE_MSK 0x0008 /* RX overrun error */
#define ALTERA_UART_STATUS_TOE_MSK 0x0010 /* TX overrun error */
#define ALTERA_UART_STATUS_TMT_MSK 0x0020 /* TX shift register state */
#define ALTERA_UART_STATUS_TRDY_MSK 0x0040 /* TX ready */
#define ALTERA_UART_STATUS_RRDY_MSK 0x0080 /* RX ready */
#define ALTERA_UART_STATUS_E_MSK 0x0100 /* exception condition */
#define ALTERA_UART_STATUS_DCTS_MSK 0x0400 /* CTS logic-level change */
#define ALTERA_UART_STATUS_CTS_MSK 0x0800 /* CTS logic state */
#define ALTERA_UART_STATUS_EOP_MSK 0x1000 /* EOP written/read */
/* Enable interrupt on... */
#define ALTERA_UART_CONTROL_PE_MSK 0x0001 /* ...parity error */
#define ALTERA_UART_CONTROL_FE_MSK 0x0002 /* ...framing error */
#define ALTERA_UART_CONTROL_BRK_MSK 0x0004 /* ...break */
#define ALTERA_UART_CONTROL_ROE_MSK 0x0008 /* ...RX overrun */
#define ALTERA_UART_CONTROL_TOE_MSK 0x0010 /* ...TX overrun */
#define ALTERA_UART_CONTROL_TMT_MSK 0x0020 /* ...TX shift register empty */
#define ALTERA_UART_CONTROL_TRDY_MSK 0x0040 /* ...TX ready */
#define ALTERA_UART_CONTROL_RRDY_MSK 0x0080 /* ...RX ready */
#define ALTERA_UART_CONTROL_E_MSK 0x0100 /* ...exception*/
#define ALTERA_UART_CONTROL_TRBK_MSK 0x0200 /* TX break */
#define ALTERA_UART_CONTROL_DCTS_MSK 0x0400 /* Interrupt on CTS change */
#define ALTERA_UART_CONTROL_RTS_MSK 0x0800 /* RTS signal */
#define ALTERA_UART_CONTROL_EOP_MSK 0x1000 /* Interrupt on EOP */
/*
* Local per-uart structure.
*/
struct altera_uart {
struct uart_port port;
unsigned int sigs; /* Local copy of line sigs */
unsigned short imr; /* Local IMR mirror */
};
static unsigned int altera_uart_tx_empty(struct uart_port *port)
{
return (readl(port->membase + ALTERA_UART_STATUS_REG) &
ALTERA_UART_STATUS_TMT_MSK) ? TIOCSER_TEMT : 0;
}
static unsigned int altera_uart_get_mctrl(struct uart_port *port)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
unsigned long flags;
unsigned int sigs;
spin_lock_irqsave(&port->lock, flags);
sigs =
(readl(port->membase + ALTERA_UART_STATUS_REG) &
ALTERA_UART_STATUS_CTS_MSK) ? TIOCM_CTS : 0;
sigs |= (pp->sigs & TIOCM_RTS);
spin_unlock_irqrestore(&port->lock, flags);
return sigs;
}
static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
pp->sigs = sigs;
if (sigs & TIOCM_RTS)
pp->imr |= ALTERA_UART_CONTROL_RTS_MSK;
else
pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
}
static void altera_uart_start_tx(struct uart_port *port)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
}
static void altera_uart_stop_tx(struct uart_port *port)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
}
static void altera_uart_stop_rx(struct uart_port *port)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
}
static void altera_uart_break_ctl(struct uart_port *port, int break_state)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
if (break_state == -1)
pp->imr |= ALTERA_UART_CONTROL_TRBK_MSK;
else
pp->imr &= ~ALTERA_UART_CONTROL_TRBK_MSK;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
}
static void altera_uart_enable_ms(struct uart_port *port)
{
}
static void altera_uart_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
unsigned long flags;
unsigned int baud, baudclk;
baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
baudclk = port->uartclk / baud;
if (old)
tty_termios_copy_hw(termios, old);
tty_termios_encode_baud_rate(termios, baud, baud);
spin_lock_irqsave(&port->lock, flags);
writel(baudclk, port->membase + ALTERA_UART_DIVISOR_REG);
spin_unlock_irqrestore(&port->lock, flags);
}
static void altera_uart_rx_chars(struct altera_uart *pp)
{
struct uart_port *port = &pp->port;
unsigned char ch, flag;
unsigned short status;
while ((status = readl(port->membase + ALTERA_UART_STATUS_REG)) &
ALTERA_UART_STATUS_RRDY_MSK) {
ch = readl(port->membase + ALTERA_UART_RXDATA_REG);
flag = TTY_NORMAL;
port->icount.rx++;
if (status & ALTERA_UART_STATUS_E_MSK) {
writel(status, port->membase + ALTERA_UART_STATUS_REG);
if (status & ALTERA_UART_STATUS_BRK_MSK) {
port->icount.brk++;
if (uart_handle_break(port))
continue;
} else if (status & ALTERA_UART_STATUS_PE_MSK) {
port->icount.parity++;
} else if (status & ALTERA_UART_STATUS_ROE_MSK) {
port->icount.overrun++;
} else if (status & ALTERA_UART_STATUS_FE_MSK) {
port->icount.frame++;
}
status &= port->read_status_mask;
if (status & ALTERA_UART_STATUS_BRK_MSK)
flag = TTY_BREAK;
else if (status & ALTERA_UART_STATUS_PE_MSK)
flag = TTY_PARITY;
else if (status & ALTERA_UART_STATUS_FE_MSK)
flag = TTY_FRAME;
}
if (uart_handle_sysrq_char(port, ch))
continue;
uart_insert_char(port, status, ALTERA_UART_STATUS_ROE_MSK, ch,
flag);
}
tty_flip_buffer_push(port->state->port.tty);
}
static void altera_uart_tx_chars(struct altera_uart *pp)
{
struct uart_port *port = &pp->port;
struct circ_buf *xmit = &port->state->xmit;
if (port->x_char) {
/* Send special char - probably flow control */
writel(port->x_char, port->membase + ALTERA_UART_TXDATA_REG);
port->x_char = 0;
port->icount.tx++;
return;
}
while (readl(port->membase + ALTERA_UART_STATUS_REG) &
ALTERA_UART_STATUS_TRDY_MSK) {
if (xmit->head == xmit->tail)
break;
writel(xmit->buf[xmit->tail],
port->membase + ALTERA_UART_TXDATA_REG);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (xmit->head == xmit->tail) {
pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
}
}
static irqreturn_t altera_uart_interrupt(int irq, void *data)
{
struct uart_port *port = data;
struct altera_uart *pp = container_of(port, struct altera_uart, port);
unsigned int isr;
isr = readl(port->membase + ALTERA_UART_STATUS_REG) & pp->imr;
if (isr & ALTERA_UART_STATUS_RRDY_MSK)
altera_uart_rx_chars(pp);
if (isr & ALTERA_UART_STATUS_TRDY_MSK)
altera_uart_tx_chars(pp);
return IRQ_RETVAL(isr);
}
static void altera_uart_config_port(struct uart_port *port, int flags)
{
port->type = PORT_ALTERA_UART;
/* Clear mask, so no surprise interrupts. */
writel(0, port->membase + ALTERA_UART_CONTROL_REG);
/* Clear status register */
writel(0, port->membase + ALTERA_UART_STATUS_REG);
}
static int altera_uart_startup(struct uart_port *port)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
unsigned long flags;
int ret;
ret = request_irq(port->irq, altera_uart_interrupt, IRQF_DISABLED,
DRV_NAME, port);
if (ret) {
pr_err(DRV_NAME ": unable to attach Altera UART %d "
"interrupt vector=%d\n", port->line, port->irq);
return ret;
}
spin_lock_irqsave(&port->lock, flags);
/* Enable RX interrupts now */
pp->imr = ALTERA_UART_CONTROL_RRDY_MSK;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
return 0;
}
static void altera_uart_shutdown(struct uart_port *port)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
/* Disable all interrupts now */
pp->imr = 0;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
spin_unlock_irqrestore(&port->lock, flags);
free_irq(port->irq, port);
}
static const char *altera_uart_type(struct uart_port *port)
{
return (port->type == PORT_ALTERA_UART) ? "Altera UART" : NULL;
}
static int altera_uart_request_port(struct uart_port *port)
{
/* UARTs always present */
return 0;
}
static void altera_uart_release_port(struct uart_port *port)
{
/* Nothing to release... */
}
static int altera_uart_verify_port(struct uart_port *port,
struct serial_struct *ser)
{
if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_ALTERA_UART))
return -EINVAL;
return 0;
}
/*
* Define the basic serial functions we support.
*/
static struct uart_ops altera_uart_ops = {
.tx_empty = altera_uart_tx_empty,
.get_mctrl = altera_uart_get_mctrl,
.set_mctrl = altera_uart_set_mctrl,
.start_tx = altera_uart_start_tx,
.stop_tx = altera_uart_stop_tx,
.stop_rx = altera_uart_stop_rx,
.enable_ms = altera_uart_enable_ms,
.break_ctl = altera_uart_break_ctl,
.startup = altera_uart_startup,
.shutdown = altera_uart_shutdown,
.set_termios = altera_uart_set_termios,
.type = altera_uart_type,
.request_port = altera_uart_request_port,
.release_port = altera_uart_release_port,
.config_port = altera_uart_config_port,
.verify_port = altera_uart_verify_port,
};
static struct altera_uart altera_uart_ports[CONFIG_SERIAL_ALTERA_UART_MAXPORTS];
#if defined(CONFIG_SERIAL_ALTERA_UART_CONSOLE)
int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp)
{
struct uart_port *port;
int i;
for (i = 0; i < CONFIG_SERIAL_ALTERA_UART_MAXPORTS && platp[i].mapbase; i++) {
port = &altera_uart_ports[i].port;
port->line = i;
port->type = PORT_ALTERA_UART;
port->mapbase = platp[i].mapbase;
port->membase = ioremap(port->mapbase, ALTERA_UART_SIZE);
port->iotype = SERIAL_IO_MEM;
port->irq = platp[i].irq;
port->uartclk = platp[i].uartclk;
port->flags = ASYNC_BOOT_AUTOCONF;
port->ops = &altera_uart_ops;
}
return 0;
}
static void altera_uart_console_putc(struct console *co, const char c)
{
struct uart_port *port = &(altera_uart_ports + co->index)->port;
int i;
for (i = 0; i < 0x10000; i++) {
if (readl(port->membase + ALTERA_UART_STATUS_REG) &
ALTERA_UART_STATUS_TRDY_MSK)
break;
}
writel(c, port->membase + ALTERA_UART_TXDATA_REG);
for (i = 0; i < 0x10000; i++) {
if (readl(port->membase + ALTERA_UART_STATUS_REG) &
ALTERA_UART_STATUS_TRDY_MSK)
break;
}
}
static void altera_uart_console_write(struct console *co, const char *s,
unsigned int count)
{
for (; count; count--, s++) {
altera_uart_console_putc(co, *s);
if (*s == '\n')
altera_uart_console_putc(co, '\r');
}
}
static int __init altera_uart_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = CONFIG_SERIAL_ALTERA_UART_BAUDRATE;
int bits = 8;
int parity = 'n';
int flow = 'n';
if (co->index < 0 || co->index >= CONFIG_SERIAL_ALTERA_UART_MAXPORTS)
return -EINVAL;
port = &altera_uart_ports[co->index].port;