提交 49c35561 编写于 作者: L Linus Torvalds

Merge branch 'serial-from-alan'

* serial-from-alan: (79 commits)
  moxa: prevent opening unavailable ports
  imx: serial: use tty_encode_baud_rate to set true rate
  imx: serial: add IrDA support to serial driver
  imx: serial: use rational library function
  lib: isolate rational fractions helper function
  imx: serial: handle initialisation failure correctly
  imx: serial: be sure to stop xmit upon shutdown
  imx: serial: notify higher layers in case xmit IRQ was not called
  imx: serial: fix one bit field type
  imx: serial: fix whitespaces (no changes in functionality)
  tty: use prepare/finish_wait
  tty: remove sleep_on
  sierra: driver interface blacklisting
  sierra: driver urb handling improvements
  tty: resolve some sierra breakage
  timbuart: Fix the termios logic
  serial: Added Timberdale UART driver
  tty: Add URL for ttydev queue
  devpts: unregister the file system on error
  tty: Untangle termios and mm mutex dependencies
  ...
...@@ -71,7 +71,7 @@ P: Person ...@@ -71,7 +71,7 @@ P: Person
M: Mail patches to M: Mail patches to
L: Mailing list that is relevant to this area L: Mailing list that is relevant to this area
W: Web-page with status/info W: Web-page with status/info
T: SCM tree type and location. Type is one of: git, hg, quilt. T: SCM tree type and location. Type is one of: git, hg, quilt, stgit.
S: Status, one of the following: S: Status, one of the following:
Supported: Someone is actually paid to look after this. Supported: Someone is actually paid to look after this.
...@@ -159,7 +159,8 @@ F: drivers/net/r8169.c ...@@ -159,7 +159,8 @@ F: drivers/net/r8169.c
8250/16?50 (AND CLONE UARTS) SERIAL DRIVER 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
L: linux-serial@vger.kernel.org L: linux-serial@vger.kernel.org
W: http://serial.sourceforge.net W: http://serial.sourceforge.net
S: Orphan M: alan@lxorguk.ukuu.org.uk
S: Odd Fixes
F: drivers/serial/8250* F: drivers/serial/8250*
F: include/linux/serial_8250.h F: include/linux/serial_8250.h
...@@ -5629,6 +5630,7 @@ P: Alan Cox ...@@ -5629,6 +5630,7 @@ P: Alan Cox
M: alan@lxorguk.ukuu.org.uk M: alan@lxorguk.ukuu.org.uk
L: linux-kernel@vger.kernel.org L: linux-kernel@vger.kernel.org
S: Maintained S: Maintained
T: stgit http://zeniv.linux.org.uk/~alan/ttydev/
TULIP NETWORK DRIVERS TULIP NETWORK DRIVERS
P: Grant Grundler P: Grant Grundler
......
...@@ -20,11 +20,16 @@ ...@@ -20,11 +20,16 @@
#define ASMARM_ARCH_UART_H #define ASMARM_ARCH_UART_H
#define IMXUART_HAVE_RTSCTS (1<<0) #define IMXUART_HAVE_RTSCTS (1<<0)
#define IMXUART_IRDA (1<<1)
struct imxuart_platform_data { struct imxuart_platform_data {
int (*init)(struct platform_device *pdev); int (*init)(struct platform_device *pdev);
int (*exit)(struct platform_device *pdev); int (*exit)(struct platform_device *pdev);
unsigned int flags; unsigned int flags;
void (*irda_enable)(int enable);
unsigned int irda_inv_rx:1;
unsigned int irda_inv_tx:1;
unsigned short transceiver_delay;
}; };
#endif #endif
...@@ -67,6 +67,7 @@ static inline int user_termio_to_kernel_termios(struct ktermios *termios, ...@@ -67,6 +67,7 @@ static inline int user_termio_to_kernel_termios(struct ktermios *termios,
SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); SET_LOW_TERMIOS_BITS(termios, termio, c_oflag);
SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); SET_LOW_TERMIOS_BITS(termios, termio, c_cflag);
SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); SET_LOW_TERMIOS_BITS(termios, termio, c_lflag);
get_user(termios->c_line, &termio->c_line);
return copy_from_user(termios->c_cc, termio->c_cc, NCC); return copy_from_user(termios->c_cc, termio->c_cc, NCC);
} }
......
...@@ -277,8 +277,8 @@ static int hci_uart_tty_open(struct tty_struct *tty) ...@@ -277,8 +277,8 @@ static int hci_uart_tty_open(struct tty_struct *tty)
/* FIXME: why is this needed. Note don't use ldisc_ref here as the /* FIXME: why is this needed. Note don't use ldisc_ref here as the
open path is before the ldisc is referencable */ open path is before the ldisc is referencable */
if (tty->ldisc.ops->flush_buffer) if (tty->ldisc->ops->flush_buffer)
tty->ldisc.ops->flush_buffer(tty); tty->ldisc->ops->flush_buffer(tty);
tty_driver_flush_buffer(tty); tty_driver_flush_buffer(tty);
return 0; return 0;
...@@ -463,7 +463,6 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, ...@@ -463,7 +463,6 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
clear_bit(HCI_UART_PROTO_SET, &hu->flags); clear_bit(HCI_UART_PROTO_SET, &hu->flags);
return err; return err;
} }
tty->low_latency = 1;
} else } else
return -EBUSY; return -EBUSY;
break; break;
......
...@@ -97,6 +97,19 @@ config DEVKMEM ...@@ -97,6 +97,19 @@ config DEVKMEM
kind of kernel debugging operations. kind of kernel debugging operations.
When in doubt, say "N". When in doubt, say "N".
config BFIN_JTAG_COMM
tristate "Blackfin JTAG Communication"
depends on BLACKFIN
help
Add support for emulating a TTY device over the Blackfin JTAG.
To compile this driver as a module, choose M here: the
module will be called bfin_jtag_comm.
config BFIN_JTAG_COMM_CONSOLE
bool "Console on Blackfin JTAG"
depends on BFIN_JTAG_COMM=y
config SERIAL_NONSTANDARD config SERIAL_NONSTANDARD
bool "Non-standard serial port support" bool "Non-standard serial port support"
depends on HAS_IOMEM depends on HAS_IOMEM
......
...@@ -13,6 +13,7 @@ obj-$(CONFIG_LEGACY_PTYS) += pty.o ...@@ -13,6 +13,7 @@ obj-$(CONFIG_LEGACY_PTYS) += pty.o
obj-$(CONFIG_UNIX98_PTYS) += pty.o obj-$(CONFIG_UNIX98_PTYS) += pty.o
obj-y += misc.o obj-y += misc.o
obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o selection.o keyboard.o obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o selection.o keyboard.o
obj-$(CONFIG_BFIN_JTAG_COMM) += bfin_jtag_comm.o
obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o
obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o
obj-$(CONFIG_AUDIT) += tty_audit.o obj-$(CONFIG_AUDIT) += tty_audit.o
......
/*
* TTY over Blackfin JTAG Communication
*
* Copyright 2008-2009 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Licensed under the GPL-2 or later.
*/
#include <linux/circ_buf.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <asm/atomic.h>
/* See the Debug/Emulation chapter in the HRM */
#define EMUDOF 0x00000001 /* EMUDAT_OUT full & valid */
#define EMUDIF 0x00000002 /* EMUDAT_IN full & valid */
#define EMUDOOVF 0x00000004 /* EMUDAT_OUT overflow */
#define EMUDIOVF 0x00000008 /* EMUDAT_IN overflow */
#define DRV_NAME "bfin-jtag-comm"
#define DEV_NAME "ttyBFJC"
#define pr_init(fmt, args...) ({ static const __initdata char __fmt[] = fmt; printk(__fmt, ## args); })
#define debug(fmt, args...) pr_debug(DRV_NAME ": " fmt, ## args)
static inline uint32_t bfin_write_emudat(uint32_t emudat)
{
__asm__ __volatile__("emudat = %0;" : : "d"(emudat));
return emudat;
}
static inline uint32_t bfin_read_emudat(void)
{
uint32_t emudat;
__asm__ __volatile__("%0 = emudat;" : "=d"(emudat));
return emudat;
}
static inline uint32_t bfin_write_emudat_chars(char a, char b, char c, char d)
{
return bfin_write_emudat((a << 0) | (b << 8) | (c << 16) | (d << 24));
}
#define CIRC_SIZE 2048 /* see comment in tty_io.c:do_tty_write() */
#define CIRC_MASK (CIRC_SIZE - 1)
#define circ_empty(circ) ((circ)->head == (circ)->tail)
#define circ_free(circ) CIRC_SPACE((circ)->head, (circ)->tail, CIRC_SIZE)
#define circ_cnt(circ) CIRC_CNT((circ)->head, (circ)->tail, CIRC_SIZE)
#define circ_byte(circ, idx) ((circ)->buf[(idx) & CIRC_MASK])
static struct tty_driver *bfin_jc_driver;
static struct task_struct *bfin_jc_kthread;
static struct tty_struct * volatile bfin_jc_tty;
static unsigned long bfin_jc_count;
static DEFINE_MUTEX(bfin_jc_tty_mutex);
static volatile struct circ_buf bfin_jc_write_buf;
static int
bfin_jc_emudat_manager(void *arg)
{
uint32_t inbound_len = 0, outbound_len = 0;
while (!kthread_should_stop()) {
/* no one left to give data to, so sleep */
if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) {
debug("waiting for readers\n");
__set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
__set_current_state(TASK_RUNNING);
}
/* no data available, so just chill */
if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) {
debug("waiting for data (in_len = %i) (circ: %i %i)\n",
inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head);
if (inbound_len)
schedule();
else
schedule_timeout_interruptible(HZ);
continue;
}
/* if incoming data is ready, eat it */
if (bfin_read_DBGSTAT() & EMUDIF) {
struct tty_struct *tty;
mutex_lock(&bfin_jc_tty_mutex);
tty = (struct tty_struct *)bfin_jc_tty;
if (tty != NULL) {
uint32_t emudat = bfin_read_emudat();
if (inbound_len == 0) {
debug("incoming length: 0x%08x\n", emudat);
inbound_len = emudat;
} else {
size_t num_chars = (4 <= inbound_len ? 4 : inbound_len);
debug(" incoming data: 0x%08x (pushing %zu)\n", emudat, num_chars);
inbound_len -= num_chars;
tty_insert_flip_string(tty, (unsigned char *)&emudat, num_chars);
tty_flip_buffer_push(tty);
}
}
mutex_unlock(&bfin_jc_tty_mutex);
}
/* if outgoing data is ready, post it */
if (!(bfin_read_DBGSTAT() & EMUDOF) && !circ_empty(&bfin_jc_write_buf)) {
if (outbound_len == 0) {
outbound_len = circ_cnt(&bfin_jc_write_buf);
bfin_write_emudat(outbound_len);
debug("outgoing length: 0x%08x\n", outbound_len);
} else {
struct tty_struct *tty;
int tail = bfin_jc_write_buf.tail;
size_t ate = (4 <= outbound_len ? 4 : outbound_len);
uint32_t emudat =
bfin_write_emudat_chars(
circ_byte(&bfin_jc_write_buf, tail + 0),
circ_byte(&bfin_jc_write_buf, tail + 1),
circ_byte(&bfin_jc_write_buf, tail + 2),
circ_byte(&bfin_jc_write_buf, tail + 3)
);
bfin_jc_write_buf.tail += ate;
outbound_len -= ate;
mutex_lock(&bfin_jc_tty_mutex);
tty = (struct tty_struct *)bfin_jc_tty;
if (tty)
tty_wakeup(tty);
mutex_unlock(&bfin_jc_tty_mutex);
debug(" outgoing data: 0x%08x (pushing %zu)\n", emudat, ate);
}
}
}
__set_current_state(TASK_RUNNING);
return 0;
}
static int
bfin_jc_open(struct tty_struct *tty, struct file *filp)
{
mutex_lock(&bfin_jc_tty_mutex);
debug("open %lu\n", bfin_jc_count);
++bfin_jc_count;
bfin_jc_tty = tty;
wake_up_process(bfin_jc_kthread);
mutex_unlock(&bfin_jc_tty_mutex);
return 0;
}
static void
bfin_jc_close(struct tty_struct *tty, struct file *filp)
{
mutex_lock(&bfin_jc_tty_mutex);
debug("close %lu\n", bfin_jc_count);
if (--bfin_jc_count == 0)
bfin_jc_tty = NULL;
wake_up_process(bfin_jc_kthread);
mutex_unlock(&bfin_jc_tty_mutex);
}
/* XXX: we dont handle the put_char() case where we must handle count = 1 */
static int
bfin_jc_circ_write(const unsigned char *buf, int count)
{
int i;
count = min(count, circ_free(&bfin_jc_write_buf));
debug("going to write chunk of %i bytes\n", count);
for (i = 0; i < count; ++i)
circ_byte(&bfin_jc_write_buf, bfin_jc_write_buf.head + i) = buf[i];
bfin_jc_write_buf.head += i;
return i;
}
#ifndef CONFIG_BFIN_JTAG_COMM_CONSOLE
# define acquire_console_sem()
# define release_console_sem()
#endif
static int
bfin_jc_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
int i;
acquire_console_sem();
i = bfin_jc_circ_write(buf, count);
release_console_sem();
wake_up_process(bfin_jc_kthread);
return i;
}
static void
bfin_jc_flush_chars(struct tty_struct *tty)
{
wake_up_process(bfin_jc_kthread);
}
static int
bfin_jc_write_room(struct tty_struct *tty)
{
return circ_free(&bfin_jc_write_buf);
}
static int
bfin_jc_chars_in_buffer(struct tty_struct *tty)
{
return circ_cnt(&bfin_jc_write_buf);
}
static void
bfin_jc_wait_until_sent(struct tty_struct *tty, int timeout)
{
unsigned long expire = jiffies + timeout;
while (!circ_empty(&bfin_jc_write_buf)) {
if (signal_pending(current))
break;
if (time_after(jiffies, expire))
break;
}
}
static struct tty_operations bfin_jc_ops = {
.open = bfin_jc_open,
.close = bfin_jc_close,
.write = bfin_jc_write,
/*.put_char = bfin_jc_put_char,*/
.flush_chars = bfin_jc_flush_chars,
.write_room = bfin_jc_write_room,
.chars_in_buffer = bfin_jc_chars_in_buffer,
.wait_until_sent = bfin_jc_wait_until_sent,
};
static int __init bfin_jc_init(void)
{
int ret;
bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME);
if (IS_ERR(bfin_jc_kthread))
return PTR_ERR(bfin_jc_kthread);
ret = -ENOMEM;
bfin_jc_write_buf.head = bfin_jc_write_buf.tail = 0;
bfin_jc_write_buf.buf = kmalloc(CIRC_SIZE, GFP_KERNEL);
if (!bfin_jc_write_buf.buf)
goto err;
bfin_jc_driver = alloc_tty_driver(1);
if (!bfin_jc_driver)
goto err;
bfin_jc_driver->owner = THIS_MODULE;
bfin_jc_driver->driver_name = DRV_NAME;
bfin_jc_driver->name = DEV_NAME;
bfin_jc_driver->type = TTY_DRIVER_TYPE_SERIAL;
bfin_jc_driver->subtype = SERIAL_TYPE_NORMAL;
bfin_jc_driver->init_termios = tty_std_termios;
tty_set_operations(bfin_jc_driver, &bfin_jc_ops);
ret = tty_register_driver(bfin_jc_driver);
if (ret)
goto err;
pr_init(KERN_INFO DRV_NAME ": initialized\n");
return 0;
err:
put_tty_driver(bfin_jc_driver);
kfree(bfin_jc_write_buf.buf);
kthread_stop(bfin_jc_kthread);
return ret;
}
module_init(bfin_jc_init);
static void __exit bfin_jc_exit(void)
{
kthread_stop(bfin_jc_kthread);
kfree(bfin_jc_write_buf.buf);
tty_unregister_driver(bfin_jc_driver);
put_tty_driver(bfin_jc_driver);
}
module_exit(bfin_jc_exit);
#if defined(CONFIG_BFIN_JTAG_COMM_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
static void
bfin_jc_straight_buffer_write(const char *buf, unsigned count)
{
unsigned ate = 0;
while (bfin_read_DBGSTAT() & EMUDOF)
continue;
bfin_write_emudat(count);
while (ate < count) {
while (bfin_read_DBGSTAT() & EMUDOF)
continue;
bfin_write_emudat_chars(buf[ate], buf[ate+1], buf[ate+2], buf[ate+3]);
ate += 4;
}
}
#endif
#ifdef CONFIG_BFIN_JTAG_COMM_CONSOLE
static void
bfin_jc_console_write(struct console *co, const char *buf, unsigned count)
{
if (bfin_jc_kthread == NULL)
bfin_jc_straight_buffer_write(buf, count);
else
bfin_jc_circ_write(buf, count);
}
static struct tty_driver *
bfin_jc_console_device(struct console *co, int *index)
{
*index = co->index;
return bfin_jc_driver;
}
static struct console bfin_jc_console = {
.name = DEV_NAME,
.write = bfin_jc_console_write,
.device = bfin_jc_console_device,
.flags = CON_ANYTIME | CON_PRINTBUFFER,
.index = -1,
};
static int __init bfin_jc_console_init(void)
{
register_console(&bfin_jc_console);
return 0;
}
console_initcall(bfin_jc_console_init);
#endif
#ifdef CONFIG_EARLY_PRINTK
static void __init
bfin_jc_early_write(struct console *co, const char *buf, unsigned int count)
{
bfin_jc_straight_buffer_write(buf, count);
}
static struct __initdata console bfin_jc_early_console = {
.name = "early_BFJC",
.write = bfin_jc_early_write,
.flags = CON_ANYTIME | CON_PRINTBUFFER,
.index = -1,
};
struct console * __init
bfin_jc_early_init(unsigned int port, unsigned int cflag)
{
return &bfin_jc_early_console;
}
#endif
MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
MODULE_DESCRIPTION("TTY over Blackfin JTAG Communication");
MODULE_LICENSE("GPL");
此差异已折叠。
...@@ -745,7 +745,7 @@ static int epca_carrier_raised(struct tty_port *port) ...@@ -745,7 +745,7 @@ static int epca_carrier_raised(struct tty_port *port)
return 0; return 0;
} }
static void epca_raise_dtr_rts(struct tty_port *port) static void epca_dtr_rts(struct tty_port *port, int onoff)
{ {
} }
...@@ -925,7 +925,7 @@ static const struct tty_operations pc_ops = { ...@@ -925,7 +925,7 @@ static const struct tty_operations pc_ops = {
static const struct tty_port_operations epca_port_ops = { static const struct tty_port_operations epca_port_ops = {
.carrier_raised = epca_carrier_raised, .carrier_raised = epca_carrier_raised,
.raise_dtr_rts = epca_raise_dtr_rts, .dtr_rts = epca_dtr_rts,
}; };
static int info_open(struct tty_struct *tty, struct file *filp) static int info_open(struct tty_struct *tty, struct file *filp)
...@@ -1518,7 +1518,7 @@ static void doevent(int crd) ...@@ -1518,7 +1518,7 @@ static void doevent(int crd)
if (event & MODEMCHG_IND) { if (event & MODEMCHG_IND) {
/* A modem signal change has been indicated */ /* A modem signal change has been indicated */
ch->imodem = mstat; ch->imodem = mstat;
if (test_bit(ASYNC_CHECK_CD, &ch->port.flags)) { if (test_bit(ASYNCB_CHECK_CD, &ch->port.flags)) {
/* We are now receiving dcd */ /* We are now receiving dcd */
if (mstat & ch->dcd) if (mstat & ch->dcd)
wake_up_interruptible(&ch->port.open_wait); wake_up_interruptible(&ch->port.open_wait);
...@@ -1765,9 +1765,9 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) ...@@ -1765,9 +1765,9 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
* that the driver will wait on carrier detect. * that the driver will wait on carrier detect.
*/ */
if (ts->c_cflag & CLOCAL) if (ts->c_cflag & CLOCAL)
clear_bit(ASYNC_CHECK_CD, &ch->port.flags); clear_bit(ASYNCB_CHECK_CD, &ch->port.flags);
else else
set_bit(ASYNC_CHECK_CD, &ch->port.flags); set_bit(ASYNCB_CHECK_CD, &ch->port.flags);
mval = ch->m_dtr | ch->m_rts; mval = ch->m_dtr | ch->m_rts;
} /* End CBAUD not detected */ } /* End CBAUD not detected */
iflag = termios2digi_i(ch, ts->c_iflag); iflag = termios2digi_i(ch, ts->c_iflag);
...@@ -2114,8 +2114,8 @@ static int pc_ioctl(struct tty_struct *tty, struct file *file, ...@@ -2114,8 +2114,8 @@ static int pc_ioctl(struct tty_struct *tty, struct file *file,
tty_wait_until_sent(tty, 0); tty_wait_until_sent(tty, 0);
} else { } else {
/* ldisc lock already held in ioctl */ /* ldisc lock already held in ioctl */
if (tty->ldisc.ops->flush_buffer) if (tty->ldisc->ops->flush_buffer)
tty->ldisc.ops->flush_buffer(tty); tty->ldisc->ops->flush_buffer(tty);
} }
unlock_kernel(); unlock_kernel();
/* Fall Thru */ /* Fall Thru */
...@@ -2244,7 +2244,8 @@ static void do_softint(struct work_struct *work) ...@@ -2244,7 +2244,8 @@ static void do_softint(struct work_struct *work)
if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) { if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
tty_hangup(tty); tty_hangup(tty);
wake_up_interruptible(&ch->port.open_wait); wake_up_interruptible(&ch->port.open_wait);
clear_bit(ASYNC_NORMAL_ACTIVE, &ch->port.flags); clear_bit(ASYNCB_NORMAL_ACTIVE,
&ch->port.flags);
} }
} }
tty_kref_put(tty); tty_kref_put(tty);
......
...@@ -868,11 +868,11 @@ i2Input(i2ChanStrPtr pCh) ...@@ -868,11 +868,11 @@ i2Input(i2ChanStrPtr pCh)
amountToMove = count; amountToMove = count;
} }
// Move the first block // Move the first block
pCh->pTTY->ldisc.ops->receive_buf( pCh->pTTY, pCh->pTTY->ldisc->ops->receive_buf( pCh->pTTY,
&(pCh->Ibuf[stripIndex]), NULL, amountToMove ); &(pCh->Ibuf[stripIndex]), NULL, amountToMove );
// If we needed to wrap, do the second data move // If we needed to wrap, do the second data move
if (count > amountToMove) { if (count > amountToMove) {
pCh->pTTY->ldisc.ops->receive_buf( pCh->pTTY, pCh->pTTY->ldisc->ops->receive_buf( pCh->pTTY,
pCh->Ibuf, NULL, count - amountToMove ); pCh->Ibuf, NULL, count - amountToMove );
} }
// Bump and wrap the stripIndex all at once by the amount of data read. This // Bump and wrap the stripIndex all at once by the amount of data read. This
......
...@@ -1315,8 +1315,8 @@ static inline void isig(int sig, struct tty_struct *tty, int flush) ...@@ -1315,8 +1315,8 @@ static inline void isig(int sig, struct tty_struct *tty, int flush)
if (tty->pgrp) if (tty->pgrp)
kill_pgrp(tty->pgrp, sig, 1); kill_pgrp(tty->pgrp, sig, 1);
if (flush || !L_NOFLSH(tty)) { if (flush || !L_NOFLSH(tty)) {
if ( tty->ldisc.ops->flush_buffer ) if ( tty->ldisc->ops->flush_buffer )
tty->ldisc.ops->flush_buffer(tty); tty->ldisc->ops->flush_buffer(tty);
i2InputFlush( tty->driver_data ); i2InputFlush( tty->driver_data );
} }
} }
......
...@@ -329,7 +329,7 @@ static inline void drop_rts(struct isi_port *port) ...@@ -329,7 +329,7 @@ static inline void drop_rts(struct isi_port *port)
/* card->lock MUST NOT be held */ /* card->lock MUST NOT be held */
static void isicom_raise_dtr_rts(struct tty_port *port) static void isicom_dtr_rts(struct tty_port *port, int on)
{ {
struct isi_port *ip = container_of(port, struct isi_port, port); struct isi_port *ip = container_of(port, struct isi_port, port);
struct isi_board *card = ip->card; struct isi_board *card = ip->card;
...@@ -339,10 +339,17 @@ static void isicom_raise_dtr_rts(struct tty_port *port) ...@@ -339,10 +339,17 @@ static void isicom_raise_dtr_rts(struct tty_port *port)
if (!lock_card(card)) if (!lock_card(card))
return; return;
outw(0x8000 | (channel << card->shift_count) | 0x02, base); if (on) {
outw(0x0f04, base); outw(0x8000 | (channel << card->shift_count) | 0x02, base);
InterruptTheCard(base); outw(0x0f04, base);
ip->status |= (ISI_DTR | ISI_RTS); InterruptTheCard(base);
ip->status |= (ISI_DTR | ISI_RTS);
} else {
outw(0x8000 | (channel << card->shift_count) | 0x02, base);
outw(0x0C04, base);
InterruptTheCard(base);
ip->status &= ~(ISI_DTR | ISI_RTS);
}
unlock_card(card); unlock_card(card);
} }
...@@ -1339,7 +1346,7 @@ static const struct tty_operations isicom_ops = { ...@@ -1339,7 +1346,7 @@ static const struct tty_operations isicom_ops = {
static const struct tty_port_operations isicom_port_ops = { static const struct tty_port_operations isicom_port_ops = {
.carrier_raised = isicom_carrier_raised, .carrier_raised = isicom_carrier_raised,
.raise_dtr_rts = isicom_raise_dtr_rts, .dtr_rts = isicom_dtr_rts,
}; };
static int __devinit reset_card(struct pci_dev *pdev, static int __devinit reset_card(struct pci_dev *pdev,
......
...@@ -1140,14 +1140,14 @@ static int stli_carrier_raised(struct tty_port *port) ...@@ -1140,14 +1140,14 @@ static int stli_carrier_raised(struct tty_port *port)
return (portp->sigs & TIOCM_CD) ? 1 : 0; return (portp->sigs & TIOCM_CD) ? 1 : 0;
} }
static void stli_raise_dtr_rts(struct tty_port *port) static void stli_dtr_rts(struct tty_port *port, int on)
{ {
struct stliport *portp = container_of(port, struct stliport, port); struct stliport *portp = container_of(port, struct stliport, port);
struct stlibrd *brdp = stli_brds[portp->brdnr]; struct stlibrd *brdp = stli_brds[portp->brdnr];
stli_mkasysigs(&portp->asig, 1, 1); stli_mkasysigs(&portp->asig, on, on);
if (stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, if (stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,
sizeof(asysigs_t), 0) < 0) sizeof(asysigs_t), 0) < 0)
printk(KERN_WARNING "istallion: dtr raise failed.\n"); printk(KERN_WARNING "istallion: dtr set failed.\n");
} }
...@@ -4417,7 +4417,7 @@ static const struct tty_operations stli_ops = { ...@@ -4417,7 +4417,7 @@ static const struct tty_operations stli_ops = {
static const struct tty_port_operations stli_port_ops = { static const struct tty_port_operations stli_port_ops = {
.carrier_raised = stli_carrier_raised, .carrier_raised = stli_carrier_raised,
.raise_dtr_rts = stli_raise_dtr_rts, .dtr_rts = stli_dtr_rts,
}; };
/*****************************************************************************/ /*****************************************************************************/
......
...@@ -1184,6 +1184,11 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) ...@@ -1184,6 +1184,11 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
return -ENODEV; return -ENODEV;
} }
if (port % MAX_PORTS_PER_BOARD >= brd->numPorts) {
mutex_unlock(&moxa_openlock);
return -ENODEV;
}
ch = &brd->ports[port % MAX_PORTS_PER_BOARD]; ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
ch->port.count++; ch->port.count++;
tty->driver_data = ch; tty->driver_data = ch;
......
...@@ -547,14 +547,18 @@ static int mxser_carrier_raised(struct tty_port *port) ...@@ -547,14 +547,18 @@ static int mxser_carrier_raised(struct tty_port *port)
return (inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD)?1:0; return (inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD)?1:0;
} }
static void mxser_raise_dtr_rts(struct tty_port *port) static void mxser_dtr_rts(struct tty_port *port, int on)
{ {
struct mxser_port *mp = container_of(port, struct mxser_port, port); struct mxser_port *mp = container_of(port, struct mxser_port, port);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&mp->slock, flags); spin_lock_irqsave(&mp->slock, flags);
outb(inb(mp->ioaddr + UART_MCR) | if (on)
UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR); outb(inb(mp->ioaddr + UART_MCR) |
UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR);
else
outb(inb(mp->ioaddr + UART_MCR)&~(UART_MCR_DTR | UART_MCR_RTS),
mp->ioaddr + UART_MCR);
spin_unlock_irqrestore(&mp->slock, flags); spin_unlock_irqrestore(&mp->slock, flags);
} }
...@@ -2356,7 +2360,7 @@ static const struct tty_operations mxser_ops = { ...@@ -2356,7 +2360,7 @@ static const struct tty_operations mxser_ops = {
struct tty_port_operations mxser_port_ops = { struct tty_port_operations mxser_port_ops = {
.carrier_raised = mxser_carrier_raised, .carrier_raised = mxser_carrier_raised,
.raise_dtr_rts = mxser_raise_dtr_rts, .dtr_rts = mxser_dtr_rts,
}; };
/* /*
......
...@@ -342,8 +342,8 @@ static int n_hdlc_tty_open (struct tty_struct *tty) ...@@ -342,8 +342,8 @@ static int n_hdlc_tty_open (struct tty_struct *tty)
#endif #endif
/* Flush any pending characters in the driver and discipline. */ /* Flush any pending characters in the driver and discipline. */
if (tty->ldisc.ops->flush_buffer) if (tty->ldisc->ops->flush_buffer)
tty->ldisc.ops->flush_buffer(tty); tty->ldisc->ops->flush_buffer(tty);
tty_driver_flush_buffer(tty); tty_driver_flush_buffer(tty);
......
...@@ -73,24 +73,6 @@ ...@@ -73,24 +73,6 @@
#define ECHO_OP_SET_CANON_COL 0x81 #define ECHO_OP_SET_CANON_COL 0x81
#define ECHO_OP_ERASE_TAB 0x82 #define ECHO_OP_ERASE_TAB 0x82
static inline unsigned char *alloc_buf(void)
{
gfp_t prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
if (PAGE_SIZE != N_TTY_BUF_SIZE)
return kmalloc(N_TTY_BUF_SIZE, prio);
else
return (unsigned char *)__get_free_page(prio);
}
static inline void free_buf(unsigned char *buf)
{
if (PAGE_SIZE != N_TTY_BUF_SIZE)
kfree(buf);
else
free_page((unsigned long) buf);
}
static inline int tty_put_user(struct tty_struct *tty, unsigned char x, static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
unsigned char __user *ptr) unsigned char __user *ptr)
{ {
...@@ -1558,11 +1540,11 @@ static void n_tty_close(struct tty_struct *tty) ...@@ -1558,11 +1540,11 @@ static void n_tty_close(struct tty_struct *tty)
{ {
n_tty_flush_buffer(tty); n_tty_flush_buffer(tty);
if (tty->read_buf) { if (tty->read_buf) {
free_buf(tty->read_buf); kfree(tty->read_buf);
tty->read_buf = NULL; tty->read_buf = NULL;
} }
if (tty->echo_buf) { if (tty->echo_buf) {
free_buf(tty->echo_buf); kfree(tty->echo_buf);
tty->echo_buf = NULL; tty->echo_buf = NULL;
} }
} }
...@@ -1584,17 +1566,16 @@ static int n_tty_open(struct tty_struct *tty) ...@@ -1584,17 +1566,16 @@ static int n_tty_open(struct tty_struct *tty)
/* These are ugly. Currently a malloc failure here can panic */ /* These are ugly. Currently a malloc failure here can panic */
if (!tty->read_buf) { if (!tty->read_buf) {
tty->read_buf = alloc_buf(); tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
if (!tty->read_buf) if (!tty->read_buf)
return -ENOMEM; return -ENOMEM;
} }
if (!tty->echo_buf) { if (!tty->echo_buf) {
tty->echo_buf = alloc_buf(); tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
if (!tty->echo_buf) if (!tty->echo_buf)
return -ENOMEM; return -ENOMEM;
} }
memset(tty->read_buf, 0, N_TTY_BUF_SIZE);
memset(tty->echo_buf, 0, N_TTY_BUF_SIZE);
reset_buffer_flags(tty); reset_buffer_flags(tty);
tty->column = 0; tty->column = 0;
n_tty_set_termios(tty, NULL); n_tty_set_termios(tty, NULL);
......
...@@ -383,7 +383,7 @@ static void async_mode(MGSLPC_INFO *info); ...@@ -383,7 +383,7 @@ static void async_mode(MGSLPC_INFO *info);
static void tx_timeout(unsigned long context); static void tx_timeout(unsigned long context);
static int carrier_raised(struct tty_port *port); static int carrier_raised(struct tty_port *port);
static void raise_dtr_rts(struct tty_port *port); static void dtr_rts(struct tty_port *port, int onoff);
#if SYNCLINK_GENERIC_HDLC #if SYNCLINK_GENERIC_HDLC
#define dev_to_port(D) (dev_to_hdlc(D)->priv) #define dev_to_port(D) (dev_to_hdlc(D)->priv)
...@@ -513,7 +513,7 @@ static void ldisc_receive_buf(struct tty_struct *tty, ...@@ -513,7 +513,7 @@ static void ldisc_receive_buf(struct tty_struct *tty,
static const struct tty_port_operations mgslpc_port_ops = { static const struct tty_port_operations mgslpc_port_ops = {
.carrier_raised = carrier_raised, .carrier_raised = carrier_raised,
.raise_dtr_rts = raise_dtr_rts .dtr_rts = dtr_rts
}; };
static int mgslpc_probe(struct pcmcia_device *link) static int mgslpc_probe(struct pcmcia_device *link)
...@@ -2528,13 +2528,16 @@ static int carrier_raised(struct tty_port *port) ...@@ -2528,13 +2528,16 @@ static int carrier_raised(struct tty_port *port)
return 0; return 0;
} }
static void raise_dtr_rts(struct tty_port *port) static void dtr_rts(struct tty_port *port, int onoff)
{ {
MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port); MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&info->lock,flags); spin_lock_irqsave(&info->lock,flags);
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; if (onoff)
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
else
info->serial_signals &= ~SerialSignal_RTS + SerialSignal_DTR;
set_signals(info); set_signals(info);
spin_unlock_irqrestore(&info->lock,flags); spin_unlock_irqrestore(&info->lock,flags);
} }
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include <asm/system.h> #include <asm/system.h>
/* These are global because they are accessed in tty_io.c */
#ifdef CONFIG_UNIX98_PTYS #ifdef CONFIG_UNIX98_PTYS
static struct tty_driver *ptm_driver; static struct tty_driver *ptm_driver;
static struct tty_driver *pts_driver; static struct tty_driver *pts_driver;
...@@ -111,7 +110,7 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf, ...@@ -111,7 +110,7 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf,
c = to->receive_room; c = to->receive_room;
if (c > count) if (c > count)
c = count; c = count;
to->ldisc.ops->receive_buf(to, buf, NULL, c); to->ldisc->ops->receive_buf(to, buf, NULL, c);
return c; return c;
} }
...@@ -149,11 +148,11 @@ static int pty_chars_in_buffer(struct tty_struct *tty) ...@@ -149,11 +148,11 @@ static int pty_chars_in_buffer(struct tty_struct *tty)
int count; int count;
/* We should get the line discipline lock for "tty->link" */ /* We should get the line discipline lock for "tty->link" */
if (!to || !to->ldisc.ops->chars_in_buffer) if (!to || !to->ldisc->ops->chars_in_buffer)
return 0; return 0;
/* The ldisc must report 0 if no characters available to be read */ /* The ldisc must report 0 if no characters available to be read */
count = to->ldisc.ops->chars_in_buffer(to); count = to->ldisc->ops->chars_in_buffer(to);
if (tty->driver->subtype == PTY_TYPE_SLAVE) if (tty->driver->subtype == PTY_TYPE_SLAVE)
return count; return count;
...@@ -187,8 +186,8 @@ static void pty_flush_buffer(struct tty_struct *tty) ...@@ -187,8 +186,8 @@ static void pty_flush_buffer(struct tty_struct *tty)
if (!to) if (!to)
return; return;
if (to->ldisc.ops->flush_buffer) if (to->ldisc->ops->flush_buffer)
to->ldisc.ops->flush_buffer(to); to->ldisc->ops->flush_buffer(to);
if (to->packet) { if (to->packet) {
spin_lock_irqsave(&tty->ctrl_lock, flags); spin_lock_irqsave(&tty->ctrl_lock, flags);
......
...@@ -872,11 +872,16 @@ static int carrier_raised(struct tty_port *port) ...@@ -872,11 +872,16 @@ static int carrier_raised(struct tty_port *port)
return (sGetChanStatusLo(&info->channel) & CD_ACT) ? 1 : 0; return (sGetChanStatusLo(&info->channel) & CD_ACT) ? 1 : 0;
} }
static void raise_dtr_rts(struct tty_port *port) static void dtr_rts(struct tty_port *port, int on)
{ {
struct r_port *info = container_of(port, struct r_port, port); struct r_port *info = container_of(port, struct r_port, port);
sSetDTR(&info->channel); if (on) {
sSetRTS(&info->channel); sSetDTR(&info->channel);
sSetRTS(&info->channel);
} else {
sClrDTR(&info->channel);
sClrRTS(&info->channel);
}
} }
/* /*
...@@ -934,7 +939,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp) ...@@ -934,7 +939,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
/* /*
* Info->count is now 1; so it's safe to sleep now. * Info->count is now 1; so it's safe to sleep now.
*/ */
if (!test_bit(ASYNC_INITIALIZED, &port->flags)) { if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
cp = &info->channel; cp = &info->channel;
sSetRxTrigger(cp, TRIG_1); sSetRxTrigger(cp, TRIG_1);
if (sGetChanStatus(cp) & CD_ACT) if (sGetChanStatus(cp) & CD_ACT)
...@@ -958,7 +963,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp) ...@@ -958,7 +963,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
sEnRxFIFO(cp); sEnRxFIFO(cp);
sEnTransmit(cp); sEnTransmit(cp);
set_bit(ASYNC_INITIALIZED, &info->port.flags); set_bit(ASYNCB_INITIALIZED, &info->port.flags);
/* /*
* Set up the tty->alt_speed kludge * Set up the tty->alt_speed kludge
...@@ -1641,7 +1646,7 @@ static int rp_write(struct tty_struct *tty, ...@@ -1641,7 +1646,7 @@ static int rp_write(struct tty_struct *tty,
/* Write remaining data into the port's xmit_buf */ /* Write remaining data into the port's xmit_buf */
while (1) { while (1) {
/* Hung up ? */ /* Hung up ? */
if (!test_bit(ASYNC_NORMAL_ACTIVE, &info->port.flags)) if (!test_bit(ASYNCB_NORMAL_ACTIVE, &info->port.flags))
goto end; goto end;
c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1); c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
c = min(c, XMIT_BUF_SIZE - info->xmit_head); c = min(c, XMIT_BUF_SIZE - info->xmit_head);
...@@ -2250,7 +2255,7 @@ static const struct tty_operations rocket_ops = { ...@@ -2250,7 +2255,7 @@ static const struct tty_operations rocket_ops = {
static const struct tty_port_operations rocket_port_ops = { static const struct tty_port_operations rocket_port_ops = {
.carrier_raised = carrier_raised, .carrier_raised = carrier_raised,
.raise_dtr_rts = raise_dtr_rts, .dtr_rts = dtr_rts,
}; };
/* /*
......
...@@ -327,7 +327,7 @@ int paste_selection(struct tty_struct *tty) ...@@ -327,7 +327,7 @@ int paste_selection(struct tty_struct *tty)
} }
count = sel_buffer_lth - pasted; count = sel_buffer_lth - pasted;
count = min(count, tty->receive_room); count = min(count, tty->receive_room);
tty->ldisc.ops->receive_buf(tty, sel_buffer + pasted, tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
NULL, count); NULL, count);
pasted += count; pasted += count;
} }
......
...@@ -772,11 +772,11 @@ static int stl_carrier_raised(struct tty_port *port) ...@@ -772,11 +772,11 @@ static int stl_carrier_raised(struct tty_port *port)
return (portp->sigs & TIOCM_CD) ? 1 : 0; return (portp->sigs & TIOCM_CD) ? 1 : 0;
} }
static void stl_raise_dtr_rts(struct tty_port *port) static void stl_dtr_rts(struct tty_port *port, int on)
{ {
struct stlport *portp = container_of(port, struct stlport, port); struct stlport *portp = container_of(port, struct stlport, port);
/* Takes brd_lock internally */ /* Takes brd_lock internally */
stl_setsignals(portp, 1, 1); stl_setsignals(portp, on, on);
} }
/*****************************************************************************/ /*****************************************************************************/
...@@ -2547,7 +2547,7 @@ static const struct tty_operations stl_ops = { ...@@ -2547,7 +2547,7 @@ static const struct tty_operations stl_ops = {
static const struct tty_port_operations stl_port_ops = { static const struct tty_port_operations stl_port_ops = {
.carrier_raised = stl_carrier_raised, .carrier_raised = stl_carrier_raised,
.raise_dtr_rts = stl_raise_dtr_rts, .dtr_rts = stl_dtr_rts,
}; };
/*****************************************************************************/ /*****************************************************************************/
......
...@@ -3247,13 +3247,16 @@ static int carrier_raised(struct tty_port *port) ...@@ -3247,13 +3247,16 @@ static int carrier_raised(struct tty_port *port)
return (info->serial_signals & SerialSignal_DCD) ? 1 : 0; return (info->serial_signals & SerialSignal_DCD) ? 1 : 0;
} }
static void raise_dtr_rts(struct tty_port *port) static void dtr_rts(struct tty_port *port, int on)
{ {
struct mgsl_struct *info = container_of(port, struct mgsl_struct, port); struct mgsl_struct *info = container_of(port, struct mgsl_struct, port);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&info->irq_spinlock,flags); spin_lock_irqsave(&info->irq_spinlock,flags);
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; if (on)
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
else
info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
usc_set_serial_signals(info); usc_set_serial_signals(info);
spin_unlock_irqrestore(&info->irq_spinlock,flags); spin_unlock_irqrestore(&info->irq_spinlock,flags);
} }
...@@ -4258,7 +4261,7 @@ static void mgsl_add_device( struct mgsl_struct *info ) ...@@ -4258,7 +4261,7 @@ static void mgsl_add_device( struct mgsl_struct *info )
static const struct tty_port_operations mgsl_port_ops = { static const struct tty_port_operations mgsl_port_ops = {
.carrier_raised = carrier_raised, .carrier_raised = carrier_raised,
.raise_dtr_rts = raise_dtr_rts, .dtr_rts = dtr_rts,
}; };
......
...@@ -214,6 +214,7 @@ struct slgt_desc ...@@ -214,6 +214,7 @@ struct slgt_desc
#define set_desc_next(a,b) (a).next = cpu_to_le32((unsigned int)(b)) #define set_desc_next(a,b) (a).next = cpu_to_le32((unsigned int)(b))
#define set_desc_count(a,b)(a).count = cpu_to_le16((unsigned short)(b)) #define set_desc_count(a,b)(a).count = cpu_to_le16((unsigned short)(b))
#define set_desc_eof(a,b) (a).status = cpu_to_le16((b) ? (le16_to_cpu((a).status) | BIT0) : (le16_to_cpu((a).status) & ~BIT0)) #define set_desc_eof(a,b) (a).status = cpu_to_le16((b) ? (le16_to_cpu((a).status) | BIT0) : (le16_to_cpu((a).status) & ~BIT0))
#define set_desc_status(a, b) (a).status = cpu_to_le16((unsigned short)(b))
#define desc_count(a) (le16_to_cpu((a).count)) #define desc_count(a) (le16_to_cpu((a).count))
#define desc_status(a) (le16_to_cpu((a).status)) #define desc_status(a) (le16_to_cpu((a).status))
#define desc_complete(a) (le16_to_cpu((a).status) & BIT15) #define desc_complete(a) (le16_to_cpu((a).status) & BIT15)
...@@ -297,6 +298,7 @@ struct slgt_info { ...@@ -297,6 +298,7 @@ struct slgt_info {
u32 max_frame_size; /* as set by device config */ u32 max_frame_size; /* as set by device config */
unsigned int rbuf_fill_level; unsigned int rbuf_fill_level;
unsigned int rx_pio;
unsigned int if_mode; unsigned int if_mode;
unsigned int base_clock; unsigned int base_clock;
...@@ -331,6 +333,8 @@ struct slgt_info { ...@@ -331,6 +333,8 @@ struct slgt_info {
struct slgt_desc *rbufs; struct slgt_desc *rbufs;
unsigned int rbuf_current; unsigned int rbuf_current;
unsigned int rbuf_index; unsigned int rbuf_index;
unsigned int rbuf_fill_index;
unsigned short rbuf_fill_count;
unsigned int tbuf_count; unsigned int tbuf_count;
struct slgt_desc *tbufs; struct slgt_desc *tbufs;
...@@ -2110,6 +2114,40 @@ static void ri_change(struct slgt_info *info, unsigned short status) ...@@ -2110,6 +2114,40 @@ static void ri_change(struct slgt_info *info, unsigned short status)
info->pending_bh |= BH_STATUS; info->pending_bh |= BH_STATUS;
} }
static void isr_rxdata(struct slgt_info *info)
{
unsigned int count = info->rbuf_fill_count;
unsigned int i = info->rbuf_fill_index;
unsigned short reg;
while (rd_reg16(info, SSR) & IRQ_RXDATA) {
reg = rd_reg16(info, RDR);
DBGISR(("isr_rxdata %s RDR=%04X\n", info->device_name, reg));
if (desc_complete(info->rbufs[i])) {
/* all buffers full */
rx_stop(info);
info->rx_restart = 1;
continue;
}
info->rbufs[i].buf[count++] = (unsigned char)reg;
/* async mode saves status byte to buffer for each data byte */
if (info->params.mode == MGSL_MODE_ASYNC)
info->rbufs[i].buf[count++] = (unsigned char)(reg >> 8);
if (count == info->rbuf_fill_level || (reg & BIT10)) {
/* buffer full or end of frame */
set_desc_count(info->rbufs[i], count);
set_desc_status(info->rbufs[i], BIT15 | (reg >> 8));
info->rbuf_fill_count = count = 0;
if (++i == info->rbuf_count)
i = 0;
info->pending_bh |= BH_RECEIVE;
}
}
info->rbuf_fill_index = i;
info->rbuf_fill_count = count;
}
static void isr_serial(struct slgt_info *info) static void isr_serial(struct slgt_info *info)
{ {
unsigned short status = rd_reg16(info, SSR); unsigned short status = rd_reg16(info, SSR);
...@@ -2125,6 +2163,8 @@ static void isr_serial(struct slgt_info *info) ...@@ -2125,6 +2163,8 @@ static void isr_serial(struct slgt_info *info)
if (info->tx_count) if (info->tx_count)
isr_txeom(info, status); isr_txeom(info, status);
} }
if (info->rx_pio && (status & IRQ_RXDATA))
isr_rxdata(info);
if ((status & IRQ_RXBREAK) && (status & RXBREAK)) { if ((status & IRQ_RXBREAK) && (status & RXBREAK)) {
info->icount.brk++; info->icount.brk++;
/* process break detection if tty control allows */ /* process break detection if tty control allows */
...@@ -2141,7 +2181,8 @@ static void isr_serial(struct slgt_info *info) ...@@ -2141,7 +2181,8 @@ static void isr_serial(struct slgt_info *info)
} else { } else {
if (status & (IRQ_TXIDLE + IRQ_TXUNDER)) if (status & (IRQ_TXIDLE + IRQ_TXUNDER))
isr_txeom(info, status); isr_txeom(info, status);
if (info->rx_pio && (status & IRQ_RXDATA))
isr_rxdata(info);
if (status & IRQ_RXIDLE) { if (status & IRQ_RXIDLE) {
if (status & RXIDLE) if (status & RXIDLE)
info->icount.rxidle++; info->icount.rxidle++;
...@@ -2642,6 +2683,10 @@ static int rx_enable(struct slgt_info *info, int enable) ...@@ -2642,6 +2683,10 @@ static int rx_enable(struct slgt_info *info, int enable)
return -EINVAL; return -EINVAL;
} }
info->rbuf_fill_level = rbuf_fill_level; info->rbuf_fill_level = rbuf_fill_level;
if (rbuf_fill_level < 128)
info->rx_pio = 1; /* PIO mode */
else
info->rx_pio = 0; /* DMA mode */
rx_stop(info); /* restart receiver to use new fill level */ rx_stop(info); /* restart receiver to use new fill level */
} }
...@@ -3099,13 +3144,16 @@ static int carrier_raised(struct tty_port *port) ...@@ -3099,13 +3144,16 @@ static int carrier_raised(struct tty_port *port)
return (info->signals & SerialSignal_DCD) ? 1 : 0; return (info->signals & SerialSignal_DCD) ? 1 : 0;
} }
static void raise_dtr_rts(struct tty_port *port) static void dtr_rts(struct tty_port *port, int on)
{ {
unsigned long flags; unsigned long flags;
struct slgt_info *info = container_of(port, struct slgt_info, port); struct slgt_info *info = container_of(port, struct slgt_info, port);
spin_lock_irqsave(&info->lock,flags); spin_lock_irqsave(&info->lock,flags);
info->signals |= SerialSignal_RTS + SerialSignal_DTR; if (on)
info->signals |= SerialSignal_RTS + SerialSignal_DTR;
else
info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
set_signals(info); set_signals(info);
spin_unlock_irqrestore(&info->lock,flags); spin_unlock_irqrestore(&info->lock,flags);
} }
...@@ -3419,7 +3467,7 @@ static void add_device(struct slgt_info *info) ...@@ -3419,7 +3467,7 @@ static void add_device(struct slgt_info *info)
static const struct tty_port_operations slgt_port_ops = { static const struct tty_port_operations slgt_port_ops = {
.carrier_raised = carrier_raised, .carrier_raised = carrier_raised,
.raise_dtr_rts = raise_dtr_rts, .dtr_rts = dtr_rts,
}; };
/* /*
...@@ -3841,15 +3889,27 @@ static void rx_start(struct slgt_info *info) ...@@ -3841,15 +3889,27 @@ static void rx_start(struct slgt_info *info)
rdma_reset(info); rdma_reset(info);
reset_rbufs(info); reset_rbufs(info);
/* set 1st descriptor address */ if (info->rx_pio) {
wr_reg32(info, RDDAR, info->rbufs[0].pdesc); /* rx request when rx FIFO not empty */
wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) & ~BIT14));
if (info->params.mode != MGSL_MODE_ASYNC) { slgt_irq_on(info, IRQ_RXDATA);
/* enable rx DMA and DMA interrupt */ if (info->params.mode == MGSL_MODE_ASYNC) {
wr_reg32(info, RDCSR, (BIT2 + BIT0)); /* enable saving of rx status */
wr_reg32(info, RDCSR, BIT6);
}
} else { } else {
/* enable saving of rx status, rx DMA and DMA interrupt */ /* rx request when rx FIFO half full */
wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0)); wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) | BIT14));
/* set 1st descriptor address */
wr_reg32(info, RDDAR, info->rbufs[0].pdesc);
if (info->params.mode != MGSL_MODE_ASYNC) {
/* enable rx DMA and DMA interrupt */
wr_reg32(info, RDCSR, (BIT2 + BIT0));
} else {
/* enable saving of rx status, rx DMA and DMA interrupt */
wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0));
}
} }
slgt_irq_on(info, IRQ_RXOVER); slgt_irq_on(info, IRQ_RXOVER);
...@@ -4467,6 +4527,8 @@ static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last ...@@ -4467,6 +4527,8 @@ static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last
static void reset_rbufs(struct slgt_info *info) static void reset_rbufs(struct slgt_info *info)
{ {
free_rbufs(info, 0, info->rbuf_count - 1); free_rbufs(info, 0, info->rbuf_count - 1);
info->rbuf_fill_index = 0;
info->rbuf_fill_count = 0;
} }
/* /*
......
...@@ -3277,13 +3277,16 @@ static int carrier_raised(struct tty_port *port) ...@@ -3277,13 +3277,16 @@ static int carrier_raised(struct tty_port *port)
return (info->serial_signals & SerialSignal_DCD) ? 1 : 0; return (info->serial_signals & SerialSignal_DCD) ? 1 : 0;
} }
static void raise_dtr_rts(struct tty_port *port) static void dtr_rts(struct tty_port *port, int on)
{ {
SLMP_INFO *info = container_of(port, SLMP_INFO, port); SLMP_INFO *info = container_of(port, SLMP_INFO, port);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&info->lock,flags); spin_lock_irqsave(&info->lock,flags);
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; if (on)
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
else
info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
set_signals(info); set_signals(info);
spin_unlock_irqrestore(&info->lock,flags); spin_unlock_irqrestore(&info->lock,flags);
} }
...@@ -3746,7 +3749,7 @@ static void add_device(SLMP_INFO *info) ...@@ -3746,7 +3749,7 @@ static void add_device(SLMP_INFO *info)
static const struct tty_port_operations port_ops = { static const struct tty_port_operations port_ops = {
.carrier_raised = carrier_raised, .carrier_raised = carrier_raised,
.raise_dtr_rts = raise_dtr_rts, .dtr_rts = dtr_rts,
}; };
/* Allocate and initialize a device instance structure /* Allocate and initialize a device instance structure
......
...@@ -29,10 +29,7 @@ static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor, ...@@ -29,10 +29,7 @@ static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
buf = kmalloc(sizeof(*buf), GFP_KERNEL); buf = kmalloc(sizeof(*buf), GFP_KERNEL);
if (!buf) if (!buf)
goto err; goto err;
if (PAGE_SIZE != N_TTY_BUF_SIZE) buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
else
buf->data = (unsigned char *)__get_free_page(GFP_KERNEL);
if (!buf->data) if (!buf->data)
goto err_buf; goto err_buf;
atomic_set(&buf->count, 1); atomic_set(&buf->count, 1);
...@@ -52,10 +49,7 @@ static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor, ...@@ -52,10 +49,7 @@ static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
static void tty_audit_buf_free(struct tty_audit_buf *buf) static void tty_audit_buf_free(struct tty_audit_buf *buf)
{ {
WARN_ON(buf->valid != 0); WARN_ON(buf->valid != 0);
if (PAGE_SIZE != N_TTY_BUF_SIZE) kfree(buf->data);
kfree(buf->data);
else
free_page((unsigned long)buf->data);
kfree(buf); kfree(buf);
} }
......
...@@ -295,7 +295,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line) ...@@ -295,7 +295,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
struct tty_driver *p, *res = NULL; struct tty_driver *p, *res = NULL;
int tty_line = 0; int tty_line = 0;
int len; int len;
char *str; char *str, *stp;
for (str = name; *str; str++) for (str = name; *str; str++)
if ((*str >= '0' && *str <= '9') || *str == ',') if ((*str >= '0' && *str <= '9') || *str == ',')
...@@ -311,13 +311,14 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line) ...@@ -311,13 +311,14 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
list_for_each_entry(p, &tty_drivers, tty_drivers) { list_for_each_entry(p, &tty_drivers, tty_drivers) {
if (strncmp(name, p->name, len) != 0) if (strncmp(name, p->name, len) != 0)
continue; continue;
if (*str == ',') stp = str;
str++; if (*stp == ',')
if (*str == '\0') stp++;
str = NULL; if (*stp == '\0')
stp = NULL;
if (tty_line >= 0 && tty_line <= p->num && p->ops && if (tty_line >= 0 && tty_line <= p->num && p->ops &&
p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) { p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) {
res = tty_driver_kref_get(p); res = tty_driver_kref_get(p);
*line = tty_line; *line = tty_line;
break; break;
...@@ -469,43 +470,6 @@ void tty_wakeup(struct tty_struct *tty) ...@@ -469,43 +470,6 @@ void tty_wakeup(struct tty_struct *tty)
EXPORT_SYMBOL_GPL(tty_wakeup); EXPORT_SYMBOL_GPL(tty_wakeup);
/**
* tty_ldisc_flush - flush line discipline queue
* @tty: tty
*
* Flush the line discipline queue (if any) for this tty. If there
* is no line discipline active this is a no-op.
*/
void tty_ldisc_flush(struct tty_struct *tty)
{
struct tty_ldisc *ld = tty_ldisc_ref(tty);
if (ld) {
if (ld->ops->flush_buffer)
ld->ops->flush_buffer(tty);
tty_ldisc_deref(ld);
}
tty_buffer_flush(tty);
}
EXPORT_SYMBOL_GPL(tty_ldisc_flush);
/**
* tty_reset_termios - reset terminal state
* @tty: tty to reset
*
* Restore a terminal to the driver default state
*/
static void tty_reset_termios(struct tty_struct *tty)
{
mutex_lock(&tty->termios_mutex);
*tty->termios = tty->driver->init_termios;
tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
mutex_unlock(&tty->termios_mutex);
}
/** /**
* do_tty_hangup - actual handler for hangup events * do_tty_hangup - actual handler for hangup events
* @work: tty device * @work: tty device
...@@ -535,7 +499,6 @@ static void do_tty_hangup(struct work_struct *work) ...@@ -535,7 +499,6 @@ static void do_tty_hangup(struct work_struct *work)
struct file *cons_filp = NULL; struct file *cons_filp = NULL;
struct file *filp, *f = NULL; struct file *filp, *f = NULL;
struct task_struct *p; struct task_struct *p;
struct tty_ldisc *ld;
int closecount = 0, n; int closecount = 0, n;
unsigned long flags; unsigned long flags;
int refs = 0; int refs = 0;
...@@ -566,40 +529,8 @@ static void do_tty_hangup(struct work_struct *work) ...@@ -566,40 +529,8 @@ static void do_tty_hangup(struct work_struct *work)
filp->f_op = &hung_up_tty_fops; filp->f_op = &hung_up_tty_fops;
} }
file_list_unlock(); file_list_unlock();
/*
* FIXME! What are the locking issues here? This may me overdoing
* things... This question is especially important now that we've
* removed the irqlock.
*/
ld = tty_ldisc_ref(tty);
if (ld != NULL) {
/* We may have no line discipline at this point */
if (ld->ops->flush_buffer)
ld->ops->flush_buffer(tty);
tty_driver_flush_buffer(tty);
if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
ld->ops->write_wakeup)
ld->ops->write_wakeup(tty);
if (ld->ops->hangup)
ld->ops->hangup(tty);
}
/*
* FIXME: Once we trust the LDISC code better we can wait here for
* ldisc completion and fix the driver call race
*/
wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
/*
* Shutdown the current line discipline, and reset it to
* N_TTY.
*/
if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
tty_reset_termios(tty);
/* Defer ldisc switch */
/* tty_deferred_ldisc_switch(N_TTY);
This should get done automatically when the port closes and tty_ldisc_hangup(tty);
tty_release is called */
read_lock(&tasklist_lock); read_lock(&tasklist_lock);
if (tty->session) { if (tty->session) {
...@@ -628,12 +559,15 @@ static void do_tty_hangup(struct work_struct *work) ...@@ -628,12 +559,15 @@ static void do_tty_hangup(struct work_struct *work)
read_unlock(&tasklist_lock); read_unlock(&tasklist_lock);
spin_lock_irqsave(&tty->ctrl_lock, flags); spin_lock_irqsave(&tty->ctrl_lock, flags);
tty->flags = 0; clear_bit(TTY_THROTTLED, &tty->flags);
clear_bit(TTY_PUSH, &tty->flags);
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
put_pid(tty->session); put_pid(tty->session);
put_pid(tty->pgrp); put_pid(tty->pgrp);
tty->session = NULL; tty->session = NULL;
tty->pgrp = NULL; tty->pgrp = NULL;
tty->ctrl_status = 0; tty->ctrl_status = 0;
set_bit(TTY_HUPPED, &tty->flags);
spin_unlock_irqrestore(&tty->ctrl_lock, flags); spin_unlock_irqrestore(&tty->ctrl_lock, flags);
/* Account for the p->signal references we killed */ /* Account for the p->signal references we killed */
...@@ -659,10 +593,7 @@ static void do_tty_hangup(struct work_struct *work) ...@@ -659,10 +593,7 @@ static void do_tty_hangup(struct work_struct *work)
* can't yet guarantee all that. * can't yet guarantee all that.
*/ */
set_bit(TTY_HUPPED, &tty->flags); set_bit(TTY_HUPPED, &tty->flags);
if (ld) { tty_ldisc_enable(tty);
tty_ldisc_enable(tty);
tty_ldisc_deref(ld);
}
unlock_kernel(); unlock_kernel();
if (f) if (f)
fput(f); fput(f);
...@@ -2480,6 +2411,24 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int ...@@ -2480,6 +2411,24 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int
return tty->ops->tiocmset(tty, file, set, clear); return tty->ops->tiocmset(tty, file, set, clear);
} }
struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
{
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
tty = tty->link;
return tty;
}
EXPORT_SYMBOL(tty_pair_get_tty);
struct tty_struct *tty_pair_get_pty(struct tty_struct *tty)
{
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
return tty;
return tty->link;
}
EXPORT_SYMBOL(tty_pair_get_pty);
/* /*
* Split this up, as gcc can choke on it otherwise.. * Split this up, as gcc can choke on it otherwise..
*/ */
...@@ -2495,11 +2444,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -2495,11 +2444,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (tty_paranoia_check(tty, inode, "tty_ioctl")) if (tty_paranoia_check(tty, inode, "tty_ioctl"))
return -EINVAL; return -EINVAL;
real_tty = tty; real_tty = tty_pair_get_tty(tty);
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
real_tty = tty->link;
/* /*
* Factor out some common prep work * Factor out some common prep work
...@@ -2555,7 +2500,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -2555,7 +2500,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case TIOCGSID: case TIOCGSID:
return tiocgsid(tty, real_tty, p); return tiocgsid(tty, real_tty, p);
case TIOCGETD: case TIOCGETD:
return put_user(tty->ldisc.ops->num, (int __user *)p); return put_user(tty->ldisc->ops->num, (int __user *)p);
case TIOCSETD: case TIOCSETD:
return tiocsetd(tty, p); return tiocsetd(tty, p);
/* /*
...@@ -2770,6 +2715,7 @@ void initialize_tty_struct(struct tty_struct *tty, ...@@ -2770,6 +2715,7 @@ void initialize_tty_struct(struct tty_struct *tty,
tty->buf.head = tty->buf.tail = NULL; tty->buf.head = tty->buf.tail = NULL;
tty_buffer_init(tty); tty_buffer_init(tty);
mutex_init(&tty->termios_mutex); mutex_init(&tty->termios_mutex);
mutex_init(&tty->ldisc_mutex);
init_waitqueue_head(&tty->write_wait); init_waitqueue_head(&tty->write_wait);
init_waitqueue_head(&tty->read_wait); init_waitqueue_head(&tty->read_wait);
INIT_WORK(&tty->hangup_work, do_tty_hangup); INIT_WORK(&tty->hangup_work, do_tty_hangup);
......
...@@ -97,14 +97,19 @@ EXPORT_SYMBOL(tty_driver_flush_buffer); ...@@ -97,14 +97,19 @@ EXPORT_SYMBOL(tty_driver_flush_buffer);
* @tty: terminal * @tty: terminal
* *
* Indicate that a tty should stop transmitting data down the stack. * Indicate that a tty should stop transmitting data down the stack.
* Takes the termios mutex to protect against parallel throttle/unthrottle
* and also to ensure the driver can consistently reference its own
* termios data at this point when implementing software flow control.
*/ */
void tty_throttle(struct tty_struct *tty) void tty_throttle(struct tty_struct *tty)
{ {
mutex_lock(&tty->termios_mutex);
/* check TTY_THROTTLED first so it indicates our state */ /* check TTY_THROTTLED first so it indicates our state */
if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) && if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
tty->ops->throttle) tty->ops->throttle)
tty->ops->throttle(tty); tty->ops->throttle(tty);
mutex_unlock(&tty->termios_mutex);
} }
EXPORT_SYMBOL(tty_throttle); EXPORT_SYMBOL(tty_throttle);
...@@ -113,13 +118,21 @@ EXPORT_SYMBOL(tty_throttle); ...@@ -113,13 +118,21 @@ EXPORT_SYMBOL(tty_throttle);
* @tty: terminal * @tty: terminal
* *
* Indicate that a tty may continue transmitting data down the stack. * Indicate that a tty may continue transmitting data down the stack.
* Takes the termios mutex to protect against parallel throttle/unthrottle
* and also to ensure the driver can consistently reference its own
* termios data at this point when implementing software flow control.
*
* Drivers should however remember that the stack can issue a throttle,
* then change flow control method, then unthrottle.
*/ */
void tty_unthrottle(struct tty_struct *tty) void tty_unthrottle(struct tty_struct *tty)
{ {
mutex_lock(&tty->termios_mutex);
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
tty->ops->unthrottle) tty->ops->unthrottle)
tty->ops->unthrottle(tty); tty->ops->unthrottle(tty);
mutex_unlock(&tty->termios_mutex);
} }
EXPORT_SYMBOL(tty_unthrottle); EXPORT_SYMBOL(tty_unthrottle);
...@@ -613,9 +626,25 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt) ...@@ -613,9 +626,25 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
return 0; return 0;
} }
static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
{
mutex_lock(&tty->termios_mutex);
memcpy(kterm, tty->termios, sizeof(struct ktermios));
mutex_unlock(&tty->termios_mutex);
}
static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
{
mutex_lock(&tty->termios_mutex);
memcpy(kterm, tty->termios_locked, sizeof(struct ktermios));
mutex_unlock(&tty->termios_mutex);
}
static int get_termio(struct tty_struct *tty, struct termio __user *termio) static int get_termio(struct tty_struct *tty, struct termio __user *termio)
{ {
if (kernel_termios_to_user_termio(termio, tty->termios)) struct ktermios kterm;
copy_termios(tty, &kterm);
if (kernel_termios_to_user_termio(termio, &kterm))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
...@@ -917,6 +946,8 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, ...@@ -917,6 +946,8 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
struct tty_struct *real_tty; struct tty_struct *real_tty;
void __user *p = (void __user *)arg; void __user *p = (void __user *)arg;
int ret = 0; int ret = 0;
struct ktermios kterm;
struct termiox ktermx;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY && if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER) tty->driver->subtype == PTY_TYPE_MASTER)
...@@ -952,23 +983,20 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, ...@@ -952,23 +983,20 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
return set_termios(real_tty, p, TERMIOS_OLD); return set_termios(real_tty, p, TERMIOS_OLD);
#ifndef TCGETS2 #ifndef TCGETS2
case TCGETS: case TCGETS:
mutex_lock(&real_tty->termios_mutex); copy_termios(real_tty, &kterm);
if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
ret = -EFAULT; ret = -EFAULT;
mutex_unlock(&real_tty->termios_mutex);
return ret; return ret;
#else #else
case TCGETS: case TCGETS:
mutex_lock(&real_tty->termios_mutex); copy_termios(real_tty, &kterm);
if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios)) if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
ret = -EFAULT; ret = -EFAULT;
mutex_unlock(&real_tty->termios_mutex);
return ret; return ret;
case TCGETS2: case TCGETS2:
mutex_lock(&real_tty->termios_mutex); copy_termios(real_tty, &kterm);
if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios)) if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
ret = -EFAULT; ret = -EFAULT;
mutex_unlock(&real_tty->termios_mutex);
return ret; return ret;
case TCSETSF2: case TCSETSF2:
return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
...@@ -987,34 +1015,36 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, ...@@ -987,34 +1015,36 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
return set_termios(real_tty, p, TERMIOS_TERMIO); return set_termios(real_tty, p, TERMIOS_TERMIO);
#ifndef TCGETS2 #ifndef TCGETS2
case TIOCGLCKTRMIOS: case TIOCGLCKTRMIOS:
mutex_lock(&real_tty->termios_mutex); copy_termios_locked(real_tty, &kterm);
if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked)) if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
ret = -EFAULT; ret = -EFAULT;
mutex_unlock(&real_tty->termios_mutex);
return ret; return ret;
case TIOCSLCKTRMIOS: case TIOCSLCKTRMIOS:
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
mutex_lock(&real_tty->termios_mutex); copy_termios_locked(real_tty, &kterm);
if (user_termios_to_kernel_termios(real_tty->termios_locked, if (user_termios_to_kernel_termios(&kterm,
(struct termios __user *) arg)) (struct termios __user *) arg))
ret = -EFAULT; return -EFAULT;
mutex_lock(&real_tty->termios_mutex);
memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
mutex_unlock(&real_tty->termios_mutex); mutex_unlock(&real_tty->termios_mutex);
return ret; return 0;
#else #else
case TIOCGLCKTRMIOS: case TIOCGLCKTRMIOS:
mutex_lock(&real_tty->termios_mutex); copy_termios_locked(real_tty, &kterm);
if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked)) if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
ret = -EFAULT; ret = -EFAULT;
mutex_unlock(&real_tty->termios_mutex);
return ret; return ret;
case TIOCSLCKTRMIOS: case TIOCSLCKTRMIOS:
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
ret = -EPERM; return -EPERM;
mutex_lock(&real_tty->termios_mutex); copy_termios_locked(real_tty, &kterm);
if (user_termios_to_kernel_termios_1(real_tty->termios_locked, if (user_termios_to_kernel_termios_1(&kterm,
(struct termios __user *) arg)) (struct termios __user *) arg))
ret = -EFAULT; return -EFAULT;
mutex_lock(&real_tty->termios_mutex);
memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
mutex_unlock(&real_tty->termios_mutex); mutex_unlock(&real_tty->termios_mutex);
return ret; return ret;
#endif #endif
...@@ -1023,9 +1053,10 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, ...@@ -1023,9 +1053,10 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
if (real_tty->termiox == NULL) if (real_tty->termiox == NULL)
return -EINVAL; return -EINVAL;
mutex_lock(&real_tty->termios_mutex); mutex_lock(&real_tty->termios_mutex);
if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox))) memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
ret = -EFAULT;
mutex_unlock(&real_tty->termios_mutex); mutex_unlock(&real_tty->termios_mutex);
if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
ret = -EFAULT;
return ret; return ret;
case TCSETX: case TCSETX:
return set_termiox(real_tty, p, 0); return set_termiox(real_tty, p, 0);
...@@ -1035,10 +1066,9 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, ...@@ -1035,10 +1066,9 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
return set_termiox(real_tty, p, TERMIOS_FLUSH); return set_termiox(real_tty, p, TERMIOS_FLUSH);
#endif #endif
case TIOCGSOFTCAR: case TIOCGSOFTCAR:
mutex_lock(&real_tty->termios_mutex); copy_termios(real_tty, &kterm);
ret = put_user(C_CLOCAL(real_tty) ? 1 : 0, ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
(int __user *)arg); (int __user *)arg);
mutex_unlock(&real_tty->termios_mutex);
return ret; return ret;
case TIOCSSOFTCAR: case TIOCSSOFTCAR:
if (get_user(arg, (unsigned int __user *) arg)) if (get_user(arg, (unsigned int __user *) arg))
......
此差异已折叠。
...@@ -137,7 +137,7 @@ int tty_port_carrier_raised(struct tty_port *port) ...@@ -137,7 +137,7 @@ int tty_port_carrier_raised(struct tty_port *port)
EXPORT_SYMBOL(tty_port_carrier_raised); EXPORT_SYMBOL(tty_port_carrier_raised);
/** /**
* tty_port_raise_dtr_rts - Riase DTR/RTS * tty_port_raise_dtr_rts - Raise DTR/RTS
* @port: tty port * @port: tty port
* *
* Wrapper for the DTR/RTS raise logic. For the moment this is used * Wrapper for the DTR/RTS raise logic. For the moment this is used
...@@ -147,11 +147,27 @@ EXPORT_SYMBOL(tty_port_carrier_raised); ...@@ -147,11 +147,27 @@ EXPORT_SYMBOL(tty_port_carrier_raised);
void tty_port_raise_dtr_rts(struct tty_port *port) void tty_port_raise_dtr_rts(struct tty_port *port)
{ {
if (port->ops->raise_dtr_rts) if (port->ops->dtr_rts)
port->ops->raise_dtr_rts(port); port->ops->dtr_rts(port, 1);
} }
EXPORT_SYMBOL(tty_port_raise_dtr_rts); EXPORT_SYMBOL(tty_port_raise_dtr_rts);
/**
* tty_port_lower_dtr_rts - Lower DTR/RTS
* @port: tty port
*
* Wrapper for the DTR/RTS raise logic. For the moment this is used
* to hide some internal details. This will eventually become entirely
* internal to the tty port.
*/
void tty_port_lower_dtr_rts(struct tty_port *port)
{
if (port->ops->dtr_rts)
port->ops->dtr_rts(port, 0);
}
EXPORT_SYMBOL(tty_port_lower_dtr_rts);
/** /**
* tty_port_block_til_ready - Waiting logic for tty open * tty_port_block_til_ready - Waiting logic for tty open
* @port: the tty port being opened * @port: the tty port being opened
...@@ -167,7 +183,7 @@ EXPORT_SYMBOL(tty_port_raise_dtr_rts); ...@@ -167,7 +183,7 @@ EXPORT_SYMBOL(tty_port_raise_dtr_rts);
* - port flags and counts * - port flags and counts
* *
* The passed tty_port must implement the carrier_raised method if it can * The passed tty_port must implement the carrier_raised method if it can
* do carrier detect and the raise_dtr_rts method if it supports software * do carrier detect and the dtr_rts method if it supports software
* management of these lines. Note that the dtr/rts raise is done each * management of these lines. Note that the dtr/rts raise is done each
* iteration as a hangup may have previously dropped them while we wait. * iteration as a hangup may have previously dropped them while we wait.
*/ */
...@@ -182,7 +198,8 @@ int tty_port_block_til_ready(struct tty_port *port, ...@@ -182,7 +198,8 @@ int tty_port_block_til_ready(struct tty_port *port,
/* block if port is in the process of being closed */ /* block if port is in the process of being closed */
if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
interruptible_sleep_on(&port->close_wait); wait_event_interruptible(port->close_wait,
!(port->flags & ASYNC_CLOSING));
if (port->flags & ASYNC_HUP_NOTIFY) if (port->flags & ASYNC_HUP_NOTIFY)
return -EAGAIN; return -EAGAIN;
else else
...@@ -205,7 +222,6 @@ int tty_port_block_til_ready(struct tty_port *port, ...@@ -205,7 +222,6 @@ int tty_port_block_til_ready(struct tty_port *port,
before the next open may complete */ before the next open may complete */
retval = 0; retval = 0;
add_wait_queue(&port->open_wait, &wait);
/* The port lock protects the port counts */ /* The port lock protects the port counts */
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
...@@ -219,7 +235,7 @@ int tty_port_block_til_ready(struct tty_port *port, ...@@ -219,7 +235,7 @@ int tty_port_block_til_ready(struct tty_port *port,
if (tty->termios->c_cflag & CBAUD) if (tty->termios->c_cflag & CBAUD)
tty_port_raise_dtr_rts(port); tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE); prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
/* Check for a hangup or uninitialised port. Return accordingly */ /* Check for a hangup or uninitialised port. Return accordingly */
if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
if (port->flags & ASYNC_HUP_NOTIFY) if (port->flags & ASYNC_HUP_NOTIFY)
...@@ -240,8 +256,7 @@ int tty_port_block_til_ready(struct tty_port *port, ...@@ -240,8 +256,7 @@ int tty_port_block_til_ready(struct tty_port *port,
} }
schedule(); schedule();
} }
set_current_state(TASK_RUNNING); finish_wait(&port->open_wait, &wait);
remove_wait_queue(&port->open_wait, &wait);
/* Update counts. A parallel hangup will have set count to zero and /* Update counts. A parallel hangup will have set count to zero and
we must not mess that up further */ we must not mess that up further */
...@@ -292,6 +307,17 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f ...@@ -292,6 +307,17 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
if (port->flags & ASYNC_INITIALIZED && if (port->flags & ASYNC_INITIALIZED &&
port->closing_wait != ASYNC_CLOSING_WAIT_NONE) port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, port->closing_wait); tty_wait_until_sent(tty, port->closing_wait);
if (port->drain_delay) {
unsigned int bps = tty_get_baud_rate(tty);
long timeout;
if (bps > 1200)
timeout = max_t(long, (HZ * 10 * port->drain_delay) / bps,
HZ / 10);
else
timeout = 2 * HZ;
schedule_timeout_interruptible(timeout);
}
return 1; return 1;
} }
EXPORT_SYMBOL(tty_port_close_start); EXPORT_SYMBOL(tty_port_close_start);
...@@ -302,6 +328,9 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty) ...@@ -302,6 +328,9 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
tty_ldisc_flush(tty); tty_ldisc_flush(tty);
if (tty->termios->c_cflag & HUPCL)
tty_port_lower_dtr_rts(port);
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
tty->closing = 0; tty->closing = 0;
......
此差异已折叠。
...@@ -287,6 +287,13 @@ static const struct serial8250_config uart_config[] = { ...@@ -287,6 +287,13 @@ static const struct serial8250_config uart_config[] = {
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO, .flags = UART_CAP_FIFO,
}, },
[PORT_AR7] = {
.name = "AR7",
.fifo_size = 16,
.tx_loadsz = 16,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00,
.flags = UART_CAP_FIFO | UART_CAP_AFE,
},
}; };
#if defined (CONFIG_SERIAL_8250_AU1X00) #if defined (CONFIG_SERIAL_8250_AU1X00)
......
...@@ -2776,6 +2776,9 @@ static struct pci_device_id serial_pci_tbl[] = { ...@@ -2776,6 +2776,9 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_OXSEMI, 0x950a, { PCI_VENDOR_ID_OXSEMI, 0x950a,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_2_1130000 }, pbn_b0_2_1130000 },
{ PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_C950,
PCI_VENDOR_ID_OXSEMI, PCI_SUBDEVICE_ID_OXSEMI_C950, 0, 0,
pbn_b0_1_921600 },
{ PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_4_115200 }, pbn_b0_4_115200 },
......
...@@ -833,6 +833,7 @@ config SERIAL_IMX ...@@ -833,6 +833,7 @@ config SERIAL_IMX
bool "IMX serial port support" bool "IMX serial port support"
depends on ARM && (ARCH_IMX || ARCH_MXC) depends on ARM && (ARCH_IMX || ARCH_MXC)
select SERIAL_CORE select SERIAL_CORE
select RATIONAL
help help
If you have a machine based on a Motorola IMX CPU you If you have a machine based on a Motorola IMX CPU you
can enable its onboard serial port by enabling this option. can enable its onboard serial port by enabling this option.
...@@ -1433,4 +1434,11 @@ config SPORT_BAUD_RATE ...@@ -1433,4 +1434,11 @@ config SPORT_BAUD_RATE
default 19200 if (SERIAL_SPORT_BAUD_RATE_19200) default 19200 if (SERIAL_SPORT_BAUD_RATE_19200)
default 9600 if (SERIAL_SPORT_BAUD_RATE_9600) default 9600 if (SERIAL_SPORT_BAUD_RATE_9600)
config SERIAL_TIMBERDALE
tristate "Support for timberdale UART"
depends on MFD_TIMBERDALE
select SERIAL_CORE
---help---
Add support for UART controller on timberdale.
endmenu endmenu
...@@ -77,3 +77,4 @@ obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o ...@@ -77,3 +77,4 @@ obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
...@@ -330,6 +330,11 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart) ...@@ -330,6 +330,11 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
/* Clear TFI bit */ /* Clear TFI bit */
UART_PUT_LSR(uart, TFI); UART_PUT_LSR(uart, TFI);
#endif #endif
/* Anomaly notes:
* 05000215 - we always clear ETBEI within last UART TX
* interrupt to end a string. It is always set
* when start a new tx.
*/
UART_CLEAR_IER(uart, ETBEI); UART_CLEAR_IER(uart, ETBEI);
return; return;
} }
...@@ -415,6 +420,7 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) ...@@ -415,6 +420,7 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail)); set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail));
set_dma_x_count(uart->tx_dma_channel, uart->tx_count); set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
set_dma_x_modify(uart->tx_dma_channel, 1); set_dma_x_modify(uart->tx_dma_channel, 1);
SSYNC();
enable_dma(uart->tx_dma_channel); enable_dma(uart->tx_dma_channel);
UART_SET_IER(uart, ETBEI); UART_SET_IER(uart, ETBEI);
...@@ -473,27 +479,41 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart) ...@@ -473,27 +479,41 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart) void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
{ {
int x_pos, pos; int x_pos, pos;
unsigned long flags;
spin_lock_irqsave(&uart->port.lock, flags);
dma_disable_irq(uart->rx_dma_channel);
spin_lock_bh(&uart->port.lock);
/* 2D DMA RX buffer ring is used. Because curr_y_count and
* curr_x_count can't be read as an atomic operation,
* curr_y_count should be read before curr_x_count. When
* curr_x_count is read, curr_y_count may already indicate
* next buffer line. But, the position calculated here is
* still indicate the old line. The wrong position data may
* be smaller than current buffer tail, which cause garbages
* are received if it is not prohibit.
*/
uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel); uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
x_pos = get_dma_curr_xcount(uart->rx_dma_channel); x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows; uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
if (uart->rx_dma_nrows == DMA_RX_YCOUNT) if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0)
uart->rx_dma_nrows = 0; uart->rx_dma_nrows = 0;
x_pos = DMA_RX_XCOUNT - x_pos; x_pos = DMA_RX_XCOUNT - x_pos;
if (x_pos == DMA_RX_XCOUNT) if (x_pos == DMA_RX_XCOUNT)
x_pos = 0; x_pos = 0;
pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos; pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos;
if (pos != uart->rx_dma_buf.tail) { /* Ignore receiving data if new position is in the same line of
* current buffer tail and small.
*/
if (pos > uart->rx_dma_buf.tail ||
uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) {
uart->rx_dma_buf.head = pos; uart->rx_dma_buf.head = pos;
bfin_serial_dma_rx_chars(uart); bfin_serial_dma_rx_chars(uart);
uart->rx_dma_buf.tail = uart->rx_dma_buf.head; uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
} }
spin_unlock_irqrestore(&uart->port.lock, flags); spin_unlock_bh(&uart->port.lock);
dma_enable_irq(uart->rx_dma_channel);
mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES); mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);
} }
...@@ -514,6 +534,11 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id) ...@@ -514,6 +534,11 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) { if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
disable_dma(uart->tx_dma_channel); disable_dma(uart->tx_dma_channel);
clear_dma_irqstat(uart->tx_dma_channel); clear_dma_irqstat(uart->tx_dma_channel);
/* Anomaly notes:
* 05000215 - we always clear ETBEI within last UART TX
* interrupt to end a string. It is always set
* when start a new tx.
*/
UART_CLEAR_IER(uart, ETBEI); UART_CLEAR_IER(uart, ETBEI);
xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1); xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
uart->port.icount.tx += uart->tx_count; uart->port.icount.tx += uart->tx_count;
...@@ -532,11 +557,26 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id) ...@@ -532,11 +557,26 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
{ {
struct bfin_serial_port *uart = dev_id; struct bfin_serial_port *uart = dev_id;
unsigned short irqstat; unsigned short irqstat;
int x_pos, pos;
spin_lock(&uart->port.lock); spin_lock(&uart->port.lock);
irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
clear_dma_irqstat(uart->rx_dma_channel); clear_dma_irqstat(uart->rx_dma_channel);
bfin_serial_dma_rx_chars(uart);
uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0)
uart->rx_dma_nrows = 0;
pos = uart->rx_dma_nrows * DMA_RX_XCOUNT;
if (pos > uart->rx_dma_buf.tail ||
uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) {
uart->rx_dma_buf.head = pos;
bfin_serial_dma_rx_chars(uart);
uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
}
spin_unlock(&uart->port.lock); spin_unlock(&uart->port.lock);
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -789,8 +829,16 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, ...@@ -789,8 +829,16 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
__func__); __func__);
} }
if (termios->c_cflag & CSTOPB) /* Anomaly notes:
lcr |= STB; * 05000231 - STOP bit is always set to 1 whatever the user is set.
*/
if (termios->c_cflag & CSTOPB) {
if (ANOMALY_05000231)
printk(KERN_WARNING "STOP bits other than 1 is not "
"supported in case of anomaly 05000231.\n");
else
lcr |= STB;
}
if (termios->c_cflag & PARENB) if (termios->c_cflag & PARENB)
lcr |= PEN; lcr |= PEN;
if (!(termios->c_cflag & PARODD)) if (!(termios->c_cflag & PARODD))
...@@ -940,6 +988,10 @@ static void bfin_serial_reset_irda(struct uart_port *port) ...@@ -940,6 +988,10 @@ static void bfin_serial_reset_irda(struct uart_port *port)
} }
#ifdef CONFIG_CONSOLE_POLL #ifdef CONFIG_CONSOLE_POLL
/* Anomaly notes:
* 05000099 - Because we only use THRE in poll_put and DR in poll_get,
* losing other bits of UART_LSR is not a problem here.
*/
static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr) static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr)
{ {
struct bfin_serial_port *uart = (struct bfin_serial_port *)port; struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
...@@ -1245,12 +1297,17 @@ static __init void early_serial_write(struct console *con, const char *s, ...@@ -1245,12 +1297,17 @@ static __init void early_serial_write(struct console *con, const char *s,
} }
} }
/*
* This should have a .setup or .early_setup in it, but then things get called
* without the command line options, and the baud rate gets messed up - so
* don't let the common infrastructure play with things. (see calls to setup
* & earlysetup in ./kernel/printk.c:register_console()
*/
static struct __initdata console bfin_early_serial_console = { static struct __initdata console bfin_early_serial_console = {
.name = "early_BFuart", .name = "early_BFuart",
.write = early_serial_write, .write = early_serial_write,
.device = uart_console_device, .device = uart_console_device,
.flags = CON_PRINTBUFFER, .flags = CON_PRINTBUFFER,
.setup = bfin_serial_console_setup,
.index = -1, .index = -1,
.data = &bfin_serial_reg, .data = &bfin_serial_reg,
}; };
......
...@@ -101,15 +101,16 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value) ...@@ -101,15 +101,16 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
{ {
pr_debug("%s value:%x\n", __func__, value); pr_debug("%s value:%x\n", __func__, value);
/* Place a Start and Stop bit */ /* Place a Start and Stop bit */
__asm__ volatile ( __asm__ __volatile__ (
"R2 = b#01111111100;\n\t" "R2 = b#01111111100;"
"R3 = b#10000000001;\n\t" "R3 = b#10000000001;"
"%0 <<= 2;\n\t" "%0 <<= 2;"
"%0 = %0 & R2;\n\t" "%0 = %0 & R2;"
"%0 = %0 | R3;\n\t" "%0 = %0 | R3;"
:"=r"(value) : "=d"(value)
:"0"(value) : "d"(value)
:"R2", "R3"); : "ASTAT", "R2", "R3"
);
pr_debug("%s value:%x\n", __func__, value); pr_debug("%s value:%x\n", __func__, value);
SPORT_PUT_TX(up, value); SPORT_PUT_TX(up, value);
...@@ -118,27 +119,30 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value) ...@@ -118,27 +119,30 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
static inline unsigned int rx_one_byte(struct sport_uart_port *up) static inline unsigned int rx_one_byte(struct sport_uart_port *up)
{ {
unsigned int value, extract; unsigned int value, extract;
u32 tmp_mask1, tmp_mask2, tmp_shift, tmp;
value = SPORT_GET_RX32(up); value = SPORT_GET_RX32(up);
pr_debug("%s value:%x\n", __func__, value); pr_debug("%s value:%x\n", __func__, value);
/* Extract 8 bits data */ /* Extract 8 bits data */
__asm__ volatile ( __asm__ __volatile__ (
"R5 = 0;\n\t" "%[extr] = 0;"
"P0 = 8;\n\t" "%[mask1] = 0x1801(Z);"
"R1 = 0x1801(Z);\n\t" "%[mask2] = 0x0300(Z);"
"R3 = 0x0300(Z);\n\t" "%[shift] = 0;"
"R4 = 0;\n\t" "LSETUP(.Lloop_s, .Lloop_e) LC0 = %[lc];"
"LSETUP(loop_s, loop_e) LC0 = P0;\nloop_s:\t" ".Lloop_s:"
"R2 = extract(%1, R1.L)(Z);\n\t" "%[tmp] = extract(%[val], %[mask1].L)(Z);"
"R2 <<= R4;\n\t" "%[tmp] <<= %[shift];"
"R5 = R5 | R2;\n\t" "%[extr] = %[extr] | %[tmp];"
"R1 = R1 - R3;\nloop_e:\t" "%[mask1] = %[mask1] - %[mask2];"
"R4 += 1;\n\t" ".Lloop_e:"
"%0 = R5;\n\t" "%[shift] += 1;"
:"=r"(extract) : [val]"=d"(value), [extr]"=d"(extract), [shift]"=d"(tmp_shift), [tmp]"=d"(tmp),
:"r"(value) [mask1]"=d"(tmp_mask1), [mask2]"=d"(tmp_mask2)
:"P0", "R1", "R2","R3","R4", "R5"); : "d"(value), [lc]"a"(8)
: "ASTAT", "LB0", "LC0", "LT0"
);
pr_debug(" extract:%x\n", extract); pr_debug(" extract:%x\n", extract);
return extract; return extract;
...@@ -149,7 +153,7 @@ static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate) ...@@ -149,7 +153,7 @@ static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate)
int tclkdiv, tfsdiv, rclkdiv; int tclkdiv, tfsdiv, rclkdiv;
/* Set TCR1 and TCR2 */ /* Set TCR1 and TCR2 */
SPORT_PUT_TCR1(up, (LTFS | ITFS | TFSR | TLSBIT | ITCLK)); SPORT_PUT_TCR1(up, (LATFS | ITFS | TFSR | TLSBIT | ITCLK));
SPORT_PUT_TCR2(up, 10); SPORT_PUT_TCR2(up, 10);
pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up)); pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up));
...@@ -419,7 +423,7 @@ static void sport_shutdown(struct uart_port *port) ...@@ -419,7 +423,7 @@ static void sport_shutdown(struct uart_port *port)
} }
static void sport_set_termios(struct uart_port *port, static void sport_set_termios(struct uart_port *port,
struct termios *termios, struct termios *old) struct ktermios *termios, struct ktermios *old)
{ {
pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag); pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag);
uart_update_timeout(port, CS8 ,port->uartclk); uart_update_timeout(port, CS8 ,port->uartclk);
......
...@@ -137,7 +137,12 @@ static LIST_HEAD(icom_adapter_head); ...@@ -137,7 +137,12 @@ static LIST_HEAD(icom_adapter_head);
static spinlock_t icom_lock; static spinlock_t icom_lock;
#ifdef ICOM_TRACE #ifdef ICOM_TRACE
static inline void trace(struct icom_port *, char *, unsigned long) {}; static inline void trace(struct icom_port *icom_port, char *trace_pt,
unsigned long trace_data)
{
dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n",
icom_port->port, trace_pt, trace_data);
}
#else #else
static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {}; static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {};
#endif #endif
...@@ -408,7 +413,7 @@ static void load_code(struct icom_port *icom_port) ...@@ -408,7 +413,7 @@ static void load_code(struct icom_port *icom_port)
release_firmware(fw); release_firmware(fw);
/* Set Hardware level */ /* Set Hardware level */
if ((icom_port->adapter->version | ADAPTER_V2) == ADAPTER_V2) if (icom_port->adapter->version == ADAPTER_V2)
writeb(V2_HARDWARE, &(icom_port->dram->misc_flags)); writeb(V2_HARDWARE, &(icom_port->dram->misc_flags));
/* Start the processor in Adapter */ /* Start the processor in Adapter */
...@@ -861,7 +866,7 @@ static irqreturn_t icom_interrupt(int irq, void *dev_id) ...@@ -861,7 +866,7 @@ static irqreturn_t icom_interrupt(int irq, void *dev_id)
/* find icom_port for this interrupt */ /* find icom_port for this interrupt */
icom_adapter = (struct icom_adapter *) dev_id; icom_adapter = (struct icom_adapter *) dev_id;
if ((icom_adapter->version | ADAPTER_V2) == ADAPTER_V2) { if (icom_adapter->version == ADAPTER_V2) {
int_reg = icom_adapter->base_addr + 0x8024; int_reg = icom_adapter->base_addr + 0x8024;
adapter_interrupts = readl(int_reg); adapter_interrupts = readl(int_reg);
...@@ -1647,15 +1652,6 @@ static void __exit icom_exit(void) ...@@ -1647,15 +1652,6 @@ static void __exit icom_exit(void)
module_init(icom_init); module_init(icom_init);
module_exit(icom_exit); module_exit(icom_exit);
#ifdef ICOM_TRACE
static inline void trace(struct icom_port *icom_port, char *trace_pt,
unsigned long trace_data)
{
dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n",
icom_port->port, trace_pt, trace_data);
}
#endif
MODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>"); MODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>");
MODULE_DESCRIPTION("IBM iSeries Serial IOA driver"); MODULE_DESCRIPTION("IBM iSeries Serial IOA driver");
MODULE_SUPPORTED_DEVICE MODULE_SUPPORTED_DEVICE
......
...@@ -8,6 +8,9 @@ ...@@ -8,6 +8,9 @@
* Author: Sascha Hauer <sascha@saschahauer.de> * Author: Sascha Hauer <sascha@saschahauer.de>
* Copyright (C) 2004 Pengutronix * Copyright (C) 2004 Pengutronix
* *
* Copyright (C) 2009 emlix GmbH
* Author: Fabian Godehardt (added IrDA support for iMX)
*
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
...@@ -41,6 +44,8 @@ ...@@ -41,6 +44,8 @@
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/serial.h> #include <linux/serial.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h>
#include <linux/rational.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -148,6 +153,7 @@ ...@@ -148,6 +153,7 @@
#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ #define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */
#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ #define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */
#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ #define UFCR_RFDIV (7<<7) /* Reference freq divider mask */
#define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7)
#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */ #define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */
#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */ #define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */
#define USR1_RTSS (1<<14) /* RTS pin status */ #define USR1_RTSS (1<<14) /* RTS pin status */
...@@ -211,10 +217,20 @@ struct imx_port { ...@@ -211,10 +217,20 @@ struct imx_port {
struct timer_list timer; struct timer_list timer;
unsigned int old_status; unsigned int old_status;
int txirq,rxirq,rtsirq; int txirq,rxirq,rtsirq;
int have_rtscts:1; unsigned int have_rtscts:1;
unsigned int use_irda:1;
unsigned int irda_inv_rx:1;
unsigned int irda_inv_tx:1;
unsigned short trcv_delay; /* transceiver delay */
struct clk *clk; struct clk *clk;
}; };
#ifdef CONFIG_IRDA
#define USE_IRDA(sport) ((sport)->use_irda)
#else
#define USE_IRDA(sport) (0)
#endif
/* /*
* Handle any change of modem status signal since we were last called. * Handle any change of modem status signal since we were last called.
*/ */
...@@ -268,6 +284,48 @@ static void imx_stop_tx(struct uart_port *port) ...@@ -268,6 +284,48 @@ static void imx_stop_tx(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = (struct imx_port *)port;
unsigned long temp; unsigned long temp;
if (USE_IRDA(sport)) {
/* half duplex - wait for end of transmission */
int n = 256;
while ((--n > 0) &&
!(readl(sport->port.membase + USR2) & USR2_TXDC)) {
udelay(5);
barrier();
}
/*
* irda transceiver - wait a bit more to avoid
* cutoff, hardware dependent
*/
udelay(sport->trcv_delay);
/*
* half duplex - reactivate receive mode,
* flush receive pipe echo crap
*/
if (readl(sport->port.membase + USR2) & USR2_TXDC) {
temp = readl(sport->port.membase + UCR1);
temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN);
writel(temp, sport->port.membase + UCR1);
temp = readl(sport->port.membase + UCR4);
temp &= ~(UCR4_TCEN);
writel(temp, sport->port.membase + UCR4);
while (readl(sport->port.membase + URXD0) &
URXD_CHARRDY)
barrier();
temp = readl(sport->port.membase + UCR1);
temp |= UCR1_RRDYEN;
writel(temp, sport->port.membase + UCR1);
temp = readl(sport->port.membase + UCR4);
temp |= UCR4_DREN;
writel(temp, sport->port.membase + UCR4);
}
return;
}
temp = readl(sport->port.membase + UCR1); temp = readl(sport->port.membase + UCR1);
writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);
} }
...@@ -302,13 +360,15 @@ static inline void imx_transmit_buffer(struct imx_port *sport) ...@@ -302,13 +360,15 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
/* send xmit->buf[xmit->tail] /* send xmit->buf[xmit->tail]
* out the port here */ * out the port here */
writel(xmit->buf[xmit->tail], sport->port.membase + URTX0); writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);
xmit->tail = (xmit->tail + 1) & xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
(UART_XMIT_SIZE - 1);
sport->port.icount.tx++; sport->port.icount.tx++;
if (uart_circ_empty(xmit)) if (uart_circ_empty(xmit))
break; break;
} }
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&sport->port);
if (uart_circ_empty(xmit)) if (uart_circ_empty(xmit))
imx_stop_tx(&sport->port); imx_stop_tx(&sport->port);
} }
...@@ -321,9 +381,30 @@ static void imx_start_tx(struct uart_port *port) ...@@ -321,9 +381,30 @@ static void imx_start_tx(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = (struct imx_port *)port;
unsigned long temp; unsigned long temp;
if (USE_IRDA(sport)) {
/* half duplex in IrDA mode; have to disable receive mode */
temp = readl(sport->port.membase + UCR4);
temp &= ~(UCR4_DREN);
writel(temp, sport->port.membase + UCR4);
temp = readl(sport->port.membase + UCR1);
temp &= ~(UCR1_RRDYEN);
writel(temp, sport->port.membase + UCR1);
}
temp = readl(sport->port.membase + UCR1); temp = readl(sport->port.membase + UCR1);
writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
if (USE_IRDA(sport)) {
temp = readl(sport->port.membase + UCR1);
temp |= UCR1_TRDYEN;
writel(temp, sport->port.membase + UCR1);
temp = readl(sport->port.membase + UCR4);
temp |= UCR4_TCEN;
writel(temp, sport->port.membase + UCR4);
}
if (readl(sport->port.membase + UTS) & UTS_TXEMPTY) if (readl(sport->port.membase + UTS) & UTS_TXEMPTY)
imx_transmit_buffer(sport); imx_transmit_buffer(sport);
} }
...@@ -395,8 +476,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) ...@@ -395,8 +476,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
continue; continue;
} }
if (uart_handle_sysrq_char if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
(&sport->port, (unsigned char)rx))
continue; continue;
if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) { if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) {
...@@ -471,26 +551,26 @@ static unsigned int imx_tx_empty(struct uart_port *port) ...@@ -471,26 +551,26 @@ static unsigned int imx_tx_empty(struct uart_port *port)
*/ */
static unsigned int imx_get_mctrl(struct uart_port *port) static unsigned int imx_get_mctrl(struct uart_port *port)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = (struct imx_port *)port;
unsigned int tmp = TIOCM_DSR | TIOCM_CAR; unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
if (readl(sport->port.membase + USR1) & USR1_RTSS) if (readl(sport->port.membase + USR1) & USR1_RTSS)
tmp |= TIOCM_CTS; tmp |= TIOCM_CTS;
if (readl(sport->port.membase + UCR2) & UCR2_CTS) if (readl(sport->port.membase + UCR2) & UCR2_CTS)
tmp |= TIOCM_RTS; tmp |= TIOCM_RTS;
return tmp; return tmp;
} }
static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
{ {
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = (struct imx_port *)port;
unsigned long temp; unsigned long temp;
temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS; temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS;
if (mctrl & TIOCM_RTS) if (mctrl & TIOCM_RTS)
temp |= UCR2_CTS; temp |= UCR2_CTS;
writel(temp, sport->port.membase + UCR2); writel(temp, sport->port.membase + UCR2);
...@@ -534,12 +614,7 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) ...@@ -534,12 +614,7 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
if(!ufcr_rfdiv) if(!ufcr_rfdiv)
ufcr_rfdiv = 1; ufcr_rfdiv = 1;
if(ufcr_rfdiv >= 7) val |= UFCR_RFDIV_REG(ufcr_rfdiv);
ufcr_rfdiv = 6;
else
ufcr_rfdiv = 6 - ufcr_rfdiv;
val |= UFCR_RFDIV & (ufcr_rfdiv << 7);
writel(val, sport->port.membase + UFCR); writel(val, sport->port.membase + UFCR);
...@@ -558,8 +633,24 @@ static int imx_startup(struct uart_port *port) ...@@ -558,8 +633,24 @@ static int imx_startup(struct uart_port *port)
* requesting IRQs * requesting IRQs
*/ */
temp = readl(sport->port.membase + UCR4); temp = readl(sport->port.membase + UCR4);
if (USE_IRDA(sport))
temp |= UCR4_IRSC;
writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
if (USE_IRDA(sport)) {
/* reset fifo's and state machines */
int i = 100;
temp = readl(sport->port.membase + UCR2);
temp &= ~UCR2_SRST;
writel(temp, sport->port.membase + UCR2);
while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) &&
(--i > 0)) {
udelay(1);
}
}
/* /*
* Allocate the IRQ(s) i.MX1 has three interrupts whereas later * Allocate the IRQ(s) i.MX1 has three interrupts whereas later
* chips only have one interrupt. * chips only have one interrupt.
...@@ -575,12 +666,16 @@ static int imx_startup(struct uart_port *port) ...@@ -575,12 +666,16 @@ static int imx_startup(struct uart_port *port)
if (retval) if (retval)
goto error_out2; goto error_out2;
retval = request_irq(sport->rtsirq, imx_rtsint, /* do not use RTS IRQ on IrDA */
(sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 : if (!USE_IRDA(sport)) {
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, retval = request_irq(sport->rtsirq, imx_rtsint,
DRIVER_NAME, sport); (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 :
if (retval) IRQF_TRIGGER_FALLING |
goto error_out3; IRQF_TRIGGER_RISING,
DRIVER_NAME, sport);
if (retval)
goto error_out3;
}
} else { } else {
retval = request_irq(sport->port.irq, imx_int, 0, retval = request_irq(sport->port.irq, imx_int, 0,
DRIVER_NAME, sport); DRIVER_NAME, sport);
...@@ -597,18 +692,49 @@ static int imx_startup(struct uart_port *port) ...@@ -597,18 +692,49 @@ static int imx_startup(struct uart_port *port)
temp = readl(sport->port.membase + UCR1); temp = readl(sport->port.membase + UCR1);
temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
if (USE_IRDA(sport)) {
temp |= UCR1_IREN;
temp &= ~(UCR1_RTSDEN);
}
writel(temp, sport->port.membase + UCR1); writel(temp, sport->port.membase + UCR1);
temp = readl(sport->port.membase + UCR2); temp = readl(sport->port.membase + UCR2);
temp |= (UCR2_RXEN | UCR2_TXEN); temp |= (UCR2_RXEN | UCR2_TXEN);
writel(temp, sport->port.membase + UCR2); writel(temp, sport->port.membase + UCR2);
if (USE_IRDA(sport)) {
/* clear RX-FIFO */
int i = 64;
while ((--i > 0) &&
(readl(sport->port.membase + URXD0) & URXD_CHARRDY)) {
barrier();
}
}
#if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3 #if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3
temp = readl(sport->port.membase + UCR3); temp = readl(sport->port.membase + UCR3);
temp |= UCR3_RXDMUXSEL; temp |= UCR3_RXDMUXSEL;
writel(temp, sport->port.membase + UCR3); writel(temp, sport->port.membase + UCR3);
#endif #endif
if (USE_IRDA(sport)) {
temp = readl(sport->port.membase + UCR4);
if (sport->irda_inv_rx)
temp |= UCR4_INVR;
else
temp &= ~(UCR4_INVR);
writel(temp | UCR4_DREN, sport->port.membase + UCR4);
temp = readl(sport->port.membase + UCR3);
if (sport->irda_inv_tx)
temp |= UCR3_INVT;
else
temp &= ~(UCR3_INVT);
writel(temp, sport->port.membase + UCR3);
}
/* /*
* Enable modem status interrupts * Enable modem status interrupts
*/ */
...@@ -616,6 +742,16 @@ static int imx_startup(struct uart_port *port) ...@@ -616,6 +742,16 @@ static int imx_startup(struct uart_port *port)
imx_enable_ms(&sport->port); imx_enable_ms(&sport->port);
spin_unlock_irqrestore(&sport->port.lock,flags); spin_unlock_irqrestore(&sport->port.lock,flags);
if (USE_IRDA(sport)) {
struct imxuart_platform_data *pdata;
pdata = sport->port.dev->platform_data;
sport->irda_inv_rx = pdata->irda_inv_rx;
sport->irda_inv_tx = pdata->irda_inv_tx;
sport->trcv_delay = pdata->transceiver_delay;
if (pdata->irda_enable)
pdata->irda_enable(1);
}
return 0; return 0;
error_out3: error_out3:
...@@ -633,6 +769,17 @@ static void imx_shutdown(struct uart_port *port) ...@@ -633,6 +769,17 @@ static void imx_shutdown(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port; struct imx_port *sport = (struct imx_port *)port;
unsigned long temp; unsigned long temp;
temp = readl(sport->port.membase + UCR2);
temp &= ~(UCR2_TXEN);
writel(temp, sport->port.membase + UCR2);
if (USE_IRDA(sport)) {
struct imxuart_platform_data *pdata;
pdata = sport->port.dev->platform_data;
if (pdata->irda_enable)
pdata->irda_enable(0);
}
/* /*
* Stop our timer. * Stop our timer.
*/ */
...@@ -642,7 +789,8 @@ static void imx_shutdown(struct uart_port *port) ...@@ -642,7 +789,8 @@ static void imx_shutdown(struct uart_port *port)
* Free the interrupts * Free the interrupts
*/ */
if (sport->txirq > 0) { if (sport->txirq > 0) {
free_irq(sport->rtsirq, sport); if (!USE_IRDA(sport))
free_irq(sport->rtsirq, sport);
free_irq(sport->txirq, sport); free_irq(sport->txirq, sport);
free_irq(sport->rxirq, sport); free_irq(sport->rxirq, sport);
} else } else
...@@ -654,6 +802,9 @@ static void imx_shutdown(struct uart_port *port) ...@@ -654,6 +802,9 @@ static void imx_shutdown(struct uart_port *port)
temp = readl(sport->port.membase + UCR1); temp = readl(sport->port.membase + UCR1);
temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
if (USE_IRDA(sport))
temp &= ~(UCR1_IREN);
writel(temp, sport->port.membase + UCR1); writel(temp, sport->port.membase + UCR1);
} }
...@@ -665,7 +816,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, ...@@ -665,7 +816,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned long flags; unsigned long flags;
unsigned int ucr2, old_ucr1, old_txrxen, baud, quot; unsigned int ucr2, old_ucr1, old_txrxen, baud, quot;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
unsigned int div, num, denom, ufcr; unsigned int div, ufcr;
unsigned long num, denom;
uint64_t tdiv64;
/* /*
* If we don't support modem control lines, don't allow * If we don't support modem control lines, don't allow
...@@ -761,38 +914,39 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, ...@@ -761,38 +914,39 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
sport->port.membase + UCR2); sport->port.membase + UCR2);
old_txrxen &= (UCR2_TXEN | UCR2_RXEN); old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
div = sport->port.uartclk / (baud * 16); if (USE_IRDA(sport)) {
if (div > 7) /*
div = 7; * use maximum available submodule frequency to
if (!div) * avoid missing short pulses due to low sampling rate
*/
div = 1; div = 1;
} else {
num = baud; div = sport->port.uartclk / (baud * 16);
denom = port->uartclk / div / 16; if (div > 7)
div = 7;
/* shift num and denom right until they fit into 16 bits */ if (!div)
while (num > 0x10000 || denom > 0x10000) { div = 1;
num >>= 1;
denom >>= 1;
} }
if (num > 0)
num -= 1;
if (denom > 0)
denom -= 1;
writel(num, sport->port.membase + UBIR); rational_best_approximation(16 * div * baud, sport->port.uartclk,
writel(denom, sport->port.membase + UBMR); 1 << 16, 1 << 16, &num, &denom);
if (div == 7) tdiv64 = sport->port.uartclk;
div = 6; /* 6 in RFDIV means divide by 7 */ tdiv64 *= num;
else do_div(tdiv64, denom * 16 * div);
div = 6 - div; tty_encode_baud_rate(sport->port.info->port.tty,
(speed_t)tdiv64, (speed_t)tdiv64);
num -= 1;
denom -= 1;
ufcr = readl(sport->port.membase + UFCR); ufcr = readl(sport->port.membase + UFCR);
ufcr = (ufcr & (~UFCR_RFDIV)) | ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div);
(div << 7);
writel(ufcr, sport->port.membase + UFCR); writel(ufcr, sport->port.membase + UFCR);
writel(num, sport->port.membase + UBIR);
writel(denom, sport->port.membase + UBMR);
#ifdef ONEMS #ifdef ONEMS
writel(sport->port.uartclk / div / 1000, sport->port.membase + ONEMS); writel(sport->port.uartclk / div / 1000, sport->port.membase + ONEMS);
#endif #endif
...@@ -1072,22 +1226,22 @@ static struct uart_driver imx_reg = { ...@@ -1072,22 +1226,22 @@ static struct uart_driver imx_reg = {
static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) static int serial_imx_suspend(struct platform_device *dev, pm_message_t state)
{ {
struct imx_port *sport = platform_get_drvdata(dev); struct imx_port *sport = platform_get_drvdata(dev);
if (sport) if (sport)
uart_suspend_port(&imx_reg, &sport->port); uart_suspend_port(&imx_reg, &sport->port);
return 0; return 0;
} }
static int serial_imx_resume(struct platform_device *dev) static int serial_imx_resume(struct platform_device *dev)
{ {
struct imx_port *sport = platform_get_drvdata(dev); struct imx_port *sport = platform_get_drvdata(dev);
if (sport) if (sport)
uart_resume_port(&imx_reg, &sport->port); uart_resume_port(&imx_reg, &sport->port);
return 0; return 0;
} }
static int serial_imx_probe(struct platform_device *pdev) static int serial_imx_probe(struct platform_device *pdev)
...@@ -1143,19 +1297,29 @@ static int serial_imx_probe(struct platform_device *pdev) ...@@ -1143,19 +1297,29 @@ static int serial_imx_probe(struct platform_device *pdev)
imx_ports[pdev->id] = sport; imx_ports[pdev->id] = sport;
pdata = pdev->dev.platform_data; pdata = pdev->dev.platform_data;
if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS)) if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
sport->have_rtscts = 1; sport->have_rtscts = 1;
#ifdef CONFIG_IRDA
if (pdata && (pdata->flags & IMXUART_IRDA))
sport->use_irda = 1;
#endif
if (pdata->init) { if (pdata->init) {
ret = pdata->init(pdev); ret = pdata->init(pdev);
if (ret) if (ret)
goto clkput; goto clkput;
} }
uart_add_one_port(&imx_reg, &sport->port); ret = uart_add_one_port(&imx_reg, &sport->port);
if (ret)
goto deinit;
platform_set_drvdata(pdev, &sport->port); platform_set_drvdata(pdev, &sport->port);
return 0; return 0;
deinit:
if (pdata->exit)
pdata->exit(pdev);
clkput: clkput:
clk_put(sport->clk); clk_put(sport->clk);
clk_disable(sport->clk); clk_disable(sport->clk);
...@@ -1193,13 +1357,13 @@ static int serial_imx_remove(struct platform_device *pdev) ...@@ -1193,13 +1357,13 @@ static int serial_imx_remove(struct platform_device *pdev)
} }
static struct platform_driver serial_imx_driver = { static struct platform_driver serial_imx_driver = {
.probe = serial_imx_probe, .probe = serial_imx_probe,
.remove = serial_imx_remove, .remove = serial_imx_remove,
.suspend = serial_imx_suspend, .suspend = serial_imx_suspend,
.resume = serial_imx_resume, .resume = serial_imx_resume,
.driver = { .driver = {
.name = "imx-uart", .name = "imx-uart",
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
}; };
......
...@@ -61,6 +61,7 @@ enum { ...@@ -61,6 +61,7 @@ enum {
if ((DBG_##nlevel & jsm_debug)) \ if ((DBG_##nlevel & jsm_debug)) \
dev_printk(KERN_##klevel, pdev->dev, fmt, ## args) dev_printk(KERN_##klevel, pdev->dev, fmt, ## args)
#define MAXLINES 256
#define MAXPORTS 8 #define MAXPORTS 8
#define MAX_STOPS_SENT 5 #define MAX_STOPS_SENT 5
......
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#include "jsm.h" #include "jsm.h"
static DECLARE_BITMAP(linemap, MAXLINES);
static void jsm_carrier(struct jsm_channel *ch); static void jsm_carrier(struct jsm_channel *ch);
static inline int jsm_get_mstat(struct jsm_channel *ch) static inline int jsm_get_mstat(struct jsm_channel *ch)
...@@ -433,6 +435,7 @@ int __devinit jsm_tty_init(struct jsm_board *brd) ...@@ -433,6 +435,7 @@ int __devinit jsm_tty_init(struct jsm_board *brd)
int __devinit jsm_uart_port_init(struct jsm_board *brd) int __devinit jsm_uart_port_init(struct jsm_board *brd)
{ {
int i; int i;
unsigned int line;
struct jsm_channel *ch; struct jsm_channel *ch;
if (!brd) if (!brd)
...@@ -459,9 +462,15 @@ int __devinit jsm_uart_port_init(struct jsm_board *brd) ...@@ -459,9 +462,15 @@ int __devinit jsm_uart_port_init(struct jsm_board *brd)
brd->channels[i]->uart_port.membase = brd->re_map_membase; brd->channels[i]->uart_port.membase = brd->re_map_membase;
brd->channels[i]->uart_port.fifosize = 16; brd->channels[i]->uart_port.fifosize = 16;
brd->channels[i]->uart_port.ops = &jsm_ops; brd->channels[i]->uart_port.ops = &jsm_ops;
brd->channels[i]->uart_port.line = brd->channels[i]->ch_portnum + brd->boardnum * 2; line = find_first_zero_bit(linemap, MAXLINES);
if (line >= MAXLINES) {
printk(KERN_INFO "jsm: linemap is full, added device failed\n");
continue;
} else
set_bit((int)line, linemap);
brd->channels[i]->uart_port.line = line;
if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port)) if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port))
printk(KERN_INFO "Added device failed\n"); printk(KERN_INFO "jsm: add device failed\n");
else else
printk(KERN_INFO "Added device \n"); printk(KERN_INFO "Added device \n");
} }
...@@ -494,6 +503,7 @@ int jsm_remove_uart_port(struct jsm_board *brd) ...@@ -494,6 +503,7 @@ int jsm_remove_uart_port(struct jsm_board *brd)
ch = brd->channels[i]; ch = brd->channels[i];
clear_bit((int)(ch->uart_port.line), linemap);
uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port); uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port);
} }
......
/*
* timbuart.c timberdale FPGA UART driver
* Copyright (c) 2009 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Supports:
* Timberdale FPGA UART
*/
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/serial_core.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include "timbuart.h"
struct timbuart_port {
struct uart_port port;
struct tasklet_struct tasklet;
int usedma;
u8 last_ier;
struct platform_device *dev;
};
static int baudrates[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800,
921600, 1843200, 3250000};
static void timbuart_mctrl_check(struct uart_port *port, u8 isr, u8 *ier);
static irqreturn_t timbuart_handleinterrupt(int irq, void *devid);
static void timbuart_stop_rx(struct uart_port *port)
{
/* spin lock held by upper layer, disable all RX interrupts */
u8 ier = ioread8(port->membase + TIMBUART_IER) & ~RXFLAGS;
iowrite8(ier, port->membase + TIMBUART_IER);
}
static void timbuart_stop_tx(struct uart_port *port)
{
/* spinlock held by upper layer, disable TX interrupt */
u8 ier = ioread8(port->membase + TIMBUART_IER) & ~TXBAE;
iowrite8(ier, port->membase + TIMBUART_IER);
}
static void timbuart_start_tx(struct uart_port *port)
{
struct timbuart_port *uart =
container_of(port, struct timbuart_port, port);
/* do not transfer anything here -> fire off the tasklet */
tasklet_schedule(&uart->tasklet);
}
static void timbuart_flush_buffer(struct uart_port *port)
{
u8 ctl = ioread8(port->membase + TIMBUART_CTRL) | TIMBUART_CTRL_FLSHTX;
iowrite8(ctl, port->membase + TIMBUART_CTRL);
iowrite8(TXBF, port->membase + TIMBUART_ISR);
}
static void timbuart_rx_chars(struct uart_port *port)
{
struct tty_struct *tty = port->info->port.tty;
while (ioread8(port->membase + TIMBUART_ISR) & RXDP) {
u8 ch = ioread8(port->membase + TIMBUART_RXFIFO);
port->icount.rx++;
tty_insert_flip_char(tty, ch, TTY_NORMAL);
}
spin_unlock(&port->lock);
tty_flip_buffer_push(port->info->port.tty);
spin_lock(&port->lock);
dev_dbg(port->dev, "%s - total read %d bytes\n",
__func__, port->icount.rx);
}
static void timbuart_tx_chars(struct uart_port *port)
{
struct circ_buf *xmit = &port->info->xmit;
while (!(ioread8(port->membase + TIMBUART_ISR) & TXBF) &&
!uart_circ_empty(xmit)) {
iowrite8(xmit->buf[xmit->tail],
port->membase + TIMBUART_TXFIFO);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
}
dev_dbg(port->dev,
"%s - total written %d bytes, CTL: %x, RTS: %x, baud: %x\n",
__func__,
port->icount.tx,
ioread8(port->membase + TIMBUART_CTRL),
port->mctrl & TIOCM_RTS,
ioread8(port->membase + TIMBUART_BAUDRATE));
}
static void timbuart_handle_tx_port(struct uart_port *port, u8 isr, u8 *ier)
{
struct timbuart_port *uart =
container_of(port, struct timbuart_port, port);
struct circ_buf *xmit = &port->info->xmit;
if (uart_circ_empty(xmit) || uart_tx_stopped(port))
return;
if (port->x_char)
return;
if (isr & TXFLAGS) {
timbuart_tx_chars(port);
/* clear all TX interrupts */
iowrite8(TXFLAGS, port->membase + TIMBUART_ISR);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
} else
/* Re-enable any tx interrupt */
*ier |= uart->last_ier & TXFLAGS;
/* enable interrupts if there are chars in the transmit buffer,
* Or if we delivered some bytes and want the almost empty interrupt
* we wake up the upper layer later when we got the interrupt
* to give it some time to go out...
*/
if (!uart_circ_empty(xmit))
*ier |= TXBAE;
dev_dbg(port->dev, "%s - leaving\n", __func__);
}
void timbuart_handle_rx_port(struct uart_port *port, u8 isr, u8 *ier)
{
if (isr & RXFLAGS) {
/* Some RX status is set */
if (isr & RXBF) {
u8 ctl = ioread8(port->membase + TIMBUART_CTRL) |
TIMBUART_CTRL_FLSHRX;
iowrite8(ctl, port->membase + TIMBUART_CTRL);
port->icount.overrun++;
} else if (isr & (RXDP))
timbuart_rx_chars(port);
/* ack all RX interrupts */
iowrite8(RXFLAGS, port->membase + TIMBUART_ISR);
}
/* always have the RX interrupts enabled */
*ier |= RXBAF | RXBF | RXTT;
dev_dbg(port->dev, "%s - leaving\n", __func__);
}
void timbuart_tasklet(unsigned long arg)
{
struct timbuart_port *uart = (struct timbuart_port *)arg;
u8 isr, ier = 0;
spin_lock(&uart->port.lock);
isr = ioread8(uart->port.membase + TIMBUART_ISR);
dev_dbg(uart->port.dev, "%s ISR: %x\n", __func__, isr);
if (!uart->usedma)
timbuart_handle_tx_port(&uart->port, isr, &ier);
timbuart_mctrl_check(&uart->port, isr, &ier);
if (!uart->usedma)
timbuart_handle_rx_port(&uart->port, isr, &ier);
iowrite8(ier, uart->port.membase + TIMBUART_IER);
spin_unlock(&uart->port.lock);
dev_dbg(uart->port.dev, "%s leaving\n", __func__);
}
static unsigned int timbuart_tx_empty(struct uart_port *port)
{
u8 isr = ioread8(port->membase + TIMBUART_ISR);
return (isr & TXBAE) ? TIOCSER_TEMT : 0;
}
static unsigned int timbuart_get_mctrl(struct uart_port *port)
{
u8 cts = ioread8(port->membase + TIMBUART_CTRL);
dev_dbg(port->dev, "%s - cts %x\n", __func__, cts);
if (cts & TIMBUART_CTRL_CTS)
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
else
return TIOCM_DSR | TIOCM_CAR;
}
static void timbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
dev_dbg(port->dev, "%s - %x\n", __func__, mctrl);
if (mctrl & TIOCM_RTS)
iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL);
else
iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL);
}
static void timbuart_mctrl_check(struct uart_port *port, u8 isr, u8 *ier)
{
unsigned int cts;
if (isr & CTS_DELTA) {
/* ack */
iowrite8(CTS_DELTA, port->membase + TIMBUART_ISR);
cts = timbuart_get_mctrl(port);
uart_handle_cts_change(port, cts & TIOCM_CTS);
wake_up_interruptible(&port->info->delta_msr_wait);
}
*ier |= CTS_DELTA;
}
static void timbuart_enable_ms(struct uart_port *port)
{
/* N/A */
}
static void timbuart_break_ctl(struct uart_port *port, int ctl)
{
/* N/A */
}
static int timbuart_startup(struct uart_port *port)
{
struct timbuart_port *uart =
container_of(port, struct timbuart_port, port);
dev_dbg(port->dev, "%s\n", __func__);
iowrite8(TIMBUART_CTRL_FLSHRX, port->membase + TIMBUART_CTRL);
iowrite8(0xff, port->membase + TIMBUART_ISR);
/* Enable all but TX interrupts */
iowrite8(RXBAF | RXBF | RXTT | CTS_DELTA,
port->membase + TIMBUART_IER);
return request_irq(port->irq, timbuart_handleinterrupt, IRQF_SHARED,
"timb-uart", uart);
}
static void timbuart_shutdown(struct uart_port *port)
{
struct timbuart_port *uart =
container_of(port, struct timbuart_port, port);
dev_dbg(port->dev, "%s\n", __func__);
free_irq(port->irq, uart);
iowrite8(0, port->membase + TIMBUART_IER);
}
static int get_bindex(int baud)
{
int i;
for (i = 0; i < ARRAY_SIZE(baudrates); i++)
if (baud <= baudrates[i])
return i;
return -1;
}
static void timbuart_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
unsigned int baud;
short bindex;
unsigned long flags;
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
bindex = get_bindex(baud);
dev_dbg(port->dev, "%s - bindex %d\n", __func__, bindex);
if (bindex < 0)
bindex = 0;
baud = baudrates[bindex];
/* The serial layer calls into this once with old = NULL when setting
up initially */
if (old)
tty_termios_copy_hw(termios, old);
tty_termios_encode_baud_rate(termios, baud, baud);
spin_lock_irqsave(&port->lock, flags);
iowrite8((u8)bindex, port->membase + TIMBUART_BAUDRATE);
uart_update_timeout(port, termios->c_cflag, baud);
spin_unlock_irqrestore(&port->lock, flags);
}
static const char *timbuart_type(struct uart_port *port)
{
return port->type == PORT_UNKNOWN ? "timbuart" : NULL;
}
/* We do not request/release mappings of the registers here,
* currently it's done in the proble function.
*/
static void timbuart_release_port(struct uart_port *port)
{
struct platform_device *pdev = to_platform_device(port->dev);
int size =
resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0));
if (port->flags & UPF_IOREMAP) {
iounmap(port->membase);
port->membase = NULL;
}
release_mem_region(port->mapbase, size);
}
static int timbuart_request_port(struct uart_port *port)
{
struct platform_device *pdev = to_platform_device(port->dev);
int size =
resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0));
if (!request_mem_region(port->mapbase, size, "timb-uart"))
return -EBUSY;
if (port->flags & UPF_IOREMAP) {
port->membase = ioremap(port->mapbase, size);
if (port->membase == NULL) {
release_mem_region(port->mapbase, size);
return -ENOMEM;
}
}
return 0;
}
static irqreturn_t timbuart_handleinterrupt(int irq, void *devid)
{
struct timbuart_port *uart = (struct timbuart_port *)devid;
if (ioread8(uart->port.membase + TIMBUART_IPR)) {
uart->last_ier = ioread8(uart->port.membase + TIMBUART_IER);
/* disable interrupts, the tasklet enables them again */
iowrite8(0, uart->port.membase + TIMBUART_IER);
/* fire off bottom half */
tasklet_schedule(&uart->tasklet);
return IRQ_HANDLED;
} else
return IRQ_NONE;
}
/*
* Configure/autoconfigure the port.
*/
static void timbuart_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_TIMBUART;
timbuart_request_port(port);
}
}
static int timbuart_verify_port(struct uart_port *port,
struct serial_struct *ser)
{
/* we don't want the core code to modify any port params */
return -EINVAL;
}
static struct uart_ops timbuart_ops = {
.tx_empty = timbuart_tx_empty,
.set_mctrl = timbuart_set_mctrl,
.get_mctrl = timbuart_get_mctrl,
.stop_tx = timbuart_stop_tx,
.start_tx = timbuart_start_tx,
.flush_buffer = timbuart_flush_buffer,
.stop_rx = timbuart_stop_rx,
.enable_ms = timbuart_enable_ms,
.break_ctl = timbuart_break_ctl,
.startup = timbuart_startup,
.shutdown = timbuart_shutdown,
.set_termios = timbuart_set_termios,
.type = timbuart_type,
.release_port = timbuart_release_port,
.request_port = timbuart_request_port,
.config_port = timbuart_config_port,
.verify_port = timbuart_verify_port
};
static struct uart_driver timbuart_driver = {
.owner = THIS_MODULE,
.driver_name = "timberdale_uart",
.dev_name = "ttyTU",
.major = TIMBUART_MAJOR,
.minor = TIMBUART_MINOR,
.nr = 1
};
static int timbuart_probe(struct platform_device *dev)
{
int err;
struct timbuart_port *uart;
struct resource *iomem;
dev_dbg(&dev->dev, "%s\n", __func__);
uart = kzalloc(sizeof(*uart), GFP_KERNEL);
if (!uart) {
err = -EINVAL;
goto err_mem;
}
uart->usedma = 0;
uart->port.uartclk = 3250000 * 16;
uart->port.fifosize = TIMBUART_FIFO_SIZE;
uart->port.regshift = 2;
uart->port.iotype = UPIO_MEM;
uart->port.ops = &timbuart_ops;
uart->port.irq = 0;
uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
uart->port.line = 0;
uart->port.dev = &dev->dev;
iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!iomem) {
err = -ENOMEM;
goto err_register;
}
uart->port.mapbase = iomem->start;
uart->port.membase = NULL;
uart->port.irq = platform_get_irq(dev, 0);
if (uart->port.irq < 0) {
err = -EINVAL;
goto err_register;
}
tasklet_init(&uart->tasklet, timbuart_tasklet, (unsigned long)uart);
err = uart_register_driver(&timbuart_driver);
if (err)
goto err_register;
err = uart_add_one_port(&timbuart_driver, &uart->port);
if (err)
goto err_add_port;
platform_set_drvdata(dev, uart);
return 0;
err_add_port:
uart_unregister_driver(&timbuart_driver);
err_register:
kfree(uart);
err_mem:
printk(KERN_ERR "timberdale: Failed to register Timberdale UART: %d\n",
err);
return err;
}
static int timbuart_remove(struct platform_device *dev)
{
struct timbuart_port *uart = platform_get_drvdata(dev);
tasklet_kill(&uart->tasklet);
uart_remove_one_port(&timbuart_driver, &uart->port);
uart_unregister_driver(&timbuart_driver);
kfree(uart);
return 0;
}
static struct platform_driver timbuart_platform_driver = {
.driver = {
.name = "timb-uart",
.owner = THIS_MODULE,
},
.probe = timbuart_probe,
.remove = timbuart_remove,
};
/*--------------------------------------------------------------------------*/
static int __init timbuart_init(void)
{
return platform_driver_register(&timbuart_platform_driver);
}
static void __exit timbuart_exit(void)
{
platform_driver_unregister(&timbuart_platform_driver);
}
module_init(timbuart_init);
module_exit(timbuart_exit);
MODULE_DESCRIPTION("Timberdale UART driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:timb-uart");
/*
* timbuart.c timberdale FPGA GPIO driver
* Copyright (c) 2009 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Supports:
* Timberdale FPGA UART
*/
#ifndef _TIMBUART_H
#define _TIMBUART_H
#define TIMBUART_FIFO_SIZE 2048
#define TIMBUART_RXFIFO 0x08
#define TIMBUART_TXFIFO 0x0c
#define TIMBUART_IER 0x10
#define TIMBUART_IPR 0x14
#define TIMBUART_ISR 0x18
#define TIMBUART_CTRL 0x1c
#define TIMBUART_BAUDRATE 0x20
#define TIMBUART_CTRL_RTS 0x01
#define TIMBUART_CTRL_CTS 0x02
#define TIMBUART_CTRL_FLSHTX 0x40
#define TIMBUART_CTRL_FLSHRX 0x80
#define TXBF 0x01
#define TXBAE 0x02
#define CTS_DELTA 0x04
#define RXDP 0x08
#define RXBAF 0x10
#define RXBF 0x20
#define RXTT 0x40
#define RXBNAE 0x80
#define TXBE 0x100
#define RXFLAGS (RXDP | RXBAF | RXBF | RXTT | RXBNAE)
#define TXFLAGS (TXBF | TXBAE)
#define TIMBUART_MAJOR 204
#define TIMBUART_MINOR 192
#endif /* _TIMBUART_H */
此差异已折叠。
...@@ -89,8 +89,8 @@ struct acm { ...@@ -89,8 +89,8 @@ struct acm {
struct usb_device *dev; /* the corresponding usb device */ struct usb_device *dev; /* the corresponding usb device */
struct usb_interface *control; /* control interface */ struct usb_interface *control; /* control interface */
struct usb_interface *data; /* data interface */ struct usb_interface *data; /* data interface */
struct tty_struct *tty; /* the corresponding tty */ struct tty_port port; /* our tty port data */
struct urb *ctrlurb; /* urbs */ struct urb *ctrlurb; /* urbs */
u8 *ctrl_buffer; /* buffers of urbs */ u8 *ctrl_buffer; /* buffers of urbs */
dma_addr_t ctrl_dma; /* dma handles of buffers */ dma_addr_t ctrl_dma; /* dma handles of buffers */
u8 *country_codes; /* country codes from device */ u8 *country_codes; /* country codes from device */
...@@ -120,7 +120,6 @@ struct acm { ...@@ -120,7 +120,6 @@ struct acm {
unsigned int ctrlout; /* output control lines (DTR, RTS) */ unsigned int ctrlout; /* output control lines (DTR, RTS) */
unsigned int writesize; /* max packet size for the output bulk endpoint */ unsigned int writesize; /* max packet size for the output bulk endpoint */
unsigned int readsize,ctrlsize; /* buffer sizes for freeing */ unsigned int readsize,ctrlsize; /* buffer sizes for freeing */
unsigned int used; /* someone has this acm's device open */
unsigned int minor; /* acm minor number */ unsigned int minor; /* acm minor number */
unsigned char throttle; /* throttled by tty layer */ unsigned char throttle; /* throttled by tty layer */
unsigned char clocal; /* termios CLOCAL */ unsigned char clocal; /* termios CLOCAL */
......
...@@ -93,8 +93,7 @@ static int belkin_sa_startup(struct usb_serial *serial); ...@@ -93,8 +93,7 @@ static int belkin_sa_startup(struct usb_serial *serial);
static void belkin_sa_shutdown(struct usb_serial *serial); static void belkin_sa_shutdown(struct usb_serial *serial);
static int belkin_sa_open(struct tty_struct *tty, static int belkin_sa_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp); struct usb_serial_port *port, struct file *filp);
static void belkin_sa_close(struct tty_struct *tty, static void belkin_sa_close(struct usb_serial_port *port);
struct usb_serial_port *port, struct file *filp);
static void belkin_sa_read_int_callback(struct urb *urb); static void belkin_sa_read_int_callback(struct urb *urb);
static void belkin_sa_set_termios(struct tty_struct *tty, static void belkin_sa_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios * old); struct usb_serial_port *port, struct ktermios * old);
...@@ -244,8 +243,7 @@ static int belkin_sa_open(struct tty_struct *tty, ...@@ -244,8 +243,7 @@ static int belkin_sa_open(struct tty_struct *tty,
} /* belkin_sa_open */ } /* belkin_sa_open */
static void belkin_sa_close(struct tty_struct *tty, static void belkin_sa_close(struct usb_serial_port *port)
struct usb_serial_port *port, struct file *filp)
{ {
dbg("%s port %d", __func__, port->number); dbg("%s port %d", __func__, port->number);
......
...@@ -262,13 +262,33 @@ error: kfree(priv); ...@@ -262,13 +262,33 @@ error: kfree(priv);
return r; return r;
} }
static void ch341_close(struct tty_struct *tty, struct usb_serial_port *port, static int ch341_carrier_raised(struct usb_serial_port *port)
struct file *filp) {
struct ch341_private *priv = usb_get_serial_port_data(port);
if (priv->line_status & CH341_BIT_DCD)
return 1;
return 0;
}
static void ch341_dtr_rts(struct usb_serial_port *port, int on)
{ {
struct ch341_private *priv = usb_get_serial_port_data(port); struct ch341_private *priv = usb_get_serial_port_data(port);
unsigned long flags; unsigned long flags;
unsigned int c_cflag;
dbg("%s - port %d", __func__, port->number);
/* drop DTR and RTS */
spin_lock_irqsave(&priv->lock, flags);
if (on)
priv->line_control |= CH341_BIT_RTS | CH341_BIT_DTR;
else
priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR);
spin_unlock_irqrestore(&priv->lock, flags);
ch341_set_handshake(port->serial->dev, priv->line_control);
wake_up_interruptible(&priv->delta_msr_wait);
}
static void ch341_close(struct usb_serial_port *port)
{
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
/* shutdown our urbs */ /* shutdown our urbs */
...@@ -276,18 +296,6 @@ static void ch341_close(struct tty_struct *tty, struct usb_serial_port *port, ...@@ -276,18 +296,6 @@ static void ch341_close(struct tty_struct *tty, struct usb_serial_port *port,
usb_kill_urb(port->write_urb); usb_kill_urb(port->write_urb);
usb_kill_urb(port->read_urb); usb_kill_urb(port->read_urb);
usb_kill_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_in_urb);
if (tty) {
c_cflag = tty->termios->c_cflag;
if (c_cflag & HUPCL) {
/* drop DTR and RTS */
spin_lock_irqsave(&priv->lock, flags);
priv->line_control = 0;
spin_unlock_irqrestore(&priv->lock, flags);
ch341_set_handshake(port->serial->dev, 0);
}
}
wake_up_interruptible(&priv->delta_msr_wait);
} }
...@@ -302,7 +310,6 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port, ...@@ -302,7 +310,6 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port,
dbg("ch341_open()"); dbg("ch341_open()");
priv->baud_rate = DEFAULT_BAUD_RATE; priv->baud_rate = DEFAULT_BAUD_RATE;
priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;
r = ch341_configure(serial->dev, priv); r = ch341_configure(serial->dev, priv);
if (r) if (r)
...@@ -322,7 +329,7 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port, ...@@ -322,7 +329,7 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port,
if (r) { if (r) {
dev_err(&port->dev, "%s - failed submitting interrupt urb," dev_err(&port->dev, "%s - failed submitting interrupt urb,"
" error %d\n", __func__, r); " error %d\n", __func__, r);
ch341_close(tty, port, NULL); ch341_close(port);
return -EPROTO; return -EPROTO;
} }
...@@ -343,9 +350,6 @@ static void ch341_set_termios(struct tty_struct *tty, ...@@ -343,9 +350,6 @@ static void ch341_set_termios(struct tty_struct *tty,
dbg("ch341_set_termios()"); dbg("ch341_set_termios()");
if (!tty || !tty->termios)
return;
baud_rate = tty_get_baud_rate(tty); baud_rate = tty_get_baud_rate(tty);
priv->baud_rate = baud_rate; priv->baud_rate = baud_rate;
...@@ -568,6 +572,8 @@ static struct usb_serial_driver ch341_device = { ...@@ -568,6 +572,8 @@ static struct usb_serial_driver ch341_device = {
.usb_driver = &ch341_driver, .usb_driver = &ch341_driver,
.num_ports = 1, .num_ports = 1,
.open = ch341_open, .open = ch341_open,
.dtr_rts = ch341_dtr_rts,
.carrier_raised = ch341_carrier_raised,
.close = ch341_close, .close = ch341_close,
.ioctl = ch341_ioctl, .ioctl = ch341_ioctl,
.set_termios = ch341_set_termios, .set_termios = ch341_set_termios,
......
...@@ -169,7 +169,9 @@ static int usb_console_setup(struct console *co, char *options) ...@@ -169,7 +169,9 @@ static int usb_console_setup(struct console *co, char *options)
kfree(tty); kfree(tty);
} }
} }
/* So we know not to kill the hardware on a hangup on this
port. We have also bumped the use count by one so it won't go
idle */
port->console = 1; port->console = 1;
retval = 0; retval = 0;
...@@ -182,7 +184,7 @@ static int usb_console_setup(struct console *co, char *options) ...@@ -182,7 +184,7 @@ static int usb_console_setup(struct console *co, char *options)
kfree(tty); kfree(tty);
reset_open_count: reset_open_count:
port->port.count = 0; port->port.count = 0;
goto out; goto out;
} }
static void usb_console_write(struct console *co, static void usb_console_write(struct console *co,
......
此差异已折叠。
...@@ -61,8 +61,7 @@ static int cyberjack_startup(struct usb_serial *serial); ...@@ -61,8 +61,7 @@ static int cyberjack_startup(struct usb_serial *serial);
static void cyberjack_shutdown(struct usb_serial *serial); static void cyberjack_shutdown(struct usb_serial *serial);
static int cyberjack_open(struct tty_struct *tty, static int cyberjack_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp); struct usb_serial_port *port, struct file *filp);
static void cyberjack_close(struct tty_struct *tty, static void cyberjack_close(struct usb_serial_port *port);
struct usb_serial_port *port, struct file *filp);
static int cyberjack_write(struct tty_struct *tty, static int cyberjack_write(struct tty_struct *tty,
struct usb_serial_port *port, const unsigned char *buf, int count); struct usb_serial_port *port, const unsigned char *buf, int count);
static int cyberjack_write_room(struct tty_struct *tty); static int cyberjack_write_room(struct tty_struct *tty);
...@@ -185,8 +184,7 @@ static int cyberjack_open(struct tty_struct *tty, ...@@ -185,8 +184,7 @@ static int cyberjack_open(struct tty_struct *tty,
return result; return result;
} }
static void cyberjack_close(struct tty_struct *tty, static void cyberjack_close(struct usb_serial_port *port)
struct usb_serial_port *port, struct file *filp)
{ {
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
......
...@@ -174,8 +174,8 @@ static int cypress_ca42v2_startup(struct usb_serial *serial); ...@@ -174,8 +174,8 @@ static int cypress_ca42v2_startup(struct usb_serial *serial);
static void cypress_shutdown(struct usb_serial *serial); static void cypress_shutdown(struct usb_serial *serial);
static int cypress_open(struct tty_struct *tty, static int cypress_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp); struct usb_serial_port *port, struct file *filp);
static void cypress_close(struct tty_struct *tty, static void cypress_close(struct usb_serial_port *port);
struct usb_serial_port *port, struct file *filp); static void cypress_dtr_rts(struct usb_serial_port *port, int on);
static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port, static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count); const unsigned char *buf, int count);
static void cypress_send(struct usb_serial_port *port); static void cypress_send(struct usb_serial_port *port);
...@@ -218,6 +218,7 @@ static struct usb_serial_driver cypress_earthmate_device = { ...@@ -218,6 +218,7 @@ static struct usb_serial_driver cypress_earthmate_device = {
.shutdown = cypress_shutdown, .shutdown = cypress_shutdown,
.open = cypress_open, .open = cypress_open,
.close = cypress_close, .close = cypress_close,
.dtr_rts = cypress_dtr_rts,
.write = cypress_write, .write = cypress_write,
.write_room = cypress_write_room, .write_room = cypress_write_room,
.ioctl = cypress_ioctl, .ioctl = cypress_ioctl,
...@@ -244,6 +245,7 @@ static struct usb_serial_driver cypress_hidcom_device = { ...@@ -244,6 +245,7 @@ static struct usb_serial_driver cypress_hidcom_device = {
.shutdown = cypress_shutdown, .shutdown = cypress_shutdown,
.open = cypress_open, .open = cypress_open,
.close = cypress_close, .close = cypress_close,
.dtr_rts = cypress_dtr_rts,
.write = cypress_write, .write = cypress_write,
.write_room = cypress_write_room, .write_room = cypress_write_room,
.ioctl = cypress_ioctl, .ioctl = cypress_ioctl,
...@@ -270,6 +272,7 @@ static struct usb_serial_driver cypress_ca42v2_device = { ...@@ -270,6 +272,7 @@ static struct usb_serial_driver cypress_ca42v2_device = {
.shutdown = cypress_shutdown, .shutdown = cypress_shutdown,
.open = cypress_open, .open = cypress_open,
.close = cypress_close, .close = cypress_close,
.dtr_rts = cypress_dtr_rts,
.write = cypress_write, .write = cypress_write,
.write_room = cypress_write_room, .write_room = cypress_write_room,
.ioctl = cypress_ioctl, .ioctl = cypress_ioctl,
...@@ -656,11 +659,7 @@ static int cypress_open(struct tty_struct *tty, ...@@ -656,11 +659,7 @@ static int cypress_open(struct tty_struct *tty,
priv->rx_flags = 0; priv->rx_flags = 0;
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
/* raise both lines and set termios */ /* Set termios */
spin_lock_irqsave(&priv->lock, flags);
priv->line_control = CONTROL_DTR | CONTROL_RTS;
priv->cmd_ctrl = 1;
spin_unlock_irqrestore(&priv->lock, flags);
result = cypress_write(tty, port, NULL, 0); result = cypress_write(tty, port, NULL, 0);
if (result) { if (result) {
...@@ -694,76 +693,42 @@ static int cypress_open(struct tty_struct *tty, ...@@ -694,76 +693,42 @@ static int cypress_open(struct tty_struct *tty,
__func__, result); __func__, result);
cypress_set_dead(port); cypress_set_dead(port);
} }
port->port.drain_delay = 256;
return result; return result;
} /* cypress_open */ } /* cypress_open */
static void cypress_dtr_rts(struct usb_serial_port *port, int on)
{
struct cypress_private *priv = usb_get_serial_port_data(port);
/* drop dtr and rts */
priv = usb_get_serial_port_data(port);
spin_lock_irq(&priv->lock);
if (on == 0)
priv->line_control = 0;
else
priv->line_control = CONTROL_DTR | CONTROL_RTS;
priv->cmd_ctrl = 1;
spin_unlock_irq(&priv->lock);
cypress_write(NULL, port, NULL, 0);
}
static void cypress_close(struct tty_struct *tty, static void cypress_close(struct usb_serial_port *port)
struct usb_serial_port *port, struct file *filp)
{ {
struct cypress_private *priv = usb_get_serial_port_data(port); struct cypress_private *priv = usb_get_serial_port_data(port);
unsigned int c_cflag;
int bps;
long timeout;
wait_queue_t wait;
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
/* wait for data to drain from buffer */
spin_lock_irq(&priv->lock);
timeout = CYPRESS_CLOSING_WAIT;
init_waitqueue_entry(&wait, current);
add_wait_queue(&tty->write_wait, &wait);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (cypress_buf_data_avail(priv->buf) == 0
|| timeout == 0 || signal_pending(current)
/* without mutex, allowed due to harmless failure mode */
|| port->serial->disconnected)
break;
spin_unlock_irq(&priv->lock);
timeout = schedule_timeout(timeout);
spin_lock_irq(&priv->lock);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&tty->write_wait, &wait);
/* clear out any remaining data in the buffer */
cypress_buf_clear(priv->buf);
spin_unlock_irq(&priv->lock);
/* writing is potentially harmful, lock must be taken */ /* writing is potentially harmful, lock must be taken */
mutex_lock(&port->serial->disc_mutex); mutex_lock(&port->serial->disc_mutex);
if (port->serial->disconnected) { if (port->serial->disconnected) {
mutex_unlock(&port->serial->disc_mutex); mutex_unlock(&port->serial->disc_mutex);
return; return;
} }
/* wait for characters to drain from device */ cypress_buf_clear(priv->buf);
if (tty) {
bps = tty_get_baud_rate(tty);
if (bps > 1200)
timeout = max((HZ * 2560) / bps, HZ / 10);
else
timeout = 2 * HZ;
schedule_timeout_interruptible(timeout);
}
dbg("%s - stopping urbs", __func__); dbg("%s - stopping urbs", __func__);
usb_kill_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_in_urb);
usb_kill_urb(port->interrupt_out_urb); usb_kill_urb(port->interrupt_out_urb);
if (tty) {
c_cflag = tty->termios->c_cflag;
if (c_cflag & HUPCL) {
/* drop dtr and rts */
priv = usb_get_serial_port_data(port);
spin_lock_irq(&priv->lock);
priv->line_control = 0;
priv->cmd_ctrl = 1;
spin_unlock_irq(&priv->lock);
cypress_write(tty, port, NULL, 0);
}
}
if (stats) if (stats)
dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n", dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",
......
...@@ -81,8 +81,7 @@ static int debug; ...@@ -81,8 +81,7 @@ static int debug;
/* function prototypes for an empeg-car player */ /* function prototypes for an empeg-car player */
static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port, static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp); struct file *filp);
static void empeg_close(struct tty_struct *tty, struct usb_serial_port *port, static void empeg_close(struct usb_serial_port *port);
struct file *filp);
static int empeg_write(struct tty_struct *tty, struct usb_serial_port *port, static int empeg_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, const unsigned char *buf,
int count); int count);
...@@ -181,8 +180,7 @@ static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port, ...@@ -181,8 +180,7 @@ static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port,
} }
static void empeg_close(struct tty_struct *tty, struct usb_serial_port *port, static void empeg_close(struct usb_serial_port *port)
struct file *filp)
{ {
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
......
此差异已折叠。
...@@ -993,8 +993,7 @@ static int garmin_open(struct tty_struct *tty, ...@@ -993,8 +993,7 @@ static int garmin_open(struct tty_struct *tty,
} }
static void garmin_close(struct tty_struct *tty, static void garmin_close(struct usb_serial_port *port)
struct usb_serial_port *port, struct file *filp)
{ {
struct usb_serial *serial = port->serial; struct usb_serial *serial = port->serial;
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
......
...@@ -184,8 +184,7 @@ int usb_serial_generic_resume(struct usb_serial *serial) ...@@ -184,8 +184,7 @@ int usb_serial_generic_resume(struct usb_serial *serial)
} }
EXPORT_SYMBOL_GPL(usb_serial_generic_resume); EXPORT_SYMBOL_GPL(usb_serial_generic_resume);
void usb_serial_generic_close(struct tty_struct *tty, void usb_serial_generic_close(struct usb_serial_port *port)
struct usb_serial_port *port, struct file *filp)
{ {
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
generic_cleanup(port); generic_cleanup(port);
......
...@@ -207,8 +207,7 @@ static void edge_bulk_out_cmd_callback(struct urb *urb); ...@@ -207,8 +207,7 @@ static void edge_bulk_out_cmd_callback(struct urb *urb);
/* function prototypes for the usbserial callbacks */ /* function prototypes for the usbserial callbacks */
static int edge_open(struct tty_struct *tty, struct usb_serial_port *port, static int edge_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp); struct file *filp);
static void edge_close(struct tty_struct *tty, struct usb_serial_port *port, static void edge_close(struct usb_serial_port *port);
struct file *filp);
static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, static int edge_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count); const unsigned char *buf, int count);
static int edge_write_room(struct tty_struct *tty); static int edge_write_room(struct tty_struct *tty);
...@@ -965,7 +964,7 @@ static int edge_open(struct tty_struct *tty, ...@@ -965,7 +964,7 @@ static int edge_open(struct tty_struct *tty,
if (!edge_port->txfifo.fifo) { if (!edge_port->txfifo.fifo) {
dbg("%s - no memory", __func__); dbg("%s - no memory", __func__);
edge_close(tty, port, filp); edge_close(port);
return -ENOMEM; return -ENOMEM;
} }
...@@ -975,7 +974,7 @@ static int edge_open(struct tty_struct *tty, ...@@ -975,7 +974,7 @@ static int edge_open(struct tty_struct *tty,
if (!edge_port->write_urb) { if (!edge_port->write_urb) {
dbg("%s - no memory", __func__); dbg("%s - no memory", __func__);
edge_close(tty, port, filp); edge_close(port);
return -ENOMEM; return -ENOMEM;
} }
...@@ -1099,8 +1098,7 @@ static void block_until_tx_empty(struct edgeport_port *edge_port) ...@@ -1099,8 +1098,7 @@ static void block_until_tx_empty(struct edgeport_port *edge_port)
* edge_close * edge_close
* this function is called by the tty driver when a port is closed * this function is called by the tty driver when a port is closed
*****************************************************************************/ *****************************************************************************/
static void edge_close(struct tty_struct *tty, static void edge_close(struct usb_serial_port *port)
struct usb_serial_port *port, struct file *filp)
{ {
struct edgeport_serial *edge_serial; struct edgeport_serial *edge_serial;
struct edgeport_port *edge_port; struct edgeport_port *edge_port;
......
...@@ -2009,8 +2009,7 @@ static int edge_open(struct tty_struct *tty, ...@@ -2009,8 +2009,7 @@ static int edge_open(struct tty_struct *tty,
return status; return status;
} }
static void edge_close(struct tty_struct *tty, static void edge_close(struct usb_serial_port *port)
struct usb_serial_port *port, struct file *filp)
{ {
struct edgeport_serial *edge_serial; struct edgeport_serial *edge_serial;
struct edgeport_port *edge_port; struct edgeport_port *edge_port;
......
...@@ -76,8 +76,7 @@ static int initial_wait; ...@@ -76,8 +76,7 @@ static int initial_wait;
/* Function prototypes for an ipaq */ /* Function prototypes for an ipaq */
static int ipaq_open(struct tty_struct *tty, static int ipaq_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp); struct usb_serial_port *port, struct file *filp);
static void ipaq_close(struct tty_struct *tty, static void ipaq_close(struct usb_serial_port *port);
struct usb_serial_port *port, struct file *filp);
static int ipaq_calc_num_ports(struct usb_serial *serial); static int ipaq_calc_num_ports(struct usb_serial *serial);
static int ipaq_startup(struct usb_serial *serial); static int ipaq_startup(struct usb_serial *serial);
static void ipaq_shutdown(struct usb_serial *serial); static void ipaq_shutdown(struct usb_serial *serial);
...@@ -714,8 +713,7 @@ static int ipaq_open(struct tty_struct *tty, ...@@ -714,8 +713,7 @@ static int ipaq_open(struct tty_struct *tty,
} }
static void ipaq_close(struct tty_struct *tty, static void ipaq_close(struct usb_serial_port *port)
struct usb_serial_port *port, struct file *filp)
{ {
struct ipaq_private *priv = usb_get_serial_port_data(port); struct ipaq_private *priv = usb_get_serial_port_data(port);
......
此差异已折叠。
...@@ -88,8 +88,7 @@ static int xbof = -1; ...@@ -88,8 +88,7 @@ static int xbof = -1;
static int ir_startup (struct usb_serial *serial); static int ir_startup (struct usb_serial *serial);
static int ir_open(struct tty_struct *tty, struct usb_serial_port *port, static int ir_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filep); struct file *filep);
static void ir_close(struct tty_struct *tty, struct usb_serial_port *port, static void ir_close(struct usb_serial_port *port);
struct file *filep);
static int ir_write(struct tty_struct *tty, struct usb_serial_port *port, static int ir_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count); const unsigned char *buf, int count);
static void ir_write_bulk_callback (struct urb *urb); static void ir_write_bulk_callback (struct urb *urb);
...@@ -346,8 +345,7 @@ static int ir_open(struct tty_struct *tty, ...@@ -346,8 +345,7 @@ static int ir_open(struct tty_struct *tty,
return result; return result;
} }
static void ir_close(struct tty_struct *tty, static void ir_close(struct usb_serial_port *port)
struct usb_serial_port *port, struct file * filp)
{ {
dbg("%s - port %d", __func__, port->number); dbg("%s - port %d", __func__, port->number);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -50,6 +50,7 @@ ifneq ($(CONFIG_HAVE_DEC_LOCK),y) ...@@ -50,6 +50,7 @@ ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
endif endif
obj-$(CONFIG_BITREVERSE) += bitrev.o obj-$(CONFIG_BITREVERSE) += bitrev.o
obj-$(CONFIG_RATIONAL) += rational.o
obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
obj-$(CONFIG_CRC16) += crc16.o obj-$(CONFIG_CRC16) += crc16.o
obj-$(CONFIG_CRC_T10DIF)+= crc-t10dif.o obj-$(CONFIG_CRC_T10DIF)+= crc-t10dif.o
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册