Commit e1776fa6 authored by Russell King's avatar Russell King

Merge flint.arm.linux.org.uk:/usr/src/bk/linux-2.6-undo

into flint.arm.linux.org.uk:/usr/src/bk/linux-2.6-serial
parents 373d2673 7acd1ea4
......@@ -29,7 +29,8 @@
#include <linux/sysrq.h>
#include <linux/serial_reg.h>
#include <linux/serial.h>
#include <linux/serialP.h>
#include <linux/serial_8250.h>
#include <linux/circ_buf.h>
#include <linux/delay.h>
#include <linux/device.h>
......@@ -1732,147 +1733,130 @@ serial8250_pm(struct uart_port *port, unsigned int state,
}
/*
* Resource handling. This is complicated by the fact that resources
* depend on the port type. Maybe we should be claiming the standard
* 8250 ports, and then trying to get other resources as necessary?
* Resource handling.
*/
static int
serial8250_request_std_resource(struct uart_8250_port *up, struct resource **res)
static int serial8250_request_std_resource(struct uart_8250_port *up)
{
unsigned int size = 8 << up->port.regshift;
int ret = 0;
switch (up->port.iotype) {
case UPIO_MEM:
if (up->port.mapbase) {
*res = request_mem_region(up->port.mapbase, size, "serial");
if (!*res)
if (!up->port.mapbase)
break;
if (!request_mem_region(up->port.mapbase, size, "serial")) {
ret = -EBUSY;
break;
}
if (up->port.flags & UPF_IOREMAP) {
up->port.membase = ioremap(up->port.mapbase, size);
if (!up->port.membase) {
release_mem_region(up->port.mapbase, size);
ret = -ENOMEM;
}
}
break;
case UPIO_HUB6:
case UPIO_PORT:
*res = request_region(up->port.iobase, size, "serial");
if (!*res)
if (!request_region(up->port.iobase, size, "serial"))
ret = -EBUSY;
break;
}
return ret;
}
static int
serial8250_request_rsa_resource(struct uart_8250_port *up, struct resource **res)
static void serial8250_release_std_resource(struct uart_8250_port *up)
{
unsigned int size = 8 << up->port.regshift;
unsigned long start;
int ret = 0;
switch (up->port.iotype) {
case UPIO_MEM:
if (up->port.mapbase) {
start = up->port.mapbase;
start += UART_RSA_BASE << up->port.regshift;
*res = request_mem_region(start, size, "serial-rsa");
if (!*res)
ret = -EBUSY;
if (!up->port.mapbase)
break;
if (up->port.flags & UPF_IOREMAP) {
iounmap(up->port.membase);
up->port.membase = NULL;
}
release_mem_region(up->port.mapbase, size);
break;
case UPIO_HUB6:
case UPIO_PORT:
start = up->port.iobase;
start += UART_RSA_BASE << up->port.regshift;
*res = request_region(start, size, "serial-rsa");
if (!*res)
ret = -EBUSY;
release_region(up->port.iobase, size);
break;
}
return ret;
}
static void serial8250_release_port(struct uart_port *port)
static int serial8250_request_rsa_resource(struct uart_8250_port *up)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned long start, offset = 0, size = 0;
if (up->port.type == PORT_RSA) {
offset = UART_RSA_BASE << up->port.regshift;
size = 8;
}
size <<= up->port.regshift;
unsigned long start = UART_RSA_BASE << up->port.regshift;
unsigned int size = 8 << up->port.regshift;
int ret = 0;
switch (up->port.iotype) {
case UPIO_MEM:
if (up->port.mapbase) {
/*
* Unmap the area.
*/
iounmap(up->port.membase);
up->port.membase = NULL;
start = up->port.mapbase;
if (size)
release_mem_region(start + offset, size);
release_mem_region(start, 8 << up->port.regshift);
}
ret = -EINVAL;
break;
case UPIO_HUB6:
case UPIO_PORT:
start = up->port.iobase;
start += up->port.iobase;
if (!request_region(start, size, "serial-rsa"))
ret = -EBUSY;
break;
}
if (size)
release_region(start + offset, size);
release_region(start + offset, 8 << up->port.regshift);
return ret;
}
static void serial8250_release_rsa_resource(struct uart_8250_port *up)
{
unsigned long offset = UART_RSA_BASE << up->port.regshift;
unsigned int size = 8 << up->port.regshift;
switch (up->port.iotype) {
case UPIO_MEM:
break;
default:
case UPIO_HUB6:
case UPIO_PORT:
release_region(up->port.iobase + offset, size);
break;
}
}
static void serial8250_release_port(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
serial8250_release_std_resource(up);
if (up->port.type == PORT_RSA)
serial8250_release_rsa_resource(up);
}
static int serial8250_request_port(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
struct resource *res = NULL, *res_rsa = NULL;
int ret = 0;
if (up->port.type == PORT_RSA) {
ret = serial8250_request_rsa_resource(up, &res_rsa);
ret = serial8250_request_std_resource(up);
if (ret == 0 && up->port.type == PORT_RSA) {
ret = serial8250_request_rsa_resource(up);
if (ret < 0)
return ret;
serial8250_release_std_resource(up);
}
ret = serial8250_request_std_resource(up, &res);
/*
* If we have a mapbase, then request that as well.
*/
if (ret == 0 && up->port.flags & UPF_IOREMAP) {
int size = res->end - res->start + 1;
up->port.membase = ioremap(up->port.mapbase, size);
if (!up->port.membase)
ret = -ENOMEM;
}
if (ret < 0) {
if (res_rsa)
release_resource(res_rsa);
if (res)
release_resource(res);
}
return ret;
}
static void serial8250_config_port(struct uart_port *port, int flags)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
struct resource *res_std = NULL, *res_rsa = NULL;
int probeflags = PROBE_ANY;
int ret;
......@@ -1888,11 +1872,11 @@ static void serial8250_config_port(struct uart_port *port, int flags)
* Find the region that we can probe for. This in turn
* tells us whether we can probe for the type of port.
*/
ret = serial8250_request_std_resource(up, &res_std);
ret = serial8250_request_std_resource(up);
if (ret < 0)
return;
ret = serial8250_request_rsa_resource(up, &res_rsa);
ret = serial8250_request_rsa_resource(up);
if (ret < 0)
probeflags &= ~PROBE_RSA;
......@@ -1901,14 +1885,10 @@ static void serial8250_config_port(struct uart_port *port, int flags)
if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
autoconfig_irq(up);
/*
* If the port wasn't an RSA port, release the resource.
*/
if (up->port.type != PORT_RSA && res_rsa)
release_resource(res_rsa);
if (up->port.type == PORT_UNKNOWN && res_std)
release_resource(res_std);
if (up->port.type != PORT_RSA && probeflags & PROBE_RSA)
serial8250_release_rsa_resource(up);
if (up->port.type == PORT_UNKNOWN)
serial8250_release_std_resource(up);
}
static int
......@@ -1964,6 +1944,22 @@ static void __init serial8250_isa_init_ports(void)
return;
first = 0;
for (i = 0; i < UART_NR; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
up->port.line = i;
spin_lock_init(&up->port.lock);
init_timer(&up->timer);
up->timer.function = serial8250_timeout;
/*
* ALPHA_KLUDGE_MCR needs to be killed.
*/
up->mcr_mask = ~ALPHA_KLUDGE_MCR;
up->mcr_force = ALPHA_KLUDGE_MCR;
}
for (i = 0, up = serial8250_ports; i < ARRAY_SIZE(old_serial_port);
i++, up++) {
up->port.iobase = old_serial_port[i].port;
......@@ -1990,18 +1986,8 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
for (i = 0; i < UART_NR; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
up->port.line = i;
up->port.ops = &serial8250_pops;
up->port.dev = dev;
init_timer(&up->timer);
up->timer.function = serial8250_timeout;
/*
* ALPHA_KLUDGE_MCR needs to be killed.
*/
up->mcr_mask = ~ALPHA_KLUDGE_MCR;
up->mcr_force = ALPHA_KLUDGE_MCR;
uart_add_one_port(drv, &up->port);
}
}
......@@ -2105,11 +2091,6 @@ static int __init serial8250_console_setup(struct console *co, char *options)
if (!port->ops)
return -ENODEV;
/*
* Temporary fix.
*/
spin_lock_init(&port->lock);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
......@@ -2170,20 +2151,6 @@ int __init early_serial_setup(struct uart_port *port)
return 0;
}
/*
* This is for ISAPNP only.
*/
void serial8250_get_irq_map(unsigned int *map)
{
int i;
for (i = 0; i < UART_NR; i++) {
if (serial8250_ports[i].port.type != PORT_UNKNOWN &&
serial8250_ports[i].port.irq < 16)
*map |= 1 << serial8250_ports[i].port.irq;
}
}
/**
* serial8250_suspend_port - suspend one serial port
* @line: serial line number
......@@ -2208,6 +2175,55 @@ void serial8250_resume_port(int line)
uart_resume_port(&serial8250_reg, &serial8250_ports[line].port);
}
/*
* Register a set of serial devices attached to a platform device. The
* list is terminated with a zero flags entry, which means we expect
* all entries to have at least UPF_AUTOPROBE set.
*/
static int __devinit serial8250_probe(struct device *dev)
{
struct plat_serial8250_port *p = dev->platform_data;
struct uart_port port;
memset(&port, 0, sizeof(struct uart_port));
for (; p && p->flags != 0; p++) {
port.iobase = p->iobase;
port.membase = p->membase;
port.irq = p->irq;
port.uartclk = p->uartclk;
port.regshift = p->regshift;
port.iotype = p->iotype;
port.flags = p->flags;
port.mapbase = p->mapbase;
port.dev = dev;
if (share_irqs)
port.flags |= UPF_SHARE_IRQ;
serial8250_register_port(&port);
}
return 0;
}
/*
* Remove a platform device. We only remove serial ports from this
* platform device if it actually added any in the first place (iow,
* dev->platform_data is non-NULL.)
*/
static int __devexit serial8250_remove(struct device *dev)
{
int i;
if (dev->platform_data) {
for (i = 0; i < UART_NR; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
if (up->port.dev == dev)
serial8250_unregister_port(i);
}
}
return 0;
}
static int serial8250_suspend(struct device *dev, u32 state, u32 level)
{
int i;
......@@ -2245,11 +2261,18 @@ static int serial8250_resume(struct device *dev, u32 level)
static struct device_driver serial8250_isa_driver = {
.name = "serial8250",
.bus = &platform_bus_type,
.probe = serial8250_probe,
.remove = serial8250_remove,
.suspend = serial8250_suspend,
.resume = serial8250_resume,
};
/*
* This "device" covers _all_ ISA 8250-compatible serial devices listed
* in the table in include/asm-*/serial.h
*/
static struct platform_device *serial8250_isa_devs;
/*
* serial8250_register_port and serial8250_unregister_port allows for
* 16x50 serial ports to be configured at run-time, to support PCMCIA
......@@ -2327,6 +2350,9 @@ int serial8250_register_port(struct uart_port *port)
struct uart_8250_port *uart;
int ret = -ENOSPC;
if (port->uartclk == 0)
return -EINVAL;
down(&serial_sem);
uart = serial8250_find_match_or_unused(port);
......@@ -2370,7 +2396,7 @@ void serial8250_unregister_port(int line)
uart_remove_one_port(&serial8250_reg, &uart->port);
uart->port.flags &= ~UPF_BOOT_AUTOCONF;
uart->port.type = PORT_UNKNOWN;
uart->port.dev = NULL;
uart->port.dev = &serial8250_isa_devs->dev;
uart_add_one_port(&serial8250_reg, &uart->port);
up(&serial_sem);
}
......@@ -2384,22 +2410,29 @@ static int __init serial8250_init(void)
"%d ports, IRQ sharing %sabled\n", (int) UART_NR,
share_irqs ? "en" : "dis");
ret = driver_register(&serial8250_isa_driver);
if (ret)
goto out;
for (i = 0; i < NR_IRQS; i++)
spin_lock_init(&irq_lists[i].lock);
ret = uart_register_driver(&serial8250_reg);
if (ret)
goto out;
serial8250_isa_devs = platform_device_register_simple("serial8250",
-1, NULL, 0);
if (IS_ERR(serial8250_isa_devs)) {
ret = PTR_ERR(serial8250_isa_devs);
goto unreg;
}
serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);
serial8250_register_ports(&serial8250_reg, NULL);
ret = driver_register(&serial8250_isa_driver);
if (ret == 0)
goto out;
platform_device_unregister(serial8250_isa_devs);
unreg:
driver_unregister(&serial8250_isa_driver);
uart_unregister_driver(&serial8250_reg);
out:
return ret;
}
......@@ -2408,17 +2441,22 @@ static void __exit serial8250_exit(void)
{
int i;
for (i = 0; i < UART_NR; i++)
uart_remove_one_port(&serial8250_reg, &serial8250_ports[i].port);
driver_unregister(&serial8250_isa_driver);
for (i = 0; i < UART_NR; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
if (up->port.dev == &serial8250_isa_devs->dev)
uart_remove_one_port(&serial8250_reg, &up->port);
}
platform_device_unregister(serial8250_isa_devs);
uart_unregister_driver(&serial8250_reg);
driver_unregister(&serial8250_isa_driver);
}
module_init(serial8250_init);
module_exit(serial8250_exit);
EXPORT_SYMBOL(serial8250_get_irq_map);
EXPORT_SYMBOL(serial8250_suspend_port);
EXPORT_SYMBOL(serial8250_resume_port);
......
......@@ -19,7 +19,6 @@
int serial8250_register_port(struct uart_port *);
void serial8250_unregister_port(int line);
void serial8250_get_irq_map(unsigned int *map);
void serial8250_suspend_port(int line);
void serial8250_resume_port(int line);
......
......@@ -1313,20 +1313,6 @@ void unregister_serial(int line)
uart_unregister_port(&serial8250_reg, line);
}
/*
* This is for ISAPNP only.
*/
void serial8250_get_irq_map(unsigned int *map)
{
int i;
for (i = 0; i < UART_NR; i++) {
if (serial8250_ports[i].port.type != PORT_UNKNOWN &&
serial8250_ports[i].port.irq < 16)
*map |= 1 << serial8250_ports[i].port.irq;
}
}
/**
* serial8250_suspend_port - suspend one serial port
* @line: serial line number
......@@ -1382,7 +1368,6 @@ module_exit(serial8250_exit);
EXPORT_SYMBOL(register_serial);
EXPORT_SYMBOL(unregister_serial);
EXPORT_SYMBOL(serial8250_get_irq_map);
EXPORT_SYMBOL(serial8250_suspend_port);
EXPORT_SYMBOL(serial8250_resume_port);
......
......@@ -162,8 +162,6 @@ static int uart_startup(struct uart_state *state, int init_hw)
return -ENOMEM;
info->xmit.buf = (unsigned char *) page;
info->tmpbuf = info->xmit.buf + UART_XMIT_SIZE;
init_MUTEX(&info->tmpbuf_sem);
uart_circ_clear(&info->xmit);
}
......@@ -238,7 +236,6 @@ static void uart_shutdown(struct uart_state *state)
if (info->xmit.buf) {
free_page((unsigned long)info->xmit.buf);
info->xmit.buf = NULL;
info->tmpbuf = NULL;
}
/*
......@@ -450,53 +447,30 @@ __uart_put_char(struct uart_port *port, struct circ_buf *circ, unsigned char c)
spin_unlock_irqrestore(&port->lock, flags);
}
static inline int
__uart_user_write(struct uart_port *port, struct circ_buf *circ,
const unsigned char __user *buf, int count)
static void uart_put_char(struct tty_struct *tty, unsigned char ch)
{
unsigned long flags;
int c, ret = 0;
if (down_interruptible(&port->info->tmpbuf_sem))
return -EINTR;
while (1) {
int c1;
c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
if (count < c)
c = count;
if (c <= 0)
break;
struct uart_state *state = tty->driver_data;
c -= copy_from_user(port->info->tmpbuf, buf, c);
if (!c) {
if (!ret)
ret = -EFAULT;
break;
}
spin_lock_irqsave(&port->lock, flags);
c1 = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
if (c1 < c)
c = c1;
memcpy(circ->buf + circ->head, port->info->tmpbuf, c);
circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
spin_unlock_irqrestore(&port->lock, flags);
buf += c;
count -= c;
ret += c;
}
up(&port->info->tmpbuf_sem);
__uart_put_char(state->port, &state->info->xmit, ch);
}
return ret;
static void uart_flush_chars(struct tty_struct *tty)
{
uart_start(tty);
}
static inline int
__uart_kern_write(struct uart_port *port, struct circ_buf *circ,
const unsigned char *buf, int count)
static int
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;
unsigned long flags;
int c, ret = 0;
if (!circ->buf)
return 0;
spin_lock_irqsave(&port->lock, flags);
while (1) {
c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
......@@ -512,33 +486,6 @@ __uart_kern_write(struct uart_port *port, struct circ_buf *circ,
}
spin_unlock_irqrestore(&port->lock, flags);
return ret;
}
static void uart_put_char(struct tty_struct *tty, unsigned char ch)
{
struct uart_state *state = tty->driver_data;
__uart_put_char(state->port, &state->info->xmit, ch);
}
static void uart_flush_chars(struct tty_struct *tty)
{
uart_start(tty);
}
static int
uart_write(struct tty_struct *tty, const unsigned char * buf, int count)
{
struct uart_state *state = tty->driver_data;
int ret;
if (!state->info->xmit.buf)
return 0;
ret = __uart_kern_write(state->port, &state->info->xmit,
buf, count);
uart_start(tty);
return ret;
}
......
/*
* linux/include/linux/serial_8250.h
*
* Copyright (C) 2004 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef _LINUX_SERIAL_8250_H
#define _LINUX_SERIAL_8250_H
#include <linux/serial_core.h>
#include <linux/device.h>
struct plat_serial8250_port {
unsigned long iobase; /* io base address */
void __iomem *membase; /* ioremap cookie or NULL */
unsigned long mapbase; /* resource base */
unsigned int irq; /* interrupt number */
unsigned int uartclk; /* UART clock rate */
unsigned char regshift; /* register shift */
unsigned char iotype; /* UPIO_* */
unsigned int flags; /* UPF_* flags */
};
#endif
......@@ -17,6 +17,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef LINUX_SERIAL_CORE_H
#define LINUX_SERIAL_CORE_H
/*
* The type definitions. These are from Ted Ts'o's serial.h
......@@ -96,6 +98,7 @@
#include <linux/circ_buf.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/tty.h>
struct uart_port;
struct uart_info;
......@@ -246,7 +249,7 @@ struct uart_state {
struct semaphore sem;
};
#define UART_XMIT_SIZE 1024
#define UART_XMIT_SIZE PAGE_SIZE
/*
* This is the state information which is only valid when the port
* is open; it may be freed by the core driver once the device has
......@@ -268,9 +271,6 @@ struct uart_info {
#define UIF_NORMAL_ACTIVE (1 << 29)
#define UIF_INITIALIZED (1 << 31)
unsigned char *tmpbuf;
struct semaphore tmpbuf_sem;
int blocked_open;
struct tasklet_struct tlet;
......@@ -458,3 +458,5 @@ uart_handle_cts_change(struct uart_port *port, unsigned int status)
!((cflag) & CLOCAL))
#endif
#endif /* LINUX_SERIAL_CORE_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment