aboutsummaryrefslogtreecommitdiff
path: root/drivers/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/serial')
-rw-r--r--drivers/serial/8250.c74
-rw-r--r--drivers/serial/8250_au1x00.c5
-rw-r--r--drivers/serial/Kconfig27
-rw-r--r--drivers/serial/Makefile12
-rw-r--r--drivers/serial/cpm_uart/cpm_uart.h58
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c309
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.c56
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm2.c16
-rw-r--r--drivers/serial/imx.c40
-rw-r--r--drivers/serial/jsm/jsm.h2
-rw-r--r--drivers/serial/jsm/jsm_driver.c2
-rw-r--r--drivers/serial/jsm/jsm_neo.c2
-rw-r--r--drivers/serial/jsm/jsm_tty.c29
-rw-r--r--drivers/serial/m32r_sio.c1
-rw-r--r--drivers/serial/serial_core.c123
-rw-r--r--drivers/serial/serial_cs.c229
-rw-r--r--drivers/serial/sunsu.c1
17 files changed, 613 insertions, 373 deletions
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 674b15c78f6..bbf78aaf9e0 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -362,6 +362,40 @@ serial_out(struct uart_8250_port *up, int offset, int value)
#define serial_inp(up, offset) serial_in(up, offset)
#define serial_outp(up, offset, value) serial_out(up, offset, value)
+/* Uart divisor latch read */
+static inline int _serial_dl_read(struct uart_8250_port *up)
+{
+ return serial_inp(up, UART_DLL) | serial_inp(up, UART_DLM) << 8;
+}
+
+/* Uart divisor latch write */
+static inline void _serial_dl_write(struct uart_8250_port *up, int value)
+{
+ serial_outp(up, UART_DLL, value & 0xff);
+ serial_outp(up, UART_DLM, value >> 8 & 0xff);
+}
+
+#ifdef CONFIG_SERIAL_8250_AU1X00
+/* Au1x00 haven't got a standard divisor latch */
+static int serial_dl_read(struct uart_8250_port *up)
+{
+ if (up->port.iotype == UPIO_AU)
+ return __raw_readl(up->port.membase + 0x28);
+ else
+ return _serial_dl_read(up);
+}
+
+static void serial_dl_write(struct uart_8250_port *up, int value)
+{
+ if (up->port.iotype == UPIO_AU)
+ __raw_writel(value, up->port.membase + 0x28);
+ else
+ _serial_dl_write(up, value);
+}
+#else
+#define serial_dl_read(up) _serial_dl_read(up)
+#define serial_dl_write(up, value) _serial_dl_write(up, value)
+#endif
/*
* For the 16C950
@@ -494,7 +528,8 @@ static void disable_rsa(struct uart_8250_port *up)
*/
static int size_fifo(struct uart_8250_port *up)
{
- unsigned char old_fcr, old_mcr, old_dll, old_dlm, old_lcr;
+ unsigned char old_fcr, old_mcr, old_lcr;
+ unsigned short old_dl;
int count;
old_lcr = serial_inp(up, UART_LCR);
@@ -505,10 +540,8 @@ static int size_fifo(struct uart_8250_port *up)
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
serial_outp(up, UART_MCR, UART_MCR_LOOP);
serial_outp(up, UART_LCR, UART_LCR_DLAB);
- old_dll = serial_inp(up, UART_DLL);
- old_dlm = serial_inp(up, UART_DLM);
- serial_outp(up, UART_DLL, 0x01);
- serial_outp(up, UART_DLM, 0x00);
+ old_dl = serial_dl_read(up);
+ serial_dl_write(up, 0x0001);
serial_outp(up, UART_LCR, 0x03);
for (count = 0; count < 256; count++)
serial_outp(up, UART_TX, count);
@@ -519,8 +552,7 @@ static int size_fifo(struct uart_8250_port *up)
serial_outp(up, UART_FCR, old_fcr);
serial_outp(up, UART_MCR, old_mcr);
serial_outp(up, UART_LCR, UART_LCR_DLAB);
- serial_outp(up, UART_DLL, old_dll);
- serial_outp(up, UART_DLM, old_dlm);
+ serial_dl_write(up, old_dl);
serial_outp(up, UART_LCR, old_lcr);
return count;
@@ -750,8 +782,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
serial_outp(up, UART_LCR, 0xE0);
- quot = serial_inp(up, UART_DLM) << 8;
- quot += serial_inp(up, UART_DLL);
+ quot = serial_dl_read(up);
quot <<= 3;
status1 = serial_in(up, 0x04); /* EXCR1 */
@@ -759,8 +790,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
serial_outp(up, 0x04, status1);
- serial_outp(up, UART_DLL, quot & 0xff);
- serial_outp(up, UART_DLM, quot >> 8);
+ serial_dl_write(up, quot);
serial_outp(up, UART_LCR, 0);
@@ -1862,8 +1892,7 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
}
- serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */
- serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */
+ serial_dl_write(up, quot);
/*
* LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
@@ -1906,6 +1935,9 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
int ret = 0;
switch (up->port.iotype) {
+ case UPIO_AU:
+ size = 0x100000;
+ /* fall thru */
case UPIO_MEM:
if (!up->port.mapbase)
break;
@@ -1938,6 +1970,9 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
unsigned int size = 8 << up->port.regshift;
switch (up->port.iotype) {
+ case UPIO_AU:
+ size = 0x100000;
+ /* fall thru */
case UPIO_MEM:
if (!up->port.mapbase)
break;
@@ -2200,10 +2235,17 @@ static void
serial8250_console_write(struct console *co, const char *s, unsigned int count)
{
struct uart_8250_port *up = &serial8250_ports[co->index];
+ unsigned long flags;
unsigned int ier;
+ int locked = 1;
touch_nmi_watchdog();
+ if (oops_in_progress) {
+ locked = spin_trylock_irqsave(&up->port.lock, flags);
+ } else
+ spin_lock_irqsave(&up->port.lock, flags);
+
/*
* First save the IER then disable the interrupts
*/
@@ -2221,8 +2263,10 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
* and restore the IER
*/
wait_for_xmitr(up, BOTH_EMPTY);
- up->ier |= UART_IER_THRI;
- serial_out(up, UART_IER, ier | UART_IER_THRI);
+ serial_out(up, UART_IER, ier);
+
+ if (locked)
+ spin_unlock_irqrestore(&up->port.lock, flags);
}
static int serial8250_console_setup(struct console *co, char *options)
diff --git a/drivers/serial/8250_au1x00.c b/drivers/serial/8250_au1x00.c
index 3d1bfd07208..58015fd14be 100644
--- a/drivers/serial/8250_au1x00.c
+++ b/drivers/serial/8250_au1x00.c
@@ -30,13 +30,12 @@
{ \
.iobase = _base, \
.membase = (void __iomem *)_base,\
- .mapbase = _base, \
+ .mapbase = CPHYSADDR(_base), \
.irq = _irq, \
.uartclk = 0, /* filled */ \
.regshift = 2, \
.iotype = UPIO_AU, \
- .flags = UPF_SKIP_TEST | \
- UPF_IOREMAP, \
+ .flags = UPF_SKIP_TEST \
}
static struct plat_serial8250_port au1x00_data[] = {
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index fe0d8b8e91c..7d22dc0478d 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -63,6 +63,33 @@ config SERIAL_8250_CONSOLE
If unsure, say N.
+config SERIAL_8250_GSC
+ tristate
+ depends on SERIAL_8250 && GSC
+ default SERIAL_8250
+
+config SERIAL_8250_PCI
+ tristate "8250/16550 PCI device support" if EMBEDDED
+ depends on SERIAL_8250 && PCI
+ default SERIAL_8250
+ help
+ This builds standard PCI serial support. You may be able to
+ disable this feature if you only need legacy serial support.
+ Saves about 9K.
+
+config SERIAL_8250_PNP
+ tristate "8250/16550 PNP device support" if EMBEDDED
+ depends on SERIAL_8250 && PNP
+ default SERIAL_8250
+ help
+ This builds standard PNP serial support. You may be able to
+ disable this feature if you only need legacy serial support.
+
+config SERIAL_8250_HP300
+ tristate
+ depends on SERIAL_8250 && HP300
+ default SERIAL_8250
+
config SERIAL_8250_CS
tristate "8250/16550 PCMCIA device support"
depends on PCMCIA && SERIAL_8250
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index d2b4c214876..0a71bf68a03 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -4,15 +4,13 @@
# $Id: Makefile,v 1.8 2002/07/21 21:32:30 rmk Exp $
#
-serial-8250-y :=
-serial-8250-$(CONFIG_PNP) += 8250_pnp.o
-serial-8250-$(CONFIG_GSC) += 8250_gsc.o
-serial-8250-$(CONFIG_PCI) += 8250_pci.o
-serial-8250-$(CONFIG_HP300) += 8250_hp300.o
-
obj-$(CONFIG_SERIAL_CORE) += serial_core.o
obj-$(CONFIG_SERIAL_21285) += 21285.o
-obj-$(CONFIG_SERIAL_8250) += 8250.o $(serial-8250-y)
+obj-$(CONFIG_SERIAL_8250) += 8250.o
+obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
+obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
+obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
+obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h
index 73c8a088c16..3b35cb77953 100644
--- a/drivers/serial/cpm_uart/cpm_uart.h
+++ b/drivers/serial/cpm_uart/cpm_uart.h
@@ -5,11 +5,20 @@
*
* Copyright (C) 2004 Freescale Semiconductor, Inc.
*
+ * 2006 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
*/
#ifndef CPM_UART_H
#define CPM_UART_H
#include <linux/config.h>
+#include <linux/platform_device.h>
+#include <linux/fs_uart_pd.h>
#if defined(CONFIG_CPM2)
#include "cpm_uart_cpm2.h"
@@ -26,14 +35,14 @@
#define FLAG_SMC 0x00000002
#define FLAG_CONSOLE 0x00000001
-#define UART_SMC1 0
-#define UART_SMC2 1
-#define UART_SCC1 2
-#define UART_SCC2 3
-#define UART_SCC3 4
-#define UART_SCC4 5
+#define UART_SMC1 fsid_smc1_uart
+#define UART_SMC2 fsid_smc2_uart
+#define UART_SCC1 fsid_scc1_uart
+#define UART_SCC2 fsid_scc2_uart
+#define UART_SCC3 fsid_scc3_uart
+#define UART_SCC4 fsid_scc4_uart
-#define UART_NR 6
+#define UART_NR fs_uart_nr
#define RX_NUM_FIFO 4
#define RX_BUF_SIZE 32
@@ -64,6 +73,7 @@ struct uart_cpm_port {
uint dp_addr;
void *mem_addr;
dma_addr_t dma_addr;
+ u32 mem_size;
/* helpers */
int baud;
int bits;
@@ -90,4 +100,38 @@ void scc2_lineif(struct uart_cpm_port *pinfo);
void scc3_lineif(struct uart_cpm_port *pinfo);
void scc4_lineif(struct uart_cpm_port *pinfo);
+/*
+ virtual to phys transtalion
+*/
+static inline unsigned long cpu2cpm_addr(void* addr, struct uart_cpm_port *pinfo)
+{
+ int offset;
+ u32 val = (u32)addr;
+ /* sane check */
+ if (likely((val >= (u32)pinfo->mem_addr)) &&
+ (val<((u32)pinfo->mem_addr + pinfo->mem_size))) {
+ offset = val - (u32)pinfo->mem_addr;
+ return pinfo->dma_addr+offset;
+ }
+ /* something nasty happened */
+ BUG();
+ return 0;
+}
+
+static inline void *cpm2cpu_addr(unsigned long addr, struct uart_cpm_port *pinfo)
+{
+ int offset;
+ u32 val = addr;
+ /* sane check */
+ if (likely((val >= pinfo->dma_addr) &&
+ (val<(pinfo->dma_addr + pinfo->mem_size)))) {
+ offset = val - (u32)pinfo->dma_addr;
+ return (void*)(pinfo->mem_addr+offset);
+ }
+ /* something nasty happened */
+ BUG();
+ return 0;
+}
+
+
#endif /* CPM_UART_H */
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index b7bf4c698a4..5cba59ad7dc 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -12,7 +12,8 @@
*
* Copyright (C) 2004 Freescale Semiconductor, Inc.
* (C) 2004 Intracom, S.A.
- * (C) 2005 MontaVista Software, Inc. by Vitaly Bordug <vbordug@ru.mvista.com>
+ * (C) 2005-2006 MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
*
* 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
@@ -41,6 +42,7 @@
#include <linux/device.h>
#include <linux/bootmem.h>
#include <linux/dma-mapping.h>
+#include <linux/fs_uart_pd.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -60,7 +62,7 @@
/* Track which ports are configured as uarts */
int cpm_uart_port_map[UART_NR];
/* How many ports did we config as uarts */
-int cpm_uart_nr;
+int cpm_uart_nr = 0;
/**************************************************************/
@@ -71,18 +73,51 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo);
/**************************************************************/
-static inline unsigned long cpu2cpm_addr(void *addr)
+
+/* Place-holder for board-specific stuff */
+struct platform_device* __attribute__ ((weak)) __init
+early_uart_get_pdev(int index)
+{
+ return NULL;
+}
+
+
+static void cpm_uart_count(void)
{
- if ((unsigned long)addr >= CPM_ADDR)
- return (unsigned long)addr;
- return virt_to_bus(addr);
+ cpm_uart_nr = 0;
+#ifdef CONFIG_SERIAL_CPM_SMC1
+ cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1;
+#endif
+#ifdef CONFIG_SERIAL_CPM_SMC2
+ cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2;
+#endif
+#ifdef CONFIG_SERIAL_CPM_SCC1
+ cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1;
+#endif
+#ifdef CONFIG_SERIAL_CPM_SCC2
+ cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2;
+#endif
+#ifdef CONFIG_SERIAL_CPM_SCC3
+ cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3;
+#endif
+#ifdef CONFIG_SERIAL_CPM_SCC4
+ cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4;
+#endif
}
-static inline void *cpm2cpu_addr(unsigned long addr)
+/* Get UART number by its id */
+static int cpm_uart_id2nr(int id)
{
- if (addr >= CPM_ADDR)
- return (void *)addr;
- return bus_to_virt(addr);
+ int i;
+ if (id < UART_NR) {
+ for (i=0; i<UART_NR; i++) {
+ if (cpm_uart_port_map[i] == id)
+ return i;
+ }
+ }
+
+ /* not found or invalid argument */
+ return -1;
}
/*
@@ -258,7 +293,7 @@ static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs)
}
/* get pointer */
- cp = cpm2cpu_addr(bdp->cbd_bufaddr);
+ cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
/* loop through the buffer */
while (i-- > 0) {
@@ -438,7 +473,11 @@ static void cpm_uart_shutdown(struct uart_port *port)
}
/* Shut them really down and reinit buffer descriptors */
- cpm_line_cr_cmd(line, CPM_CR_STOP_TX);
+ if (IS_SMC(pinfo))
+ cpm_line_cr_cmd(line, CPM_CR_STOP_TX);
+ else
+ cpm_line_cr_cmd(line, CPM_CR_GRA_STOP_TX);
+
cpm_uart_initbd(pinfo);
}
}
@@ -601,7 +640,7 @@ static int cpm_uart_tx_pump(struct uart_port *port)
/* Pick next descriptor and fill from buffer */
bdp = pinfo->tx_cur;
- p = cpm2cpu_addr(bdp->cbd_bufaddr);
+ p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
*p++ = port->x_char;
bdp->cbd_datlen = 1;
@@ -628,7 +667,7 @@ static int cpm_uart_tx_pump(struct uart_port *port)
while (!(bdp->cbd_sc & BD_SC_READY) && (xmit->tail != xmit->head)) {
count = 0;
- p = cpm2cpu_addr(bdp->cbd_bufaddr);
+ p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
while (count < pinfo->tx_fifosize) {
*p++ = xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
@@ -677,12 +716,12 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo)
mem_addr = pinfo->mem_addr;
bdp = pinfo->rx_cur = pinfo->rx_bd_base;
for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) {
- bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr);
+ bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT;
mem_addr += pinfo->rx_fifosize;
}
- bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr);
+ bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
/* Set the physical address of the host memory
@@ -692,12 +731,12 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo)
mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize);
bdp = pinfo->tx_cur = pinfo->tx_bd_base;
for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) {
- bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr);
+ bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
bdp->cbd_sc = BD_SC_INTRPT;
mem_addr += pinfo->tx_fifosize;
}
- bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr);
+ bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
bdp->cbd_sc = BD_SC_WRAP | BD_SC_INTRPT;
}
@@ -829,14 +868,6 @@ static int cpm_uart_request_port(struct uart_port *port)
if (pinfo->flags & FLAG_CONSOLE)
return 0;
- /*
- * Setup any port IO, connect any baud rate generators,
- * etc. This is expected to be handled by board
- * dependant code
- */
- if (pinfo->set_lineif)
- pinfo->set_lineif(pinfo);
-
if (IS_SMC(pinfo)) {
pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
@@ -988,6 +1019,58 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = {
},
};
+int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con)
+{
+ struct resource *r;
+ struct fs_uart_platform_info *pdata = pdev->dev.platform_data;
+ int idx = pdata->fs_no; /* It is UART_SMCx or UART_SCCx index */
+ struct uart_cpm_port *pinfo;
+ int line;
+ u32 mem, pram;
+
+ line = cpm_uart_id2nr(idx);
+ if(line < 0) {
+ printk(KERN_ERR"%s(): port %d is not registered", __FUNCTION__, idx);
+ return -1;
+ }
+
+ pinfo = (struct uart_cpm_port *) &cpm_uart_ports[idx];
+
+ pinfo->brg = pdata->brg;
+
+ if (!is_con) {
+ pinfo->port.line = line;
+ pinfo->port.flags = UPF_BOOT_AUTOCONF;
+ }
+
+ if (!(r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs")))
+ return -EINVAL;
+ mem = r->start;
+
+ if (!(r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram")))
+ return -EINVAL;
+ pram = r->start;
+
+ if(idx > fsid_smc2_uart) {
+ pinfo->sccp = (scc_t *)mem;
+ pinfo->sccup = (scc_uart_t *)pram;
+ } else {
+ pinfo->smcp = (smc_t *)mem;
+ pinfo->smcup = (smc_uart_t *)pram;
+ }
+ pinfo->tx_nrfifos = pdata->tx_num_fifo;
+ pinfo->tx_fifosize = pdata->tx_buf_size;
+
+ pinfo->rx_nrfifos = pdata->rx_num_fifo;
+ pinfo->rx_fifosize = pdata->rx_buf_size;
+
+ pinfo->port.uartclk = pdata->uart_clk;
+ pinfo->port.mapbase = (unsigned long)mem;
+ pinfo->port.irq = platform_get_irq(pdev, 0);
+
+ return 0;
+}
+
#ifdef CONFIG_SERIAL_CPM_CONSOLE
/*
* Print a string to the serial port trying not to disturb
@@ -1027,7 +1110,7 @@ static void cpm_uart_console_write(struct console *co, const char *s,
* If the buffer address is in the CPM DPRAM, don't
* convert it.
*/
- cp = cpm2cpu_addr(bdp->cbd_bufaddr);
+ cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
*cp = *s;
@@ -1044,7 +1127,7 @@ static void cpm_uart_console_write(struct console *co, const char *s,
while ((bdp->cbd_sc & BD_SC_READY) != 0)
;
- cp = cpm2cpu_addr(bdp->cbd_bufaddr);
+ cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
*cp = 13;
bdp->cbd_datlen = 1;
@@ -1067,9 +1150,7 @@ static void cpm_uart_console_write(struct console *co, const char *s,
pinfo->tx_cur = (volatile cbd_t *) bdp;
}
-/*
- * Setup console. Be careful is called early !
- */
+
static int __init cpm_uart_console_setup(struct console *co, char *options)
{
struct uart_port *port;
@@ -1080,9 +1161,29 @@ static int __init cpm_uart_console_setup(struct console *co, char *options)
int flow = 'n';
int ret;
+ struct fs_uart_platform_info *pdata;
+ struct platform_device* pdev = early_uart_get_pdev(co->index);
+
+ if (!pdev) {
+ pr_info("cpm_uart: console: compat mode\n");
+ /* compatibility - will be cleaned up */
+ cpm_uart_init_portdesc();
+ }
+
port =
(struct uart_port *)&cpm_uart_ports[cpm_uart_port_map[co->index]];
pinfo = (struct uart_cpm_port *)port;
+ if (!pdev) {
+ if (pinfo->set_lineif)
+ pinfo->set_lineif(pinfo);
+ } else {
+ pdata = pdev->dev.platform_data;
+ if (pdata)
+ if (pdata->init_ioports)
+ pdata->init_ioports();
+
+ cpm_uart_drv_get_platform_data(pdev, 1);
+ }
pinfo->flags |= FLAG_CONSOLE;
@@ -1097,14 +1198,6 @@ static int __init cpm_uart_console_setup(struct console *co, char *options)
baud = 9600;
}
- /*
- * Setup any port IO, connect any baud rate generators,
- * etc. This is expected to be handled by board
- * dependant code
- */
- if (pinfo->set_lineif)
- pinfo->set_lineif(pinfo);
-
if (IS_SMC(pinfo)) {
pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
@@ -1143,11 +1236,8 @@ static struct console cpm_scc_uart_console = {
int __init cpm_uart_console_init(void)
{
- int ret = cpm_uart_init_portdesc();
-
- if (!ret)
- register_console(&cpm_scc_uart_console);
- return ret;
+ register_console(&cpm_scc_uart_console);
+ return 0;
}
console_initcall(cpm_uart_console_init);
@@ -1165,44 +1255,129 @@ static struct uart_driver cpm_reg = {
.minor = SERIAL_CPM_MINOR,
.cons = CPM_UART_CONSOLE,
};
-
-static int __init cpm_uart_init(void)
+static int cpm_uart_drv_probe(struct device *dev)
{
- int ret, i;
-
- printk(KERN_INFO "Serial: CPM driver $Revision: 0.01 $\n");
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fs_uart_platform_info *pdata;
+ int ret = -ENODEV;
-#ifndef CONFIG_SERIAL_CPM_CONSOLE
- ret = cpm_uart_init_portdesc();
- if (ret)
+ if(!pdev) {
+ printk(KERN_ERR"CPM UART: platform data missing!\n");
return ret;
-#endif
+ }
- cpm_reg.nr = cpm_uart_nr;
- ret = uart_register_driver(&cpm_reg);
+ pdata = pdev->dev.platform_data;
+ pr_debug("cpm_uart_drv_probe: Adding CPM UART %d\n", cpm_uart_id2nr(pdata->fs_no));
- if (ret)
+ if ((ret = cpm_uart_drv_get_platform_data(pdev, 0)))
return ret;
- for (i = 0; i < cpm_uart_nr; i++) {
- int con = cpm_uart_port_map[i];
- cpm_uart_ports[con].port.line = i;
- cpm_uart_ports[con].port.flags = UPF_BOOT_AUTOCONF;
- uart_add_one_port(&cpm_reg, &cpm_uart_ports[con].port);
- }
+ if (pdata->init_ioports)
+ pdata->init_ioports();
- return ret;
+ ret = uart_add_one_port(&cpm_reg, &cpm_uart_ports[pdata->fs_no].port);
+
+ return ret;
}
-static void __exit cpm_uart_exit(void)
+static int cpm_uart_drv_remove(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fs_uart_platform_info *pdata = pdev->dev.platform_data;
+
+ pr_debug("cpm_uart_drv_remove: Removing CPM UART %d\n",
+ cpm_uart_id2nr(pdata->fs_no));
+
+ uart_remove_one_port(&cpm_reg, &cpm_uart_ports[pdata->fs_no].port);
+ return 0;
+}
+
+static struct device_driver cpm_smc_uart_driver = {
+ .name = "fsl-cpm-smc:uart",
+ .bus = &platform_bus_type,
+ .probe = cpm_uart_drv_probe,
+ .remove = cpm_uart_drv_remove,
+};
+
+static struct device_driver cpm_scc_uart_driver = {
+ .name = "fsl-cpm-scc:uart",
+ .bus = &platform_bus_type,
+ .probe = cpm_uart_drv_probe,
+ .remove = cpm_uart_drv_remove,
+};
+
+/*
+ This is supposed to match uart devices on platform bus,
+ */
+static int match_is_uart (struct device* dev, void* data)
{
+ struct platform_device* pdev = container_of(dev, struct platform_device, dev);
+ int ret = 0;
+ /* this was setfunc as uart */
+ if(strstr(pdev->name,":uart")) {
+ ret = 1;
+ }
+ return ret;
+}
+
+
+static int cpm_uart_init(void) {
+
+ int ret;
int i;
+ struct device *dev;
+ printk(KERN_INFO "Serial: CPM driver $Revision: 0.02 $\n");
+
+ /* lookup the bus for uart devices */
+ dev = bus_find_device(&platform_bus_type, NULL, 0, match_is_uart);
+
+ /* There are devices on the bus - all should be OK */
+ if (dev) {
+ cpm_uart_count();
+ cpm_reg.nr = cpm_uart_nr;
+
+ if (!(ret = uart_register_driver(&cpm_reg))) {
+ if ((ret = driver_register(&cpm_smc_uart_driver))) {
+ uart_unregister_driver(&cpm_reg);
+ return ret;
+ }
+ if ((ret = driver_register(&cpm_scc_uart_driver))) {
+ driver_unregister(&cpm_scc_uart_driver);
+ uart_unregister_driver(&cpm_reg);
+ }
+ }
+ } else {
+ /* No capable platform devices found - falling back to legacy mode */
+ pr_info("cpm_uart: WARNING: no UART devices found on platform bus!\n");
+ pr_info(
+ "cpm_uart: the driver will guess configuration, but this mode is no longer supported.\n");
+#ifndef CONFIG_SERIAL_CPM_CONSOLE
+ ret = cpm_uart_init_portdesc();
+ if (ret)
+ return ret;
+#endif
+
+ cpm_reg.nr = cpm_uart_nr;
+ ret = uart_register_driver(&cpm_reg);
+
+ if (ret)
+ return ret;
+
+ for (i = 0; i < cpm_uart_nr; i++) {
+ int con = cpm_uart_port_map[i];
+ cpm_uart_ports[con].port.line = i;
+ cpm_uart_ports[con].port.flags = UPF_BOOT_AUTOCONF;
+ uart_add_one_port(&cpm_reg, &cpm_uart_ports[con].port);
+ }
- for (i = 0; i < cpm_uart_nr; i++) {
- int con = cpm_uart_port_map[i];
- uart_remove_one_port(&cpm_reg, &cpm_uart_ports[con].port);
}
+ return ret;
+}
+static void __exit cpm_uart_exit(void)
+{
+ driver_unregister(&cpm_scc_uart_driver);
+ driver_unregister(&cpm_smc_uart_driver);
uart_unregister_driver(&cpm_reg);
}
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
index d789ee55cbb..17406a05ce1 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
@@ -8,6 +8,8 @@
*
* Copyright (C) 2004 Freescale Semiconductor, Inc.
* (C) 2004 Intracom, S.A.
+ * (C) 2006 MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
*
* 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
@@ -81,58 +83,11 @@ void cpm_line_cr_cmd(int line, int cmd)
void smc1_lineif(struct uart_cpm_port *pinfo)
{
- volatile cpm8xx_t *cp = cpmp;
-
- (void)cp; /* fix warning */
-#if defined (CONFIG_MPC885ADS)
- /* Enable SMC1 transceivers */
- {
- cp->cp_pepar |= 0x000000c0;
- cp->cp_pedir &= ~0x000000c0;
- cp->cp_peso &= ~0x00000040;
- cp->cp_peso |= 0x00000080;
- }
-#elif defined (CONFIG_MPC86XADS)
- unsigned int iobits = 0x000000c0;
-
- if (!pinfo->is_portb) {
- cp->cp_pbpar |= iobits;
- cp->cp_pbdir &= ~iobits;
- cp->cp_pbodr &= ~iobits;
- } else {
- ((immap_t *)IMAP_ADDR)->im_ioport.iop_papar |= iobits;
- ((immap_t *)IMAP_ADDR)->im_ioport.iop_padir &= ~iobits;
- ((immap_t *)IMAP_ADDR)->im_ioport.iop_paodr &= ~iobits;
- }
-#endif
pinfo->brg = 1;
}
void smc2_lineif(struct uart_cpm_port *pinfo)
{
- volatile cpm8xx_t *cp = cpmp;
-
- (void)cp; /* fix warning */
-#if defined (CONFIG_MPC885ADS)
- cp->cp_pepar |= 0x00000c00;
- cp->cp_pedir &= ~0x00000c00;
- cp->cp_peso &= ~0x00000400;
- cp->cp_peso |= 0x00000800;
-#elif defined (CONFIG_MPC86XADS)
- unsigned int iobits = 0x00000c00;
-
- if (!pinfo->is_portb) {
- cp->cp_pbpar |= iobits;
- cp->cp_pbdir &= ~iobits;
- cp->cp_pbodr &= ~iobits;
- } else {
- ((immap_t *)IMAP_ADDR)->im_ioport.iop_papar |= iobits;
- ((immap_t *)IMAP_ADDR)->im_ioport.iop_padir &= ~iobits;
- ((immap_t *)IMAP_ADDR)->im_ioport.iop_paodr &= ~iobits;
- }
-
-#endif
-
pinfo->brg = 2;
}
@@ -191,7 +146,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
/* was hostalloc but changed cause it blows away the */
/* large tlb mapping when pinning the kernel area */
mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8));
- dma_addr = 0;
+ dma_addr = (u32)mem_addr;
} else
mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
GFP_KERNEL);
@@ -204,8 +159,9 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
}
pinfo->dp_addr = dp_offset;
- pinfo->mem_addr = mem_addr;
- pinfo->dma_addr = dma_addr;
+ pinfo->mem_addr = mem_addr; /* virtual address*/
+ pinfo->dma_addr = dma_addr; /* physical address*/
+ pinfo->mem_size = memsz;
pinfo->rx_buf = mem_addr;
pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
index fd9e53ed3fe..cdba128250a 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
@@ -8,6 +8,8 @@
*
* Copyright (C) 2004 Freescale Semiconductor, Inc.
* (C) 2004 Intracom, S.A.
+ * (C) 2006 MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
*
* 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
@@ -142,14 +144,6 @@ void scc2_lineif(struct uart_cpm_port *pinfo)
* be supported in a sane fashion.
*/
#ifndef CONFIG_STX_GP3
-#ifdef CONFIG_MPC8560_ADS
- volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
- io->iop_ppard |= 0x00000018;
- io->iop_psord &= ~0x00000008; /* Rx */
- io->iop_psord &= ~0x00000010; /* Tx */
- io->iop_pdird &= ~0x00000008; /* Rx */
- io->iop_pdird |= 0x00000010; /* Tx */
-#else
volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
io->iop_pparb |= 0x008b0000;
io->iop_pdirb |= 0x00880000;
@@ -157,7 +151,6 @@ void scc2_lineif(struct uart_cpm_port *pinfo)
io->iop_pdirb &= ~0x00030000;
io->iop_psorb &= ~0x00030000;
#endif
-#endif
cpm2_immr->im_cpmux.cmx_scr &= 0xff00ffff;
cpm2_immr->im_cpmux.cmx_scr |= 0x00090000;
pinfo->brg = 2;
@@ -218,8 +211,10 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) +
L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize);
- if (is_con)
+ if (is_con) {
mem_addr = alloc_bootmem(memsz);
+ dma_addr = virt_to_bus(mem_addr);
+ }
else
mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
GFP_KERNEL);
@@ -234,6 +229,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
pinfo->dp_addr = dp_offset;
pinfo->mem_addr = mem_addr;
pinfo->dma_addr = dma_addr;
+ pinfo->mem_size = memsz;
pinfo->rx_buf = mem_addr;
pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index c3b7a6673e9..d202eb4f384 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -45,6 +45,7 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hardware.h>
+#include <asm/arch/imx-uart.h>
/* We've been assigned a range on the "Low-density serial ports" major */
#define SERIAL_IMX_MAJOR 204
@@ -73,7 +74,8 @@ struct imx_port {
struct uart_port port;
struct timer_list timer;
unsigned int old_status;
- int txirq,rxirq,rtsirq;
+ int txirq,rxirq,rtsirq;
+ int have_rtscts:1;
};
/*
@@ -491,8 +493,12 @@ imx_set_termios(struct uart_port *port, struct termios *termios,
ucr2 = UCR2_SRST | UCR2_IRTS;
if (termios->c_cflag & CRTSCTS) {
- ucr2 &= ~UCR2_IRTS;
- ucr2 |= UCR2_CTSC;
+ if( sport->have_rtscts ) {
+ ucr2 &= ~UCR2_IRTS;
+ ucr2 |= UCR2_CTSC;
+ } else {
+ termios->c_cflag &= ~CRTSCTS;
+ }
}
if (termios->c_cflag & CSTOPB)
@@ -719,27 +725,6 @@ static void __init imx_init_ports(void)
imx_ports[i].timer.function = imx_timeout;
imx_ports[i].timer.data = (unsigned long)&imx_ports[i];
}
-
- imx_gpio_mode(PC9_PF_UART1_CTS);
- imx_gpio_mode(PC10_PF_UART1_RTS);
- imx_gpio_mode(PC11_PF_UART1_TXD);
- imx_gpio_mode(PC12_PF_UART1_RXD);
- imx_gpio_mode(PB28_PF_UART2_CTS);
- imx_gpio_mode(PB29_PF_UART2_RTS);
-
- imx_gpio_mode(PB30_PF_UART2_TXD);
- imx_gpio_mode(PB31_PF_UART2_RXD);
-
-#if 0 /* We don't need these, on the mx1 the _modem_ side of the uart
- * is implemented.
- */
- imx_gpio_mode(PD7_AF_UART2_DTR);
- imx_gpio_mode(PD8_AF_UART2_DCD);
- imx_gpio_mode(PD9_AF_UART2_RI);
- imx_gpio_mode(PD10_AF_UART2_DSR);
-#endif
-
-
}
#ifdef CONFIG_SERIAL_IMX_CONSOLE
@@ -932,7 +917,14 @@ static int serial_imx_resume(struct platform_device *dev)
static int serial_imx_probe(struct platform_device *dev)
{
+ struct imxuart_platform_data *pdata;
+
imx_ports[dev->id].port.dev = &dev->dev;
+
+ pdata = (struct imxuart_platform_data *)dev->dev.platform_data;
+ if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
+ imx_ports[dev->id].have_rtscts = 1;
+
uart_add_one_port(&imx_reg, &imx_ports[dev->id].port);
platform_set_drvdata(dev, &imx_ports[dev->id]);
return 0;
diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h
index dfc1e86d3aa..043f50b1d10 100644
--- a/drivers/serial/jsm/jsm.h
+++ b/drivers/serial/jsm/jsm.h
@@ -20,7 +20,7 @@
*
* Contact Information:
* Scott H Kilau <Scott_Kilau@digi.com>
- * Wendy Xiong <wendyx@us.ltcfwd.linux.ibm.com>
+ * Wendy Xiong <wendyx@us.ibm.com>
*
***********************************************************************/
diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c
index b1b66e71d28..b3e1f71be4d 100644
--- a/drivers/serial/jsm/jsm_driver.c
+++ b/drivers/serial/jsm/jsm_driver.c
@@ -20,7 +20,7 @@
*
* Contact Information:
* Scott H Kilau <Scott_Kilau@digi.com>
- * Wendy Xiong <wendyx@us.ltcfwd.linux.ibm.com>
+ * Wendy Xiong <wendyx@us.ibm.com>
*
*
***********************************************************************/
diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c
index 87e4e2cf8ce..a5fc589d6ef 100644
--- a/drivers/serial/jsm/jsm_neo.c
+++ b/drivers/serial/jsm/jsm_neo.c
@@ -20,7 +20,7 @@
*
* Contact Information:
* Scott H Kilau <Scott_Kilau@digi.com>
- * Wendy Xiong <wendyx@us.ltcfwd.linux.ibm.com>
+ * Wendy Xiong <wendyx@us.ibm.com>
*
***********************************************************************/
#include <linux/delay.h> /* For udelay */
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c
index 4d48b625cd3..7d823705193 100644
--- a/drivers/serial/jsm/jsm_tty.c
+++ b/drivers/serial/jsm/jsm_tty.c
@@ -142,12 +142,14 @@ static void jsm_tty_send_xchar(struct uart_port *port, char ch)
{
unsigned long lock_flags;
struct jsm_channel *channel = (struct jsm_channel *)port;
+ struct termios *termios;
spin_lock_irqsave(&port->lock, lock_flags);
- if (ch == port->info->tty->termios->c_cc[VSTART])
+ termios = port->info->tty->termios;
+ if (ch == termios->c_cc[VSTART])
channel->ch_bd->bd_ops->send_start_character(channel);
- if (ch == port->info->tty->termios->c_cc[VSTOP])
+ if (ch == termios->c_cc[VSTOP])
channel->ch_bd->bd_ops->send_stop_character(channel);
spin_unlock_irqrestore(&port->lock, lock_flags);
}
@@ -178,6 +180,7 @@ static int jsm_tty_open(struct uart_port *port)
struct jsm_board *brd;
int rc = 0;
struct jsm_channel *channel = (struct jsm_channel *)port;
+ struct termios *termios;
/* Get board pointer from our array of majors we have allocated */
brd = channel->ch_bd;
@@ -239,12 +242,13 @@ static int jsm_tty_open(struct uart_port *port)
channel->ch_cached_lsr = 0;
channel->ch_stops_sent = 0;
- channel->ch_c_cflag = port->info->tty->termios->c_cflag;
- channel->ch_c_iflag = port->info->tty->termios->c_iflag;
- channel->ch_c_oflag = port->info->tty->termios->c_oflag;
- channel->ch_c_lflag = port->info->tty->termios->c_lflag;
- channel->ch_startc = port->info->tty->termios->c_cc[VSTART];
- channel->ch_stopc = port->info->tty->termios->c_cc[VSTOP];
+ termios = port->info->tty->termios;
+ channel->ch_c_cflag = termios->c_cflag;
+ channel->ch_c_iflag = termios->c_iflag;
+ channel->ch_c_oflag = termios->c_oflag;
+ channel->ch_c_lflag = termios->c_lflag;
+ channel->ch_startc = termios->c_cc[VSTART];
+ channel->ch_stopc = termios->c_cc[VSTOP];
/* Tell UART to init itself */
brd->bd_ops->uart_init(channel);
@@ -784,6 +788,7 @@ static void jsm_carrier(struct jsm_channel *ch)
void jsm_check_queue_flow_control(struct jsm_channel *ch)
{
+ struct board_ops *bd_ops = ch->ch_bd->bd_ops;
int qleft = 0;
/* Store how much space we have left in the queue */
@@ -809,7 +814,7 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch)
/* HWFLOW */
if (ch->ch_c_cflag & CRTSCTS) {
if(!(ch->ch_flags & CH_RECEIVER_OFF)) {
- ch->ch_bd->bd_ops->disable_receiver(ch);
+ bd_ops->disable_receiver(ch);
ch->ch_flags |= (CH_RECEIVER_OFF);
jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
"Internal queue hit hilevel mark (%d)! Turning off interrupts.\n",
@@ -819,7 +824,7 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch)
/* SWFLOW */
else if (ch->ch_c_iflag & IXOFF) {
if (ch->ch_stops_sent <= MAX_STOPS_SENT) {
- ch->ch_bd->bd_ops->send_stop_character(ch);
+ bd_ops->send_stop_character(ch);
ch->ch_stops_sent++;
jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
"Sending stop char! Times sent: %x\n", ch->ch_stops_sent);
@@ -846,7 +851,7 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch)
/* HWFLOW */
if (ch->ch_c_cflag & CRTSCTS) {
if (ch->ch_flags & CH_RECEIVER_OFF) {
- ch->ch_bd->bd_ops->enable_receiver(ch);
+ bd_ops->enable_receiver(ch);
ch->ch_flags &= ~(CH_RECEIVER_OFF);
jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
"Internal queue hit lowlevel mark (%d)! Turning on interrupts.\n",
@@ -856,7 +861,7 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch)
/* SWFLOW */
else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) {
ch->ch_stops_sent = 0;
- ch->ch_bd->bd_ops->send_start_character(ch);
+ bd_ops->send_start_character(ch);
jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Sending start char!\n");
}
}
diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c
index e9c10c0a30f..321a40f33b5 100644
--- a/drivers/serial/m32r_sio.c
+++ b/drivers/serial/m32r_sio.c
@@ -1057,7 +1057,6 @@ static void m32r_sio_console_write(struct console *co, const char *s,
{
struct uart_sio_port *up = &m32r_sio_ports[co->index];
unsigned int ier;
- int i;
/*
* First save the UER then disable the interrupts
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index fcd7744c425..17839e753e4 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -1500,20 +1500,18 @@ uart_block_til_ready(struct file *filp, struct uart_state *state)
static struct uart_state *uart_get(struct uart_driver *drv, int line)
{
struct uart_state *state;
+ int ret = 0;
- mutex_lock(&port_mutex);
state = drv->state + line;
if (mutex_lock_interruptible(&state->mutex)) {
- state = ERR_PTR(-ERESTARTSYS);
- goto out;
+ ret = -ERESTARTSYS;
+ goto err;
}
state->count++;
- if (!state->port) {
- state->count--;
- mutex_unlock(&state->mutex);
- state = ERR_PTR(-ENXIO);
- goto out;
+ if (!state->port || state->port->flags & UPF_DEAD) {
+ ret = -ENXIO;
+ goto err_unlock;
}
if (!state->info) {
@@ -1531,15 +1529,17 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line)
tasklet_init(&state->info->tlet, uart_tasklet_action,
(unsigned long)state);
} else {
- state->count--;
- mutex_unlock(&state->mutex);
- state = ERR_PTR(-ENOMEM);
+ ret = -ENOMEM;
+ goto err_unlock;
}
}
-
- out:
- mutex_unlock(&port_mutex);
return state;
+
+ err_unlock:
+ state->count--;
+ mutex_unlock(&state->mutex);
+ err:
+ return ERR_PTR(ret);
}
/*
@@ -1907,9 +1907,12 @@ uart_set_options(struct uart_port *port, struct console *co,
static void uart_change_pm(struct uart_state *state, int pm_state)
{
struct uart_port *port = state->port;
- if (port->ops->pm)
- port->ops->pm(port, pm_state, state->pm_state);
- state->pm_state = pm_state;
+
+ if (state->pm_state != pm_state) {
+ if (port->ops->pm)
+ port->ops->pm(port, pm_state, state->pm_state);
+ state->pm_state = pm_state;
+ }
}
int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
@@ -2085,45 +2088,6 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
}
}
-/*
- * This reverses the effects of uart_configure_port, hanging up the
- * port before removal.
- */
-static void
-uart_unconfigure_port(struct uart_driver *drv, struct uart_state *state)
-{
- struct uart_port *port = state->port;
- struct uart_info *info = state->info;
-
- if (info && info->tty)
- tty_vhangup(info->tty);
-
- mutex_lock(&state->mutex);
-
- state->info = NULL;
-
- /*
- * Free the port IO and memory resources, if any.
- */
- if (port->type != PORT_UNKNOWN)
- port->ops->release_port(port);
-
- /*
- * Indicate that there isn't a port here anymore.
- */
- port->type = PORT_UNKNOWN;
-
- /*
- * Kill the tasklet, and free resources.
- */
- if (info) {
- tasklet_kill(&info->tlet);
- kfree(info);
- }
-
- mutex_unlock(&state->mutex);
-}
-
static struct tty_operations uart_ops = {
.open = uart_open,
.close = uart_close,
@@ -2270,6 +2234,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
state = drv->state + port->line;
mutex_lock(&port_mutex);
+ mutex_lock(&state->mutex);
if (state->port) {
ret = -EINVAL;
goto out;
@@ -2304,7 +2269,13 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
port->cons && !(port->cons->flags & CON_ENABLED))
register_console(port->cons);
+ /*
+ * Ensure UPF_DEAD is not set.
+ */
+ port->flags &= ~UPF_DEAD;
+
out:
+ mutex_unlock(&state->mutex);
mutex_unlock(&port_mutex);
return ret;
@@ -2322,6 +2293,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
{
struct uart_state *state = drv->state + port->line;
+ struct uart_info *info;
BUG_ON(in_interrupt());
@@ -2332,11 +2304,48 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
mutex_lock(&port_mutex);
/*
+ * Mark the port "dead" - this prevents any opens from
+ * succeeding while we shut down the port.
+ */
+ mutex_lock(&state->mutex);
+ port->flags |= UPF_DEAD;
+ mutex_unlock(&state->mutex);
+
+ /*
* Remove the devices from devfs
*/
tty_unregister_device(drv->tty_driver, port->line);
- uart_unconfigure_port(drv, state);
+ info = state->info;
+ if (info && info->tty)
+ tty_vhangup(info->tty);
+
+ /*
+ * All users of this port should now be disconnected from
+ * this driver, and the port shut down. We should be the
+ * only thread fiddling with this port from now on.
+ */
+ state->info = NULL;
+
+ /*
+ * Free the port IO and memory resources, if any.
+ */
+ if (port->type != PORT_UNKNOWN)
+ port->ops->release_port(port);
+
+ /*
+ * Indicate that there isn't a port here anymore.
+ */
+ port->type = PORT_UNKNOWN;
+
+ /*
+ * Kill the tasklet, and free resources.
+ */
+ if (info) {
+ tasklet_kill(&info->tlet);
+ kfree(info);
+ }
+
state->port = NULL;
mutex_unlock(&port_mutex);
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index c30333694fd..2c70773543e 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -41,6 +41,7 @@
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/serial_core.h>
+#include <linux/delay.h>
#include <linux/major.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -97,11 +98,13 @@ static const struct multi_id multi_id[] = {
#define MULTI_COUNT (sizeof(multi_id)/sizeof(struct multi_id))
struct serial_info {
- dev_link_t link;
+ struct pcmcia_device *p_dev;
int ndev;
int multi;
int slave;
int manfid;
+ int prodid;
+ int c950ctrl;
dev_node_t node[4];
int line[4];
};
@@ -113,9 +116,36 @@ struct serial_cfg_mem {
};
-static void serial_config(dev_link_t * link);
+static int serial_config(struct pcmcia_device * link);
+static void wakeup_card(struct serial_info *info)
+{
+ int ctrl = info->c950ctrl;
+
+ if (info->manfid == MANFID_OXSEMI) {
+ outb(12, ctrl + 1);
+ } else if (info->manfid == MANFID_POSSIO && info->prodid == PRODID_POSSIO_GCC) {
+ /* request_region? oxsemi branch does no request_region too... */
+ /* This sequence is needed to properly initialize MC45 attached to OXCF950.
+ * I tried decreasing these msleep()s, but it worked properly (survived
+ * 1000 stop/start operations) with these timeouts (or bigger). */
+ outb(0xA, ctrl + 1);
+ msleep(100);
+ outb(0xE, ctrl + 1);
+ msleep(300);
+ outb(0xC, ctrl + 1);
+ msleep(100);
+ outb(0xE, ctrl + 1);
+ msleep(200);
+ outb(0xF, ctrl + 1);
+ msleep(100);
+ outb(0xE, ctrl + 1);
+ msleep(100);
+ outb(0xC, ctrl + 1);
+ }
+}
+
/*======================================================================
After a card is removed, serial_remove() will unregister
@@ -123,67 +153,45 @@ static void serial_config(dev_link_t * link);
======================================================================*/
-static void serial_remove(dev_link_t *link)
+static void serial_remove(struct pcmcia_device *link)
{
struct serial_info *info = link->priv;
int i;
- link->state &= ~DEV_PRESENT;
-
DEBUG(0, "serial_release(0x%p)\n", link);
/*
* Recheck to see if the device is still configured.
*/
- if (info->link.state & DEV_CONFIG) {
- for (i = 0; i < info->ndev; i++)
- serial8250_unregister_port(info->line[i]);
+ for (i = 0; i < info->ndev; i++)
+ serial8250_unregister_port(info->line[i]);
- info->link.dev = NULL;
+ info->p_dev->dev_node = NULL;
- if (!info->slave) {
- pcmcia_release_configuration(info->link.handle);
- pcmcia_release_io(info->link.handle, &info->link.io);
- pcmcia_release_irq(info->link.handle, &info->link.irq);
- }
-
- info->link.state &= ~DEV_CONFIG;
- }
+ if (!info->slave)
+ pcmcia_disable_device(link);
}
-static int serial_suspend(struct pcmcia_device *dev)
+static int serial_suspend(struct pcmcia_device *link)
{
- dev_link_t *link = dev_to_instance(dev);
- link->state |= DEV_SUSPEND;
-
- if (link->state & DEV_CONFIG) {
- struct serial_info *info = link->priv;
- int i;
-
- for (i = 0; i < info->ndev; i++)
- serial8250_suspend_port(info->line[i]);
+ struct serial_info *info = link->priv;
+ int i;
- if (!info->slave)
- pcmcia_release_configuration(link->handle);
- }
+ for (i = 0; i < info->ndev; i++)
+ serial8250_suspend_port(info->line[i]);
return 0;
}
-static int serial_resume(struct pcmcia_device *dev)
+static int serial_resume(struct pcmcia_device *link)
{
- dev_link_t *link = dev_to_instance(dev);
- link->state &= ~DEV_SUSPEND;
-
- if (DEV_OK(link)) {
+ if (pcmcia_dev_present(link)) {
struct serial_info *info = link->priv;
int i;
- if (!info->slave)
- pcmcia_request_configuration(link->handle, &link->conf);
-
for (i = 0; i < info->ndev; i++)
serial8250_resume_port(info->line[i]);
+ wakeup_card(info);
}
return 0;
@@ -197,10 +205,9 @@ static int serial_resume(struct pcmcia_device *dev)
======================================================================*/
-static int serial_probe(struct pcmcia_device *p_dev)
+static int serial_probe(struct pcmcia_device *link)
{
struct serial_info *info;
- dev_link_t *link;
DEBUG(0, "serial_attach()\n");
@@ -209,7 +216,7 @@ static int serial_probe(struct pcmcia_device *p_dev)
if (!info)
return -ENOMEM;
memset(info, 0, sizeof (*info));
- link = &info->link;
+ info->p_dev = link;
link->priv = info;
link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
@@ -223,12 +230,7 @@ static int serial_probe(struct pcmcia_device *p_dev)
}
link->conf.IntType = INT_MEMORY_AND_IO;
- link->handle = p_dev;
- p_dev->instance = link;
- link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
- serial_config(link);
-
- return 0;
+ return serial_config(link);
}
/*======================================================================
@@ -240,9 +242,8 @@ static int serial_probe(struct pcmcia_device *p_dev)
======================================================================*/
-static void serial_detach(struct pcmcia_device *p_dev)
+static void serial_detach(struct pcmcia_device *link)
{
- dev_link_t *link = dev_to_instance(p_dev);
struct serial_info *info = link->priv;
DEBUG(0, "serial_detach(0x%p)\n", link);
@@ -263,7 +264,7 @@ static void serial_detach(struct pcmcia_device *p_dev)
/*====================================================================*/
-static int setup_serial(client_handle_t handle, struct serial_info * info,
+static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
kio_addr_t iobase, int irq)
{
struct uart_port port;
@@ -298,7 +299,7 @@ static int setup_serial(client_handle_t handle, struct serial_info * info,
/*====================================================================*/
static int
-first_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse)
+first_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse)
{
int i;
i = pcmcia_get_first_tuple(handle, tuple);
@@ -311,7 +312,7 @@ first_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse)
}
static int
-next_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse)
+next_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse)
{
int i;
i = pcmcia_get_next_tuple(handle, tuple);
@@ -325,11 +326,10 @@ next_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse)
/*====================================================================*/
-static int simple_config(dev_link_t *link)
+static int simple_config(struct pcmcia_device *link)
{
static const kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
static const int size_table[2] = { 8, 16 };
- client_handle_t handle = link->handle;
struct serial_info *info = link->priv;
struct serial_cfg_mem *cfg_mem;
tuple_t *tuple;
@@ -350,7 +350,7 @@ static int simple_config(dev_link_t *link)
buf = cfg_mem->buf;
/* If the card is already configured, look up the port and irq */
- i = pcmcia_get_configuration_info(handle, &config);
+ i = pcmcia_get_configuration_info(link, &config);
if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) {
kio_addr_t port = 0;
if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) {
@@ -363,10 +363,9 @@ static int simple_config(dev_link_t *link)
}
if (info->slave) {
kfree(cfg_mem);
- return setup_serial(handle, info, port, config.AssignedIRQ);
+ return setup_serial(link, info, port, config.AssignedIRQ);
}
}
- link->conf.Vcc = config.Vcc;
/* First pass: look for a config entry that looks normal. */
tuple->TupleData = (cisdata_t *) buf;
@@ -377,12 +376,12 @@ static int simple_config(dev_link_t *link)
/* Two tries: without IO aliases, then with aliases */
for (s = 0; s < 2; s++) {
for (try = 0; try < 2; try++) {
- i = first_tuple(handle, tuple, parse);
+ 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.Vpp1 = link->conf.Vpp2 =
+ 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)) {
@@ -390,19 +389,19 @@ static int simple_config(dev_link_t *link)
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->handle, &link->io);
+ i = pcmcia_request_io(link, &link->io);
if (i == CS_SUCCESS)
goto found_port;
}
next_entry:
- i = next_tuple(handle, tuple, parse);
+ i = next_tuple(link, tuple, parse);
}
}
}
/* 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(handle, tuple, parse);
+ 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)) {
@@ -410,50 +409,48 @@ next_entry:
for (j = 0; j < 5; j++) {
link->io.BasePort1 = base[j];
link->io.IOAddrLines = base[j] ? 16 : 3;
- i = pcmcia_request_io(link->handle, &link->io);
+ i = pcmcia_request_io(link, &link->io);
if (i == CS_SUCCESS)
goto found_port;
}
}
- i = next_tuple(handle, tuple, parse);
+ i = next_tuple(link, tuple, parse);
}
found_port:
if (i != CS_SUCCESS) {
printk(KERN_NOTICE
"serial_cs: no usable port range found, giving up\n");
- cs_error(link->handle, RequestIO, i);
+ cs_error(link, RequestIO, i);
kfree(cfg_mem);
return -1;
}
- i = pcmcia_request_irq(link->handle, &link->irq);
+ i = pcmcia_request_irq(link, &link->irq);
if (i != CS_SUCCESS) {
- cs_error(link->handle, RequestIRQ, i);
+ cs_error(link, RequestIRQ, i);
link->irq.AssignedIRQ = 0;
}
if (info->multi && (info->manfid == MANFID_3COM))
link->conf.ConfigIndex &= ~(0x08);
- i = pcmcia_request_configuration(link->handle, &link->conf);
+ i = pcmcia_request_configuration(link, &link->conf);
if (i != CS_SUCCESS) {
- cs_error(link->handle, RequestConfiguration, i);
+ cs_error(link, RequestConfiguration, i);
kfree(cfg_mem);
return -1;
}
kfree(cfg_mem);
- return setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
+ return setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ);
}
-static int multi_config(dev_link_t * link)
+static int multi_config(struct pcmcia_device * link)
{
- client_handle_t handle = link->handle;
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, rc, base2 = 0;
cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL);
@@ -464,14 +461,6 @@ static int multi_config(dev_link_t * link)
cf = &parse->cftable_entry;
buf = cfg_mem->buf;
- i = pcmcia_get_configuration_info(handle, &config);
- if (i != CS_SUCCESS) {
- cs_error(handle, GetConfigurationInfo, i);
- rc = -1;
- goto free_cfg_mem;
- }
- link->conf.Vcc = config.Vcc;
-
tuple->TupleData = (cisdata_t *) buf;
tuple->TupleOffset = 0;
tuple->TupleDataMax = 255;
@@ -480,7 +469,7 @@ static int multi_config(dev_link_t * link)
/* First, look for a generic full-sized window */
link->io.NumPorts1 = info->multi * 8;
- i = first_tuple(handle, tuple, parse);
+ 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 */
@@ -490,19 +479,19 @@ static int multi_config(dev_link_t * link)
link->io.BasePort1 = cf->io.win[0].base;
link->io.IOAddrLines =
cf->io.flags & CISTPL_IO_LINES_MASK;
- i = pcmcia_request_io(link->handle, &link->io);
+ i = pcmcia_request_io(link, &link->io);
base2 = link->io.BasePort1 + 8;
if (i == CS_SUCCESS)
break;
}
- i = next_tuple(handle, tuple, parse);
+ i = next_tuple(link, tuple, parse);
}
/* If that didn't work, look for two windows */
if (i != CS_SUCCESS) {
link->io.NumPorts1 = link->io.NumPorts2 = 8;
info->multi = 2;
- i = first_tuple(handle, tuple, parse);
+ 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;
@@ -510,26 +499,26 @@ static int multi_config(dev_link_t * link)
link->io.BasePort2 = cf->io.win[1].base;
link->io.IOAddrLines =
cf->io.flags & CISTPL_IO_LINES_MASK;
- i = pcmcia_request_io(link->handle, &link->io);
+ i = pcmcia_request_io(link, &link->io);
base2 = link->io.BasePort2;
if (i == CS_SUCCESS)
break;
}
- i = next_tuple(handle, tuple, parse);
+ i = next_tuple(link, tuple, parse);
}
}
if (i != CS_SUCCESS) {
- cs_error(link->handle, RequestIO, i);
+ cs_error(link, RequestIO, i);
rc = -1;
goto free_cfg_mem;
}
- i = pcmcia_request_irq(link->handle, &link->irq);
+ i = pcmcia_request_irq(link, &link->irq);
if (i != CS_SUCCESS) {
printk(KERN_NOTICE
"serial_cs: no usable port range found, giving up\n");
- cs_error(link->handle, RequestIRQ, i);
+ cs_error(link, RequestIRQ, i);
link->irq.AssignedIRQ = 0;
}
/* Socket Dual IO: this enables irq's for second port */
@@ -537,35 +526,43 @@ static int multi_config(dev_link_t * link)
link->conf.Present |= PRESENT_EXT_STATUS;
link->conf.ExtStatus = ESR_REQ_ATTN_ENA;
}
- i = pcmcia_request_configuration(link->handle, &link->conf);
+ i = pcmcia_request_configuration(link, &link->conf);
if (i != CS_SUCCESS) {
- cs_error(link->handle, RequestConfiguration, i);
+ cs_error(link, RequestConfiguration, i);
rc = -1;
goto free_cfg_mem;
}
/* The Oxford Semiconductor OXCF950 cards are in fact single-port:
- 8 registers are for the UART, the others are extra registers */
- if (info->manfid == MANFID_OXSEMI) {
+ * 8 registers are for the UART, the others are extra registers.
+ * Siemen's MC45 PCMCIA (Possio's GCC) is OXCF950 based too.
+ */
+ if (info->manfid == MANFID_OXSEMI || (info->manfid == MANFID_POSSIO &&
+ info->prodid == PRODID_POSSIO_GCC)) {
+ int err;
+
if (cf->index == 1 || cf->index == 3) {
- setup_serial(handle, info, base2, link->irq.AssignedIRQ);
- outb(12, link->io.BasePort1 + 1);
+ err = setup_serial(link, info, base2,
+ link->irq.AssignedIRQ);
+ base2 = link->io.BasePort1;
} else {
- setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
- outb(12, base2 + 1);
+ err = setup_serial(link, info, link->io.BasePort1,
+ link->irq.AssignedIRQ);
}
+ info->c950ctrl = base2;
+ wakeup_card(info);
rc = 0;
goto free_cfg_mem;
}
- setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ);
+ setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ);
/* The Nokia cards are not really multiport cards */
if (info->manfid == MANFID_NOKIA) {
rc = 0;
goto free_cfg_mem;
}
for (i = 0; i < info->multi - 1; i++)
- setup_serial(handle, info, base2 + (8 * i),
+ setup_serial(link, info, base2 + (8 * i),
link->irq.AssignedIRQ);
rc = 0;
free_cfg_mem:
@@ -581,9 +578,8 @@ free_cfg_mem:
======================================================================*/
-void serial_config(dev_link_t * link)
+static int serial_config(struct pcmcia_device * link)
{
- client_handle_t handle = link->handle;
struct serial_info *info = link->priv;
struct serial_cfg_mem *cfg_mem;
tuple_t *tuple;
@@ -609,7 +605,7 @@ void serial_config(dev_link_t * link)
tuple->Attributes = 0;
/* Get configuration register information */
tuple->DesiredTuple = CISTPL_CONFIG;
- last_ret = first_tuple(handle, tuple, parse);
+ last_ret = first_tuple(link, tuple, parse);
if (last_ret != CS_SUCCESS) {
last_fn = ParseTuple;
goto cs_failed;
@@ -617,18 +613,16 @@ void serial_config(dev_link_t * link)
link->conf.ConfigBase = parse->config.base;
link->conf.Present = parse->config.rmask[0];
- /* Configure card */
- link->state |= DEV_CONFIG;
-
/* Is this a compliant multifunction card? */
tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
- info->multi = (first_tuple(handle, tuple, parse) == CS_SUCCESS);
+ info->multi = (first_tuple(link, tuple, parse) == CS_SUCCESS);
/* Is this a multiport card? */
tuple->DesiredTuple = CISTPL_MANFID;
- if (first_tuple(handle, tuple, parse) == CS_SUCCESS) {
+ if (first_tuple(link, tuple, parse) == CS_SUCCESS) {
info->manfid = parse->manfid.manf;
+ info->prodid = le16_to_cpu(buf[1]);
for (i = 0; i < MULTI_COUNT; i++)
if ((info->manfid == multi_id[i].manfid) &&
(parse->manfid.card == multi_id[i].prodid))
@@ -641,11 +635,11 @@ void serial_config(dev_link_t * link)
multifunction cards that ask for appropriate IO port ranges */
tuple->DesiredTuple = CISTPL_FUNCID;
if ((info->multi == 0) &&
- ((first_tuple(handle, tuple, parse) != CS_SUCCESS) ||
+ ((first_tuple(link, tuple, parse) != CS_SUCCESS) ||
(parse->funcid.func == CISTPL_FUNCID_MULTI) ||
(parse->funcid.func == CISTPL_FUNCID_SERIAL))) {
tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
- if (first_tuple(handle, tuple, parse) == CS_SUCCESS) {
+ if (first_tuple(link, tuple, parse) == CS_SUCCESS) {
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) &&
@@ -664,31 +658,30 @@ void serial_config(dev_link_t * link)
if (info->manfid == MANFID_IBM) {
conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
- last_ret = pcmcia_access_configuration_register(link->handle, &reg);
+ last_ret = pcmcia_access_configuration_register(link, &reg);
if (last_ret) {
last_fn = AccessConfigurationRegister;
goto cs_failed;
}
reg.Action = CS_WRITE;
reg.Value = reg.Value | 1;
- last_ret = pcmcia_access_configuration_register(link->handle, &reg);
+ last_ret = pcmcia_access_configuration_register(link, &reg);
if (last_ret) {
last_fn = AccessConfigurationRegister;
goto cs_failed;
}
}
- link->dev = &info->node[0];
- link->state &= ~DEV_CONFIG_PENDING;
+ link->dev_node = &info->node[0];
kfree(cfg_mem);
- return;
+ return 0;
cs_failed:
- cs_error(link->handle, last_fn, last_ret);
+ cs_error(link, last_fn, last_ret);
failed:
serial_remove(link);
- link->state &= ~DEV_CONFIG_PENDING;
kfree(cfg_mem);
+ return -ENODEV;
}
static struct pcmcia_device_id serial_ids[] = {
@@ -739,6 +732,7 @@ static struct pcmcia_device_id serial_ids[] = {
PCMCIA_MFC_DEVICE_PROD_ID1(1, "Motorola MARQUIS", 0xf03e4e77),
PCMCIA_MFC_DEVICE_PROD_ID2(1, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302),
PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0301),
+ PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x0276),
PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039),
PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006),
PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a),
@@ -757,6 +751,7 @@ static struct pcmcia_device_id serial_ids[] = {
PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef),
PCMCIA_DEVICE_PROD_ID124("TOSHIBA", "T144PF", "PCMCIA MODEM", 0xb4585a1a, 0x7271409c, 0xbd6c43ef),
PCMCIA_DEVICE_PROD_ID123("FUJITSU", "FC14F ", "MBH10213", 0x6ee5a3d8, 0x30ead12b, 0xb00f05a0),
+ PCMCIA_DEVICE_PROD_ID123("Novatel Wireless", "Merlin UMTS Modem", "U630", 0x32607776, 0xd9e73b13, 0xe87332e),
PCMCIA_DEVICE_PROD_ID13("MEGAHERTZ", "V.34 PCMCIA MODEM", 0xf510db04, 0xbb2cce4a),
PCMCIA_DEVICE_PROD_ID12("Brain Boxes", "Bluetooth PC Card", 0xee138382, 0xd4ce9b02),
PCMCIA_DEVICE_PROD_ID12("CIRRUS LOGIC", "FAX MODEM", 0xe625f451, 0xcecd6dfa),
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 1c4396c2962..2b4f96541b8 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1730,3 +1730,4 @@ static void __exit sunsu_exit(void)
module_init(sunsu_probe);
module_exit(sunsu_exit);
+MODULE_LICENSE("GPL");