mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 02:32:09 -04:00
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 ...
This commit is contained in:
commit
49c355617f
95 changed files with 4438 additions and 2714 deletions
|
|
@ -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
|
||||
|
|
|
|||
365
drivers/char/bfin_jtag_comm.c
Normal file
365
drivers/char/bfin_jtag_comm.c
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
/*
|
||||
* 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 <[email protected]>");
|
||||
MODULE_DESCRIPTION("TTY over Blackfin JTAG Communication");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -604,7 +604,6 @@
|
|||
|
||||
#define NR_PORTS 256
|
||||
|
||||
#define ZE_V1_NPORTS 64
|
||||
#define ZO_V1 0
|
||||
#define ZO_V2 1
|
||||
#define ZE_V1 2
|
||||
|
|
@ -663,18 +662,6 @@
|
|||
static void cy_throttle(struct tty_struct *tty);
|
||||
static void cy_send_xchar(struct tty_struct *tty, char ch);
|
||||
|
||||
#define IS_CYC_Z(card) ((card).num_chips == (unsigned int)-1)
|
||||
|
||||
#define Z_FPGA_CHECK(card) \
|
||||
((readl(&((struct RUNTIME_9060 __iomem *) \
|
||||
((card).ctl_addr))->init_ctrl) & (1<<17)) != 0)
|
||||
|
||||
#define ISZLOADED(card) (((ZO_V1 == readl(&((struct RUNTIME_9060 __iomem *) \
|
||||
((card).ctl_addr))->mail_box_0)) || \
|
||||
Z_FPGA_CHECK(card)) && \
|
||||
(ZFIRM_ID == readl(&((struct FIRM_ID __iomem *) \
|
||||
((card).base_addr+ID_ADDRESS))->signature)))
|
||||
|
||||
#ifndef SERIAL_XMIT_SIZE
|
||||
#define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096))
|
||||
#endif
|
||||
|
|
@ -687,8 +674,6 @@ static void cy_send_xchar(struct tty_struct *tty, char ch);
|
|||
#define DRIVER_VERSION 0x02010203
|
||||
#define RAM_SIZE 0x80000
|
||||
|
||||
#define Z_FPGA_LOADED(X) ((readl(&(X)->init_ctrl) & (1<<17)) != 0)
|
||||
|
||||
enum zblock_type {
|
||||
ZBLOCK_PRG = 0,
|
||||
ZBLOCK_FPGA = 1
|
||||
|
|
@ -883,6 +868,29 @@ static void cyz_rx_restart(unsigned long);
|
|||
static struct timer_list cyz_rx_full_timer[NR_PORTS];
|
||||
#endif /* CONFIG_CYZ_INTR */
|
||||
|
||||
static inline bool cy_is_Z(struct cyclades_card *card)
|
||||
{
|
||||
return card->num_chips == (unsigned int)-1;
|
||||
}
|
||||
|
||||
static inline bool __cyz_fpga_loaded(struct RUNTIME_9060 __iomem *ctl_addr)
|
||||
{
|
||||
return readl(&ctl_addr->init_ctrl) & (1 << 17);
|
||||
}
|
||||
|
||||
static inline bool cyz_fpga_loaded(struct cyclades_card *card)
|
||||
{
|
||||
return __cyz_fpga_loaded(card->ctl_addr.p9060);
|
||||
}
|
||||
|
||||
static inline bool cyz_is_loaded(struct cyclades_card *card)
|
||||
{
|
||||
struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS;
|
||||
|
||||
return (card->hw_ver == ZO_V1 || cyz_fpga_loaded(card)) &&
|
||||
readl(&fw_id->signature) == ZFIRM_ID;
|
||||
}
|
||||
|
||||
static inline int serial_paranoia_check(struct cyclades_port *info,
|
||||
char *name, const char *routine)
|
||||
{
|
||||
|
|
@ -1395,19 +1403,15 @@ cyz_fetch_msg(struct cyclades_card *cinfo,
|
|||
unsigned long loc_doorbell;
|
||||
|
||||
firm_id = cinfo->base_addr + ID_ADDRESS;
|
||||
if (!ISZLOADED(*cinfo))
|
||||
return -1;
|
||||
zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
|
||||
board_ctrl = &zfw_ctrl->board_ctrl;
|
||||
|
||||
loc_doorbell = readl(&((struct RUNTIME_9060 __iomem *)
|
||||
(cinfo->ctl_addr))->loc_doorbell);
|
||||
loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell);
|
||||
if (loc_doorbell) {
|
||||
*cmd = (char)(0xff & loc_doorbell);
|
||||
*channel = readl(&board_ctrl->fwcmd_channel);
|
||||
*param = (__u32) readl(&board_ctrl->fwcmd_param);
|
||||
cy_writel(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
|
||||
loc_doorbell, 0xffffffff);
|
||||
cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -1424,15 +1428,14 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
|
|||
unsigned int index;
|
||||
|
||||
firm_id = cinfo->base_addr + ID_ADDRESS;
|
||||
if (!ISZLOADED(*cinfo))
|
||||
if (!cyz_is_loaded(cinfo))
|
||||
return -1;
|
||||
|
||||
zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
|
||||
board_ctrl = &zfw_ctrl->board_ctrl;
|
||||
|
||||
index = 0;
|
||||
pci_doorbell =
|
||||
&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->pci_doorbell;
|
||||
pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
|
||||
while ((readl(pci_doorbell) & 0xff) != 0) {
|
||||
if (index++ == 1000)
|
||||
return (int)(readl(pci_doorbell) & 0xff);
|
||||
|
|
@ -1624,10 +1627,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
|
|||
static struct BOARD_CTRL __iomem *board_ctrl;
|
||||
static struct CH_CTRL __iomem *ch_ctrl;
|
||||
static struct BUF_CTRL __iomem *buf_ctrl;
|
||||
__u32 channel;
|
||||
__u32 channel, param, fw_ver;
|
||||
__u8 cmd;
|
||||
__u32 param;
|
||||
__u32 hw_ver, fw_ver;
|
||||
int special_count;
|
||||
int delta_count;
|
||||
|
||||
|
|
@ -1635,8 +1636,6 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
|
|||
zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
|
||||
board_ctrl = &zfw_ctrl->board_ctrl;
|
||||
fw_ver = readl(&board_ctrl->fw_version);
|
||||
hw_ver = readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
|
||||
mail_box_0);
|
||||
|
||||
while (cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 1) {
|
||||
special_count = 0;
|
||||
|
|
@ -1737,15 +1736,7 @@ static irqreturn_t cyz_interrupt(int irq, void *dev_id)
|
|||
{
|
||||
struct cyclades_card *cinfo = dev_id;
|
||||
|
||||
if (unlikely(cinfo == NULL)) {
|
||||
#ifdef CY_DEBUG_INTERRUPTS
|
||||
printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",
|
||||
irq);
|
||||
#endif
|
||||
return IRQ_NONE; /* spurious interrupt */
|
||||
}
|
||||
|
||||
if (unlikely(!ISZLOADED(*cinfo))) {
|
||||
if (unlikely(!cyz_is_loaded(cinfo))) {
|
||||
#ifdef CY_DEBUG_INTERRUPTS
|
||||
printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
|
||||
"(IRQ%d).\n", irq);
|
||||
|
|
@ -1785,7 +1776,6 @@ static void cyz_poll(unsigned long arg)
|
|||
struct tty_struct *tty;
|
||||
struct FIRM_ID __iomem *firm_id;
|
||||
struct ZFW_CTRL __iomem *zfw_ctrl;
|
||||
struct BOARD_CTRL __iomem *board_ctrl;
|
||||
struct BUF_CTRL __iomem *buf_ctrl;
|
||||
unsigned long expires = jiffies + HZ;
|
||||
unsigned int port, card;
|
||||
|
|
@ -1793,19 +1783,17 @@ static void cyz_poll(unsigned long arg)
|
|||
for (card = 0; card < NR_CARDS; card++) {
|
||||
cinfo = &cy_card[card];
|
||||
|
||||
if (!IS_CYC_Z(*cinfo))
|
||||
if (!cy_is_Z(cinfo))
|
||||
continue;
|
||||
if (!ISZLOADED(*cinfo))
|
||||
if (!cyz_is_loaded(cinfo))
|
||||
continue;
|
||||
|
||||
firm_id = cinfo->base_addr + ID_ADDRESS;
|
||||
zfw_ctrl = cinfo->base_addr +
|
||||
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
|
||||
board_ctrl = &(zfw_ctrl->board_ctrl);
|
||||
|
||||
/* Skip first polling cycle to avoid racing conditions with the FW */
|
||||
if (!cinfo->intr_enabled) {
|
||||
cinfo->nports = (int)readl(&board_ctrl->n_channel);
|
||||
cinfo->intr_enabled = 1;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1874,7 +1862,7 @@ static int startup(struct cyclades_port *info)
|
|||
|
||||
set_line_char(info);
|
||||
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -1931,7 +1919,7 @@ static int startup(struct cyclades_port *info)
|
|||
base_addr = card->base_addr;
|
||||
|
||||
firm_id = base_addr + ID_ADDRESS;
|
||||
if (!ISZLOADED(*card))
|
||||
if (!cyz_is_loaded(card))
|
||||
return -ENODEV;
|
||||
|
||||
zfw_ctrl = card->base_addr +
|
||||
|
|
@ -2026,7 +2014,7 @@ static void start_xmit(struct cyclades_port *info)
|
|||
|
||||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -2070,7 +2058,7 @@ static void shutdown(struct cyclades_port *info)
|
|||
|
||||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -2126,7 +2114,7 @@ static void shutdown(struct cyclades_port *info)
|
|||
#endif
|
||||
|
||||
firm_id = base_addr + ID_ADDRESS;
|
||||
if (!ISZLOADED(*card))
|
||||
if (!cyz_is_loaded(card))
|
||||
return;
|
||||
|
||||
zfw_ctrl = card->base_addr +
|
||||
|
|
@ -2233,7 +2221,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
|
|||
#endif
|
||||
info->port.blocked_open++;
|
||||
|
||||
if (!IS_CYC_Z(*cinfo)) {
|
||||
if (!cy_is_Z(cinfo)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = cinfo->bus_index;
|
||||
|
|
@ -2296,7 +2284,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
|
|||
|
||||
base_addr = cinfo->base_addr;
|
||||
firm_id = base_addr + ID_ADDRESS;
|
||||
if (!ISZLOADED(*cinfo)) {
|
||||
if (!cyz_is_loaded(cinfo)) {
|
||||
__set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&info->port.open_wait, &wait);
|
||||
return -EINVAL;
|
||||
|
|
@ -2397,16 +2385,14 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
|
|||
treat it as absent from the system. This
|
||||
will make the user pay attention.
|
||||
*/
|
||||
if (IS_CYC_Z(*info->card)) {
|
||||
if (cy_is_Z(info->card)) {
|
||||
struct cyclades_card *cinfo = info->card;
|
||||
struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
|
||||
|
||||
if (!ISZLOADED(*cinfo)) {
|
||||
if (((ZE_V1 == readl(&((struct RUNTIME_9060 __iomem *)
|
||||
(cinfo->ctl_addr))->mail_box_0)) &&
|
||||
Z_FPGA_CHECK(*cinfo)) &&
|
||||
(ZFIRM_HLT == readl(
|
||||
&firm_id->signature))) {
|
||||
if (!cyz_is_loaded(cinfo)) {
|
||||
if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
|
||||
readl(&firm_id->signature) ==
|
||||
ZFIRM_HLT) {
|
||||
printk(KERN_ERR "cyc:Cyclades-Z Error: you "
|
||||
"need an external power supply for "
|
||||
"this number of ports.\nFirmware "
|
||||
|
|
@ -2423,18 +2409,13 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
|
|||
interrupts should be enabled as soon as the first open
|
||||
happens to one of its ports. */
|
||||
if (!cinfo->intr_enabled) {
|
||||
struct ZFW_CTRL __iomem *zfw_ctrl;
|
||||
struct BOARD_CTRL __iomem *board_ctrl;
|
||||
|
||||
zfw_ctrl = cinfo->base_addr +
|
||||
(readl(&firm_id->zfwctrl_addr) &
|
||||
0xfffff);
|
||||
|
||||
board_ctrl = &zfw_ctrl->board_ctrl;
|
||||
u16 intr;
|
||||
|
||||
/* Enable interrupts on the PLX chip */
|
||||
cy_writew(cinfo->ctl_addr + 0x68,
|
||||
readw(cinfo->ctl_addr + 0x68) | 0x0900);
|
||||
intr = readw(&cinfo->ctl_addr.p9060->
|
||||
intr_ctrl_stat) | 0x0900;
|
||||
cy_writew(&cinfo->ctl_addr.p9060->
|
||||
intr_ctrl_stat, intr);
|
||||
/* Enable interrupts on the FW */
|
||||
retval = cyz_issue_cmd(cinfo, 0,
|
||||
C_CM_IRQ_ENBL, 0L);
|
||||
|
|
@ -2442,8 +2423,6 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
|
|||
printk(KERN_ERR "cyc:IRQ enable retval "
|
||||
"was %x\n", retval);
|
||||
}
|
||||
cinfo->nports =
|
||||
(int)readl(&board_ctrl->n_channel);
|
||||
cinfo->intr_enabled = 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -2556,7 +2535,7 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
|
|||
#endif
|
||||
card = info->card;
|
||||
channel = (info->line) - (card->first_line);
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -2601,7 +2580,7 @@ static void cy_flush_buffer(struct tty_struct *tty)
|
|||
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
|
||||
spin_unlock_irqrestore(&card->card_lock, flags);
|
||||
|
||||
if (IS_CYC_Z(*card)) { /* If it is a Z card, flush the on-board
|
||||
if (cy_is_Z(card)) { /* If it is a Z card, flush the on-board
|
||||
buffers as well */
|
||||
spin_lock_irqsave(&card->card_lock, flags);
|
||||
retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
|
||||
|
|
@ -2682,7 +2661,7 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
|
|||
|
||||
spin_lock_irqsave(&card->card_lock, flags);
|
||||
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
int channel = info->line - card->first_line;
|
||||
int index = card->bus_index;
|
||||
void __iomem *base_addr = card->base_addr +
|
||||
|
|
@ -2902,7 +2881,7 @@ static int cy_chars_in_buffer(struct tty_struct *tty)
|
|||
channel = (info->line) - (card->first_line);
|
||||
|
||||
#ifdef Z_EXT_CHARS_IN_BUFFER
|
||||
if (!IS_CYC_Z(cy_card[card])) {
|
||||
if (!cy_is_Z(card)) {
|
||||
#endif /* Z_EXT_CHARS_IN_BUFFER */
|
||||
#ifdef CY_DEBUG_IO
|
||||
printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
|
||||
|
|
@ -2984,7 +2963,6 @@ static void set_line_char(struct cyclades_port *info)
|
|||
void __iomem *base_addr;
|
||||
int chip, channel, index;
|
||||
unsigned cflag, iflag;
|
||||
unsigned short chip_number;
|
||||
int baud, baud_rate = 0;
|
||||
int i;
|
||||
|
||||
|
|
@ -3013,9 +2991,8 @@ static void set_line_char(struct cyclades_port *info)
|
|||
|
||||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
chip_number = channel / 4;
|
||||
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
|
||||
index = card->bus_index;
|
||||
|
||||
|
|
@ -3233,21 +3210,17 @@ static void set_line_char(struct cyclades_port *info)
|
|||
} else {
|
||||
struct FIRM_ID __iomem *firm_id;
|
||||
struct ZFW_CTRL __iomem *zfw_ctrl;
|
||||
struct BOARD_CTRL __iomem *board_ctrl;
|
||||
struct CH_CTRL __iomem *ch_ctrl;
|
||||
struct BUF_CTRL __iomem *buf_ctrl;
|
||||
__u32 sw_flow;
|
||||
int retval;
|
||||
|
||||
firm_id = card->base_addr + ID_ADDRESS;
|
||||
if (!ISZLOADED(*card))
|
||||
if (!cyz_is_loaded(card))
|
||||
return;
|
||||
|
||||
zfw_ctrl = card->base_addr +
|
||||
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
|
||||
board_ctrl = &zfw_ctrl->board_ctrl;
|
||||
ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
|
||||
buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
|
||||
|
||||
/* baud rate */
|
||||
baud = tty_get_baud_rate(info->port.tty);
|
||||
|
|
@ -3457,7 +3430,7 @@ static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
|
|||
|
||||
card = info->card;
|
||||
channel = (info->line) - (card->first_line);
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -3497,7 +3470,7 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
|
|||
|
||||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -3523,7 +3496,7 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
|
|||
} else {
|
||||
base_addr = card->base_addr;
|
||||
firm_id = card->base_addr + ID_ADDRESS;
|
||||
if (ISZLOADED(*card)) {
|
||||
if (cyz_is_loaded(card)) {
|
||||
zfw_ctrl = card->base_addr +
|
||||
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
|
||||
board_ctrl = &zfw_ctrl->board_ctrl;
|
||||
|
|
@ -3566,7 +3539,7 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
|
|||
|
||||
card = info->card;
|
||||
channel = (info->line) - (card->first_line);
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -3641,7 +3614,7 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
|
|||
base_addr = card->base_addr;
|
||||
|
||||
firm_id = card->base_addr + ID_ADDRESS;
|
||||
if (ISZLOADED(*card)) {
|
||||
if (cyz_is_loaded(card)) {
|
||||
zfw_ctrl = card->base_addr +
|
||||
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
|
||||
board_ctrl = &zfw_ctrl->board_ctrl;
|
||||
|
|
@ -3713,7 +3686,7 @@ static int cy_break(struct tty_struct *tty, int break_state)
|
|||
card = info->card;
|
||||
|
||||
spin_lock_irqsave(&card->card_lock, flags);
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
/* Let the transmit ISR take care of this (since it
|
||||
requires stuffing characters into the output stream).
|
||||
*/
|
||||
|
|
@ -3782,7 +3755,7 @@ static int set_threshold(struct cyclades_port *info, unsigned long value)
|
|||
|
||||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -3810,7 +3783,7 @@ static int get_threshold(struct cyclades_port *info,
|
|||
|
||||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -3844,7 +3817,7 @@ static int set_timeout(struct cyclades_port *info, unsigned long value)
|
|||
|
||||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -3867,7 +3840,7 @@ static int get_timeout(struct cyclades_port *info,
|
|||
|
||||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -4121,7 +4094,7 @@ static void cy_send_xchar(struct tty_struct *tty, char ch)
|
|||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
|
||||
if (IS_CYC_Z(*card)) {
|
||||
if (cy_is_Z(card)) {
|
||||
if (ch == STOP_CHAR(tty))
|
||||
cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
|
||||
else if (ch == START_CHAR(tty))
|
||||
|
|
@ -4154,7 +4127,7 @@ static void cy_throttle(struct tty_struct *tty)
|
|||
card = info->card;
|
||||
|
||||
if (I_IXOFF(tty)) {
|
||||
if (!IS_CYC_Z(*card))
|
||||
if (!cy_is_Z(card))
|
||||
cy_send_xchar(tty, STOP_CHAR(tty));
|
||||
else
|
||||
info->throttle = 1;
|
||||
|
|
@ -4162,7 +4135,7 @@ static void cy_throttle(struct tty_struct *tty)
|
|||
|
||||
if (tty->termios->c_cflag & CRTSCTS) {
|
||||
channel = info->line - card->first_line;
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -4219,7 +4192,7 @@ static void cy_unthrottle(struct tty_struct *tty)
|
|||
if (tty->termios->c_cflag & CRTSCTS) {
|
||||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -4263,7 +4236,7 @@ static void cy_stop(struct tty_struct *tty)
|
|||
|
||||
cinfo = info->card;
|
||||
channel = info->line - cinfo->first_line;
|
||||
if (!IS_CYC_Z(*cinfo)) {
|
||||
if (!cy_is_Z(cinfo)) {
|
||||
index = cinfo->bus_index;
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
|
|
@ -4296,7 +4269,7 @@ static void cy_start(struct tty_struct *tty)
|
|||
cinfo = info->card;
|
||||
channel = info->line - cinfo->first_line;
|
||||
index = cinfo->bus_index;
|
||||
if (!IS_CYC_Z(*cinfo)) {
|
||||
if (!cy_is_Z(cinfo)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
|
||||
|
|
@ -4347,33 +4320,20 @@ static void cy_hangup(struct tty_struct *tty)
|
|||
static int __devinit cy_init_card(struct cyclades_card *cinfo)
|
||||
{
|
||||
struct cyclades_port *info;
|
||||
u32 uninitialized_var(mailbox);
|
||||
unsigned int nports, port;
|
||||
unsigned int port;
|
||||
unsigned short chip_number;
|
||||
int uninitialized_var(index);
|
||||
|
||||
spin_lock_init(&cinfo->card_lock);
|
||||
cinfo->intr_enabled = 0;
|
||||
|
||||
if (IS_CYC_Z(*cinfo)) { /* Cyclades-Z */
|
||||
mailbox = readl(&((struct RUNTIME_9060 __iomem *)
|
||||
cinfo->ctl_addr)->mail_box_0);
|
||||
nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
|
||||
cinfo->intr_enabled = 0;
|
||||
cinfo->nports = 0; /* Will be correctly set later, after
|
||||
Z FW is loaded */
|
||||
} else {
|
||||
index = cinfo->bus_index;
|
||||
nports = cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
|
||||
}
|
||||
|
||||
cinfo->ports = kzalloc(sizeof(*cinfo->ports) * nports, GFP_KERNEL);
|
||||
cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
|
||||
GFP_KERNEL);
|
||||
if (cinfo->ports == NULL) {
|
||||
printk(KERN_ERR "Cyclades: cannot allocate ports\n");
|
||||
cinfo->nports = 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (port = cinfo->first_line; port < cinfo->first_line + nports;
|
||||
for (port = cinfo->first_line; port < cinfo->first_line + cinfo->nports;
|
||||
port++) {
|
||||
info = &cinfo->ports[port - cinfo->first_line];
|
||||
tty_port_init(&info->port);
|
||||
|
|
@ -4387,9 +4347,9 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
|
|||
init_completion(&info->shutdown_wait);
|
||||
init_waitqueue_head(&info->delta_msr_wait);
|
||||
|
||||
if (IS_CYC_Z(*cinfo)) {
|
||||
if (cy_is_Z(cinfo)) {
|
||||
info->type = PORT_STARTECH;
|
||||
if (mailbox == ZO_V1)
|
||||
if (cinfo->hw_ver == ZO_V1)
|
||||
info->xmit_fifo_size = CYZ_FIFO_SIZE;
|
||||
else
|
||||
info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
|
||||
|
|
@ -4398,6 +4358,7 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
|
|||
cyz_rx_restart, (unsigned long)info);
|
||||
#endif
|
||||
} else {
|
||||
int index = cinfo->bus_index;
|
||||
info->type = PORT_CIRRUS;
|
||||
info->xmit_fifo_size = CyMAX_CHAR_FIFO;
|
||||
info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
|
||||
|
|
@ -4430,7 +4391,7 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
|
|||
}
|
||||
|
||||
#ifndef CONFIG_CYZ_INTR
|
||||
if (IS_CYC_Z(*cinfo) && !timer_pending(&cyz_timerlist)) {
|
||||
if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
|
||||
mod_timer(&cyz_timerlist, jiffies + 1);
|
||||
#ifdef CY_PCI_DEBUG
|
||||
printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
|
||||
|
|
@ -4621,11 +4582,12 @@ static int __init cy_detect_isa(void)
|
|||
|
||||
/* set cy_card */
|
||||
cy_card[j].base_addr = cy_isa_address;
|
||||
cy_card[j].ctl_addr = NULL;
|
||||
cy_card[j].ctl_addr.p9050 = NULL;
|
||||
cy_card[j].irq = (int)cy_isa_irq;
|
||||
cy_card[j].bus_index = 0;
|
||||
cy_card[j].first_line = cy_next_channel;
|
||||
cy_card[j].num_chips = cy_isa_nchan / 4;
|
||||
cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
|
||||
cy_card[j].nports = cy_isa_nchan;
|
||||
if (cy_init_card(&cy_card[j])) {
|
||||
cy_card[j].base_addr = NULL;
|
||||
free_irq(cy_isa_irq, &cy_card[j]);
|
||||
|
|
@ -4781,7 +4743,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
|
|||
struct CUSTOM_REG __iomem *cust = base_addr;
|
||||
struct ZFW_CTRL __iomem *pt_zfwctrl;
|
||||
void __iomem *tmp;
|
||||
u32 mailbox, status;
|
||||
u32 mailbox, status, nchan;
|
||||
unsigned int i;
|
||||
int retval;
|
||||
|
||||
|
|
@ -4793,7 +4755,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
|
|||
|
||||
/* Check whether the firmware is already loaded and running. If
|
||||
positive, skip this board */
|
||||
if (Z_FPGA_LOADED(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
|
||||
if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
|
||||
u32 cntval = readl(base_addr + 0x190);
|
||||
|
||||
udelay(100);
|
||||
|
|
@ -4812,7 +4774,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
|
|||
|
||||
mailbox = readl(&ctl_addr->mail_box_0);
|
||||
|
||||
if (mailbox == 0 || Z_FPGA_LOADED(ctl_addr)) {
|
||||
if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
|
||||
/* stops CPU and set window to beginning of RAM */
|
||||
cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
|
||||
cy_writel(&cust->cpu_stop, 0);
|
||||
|
|
@ -4828,7 +4790,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
|
|||
base_addr);
|
||||
if (retval)
|
||||
goto err_rel;
|
||||
if (!Z_FPGA_LOADED(ctl_addr)) {
|
||||
if (!__cyz_fpga_loaded(ctl_addr)) {
|
||||
dev_err(&pdev->dev, "fw upload successful, but fw is "
|
||||
"not loaded\n");
|
||||
goto err_rel;
|
||||
|
|
@ -4887,7 +4849,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
|
|||
"system before loading the new FW to the "
|
||||
"Cyclades-Z.\n");
|
||||
|
||||
if (Z_FPGA_LOADED(ctl_addr))
|
||||
if (__cyz_fpga_loaded(ctl_addr))
|
||||
plx_init(pdev, irq, ctl_addr);
|
||||
|
||||
retval = -EIO;
|
||||
|
|
@ -4902,16 +4864,16 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
|
|||
base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
|
||||
base_addr + readl(&fid->zfwctrl_addr));
|
||||
|
||||
nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
|
||||
dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
|
||||
readl(&pt_zfwctrl->board_ctrl.fw_version),
|
||||
readl(&pt_zfwctrl->board_ctrl.n_channel));
|
||||
readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
|
||||
|
||||
if (readl(&pt_zfwctrl->board_ctrl.n_channel) == 0) {
|
||||
if (nchan == 0) {
|
||||
dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
|
||||
"check the connection between the Z host card and the "
|
||||
"serial expanders.\n");
|
||||
|
||||
if (Z_FPGA_LOADED(ctl_addr))
|
||||
if (__cyz_fpga_loaded(ctl_addr))
|
||||
plx_init(pdev, irq, ctl_addr);
|
||||
|
||||
dev_info(&pdev->dev, "Null number of ports detected. Board "
|
||||
|
|
@ -4932,9 +4894,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
|
|||
cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
|
||||
0x00030800UL);
|
||||
|
||||
plx_init(pdev, irq, ctl_addr);
|
||||
|
||||
return 0;
|
||||
return nchan;
|
||||
err_rel:
|
||||
release_firmware(fw);
|
||||
err:
|
||||
|
|
@ -4946,7 +4906,7 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
|
|||
{
|
||||
void __iomem *addr0 = NULL, *addr2 = NULL;
|
||||
char *card_name = NULL;
|
||||
u32 mailbox;
|
||||
u32 uninitialized_var(mailbox);
|
||||
unsigned int device_id, nchan = 0, card_no, i;
|
||||
unsigned char plx_ver;
|
||||
int retval, irq;
|
||||
|
|
@ -5023,11 +4983,12 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
|
|||
}
|
||||
|
||||
/* Disable interrupts on the PLX before resetting it */
|
||||
cy_writew(addr0 + 0x68, readw(addr0 + 0x68) & ~0x0900);
|
||||
cy_writew(&ctl_addr->intr_ctrl_stat,
|
||||
readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
|
||||
|
||||
plx_init(pdev, irq, addr0);
|
||||
|
||||
mailbox = (u32)readl(&ctl_addr->mail_box_0);
|
||||
mailbox = readl(&ctl_addr->mail_box_0);
|
||||
|
||||
addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
|
||||
mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
|
||||
|
|
@ -5038,12 +4999,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
|
|||
|
||||
if (mailbox == ZE_V1) {
|
||||
card_name = "Cyclades-Ze";
|
||||
|
||||
readl(&ctl_addr->mail_box_0);
|
||||
nchan = ZE_V1_NPORTS;
|
||||
} else {
|
||||
card_name = "Cyclades-8Zo";
|
||||
|
||||
#ifdef CY_PCI_DEBUG
|
||||
if (mailbox == ZO_V1) {
|
||||
cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
|
||||
|
|
@ -5065,15 +5022,12 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
|
|||
*/
|
||||
if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
|
||||
cy_writel(addr2 + ID_ADDRESS, 0L);
|
||||
|
||||
retval = cyz_load_fw(pdev, addr2, addr0, irq);
|
||||
if (retval)
|
||||
goto err_unmap;
|
||||
/* This must be a Cyclades-8Zo/PCI. The extendable
|
||||
version will have a different device_id and will
|
||||
be allocated its maximum number of ports. */
|
||||
nchan = 8;
|
||||
}
|
||||
|
||||
retval = cyz_load_fw(pdev, addr2, addr0, irq);
|
||||
if (retval <= 0)
|
||||
goto err_unmap;
|
||||
nchan = retval;
|
||||
}
|
||||
|
||||
if ((cy_next_channel + nchan) > NR_PORTS) {
|
||||
|
|
@ -5103,8 +5057,10 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
|
|||
dev_err(&pdev->dev, "could not allocate IRQ\n");
|
||||
goto err_unmap;
|
||||
}
|
||||
cy_card[card_no].num_chips = nchan / 4;
|
||||
cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
|
||||
} else {
|
||||
cy_card[card_no].hw_ver = mailbox;
|
||||
cy_card[card_no].num_chips = (unsigned int)-1;
|
||||
#ifdef CONFIG_CYZ_INTR
|
||||
/* allocate IRQ only if board has an IRQ */
|
||||
if (irq != 0 && irq != 255) {
|
||||
|
|
@ -5117,15 +5073,15 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
|
|||
}
|
||||
}
|
||||
#endif /* CONFIG_CYZ_INTR */
|
||||
cy_card[card_no].num_chips = (unsigned int)-1;
|
||||
}
|
||||
|
||||
/* set cy_card */
|
||||
cy_card[card_no].base_addr = addr2;
|
||||
cy_card[card_no].ctl_addr = addr0;
|
||||
cy_card[card_no].ctl_addr.p9050 = addr0;
|
||||
cy_card[card_no].irq = irq;
|
||||
cy_card[card_no].bus_index = 1;
|
||||
cy_card[card_no].first_line = cy_next_channel;
|
||||
cy_card[card_no].nports = nchan;
|
||||
retval = cy_init_card(&cy_card[card_no]);
|
||||
if (retval)
|
||||
goto err_null;
|
||||
|
|
@ -5138,17 +5094,20 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
|
|||
plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
|
||||
switch (plx_ver) {
|
||||
case PLX_9050:
|
||||
|
||||
cy_writeb(addr0 + 0x4c, 0x43);
|
||||
break;
|
||||
|
||||
case PLX_9060:
|
||||
case PLX_9080:
|
||||
default: /* Old boards, use PLX_9060 */
|
||||
plx_init(pdev, irq, addr0);
|
||||
cy_writew(addr0 + 0x68, readw(addr0 + 0x68) | 0x0900);
|
||||
{
|
||||
struct RUNTIME_9060 __iomem *ctl_addr = addr0;
|
||||
plx_init(pdev, irq, ctl_addr);
|
||||
cy_writew(&ctl_addr->intr_ctrl_stat,
|
||||
readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
|
||||
|
|
@ -5179,22 +5138,23 @@ static void __devexit cy_pci_remove(struct pci_dev *pdev)
|
|||
unsigned int i;
|
||||
|
||||
/* non-Z with old PLX */
|
||||
if (!IS_CYC_Z(*cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
|
||||
if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
|
||||
PLX_9050)
|
||||
cy_writeb(cinfo->ctl_addr + 0x4c, 0);
|
||||
cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
|
||||
else
|
||||
#ifndef CONFIG_CYZ_INTR
|
||||
if (!IS_CYC_Z(*cinfo))
|
||||
if (!cy_is_Z(cinfo))
|
||||
#endif
|
||||
cy_writew(cinfo->ctl_addr + 0x68,
|
||||
readw(cinfo->ctl_addr + 0x68) & ~0x0900);
|
||||
cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
|
||||
readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
|
||||
~0x0900);
|
||||
|
||||
iounmap(cinfo->base_addr);
|
||||
if (cinfo->ctl_addr)
|
||||
iounmap(cinfo->ctl_addr);
|
||||
if (cinfo->ctl_addr.p9050)
|
||||
iounmap(cinfo->ctl_addr.p9050);
|
||||
if (cinfo->irq
|
||||
#ifndef CONFIG_CYZ_INTR
|
||||
&& !IS_CYC_Z(*cinfo)
|
||||
&& !cy_is_Z(cinfo)
|
||||
#endif /* CONFIG_CYZ_INTR */
|
||||
)
|
||||
free_irq(cinfo->irq, cinfo);
|
||||
|
|
@ -5240,7 +5200,7 @@ static int cyclades_proc_show(struct seq_file *m, void *v)
|
|||
(cur_jifs - info->idle_stats.recv_idle)/
|
||||
HZ, info->idle_stats.overruns,
|
||||
/* FIXME: double check locking */
|
||||
(long)info->port.tty->ldisc.ops->num);
|
||||
(long)info->port.tty->ldisc->ops->num);
|
||||
else
|
||||
seq_printf(m, "%3d %8lu %10lu %8lu "
|
||||
"%10lu %8lu %9lu %6ld\n",
|
||||
|
|
@ -5386,11 +5346,11 @@ static void __exit cy_cleanup_module(void)
|
|||
/* clear interrupt */
|
||||
cy_writeb(card->base_addr + Cy_ClrIntr, 0);
|
||||
iounmap(card->base_addr);
|
||||
if (card->ctl_addr)
|
||||
iounmap(card->ctl_addr);
|
||||
if (card->ctl_addr.p9050)
|
||||
iounmap(card->ctl_addr.p9050);
|
||||
if (card->irq
|
||||
#ifndef CONFIG_CYZ_INTR
|
||||
&& !IS_CYC_Z(*card)
|
||||
&& !cy_is_Z(card)
|
||||
#endif /* CONFIG_CYZ_INTR */
|
||||
)
|
||||
free_irq(card->irq, card);
|
||||
|
|
|
|||
|
|
@ -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 @@ err:
|
|||
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))
|
||||
|
|
|
|||
|
|
@ -115,19 +115,22 @@ EXPORT_SYMBOL(tty_unregister_ldisc);
|
|||
/**
|
||||
* tty_ldisc_try_get - try and reference an ldisc
|
||||
* @disc: ldisc number
|
||||
* @ld: tty ldisc structure to complete
|
||||
*
|
||||
* Attempt to open and lock a line discipline into place. Return
|
||||
* the line discipline refcounted and assigned in ld. On an error
|
||||
* report the error code back
|
||||
* the line discipline refcounted or an error.
|
||||
*/
|
||||
|
||||
static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld)
|
||||
static struct tty_ldisc *tty_ldisc_try_get(int disc)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct tty_ldisc *ld;
|
||||
struct tty_ldisc_ops *ldops;
|
||||
int err = -EINVAL;
|
||||
|
||||
|
||||
ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
|
||||
if (ld == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
ld->ops = NULL;
|
||||
ldops = tty_ldiscs[disc];
|
||||
|
|
@ -140,17 +143,19 @@ static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld)
|
|||
/* lock it */
|
||||
ldops->refcount++;
|
||||
ld->ops = ldops;
|
||||
ld->refcount = 0;
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
return err;
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
return ld;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_get - take a reference to an ldisc
|
||||
* @disc: ldisc number
|
||||
* @ld: tty line discipline structure to use
|
||||
*
|
||||
* Takes a reference to a line discipline. Deals with refcounts and
|
||||
* module locking counts. Returns NULL if the discipline is not available.
|
||||
|
|
@ -161,52 +166,54 @@ static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld)
|
|||
* takes tty_ldisc_lock to guard against ldisc races
|
||||
*/
|
||||
|
||||
static int tty_ldisc_get(int disc, struct tty_ldisc *ld)
|
||||
static struct tty_ldisc *tty_ldisc_get(int disc)
|
||||
{
|
||||
int err;
|
||||
struct tty_ldisc *ld;
|
||||
|
||||
if (disc < N_TTY || disc >= NR_LDISCS)
|
||||
return -EINVAL;
|
||||
err = tty_ldisc_try_get(disc, ld);
|
||||
if (err < 0) {
|
||||
return ERR_PTR(-EINVAL);
|
||||
ld = tty_ldisc_try_get(disc);
|
||||
if (IS_ERR(ld)) {
|
||||
request_module("tty-ldisc-%d", disc);
|
||||
err = tty_ldisc_try_get(disc, ld);
|
||||
ld = tty_ldisc_try_get(disc);
|
||||
}
|
||||
return err;
|
||||
return ld;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_put - drop ldisc reference
|
||||
* @disc: ldisc number
|
||||
* @ld: ldisc
|
||||
*
|
||||
* Drop a reference to a line discipline. Manage refcounts and
|
||||
* module usage counts
|
||||
* module usage counts. Free the ldisc once the recount hits zero.
|
||||
*
|
||||
* Locking:
|
||||
* takes tty_ldisc_lock to guard against ldisc races
|
||||
*/
|
||||
|
||||
static void tty_ldisc_put(struct tty_ldisc_ops *ld)
|
||||
static void tty_ldisc_put(struct tty_ldisc *ld)
|
||||
{
|
||||
unsigned long flags;
|
||||
int disc = ld->num;
|
||||
int disc = ld->ops->num;
|
||||
struct tty_ldisc_ops *ldo;
|
||||
|
||||
BUG_ON(disc < N_TTY || disc >= NR_LDISCS);
|
||||
|
||||
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
ld = tty_ldiscs[disc];
|
||||
BUG_ON(ld->refcount == 0);
|
||||
ld->refcount--;
|
||||
module_put(ld->owner);
|
||||
ldo = tty_ldiscs[disc];
|
||||
BUG_ON(ldo->refcount == 0);
|
||||
ldo->refcount--;
|
||||
module_put(ldo->owner);
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
kfree(ld);
|
||||
}
|
||||
|
||||
static void * tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
|
||||
static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
|
||||
{
|
||||
return (*pos < NR_LDISCS) ? pos : NULL;
|
||||
}
|
||||
|
||||
static void * tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
static void *tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
{
|
||||
(*pos)++;
|
||||
return (*pos < NR_LDISCS) ? pos : NULL;
|
||||
|
|
@ -219,12 +226,13 @@ static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
|
|||
static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
|
||||
{
|
||||
int i = *(loff_t *)v;
|
||||
struct tty_ldisc ld;
|
||||
|
||||
if (tty_ldisc_get(i, &ld) < 0)
|
||||
struct tty_ldisc *ld;
|
||||
|
||||
ld = tty_ldisc_try_get(i);
|
||||
if (IS_ERR(ld))
|
||||
return 0;
|
||||
seq_printf(m, "%-10s %2d\n", ld.ops->name ? ld.ops->name : "???", i);
|
||||
tty_ldisc_put(ld.ops);
|
||||
seq_printf(m, "%-10s %2d\n", ld->ops->name ? ld->ops->name : "???", i);
|
||||
tty_ldisc_put(ld);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -263,8 +271,7 @@ const struct file_operations tty_ldiscs_proc_fops = {
|
|||
|
||||
static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
|
||||
{
|
||||
ld->refcount = 0;
|
||||
tty->ldisc = *ld;
|
||||
tty->ldisc = ld;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -286,7 +293,7 @@ static int tty_ldisc_try(struct tty_struct *tty)
|
|||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
ld = &tty->ldisc;
|
||||
ld = tty->ldisc;
|
||||
if (test_bit(TTY_LDISC, &tty->flags)) {
|
||||
ld->refcount++;
|
||||
ret = 1;
|
||||
|
|
@ -315,10 +322,9 @@ struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
|
|||
{
|
||||
/* wait_event is a macro */
|
||||
wait_event(tty_ldisc_wait, tty_ldisc_try(tty));
|
||||
WARN_ON(tty->ldisc.refcount == 0);
|
||||
return &tty->ldisc;
|
||||
WARN_ON(tty->ldisc->refcount == 0);
|
||||
return tty->ldisc;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
|
||||
|
||||
/**
|
||||
|
|
@ -335,10 +341,9 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
|
|||
struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
|
||||
{
|
||||
if (tty_ldisc_try(tty))
|
||||
return &tty->ldisc;
|
||||
return tty->ldisc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(tty_ldisc_ref);
|
||||
|
||||
/**
|
||||
|
|
@ -366,7 +371,6 @@ void tty_ldisc_deref(struct tty_ldisc *ld)
|
|||
wake_up(&tty_ldisc_wait);
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(tty_ldisc_deref);
|
||||
|
||||
/**
|
||||
|
|
@ -388,6 +392,26 @@ void tty_ldisc_enable(struct tty_struct *tty)
|
|||
wake_up(&tty_ldisc_wait);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_set_termios_ldisc - set ldisc field
|
||||
* @tty: tty structure
|
||||
|
|
@ -407,6 +431,39 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
|
|||
mutex_unlock(&tty->termios_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_open - open a line discipline
|
||||
* @tty: tty we are opening the ldisc on
|
||||
* @ld: discipline to open
|
||||
*
|
||||
* A helper opening method. Also a convenient debugging and check
|
||||
* point.
|
||||
*/
|
||||
|
||||
static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
|
||||
{
|
||||
WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
|
||||
if (ld->ops->open)
|
||||
return ld->ops->open(tty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_close - close a line discipline
|
||||
* @tty: tty we are opening the ldisc on
|
||||
* @ld: discipline to close
|
||||
*
|
||||
* A helper close method. Also a convenient debugging and check
|
||||
* point.
|
||||
*/
|
||||
|
||||
static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
|
||||
{
|
||||
WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags));
|
||||
clear_bit(TTY_LDISC_OPEN, &tty->flags);
|
||||
if (ld->ops->close)
|
||||
ld->ops->close(tty);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_restore - helper for tty ldisc change
|
||||
|
|
@ -420,66 +477,136 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
|
|||
static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
|
||||
{
|
||||
char buf[64];
|
||||
struct tty_ldisc new_ldisc;
|
||||
struct tty_ldisc *new_ldisc;
|
||||
int r;
|
||||
|
||||
/* There is an outstanding reference here so this is safe */
|
||||
tty_ldisc_get(old->ops->num, old);
|
||||
old = tty_ldisc_get(old->ops->num);
|
||||
WARN_ON(IS_ERR(old));
|
||||
tty_ldisc_assign(tty, old);
|
||||
tty_set_termios_ldisc(tty, old->ops->num);
|
||||
if (old->ops->open && (old->ops->open(tty) < 0)) {
|
||||
tty_ldisc_put(old->ops);
|
||||
if (tty_ldisc_open(tty, old) < 0) {
|
||||
tty_ldisc_put(old);
|
||||
/* This driver is always present */
|
||||
if (tty_ldisc_get(N_TTY, &new_ldisc) < 0)
|
||||
new_ldisc = tty_ldisc_get(N_TTY);
|
||||
if (IS_ERR(new_ldisc))
|
||||
panic("n_tty: get");
|
||||
tty_ldisc_assign(tty, &new_ldisc);
|
||||
tty_ldisc_assign(tty, new_ldisc);
|
||||
tty_set_termios_ldisc(tty, N_TTY);
|
||||
if (new_ldisc.ops->open) {
|
||||
int r = new_ldisc.ops->open(tty);
|
||||
if (r < 0)
|
||||
panic("Couldn't open N_TTY ldisc for "
|
||||
"%s --- error %d.",
|
||||
tty_name(tty, buf), r);
|
||||
}
|
||||
r = tty_ldisc_open(tty, new_ldisc);
|
||||
if (r < 0)
|
||||
panic("Couldn't open N_TTY ldisc for "
|
||||
"%s --- error %d.",
|
||||
tty_name(tty, buf), r);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_halt - shut down the line discipline
|
||||
* @tty: tty device
|
||||
*
|
||||
* Shut down the line discipline and work queue for this tty device.
|
||||
* The TTY_LDISC flag being cleared ensures no further references can
|
||||
* be obtained while the delayed work queue halt ensures that no more
|
||||
* data is fed to the ldisc.
|
||||
*
|
||||
* In order to wait for any existing references to complete see
|
||||
* tty_ldisc_wait_idle.
|
||||
*/
|
||||
|
||||
static int tty_ldisc_halt(struct tty_struct *tty)
|
||||
{
|
||||
clear_bit(TTY_LDISC, &tty->flags);
|
||||
return cancel_delayed_work(&tty->buf.work);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_wait_idle - wait for the ldisc to become idle
|
||||
* @tty: tty to wait for
|
||||
*
|
||||
* Wait for the line discipline to become idle. The discipline must
|
||||
* have been halted for this to guarantee it remains idle.
|
||||
*
|
||||
* tty_ldisc_lock protects the ref counts currently.
|
||||
*/
|
||||
|
||||
static int tty_ldisc_wait_idle(struct tty_struct *tty)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
while (tty->ldisc->refcount) {
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
if (wait_event_timeout(tty_ldisc_wait,
|
||||
tty->ldisc->refcount == 0, 5 * HZ) == 0)
|
||||
return -EBUSY;
|
||||
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_set_ldisc - set line discipline
|
||||
* @tty: the terminal to set
|
||||
* @ldisc: the line discipline
|
||||
*
|
||||
* Set the discipline of a tty line. Must be called from a process
|
||||
* context.
|
||||
* context. The ldisc change logic has to protect itself against any
|
||||
* overlapping ldisc change (including on the other end of pty pairs),
|
||||
* the close of one side of a tty/pty pair, and eventually hangup.
|
||||
*
|
||||
* Locking: takes tty_ldisc_lock.
|
||||
* called functions take termios_mutex
|
||||
* Locking: takes tty_ldisc_lock, termios_mutex
|
||||
*/
|
||||
|
||||
int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
||||
{
|
||||
int retval;
|
||||
struct tty_ldisc o_ldisc, new_ldisc;
|
||||
int work;
|
||||
unsigned long flags;
|
||||
struct tty_ldisc *o_ldisc, *new_ldisc;
|
||||
int work, o_work = 0;
|
||||
struct tty_struct *o_tty;
|
||||
|
||||
restart:
|
||||
/* This is a bit ugly for now but means we can break the 'ldisc
|
||||
is part of the tty struct' assumption later */
|
||||
retval = tty_ldisc_get(ldisc, &new_ldisc);
|
||||
if (retval)
|
||||
return retval;
|
||||
new_ldisc = tty_ldisc_get(ldisc);
|
||||
if (IS_ERR(new_ldisc))
|
||||
return PTR_ERR(new_ldisc);
|
||||
|
||||
/*
|
||||
* We need to look at the tty locking here for pty/tty pairs
|
||||
* when both sides try to change in parallel.
|
||||
*/
|
||||
|
||||
o_tty = tty->link; /* o_tty is the pty side or NULL */
|
||||
|
||||
|
||||
/*
|
||||
* Check the no-op case
|
||||
*/
|
||||
|
||||
if (tty->ldisc->ops->num == ldisc) {
|
||||
tty_ldisc_put(new_ldisc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Problem: What do we do if this blocks ?
|
||||
* We could deadlock here
|
||||
*/
|
||||
|
||||
tty_wait_until_sent(tty, 0);
|
||||
|
||||
if (tty->ldisc.ops->num == ldisc) {
|
||||
tty_ldisc_put(new_ldisc.ops);
|
||||
return 0;
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
|
||||
/*
|
||||
* We could be midstream of another ldisc change which has
|
||||
* dropped the lock during processing. If so we need to wait.
|
||||
*/
|
||||
|
||||
while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
wait_event(tty_ldisc_wait,
|
||||
test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
}
|
||||
set_bit(TTY_LDISC_CHANGING, &tty->flags);
|
||||
|
||||
/*
|
||||
* No more input please, we are switching. The new ldisc
|
||||
|
|
@ -489,8 +616,6 @@ restart:
|
|||
tty->receive_room = 0;
|
||||
|
||||
o_ldisc = tty->ldisc;
|
||||
o_tty = tty->link;
|
||||
|
||||
/*
|
||||
* Make sure we don't change while someone holds a
|
||||
* reference to the line discipline. The TTY_LDISC bit
|
||||
|
|
@ -501,108 +626,181 @@ restart:
|
|||
* with a userspace app continually trying to use the tty in
|
||||
* parallel to the change and re-referencing the tty.
|
||||
*/
|
||||
clear_bit(TTY_LDISC, &tty->flags);
|
||||
if (o_tty)
|
||||
clear_bit(TTY_LDISC, &o_tty->flags);
|
||||
|
||||
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) {
|
||||
if (tty->ldisc.refcount) {
|
||||
/* Free the new ldisc we grabbed. Must drop the lock
|
||||
first. */
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
tty_ldisc_put(o_ldisc.ops);
|
||||
/*
|
||||
* There are several reasons we may be busy, including
|
||||
* random momentary I/O traffic. We must therefore
|
||||
* retry. We could distinguish between blocking ops
|
||||
* and retries if we made tty_ldisc_wait() smarter.
|
||||
* That is up for discussion.
|
||||
*/
|
||||
if (wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0)
|
||||
return -ERESTARTSYS;
|
||||
goto restart;
|
||||
}
|
||||
if (o_tty && o_tty->ldisc.refcount) {
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
tty_ldisc_put(o_tty->ldisc.ops);
|
||||
if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0)
|
||||
return -ERESTARTSYS;
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If the TTY_LDISC bit is set, then we are racing against
|
||||
* another ldisc change
|
||||
*/
|
||||
if (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
|
||||
struct tty_ldisc *ld;
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
tty_ldisc_put(new_ldisc.ops);
|
||||
ld = tty_ldisc_ref_wait(tty);
|
||||
tty_ldisc_deref(ld);
|
||||
goto restart;
|
||||
}
|
||||
/*
|
||||
* This flag is used to avoid two parallel ldisc changes. Once
|
||||
* open and close are fine grained locked this may work better
|
||||
* as a mutex shared with the open/close/hup paths
|
||||
*/
|
||||
set_bit(TTY_LDISC_CHANGING, &tty->flags);
|
||||
work = tty_ldisc_halt(tty);
|
||||
if (o_tty)
|
||||
set_bit(TTY_LDISC_CHANGING, &o_tty->flags);
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
|
||||
o_work = tty_ldisc_halt(o_tty);
|
||||
|
||||
/*
|
||||
* From this point on we know nobody has an ldisc
|
||||
* usage reference, nor can they obtain one until
|
||||
* we say so later on.
|
||||
* Wait for ->hangup_work and ->buf.work handlers to terminate.
|
||||
* We must drop the mutex here in case a hangup is also in process.
|
||||
*/
|
||||
|
||||
work = cancel_delayed_work(&tty->buf.work);
|
||||
/*
|
||||
* Wait for ->hangup_work and ->buf.work handlers to terminate
|
||||
* MUST NOT hold locks here.
|
||||
*/
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
|
||||
flush_scheduled_work();
|
||||
|
||||
/* Let any existing reference holders finish */
|
||||
retval = tty_ldisc_wait_idle(tty);
|
||||
if (retval < 0) {
|
||||
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
|
||||
tty_ldisc_put(new_ldisc);
|
||||
return retval;
|
||||
}
|
||||
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
if (test_bit(TTY_HUPPED, &tty->flags)) {
|
||||
/* We were raced by the hangup method. It will have stomped
|
||||
the ldisc data and closed the ldisc down */
|
||||
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
tty_ldisc_put(new_ldisc);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Shutdown the current discipline. */
|
||||
if (o_ldisc.ops->close)
|
||||
(o_ldisc.ops->close)(tty);
|
||||
tty_ldisc_close(tty, o_ldisc);
|
||||
|
||||
/* Now set up the new line discipline. */
|
||||
tty_ldisc_assign(tty, &new_ldisc);
|
||||
tty_ldisc_assign(tty, new_ldisc);
|
||||
tty_set_termios_ldisc(tty, ldisc);
|
||||
if (new_ldisc.ops->open)
|
||||
retval = (new_ldisc.ops->open)(tty);
|
||||
|
||||
retval = tty_ldisc_open(tty, new_ldisc);
|
||||
if (retval < 0) {
|
||||
tty_ldisc_put(new_ldisc.ops);
|
||||
tty_ldisc_restore(tty, &o_ldisc);
|
||||
/* Back to the old one or N_TTY if we can't */
|
||||
tty_ldisc_put(new_ldisc);
|
||||
tty_ldisc_restore(tty, o_ldisc);
|
||||
}
|
||||
|
||||
/* At this point we hold a reference to the new ldisc and a
|
||||
a reference to the old ldisc. If we ended up flipping back
|
||||
to the existing ldisc we have two references to it */
|
||||
|
||||
if (tty->ldisc.ops->num != o_ldisc.ops->num && tty->ops->set_ldisc)
|
||||
if (tty->ldisc->ops->num != o_ldisc->ops->num && tty->ops->set_ldisc)
|
||||
tty->ops->set_ldisc(tty);
|
||||
|
||||
tty_ldisc_put(o_ldisc.ops);
|
||||
tty_ldisc_put(o_ldisc);
|
||||
|
||||
/*
|
||||
* Allow ldisc referencing to occur as soon as the driver
|
||||
* ldisc callback completes.
|
||||
* Allow ldisc referencing to occur again
|
||||
*/
|
||||
|
||||
tty_ldisc_enable(tty);
|
||||
if (o_tty)
|
||||
tty_ldisc_enable(o_tty);
|
||||
|
||||
/* Restart it in case no characters kick it off. Safe if
|
||||
/* Restart the work queue in case no characters kick it off. Safe if
|
||||
already running */
|
||||
if (work)
|
||||
schedule_delayed_work(&tty->buf.work, 1);
|
||||
if (o_work)
|
||||
schedule_delayed_work(&o_tty->buf.work, 1);
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tty_ldisc_reinit - reinitialise the tty ldisc
|
||||
* @tty: tty to reinit
|
||||
*
|
||||
* Switch the tty back to N_TTY line discipline and leave the
|
||||
* ldisc state closed
|
||||
*/
|
||||
|
||||
static void tty_ldisc_reinit(struct tty_struct *tty)
|
||||
{
|
||||
struct tty_ldisc *ld;
|
||||
|
||||
tty_ldisc_close(tty, tty->ldisc);
|
||||
tty_ldisc_put(tty->ldisc);
|
||||
tty->ldisc = NULL;
|
||||
/*
|
||||
* Switch the line discipline back
|
||||
*/
|
||||
ld = tty_ldisc_get(N_TTY);
|
||||
BUG_ON(IS_ERR(ld));
|
||||
tty_ldisc_assign(tty, ld);
|
||||
tty_set_termios_ldisc(tty, N_TTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_hangup - hangup ldisc reset
|
||||
* @tty: tty being hung up
|
||||
*
|
||||
* Some tty devices reset their termios when they receive a hangup
|
||||
* event. In that situation we must also switch back to N_TTY properly
|
||||
* before we reset the termios data.
|
||||
*
|
||||
* Locking: We can take the ldisc mutex as the rest of the code is
|
||||
* careful to allow for this.
|
||||
*
|
||||
* In the pty pair case this occurs in the close() path of the
|
||||
* tty itself so we must be careful about locking rules.
|
||||
*/
|
||||
|
||||
void tty_ldisc_hangup(struct tty_struct *tty)
|
||||
{
|
||||
struct tty_ldisc *ld;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
tty_ldisc_deref(ld);
|
||||
}
|
||||
/*
|
||||
* 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) {
|
||||
/* Avoid racing set_ldisc */
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
/* Switch back to N_TTY */
|
||||
tty_ldisc_reinit(tty);
|
||||
/* At this point we have a closed ldisc and we want to
|
||||
reopen it. We could defer this to the next open but
|
||||
it means auditing a lot of other paths so this is a FIXME */
|
||||
WARN_ON(tty_ldisc_open(tty, tty->ldisc));
|
||||
tty_ldisc_enable(tty);
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
tty_reset_termios(tty);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_setup - open line discipline
|
||||
|
|
@ -610,24 +808,23 @@ restart:
|
|||
* @o_tty: pair tty for pty/tty pairs
|
||||
*
|
||||
* Called during the initial open of a tty/pty pair in order to set up the
|
||||
* line discplines and bind them to the tty.
|
||||
* line disciplines and bind them to the tty. This has no locking issues
|
||||
* as the device isn't yet active.
|
||||
*/
|
||||
|
||||
int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
|
||||
{
|
||||
struct tty_ldisc *ld = &tty->ldisc;
|
||||
struct tty_ldisc *ld = tty->ldisc;
|
||||
int retval;
|
||||
|
||||
if (ld->ops->open) {
|
||||
retval = (ld->ops->open)(tty);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
if (o_tty && o_tty->ldisc.ops->open) {
|
||||
retval = (o_tty->ldisc.ops->open)(o_tty);
|
||||
retval = tty_ldisc_open(tty, ld);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (o_tty) {
|
||||
retval = tty_ldisc_open(o_tty, o_tty->ldisc);
|
||||
if (retval) {
|
||||
if (ld->ops->close)
|
||||
(ld->ops->close)(tty);
|
||||
tty_ldisc_close(tty, ld);
|
||||
return retval;
|
||||
}
|
||||
tty_ldisc_enable(o_tty);
|
||||
|
|
@ -635,32 +832,25 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
|
|||
tty_ldisc_enable(tty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_release - release line discipline
|
||||
* @tty: tty being shut down
|
||||
* @o_tty: pair tty for pty/tty pairs
|
||||
*
|
||||
* Called during the final close of a tty/pty pair in order to shut down the
|
||||
* line discpline layer.
|
||||
* Called during the final close of a tty/pty pair in order to shut down
|
||||
* the line discpline layer. On exit the ldisc assigned is N_TTY and the
|
||||
* ldisc has not been opened.
|
||||
*/
|
||||
|
||||
void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct tty_ldisc ld;
|
||||
/*
|
||||
* Prevent flush_to_ldisc() from rescheduling the work for later. Then
|
||||
* kill any delayed work. As this is the final close it does not
|
||||
* race with the set_ldisc code path.
|
||||
*/
|
||||
clear_bit(TTY_LDISC, &tty->flags);
|
||||
cancel_delayed_work(&tty->buf.work);
|
||||
|
||||
/*
|
||||
* Wait for ->hangup_work and ->buf.work handlers to terminate
|
||||
*/
|
||||
|
||||
tty_ldisc_halt(tty);
|
||||
flush_scheduled_work();
|
||||
|
||||
/*
|
||||
|
|
@ -668,38 +858,19 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
|
|||
* side waiters as the file is closing so user count on the file
|
||||
* side is zero.
|
||||
*/
|
||||
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
while (tty->ldisc.refcount) {
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0);
|
||||
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
|
||||
tty_ldisc_wait_idle(tty);
|
||||
|
||||
/*
|
||||
* Shutdown the current line discipline, and reset it to N_TTY.
|
||||
*
|
||||
* FIXME: this MUST get fixed for the new reflocking
|
||||
*/
|
||||
if (tty->ldisc.ops->close)
|
||||
(tty->ldisc.ops->close)(tty);
|
||||
tty_ldisc_put(tty->ldisc.ops);
|
||||
|
||||
/*
|
||||
* Switch the line discipline back
|
||||
*/
|
||||
WARN_ON(tty_ldisc_get(N_TTY, &ld));
|
||||
tty_ldisc_assign(tty, &ld);
|
||||
tty_set_termios_ldisc(tty, N_TTY);
|
||||
if (o_tty) {
|
||||
/* FIXME: could o_tty be in setldisc here ? */
|
||||
clear_bit(TTY_LDISC, &o_tty->flags);
|
||||
if (o_tty->ldisc.ops->close)
|
||||
(o_tty->ldisc.ops->close)(o_tty);
|
||||
tty_ldisc_put(o_tty->ldisc.ops);
|
||||
WARN_ON(tty_ldisc_get(N_TTY, &ld));
|
||||
tty_ldisc_assign(o_tty, &ld);
|
||||
tty_set_termios_ldisc(o_tty, N_TTY);
|
||||
}
|
||||
tty_ldisc_reinit(tty);
|
||||
/* This will need doing differently if we need to lock */
|
||||
if (o_tty)
|
||||
tty_ldisc_release(o_tty, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -712,10 +883,10 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
|
|||
|
||||
void tty_ldisc_init(struct tty_struct *tty)
|
||||
{
|
||||
struct tty_ldisc ld;
|
||||
if (tty_ldisc_get(N_TTY, &ld) < 0)
|
||||
struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
|
||||
if (IS_ERR(ld))
|
||||
panic("n_tty: init_tty");
|
||||
tty_ldisc_assign(tty, &ld);
|
||||
tty_ldisc_assign(tty, ld);
|
||||
}
|
||||
|
||||
void tty_ldisc_begin(void)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue