diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2008-10-15 23:16:07 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2008-10-15 23:16:07 +0100 |
commit | 2502991560dc8244dbe10e48473d85722c1e2ec1 (patch) | |
tree | 63b1f3be2ed56ff06f1e8db709e4ce85d69c3add /drivers/serial | |
parent | 7e69a8c4d06b7ecb874f571e82b715a9f79bc3c4 (diff) | |
parent | a9ff8f6462635c8d9f8d64b7b10ddcea8404d77b (diff) | |
download | op-kernel-dev-2502991560dc8244dbe10e48473d85722c1e2ec1.zip op-kernel-dev-2502991560dc8244dbe10e48473d85722c1e2ec1.tar.gz |
Merge branch 'fixes' into for-linus
Conflicts:
arch/arm/mach-versatile/core.c
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/8250.c | 52 | ||||
-rw-r--r-- | drivers/serial/8250_pci.c | 4 | ||||
-rw-r--r-- | drivers/serial/Kconfig | 17 | ||||
-rw-r--r-- | drivers/serial/Makefile | 16 | ||||
-rw-r--r-- | drivers/serial/bfin_5xx.c | 123 | ||||
-rw-r--r-- | drivers/serial/crisv10.c | 5 | ||||
-rw-r--r-- | drivers/serial/mcfserial.c | 1965 | ||||
-rw-r--r-- | drivers/serial/mcfserial.h | 74 | ||||
-rw-r--r-- | drivers/serial/serial_core.c | 12 | ||||
-rw-r--r-- | drivers/serial/serial_cs.c | 302 | ||||
-rw-r--r-- | drivers/serial/sunhv.c | 2 | ||||
-rw-r--r-- | drivers/serial/sunsab.c | 2 | ||||
-rw-r--r-- | drivers/serial/sunsu.c | 2 | ||||
-rw-r--r-- | drivers/serial/sunzilog.c | 2 |
14 files changed, 285 insertions, 2293 deletions
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 8058533..ec39203 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -44,6 +44,10 @@ #include "8250.h" +#ifdef CONFIG_SPARC +#include "suncore.h" +#endif + /* * Configuration: * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option @@ -53,6 +57,13 @@ static unsigned int share_irqs = SERIAL8250_SHARE_IRQS; static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS; +static struct uart_driver serial8250_reg; + +static int serial_index(struct uart_port *port) +{ + return (serial8250_reg.minor - 64) + port->line; +} + /* * Debugging. */ @@ -536,7 +547,7 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) /* * FIFO support. */ -static inline void serial8250_clear_fifos(struct uart_8250_port *p) +static void serial8250_clear_fifos(struct uart_8250_port *p) { if (p->capabilities & UART_CAP_FIFO) { serial_outp(p, UART_FCR, UART_FCR_ENABLE_FIFO); @@ -551,7 +562,7 @@ static inline void serial8250_clear_fifos(struct uart_8250_port *p) * capability" bit enabled. Note that on XR16C850s, we need to * reset LCR to write to IER. */ -static inline void serial8250_set_sleep(struct uart_8250_port *p, int sleep) +static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) { if (p->capabilities & UART_CAP_SLEEP) { if (p->capabilities & UART_CAP_EFR) { @@ -993,7 +1004,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) return; DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%p): ", - up->port.line, up->port.iobase, up->port.membase); + serial_index(&up->port), up->port.iobase, up->port.membase); /* * We really do need global IRQs disabled here - we're going to @@ -1128,8 +1139,8 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) if (up->capabilities != uart_config[up->port.type].flags) { printk(KERN_WARNING "ttyS%d: detected caps %08x should be %08x\n", - up->port.line, up->capabilities, - uart_config[up->port.type].flags); + serial_index(&up->port), up->capabilities, + uart_config[up->port.type].flags); } up->port.fifosize = uart_config[up->port.type].fifo_size; @@ -1424,8 +1435,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up) /* * This handles the interrupt from one port. */ -static inline void -serial8250_handle_port(struct uart_8250_port *up) +static void serial8250_handle_port(struct uart_8250_port *up) { unsigned int status; unsigned long flags; @@ -1719,7 +1729,7 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state) /* * Wait for transmitter & holding register to empty */ -static inline void wait_for_xmitr(struct uart_8250_port *up, int bits) +static void wait_for_xmitr(struct uart_8250_port *up, int bits) { unsigned int status, tmout = 10000; @@ -1854,7 +1864,8 @@ static int serial8250_startup(struct uart_port *port) */ if (!(up->port.flags & UPF_BUGGY_UART) && (serial_inp(up, UART_LSR) == 0xff)) { - printk("ttyS%d: LSR safety check engaged!\n", up->port.line); + printk(KERN_INFO "ttyS%d: LSR safety check engaged!\n", + serial_index(&up->port)); return -ENODEV; } @@ -1909,7 +1920,8 @@ static int serial8250_startup(struct uart_port *port) */ if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) { up->bugs |= UART_BUG_THRE; - pr_debug("ttyS%d - using backup timer\n", port->line); + pr_debug("ttyS%d - using backup timer\n", + serial_index(port)); } } @@ -1969,7 +1981,7 @@ static int serial8250_startup(struct uart_port *port) if (!(up->bugs & UART_BUG_TXEN)) { up->bugs |= UART_BUG_TXEN; pr_debug("ttyS%d - enabling bad tx status workarounds\n", - port->line); + serial_index(port)); } } else { up->bugs &= ~UART_BUG_TXEN; @@ -2637,7 +2649,6 @@ static int serial8250_console_early_setup(void) return serial8250_find_port_for_earlycon(); } -static struct uart_driver serial8250_reg; static struct console serial8250_console = { .name = "ttyS", .write = serial8250_console_write, @@ -2684,7 +2695,6 @@ static struct uart_driver serial8250_reg = { .dev_name = "ttyS", .major = TTY_MAJOR, .minor = 64, - .nr = UART_NR, .cons = SERIAL8250_CONSOLE, }; @@ -2966,10 +2976,12 @@ static int __init serial8250_init(void) "%d ports, IRQ sharing %sabled\n", nr_uarts, share_irqs ? "en" : "dis"); - for (i = 0; i < NR_IRQS; i++) - spin_lock_init(&irq_lists[i].lock); - +#ifdef CONFIG_SPARC + ret = sunserial_register_minors(&serial8250_reg, UART_NR); +#else + serial8250_reg.nr = UART_NR; ret = uart_register_driver(&serial8250_reg); +#endif if (ret) goto out; @@ -2994,7 +3006,11 @@ static int __init serial8250_init(void) put_dev: platform_device_put(serial8250_isa_devs); unreg_uart_drv: +#ifdef CONFIG_SPARC + sunserial_unregister_minors(&serial8250_reg, UART_NR); +#else uart_unregister_driver(&serial8250_reg); +#endif out: return ret; } @@ -3013,7 +3029,11 @@ static void __exit serial8250_exit(void) platform_driver_unregister(&serial8250_isa_driver); platform_device_unregister(isa_dev); +#ifdef CONFIG_SPARC + sunserial_unregister_minors(&serial8250_reg, UART_NR); +#else uart_unregister_driver(&serial8250_reg); +#endif } module_init(serial8250_init); diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index c2f2393..c014ffb1 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -2041,9 +2041,9 @@ static int pciserial_resume_one(struct pci_dev *dev) * The device may have been disabled. Re-enable it. */ err = pci_enable_device(dev); + /* FIXME: We cannot simply error out here */ if (err) - return err; - + printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n"); pciserial_resume_ports(priv); } return 0; diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 77cb342..31786b3 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -9,7 +9,6 @@ menu "Serial drivers" # The new 8250/16550 serial drivers config SERIAL_8250 tristate "8250/16550 and compatible serial support" - depends on (BROKEN || !SPARC) select SERIAL_CORE ---help--- This selects whether you want to include the driver for the standard @@ -994,24 +993,12 @@ config SERIAL_68328_RTS_CTS bool "Support RTS/CTS on 68328 serial port" depends on SERIAL_68328 -config SERIAL_COLDFIRE - bool "ColdFire serial support (DEPRECATED)" - depends on COLDFIRE - help - This driver supports the built-in serial ports of the Motorola ColdFire - family of CPUs. - This driver is deprecated because it supports only the old interface - for serial drivers and features like magic keys are not working. - Please switch to the new style driver because this driver will be - removed soon. - config SERIAL_MCF - bool "Coldfire serial support (new style driver)" + bool "Coldfire serial support" depends on COLDFIRE select SERIAL_CORE help - This new serial driver supports the Freescale Coldfire serial ports - using the new serial driver subsystem. + This serial driver supports the Freescale Coldfire serial ports. config SERIAL_MCF_BAUDRATE int "Default baudrate for Coldfire serial ports" diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 7e7383e..0c17c8d 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -4,6 +4,16 @@ obj-$(CONFIG_SERIAL_CORE) += serial_core.o obj-$(CONFIG_SERIAL_21285) += 21285.o + +# These Sparc drivers have to appear before others such as 8250 +# which share ttySx minor node space. Otherwise console device +# names change and other unplesantries. +obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o +obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o +obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o +obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o +obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o + obj-$(CONFIG_SERIAL_8250) += 8250.o obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o @@ -31,16 +41,10 @@ obj-$(CONFIG_SERIAL_S3C2400) += s3c2400.o obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o -obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o -obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o -obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o -obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o -obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o obj-$(CONFIG_SERIAL_MUX) += mux.o obj-$(CONFIG_SERIAL_68328) += 68328serial.o obj-$(CONFIG_SERIAL_68360) += 68360serial.o -obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o obj-$(CONFIG_SERIAL_MCF) += mcf.o obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 4a0d30b..569f0e2 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -1,7 +1,7 @@ /* * Blackfin On-Chip Serial Driver * - * Copyright 2006-2007 Analog Devices Inc. + * Copyright 2006-2008 Analog Devices Inc. * * Enter bugs at http://blackfin.uclinux.org/ * @@ -42,6 +42,9 @@ #define BFIN_SERIAL_MAJOR 204 #define BFIN_SERIAL_MINOR 64 +static struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS]; +static int nr_active_ports = ARRAY_SIZE(bfin_serial_resource); + /* * Setup for console. Argument comes from the menuconfig */ @@ -126,13 +129,13 @@ static int kgdb_entry_state; void kgdb_put_debug_char(int chr) { struct bfin_serial_port *uart; - + if (CONFIG_KGDB_UART_PORT < 0 || CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS) uart = &bfin_serial_ports[0]; else uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; - + while (!(UART_GET_LSR(uart) & THRE)) { SSYNC(); } @@ -152,7 +155,7 @@ int kgdb_get_debug_char(void) uart = &bfin_serial_ports[0]; else uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT]; - + while(!(UART_GET_LSR(uart) & DR)) { SSYNC(); } @@ -298,7 +301,11 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart) bfin_serial_mctrl_check(uart); if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) { - bfin_serial_stop_tx(&uart->port); +#ifdef CONFIG_BF54x + /* Clear TFI bit */ + UART_PUT_LSR(uart, TFI); +#endif + UART_CLEAR_IER(uart, ETBEI); return; } @@ -317,9 +324,6 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&uart->port); - - if (uart_circ_empty(xmit)) - bfin_serial_stop_tx(&uart->port); } static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id) @@ -645,6 +649,42 @@ static int bfin_serial_startup(struct uart_port *port) free_irq(uart->port.irq, uart); return -EBUSY; } + +# ifdef CONFIG_BF54x + { + unsigned uart_dma_ch_rx, uart_dma_ch_tx; + + switch (uart->port.irq) { + case IRQ_UART3_RX: + uart_dma_ch_rx = CH_UART3_RX; + uart_dma_ch_tx = CH_UART3_TX; + break; + case IRQ_UART2_RX: + uart_dma_ch_rx = CH_UART2_RX; + uart_dma_ch_tx = CH_UART2_TX; + break; + default: + uart_dma_ch_rx = uart_dma_ch_tx = 0; + break; + }; + + if (uart_dma_ch_rx && + request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) { + printk(KERN_NOTICE"Fail to attach UART interrupt\n"); + free_irq(uart->port.irq, uart); + free_irq(uart->port.irq + 1, uart); + return -EBUSY; + } + if (uart_dma_ch_tx && + request_dma(uart_dma_ch_tx, "BFIN_UART_TX") < 0) { + printk(KERN_NOTICE "Fail to attach UART interrupt\n"); + free_dma(uart_dma_ch_rx); + free_irq(uart->port.irq, uart); + free_irq(uart->port.irq + 1, uart); + return -EBUSY; + } + } +# endif #endif UART_SET_IER(uart, ERBFI); return 0; @@ -662,6 +702,20 @@ static void bfin_serial_shutdown(struct uart_port *port) del_timer(&(uart->rx_dma_timer)); dma_free_coherent(NULL, PAGE_SIZE, uart->rx_dma_buf.buf, 0); #else +#ifdef CONFIG_BF54x + switch (uart->port.irq) { + case IRQ_UART3_RX: + free_dma(CH_UART3_RX); + free_dma(CH_UART3_TX); + break; + case IRQ_UART2_RX: + free_dma(CH_UART2_RX); + free_dma(CH_UART2_TX); + break; + default: + break; + }; +#endif #ifdef CONFIG_KGDB_UART if (uart->port.line != CONFIG_KGDB_UART_PORT) #endif @@ -757,6 +811,9 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, val |= UCEN; UART_PUT_GCTL(uart, val); + /* Port speed changed, update the per-port timeout. */ + uart_update_timeout(port, termios->c_cflag, baud); + spin_unlock_irqrestore(&uart->port.lock, flags); } @@ -859,8 +916,9 @@ static void __init bfin_serial_init_ports(void) return; first = 0; - for (i = 0; i < nr_ports; i++) { + for (i = 0; i < nr_active_ports; i++) { bfin_serial_ports[i].port.uartclk = get_sclk(); + bfin_serial_ports[i].port.fifosize = BFIN_UART_TX_FIFO_SIZE; bfin_serial_ports[i].port.ops = &bfin_serial_pops; bfin_serial_ports[i].port.line = i; bfin_serial_ports[i].port.iotype = UPIO_MEM; @@ -961,7 +1019,7 @@ bfin_serial_console_setup(struct console *co, char *options) * if so, search for the first available port that does have * console support. */ - if (co->index == -1 || co->index >= nr_ports) + if (co->index == -1 || co->index >= nr_active_ports) co->index = 0; uart = &bfin_serial_ports[co->index]; @@ -1056,7 +1114,7 @@ static __init void early_serial_write(struct console *con, const char *s, } } -static struct __init console bfin_early_serial_console = { +static struct __initdata console bfin_early_serial_console = { .name = "early_BFuart", .write = early_serial_write, .device = uart_console_device, @@ -1072,7 +1130,7 @@ struct console __init *bfin_earlyserial_init(unsigned int port, struct bfin_serial_port *uart; struct ktermios t; - if (port == -1 || port >= nr_ports) + if (port == -1 || port >= nr_active_ports) port = 0; bfin_serial_init_ports(); bfin_early_serial_console.index = port; @@ -1100,20 +1158,26 @@ static struct uart_driver bfin_serial_reg = { static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state) { - struct bfin_serial_port *uart = platform_get_drvdata(dev); + int i; - if (uart) - uart_suspend_port(&bfin_serial_reg, &uart->port); + for (i = 0; i < nr_active_ports; i++) { + if (bfin_serial_ports[i].port.dev != &dev->dev) + continue; + uart_suspend_port(&bfin_serial_reg, &bfin_serial_ports[i].port); + } return 0; } static int bfin_serial_resume(struct platform_device *dev) { - struct bfin_serial_port *uart = platform_get_drvdata(dev); + int i; - if (uart) - uart_resume_port(&bfin_serial_reg, &uart->port); + for (i = 0; i < nr_active_ports; i++) { + if (bfin_serial_ports[i].port.dev != &dev->dev) + continue; + uart_resume_port(&bfin_serial_reg, &bfin_serial_ports[i].port); + } return 0; } @@ -1128,32 +1192,31 @@ static int bfin_serial_probe(struct platform_device *dev) break; if (i < dev->num_resources) { - for (i = 0; i < nr_ports; i++, res++) { + for (i = 0; i < nr_active_ports; i++, res++) { if (bfin_serial_ports[i].port.mapbase != res->start) continue; bfin_serial_ports[i].port.dev = &dev->dev; uart_add_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port); - platform_set_drvdata(dev, &bfin_serial_ports[i]); } } return 0; } -static int bfin_serial_remove(struct platform_device *pdev) +static int bfin_serial_remove(struct platform_device *dev) { - struct bfin_serial_port *uart = platform_get_drvdata(pdev); - + int i; + for (i = 0; i < nr_active_ports; i++) { + if (bfin_serial_ports[i].port.dev != &dev->dev) + continue; + uart_remove_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port); + bfin_serial_ports[i].port.dev = NULL; #ifdef CONFIG_SERIAL_BFIN_CTSRTS - gpio_free(uart->cts_pin); - gpio_free(uart->rts_pin); + gpio_free(bfin_serial_ports[i].cts_pin); + gpio_free(bfin_serial_ports[i].rts_pin); #endif - - platform_set_drvdata(pdev, NULL); - - if (uart) - uart_remove_one_port(&bfin_serial_reg, &uart->port); + } return 0; } diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c index bf94a77..211c217 100644 --- a/drivers/serial/crisv10.c +++ b/drivers/serial/crisv10.c @@ -457,7 +457,6 @@ static struct e100_serial rs_table[] = { #define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial)) static struct ktermios *serial_termios[NR_PORTS]; -static struct ktermios *serial_termios_locked[NR_PORTS]; #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER static struct fast_timer fast_timers[NR_PORTS]; #endif @@ -4419,6 +4418,7 @@ rs_init(void) rs485_pa_bit)) { printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " "RS485 pin\n"); + put_tty_driver(driver); return -EBUSY; } #endif @@ -4427,6 +4427,7 @@ rs_init(void) rs485_port_g_bit)) { printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " "RS485 pin\n"); + put_tty_driver(driver); return -EBUSY; } #endif @@ -4446,8 +4447,6 @@ rs_init(void) driver->init_termios.c_ispeed = 115200; driver->init_termios.c_ospeed = 115200; driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - driver->termios = serial_termios; - driver->termios_locked = serial_termios_locked; tty_set_operations(driver, &rs_ops); serial_driver = driver; diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c deleted file mode 100644 index fbe3835..0000000 --- a/drivers/serial/mcfserial.c +++ /dev/null @@ -1,1965 +0,0 @@ -#warning This driver is deprecated. Check Kconfig for details. -/* - * mcfserial.c -- serial driver for ColdFire internal UARTS. - * - * Copyright (C) 1999-2003 Greg Ungerer <gerg@snapgear.com> - * Copyright (c) 2000-2001 Lineo, Inc. <www.lineo.com> - * Copyright (C) 2001-2002 SnapGear Inc. <www.snapgear.com> - * - * Based on code from 68332serial.c which was: - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1998 TSHG - * Copyright (c) 1999 Rt-Control Inc. <jeff@uclinux.org> - * - * Changes: - * 08/07/2003 Daniele Bellucci <bellucda@tiscali.it> - * some cleanups in mcfrs_write. - * - */ - -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/wait.h> -#include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/string.h> -#include <linux/fcntl.h> -#include <linux/mm.h> -#include <linux/kernel.h> -#include <linux/serial.h> -#include <linux/serialP.h> -#include <linux/console.h> -#include <linux/init.h> -#include <linux/bitops.h> -#include <linux/delay.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/system.h> -#include <asm/delay.h> -#include <asm/coldfire.h> -#include <asm/mcfsim.h> -#include <asm/mcfuart.h> -#include <asm/nettel.h> -#include <asm/uaccess.h> -#include "mcfserial.h" - -struct timer_list mcfrs_timer_struct; - -/* - * Default console baud rate, we use this as the default - * for all ports so init can just open /dev/console and - * keep going. Perhaps one day the cflag settings for the - * console can be used instead. - */ -#if defined(CONFIG_HW_FEITH) -#define CONSOLE_BAUD_RATE 38400 -#define DEFAULT_CBAUD B38400 -#elif defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB) || \ - defined(CONFIG_M5329EVB) || defined(CONFIG_GILBARCO) -#define CONSOLE_BAUD_RATE 115200 -#define DEFAULT_CBAUD B115200 -#elif defined(CONFIG_ARNEWSH) || defined(CONFIG_FREESCALE) || \ - defined(CONFIG_senTec) || defined(CONFIG_SNEHA) || defined(CONFIG_AVNET) -#define CONSOLE_BAUD_RATE 19200 -#define DEFAULT_CBAUD B19200 -#endif - -#ifndef CONSOLE_BAUD_RATE -#define CONSOLE_BAUD_RATE 9600 -#define DEFAULT_CBAUD B9600 -#endif - -int mcfrs_console_inited = 0; -int mcfrs_console_port = -1; -int mcfrs_console_baud = CONSOLE_BAUD_RATE; -int mcfrs_console_cbaud = DEFAULT_CBAUD; - -/* - * Driver data structures. - */ -static struct tty_driver *mcfrs_serial_driver; - -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 256 - -/* Debugging... - */ -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_FLOW - -#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ - defined(CONFIG_M520x) || defined(CONFIG_M532x) -#define IRQBASE (MCFINT_VECBASE+MCFINT_UART0) -#else -#define IRQBASE 73 -#endif - -/* - * Configuration table, UARTs to look for at startup. - */ -static struct mcf_serial mcfrs_table[] = { - { /* ttyS0 */ - .magic = 0, - .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE1), - .irq = IRQBASE, - .flags = ASYNC_BOOT_AUTOCONF, - }, -#ifdef MCFUART_BASE2 - { /* ttyS1 */ - .magic = 0, - .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE2), - .irq = IRQBASE+1, - .flags = ASYNC_BOOT_AUTOCONF, - }, -#endif -#ifdef MCFUART_BASE3 - { /* ttyS2 */ - .magic = 0, - .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE3), - .irq = IRQBASE+2, - .flags = ASYNC_BOOT_AUTOCONF, - }, -#endif -#ifdef MCFUART_BASE4 - { /* ttyS3 */ - .magic = 0, - .addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE4), - .irq = IRQBASE+3, - .flags = ASYNC_BOOT_AUTOCONF, - }, -#endif -}; - - -#define NR_PORTS (sizeof(mcfrs_table) / sizeof(struct mcf_serial)) - -/* - * This is used to figure out the divisor speeds and the timeouts. - */ -static int mcfrs_baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 -}; -#define MCFRS_BAUD_TABLE_SIZE \ - (sizeof(mcfrs_baud_table)/sizeof(mcfrs_baud_table[0])) - - -#ifdef CONFIG_MAGIC_SYSRQ -/* - * Magic system request keys. Used for debugging... - */ -extern int magic_sysrq_key(int ch); -#endif - - -/* - * Forware declarations... - */ -static void mcfrs_change_speed(struct mcf_serial *info); -static void mcfrs_wait_until_sent(struct tty_struct *tty, int timeout); - - -static inline int serial_paranoia_check(struct mcf_serial *info, - char *name, const char *routine) -{ -#ifdef SERIAL_PARANOIA_CHECK - static const char badmagic[] = - "MCFRS(warning): bad magic number for serial struct %s in %s\n"; - static const char badinfo[] = - "MCFRS(warning): null mcf_serial for %s in %s\n"; - - if (!info) { - printk(badinfo, name, routine); - return 1; - } - if (info->magic != SERIAL_MAGIC) { - printk(badmagic, name, routine); - return 1; - } -#endif - return 0; -} - -/* - * Sets or clears DTR and RTS on the requested line. - */ -static void mcfrs_setsignals(struct mcf_serial *info, int dtr, int rts) -{ - volatile unsigned char *uartp; - unsigned long flags; - -#if 0 - printk("%s(%d): mcfrs_setsignals(info=%x,dtr=%d,rts=%d)\n", - __FILE__, __LINE__, info, dtr, rts); -#endif - - local_irq_save(flags); - if (dtr >= 0) { -#ifdef MCFPP_DTR0 - if (info->line) - mcf_setppdata(MCFPP_DTR1, (dtr ? 0 : MCFPP_DTR1)); - else - mcf_setppdata(MCFPP_DTR0, (dtr ? 0 : MCFPP_DTR0)); -#endif - } - if (rts >= 0) { - uartp = info->addr; - if (rts) { - info->sigs |= TIOCM_RTS; - uartp[MCFUART_UOP1] = MCFUART_UOP_RTS; - } else { - info->sigs &= ~TIOCM_RTS; - uartp[MCFUART_UOP0] = MCFUART_UOP_RTS; - } - } - local_irq_restore(flags); - return; -} - -/* - * Gets values of serial signals. - */ -static int mcfrs_getsignals(struct mcf_serial *info) -{ - volatile unsigned char *uartp; - unsigned long flags; - int sigs; -#if defined(CONFIG_NETtel) && defined(CONFIG_M5307) - unsigned short ppdata; -#endif - -#if 0 - printk("%s(%d): mcfrs_getsignals(info=%x)\n", __FILE__, __LINE__); -#endif - - local_irq_save(flags); - uartp = info->addr; - sigs = (uartp[MCFUART_UIPR] & MCFUART_UIPR_CTS) ? 0 : TIOCM_CTS; - sigs |= (info->sigs & TIOCM_RTS); - -#ifdef MCFPP_DCD0 -{ - unsigned int ppdata; - ppdata = mcf_getppdata(); - if (info->line == 0) { - sigs |= (ppdata & MCFPP_DCD0) ? 0 : TIOCM_CD; - sigs |= (ppdata & MCFPP_DTR0) ? 0 : TIOCM_DTR; - } else if (info->line == 1) { - sigs |= (ppdata & MCFPP_DCD1) ? 0 : TIOCM_CD; - sigs |= (ppdata & MCFPP_DTR1) ? 0 : TIOCM_DTR; - } -} -#endif - - local_irq_restore(flags); - return(sigs); -} - -/* - * ------------------------------------------------------------ - * mcfrs_stop() and mcfrs_start() - * - * This routines are called before setting or resetting tty->stopped. - * They enable or disable transmitter interrupts, as necessary. - * ------------------------------------------------------------ - */ -static void mcfrs_stop(struct tty_struct *tty) -{ - volatile unsigned char *uartp; - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "mcfrs_stop")) - return; - - local_irq_save(flags); - uartp = info->addr; - info->imr &= ~MCFUART_UIR_TXREADY; - uartp[MCFUART_UIMR] = info->imr; - local_irq_restore(flags); -} - -static void mcfrs_start(struct tty_struct *tty) -{ - volatile unsigned char *uartp; - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "mcfrs_start")) - return; - - local_irq_save(flags); - if (info->xmit_cnt && info->xmit_buf) { - uartp = info->addr; - info->imr |= MCFUART_UIR_TXREADY; - uartp[MCFUART_UIMR] = info->imr; - } - local_irq_restore(flags); -} - -/* - * ---------------------------------------------------------------------- - * - * Here starts the interrupt handling routines. All of the following - * subroutines are declared as inline and are folded into - * mcfrs_interrupt(). They were separated out for readability's sake. - * - * Note: mcfrs_interrupt() is a "fast" interrupt, which means that it - * runs with interrupts turned off. People who may want to modify - * mcfrs_interrupt() should try to keep the interrupt handler as fast as - * possible. After you are done making modifications, it is not a bad - * idea to do: - * - * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c - * - * and look at the resulting assemble code in serial.s. - * - * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 - * ----------------------------------------------------------------------- - */ - -static inline void receive_chars(struct mcf_serial *info) -{ - volatile unsigned char *uartp; - struct tty_struct *tty = info->port.tty; - unsigned char status, ch, flag; - - if (!tty) - return; - - uartp = info->addr; - - while ((status = uartp[MCFUART_USR]) & MCFUART_USR_RXREADY) { - ch = uartp[MCFUART_URB]; - info->stats.rx++; - -#ifdef CONFIG_MAGIC_SYSRQ - if (mcfrs_console_inited && (info->line == mcfrs_console_port)) { - if (magic_sysrq_key(ch)) - continue; - } -#endif - - flag = TTY_NORMAL; - if (status & MCFUART_USR_RXERR) { - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETERR; - if (status & MCFUART_USR_RXBREAK) { - info->stats.rxbreak++; - flag = TTY_BREAK; - } else if (status & MCFUART_USR_RXPARITY) { - info->stats.rxparity++; - flag = TTY_PARITY; - } else if (status & MCFUART_USR_RXOVERRUN) { - info->stats.rxoverrun++; - flag = TTY_OVERRUN; - } else if (status & MCFUART_USR_RXFRAMING) { - info->stats.rxframing++; - flag = TTY_FRAME; - } - } - tty_insert_flip_char(tty, ch, flag); - } - tty_schedule_flip(tty); - return; -} - -static inline void transmit_chars(struct mcf_serial *info) -{ - volatile unsigned char *uartp; - - uartp = info->addr; - - if (info->x_char) { - /* Send special char - probably flow control */ - uartp[MCFUART_UTB] = info->x_char; - info->x_char = 0; - info->stats.tx++; - } - - if ((info->xmit_cnt <= 0) || info->port.tty->stopped) { - info->imr &= ~MCFUART_UIR_TXREADY; - uartp[MCFUART_UIMR] = info->imr; - return; - } - - while (uartp[MCFUART_USR] & MCFUART_USR_TXREADY) { - uartp[MCFUART_UTB] = info->xmit_buf[info->xmit_tail++]; - info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); - info->stats.tx++; - if (--info->xmit_cnt <= 0) - break; - } - - if (info->xmit_cnt < WAKEUP_CHARS) - schedule_work(&info->tqueue); - return; -} - -/* - * This is the serial driver's generic interrupt routine - */ -irqreturn_t mcfrs_interrupt(int irq, void *dev_id) -{ - struct mcf_serial *info; - unsigned char isr; - - info = &mcfrs_table[(irq - IRQBASE)]; - isr = info->addr[MCFUART_UISR] & info->imr; - - if (isr & MCFUART_UIR_RXREADY) - receive_chars(info); - if (isr & MCFUART_UIR_TXREADY) - transmit_chars(info); - return IRQ_HANDLED; -} - -/* - * ------------------------------------------------------------------- - * Here ends the serial interrupt routines. - * ------------------------------------------------------------------- - */ - -static void mcfrs_offintr(struct work_struct *work) -{ - struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue); - struct tty_struct *tty = info->port.tty; - - if (tty) - tty_wakeup(tty); -} - - -/* - * Change of state on a DCD line. - */ -void mcfrs_modem_change(struct mcf_serial *info, int dcd) -{ - if (info->count == 0) - return; - - if (info->flags & ASYNC_CHECK_CD) { - if (dcd) - wake_up_interruptible(&info->open_wait); - else - schedule_work(&info->tqueue_hangup); - } -} - - -#ifdef MCFPP_DCD0 - -unsigned short mcfrs_ppstatus; - -/* - * This subroutine is called when the RS_TIMER goes off. It is used - * to monitor the state of the DCD lines - since they have no edge - * sensors and interrupt generators. - */ -static void mcfrs_timer(void) -{ - unsigned int ppstatus, dcdval, i; - - ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1); - - if (ppstatus != mcfrs_ppstatus) { - for (i = 0; (i < 2); i++) { - dcdval = (i ? MCFPP_DCD1 : MCFPP_DCD0); - if ((ppstatus & dcdval) != (mcfrs_ppstatus & dcdval)) { - mcfrs_modem_change(&mcfrs_table[i], - ((ppstatus & dcdval) ? 0 : 1)); - } - } - } - mcfrs_ppstatus = ppstatus; - - /* Re-arm timer */ - mcfrs_timer_struct.expires = jiffies + HZ/25; - add_timer(&mcfrs_timer_struct); -} - -#endif /* MCFPP_DCD0 */ - - -/* - * This routine is called from the scheduler tqueue when the interrupt - * routine has signalled that a hangup has occurred. The path of - * hangup processing is: - * - * serial interrupt routine -> (scheduler tqueue) -> - * do_serial_hangup() -> tty->hangup() -> mcfrs_hangup() - * - */ -static void do_serial_hangup(struct work_struct *work) -{ - struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue_hangup); - struct tty_struct *tty = info->port.tty; - - if (tty) - tty_hangup(tty); -} - -static int startup(struct mcf_serial * info) -{ - volatile unsigned char *uartp; - unsigned long flags; - - if (info->flags & ASYNC_INITIALIZED) - return 0; - - if (!info->xmit_buf) { - info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL); - if (!info->xmit_buf) - return -ENOMEM; - } - - local_irq_save(flags); - -#ifdef SERIAL_DEBUG_OPEN - printk("starting up ttyS%d (irq %d)...\n", info->line, info->irq); -#endif - - /* - * Reset UART, get it into known state... - */ - uartp = info->addr; - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ - mcfrs_setsignals(info, 1, 1); - - if (info->port.tty) - clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - - /* - * and set the speed of the serial port - */ - mcfrs_change_speed(info); - - /* - * Lastly enable the UART transmitter and receiver, and - * interrupt enables. - */ - info->imr = MCFUART_UIR_RXREADY; - uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE; - uartp[MCFUART_UIMR] = info->imr; - - info->flags |= ASYNC_INITIALIZED; - local_irq_restore(flags); - return 0; -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void shutdown(struct mcf_serial * info) -{ - volatile unsigned char *uartp; - unsigned long flags; - - if (!(info->flags & ASYNC_INITIALIZED)) - return; - -#ifdef SERIAL_DEBUG_OPEN - printk("Shutting down serial port %d (irq %d)....\n", info->line, - info->irq); -#endif - - local_irq_save(flags); - - uartp = info->addr; - uartp[MCFUART_UIMR] = 0; /* mask all interrupts */ - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ - - if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) - mcfrs_setsignals(info, 0, 0); - - if (info->xmit_buf) { - free_page((unsigned long) info->xmit_buf); - info->xmit_buf = 0; - } - - if (info->port.tty) - set_bit(TTY_IO_ERROR, &info->port.tty->flags); - - info->flags &= ~ASYNC_INITIALIZED; - local_irq_restore(flags); -} - - -/* - * This routine is called to set the UART divisor registers to match - * the specified baud rate for a serial port. - */ -static void mcfrs_change_speed(struct mcf_serial *info) -{ - volatile unsigned char *uartp; - unsigned int baudclk, cflag; - unsigned long flags; - unsigned char mr1, mr2; - int i; -#ifdef CONFIG_M5272 - unsigned int fraction; -#endif - - if (!info->port.tty || !info->port.tty->termios) - return; - cflag = info->port.tty->termios->c_cflag; - if (info->addr == 0) - return; - -#if 0 - printk("%s(%d): mcfrs_change_speed()\n", __FILE__, __LINE__); -#endif - - i = cflag & CBAUD; - if (i & CBAUDEX) { - i &= ~CBAUDEX; - if (i < 1 || i > 4) - info->port.tty->termios->c_cflag &= ~CBAUDEX; - else - i += 15; - } - if (i == 0) { - mcfrs_setsignals(info, 0, -1); - return; - } - - /* compute the baudrate clock */ -#ifdef CONFIG_M5272 - /* - * For the MCF5272, also compute the baudrate fraction. - */ - baudclk = (MCF_BUSCLK / mcfrs_baud_table[i]) / 32; - fraction = MCF_BUSCLK - (baudclk * 32 * mcfrs_baud_table[i]); - fraction *= 16; - fraction /= (32 * mcfrs_baud_table[i]); -#else - baudclk = ((MCF_BUSCLK / mcfrs_baud_table[i]) + 16) / 32; -#endif - - info->baud = mcfrs_baud_table[i]; - - mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR; - mr2 = 0; - - switch (cflag & CSIZE) { - case CS5: mr1 |= MCFUART_MR1_CS5; break; - case CS6: mr1 |= MCFUART_MR1_CS6; break; - case CS7: mr1 |= MCFUART_MR1_CS7; break; - case CS8: - default: mr1 |= MCFUART_MR1_CS8; break; - } - - if (cflag & PARENB) { - if (cflag & CMSPAR) { - if (cflag & PARODD) - mr1 |= MCFUART_MR1_PARITYMARK; - else - mr1 |= MCFUART_MR1_PARITYSPACE; - } else { - if (cflag & PARODD) - mr1 |= MCFUART_MR1_PARITYODD; - else - mr1 |= MCFUART_MR1_PARITYEVEN; - } - } else { - mr1 |= MCFUART_MR1_PARITYNONE; - } - - if (cflag & CSTOPB) - mr2 |= MCFUART_MR2_STOP2; - else - mr2 |= MCFUART_MR2_STOP1; - - if (cflag & CRTSCTS) { - mr1 |= MCFUART_MR1_RXRTS; - mr2 |= MCFUART_MR2_TXCTS; - } - - if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; - else - info->flags |= ASYNC_CHECK_CD; - - uartp = info->addr; - - local_irq_save(flags); -#if 0 - printk("%s(%d): mr1=%x mr2=%x baudclk=%x\n", __FILE__, __LINE__, - mr1, mr2, baudclk); -#endif - /* - Note: pg 12-16 of MCF5206e User's Manual states that a - software reset should be performed prior to changing - UMR1,2, UCSR, UACR, bit 7 - */ - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR; /* reset MR pointer */ - uartp[MCFUART_UMR] = mr1; - uartp[MCFUART_UMR] = mr2; - uartp[MCFUART_UBG1] = (baudclk & 0xff00) >> 8; /* set msb byte */ - uartp[MCFUART_UBG2] = (baudclk & 0xff); /* set lsb byte */ -#ifdef CONFIG_M5272 - uartp[MCFUART_UFPD] = (fraction & 0xf); /* set fraction */ -#endif - uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER; - uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE; - mcfrs_setsignals(info, 1, -1); - local_irq_restore(flags); - return; -} - -static void mcfrs_flush_chars(struct tty_struct *tty) -{ - volatile unsigned char *uartp; - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "mcfrs_flush_chars")) - return; - - uartp = (volatile unsigned char *) info->addr; - - /* - * re-enable receiver interrupt - */ - local_irq_save(flags); - if ((!(info->imr & MCFUART_UIR_RXREADY)) && - (info->flags & ASYNC_INITIALIZED) ) { - info->imr |= MCFUART_UIR_RXREADY; - uartp[MCFUART_UIMR] = info->imr; - } - local_irq_restore(flags); - - if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || - !info->xmit_buf) - return; - - /* Enable transmitter */ - local_irq_save(flags); - info->imr |= MCFUART_UIR_TXREADY; - uartp[MCFUART_UIMR] = info->imr; - local_irq_restore(flags); -} - -static int mcfrs_write(struct tty_struct * tty, - const unsigned char *buf, int count) -{ - volatile unsigned char *uartp; - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; - unsigned long flags; - int c, total = 0; - -#if 0 - printk("%s(%d): mcfrs_write(tty=%x,buf=%x,count=%d)\n", - __FILE__, __LINE__, (int)tty, (int)buf, count); -#endif - - if (serial_paranoia_check(info, tty->name, "mcfrs_write")) - return 0; - - if (!tty || !info->xmit_buf) - return 0; - - local_save_flags(flags); - while (1) { - local_irq_disable(); - c = min(count, (int) min(((int)SERIAL_XMIT_SIZE) - info->xmit_cnt - 1, - ((int)SERIAL_XMIT_SIZE) - info->xmit_head)); - local_irq_restore(flags); - - if (c <= 0) - break; - - memcpy(info->xmit_buf + info->xmit_head, buf, c); - - local_irq_disable(); - info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt += c; - local_irq_restore(flags); - - buf += c; - count -= c; - total += c; - } - - local_irq_disable(); - uartp = info->addr; - info->imr |= MCFUART_UIR_TXREADY; - uartp[MCFUART_UIMR] = info->imr; - local_irq_restore(flags); - - return total; -} - -static int mcfrs_write_room(struct tty_struct *tty) -{ - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; - int ret; - - if (serial_paranoia_check(info, tty->name, "mcfrs_write_room")) - return 0; - ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; - if (ret < 0) - ret = 0; - return ret; -} - -static int mcfrs_chars_in_buffer(struct tty_struct *tty) -{ - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "mcfrs_chars_in_buffer")) - return 0; - return info->xmit_cnt; -} - -static void mcfrs_flush_buffer(struct tty_struct *tty) -{ - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->name, "mcfrs_flush_buffer")) - return; - - local_irq_save(flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - local_irq_restore(flags); - - tty_wakeup(tty); -} - -/* - * ------------------------------------------------------------ - * mcfrs_throttle() - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - * ------------------------------------------------------------ - */ -static void mcfrs_throttle(struct tty_struct * tty) -{ - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %d....\n", tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); -#endif - - if (serial_paranoia_check(info, tty->name, "mcfrs_throttle")) - return; - - if (I_IXOFF(tty)) - info->x_char = STOP_CHAR(tty); - - /* Turn off RTS line (do this atomic) */ -} - -static void mcfrs_unthrottle(struct tty_struct * tty) -{ - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("unthrottle %s: %d....\n", tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); -#endif - - if (serial_paranoia_check(info, tty->name, "mcfrs_unthrottle")) - return; - - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - info->x_char = START_CHAR(tty); - } - - /* Assert RTS line (do this atomic) */ -} - -/* - * ------------------------------------------------------------ - * mcfrs_ioctl() and friends - * ------------------------------------------------------------ - */ - -static int get_serial_info(struct mcf_serial * info, - struct serial_struct * retinfo) -{ - struct serial_struct tmp; - - if (!retinfo) - return -EFAULT; - memset(&tmp, 0, sizeof(tmp)); - tmp.type = info->type; - tmp.line = info->line; - tmp.port = (unsigned int) info->addr; - tmp.irq = info->irq; - tmp.flags = info->flags; - tmp.baud_base = info->baud_base; - tmp.close_delay = info->close_delay; - tmp.closing_wait = info->closing_wait; - tmp.custom_divisor = info->custom_divisor; - return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0; -} - -static int set_serial_info(struct mcf_serial * info, - struct serial_struct * new_info) -{ - struct serial_struct new_serial; - struct mcf_serial old_info; - int retval = 0; - - if (!new_info) - return -EFAULT; - if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) - return -EFAULT; - old_info = *info; - - if (!capable(CAP_SYS_ADMIN)) { - if ((new_serial.baud_base != info->baud_base) || - (new_serial.type != info->type) || - (new_serial.close_delay != info->close_delay) || - ((new_serial.flags & ~ASYNC_USR_MASK) != - (info->flags & ~ASYNC_USR_MASK))) - return -EPERM; - info->flags = ((info->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); - info->custom_divisor = new_serial.custom_divisor; - goto check_and_exit; - } - - if (info->count > 1) - return -EBUSY; - - /* - * OK, past this point, all the error checking has been done. - * At this point, we start making changes..... - */ - - info->baud_base = new_serial.baud_base; - info->flags = ((info->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); - info->type = new_serial.type; - info->close_delay = new_serial.close_delay; - info->closing_wait = new_serial.closing_wait; - -check_and_exit: - retval = startup(info); - return retval; -} - -/* - * get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - */ -static int get_lsr_info(struct mcf_serial * info, unsigned int *value) -{ - volatile unsigned char *uartp; - unsigned long flags; - unsigned char status; - - local_irq_save(flags); - uartp = info->addr; - status = (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY) ? TIOCSER_TEMT : 0; - local_irq_restore(flags); - - return put_user(status,value); -} - -/* - * This routine sends a break character out the serial port. - */ -static void send_break( struct mcf_serial * info, int duration) -{ - volatile unsigned char *uartp; - unsigned long flags; - - if (!info->addr) - return; - set_current_state(TASK_INTERRUPTIBLE); - uartp = info->addr; - - local_irq_save(flags); - uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTART; - schedule_timeout(duration); - uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTOP; - local_irq_restore(flags); -} - -static int mcfrs_tiocmget(struct tty_struct *tty, struct file *file) -{ - struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl")) - return -ENODEV; - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - - return mcfrs_getsignals(info); -} - -static int mcfrs_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) -{ - struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; - int rts = -1, dtr = -1; - - if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl")) - return -ENODEV; - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - - if (set & TIOCM_RTS) - rts = 1; - if (set & TIOCM_DTR) - dtr = 1; - if (clear & TIOCM_RTS) - rts = 0; - if (clear & TIOCM_DTR) - dtr = 0; - - mcfrs_setsignals(info, dtr, rts); - - return 0; -} - -static int mcfrs_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) -{ - struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; - int retval, error; - - if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl")) - return -ENODEV; - - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && - (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - } - - switch (cmd) { - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (!arg) - send_break(info, HZ/4); /* 1/4 second */ - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - send_break(info, arg ? arg*(HZ/10) : HZ/4); - return 0; - case TIOCGSERIAL: - if (access_ok(VERIFY_WRITE, (void *) arg, - sizeof(struct serial_struct))) - return get_serial_info(info, - (struct serial_struct *) arg); - return -EFAULT; - case TIOCSSERIAL: - return set_serial_info(info, - (struct serial_struct *) arg); - case TIOCSERGETLSR: /* Get line status register */ - if (access_ok(VERIFY_WRITE, (void *) arg, - sizeof(unsigned int))) - return get_lsr_info(info, (unsigned int *) arg); - return -EFAULT; - case TIOCSERGSTRUCT: - error = copy_to_user((struct mcf_serial *) arg, - info, sizeof(struct mcf_serial)); - if (error) - return -EFAULT; - return 0; - -#ifdef TIOCSET422 - case TIOCSET422: { - unsigned int val; - get_user(val, (unsigned int *) arg); - mcf_setpa(MCFPP_PA11, (val ? 0 : MCFPP_PA11)); - break; - } - case TIOCGET422: { - unsigned int val; - val = (mcf_getpa() & MCFPP_PA11) ? 0 : 1; - put_user(val, (unsigned int *) arg); - break; - } -#endif - - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static void mcfrs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) -{ - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; - - if (tty->termios->c_cflag == old_termios->c_cflag) - return; - - mcfrs_change_speed(info); - - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->hw_stopped = 0; - mcfrs_setsignals(info, -1, 1); -#if 0 - mcfrs_start(tty); -#endif - } -} - -/* - * ------------------------------------------------------------ - * mcfrs_close() - * - * This routine is called when the serial port gets closed. First, we - * wait for the last remaining data to be sent. Then, we unlink its - * S structure from the interrupt chain if necessary, and we free - * that IRQ if nothing is left in the chain. - * ------------------------------------------------------------ - */ -static void mcfrs_close(struct tty_struct *tty, struct file * filp) -{ - volatile unsigned char *uartp; - struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; - unsigned long flags; - - if (!info || serial_paranoia_check(info, tty->name, "mcfrs_close")) - return; - - local_irq_save(flags); - - if (tty_hung_up_p(filp)) { - local_irq_restore(flags); - return; - } - -#ifdef SERIAL_DEBUG_OPEN - printk("mcfrs_close ttyS%d, count = %d\n", info->line, info->count); -#endif - if ((tty->count == 1) && (info->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. Info->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - printk("MCFRS: bad serial port count; tty->count is 1, " - "info->count is %d\n", info->count); - info->count = 1; - } - if (--info->count < 0) { - printk("MCFRS: bad serial port count for ttyS%d: %d\n", - info->line, info->count); - info->count = 0; - } - if (info->count) { - local_irq_restore(flags); - return; - } - info->flags |= ASYNC_CLOSING; - - /* - * Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters. - */ - tty->closing = 1; - if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); - - /* - * At this point we stop accepting input. To do this, we - * disable the receive line status interrupts, and tell the - * interrupt driver to stop checking the data ready bit in the - * line status register. - */ - info->imr &= ~MCFUART_UIR_RXREADY; - uartp = info->addr; - uartp[MCFUART_UIMR] = info->imr; - -#if 0 - /* FIXME: do we need to keep this enabled for console?? */ - if (mcfrs_console_inited && (mcfrs_console_port == info->line)) { - /* Do not disable the UART */ ; - } else -#endif - shutdown(info); - mcfrs_flush_buffer(tty); - tty_ldisc_flush(tty); - - tty->closing = 0; - info->event = 0; - info->port.tty = NULL; -#if 0 - if (tty->ldisc.num != ldiscs[N_TTY].num) { - if (tty->ldisc.close) - (tty->ldisc.close)(tty); - tty->ldisc = ldiscs[N_TTY]; - tty->termios->c_line = N_TTY; - if (tty->ldisc.open) - (tty->ldisc.open)(tty); - } -#endif - if (info->blocked_open) { - if (info->close_delay) { - msleep_interruptible(jiffies_to_msecs(info->close_delay)); - } - wake_up_interruptible(&info->open_wait); - } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); - local_irq_restore(flags); -} - -/* - * mcfrs_wait_until_sent() --- wait until the transmitter is empty - */ -static void -mcfrs_wait_until_sent(struct tty_struct *tty, int timeout) -{ -#ifdef CONFIG_M5272 -#define MCF5272_FIFO_SIZE 25 /* fifo size + shift reg */ - - struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; - volatile unsigned char *uartp; - unsigned long orig_jiffies, fifo_time, char_time, fifo_cnt; - - if (serial_paranoia_check(info, tty->name, "mcfrs_wait_until_sent")) - return; - - orig_jiffies = jiffies; - - /* - * Set the check interval to be 1/5 of the approximate time - * to send the entire fifo, and make it at least 1. The check - * interval should also be less than the timeout. - * - * Note: we have to use pretty tight timings here to satisfy - * the NIST-PCTS. - */ - lock_kernel(); - - fifo_time = (MCF5272_FIFO_SIZE * HZ * 10) / info->baud; - char_time = fifo_time / 5; - if (char_time == 0) - char_time = 1; - if (timeout && timeout < char_time) - char_time = timeout; - - /* - * Clamp the timeout period at 2 * the time to empty the - * fifo. Just to be safe, set the minimum at .5 seconds. - */ - fifo_time *= 2; - if (fifo_time < (HZ/2)) - fifo_time = HZ/2; - if (!timeout || timeout > fifo_time) - timeout = fifo_time; - - /* - * Account for the number of bytes in the UART - * transmitter FIFO plus any byte being shifted out. - */ - uartp = (volatile unsigned char *) info->addr; - for (;;) { - fifo_cnt = (uartp[MCFUART_UTF] & MCFUART_UTF_TXB); - if ((uartp[MCFUART_USR] & (MCFUART_USR_TXREADY| - MCFUART_USR_TXEMPTY)) == - MCFUART_USR_TXREADY) - fifo_cnt++; - if (fifo_cnt == 0) - break; - msleep_interruptible(jiffies_to_msecs(char_time)); - if (signal_pending(current)) - break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) - break; - } - unlock_kernel(); -#else - /* - * For the other coldfire models, assume all data has been sent - */ -#endif -} - -/* - * mcfrs_hangup() --- called by tty_hangup() when a hangup is signaled. - */ -void mcfrs_hangup(struct tty_struct *tty) -{ - struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; - - if (serial_paranoia_check(info, tty->name, "mcfrs_hangup")) - return; - - mcfrs_flush_buffer(tty); - shutdown(info); - info->event = 0; - info->count = 0; - info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->port.tty = NULL; - wake_up_interruptible(&info->open_wait); -} - -/* - * ------------------------------------------------------------ - * mcfrs_open() and friends - * ------------------------------------------------------------ - */ -static int block_til_ready(struct tty_struct *tty, struct file * filp, - struct mcf_serial *info) -{ - DECLARE_WAITQUEUE(wait, current); - int retval; - int do_clocal = 0; - - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (info->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) - return -EAGAIN; - else - return -ERESTARTSYS; -#else - return -EAGAIN; -#endif - } - - /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; - } - - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - - /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that - * mcfrs_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - retval = 0; - add_wait_queue(&info->open_wait, &wait); -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready before block: ttyS%d, count = %d\n", - info->line, info->count); -#endif - info->count--; - info->blocked_open++; - while (1) { - local_irq_disable(); - mcfrs_setsignals(info, 1, 1); - local_irq_enable(); - current->state = TASK_INTERRUPTIBLE; - if (tty_hung_up_p(filp) || - !(info->flags & ASYNC_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; -#else - retval = -EAGAIN; -#endif - break; - } - if (!(info->flags & ASYNC_CLOSING) && - (do_clocal || (mcfrs_getsignals(info) & TIOCM_CD))) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready blocking: ttyS%d, count = %d\n", - info->line, info->count); -#endif - schedule(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&info->open_wait, &wait); - if (!tty_hung_up_p(filp)) - info->count++; - info->blocked_open--; -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready after blocking: ttyS%d, count = %d\n", - info->line, info->count); -#endif - if (retval) - return retval; - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; -} - -/* - * This routine is called whenever a serial port is opened. It - * enables interrupts for a serial port, linking in its structure into - * the IRQ chain. It also performs the serial-specific - * initialization for the tty structure. - */ -int mcfrs_open(struct tty_struct *tty, struct file * filp) -{ - struct mcf_serial *info; - int retval, line; - - line = tty->index; - if ((line < 0) || (line >= NR_PORTS)) - return -ENODEV; - info = mcfrs_table + line; - if (serial_paranoia_check(info, tty->name, "mcfrs_open")) - return -ENODEV; -#ifdef SERIAL_DEBUG_OPEN - printk("mcfrs_open %s, count = %d\n", tty->name, info->count); -#endif - info->count++; - tty->driver_data = info; - info->port.tty = tty; - - /* - * Start up serial port - */ - retval = startup(info); - if (retval) - return retval; - - retval = block_til_ready(tty, filp, info); - if (retval) { -#ifdef SERIAL_DEBUG_OPEN - printk("mcfrs_open returning after block_til_ready with %d\n", - retval); -#endif - return retval; - } - -#ifdef SERIAL_DEBUG_OPEN - printk("mcfrs_open %s successful...\n", tty->name); -#endif - return 0; -} - -/* - * Based on the line number set up the internal interrupt stuff. - */ -static void mcfrs_irqinit(struct mcf_serial *info) -{ -#if defined(CONFIG_M5272) - volatile unsigned long *icrp; - volatile unsigned long *portp; - volatile unsigned char *uartp; - - uartp = info->addr; - icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR2); - - switch (info->line) { - case 0: - *icrp = 0xe0000000; - break; - case 1: - *icrp = 0x0e000000; - break; - default: - printk("MCFRS: don't know how to handle UART %d interrupt?\n", - info->line); - return; - } - - /* Enable the output lines for the serial ports */ - portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PBCNT); - *portp = (*portp & ~0x000000ff) | 0x00000055; - portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PDCNT); - *portp = (*portp & ~0x000003fc) | 0x000002a8; -#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) - volatile unsigned char *icrp, *uartp; - volatile unsigned long *imrp; - - uartp = info->addr; - - icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 + - MCFINTC_ICR0 + MCFINT_UART0 + info->line); - *icrp = 0x30 + info->line; /* level 6, line based priority */ - - imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 + - MCFINTC_IMRL); - *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1); -#if defined(CONFIG_M527x) - { - /* - * External Pin Mask Setting & Enable External Pin for Interface - * mrcbis@aliceposta.it - */ - u16 *serpin_enable_mask; - serpin_enable_mask = (u16 *) (MCF_IPSBAR + MCF_GPIO_PAR_UART); - if (info->line == 0) - *serpin_enable_mask |= UART0_ENABLE_MASK; - else if (info->line == 1) - *serpin_enable_mask |= UART1_ENABLE_MASK; - else if (info->line == 2) - *serpin_enable_mask |= UART2_ENABLE_MASK; - } -#endif -#if defined(CONFIG_M528x) - /* make sure PUAPAR is set for UART0 and UART1 */ - if (info->line < 2) { - volatile unsigned char *portp = (volatile unsigned char *) (MCF_MBAR + MCF5282_GPIO_PUAPAR); - *portp |= (0x03 << (info->line * 2)); - } -#endif -#elif defined(CONFIG_M520x) - volatile unsigned char *icrp, *uartp; - volatile unsigned long *imrp; - - uartp = info->addr; - - icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 + - MCFINTC_ICR0 + MCFINT_UART0 + info->line); - *icrp = 0x03; - - imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 + - MCFINTC_IMRL); - *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1); - if (info->line < 2) { - unsigned short *uart_par; - uart_par = (unsigned short *)(MCF_IPSBAR + MCF_GPIO_PAR_UART); - if (info->line == 0) - *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD0 - | MCF_GPIO_PAR_UART_PAR_URXD0; - else if (info->line == 1) - *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD1 - | MCF_GPIO_PAR_UART_PAR_URXD1; - } else if (info->line == 2) { - unsigned char *feci2c_par; - feci2c_par = (unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C); - *feci2c_par &= ~0x0F; - *feci2c_par |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 - | MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2; - } -#elif defined(CONFIG_M532x) - volatile unsigned char *uartp; - uartp = info->addr; - switch (info->line) { - case 0: - MCF_INTC0_ICR26 = 0x3; - MCF_INTC0_CIMR = 26; - /* GPIO initialization */ - MCF_GPIO_PAR_UART |= 0x000F; - break; - case 1: - MCF_INTC0_ICR27 = 0x3; - MCF_INTC0_CIMR = 27; - /* GPIO initialization */ - MCF_GPIO_PAR_UART |= 0x0FF0; - break; - case 2: - MCF_INTC0_ICR28 = 0x3; - MCF_INTC0_CIMR = 28; - /* GPIOs also must be initalized, depends on board */ - break; - } -#else - volatile unsigned char *icrp, *uartp; - - switch (info->line) { - case 0: - icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART1ICR); - *icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 | - MCFSIM_ICR_PRI1; - mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1); - break; - case 1: - icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART2ICR); - *icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 | - MCFSIM_ICR_PRI2; - mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2); - break; - default: - printk("MCFRS: don't know how to handle UART %d interrupt?\n", - info->line); - return; - } - - uartp = info->addr; - uartp[MCFUART_UIVR] = info->irq; -#endif - - /* Clear mask, so no surprise interrupts. */ - uartp[MCFUART_UIMR] = 0; - - if (request_irq(info->irq, mcfrs_interrupt, IRQF_DISABLED, - "ColdFire UART", NULL)) { - printk("MCFRS: Unable to attach ColdFire UART %d interrupt " - "vector=%d\n", info->line, info->irq); - } - - return; -} - - -char *mcfrs_drivername = "ColdFire internal UART serial driver version 1.00\n"; - - -/* - * Serial stats reporting... - */ -int mcfrs_readproc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - struct mcf_serial *info; - char str[20]; - int len, sigs, i; - - len = sprintf(page, mcfrs_drivername); - for (i = 0; (i < NR_PORTS); i++) { - info = &mcfrs_table[i]; - len += sprintf((page + len), "%d: port:%x irq=%d baud:%d ", - i, (unsigned int) info->addr, info->irq, info->baud); - if (info->stats.rx || info->stats.tx) - len += sprintf((page + len), "tx:%d rx:%d ", - info->stats.tx, info->stats.rx); - if (info->stats.rxframing) - len += sprintf((page + len), "fe:%d ", - info->stats.rxframing); - if (info->stats.rxparity) - len += sprintf((page + len), "pe:%d ", - info->stats.rxparity); - if (info->stats.rxbreak) - len += sprintf((page + len), "brk:%d ", - info->stats.rxbreak); - if (info->stats.rxoverrun) - len += sprintf((page + len), "oe:%d ", - info->stats.rxoverrun); - - str[0] = str[1] = 0; - if ((sigs = mcfrs_getsignals(info))) { - if (sigs & TIOCM_RTS) - strcat(str, "|RTS"); - if (sigs & TIOCM_CTS) - strcat(str, "|CTS"); - if (sigs & TIOCM_DTR) - strcat(str, "|DTR"); - if (sigs & TIOCM_CD) - strcat(str, "|CD"); - } - - len += sprintf((page + len), "%s\n", &str[1]); - } - - return(len); -} - - -/* Finally, routines used to initialize the serial driver. */ - -static void show_serial_version(void) -{ - printk(mcfrs_drivername); -} - -static const struct tty_operations mcfrs_ops = { - .open = mcfrs_open, - .close = mcfrs_close, - .write = mcfrs_write, - .flush_chars = mcfrs_flush_chars, - .write_room = mcfrs_write_room, - .chars_in_buffer = mcfrs_chars_in_buffer, - .flush_buffer = mcfrs_flush_buffer, - .ioctl = mcfrs_ioctl, - .throttle = mcfrs_throttle, - .unthrottle = mcfrs_unthrottle, - .set_termios = mcfrs_set_termios, - .stop = mcfrs_stop, - .start = mcfrs_start, - .hangup = mcfrs_hangup, - .read_proc = mcfrs_readproc, - .wait_until_sent = mcfrs_wait_until_sent, - .tiocmget = mcfrs_tiocmget, - .tiocmset = mcfrs_tiocmset, -}; - -/* mcfrs_init inits the driver */ -static int __init -mcfrs_init(void) -{ - struct mcf_serial *info; - unsigned long flags; - int i; - - /* Setup base handler, and timer table. */ -#ifdef MCFPP_DCD0 - init_timer(&mcfrs_timer_struct); - mcfrs_timer_struct.function = mcfrs_timer; - mcfrs_timer_struct.data = 0; - mcfrs_timer_struct.expires = jiffies + HZ/25; - add_timer(&mcfrs_timer_struct); - mcfrs_ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1); -#endif - mcfrs_serial_driver = alloc_tty_driver(NR_PORTS); - if (!mcfrs_serial_driver) - return -ENOMEM; - - show_serial_version(); - - /* Initialize the tty_driver structure */ - mcfrs_serial_driver->owner = THIS_MODULE; - mcfrs_serial_driver->name = "ttyS"; - mcfrs_serial_driver->driver_name = "mcfserial"; - mcfrs_serial_driver->major = TTY_MAJOR; - mcfrs_serial_driver->minor_start = 64; - mcfrs_serial_driver->type = TTY_DRIVER_TYPE_SERIAL; - mcfrs_serial_driver->subtype = SERIAL_TYPE_NORMAL; - mcfrs_serial_driver->init_termios = tty_std_termios; - - mcfrs_serial_driver->init_termios.c_cflag = - mcfrs_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL; - mcfrs_serial_driver->flags = TTY_DRIVER_REAL_RAW; - - tty_set_operations(mcfrs_serial_driver, &mcfrs_ops); - - if (tty_register_driver(mcfrs_serial_driver)) { - printk("MCFRS: Couldn't register serial driver\n"); - put_tty_driver(mcfrs_serial_driver); - return(-EBUSY); - } - - local_irq_save(flags); - - /* - * Configure all the attached serial ports. - */ - for (i = 0, info = mcfrs_table; (i < NR_PORTS); i++, info++) { - info->magic = SERIAL_MAGIC; - info->line = i; - info->port.tty = NULL; - info->custom_divisor = 16; - info->close_delay = 50; - info->closing_wait = 3000; - info->x_char = 0; - info->event = 0; - info->count = 0; - info->blocked_open = 0; - INIT_WORK(&info->tqueue, mcfrs_offintr); - INIT_WORK(&info->tqueue_hangup, do_serial_hangup); - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - - info->imr = 0; - mcfrs_setsignals(info, 0, 0); - mcfrs_irqinit(info); - - printk("ttyS%d at 0x%04x (irq = %d)", info->line, - (unsigned int) info->addr, info->irq); - printk(" is a builtin ColdFire UART\n"); - } - - local_irq_restore(flags); - return 0; -} - -module_init(mcfrs_init); - -/****************************************************************************/ -/* Serial Console */ -/****************************************************************************/ - -/* - * Quick and dirty UART initialization, for console output. - */ - -void mcfrs_init_console(void) -{ - volatile unsigned char *uartp; - unsigned int clk; - - /* - * Reset UART, get it into known state... - */ - uartp = (volatile unsigned char *) (MCF_MBAR + - (mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1)); - - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ - uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR; /* reset MR pointer */ - - /* - * Set port for defined baud , 8 data bits, 1 stop bit, no parity. - */ - uartp[MCFUART_UMR] = MCFUART_MR1_PARITYNONE | MCFUART_MR1_CS8; - uartp[MCFUART_UMR] = MCFUART_MR2_STOP1; - -#ifdef CONFIG_M5272 -{ - /* - * For the MCF5272, also compute the baudrate fraction. - */ - int fraction = MCF_BUSCLK - (clk * 32 * mcfrs_console_baud); - fraction *= 16; - fraction /= (32 * mcfrs_console_baud); - uartp[MCFUART_UFPD] = (fraction & 0xf); /* set fraction */ - clk = (MCF_BUSCLK / mcfrs_console_baud) / 32; -} -#else - clk = ((MCF_BUSCLK / mcfrs_console_baud) + 16) / 32; /* set baud */ -#endif - - uartp[MCFUART_UBG1] = (clk & 0xff00) >> 8; /* set msb baud */ - uartp[MCFUART_UBG2] = (clk & 0xff); /* set lsb baud */ - uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER; - uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE; - - mcfrs_console_inited++; - return; -} - - -/* - * Setup for console. Argument comes from the boot command line. - */ - -int mcfrs_console_setup(struct console *cp, char *arg) -{ - int i, n = CONSOLE_BAUD_RATE; - - if (!cp) - return(-1); - - if (!strncmp(cp->name, "ttyS", 4)) - mcfrs_console_port = cp->index; - else if (!strncmp(cp->name, "cua", 3)) - mcfrs_console_port = cp->index; - else - return(-1); - - if (arg) - n = simple_strtoul(arg,NULL,0); - for (i = 0; i < MCFRS_BAUD_TABLE_SIZE; i++) - if (mcfrs_baud_table[i] == n) - break; - if (i < MCFRS_BAUD_TABLE_SIZE) { - mcfrs_console_baud = n; - mcfrs_console_cbaud = 0; - if (i > 15) { - mcfrs_console_cbaud |= CBAUDEX; - i -= 15; - } - mcfrs_console_cbaud |= i; - } - mcfrs_init_console(); /* make sure baud rate changes */ - return(0); -} - - -static struct tty_driver *mcfrs_console_device(struct console *c, int *index) -{ - *index = c->index; - return mcfrs_serial_driver; -} - - -/* - * Output a single character, using UART polled mode. - * This is used for console output. - */ - -int mcfrs_put_char(char ch) -{ - volatile unsigned char *uartp; - unsigned long flags; - int i; - - uartp = (volatile unsigned char *) (MCF_MBAR + - (mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1)); - - local_irq_save(flags); - for (i = 0; (i < 0x10000); i++) { - if (uartp[MCFUART_USR] & MCFUART_USR_TXREADY) - break; - } - if (i < 0x10000) { - uartp[MCFUART_UTB] = ch; - for (i = 0; (i < 0x10000); i++) - if (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY) - break; - } - if (i >= 0x10000) - mcfrs_init_console(); /* try and get it back */ - local_irq_restore(flags); - - return 1; -} - - -/* - * rs_console_write is registered for printk output. - */ - -void mcfrs_console_write(struct console *cp, const char *p, unsigned len) -{ - if (!mcfrs_console_inited) - mcfrs_init_console(); - while (len-- > 0) { - if (*p == '\n') - mcfrs_put_char('\r'); - mcfrs_put_char(*p++); - } -} - -/* - * declare our consoles - */ - -struct console mcfrs_console = { - .name = "ttyS", - .write = mcfrs_console_write, - .device = mcfrs_console_device, - .setup = mcfrs_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -static int __init mcfrs_console_init(void) -{ - register_console(&mcfrs_console); - return 0; -} - -console_initcall(mcfrs_console_init); - -/****************************************************************************/ diff --git a/drivers/serial/mcfserial.h b/drivers/serial/mcfserial.h deleted file mode 100644 index 56420e2..0000000 --- a/drivers/serial/mcfserial.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * mcfserial.c -- serial driver for ColdFire internal UARTS. - * - * Copyright (c) 1999 Greg Ungerer <gerg@snapgear.com> - * Copyright (c) 2000-2001 Lineo, Inc. <www.lineo.com> - * Copyright (c) 2002 SnapGear Inc., <www.snapgear.com> - * - * Based on code from 68332serial.c which was: - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1998 TSHG - * Copyright (c) 1999 Rt-Control Inc. <jeff@uclinux.org> - */ -#ifndef _MCF_SERIAL_H -#define _MCF_SERIAL_H - -#include <linux/serial.h> - -#ifdef __KERNEL__ - -/* - * Define a local serial stats structure. - */ - -struct mcf_stats { - unsigned int rx; - unsigned int tx; - unsigned int rxbreak; - unsigned int rxframing; - unsigned int rxparity; - unsigned int rxoverrun; -}; - - -/* - * This is our internal structure for each serial port's state. - * Each serial port has one of these structures associated with it. - */ - -struct mcf_serial { - int magic; - volatile unsigned char *addr; /* UART memory address */ - int irq; - int flags; /* defined in tty.h */ - int type; /* UART type */ - struct tty_struct *tty; - unsigned char imr; /* Software imr register */ - unsigned int baud; - int sigs; - int custom_divisor; - int x_char; /* xon/xoff character */ - int baud_base; - int close_delay; - unsigned short closing_wait; - unsigned short closing_wait2; - unsigned long event; - int line; - int count; /* # of fd on device */ - int blocked_open; /* # of blocked opens */ - unsigned char *xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; - struct mcf_stats stats; - struct work_struct tqueue; - struct work_struct tqueue_hangup; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; - -}; - -#endif /* __KERNEL__ */ - -#endif /* _MCF_SERIAL_H */ diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index f977c98..6bdf336 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -2051,7 +2051,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) "transmitter\n", port->dev ? port->dev->bus_id : "", port->dev ? ": " : "", - drv->dev_name, port->line); + drv->dev_name, + drv->tty_driver->name_base + port->line); ops->shutdown(port); } @@ -2154,12 +2155,11 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) switch (port->iotype) { case UPIO_PORT: - snprintf(address, sizeof(address), - "I/O 0x%x", port->iobase); + snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase); break; case UPIO_HUB6: snprintf(address, sizeof(address), - "I/O 0x%x offset 0x%x", port->iobase, port->hub6); + "I/O 0x%lx offset 0x%x", port->iobase, port->hub6); break; case UPIO_MEM: case UPIO_MEM32: @@ -2177,7 +2177,9 @@ uart_report_port(struct uart_driver *drv, struct uart_port *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)); + drv->dev_name, + drv->tty_driver->name_base + port->line, + address, port->irq, uart_type(port)); } static void diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 164d2a4..7546aa8 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -431,131 +431,103 @@ first_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse) { int i; i = pcmcia_get_first_tuple(handle, tuple); - if (i != CS_SUCCESS) - return CS_NO_MORE_ITEMS; - i = pcmcia_get_tuple_data(handle, tuple); - if (i != CS_SUCCESS) + if (i != 0) return i; - return pcmcia_parse_tuple(handle, tuple, parse); -} - -static int -next_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse) -{ - int i; - i = pcmcia_get_next_tuple(handle, tuple); - if (i != CS_SUCCESS) - return CS_NO_MORE_ITEMS; i = pcmcia_get_tuple_data(handle, tuple); - if (i != CS_SUCCESS) + if (i != 0) return i; - return pcmcia_parse_tuple(handle, tuple, parse); + return pcmcia_parse_tuple(tuple, parse); } /*====================================================================*/ -static int simple_config(struct pcmcia_device *link) +static int simple_config_check(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cf, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) { - static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; static const int size_table[2] = { 8, 16 }; - struct serial_info *info = link->priv; - struct serial_cfg_mem *cfg_mem; - tuple_t *tuple; - u_char *buf; - cisparse_t *parse; - cistpl_cftable_entry_t *cf; - config_info_t config; - int i, j, try; - int s; + int *try = priv_data; + + if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) + p_dev->conf.Vpp = + cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; + + if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[(*try >> 1)]) + && (cf->io.win[0].base != 0)) { + p_dev->io.BasePort1 = cf->io.win[0].base; + p_dev->io.IOAddrLines = ((*try & 0x1) == 0) ? + 16 : cf->io.flags & CISTPL_IO_LINES_MASK; + if (!pcmcia_request_io(p_dev, &p_dev->io)) + return 0; + } + return -EINVAL; +} - cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL); - if (!cfg_mem) - return -1; +static int simple_config_check_notpicky(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cf, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; + int j; + + if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { + for (j = 0; j < 5; j++) { + p_dev->io.BasePort1 = base[j]; + p_dev->io.IOAddrLines = base[j] ? 16 : 3; + if (!pcmcia_request_io(p_dev, &p_dev->io)) + return 0; + } + } + return -ENODEV; +} - tuple = &cfg_mem->tuple; - parse = &cfg_mem->parse; - cf = &parse->cftable_entry; - buf = cfg_mem->buf; +static int simple_config(struct pcmcia_device *link) +{ + struct serial_info *info = link->priv; + int i = -ENODEV, try; /* If the card is already configured, look up the port and irq */ - i = pcmcia_get_configuration_info(link, &config); - if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) { + if (link->function_config) { unsigned int port = 0; - if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) { - port = config.BasePort2; + if ((link->io.BasePort2 != 0) && + (link->io.NumPorts2 == 8)) { + port = link->io.BasePort2; info->slave = 1; } else if ((info->manfid == MANFID_OSITECH) && - (config.NumPorts1 == 0x40)) { - port = config.BasePort1 + 0x28; + (link->io.NumPorts1 == 0x40)) { + port = link->io.BasePort1 + 0x28; info->slave = 1; } if (info->slave) { - kfree(cfg_mem); - return setup_serial(link, info, port, config.AssignedIRQ); + return setup_serial(link, info, port, + link->irq.AssignedIRQ); } } - /* First pass: look for a config entry that looks normal. */ - tuple->TupleData = (cisdata_t *) buf; - tuple->TupleOffset = 0; - tuple->TupleDataMax = 255; - tuple->Attributes = 0; - tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; - /* Two tries: without IO aliases, then with aliases */ - for (s = 0; s < 2; s++) { - for (try = 0; try < 2; try++) { - i = first_tuple(link, tuple, parse); - while (i != CS_NO_MORE_ITEMS) { - if (i != CS_SUCCESS) - goto next_entry; - if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp = - cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; - if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[s]) && - (cf->io.win[0].base != 0)) { - link->conf.ConfigIndex = cf->index; - link->io.BasePort1 = cf->io.win[0].base; - link->io.IOAddrLines = (try == 0) ? - 16 : cf->io.flags & CISTPL_IO_LINES_MASK; - i = pcmcia_request_io(link, &link->io); - if (i == CS_SUCCESS) - goto found_port; - } -next_entry: - i = next_tuple(link, tuple, parse); - } - } - } + /* First pass: look for a config entry that looks normal. + * Two tries: without IO aliases, then with aliases */ + for (try = 0; try < 4; try++) + if (!pcmcia_loop_config(link, simple_config_check, &try)) + goto found_port; + /* Second pass: try to find an entry that isn't picky about its base address, then try to grab any standard serial port address, and finally try to get any free port. */ - i = first_tuple(link, tuple, parse); - while (i != CS_NO_MORE_ITEMS) { - if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && - ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { - link->conf.ConfigIndex = cf->index; - for (j = 0; j < 5; j++) { - link->io.BasePort1 = base[j]; - link->io.IOAddrLines = base[j] ? 16 : 3; - i = pcmcia_request_io(link, &link->io); - if (i == CS_SUCCESS) - goto found_port; - } - } - i = next_tuple(link, tuple, parse); - } + if (!pcmcia_loop_config(link, simple_config_check_notpicky, NULL)) + goto found_port; - found_port: - if (i != CS_SUCCESS) { - printk(KERN_NOTICE - "serial_cs: no usable port range found, giving up\n"); - cs_error(link, RequestIO, i); - kfree(cfg_mem); - return -1; - } + printk(KERN_NOTICE + "serial_cs: no usable port range found, giving up\n"); + cs_error(link, RequestIO, i); + return -1; +found_port: i = pcmcia_request_irq(link, &link->irq); - if (i != CS_SUCCESS) { + if (i != 0) { cs_error(link, RequestIRQ, i); link->irq.AssignedIRQ = 0; } @@ -569,88 +541,76 @@ next_entry: info->quirk->config(link); i = pcmcia_request_configuration(link, &link->conf); - if (i != CS_SUCCESS) { + if (i != 0) { cs_error(link, RequestConfiguration, i); - kfree(cfg_mem); return -1; } - kfree(cfg_mem); return setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ); } -static int multi_config(struct pcmcia_device * link) +static int multi_config_check(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cf, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) { - struct serial_info *info = link->priv; - struct serial_cfg_mem *cfg_mem; - tuple_t *tuple; - u_char *buf; - cisparse_t *parse; - cistpl_cftable_entry_t *cf; - int i, rc, base2 = 0; + int *base2 = priv_data; + + /* The quad port cards have bad CIS's, so just look for a + window larger than 8 ports and assume it will be right */ + if ((cf->io.nwin == 1) && (cf->io.win[0].len > 8)) { + p_dev->io.BasePort1 = cf->io.win[0].base; + p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; + if (!pcmcia_request_io(p_dev, &p_dev->io)) { + *base2 = p_dev->io.BasePort1 + 8; + return 0; + } + } + return -ENODEV; +} - cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL); - if (!cfg_mem) - return -1; - tuple = &cfg_mem->tuple; - parse = &cfg_mem->parse; - cf = &parse->cftable_entry; - buf = cfg_mem->buf; +static int multi_config_check_notpicky(struct pcmcia_device *p_dev, + cistpl_cftable_entry_t *cf, + cistpl_cftable_entry_t *dflt, + unsigned int vcc, + void *priv_data) +{ + int *base2 = priv_data; + + if (cf->io.nwin == 2) { + p_dev->io.BasePort1 = cf->io.win[0].base; + p_dev->io.BasePort2 = cf->io.win[1].base; + p_dev->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; + if (!pcmcia_request_io(p_dev, &p_dev->io)) { + *base2 = p_dev->io.BasePort2; + return 0; + } + } + return -ENODEV; +} - tuple->TupleData = (cisdata_t *) buf; - tuple->TupleOffset = 0; - tuple->TupleDataMax = 255; - tuple->Attributes = 0; - tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; +static int multi_config(struct pcmcia_device *link) +{ + struct serial_info *info = link->priv; + int i, base2 = 0; /* First, look for a generic full-sized window */ link->io.NumPorts1 = info->multi * 8; - i = first_tuple(link, tuple, parse); - while (i != CS_NO_MORE_ITEMS) { - /* The quad port cards have bad CIS's, so just look for a - window larger than 8 ports and assume it will be right */ - if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && - (cf->io.win[0].len > 8)) { - link->conf.ConfigIndex = cf->index; - link->io.BasePort1 = cf->io.win[0].base; - link->io.IOAddrLines = - cf->io.flags & CISTPL_IO_LINES_MASK; - i = pcmcia_request_io(link, &link->io); - base2 = link->io.BasePort1 + 8; - if (i == CS_SUCCESS) - break; - } - i = next_tuple(link, tuple, parse); - } - - /* If that didn't work, look for two windows */ - if (i != CS_SUCCESS) { + if (pcmcia_loop_config(link, multi_config_check, &base2)) { + /* If that didn't work, look for two windows */ link->io.NumPorts1 = link->io.NumPorts2 = 8; info->multi = 2; - i = first_tuple(link, tuple, parse); - while (i != CS_NO_MORE_ITEMS) { - if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) { - link->conf.ConfigIndex = cf->index; - link->io.BasePort1 = cf->io.win[0].base; - link->io.BasePort2 = cf->io.win[1].base; - link->io.IOAddrLines = - cf->io.flags & CISTPL_IO_LINES_MASK; - i = pcmcia_request_io(link, &link->io); - base2 = link->io.BasePort2; - if (i == CS_SUCCESS) - break; - } - i = next_tuple(link, tuple, parse); + if (pcmcia_loop_config(link, multi_config_check_notpicky, + &base2)) { + printk(KERN_NOTICE "serial_cs: no usable port range" + "found, giving up\n"); + return -ENODEV; } } - if (i != CS_SUCCESS) { - cs_error(link, RequestIO, i); - rc = -1; - goto free_cfg_mem; - } - i = pcmcia_request_irq(link, &link->irq); - if (i != CS_SUCCESS) { + if (i != 0) { + /* FIXME: comment does not fit, error handling does not fit */ printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n"); cs_error(link, RequestIRQ, i); @@ -664,10 +624,9 @@ static int multi_config(struct pcmcia_device * link) info->quirk->config(link); i = pcmcia_request_configuration(link, &link->conf); - if (i != CS_SUCCESS) { + if (i != 0) { cs_error(link, RequestConfiguration, i); - rc = -1; - goto free_cfg_mem; + return -ENODEV; } /* The Oxford Semiconductor OXCF950 cards are in fact single-port: @@ -678,7 +637,8 @@ static int multi_config(struct pcmcia_device * link) info->prodid == PRODID_POSSIO_GCC)) { int err; - if (cf->index == 1 || cf->index == 3) { + if (link->conf.ConfigIndex == 1 || + link->conf.ConfigIndex == 3) { err = setup_serial(link, info, base2, link->irq.AssignedIRQ); base2 = link->io.BasePort1; @@ -695,18 +655,14 @@ static int multi_config(struct pcmcia_device * link) if (info->quirk && info->quirk->wakeup) info->quirk->wakeup(link); - rc = 0; - goto free_cfg_mem; + return 0; } setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ); for (i = 0; i < info->multi - 1; i++) setup_serial(link, info, base2 + (8 * i), link->irq.AssignedIRQ); - rc = 0; -free_cfg_mem: - kfree(cfg_mem); - return rc; + return 0; } /*====================================================================== @@ -746,7 +702,7 @@ static int serial_config(struct pcmcia_device * link) /* Is this a compliant multifunction card? */ tuple->DesiredTuple = CISTPL_LONGLINK_MFC; tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; - info->multi = (first_tuple(link, tuple, parse) == CS_SUCCESS); + info->multi = (first_tuple(link, tuple, parse) == 0); /* Is this a multiport card? */ tuple->DesiredTuple = CISTPL_MANFID; @@ -770,7 +726,7 @@ static int serial_config(struct pcmcia_device * link) ((link->func_id == CISTPL_FUNCID_MULTI) || (link->func_id == CISTPL_FUNCID_SERIAL))) { tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; - if (first_tuple(link, tuple, parse) == CS_SUCCESS) { + if (first_tuple(link, tuple, parse) == 0) { if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) info->multi = cf->io.win[0].len >> 3; if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index e41766d..a94a2ab 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c @@ -616,7 +616,7 @@ static int __devexit hv_remove(struct of_device *dev) return 0; } -static struct of_device_id hv_match[] = { +static const struct of_device_id hv_match[] = { { .name = "console", .compatible = "qcn", diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 29b4458..0355efe 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -1078,7 +1078,7 @@ static int __devexit sab_remove(struct of_device *op) return 0; } -static struct of_device_id sab_match[] = { +static const struct of_device_id sab_match[] = { { .name = "se", }, diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index a378464..a4dc79b1 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1506,7 +1506,7 @@ static int __devexit su_remove(struct of_device *op) return 0; } -static struct of_device_id su_match[] = { +static const struct of_device_id su_match[] = { { .name = "su", }, diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 3cb4c8a..45a299f 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1480,7 +1480,7 @@ static int __devexit zs_remove(struct of_device *op) return 0; } -static struct of_device_id zs_match[] = { +static const struct of_device_id zs_match[] = { { .name = "zs", }, |