Commit 49c35561 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
  ...
parents 991ec02c f0e85277
......@@ -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");
This diff is collapsed.
......@@ -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,