提交 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
M: Mail patches to
L: Mailing list that is relevant to this area
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:
Supported: Someone is actually paid to look after this.
......@@ -159,7 +159,8 @@ F: drivers/net/r8169.c
8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
L: linux-serial@vger.kernel.org
W: http://serial.sourceforge.net
S: Orphan
M: alan@lxorguk.ukuu.org.uk
S: Odd Fixes
F: drivers/serial/8250*
F: include/linux/serial_8250.h
......@@ -5629,6 +5630,7 @@ P: Alan Cox
M: alan@lxorguk.ukuu.org.uk
L: linux-kernel@vger.kernel.org
S: Maintained
T: stgit http://zeniv.linux.org.uk/~alan/ttydev/
TULIP NETWORK DRIVERS
P: Grant Grundler
......
......@@ -20,11 +20,16 @@
#define ASMARM_ARCH_UART_H
#define IMXUART_HAVE_RTSCTS (1<<0)
#define IMXUART_IRDA (1<<1)
struct imxuart_platform_data {
int (*init)(struct platform_device *pdev);
int (*exit)(struct platform_device *pdev);
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
......@@ -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_cflag);
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);
}
......
......@@ -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
open path is before the ldisc is referencable */
if (tty->ldisc.ops->flush_buffer)
tty->ldisc.ops->flush_buffer(tty);
if (tty->ldisc->ops->flush_buffer)
tty->ldisc->ops->flush_buffer(tty);
tty_driver_flush_buffer(tty);
return 0;
......@@ -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);
return err;
}
tty->low_latency = 1;
} else
return -EBUSY;
break;
......
......@@ -97,6 +97,19 @@ config DEVKMEM
kind of kernel debugging operations.
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
bool "Non-standard serial port support"
depends on HAS_IOMEM
......
......@@ -13,6 +13,7 @@ obj-$(CONFIG_LEGACY_PTYS) += pty.o
obj-$(CONFIG_UNIX98_PTYS) += pty.o
obj-y += misc.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_HW_CONSOLE) += vt.o defkeymap.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)
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 = {
static const struct tty_port_operations epca_port_ops = {
.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)
......@@ -1518,7 +1518,7 @@ static void doevent(int crd)
if (event & MODEMCHG_IND) {
/* A modem signal change has been indicated */
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 */
if (mstat & ch->dcd)
wake_up_interruptible(&ch->port.open_wait);
......@@ -1765,9 +1765,9 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
* that the driver will wait on carrier detect.
*/
if (ts->c_cflag & CLOCAL)
clear_bit(ASYNC_CHECK_CD, &ch->port.flags);
clear_bit(ASYNCB_CHECK_CD, &ch->port.flags);
else
set_bit(ASYNC_CHECK_CD, &ch->port.flags);
set_bit(ASYNCB_CHECK_CD, &ch->port.flags);
mval = ch->m_dtr | ch->m_rts;
} /* End CBAUD not detected */
iflag = termios2digi_i(ch, ts->c_iflag);
......@@ -2114,8 +2114,8 @@ static int pc_ioctl(struct tty_struct *tty, struct file *file,
tty_wait_until_sent(tty, 0);
} else {
/* ldisc lock already held in ioctl */
if (tty->ldisc.ops->flush_buffer)
tty->ldisc.ops->flush_buffer(tty);
if (tty->ldisc->ops->flush_buffer)
tty->ldisc->ops->flush_buffer(tty);
}
unlock_kernel();
/* Fall Thru */
......@@ -2244,7 +2244,8 @@ static void do_softint(struct work_struct *work)
if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
tty_hangup(tty);
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);
......
......@@ -868,11 +868,11 @@ i2Input(i2ChanStrPtr pCh)
amountToMove = count;
}
// 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 );
// If we needed to wrap, do the second data move
if (count > amountToMove) {
pCh->pTTY->ldisc.ops->receive_buf( pCh->pTTY,
pCh->pTTY->ldisc->ops->receive_buf( pCh->pTTY,
pCh->Ibuf, NULL, count - amountToMove );
}
// 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)
if (tty->pgrp)
kill_pgrp(tty->pgrp, sig, 1);
if (flush || !L_NOFLSH(tty)) {
if ( tty->ldisc.ops->flush_buffer )
tty->ldisc.ops->flush_buffer(tty);
if ( tty->ldisc->ops->flush_buffer )
tty->ldisc->ops->flush_buffer(tty);
i2InputFlush( tty->driver_data );
}
}
......
......@@ -329,7 +329,7 @@ static inline void drop_rts(struct isi_port *port)
/* 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_board *card = ip->card;
......@@ -339,10 +339,17 @@ static void isicom_raise_dtr_rts(struct tty_port *port)
if (!lock_card(card))
return;
outw(0x8000 | (channel << card->shift_count) | 0x02, base);
outw(0x0f04, base);
InterruptTheCard(base);
ip->status |= (ISI_DTR | ISI_RTS);
if (on) {
outw(0x8000 | (channel << card->shift_count) | 0x02, base);
outw(0x0f04, base);
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);
}
......@@ -1339,7 +1346,7 @@ static const struct tty_operations isicom_ops = {
static const struct tty_port_operations isicom_port_ops = {
.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,
......
......@@ -1140,14 +1140,14 @@ static int stli_carrier_raised(struct tty_port *port)
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 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,
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 = {
static const struct tty_port_operations stli_port_ops = {
.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)
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->port.count++;
tty->driver_data = ch;
......
......@@ -547,14 +547,18 @@ static int mxser_carrier_raised(struct tty_port *port)
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);
unsigned long flags;
spin_lock_irqsave(&mp->slock, flags);
outb(inb(mp->ioaddr + UART_MCR) |
UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR);
if (on)
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);
}
......@@ -2356,7 +2360,7 @@ static const struct tty_operations mxser_ops = {
struct tty_port_operations mxser_port_ops = {
.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)
#endif
/* Flush any pending characters in the driver and discipline. */
if (tty->ldisc.ops->flush_buffer)
tty->ldisc.ops->flush_buffer(tty);
if (tty->ldisc->ops->flush_buffer)
tty->ldisc->ops->flush_buffer(tty);
tty_driver_flush_buffer(tty);
......
......@@ -73,24 +73,6 @@
#define ECHO_OP_SET_CANON_COL 0x81
#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,
unsigned char __user *ptr)
{
......@@ -1558,11 +1540,11 @@ static void n_tty_close(struct tty_struct *tty)
{
n_tty_flush_buffer(tty);
if (tty->read_buf) {
free_buf(tty->read_buf);
kfree(tty->read_buf);
tty->read_buf = NULL;
}
if (tty->echo_buf) {
free_buf(tty->echo_buf);
kfree(tty->echo_buf);
tty->echo_buf = NULL;
}
}
......@@ -1584,17 +1566,16 @@ static int n_tty_open(struct tty_struct *tty)
/* These are ugly. Currently a malloc failure here can panic */
if (!tty->read_buf) {
tty->read_buf = alloc_buf();
tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
if (!tty->read_buf)
return -ENOMEM;
}
if (!tty->echo_buf) {
tty->echo_buf = alloc_buf();
tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
if (!tty->echo_buf)
return -ENOMEM;
}
memset(tty->read_buf, 0, N_TTY_BUF_SIZE);
memset(tty->echo_buf, 0, N_TTY_BUF_SIZE);
reset_buffer_flags(tty);
tty->column = 0;
n_tty_set_termios(tty, NULL);
......
......@@ -383,7 +383,7 @@ static void async_mode(MGSLPC_INFO *info);
static void tx_timeout(unsigned long context);
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
#define dev_to_port(D) (dev_to_hdlc(D)->priv)
......@@ -513,7 +513,7 @@ static void ldisc_receive_buf(struct tty_struct *tty,
static const struct tty_port_operations mgslpc_port_ops = {
.carrier_raised = carrier_raised,
.raise_dtr_rts = raise_dtr_rts
.dtr_rts = dtr_rts
};
static int mgslpc_probe(struct pcmcia_device *link)
......@@ -2528,13 +2528,16 @@ static int carrier_raised(struct tty_port *port)
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);
unsigned long 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);
spin_unlock_irqrestore(&info->lock,flags);
}
......
......@@ -30,7 +30,6 @@
#include <asm/system.h>
/* These are global because they are accessed in tty_io.c */
#ifdef CONFIG_UNIX98_PTYS
static struct tty_driver *ptm_driver;
static struct tty_driver *pts_driver;
......@@ -111,7 +110,7 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf,
c = to->receive_room;
if (c > count)
c = count;
to->ldisc.ops->receive_buf(to, buf, NULL, c);
to->ldisc->ops->receive_buf(to, buf, NULL, c);
return c;
}
......@@ -149,11 +148,11 @@ static int pty_chars_in_buffer(struct tty_struct *tty)
int count;
/* 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;
/* 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)
return count;
......@@ -187,8 +186,8 @@ static void pty_flush_buffer(struct tty_struct *tty)
if (!to)
return;
if (to->ldisc.ops->flush_buffer)
to->ldisc.ops->flush_buffer(to);
if (to->ldisc->ops->flush_buffer)
to->ldisc->ops->flush_buffer(to);
if (to->packet) {
spin_lock_irqsave(&tty->ctrl_lock, flags);
......
......@@ -872,11 +872,16 @@ static int carrier_raised(struct tty_port *port)
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);
sSetDTR(&info->channel);
sSetRTS(&info->channel);
if (on) {
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)
/*
* 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;
sSetRxTrigger(cp, TRIG_1);
if (sGetChanStatus(cp) & CD_ACT)
......@@ -958,7 +963,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
sEnRxFIFO(cp);
sEnTransmit(cp);
set_bit(ASYNC_INITIALIZED, &info->port.flags);
set_bit(ASYNCB_INITIALIZED, &info->port.flags);
/*
* Set up the tty->alt_speed kludge
......@@ -1641,7 +1646,7 @@ static int rp_write(struct tty_struct *tty,
/* Write remaining data into the port's xmit_buf */
while (1) {
/* Hung up ? */
if (!test_bit(ASYNC_NORMAL_ACTIVE, &info->port.flags))
if (!test_bit(ASYNCB_NORMAL_ACTIVE, &info->port.flags))
goto end;
c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
c = min(c, XMIT_BUF_SIZE - info->xmit_head);
......@@ -2250,7 +2255,7 @@ static const struct tty_operations rocket_ops = {
static const struct tty_port_operations rocket_port_ops = {
.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)
}
count = sel_buffer_lth - pasted;
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);
pasted += count;
}
......
......@@ -772,11 +772,11 @@ static int stl_carrier_raised(struct tty_port *port)
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);
/* 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 = {
static const struct tty_port_operations stl_port_ops = {
.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)
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);
unsigned long 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);
spin_unlock_irqrestore(&info->irq_spinlock,flags);
}
......@@ -4258,7 +4261,7 @@ static void mgsl_add_device( struct mgsl_struct *info )
static const struct tty_port_operations mgsl_port_ops = {
.carrier_raised = carrier_raised,
.raise_dtr_rts = raise_dtr_rts,
.dtr_rts = dtr_rts,
};
......
......@@ -214,6 +214,7 @@ struct slgt_desc
#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_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_status(a) (le16_to_cpu((a).status))
#define desc_complete(a) (le16_to_cpu((a).status) & BIT15)
......@@ -297,6 +298,7 @@ struct slgt_info {
u32 max_frame_size; /* as set by device config */
unsigned int rbuf_fill_level;
unsigned int rx_pio;
unsigned int if_mode;
unsigned int base_clock;
......@@ -331,6 +333,8 @@ struct slgt_info {
struct slgt_desc *rbufs;
unsigned int rbuf_current;
unsigned int rbuf_index;
unsigned int rbuf_fill_index;
unsigned short rbuf_fill_count;
unsigned int tbuf_count;
struct slgt_desc *tbufs;
......@@ -2110,6 +2114,40 @@ static void ri_change(struct slgt_info *info, unsigned short 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)
{
unsigned short status = rd_reg16(info, SSR);
......@@ -2125,6 +2163,8 @@ static void isr_serial(struct slgt_info *info)
if (info->tx_count)
isr_txeom(info, status);
}
if (info->rx_pio && (status & IRQ_RXDATA))
isr_rxdata(info);
if ((status & IRQ_RXBREAK) && (status & RXBREAK)) {
info->icount.brk++;
/* process break detection if tty control allows */
......@@ -2141,7 +2181,8 @@ static void isr_serial(struct slgt_info *info)
} else {
if (status & (IRQ_TXIDLE + IRQ_TXUNDER))
isr_txeom(info, status);
if (info->rx_pio && (status & IRQ_RXDATA))
isr_rxdata(info);
if (status & IRQ_RXIDLE) {
if (status & RXIDLE)
info->icount.rxidle++;
......@@ -2642,6 +2683,10 @@ static int rx_enable(struct slgt_info *info, int enable)
return -EINVAL;
}
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 */
}
......@@ -3099,13 +3144,16 @@ static int carrier_raised(struct tty_port *port)
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;
struct slgt_info *info = container_of(port, struct slgt_info, port);
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);
spin_unlock_irqrestore(&info->lock,flags);
}
......@@ -3419,7 +3467,7 @@ static void add_device(struct slgt_info *info)
static const struct tty_port_operations slgt_port_ops = {
.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)
rdma_reset(info);
reset_rbufs(info);
/* 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));
if (info->rx_pio) {
/* rx request when rx FIFO not empty */
wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) & ~BIT14));
slgt_irq_on(info, IRQ_RXDATA);
if (info->params.mode == MGSL_MODE_ASYNC) {
/* enable saving of rx status */
wr_reg32(info, RDCSR, BIT6);
}
} else {
/* enable saving of rx status, rx DMA and DMA interrupt */
wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0));
/* rx request when rx FIFO half full */
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);
......@@ -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)
{
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)
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);
unsigned long 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);
spin_unlock_irqrestore(&info->lock,flags);
}
......@@ -3746,7 +3749,7 @@ static void add_device(SLMP_INFO *info)
static const struct tty_port_operations port_ops = {
.carrier_raised = carrier_raised,
.raise_dtr_rts = raise_dtr_rts,
.dtr_rts = dtr_rts,
};
/* Allocate and initialize a device instance structure
......
......@@ -29,10 +29,7 @@ static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
buf = kmalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
goto err;
if (PAGE_SIZE != N_TTY_BUF_SIZE)
buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
else
buf->data = (unsigned char *)__get_free_page(GFP_KERNEL);
buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
if (!buf->data)
goto err_buf;
atomic_set(&buf->count, 1);
......@@ -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)
{
WARN_ON(buf->valid != 0);
if (PAGE_SIZE != N_TTY_BUF_SIZE)
kfree(buf->data);
else
free_page((unsigned long)buf->data);
kfree(buf->data);
kfree(buf);
}
......
......@@ -295,7 +295,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
struct tty_driver *p, *res = NULL;
int tty_line = 0;
int len;
char *str;
char *str, *stp;
for (str = name; *str; str++)
if ((*str >= '0' && *str <= '9') || *str == ',')
......@@ -311,13 +311,14 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
list_for_each_entry(p, &tty_drivers, tty_drivers) {
if (strncmp(name, p->name, len) != 0)
continue;
if (*str == ',')
str++;
if (*str == '\0')
str = NULL;
stp = str;
if (*stp == ',')
stp++;
if (*stp == '\0')
stp = NULL;
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);
*line = tty_line;
break;
......@@ -469,43 +470,6 @@ void tty_wakeup(struct tty_struct *tty)
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
* @work: tty device
......@@ -535,7 +499,6 @@ static void do_tty_hangup(struct work_struct *work)
struct file *cons_filp = NULL;
struct file *filp, *f = NULL;
struct task_struct *p;
struct tty_ldisc *ld;
int closecount = 0, n;
unsigned long flags;
int refs = 0;
......@@ -566,40 +529,8 @@ static void do_tty_hangup(struct work_struct *work)
filp->f_op = &hung_up_tty_fops;
}
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_release is called */
tty_ldisc_hangup(tty);
read_lock(&tasklist_lock);
if (tty->session) {
......@@ -628,12 +559,15 @@ static void do_tty_hangup(struct work_struct *work)
read_unlock(&tasklist_lock);
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->pgrp);
tty->session = NULL;
tty->pgrp = NULL;
tty->ctrl_status = 0;
set_bit(TTY_HUPPED, &tty->flags);
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
/* Account for the p->signal references we killed */
......@@ -659,10 +593,7 @@ static void do_tty_hangup(struct work_struct *work)
* can't yet guarantee all that.
*/
set_bit(TTY_HUPPED, &tty->flags);
if (ld) {
tty_ldisc_enable(tty);
tty_ldisc_deref(ld);
}
tty_ldisc_enable(tty);
unlock_kernel();
if (f)
fput(f);
......@@ -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);
}
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..
*/
......@@ -2495,11 +2444,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (tty_paranoia_check(tty, inode, "tty_ioctl"))
return -EINVAL;
real_tty = tty;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
real_tty = tty->link;
real_tty = tty_pair_get_tty(tty);
/*
* Factor out some common prep work
......@@ -2555,7 +2500,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case TIOCGSID:
return tiocgsid(tty, real_tty, p);
case TIOCGETD:
return put_user(tty->ldisc.ops->num, (int __user *)p);
return put_user(tty->ldisc->ops->num, (int __user *)p);
case TIOCSETD:
return tiocsetd(tty, p);
/*
......@@ -2770,6 +2715,7 @@ void initialize_tty_struct(struct tty_struct *tty,
tty->buf.head = tty->buf.tail = NULL;
tty_buffer_init(tty);
mutex_init(&tty->termios_mutex);
mutex_init(&tty->ldisc_mutex);
init_waitqueue_head(&tty->write_wait);
init_waitqueue_head(&tty->read_wait);
INIT_WORK(&tty->hangup_work, do_tty_hangup);
......
......@@ -97,14 +97,19 @@ EXPORT_SYMBOL(tty_driver_flush_buffer);
* @tty: terminal
*
* 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)
{
mutex_lock(&tty->termios_mutex);
/* check TTY_THROTTLED first so it indicates our state */
if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
tty->ops->throttle)
tty->ops->throttle(tty);
mutex_unlock(&tty->termios_mutex);
}
EXPORT_SYMBOL(tty_throttle);
......@@ -113,13 +118,21 @@ EXPORT_SYMBOL(tty_throttle);
* @tty: terminal
*
* 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)
{
mutex_lock(&tty->termios_mutex);
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
tty->ops->unthrottle)
tty->ops->unthrottle(tty);
mutex_unlock(&tty->termios_mutex);
}
EXPORT_SYMBOL(tty_unthrottle);
......@@ -613,9 +626,25 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
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)
{
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 0;
}
......@@ -917,6 +946,8 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
struct tty_struct *real_tty;
void __user *p = (void __user *)arg;
int ret = 0;
struct ktermios kterm;
struct termiox ktermx;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
......@@ -952,23 +983,20 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
return set_termios(real_tty, p, TERMIOS_OLD);
#ifndef TCGETS2
case TCGETS:
mutex_lock(&real_tty->termios_mutex);
if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
copy_termios(real_tty, &kterm);
if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
ret = -EFAULT;
mutex_unlock(&real_tty->termios_mutex);
return ret;
#else
case TCGETS:
mutex_lock(&real_tty->termios_mutex);
if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
copy_termios(real_tty, &kterm);
if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
ret = -EFAULT;
mutex_unlock(&real_tty->termios_mutex);
return ret;
case TCGETS2:
mutex_lock(&real_tty->termios_mutex);
if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
copy_termios(real_tty, &kterm);
if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
ret = -EFAULT;
mutex_unlock(&real_tty->termios_mutex);
return ret;
case TCSETSF2:
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,
return set_termios(real_tty, p, TERMIOS_TERMIO);
#ifndef TCGETS2
case TIOCGLCKTRMIOS:
mutex_lock(&real_tty->termios_mutex);
if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
copy_termios_locked(real_tty, &kterm);
if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
ret = -EFAULT;
mutex_unlock(&real_tty->termios_mutex);
return ret;
case TIOCSLCKTRMIOS:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
mutex_lock(&real_tty->termios_mutex);
if (user_termios_to_kernel_termios(real_tty->termios_locked,
copy_termios_locked(real_tty, &kterm);
if (user_termios_to_kernel_termios(&kterm,
(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);
return ret;
return 0;
#else
case TIOCGLCKTRMIOS:
mutex_lock(&real_tty->termios_mutex);
if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
copy_termios_locked(real_tty, &kterm);
if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
ret = -EFAULT;
mutex_unlock(&real_tty->termios_mutex);
return ret;
case TIOCSLCKTRMIOS:
if (!capable(CAP_SYS_ADMIN))
ret = -EPERM;
mutex_lock(&real_tty->termios_mutex);
if (user_termios_to_kernel_termios_1(real_tty->termios_locked,
return -EPERM;
copy_termios_locked(real_tty, &kterm);
if (user_termios_to_kernel_termios_1(&kterm,
(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);
return ret;
#endif
......@@ -1023,9 +1053,10 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
if (real_tty->termiox == NULL)
return -EINVAL;
mutex_lock(&real_tty->termios_mutex);
if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox)))
ret = -EFAULT;
memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
mutex_unlock(&real_tty->termios_mutex);
if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
ret = -EFAULT;
return ret;
case TCSETX:
return set_termiox(real_tty, p, 0);
......@@ -1035,10 +1066,9 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
return set_termiox(real_tty, p, TERMIOS_FLUSH);
#endif
case TIOCGSOFTCAR:
mutex_lock(&real_tty->termios_mutex);
ret = put_user(C_CLOCAL(real_tty) ? 1 : 0,
copy_termios(real_tty, &kterm);
ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
(int __user *)arg);
mutex_unlock(&real_tty->termios_mutex);
return ret;
case TIOCSSOFTCAR:
if (get_user(arg, (unsigned int __user *) arg))
......
此差异已折叠。
......@@ -137,7 +137,7 @@ int tty_port_carrier_raised(struct tty_port *port)
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
*
* Wrapper for the DTR/RTS raise logic. For the moment this is used
......@@ -147,11 +147,27 @@ EXPORT_SYMBOL(tty_port_carrier_raised);
void tty_port_raise_dtr_rts(struct tty_port *port)
{
if (port->ops->raise_dtr_rts)
port->ops->raise_dtr_rts(port);
if (port->ops->dtr_rts)
port->ops->dtr_rts(port, 1);
}
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
* @port: the tty port being opened
......@@ -167,7 +183,7 @@ EXPORT_SYMBOL(tty_port_raise_dtr_rts);
* - port flags and counts
*
* 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
* 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,
/* block if port is in the process of being closed */
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)
return -EAGAIN;
else
......@@ -205,7 +222,6 @@ int tty_port_block_til_ready(struct tty_port *port,
before the next open may complete */
retval = 0;
add_wait_queue(&port->open_wait, &wait);
/* The port lock protects the port counts */
spin_lock_irqsave(&port->lock, flags);
......@@ -219,7 +235,7 @@ int tty_port_block_til_ready(struct tty_port *port,
if (tty->termios->c_cflag & CBAUD)
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 */
if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
if (port->flags & ASYNC_HUP_NOTIFY)
......@@ -240,8 +256,7 @@ int tty_port_block_til_ready(struct tty_port *port,
}
schedule();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&port->open_wait, &wait);
finish_wait(&port->open_wait, &wait);
/* Update counts. A parallel hangup will have set count to zero and
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
if (port->flags & ASYNC_INITIALIZED &&
port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
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;
}
EXPORT_SYMBOL(tty_port_close_start);
......@@ -302,6 +328,9 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
tty_ldisc_flush(tty);
if (tty->termios->c_cflag & HUPCL)
tty_port_lower_dtr_rts(port);
spin_lock_irqsave(&port->lock, flags);
tty->closing = 0;
......
此差异已折叠。
......@@ -287,6 +287,13 @@ static const struct serial8250_config uart_config[] = {
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.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)
......
......@@ -2776,6 +2776,9 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_OXSEMI, 0x950a,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
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_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_4_115200 },
......
......@@ -833,6 +833,7 @@ config SERIAL_IMX
bool "IMX serial port support"
depends on ARM && (ARCH_IMX || ARCH_MXC)
select SERIAL_CORE
select RATIONAL
help
If you have a machine based on a Motorola IMX CPU you
can enable its onboard serial port by enabling this option.
......@@ -1433,4 +1434,11 @@ config SPORT_BAUD_RATE
default 19200 if (SERIAL_SPORT_BAUD_RATE_19200)
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
......@@ -77,3 +77,4 @@ obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.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)
/* Clear TFI bit */
UART_PUT_LSR(uart, TFI);
#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);
return;
}
......@@ -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_x_count(uart->tx_dma_channel, uart->tx_count);
set_dma_x_modify(uart->tx_dma_channel, 1);
SSYNC();
enable_dma(uart->tx_dma_channel);
UART_SET_IER(uart, ETBEI);
......@@ -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)
{
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);
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)
if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0)
uart->rx_dma_nrows = 0;
x_pos = DMA_RX_XCOUNT - x_pos;
if (x_pos == DMA_RX_XCOUNT)
x_pos = 0;
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;
bfin_serial_dma_rx_chars(uart);
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);
}
......@@ -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)) {
disable_dma(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);
xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
uart->port.icount.tx += uart->tx_count;
......@@ -532,11 +557,26 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
{
struct bfin_serial_port *uart = dev_id;
unsigned short irqstat;
int x_pos, pos;
spin_lock(&uart->port.lock);
irqstat = get_dma_curr_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);
return IRQ_HANDLED;
......@@ -789,8 +829,16 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
__func__);
}
if (termios->c_cflag & CSTOPB)
lcr |= STB;
/* Anomaly notes:
* 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)
lcr |= PEN;
if (!(termios->c_cflag & PARODD))
......@@ -940,6 +988,10 @@ static void bfin_serial_reset_irda(struct uart_port *port)
}
#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)
{
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,
}
}
/*
* 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 = {
.name = "early_BFuart",
.write = early_serial_write,
.device = uart_console_device,
.flags = CON_PRINTBUFFER,
.setup = bfin_serial_console_setup,
.index = -1,
.data = &bfin_serial_reg,
};
......
......@@ -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);
/* Place a Start and Stop bit */
__asm__ volatile (
"R2 = b#01111111100;\n\t"
"R3 = b#10000000001;\n\t"
"%0 <<= 2;\n\t"
"%0 = %0 & R2;\n\t"
"%0 = %0 | R3;\n\t"
:"=r"(value)
:"0"(value)
:"R2", "R3");
__asm__ __volatile__ (
"R2 = b#01111111100;"
"R3 = b#10000000001;"
"%0 <<= 2;"
"%0 = %0 & R2;"
"%0 = %0 | R3;"
: "=d"(value)
: "d"(value)
: "ASTAT", "R2", "R3"
);
pr_debug("%s value:%x\n", __func__, value);
SPORT_PUT_TX(up, 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)
{
unsigned int value, extract;
u32 tmp_mask1, tmp_mask2, tmp_shift, tmp;
value = SPORT_GET_RX32(up);
pr_debug("%s value:%x\n", __func__, value);
/* Extract 8 bits data */
__asm__ volatile (
"R5 = 0;\n\t"
"P0 = 8;\n\t"
"R1 = 0x1801(Z);\n\t"
"R3 = 0x0300(Z);\n\t"
"R4 = 0;\n\t"
"LSETUP(loop_s, loop_e) LC0 = P0;\nloop_s:\t"
"R2 = extract(%1, R1.L)(Z);\n\t"
"R2 <<= R4;\n\t"
"R5 = R5 | R2;\n\t"
"R1 = R1 - R3;\nloop_e:\t"
"R4 += 1;\n\t"
"%0 = R5;\n\t"
:"=r"(extract)
:"r"(value)
:"P0", "R1", "R2","R3","R4", "R5");
__asm__ __volatile__ (
"%[extr] = 0;"
"%[mask1] = 0x1801(Z);"
"%[mask2] = 0x0300(Z);"
"%[shift] = 0;"
"LSETUP(.Lloop_s, .Lloop_e) LC0 = %[lc];"
".Lloop_s:"
"%[tmp] = extract(%[val], %[mask1].L)(Z);"
"%[tmp] <<= %[shift];"
"%[extr] = %[extr] | %[tmp];"
"%[mask1] = %[mask1] - %[mask2];"
".Lloop_e:"
"%[shift] += 1;"
: [val]"=d"(value), [extr]"=d"(extract), [shift]"=d"(tmp_shift), [tmp]"=d"(tmp),
[mask1]"=d"(tmp_mask1), [mask2]"=d"(tmp_mask2)
: "d"(value), [lc]"a"(8)
: "ASTAT", "LB0", "LC0", "LT0"
);
pr_debug(" extract:%x\n", extract);
return extract;
......@@ -149,7 +153,7 @@ static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate)
int tclkdiv, tfsdiv, rclkdiv;
/* 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);
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)
}
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);
uart_update_timeout(port, CS8 ,port->uartclk);
......
......@@ -137,7 +137,12 @@ static LIST_HEAD(icom_adapter_head);
static spinlock_t icom_lock;
#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
static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {};
#endif
......@@ -408,7 +413,7 @@ static void load_code(struct icom_port *icom_port)
release_firmware(fw);
/* 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));
/* Start the processor in Adapter */
......@@ -861,7 +866,7 @@ static irqreturn_t icom_interrupt(int irq, void *dev_id)
/* find icom_port for this interrupt */
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;
adapter_interrupts = readl(int_reg);
......@@ -1647,15 +1652,6 @@ static void __exit icom_exit(void)
module_init(icom_init);
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_DESCRIPTION("IBM iSeries Serial IOA driver");
MODULE_SUPPORTED_DEVICE
......
......@@ -8,6 +8,9 @@
* Author: Sascha Hauer <sascha@saschahauer.de>
* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
......@@ -41,6 +44,8 @@
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/rational.h>
#include <asm/io.h>
#include <asm/irq.h>
......@@ -148,6 +153,7 @@
#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */
#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */
#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 USR1_PARITYERR (1<<15) /* Parity error interrupt flag */
#define USR1_RTSS (1<<14) /* RTS pin status */
......@@ -211,10 +217,20 @@ struct imx_port {
struct timer_list timer;
unsigned int old_status;
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;
};
#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.
*/
......@@ -268,6 +284,48 @@ static void imx_stop_tx(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port;
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);
writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);
}
......@@ -302,13 +360,15 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
/* send xmit->buf[xmit->tail]
* out the port here */
writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);
xmit->tail = (xmit->tail + 1) &
(UART_XMIT_SIZE - 1);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
sport->port.icount.tx++;
if (uart_circ_empty(xmit))
break;
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&sport->port);
if (uart_circ_empty(xmit))
imx_stop_tx(&sport->port);
}
......@@ -321,9 +381,30 @@ static void imx_start_tx(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port;
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);
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)
imx_transmit_buffer(sport);
}
......@@ -395,8 +476,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
continue;
}
if (uart_handle_sysrq_char
(&sport->port, (unsigned char)rx))
if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
continue;
if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) {
......@@ -471,26 +551,26 @@ static unsigned int imx_tx_empty(struct uart_port *port)
*/
static unsigned int imx_get_mctrl(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
struct imx_port *sport = (struct imx_port *)port;
unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
if (readl(sport->port.membase + USR1) & USR1_RTSS)
tmp |= TIOCM_CTS;
if (readl(sport->port.membase + USR1) & USR1_RTSS)
tmp |= TIOCM_CTS;
if (readl(sport->port.membase + UCR2) & UCR2_CTS)
tmp |= TIOCM_RTS;
if (readl(sport->port.membase + UCR2) & UCR2_CTS)
tmp |= TIOCM_RTS;
return tmp;
return tmp;
}
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;
temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS;
if (mctrl & TIOCM_RTS)
if (mctrl & TIOCM_RTS)
temp |= UCR2_CTS;
writel(temp, sport->port.membase + UCR2);
......@@ -534,12 +614,7 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
if(!ufcr_rfdiv)
ufcr_rfdiv = 1;
if(ufcr_rfdiv >= 7)
ufcr_rfdiv = 6;
else
ufcr_rfdiv = 6 - ufcr_rfdiv;
val |= UFCR_RFDIV & (ufcr_rfdiv << 7);
val |= UFCR_RFDIV_REG(ufcr_rfdiv);
writel(val, sport->port.membase + UFCR);
......@@ -558,8 +633,24 @@ static int imx_startup(struct uart_port *port)
* requesting IRQs
*/
temp = readl(sport->port.membase + UCR4);
if (USE_IRDA(sport))
temp |= UCR4_IRSC;
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
* chips only have one interrupt.
......@@ -575,12 +666,16 @@ static int imx_startup(struct uart_port *port)
if (retval)
goto error_out2;
retval = request_irq(sport->rtsirq, imx_rtsint,
(sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 :
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
DRIVER_NAME, sport);
if (retval)
goto error_out3;
/* do not use RTS IRQ on IrDA */
if (!USE_IRDA(sport)) {
retval = request_irq(sport->rtsirq, imx_rtsint,
(sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 :
IRQF_TRIGGER_FALLING |
IRQF_TRIGGER_RISING,
DRIVER_NAME, sport);
if (retval)
goto error_out3;
}
} else {
retval = request_irq(sport->port.irq, imx_int, 0,
DRIVER_NAME, sport);
......@@ -597,18 +692,49 @@ static int imx_startup(struct uart_port *port)
temp = readl(sport->port.membase + UCR1);
temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
if (USE_IRDA(sport)) {
temp |= UCR1_IREN;
temp &= ~(UCR1_RTSDEN);
}
writel(temp, sport->port.membase + UCR1);
temp = readl(sport->port.membase + UCR2);
temp |= (UCR2_RXEN | UCR2_TXEN);
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
temp = readl(sport->port.membase + UCR3);
temp |= UCR3_RXDMUXSEL;
writel(temp, sport->port.membase + UCR3);
#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
*/
......@@ -616,6 +742,16 @@ static int imx_startup(struct uart_port *port)
imx_enable_ms(&sport->port);
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;
error_out3:
......@@ -633,6 +769,17 @@ static void imx_shutdown(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port;
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.
*/
......@@ -642,7 +789,8 @@ static void imx_shutdown(struct uart_port *port)
* Free the interrupts
*/
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->rxirq, sport);
} else
......@@ -654,6 +802,9 @@ static void imx_shutdown(struct uart_port *port)
temp = readl(sport->port.membase + UCR1);
temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
if (USE_IRDA(sport))
temp &= ~(UCR1_IREN);
writel(temp, sport->port.membase + UCR1);
}
......@@ -665,7 +816,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned long flags;
unsigned int ucr2, old_ucr1, old_txrxen, baud, quot;
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
......@@ -761,38 +914,39 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
sport->port.membase + UCR2);
old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
div = sport->port.uartclk / (baud * 16);
if (div > 7)
div = 7;
if (!div)
if (USE_IRDA(sport)) {
/*
* use maximum available submodule frequency to
* avoid missing short pulses due to low sampling rate
*/
div = 1;
num = baud;
denom = port->uartclk / div / 16;
/* shift num and denom right until they fit into 16 bits */
while (num > 0x10000 || denom > 0x10000) {
num >>= 1;
denom >>= 1;
} else {
div = sport->port.uartclk / (baud * 16);
if (div > 7)
div = 7;
if (!div)
div = 1;
}
if (num > 0)
num -= 1;
if (denom > 0)
denom -= 1;
writel(num, sport->port.membase + UBIR);
writel(denom, sport->port.membase + UBMR);
rational_best_approximation(16 * div * baud, sport->port.uartclk,
1 << 16, 1 << 16, &num, &denom);
if (div == 7)
div = 6; /* 6 in RFDIV means divide by 7 */
else
div = 6 - div;
tdiv64 = sport->port.uartclk;
tdiv64 *= num;
do_div(tdiv64, denom * 16 * 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 = (ufcr & (~UFCR_RFDIV)) |
(div << 7);
ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div);
writel(ufcr, sport->port.membase + UFCR);
writel(num, sport->port.membase + UBIR);
writel(denom, sport->port.membase + UBMR);
#ifdef ONEMS
writel(sport->port.uartclk / div / 1000, sport->port.membase + ONEMS);
#endif
......@@ -1072,22 +1226,22 @@ static struct uart_driver imx_reg = {
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)
uart_suspend_port(&imx_reg, &sport->port);
if (sport)
uart_suspend_port(&imx_reg, &sport->port);
return 0;
return 0;
}
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)
uart_resume_port(&imx_reg, &sport->port);
if (sport)
uart_resume_port(&imx_reg, &sport->port);
return 0;
return 0;
}
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;
pdata = pdev->dev.platform_data;
if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
sport->have_rtscts = 1;
#ifdef CONFIG_IRDA
if (pdata && (pdata->flags & IMXUART_IRDA))
sport->use_irda = 1;
#endif
if (pdata->init) {
ret = pdata->init(pdev);
if (ret)
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);
return 0;
deinit:
if (pdata->exit)
pdata->exit(pdev);
clkput:
clk_put(sport->clk);
clk_disable(sport->clk);
......@@ -1193,13 +1357,13 @@ static int serial_imx_remove(struct platform_device *pdev)
}
static struct platform_driver serial_imx_driver = {
.probe = serial_imx_probe,
.remove = serial_imx_remove,
.probe = serial_imx_probe,
.remove = serial_imx_remove,
.suspend = serial_imx_suspend,
.resume = serial_imx_resume,
.driver = {
.name = "imx-uart",
.name = "imx-uart",
.owner = THIS_MODULE,
},
};
......
......@@ -61,6 +61,7 @@ enum {
if ((DBG_##nlevel & jsm_debug)) \
dev_printk(KERN_##klevel, pdev->dev, fmt, ## args)
#define MAXLINES 256
#define MAXPORTS 8
#define MAX_STOPS_SENT 5
......
......@@ -33,6 +33,8 @@
#include "jsm.h"
static DECLARE_BITMAP(linemap, MAXLINES);
static void jsm_carrier(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)
int __devinit jsm_uart_port_init(struct jsm_board *brd)
{
int i;
unsigned int line;
struct jsm_channel *ch;
if (!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.fifosize = 16;
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))
printk(KERN_INFO "Added device failed\n");
printk(KERN_INFO "jsm: add device failed\n");
else
printk(KERN_INFO "Added device \n");
}
......@@ -494,6 +503,7 @@ int jsm_remove_uart_port(struct jsm_board *brd)
ch = brd->channels[i];
clear_bit((int)(ch->uart_port.line), linemap);
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 {
struct usb_device *dev; /* the corresponding usb device */
struct usb_interface *control; /* control interface */
struct usb_interface *data; /* data interface */
struct tty_struct *tty; /* the corresponding tty */
struct urb *ctrlurb; /* urbs */
struct tty_port port; /* our tty port data */
struct urb *ctrlurb; /* urbs */
u8 *ctrl_buffer; /* buffers of urbs */
dma_addr_t ctrl_dma; /* dma handles of buffers */
u8 *country_codes; /* country codes from device */
......@@ -120,7 +120,6 @@ struct acm {
unsigned int ctrlout; /* output control lines (DTR, RTS) */
unsigned int writesize; /* max packet size for the output bulk endpoint */
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 char throttle; /* throttled by tty layer */
unsigned char clocal; /* termios CLOCAL */
......
......@@ -93,8 +93,7 @@ static int belkin_sa_startup(struct usb_serial *serial);
static void belkin_sa_shutdown(struct usb_serial *serial);
static int belkin_sa_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void belkin_sa_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void belkin_sa_close(struct usb_serial_port *port);
static void belkin_sa_read_int_callback(struct urb *urb);
static void belkin_sa_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios * old);
......@@ -244,8 +243,7 @@ static int belkin_sa_open(struct tty_struct *tty,
} /* belkin_sa_open */
static void belkin_sa_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void belkin_sa_close(struct usb_serial_port *port)
{
dbg("%s port %d", __func__, port->number);
......
......@@ -262,13 +262,33 @@ error: kfree(priv);
return r;
}
static void ch341_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp)
static int ch341_carrier_raised(struct usb_serial_port *port)
{
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);
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);
/* shutdown our urbs */
......@@ -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->read_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,
dbg("ch341_open()");
priv->baud_rate = DEFAULT_BAUD_RATE;
priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;
r = ch341_configure(serial->dev, priv);
if (r)
......@@ -322,7 +329,7 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port,
if (r) {
dev_err(&port->dev, "%s - failed submitting interrupt urb,"
" error %d\n", __func__, r);
ch341_close(tty, port, NULL);
ch341_close(port);
return -EPROTO;
}
......@@ -343,9 +350,6 @@ static void ch341_set_termios(struct tty_struct *tty,
dbg("ch341_set_termios()");
if (!tty || !tty->termios)
return;
baud_rate = tty_get_baud_rate(tty);
priv->baud_rate = baud_rate;
......@@ -568,6 +572,8 @@ static struct usb_serial_driver ch341_device = {
.usb_driver = &ch341_driver,
.num_ports = 1,
.open = ch341_open,
.dtr_rts = ch341_dtr_rts,
.carrier_raised = ch341_carrier_raised,
.close = ch341_close,
.ioctl = ch341_ioctl,
.set_termios = ch341_set_termios,
......
......@@ -169,7 +169,9 @@ static int usb_console_setup(struct console *co, char *options)
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;
retval = 0;
......@@ -182,7 +184,7 @@ static int usb_console_setup(struct console *co, char *options)
kfree(tty);
reset_open_count:
port->port.count = 0;
goto out;
goto out;
}
static void usb_console_write(struct console *co,
......
此差异已折叠。
......@@ -61,8 +61,7 @@ static int cyberjack_startup(struct usb_serial *serial);
static void cyberjack_shutdown(struct usb_serial *serial);
static int cyberjack_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void cyberjack_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void cyberjack_close(struct usb_serial_port *port);
static int cyberjack_write(struct tty_struct *tty,
struct usb_serial_port *port, const unsigned char *buf, int count);
static int cyberjack_write_room(struct tty_struct *tty);
......@@ -185,8 +184,7 @@ static int cyberjack_open(struct tty_struct *tty,
return result;
}
static void cyberjack_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void cyberjack_close(struct usb_serial_port *port)
{
dbg("%s - port %d", __func__, port->number);
......
......@@ -174,8 +174,8 @@ static int cypress_ca42v2_startup(struct usb_serial *serial);
static void cypress_shutdown(struct usb_serial *serial);
static int cypress_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void cypress_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void cypress_close(struct usb_serial_port *port);
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,
const unsigned char *buf, int count);
static void cypress_send(struct usb_serial_port *port);
......@@ -218,6 +218,7 @@ static struct usb_serial_driver cypress_earthmate_device = {
.shutdown = cypress_shutdown,
.open = cypress_open,
.close = cypress_close,
.dtr_rts = cypress_dtr_rts,
.write = cypress_write,
.write_room = cypress_write_room,
.ioctl = cypress_ioctl,
......@@ -244,6 +245,7 @@ static struct usb_serial_driver cypress_hidcom_device = {
.shutdown = cypress_shutdown,
.open = cypress_open,
.close = cypress_close,
.dtr_rts = cypress_dtr_rts,
.write = cypress_write,
.write_room = cypress_write_room,
.ioctl = cypress_ioctl,
......@@ -270,6 +272,7 @@ static struct usb_serial_driver cypress_ca42v2_device = {
.shutdown = cypress_shutdown,
.open = cypress_open,
.close = cypress_close,
.dtr_rts = cypress_dtr_rts,
.write = cypress_write,
.write_room = cypress_write_room,
.ioctl = cypress_ioctl,
......@@ -656,11 +659,7 @@ static int cypress_open(struct tty_struct *tty,
priv->rx_flags = 0;
spin_unlock_irqrestore(&priv->lock, flags);
/* raise both lines and 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);
/* Set termios */
result = cypress_write(tty, port, NULL, 0);
if (result) {
......@@ -694,76 +693,42 @@ static int cypress_open(struct tty_struct *tty,
__func__, result);
cypress_set_dead(port);
}
port->port.drain_delay = 256;
return result;
} /* 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,
struct usb_serial_port *port, struct file *filp)
static void cypress_close(struct usb_serial_port *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);
/* 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 */
mutex_lock(&port->serial->disc_mutex);
if (port->serial->disconnected) {
mutex_unlock(&port->serial->disc_mutex);
return;
}
/* wait for characters to drain from device */
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);
}
cypress_buf_clear(priv->buf);
dbg("%s - stopping urbs", __func__);
usb_kill_urb(port->interrupt_in_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)
dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",
......
......@@ -81,8 +81,7 @@ static int debug;
/* function prototypes for an empeg-car player */
static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void empeg_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void empeg_close(struct usb_serial_port *port);
static int empeg_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf,
int count);
......@@ -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,
struct file *filp)
static void empeg_close(struct usb_serial_port *port)
{
dbg("%s - port %d", __func__, port->number);
......
此差异已折叠。
......@@ -993,8 +993,7 @@ static int garmin_open(struct tty_struct *tty,
}
static void garmin_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void garmin_close(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
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)
}
EXPORT_SYMBOL_GPL(usb_serial_generic_resume);
void usb_serial_generic_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
void usb_serial_generic_close(struct usb_serial_port *port)
{
dbg("%s - port %d", __func__, port->number);
generic_cleanup(port);
......
......@@ -207,8 +207,7 @@ static void edge_bulk_out_cmd_callback(struct urb *urb);
/* function prototypes for the usbserial callbacks */
static int edge_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void edge_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void edge_close(struct usb_serial_port *port);
static int edge_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
static int edge_write_room(struct tty_struct *tty);
......@@ -965,7 +964,7 @@ static int edge_open(struct tty_struct *tty,
if (!edge_port->txfifo.fifo) {
dbg("%s - no memory", __func__);
edge_close(tty, port, filp);
edge_close(port);
return -ENOMEM;
}
......@@ -975,7 +974,7 @@ static int edge_open(struct tty_struct *tty,
if (!edge_port->write_urb) {
dbg("%s - no memory", __func__);
edge_close(tty, port, filp);
edge_close(port);
return -ENOMEM;
}
......@@ -1099,8 +1098,7 @@ static void block_until_tx_empty(struct edgeport_port *edge_port)
* edge_close
* this function is called by the tty driver when a port is closed
*****************************************************************************/
static void edge_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void edge_close(struct usb_serial_port *port)
{
struct edgeport_serial *edge_serial;
struct edgeport_port *edge_port;
......
......@@ -2009,8 +2009,7 @@ static int edge_open(struct tty_struct *tty,
return status;
}
static void edge_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void edge_close(struct usb_serial_port *port)
{
struct edgeport_serial *edge_serial;
struct edgeport_port *edge_port;
......
......@@ -76,8 +76,7 @@ static int initial_wait;
/* Function prototypes for an ipaq */
static int ipaq_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void ipaq_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void ipaq_close(struct usb_serial_port *port);
static int ipaq_calc_num_ports(struct usb_serial *serial);
static int ipaq_startup(struct usb_serial *serial);
static void ipaq_shutdown(struct usb_serial *serial);
......@@ -714,8 +713,7 @@ static int ipaq_open(struct tty_struct *tty,
}
static void ipaq_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void ipaq_close(struct usb_serial_port *port)
{
struct ipaq_private *priv = usb_get_serial_port_data(port);
......
此差异已折叠。
......@@ -88,8 +88,7 @@ static int xbof = -1;
static int ir_startup (struct usb_serial *serial);
static int ir_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filep);
static void ir_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filep);
static void ir_close(struct usb_serial_port *port);
static int ir_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
static void ir_write_bulk_callback (struct urb *urb);
......@@ -346,8 +345,7 @@ static int ir_open(struct tty_struct *tty,
return result;
}
static void ir_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file * filp)
static void ir_close(struct usb_serial_port *port)
{
dbg("%s - port %d", __func__, port->number);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -50,6 +50,7 @@ ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
endif
obj-$(CONFIG_BITREVERSE) += bitrev.o
obj-$(CONFIG_RATIONAL) += rational.o
obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
obj-$(CONFIG_CRC16) += crc16.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.
先完成此消息的编辑!
想要评论请 注册