#include <linux/device.h>
#include <linux/serial.h> /* for serial_state and serial_icounter_struct */
#include <linux/delay.h>
+#include <linux/mutex.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
/*
* This is used to lock changes in serial line configuration.
*/
-static DECLARE_MUTEX(port_sem);
+static DEFINE_MUTEX(port_mutex);
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
void uart_write_wakeup(struct uart_port *port)
{
struct uart_info *info = port->info;
+ /*
+ * This means you called this function _after_ the port was
+ * closed. No cookie for you.
+ */
+ BUG_ON(!info);
tasklet_schedule(&info->tlet);
}
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
- port->ops->stop_tx(port, 1);
+ port->ops->stop_tx(port);
spin_unlock_irqrestore(&port->lock, flags);
}
if (!uart_circ_empty(&state->info->xmit) && state->info->xmit.buf &&
!tty->stopped && !tty->hw_stopped)
- port->ops->start_tx(port, 1);
+ port->ops->start_tx(port);
}
static void uart_start(struct tty_struct *tty)
* once we have successfully opened the port. Also set
* up the tty->alt_speed kludge
*/
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
if (port->type == PORT_UNKNOWN)
return 0;
uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
}
+ if (info->flags & UIF_CTS_FLOW) {
+ spin_lock_irq(&port->lock);
+ if (!(port->ops->get_mctrl(port) & TIOCM_CTS))
+ info->tty->hw_stopped = 1;
+ spin_unlock_irq(&port->lock);
+ }
+
info->flags |= UIF_INITIALIZED;
clear_bit(TTY_IO_ERROR, &info->tty->flags);
struct uart_info *info = state->info;
struct uart_port *port = state->port;
- if (!(info->flags & UIF_INITIALIZED))
- return;
-
/*
- * Turn off DTR and RTS early.
+ * Set the TTY IO error marker
*/
- if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
- uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
- /*
- * clear delta_msr_wait queue to avoid mem leaks: we may free
- * the irq here so the queue might never be woken up. Note
- * that we won't end up waiting on delta_msr_wait again since
- * any outstanding file descriptors should be pointing at
- * hung_up_tty_fops now.
- */
- wake_up_interruptible(&info->delta_msr_wait);
+ if (info->flags & UIF_INITIALIZED) {
+ info->flags &= ~UIF_INITIALIZED;
- /*
- * Free the IRQ and disable the port.
- */
- port->ops->shutdown(port);
+ /*
+ * Turn off DTR and RTS early.
+ */
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+ uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+
+ /*
+ * clear delta_msr_wait queue to avoid mem leaks: we may free
+ * the irq here so the queue might never be woken up. Note
+ * that we won't end up waiting on delta_msr_wait again since
+ * any outstanding file descriptors should be pointing at
+ * hung_up_tty_fops now.
+ */
+ wake_up_interruptible(&info->delta_msr_wait);
+
+ /*
+ * Free the IRQ and disable the port.
+ */
+ port->ops->shutdown(port);
+
+ /*
+ * Ensure that the IRQ handler isn't running on another CPU.
+ */
+ synchronize_irq(port->irq);
+ }
/*
- * Ensure that the IRQ handler isn't running on another CPU.
+ * kill off our tasklet
*/
- synchronize_irq(port->irq);
+ tasklet_kill(&info->tlet);
/*
* Free the transmit buffer page.
free_page((unsigned long)info->xmit.buf);
info->xmit.buf = NULL;
}
-
- /*
- * kill off our tasklet
- */
- tasklet_kill(&info->tlet);
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
-
- info->flags &= ~UIF_INITIALIZED;
}
/**
struct termios *old, unsigned int min, unsigned int max)
{
unsigned int try, baud, altbaud = 38400;
- unsigned int flags = port->flags & UPF_SPD_MASK;
+ upf_t flags = port->flags & UPF_SPD_MASK;
if (flags == UPF_SPD_HI)
altbaud = 57600;
}
static int
-uart_write(struct tty_struct *tty, const unsigned char * buf, int count)
+uart_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
struct uart_state *state = tty->driver_data;
- struct uart_port *port = state->port;
- struct circ_buf *circ = &state->info->xmit;
+ struct uart_port *port;
+ struct circ_buf *circ;
unsigned long flags;
int c, ret = 0;
+ /*
+ * This means you called this function _after_ the port was
+ * closed. No cookie for you.
+ */
+ if (!state || !state->info) {
+ WARN_ON(1);
+ return -EL3HLT;
+ }
+
+ port = state->port;
+ circ = &state->info->xmit;
+
if (!circ->buf)
return 0;
struct uart_port *port = state->port;
unsigned long flags;
+ /*
+ * This means you called this function _after_ the port was
+ * closed. No cookie for you.
+ */
+ if (!state || !state->info) {
+ WARN_ON(1);
+ return;
+ }
+
DPRINTK("uart_flush_buffer(%d) called\n", tty->index);
spin_lock_irqsave(&port->lock, flags);
port->x_char = ch;
if (ch) {
spin_lock_irqsave(&port->lock, flags);
- port->ops->start_tx(port, 0);
+ port->ops->start_tx(port);
spin_unlock_irqrestore(&port->lock, flags);
}
}
struct serial_struct new_serial;
struct uart_port *port = state->port;
unsigned long new_port;
- unsigned int change_irq, change_port, old_flags, closing_wait;
+ unsigned int change_irq, change_port, closing_wait;
unsigned int old_custom_divisor, close_delay;
+ upf_t old_flags, new_flags;
int retval = 0;
if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
* module insertion/removal doesn't change anything
* under us.
*/
- down(&state->sem);
+ mutex_lock(&state->mutex);
change_irq = new_serial.irq != port->irq;
new_serial.type != port->type;
old_flags = port->flags;
+ new_flags = new_serial.flags;
old_custom_divisor = port->custom_divisor;
if (!capable(CAP_SYS_ADMIN)) {
(close_delay != state->close_delay) ||
(closing_wait != state->closing_wait) ||
(new_serial.xmit_fifo_size != port->fifosize) ||
- (((new_serial.flags ^ old_flags) & ~UPF_USR_MASK) != 0))
+ (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0))
goto exit;
port->flags = ((port->flags & ~UPF_USR_MASK) |
- (new_serial.flags & UPF_USR_MASK));
+ (new_flags & UPF_USR_MASK));
port->custom_divisor = new_serial.custom_divisor;
goto check_and_exit;
}
port->irq = new_serial.irq;
port->uartclk = new_serial.baud_base * 16;
port->flags = (port->flags & ~UPF_CHANGE_MASK) |
- (new_serial.flags & UPF_CHANGE_MASK);
+ (new_flags & UPF_CHANGE_MASK);
port->custom_divisor = new_serial.custom_divisor;
state->close_delay = close_delay;
state->closing_wait = closing_wait;
} else
retval = uart_startup(state, 1);
exit:
- up(&state->sem);
+ mutex_unlock(&state->mutex);
return retval;
}
struct uart_port *port = state->port;
int result = -EIO;
- down(&state->sem);
+ mutex_lock(&state->mutex);
if ((!file || !tty_hung_up_p(file)) &&
!(tty->flags & (1 << TTY_IO_ERROR))) {
result = port->mctrl;
+
+ spin_lock_irq(&port->lock);
result |= port->ops->get_mctrl(port);
+ spin_unlock_irq(&port->lock);
}
- up(&state->sem);
+ mutex_unlock(&state->mutex);
return result;
}
struct uart_port *port = state->port;
int ret = -EIO;
- down(&state->sem);
+ mutex_lock(&state->mutex);
if ((!file || !tty_hung_up_p(file)) &&
!(tty->flags & (1 << TTY_IO_ERROR))) {
uart_update_mctrl(port, set, clear);
ret = 0;
}
- up(&state->sem);
+ mutex_unlock(&state->mutex);
return ret;
}
BUG_ON(!kernel_locked());
- down(&state->sem);
+ mutex_lock(&state->mutex);
if (port->type != PORT_UNKNOWN)
port->ops->break_ctl(port, break_state);
- up(&state->sem);
+ mutex_unlock(&state->mutex);
}
static int uart_do_autoconfig(struct uart_state *state)
* changing, and hence any extra opens of the port while
* we're auto-configuring.
*/
- if (down_interruptible(&state->sem))
+ if (mutex_lock_interruptible(&state->mutex))
return -ERESTARTSYS;
ret = -EBUSY;
ret = uart_startup(state, 1);
}
- up(&state->sem);
+ mutex_unlock(&state->mutex);
return ret;
}
if (ret != -ENOIOCTLCMD)
goto out;
- down(&state->sem);
+ mutex_lock(&state->mutex);
if (tty_hung_up_p(filp)) {
ret = -EIO;
}
}
out_up:
- up(&state->sem);
+ mutex_unlock(&state->mutex);
out:
return ret;
}
spin_unlock_irqrestore(&state->port->lock, flags);
}
+ /* Handle turning on CRTSCTS */
+ if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
+ spin_lock_irqsave(&state->port->lock, flags);
+ if (!(state->port->ops->get_mctrl(state->port) & TIOCM_CTS)) {
+ tty->hw_stopped = 1;
+ state->port->ops->stop_tx(state->port);
+ }
+ spin_unlock_irqrestore(&state->port->lock, flags);
+ }
+
#if 0
/*
* No need to wake up processes in open wait, since they
DPRINTK("uart_close(%d) called\n", port->line);
- down(&state->sem);
+ mutex_lock(&state->mutex);
if (tty_hung_up_p(filp))
goto done;
wake_up_interruptible(&state->info->open_wait);
done:
- up(&state->sem);
+ mutex_unlock(&state->mutex);
}
static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
BUG_ON(!kernel_locked());
DPRINTK("uart_hangup(%d)\n", state->port->line);
- down(&state->sem);
+ mutex_lock(&state->mutex);
if (state->info && state->info->flags & UIF_NORMAL_ACTIVE) {
uart_flush_buffer(tty);
uart_shutdown(state);
wake_up_interruptible(&state->info->open_wait);
wake_up_interruptible(&state->info->delta_msr_wait);
}
- up(&state->sem);
+ mutex_unlock(&state->mutex);
}
/*
DECLARE_WAITQUEUE(wait, current);
struct uart_info *info = state->info;
struct uart_port *port = state->port;
+ unsigned int mctrl;
info->blocked_open++;
state->count--;
* and wait for the carrier to indicate that the
* modem is ready for us.
*/
- if (port->ops->get_mctrl(port) & TIOCM_CAR)
+ spin_lock_irq(&port->lock);
+ port->ops->enable_ms(port);
+ mctrl = port->ops->get_mctrl(port);
+ spin_unlock_irq(&port->lock);
+ if (mctrl & TIOCM_CAR)
break;
- up(&state->sem);
+ mutex_unlock(&state->mutex);
schedule();
- down(&state->sem);
+ mutex_lock(&state->mutex);
if (signal_pending(current))
break;
static struct uart_state *uart_get(struct uart_driver *drv, int line)
{
struct uart_state *state;
+ int ret = 0;
- down(&port_sem);
state = drv->state + line;
- if (down_interruptible(&state->sem)) {
- state = ERR_PTR(-ERESTARTSYS);
- goto out;
+ if (mutex_lock_interruptible(&state->mutex)) {
+ ret = -ERESTARTSYS;
+ goto err;
}
state->count++;
- if (!state->port) {
- state->count--;
- up(&state->sem);
- state = ERR_PTR(-ENXIO);
- goto out;
+ if (!state->port || state->port->flags & UPF_DEAD) {
+ ret = -ENXIO;
+ goto err_unlock;
}
if (!state->info) {
tasklet_init(&state->info->tlet, uart_tasklet_action,
(unsigned long)state);
} else {
- state->count--;
- up(&state->sem);
- state = ERR_PTR(-ENOMEM);
+ ret = -ENOMEM;
+ goto err_unlock;
}
}
-
- out:
- up(&port_sem);
return state;
+
+ err_unlock:
+ state->count--;
+ mutex_unlock(&state->mutex);
+ err:
+ return ERR_PTR(ret);
}
/*
if (tty_hung_up_p(filp)) {
retval = -EAGAIN;
state->count--;
- up(&state->sem);
+ mutex_unlock(&state->mutex);
goto fail;
}
*/
if (retval == 0)
retval = uart_block_til_ready(filp, state);
- up(&state->sem);
+ mutex_unlock(&state->mutex);
/*
* If this is the first open to succeed, adjust things to suit.
if(capable(CAP_SYS_ADMIN))
{
+ spin_lock_irq(&port->lock);
status = port->ops->get_mctrl(port);
+ spin_unlock_irq(&port->lock);
ret += sprintf(buf + ret, " tx:%d rx:%d",
port->icount.tx, port->icount.rx);
#endif
#ifdef CONFIG_SERIAL_CORE_CONSOLE
+/*
+ * uart_console_write - write a console message to a serial port
+ * @port: the port to write the message
+ * @s: array of characters
+ * @count: number of characters in string to write
+ * @write: function to write character to port
+ */
+void uart_console_write(struct uart_port *port, const char *s,
+ unsigned int count,
+ void (*putchar)(struct uart_port *, int))
+{
+ unsigned int i;
+
+ for (i = 0; i < count; i++, s++) {
+ if (*s == '\n')
+ putchar(port, '\r');
+ putchar(port, *s);
+ }
+}
+EXPORT_SYMBOL_GPL(uart_console_write);
+
/*
* Check whether an invalid uart number has been specified, and
* if so, search for the first available port that does have
unsigned int cflag;
};
-static struct baud_rates baud_rates[] = {
+static const struct baud_rates baud_rates[] = {
{ 921600, B921600 },
{ 460800, B460800 },
{ 230400, B230400 },
struct termios termios;
int i;
+ /*
+ * Ensure that the serial console lock is initialised
+ * early.
+ */
+ spin_lock_init(&port->lock);
+
memset(&termios, 0, sizeof(struct termios));
termios.c_cflag = CREAD | HUPCL | CLOCAL;
static void uart_change_pm(struct uart_state *state, int pm_state)
{
struct uart_port *port = state->port;
- if (port->ops->pm)
- port->ops->pm(port, pm_state, state->pm_state);
- state->pm_state = pm_state;
+
+ if (state->pm_state != pm_state) {
+ if (port->ops->pm)
+ port->ops->pm(port, pm_state, state->pm_state);
+ state->pm_state = pm_state;
+ }
}
int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
{
struct uart_state *state = drv->state + port->line;
- down(&state->sem);
+ mutex_lock(&state->mutex);
if (state->info && state->info->flags & UIF_INITIALIZED) {
- struct uart_ops *ops = port->ops;
+ const struct uart_ops *ops = port->ops;
spin_lock_irq(&port->lock);
- ops->stop_tx(port, 0);
+ ops->stop_tx(port);
ops->set_mctrl(port, 0);
ops->stop_rx(port);
spin_unlock_irq(&port->lock);
uart_change_pm(state, 3);
- up(&state->sem);
+ mutex_unlock(&state->mutex);
return 0;
}
{
struct uart_state *state = drv->state + port->line;
- down(&state->sem);
+ mutex_lock(&state->mutex);
uart_change_pm(state, 0);
* Re-enable the console device after suspending.
*/
if (uart_console(port)) {
- uart_change_speed(state, NULL);
+ struct termios termios;
+
+ /*
+ * First try to use the console cflag setting.
+ */
+ memset(&termios, 0, sizeof(struct termios));
+ termios.c_cflag = port->cons->cflag;
+
+ /*
+ * If that's unset, use the tty termios setting.
+ */
+ if (state->info && state->info->tty && termios.c_cflag == 0)
+ termios = *state->info->tty->termios;
+
+ port->ops->set_termios(port, &termios, NULL);
console_start(port->cons);
}
if (state->info && state->info->flags & UIF_INITIALIZED) {
- struct uart_ops *ops = port->ops;
+ const struct uart_ops *ops = port->ops;
+ int ret;
ops->set_mctrl(port, 0);
- ops->startup(port);
- uart_change_speed(state, NULL);
- spin_lock_irq(&port->lock);
- ops->set_mctrl(port, port->mctrl);
- ops->start_tx(port, 0);
- spin_unlock_irq(&port->lock);
+ ret = ops->startup(port);
+ if (ret == 0) {
+ uart_change_speed(state, NULL);
+ spin_lock_irq(&port->lock);
+ ops->set_mctrl(port, port->mctrl);
+ ops->start_tx(port);
+ spin_unlock_irq(&port->lock);
+ } else {
+ /*
+ * Failed to resume - maybe hardware went away?
+ * Clear the "initialized" flag so we won't try
+ * to call the low level drivers shutdown method.
+ */
+ state->info->flags &= ~UIF_INITIALIZED;
+ uart_shutdown(state);
+ }
}
- up(&state->sem);
+ mutex_unlock(&state->mutex);
return 0;
}
static inline void
uart_report_port(struct uart_driver *drv, struct uart_port *port)
{
- printk("%s%d", drv->dev_name, port->line);
- printk(" at ");
+ char address[64];
+
switch (port->iotype) {
case UPIO_PORT:
- printk("I/O 0x%x", port->iobase);
+ snprintf(address, sizeof(address),
+ "I/O 0x%x", port->iobase);
break;
case UPIO_HUB6:
- printk("I/O 0x%x offset 0x%x", port->iobase, port->hub6);
+ snprintf(address, sizeof(address),
+ "I/O 0x%x offset 0x%x", port->iobase, port->hub6);
break;
case UPIO_MEM:
case UPIO_MEM32:
- printk("MMIO 0x%lx", port->mapbase);
+ case UPIO_AU:
+ snprintf(address, sizeof(address),
+ "MMIO 0x%lx", port->mapbase);
+ break;
+ default:
+ strlcpy(address, "*unknown*", sizeof(address));
break;
}
- printk(" (irq = %d) is a %s\n", port->irq, uart_type(port));
+
+ printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n",
+ port->dev ? port->dev->bus_id : "",
+ port->dev ? ": " : "",
+ drv->dev_name, port->line, address, port->irq, uart_type(port));
}
static void
}
}
-/*
- * This reverses the effects of uart_configure_port, hanging up the
- * port before removal.
- */
-static void
-uart_unconfigure_port(struct uart_driver *drv, struct uart_state *state)
-{
- struct uart_port *port = state->port;
- struct uart_info *info = state->info;
-
- if (info && info->tty)
- tty_vhangup(info->tty);
-
- down(&state->sem);
-
- state->info = NULL;
-
- /*
- * Free the port IO and memory resources, if any.
- */
- if (port->type != PORT_UNKNOWN)
- port->ops->release_port(port);
-
- /*
- * Indicate that there isn't a port here anymore.
- */
- port->type = PORT_UNKNOWN;
-
- /*
- * Kill the tasklet, and free resources.
- */
- if (info) {
- tasklet_kill(&info->tlet);
- kfree(info);
- }
-
- up(&state->sem);
-}
-
static struct tty_operations uart_ops = {
.open = uart_open,
.close = uart_close,
state->close_delay = 500; /* .5 seconds */
state->closing_wait = 30000; /* 30 seconds */
- init_MUTEX(&state->sem);
+ mutex_init(&state->mutex);
}
retval = tty_register_driver(normal);
state = drv->state + port->line;
- down(&port_sem);
+ mutex_lock(&port_mutex);
+ mutex_lock(&state->mutex);
if (state->port) {
ret = -EINVAL;
goto out;
state->port = port;
- spin_lock_init(&port->lock);
port->cons = drv->cons;
port->info = state->info;
+ /*
+ * If this port is a console, then the spinlock is already
+ * initialised.
+ */
+ if (!(uart_console(port) && (port->cons->flags & CON_ENABLED)))
+ spin_lock_init(&port->lock);
+
uart_configure_port(drv, state, port);
/*
port->cons && !(port->cons->flags & CON_ENABLED))
register_console(port->cons);
+ /*
+ * Ensure UPF_DEAD is not set.
+ */
+ port->flags &= ~UPF_DEAD;
+
out:
- up(&port_sem);
+ mutex_unlock(&state->mutex);
+ mutex_unlock(&port_mutex);
return ret;
}
int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
{
struct uart_state *state = drv->state + port->line;
+ struct uart_info *info;
BUG_ON(in_interrupt());
printk(KERN_ALERT "Removing wrong port: %p != %p\n",
state->port, port);
- down(&port_sem);
+ mutex_lock(&port_mutex);
+
+ /*
+ * Mark the port "dead" - this prevents any opens from
+ * succeeding while we shut down the port.
+ */
+ mutex_lock(&state->mutex);
+ port->flags |= UPF_DEAD;
+ mutex_unlock(&state->mutex);
/*
* Remove the devices from devfs
*/
tty_unregister_device(drv->tty_driver, port->line);
- uart_unconfigure_port(drv, state);
+ info = state->info;
+ if (info && info->tty)
+ tty_vhangup(info->tty);
+
+ /*
+ * All users of this port should now be disconnected from
+ * this driver, and the port shut down. We should be the
+ * only thread fiddling with this port from now on.
+ */
+ state->info = NULL;
+
+ /*
+ * Free the port IO and memory resources, if any.
+ */
+ if (port->type != PORT_UNKNOWN)
+ port->ops->release_port(port);
+
+ /*
+ * Indicate that there isn't a port here anymore.
+ */
+ port->type = PORT_UNKNOWN;
+
+ /*
+ * Kill the tasklet, and free resources.
+ */
+ if (info) {
+ tasklet_kill(&info->tlet);
+ kfree(info);
+ }
+
state->port = NULL;
- up(&port_sem);
+ mutex_unlock(&port_mutex);
return 0;
}
/*
* Are the two ports equivalent?
*/
-static int uart_match_port(struct uart_port *port1, struct uart_port *port2)
+int uart_match_port(struct uart_port *port1, struct uart_port *port2)
{
if (port1->iotype != port2->iotype)
return 0;
return (port1->iobase == port2->iobase) &&
(port1->hub6 == port2->hub6);
case UPIO_MEM:
- return (port1->membase == port2->membase);
+ return (port1->mapbase == port2->mapbase);
}
return 0;
}
-
-/*
- * Try to find an unused uart_state slot for a port.
- */
-static struct uart_state *
-uart_find_match_or_unused(struct uart_driver *drv, struct uart_port *port)
-{
- int i;
-
- /*
- * First, find a port entry which matches. Note: if we do
- * find a matching entry, and it has a non-zero use count,
- * then we can't register the port.
- */
- for (i = 0; i < drv->nr; i++)
- if (uart_match_port(drv->state[i].port, port))
- return &drv->state[i];
-
- /*
- * We didn't find a matching entry, so look for the first
- * free entry. We look for one which hasn't been previously
- * used (indicated by zero iobase).
- */
- for (i = 0; i < drv->nr; i++)
- if (drv->state[i].port->type == PORT_UNKNOWN &&
- drv->state[i].port->iobase == 0 &&
- drv->state[i].count == 0)
- return &drv->state[i];
-
- /*
- * That also failed. Last resort is to find any currently
- * entry which doesn't have a real port associated with it.
- */
- for (i = 0; i < drv->nr; i++)
- if (drv->state[i].port->type == PORT_UNKNOWN &&
- drv->state[i].count == 0)
- return &drv->state[i];
-
- return NULL;
-}
-
-/**
- * uart_register_port: register uart settings with a port
- * @drv: pointer to the uart low level driver structure for this port
- * @port: uart port structure describing the port
- *
- * Register UART settings with the specified low level driver. Detect
- * the type of the port if UPF_BOOT_AUTOCONF is set, and detect the
- * IRQ if UPF_AUTO_IRQ is set.
- *
- * We try to pick the same port for the same IO base address, so that
- * when a modem is plugged in, unplugged and plugged back in, it gets
- * allocated the same port.
- *
- * Returns negative error, or positive line number.
- */
-int uart_register_port(struct uart_driver *drv, struct uart_port *port)
-{
- struct uart_state *state;
- int ret;
-
- down(&port_sem);
-
- state = uart_find_match_or_unused(drv, port);
-
- if (state) {
- /*
- * Ok, we've found a line that we can use.
- *
- * If we find a port that matches this one, and it appears
- * to be in-use (even if it doesn't have a type) we shouldn't
- * alter it underneath itself - the port may be open and
- * trying to do useful work.
- */
- if (uart_users(state) != 0) {
- ret = -EBUSY;
- goto out;
- }
-
- /*
- * If the port is already initialised, don't touch it.
- */
- if (state->port->type == PORT_UNKNOWN) {
- state->port->iobase = port->iobase;
- state->port->membase = port->membase;
- state->port->irq = port->irq;
- state->port->uartclk = port->uartclk;
- state->port->fifosize = port->fifosize;
- state->port->regshift = port->regshift;
- state->port->iotype = port->iotype;
- state->port->flags = port->flags;
- state->port->line = state - drv->state;
- state->port->mapbase = port->mapbase;
-
- uart_configure_port(drv, state, state->port);
- }
-
- ret = state->port->line;
- } else
- ret = -ENOSPC;
- out:
- up(&port_sem);
- return ret;
-}
-
-/**
- * uart_unregister_port - de-allocate a port
- * @drv: pointer to the uart low level driver structure for this port
- * @line: line index previously returned from uart_register_port()
- *
- * Hang up the specified line associated with the low level driver,
- * and mark the port as unused.
- */
-void uart_unregister_port(struct uart_driver *drv, int line)
-{
- struct uart_state *state;
-
- if (line < 0 || line >= drv->nr) {
- printk(KERN_ERR "Attempt to unregister ");
- printk("%s%d", drv->dev_name, line);
- printk("\n");
- return;
- }
-
- state = drv->state + line;
-
- down(&port_sem);
- uart_unconfigure_port(drv, state);
- up(&port_sem);
-}
+EXPORT_SYMBOL(uart_match_port);
EXPORT_SYMBOL(uart_write_wakeup);
EXPORT_SYMBOL(uart_register_driver);
EXPORT_SYMBOL(uart_unregister_driver);
EXPORT_SYMBOL(uart_suspend_port);
EXPORT_SYMBOL(uart_resume_port);
-EXPORT_SYMBOL(uart_register_port);
-EXPORT_SYMBOL(uart_unregister_port);
EXPORT_SYMBOL(uart_add_one_port);
EXPORT_SYMBOL(uart_remove_one_port);