TTY pull request for 3.5-rc1
Here's the big TTY/serial driver pull request for the 3.5-rc1 merge window. Nothing major in here, just lots of incremental changes from Alan and Jiri reworking some tty core things to behave better and to get a more solid grasp on some of the nasty tty locking issues. There are a few tty and serial driver updates in here as well. All of this has been in the linux-next releases for a while with no problems. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.18 (GNU/Linux) iEYEABECAAYFAk+7rBoACgkQMUfUDdst+ykXsgCfeDKx6ZgLidYy3H40Y2Pt3XEO TicAn1fcdGwOmMR/mowa+kTA68D/J6i2 =S7tG -----END PGP SIGNATURE----- Merge tag 'tty-3.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull TTY updates from Greg Kroah-Hartman: "Here's the big TTY/serial driver pull request for the 3.5-rc1 merge window. Nothing major in here, just lots of incremental changes from Alan and Jiri reworking some tty core things to behave better and to get a more solid grasp on some of the nasty tty locking issues. There are a few tty and serial driver updates in here as well. All of this has been in the linux-next releases for a while with no problems. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>" * tag 'tty-3.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (115 commits) serial: bfin_uart: Make MMR access compatible with 32 bits bf609 style controller. serial: bfin_uart: RTS and CTS MMRs can be either 16-bit width or 32-bit width. serial: bfin_uart: narrow the reboot condition in DMA tx interrupt serial: bfin_uart: Adapt bf5xx serial driver to bf60x serial4 controller. Revert "serial_core: Update buffer overrun statistics." tty: hvc_xen: NULL dereference on allocation failure tty: Fix LED error return tty: Allow uart_register/unregister/register tty: move global ldisc idle waitqueue to the individual ldisc serial8250-em: Add DT support serial8250-em: clk_get() IS_ERR() error handling fix serial_core: Update buffer overrun statistics. tty: drop the pty lock during hangup cris: fix missing tty arg in wait_event_interruptible_tty call tty/amiserial: Add missing argument for tty_unlock() tty_lock: Localise the lock pty: Lock the devpts bits privately tty_lock: undo the old tty_lock use on the ctty serial8250-em: Emma Mobile UART driver V2 Add missing call to uart_update_timeout() ...
This commit is contained in:
Коммит
94b5aff4c6
|
@ -245,14 +245,6 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
|
|||
omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate;
|
||||
omap_up.autosuspend_timeout = info->autosuspend_timeout;
|
||||
|
||||
/* Enable the MDR1 Errata i202 for OMAP2430/3xxx/44xx */
|
||||
if (!cpu_is_omap2420() && !cpu_is_ti816x())
|
||||
omap_up.errata |= UART_ERRATA_i202_MDR1_ACCESS;
|
||||
|
||||
/* Enable DMA Mode Force Idle Errata i291 for omap34xx/3630 */
|
||||
if (cpu_is_omap34xx() || cpu_is_omap3630())
|
||||
omap_up.errata |= UART_ERRATA_i291_DMA_FORCEIDLE;
|
||||
|
||||
pdata = &omap_up;
|
||||
pdata_size = sizeof(struct omap_uart_port_info);
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/of_serial.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/pda_power.h>
|
||||
|
@ -52,6 +53,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
|
|||
.irq = INT_UARTD,
|
||||
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
||||
.type = PORT_TEGRA,
|
||||
.handle_break = tegra_serial_handle_break,
|
||||
.iotype = UPIO_MEM,
|
||||
.regshift = 2,
|
||||
.uartclk = 216000000,
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/of_serial.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
|
@ -55,6 +56,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
|
|||
.irq = INT_UARTA,
|
||||
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
||||
.type = PORT_TEGRA,
|
||||
.handle_break = tegra_serial_handle_break,
|
||||
.iotype = UPIO_MEM,
|
||||
.regshift = 2,
|
||||
.uartclk = 216000000,
|
||||
|
@ -65,6 +67,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
|
|||
.irq = INT_UARTC,
|
||||
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
||||
.type = PORT_TEGRA,
|
||||
.handle_break = tegra_serial_handle_break,
|
||||
.iotype = UPIO_MEM,
|
||||
.regshift = 2,
|
||||
.uartclk = 216000000,
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/of_serial.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/input.h>
|
||||
|
@ -48,6 +49,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
|
|||
/* Memory and IRQ filled in before registration */
|
||||
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
||||
.type = PORT_TEGRA,
|
||||
.handle_break = tegra_serial_handle_break,
|
||||
.iotype = UPIO_MEM,
|
||||
.regshift = 2,
|
||||
.uartclk = 216000000,
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/of_serial.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
|
@ -49,6 +50,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
|
|||
.irq = INT_UARTA,
|
||||
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
||||
.type = PORT_TEGRA,
|
||||
.handle_break = tegra_serial_handle_break,
|
||||
.iotype = UPIO_MEM,
|
||||
.regshift = 2,
|
||||
.uartclk = 216000000,
|
||||
|
|
|
@ -65,7 +65,6 @@ struct omap_uart_port_info {
|
|||
bool dma_enabled; /* To specify DMA Mode */
|
||||
unsigned int uartclk; /* UART clock rate */
|
||||
upf_t flags; /* UPF_* flags */
|
||||
u32 errata;
|
||||
unsigned int dma_rx_buf_size;
|
||||
unsigned int dma_rx_timeout;
|
||||
unsigned int autosuspend_timeout;
|
||||
|
|
|
@ -46,7 +46,6 @@ static DEFINE_MUTEX(isdn_mutex);
|
|||
static char *isdn_revision = "$Revision: 1.1.2.3 $";
|
||||
|
||||
extern char *isdn_net_revision;
|
||||
extern char *isdn_tty_revision;
|
||||
#ifdef CONFIG_ISDN_PPP
|
||||
extern char *isdn_ppp_revision;
|
||||
#else
|
||||
|
@ -2327,8 +2326,6 @@ static int __init isdn_init(void)
|
|||
dev->chanmap[i] = -1;
|
||||
dev->m_idx[i] = -1;
|
||||
strcpy(dev->num[i], "???");
|
||||
init_waitqueue_head(&dev->mdm.info[i].open_wait);
|
||||
init_waitqueue_head(&dev->mdm.info[i].close_wait);
|
||||
}
|
||||
if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
|
||||
printk(KERN_WARNING "isdn: Could not register control devices\n");
|
||||
|
@ -2353,8 +2350,6 @@ static int __init isdn_init(void)
|
|||
|
||||
strcpy(tmprev, isdn_revision);
|
||||
printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev));
|
||||
strcpy(tmprev, isdn_tty_revision);
|
||||
printk("%s/", isdn_getrev(tmprev));
|
||||
strcpy(tmprev, isdn_net_revision);
|
||||
printk("%s/", isdn_getrev(tmprev));
|
||||
strcpy(tmprev, isdn_ppp_revision);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* $Id: isdn_tty.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
|
||||
*
|
||||
/*
|
||||
* Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
|
||||
*
|
||||
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
|
||||
|
@ -12,6 +11,7 @@
|
|||
#undef ISDN_TTY_STAT_DEBUG
|
||||
|
||||
#include <linux/isdn.h>
|
||||
#include <linux/serial.h> /* ASYNC_* flags */
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
|
@ -48,9 +48,6 @@ static int bit2si[8] =
|
|||
static int si2bit[8] =
|
||||
{4, 1, 4, 4, 4, 4, 4, 4};
|
||||
|
||||
char *isdn_tty_revision = "$Revision: 1.1.2.3 $";
|
||||
|
||||
|
||||
/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
|
||||
* to stuff incoming data directly into a tty's flip-buffer. This
|
||||
* is done to speed up tty-receiving if the receive-queue is empty.
|
||||
|
@ -68,49 +65,54 @@ isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
|
|||
struct tty_struct *tty;
|
||||
char last;
|
||||
|
||||
if (info->online) {
|
||||
if ((tty = info->tty)) {
|
||||
if (info->mcr & UART_MCR_RTS) {
|
||||
len = skb->len
|
||||
#ifdef CONFIG_ISDN_AUDIO
|
||||
+ ISDN_AUDIO_SKB_DLECOUNT(skb)
|
||||
#endif
|
||||
;
|
||||
if (!info->online)
|
||||
return 0;
|
||||
|
||||
c = tty_buffer_request_room(tty, len);
|
||||
if (c >= len) {
|
||||
tty = info->port.tty;
|
||||
if (!tty)
|
||||
return 0;
|
||||
|
||||
if (!(info->mcr & UART_MCR_RTS))
|
||||
return 0;
|
||||
|
||||
len = skb->len
|
||||
#ifdef CONFIG_ISDN_AUDIO
|
||||
if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
|
||||
int l = skb->len;
|
||||
unsigned char *dp = skb->data;
|
||||
while (--l) {
|
||||
if (*dp == DLE)
|
||||
tty_insert_flip_char(tty, DLE, 0);
|
||||
tty_insert_flip_char(tty, *dp++, 0);
|
||||
}
|
||||
if (*dp == DLE)
|
||||
tty_insert_flip_char(tty, DLE, 0);
|
||||
last = *dp;
|
||||
} else {
|
||||
+ ISDN_AUDIO_SKB_DLECOUNT(skb)
|
||||
#endif
|
||||
if (len > 1)
|
||||
tty_insert_flip_string(tty, skb->data, len - 1);
|
||||
last = skb->data[len - 1];
|
||||
;
|
||||
|
||||
c = tty_buffer_request_room(tty, len);
|
||||
if (c < len)
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_ISDN_AUDIO
|
||||
}
|
||||
#endif
|
||||
if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
|
||||
tty_insert_flip_char(tty, last, 0xFF);
|
||||
else
|
||||
tty_insert_flip_char(tty, last, TTY_NORMAL);
|
||||
tty_flip_buffer_push(tty);
|
||||
kfree_skb(skb);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
|
||||
int l = skb->len;
|
||||
unsigned char *dp = skb->data;
|
||||
while (--l) {
|
||||
if (*dp == DLE)
|
||||
tty_insert_flip_char(tty, DLE, 0);
|
||||
tty_insert_flip_char(tty, *dp++, 0);
|
||||
}
|
||||
if (*dp == DLE)
|
||||
tty_insert_flip_char(tty, DLE, 0);
|
||||
last = *dp;
|
||||
} else {
|
||||
#endif
|
||||
if (len > 1)
|
||||
tty_insert_flip_string(tty, skb->data, len - 1);
|
||||
last = skb->data[len - 1];
|
||||
#ifdef CONFIG_ISDN_AUDIO
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
|
||||
tty_insert_flip_char(tty, last, 0xFF);
|
||||
else
|
||||
tty_insert_flip_char(tty, last, TTY_NORMAL);
|
||||
tty_flip_buffer_push(tty);
|
||||
kfree_skb(skb);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* isdn_tty_readmodem() is called periodically from within timer-interrupt.
|
||||
|
@ -128,35 +130,39 @@ isdn_tty_readmodem(void)
|
|||
modem_info *info;
|
||||
|
||||
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
|
||||
if ((midx = dev->m_idx[i]) >= 0) {
|
||||
info = &dev->mdm.info[midx];
|
||||
if (info->online) {
|
||||
r = 0;
|
||||
midx = dev->m_idx[i];
|
||||
if (midx < 0)
|
||||
continue;
|
||||
|
||||
info = &dev->mdm.info[midx];
|
||||
if (!info->online)
|
||||
continue;
|
||||
|
||||
r = 0;
|
||||
#ifdef CONFIG_ISDN_AUDIO
|
||||
isdn_audio_eval_dtmf(info);
|
||||
if ((info->vonline & 1) && (info->emu.vpar[1]))
|
||||
isdn_audio_eval_silence(info);
|
||||
isdn_audio_eval_dtmf(info);
|
||||
if ((info->vonline & 1) && (info->emu.vpar[1]))
|
||||
isdn_audio_eval_silence(info);
|
||||
#endif
|
||||
if ((tty = info->tty)) {
|
||||
if (info->mcr & UART_MCR_RTS) {
|
||||
/* CISCO AsyncPPP Hack */
|
||||
if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
|
||||
r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 0);
|
||||
else
|
||||
r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 1);
|
||||
if (r)
|
||||
tty_flip_buffer_push(tty);
|
||||
} else
|
||||
r = 1;
|
||||
} else
|
||||
r = 1;
|
||||
if (r) {
|
||||
info->rcvsched = 0;
|
||||
resched = 1;
|
||||
} else
|
||||
info->rcvsched = 1;
|
||||
}
|
||||
}
|
||||
tty = info->port.tty;
|
||||
if (tty) {
|
||||
if (info->mcr & UART_MCR_RTS) {
|
||||
/* CISCO AsyncPPP Hack */
|
||||
if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
|
||||
r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 0);
|
||||
else
|
||||
r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 1);
|
||||
if (r)
|
||||
tty_flip_buffer_push(tty);
|
||||
} else
|
||||
r = 1;
|
||||
} else
|
||||
r = 1;
|
||||
if (r) {
|
||||
info->rcvsched = 0;
|
||||
resched = 1;
|
||||
} else
|
||||
info->rcvsched = 1;
|
||||
}
|
||||
if (!resched)
|
||||
isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
|
||||
|
@ -294,7 +300,7 @@ isdn_tty_tint(modem_info *info)
|
|||
len = skb->len;
|
||||
if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
|
||||
info->isdn_channel, 1, skb)) == len) {
|
||||
struct tty_struct *tty = info->tty;
|
||||
struct tty_struct *tty = info->port.tty;
|
||||
info->send_outstanding++;
|
||||
info->msr &= ~UART_MSR_CTS;
|
||||
info->lsr &= ~UART_LSR_TEMT;
|
||||
|
@ -327,7 +333,7 @@ isdn_tty_countDLE(unsigned char *buf, int len)
|
|||
static int
|
||||
isdn_tty_handleDLEdown(modem_info *info, atemu *m, int len)
|
||||
{
|
||||
unsigned char *p = &info->xmit_buf[info->xmit_count];
|
||||
unsigned char *p = &info->port.xmit_buf[info->xmit_count];
|
||||
int count = 0;
|
||||
|
||||
while (len > 0) {
|
||||
|
@ -471,7 +477,7 @@ isdn_tty_senddown(modem_info *info)
|
|||
return;
|
||||
}
|
||||
skb_reserve(skb, skb_res);
|
||||
memcpy(skb_put(skb, buflen), info->xmit_buf, buflen);
|
||||
memcpy(skb_put(skb, buflen), info->port.xmit_buf, buflen);
|
||||
info->xmit_count = 0;
|
||||
#ifdef CONFIG_ISDN_AUDIO
|
||||
if (info->vonline & 2) {
|
||||
|
@ -699,7 +705,7 @@ isdn_tty_modem_hup(modem_info *info, int local)
|
|||
printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
|
||||
#endif
|
||||
info->rcvsched = 0;
|
||||
isdn_tty_flush_buffer(info->tty);
|
||||
isdn_tty_flush_buffer(info->port.tty);
|
||||
if (info->online) {
|
||||
info->last_lhup = local;
|
||||
info->online = 0;
|
||||
|
@ -997,20 +1003,21 @@ isdn_tty_paranoia_check(modem_info *info, char *name, const char *routine)
|
|||
static void
|
||||
isdn_tty_change_speed(modem_info *info)
|
||||
{
|
||||
struct tty_port *port = &info->port;
|
||||
uint cflag,
|
||||
cval,
|
||||
quot;
|
||||
int i;
|
||||
|
||||
if (!info->tty || !info->tty->termios)
|
||||
if (!port->tty || !port->tty->termios)
|
||||
return;
|
||||
cflag = info->tty->termios->c_cflag;
|
||||
cflag = port->tty->termios->c_cflag;
|
||||
|
||||
quot = i = cflag & CBAUD;
|
||||
if (i & CBAUDEX) {
|
||||
i &= ~CBAUDEX;
|
||||
if (i < 1 || i > 2)
|
||||
info->tty->termios->c_cflag &= ~CBAUDEX;
|
||||
port->tty->termios->c_cflag &= ~CBAUDEX;
|
||||
else
|
||||
i += 15;
|
||||
}
|
||||
|
@ -1040,20 +1047,20 @@ isdn_tty_change_speed(modem_info *info)
|
|||
|
||||
/* CTS flow control flag and modem status interrupts */
|
||||
if (cflag & CRTSCTS) {
|
||||
info->flags |= ISDN_ASYNC_CTS_FLOW;
|
||||
port->flags |= ASYNC_CTS_FLOW;
|
||||
} else
|
||||
info->flags &= ~ISDN_ASYNC_CTS_FLOW;
|
||||
port->flags &= ~ASYNC_CTS_FLOW;
|
||||
if (cflag & CLOCAL)
|
||||
info->flags &= ~ISDN_ASYNC_CHECK_CD;
|
||||
port->flags &= ~ASYNC_CHECK_CD;
|
||||
else {
|
||||
info->flags |= ISDN_ASYNC_CHECK_CD;
|
||||
port->flags |= ASYNC_CHECK_CD;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
isdn_tty_startup(modem_info *info)
|
||||
{
|
||||
if (info->flags & ISDN_ASYNC_INITIALIZED)
|
||||
if (info->port.flags & ASYNC_INITIALIZED)
|
||||
return 0;
|
||||
isdn_lock_drivers();
|
||||
#ifdef ISDN_DEBUG_MODEM_OPEN
|
||||
|
@ -1063,14 +1070,14 @@ isdn_tty_startup(modem_info *info)
|
|||
* Now, initialize the UART
|
||||
*/
|
||||
info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
|
||||
if (info->tty)
|
||||
clear_bit(TTY_IO_ERROR, &info->tty->flags);
|
||||
if (info->port.tty)
|
||||
clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
|
||||
/*
|
||||
* and set the speed of the serial port
|
||||
*/
|
||||
isdn_tty_change_speed(info);
|
||||
|
||||
info->flags |= ISDN_ASYNC_INITIALIZED;
|
||||
info->port.flags |= ASYNC_INITIALIZED;
|
||||
info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
|
||||
info->send_outstanding = 0;
|
||||
return 0;
|
||||
|
@ -1083,14 +1090,14 @@ isdn_tty_startup(modem_info *info)
|
|||
static void
|
||||
isdn_tty_shutdown(modem_info *info)
|
||||
{
|
||||
if (!(info->flags & ISDN_ASYNC_INITIALIZED))
|
||||
if (!(info->port.flags & ASYNC_INITIALIZED))
|
||||
return;
|
||||
#ifdef ISDN_DEBUG_MODEM_OPEN
|
||||
printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);
|
||||
#endif
|
||||
isdn_unlock_drivers();
|
||||
info->msr &= ~UART_MSR_RI;
|
||||
if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
|
||||
if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
|
||||
info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
|
||||
if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
|
||||
isdn_tty_modem_reset_regs(info, 0);
|
||||
|
@ -1100,10 +1107,10 @@ isdn_tty_shutdown(modem_info *info)
|
|||
isdn_tty_modem_hup(info, 1);
|
||||
}
|
||||
}
|
||||
if (info->tty)
|
||||
set_bit(TTY_IO_ERROR, &info->tty->flags);
|
||||
if (info->port.tty)
|
||||
set_bit(TTY_IO_ERROR, &info->port.tty->flags);
|
||||
|
||||
info->flags &= ~ISDN_ASYNC_INITIALIZED;
|
||||
info->port.flags &= ~ASYNC_INITIALIZED;
|
||||
}
|
||||
|
||||
/* isdn_tty_write() is the main send-routine. It is called from the upper
|
||||
|
@ -1146,7 +1153,7 @@ isdn_tty_write(struct tty_struct *tty, const u_char *buf, int count)
|
|||
isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c,
|
||||
&(m->pluscount),
|
||||
&(m->lastplus));
|
||||
memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
|
||||
memcpy(&info->port.xmit_buf[info->xmit_count], buf, c);
|
||||
#ifdef CONFIG_ISDN_AUDIO
|
||||
if (info->vonline) {
|
||||
int cc = isdn_tty_handleDLEdown(info, m, c);
|
||||
|
@ -1478,107 +1485,6 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
|||
* isdn_tty_open() and friends
|
||||
* ------------------------------------------------------------
|
||||
*/
|
||||
static int
|
||||
isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info *info)
|
||||
{
|
||||
DECLARE_WAITQUEUE(wait, NULL);
|
||||
int do_clocal = 0;
|
||||
int retval;
|
||||
|
||||
/*
|
||||
* If the device is in the middle of being closed, then block
|
||||
* until it's done, and then try again.
|
||||
*/
|
||||
if (tty_hung_up_p(filp) ||
|
||||
(info->flags & ISDN_ASYNC_CLOSING)) {
|
||||
if (info->flags & ISDN_ASYNC_CLOSING)
|
||||
interruptible_sleep_on(&info->close_wait);
|
||||
#ifdef MODEM_DO_RESTART
|
||||
if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
|
||||
return -EAGAIN;
|
||||
else
|
||||
return -ERESTARTSYS;
|
||||
#else
|
||||
return -EAGAIN;
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
* If non-blocking mode is set, then make the check up front
|
||||
* and then exit.
|
||||
*/
|
||||
if ((filp->f_flags & O_NONBLOCK) ||
|
||||
(tty->flags & (1 << TTY_IO_ERROR))) {
|
||||
if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
|
||||
return -EBUSY;
|
||||
info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
|
||||
return 0;
|
||||
}
|
||||
if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) {
|
||||
if (info->normal_termios.c_cflag & CLOCAL)
|
||||
do_clocal = 1;
|
||||
} else {
|
||||
if (tty->termios->c_cflag & CLOCAL)
|
||||
do_clocal = 1;
|
||||
}
|
||||
/*
|
||||
* Block waiting for the carrier detect and the line to become
|
||||
* free (i.e., not in use by the callout). While we are in
|
||||
* this loop, info->count is dropped by one, so that
|
||||
* isdn_tty_close() knows when to free things. We restore it upon
|
||||
* exit, either normal or abnormal.
|
||||
*/
|
||||
retval = 0;
|
||||
add_wait_queue(&info->open_wait, &wait);
|
||||
#ifdef ISDN_DEBUG_MODEM_OPEN
|
||||
printk(KERN_DEBUG "isdn_tty_block_til_ready before block: ttyi%d, count = %d\n",
|
||||
info->line, info->count);
|
||||
#endif
|
||||
if (!(tty_hung_up_p(filp)))
|
||||
info->count--;
|
||||
info->blocked_open++;
|
||||
while (1) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (tty_hung_up_p(filp) ||
|
||||
!(info->flags & ISDN_ASYNC_INITIALIZED)) {
|
||||
#ifdef MODEM_DO_RESTART
|
||||
if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
|
||||
retval = -EAGAIN;
|
||||
else
|
||||
retval = -ERESTARTSYS;
|
||||
#else
|
||||
retval = -EAGAIN;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if (!(info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
|
||||
!(info->flags & ISDN_ASYNC_CLOSING) &&
|
||||
(do_clocal || (info->msr & UART_MSR_DCD))) {
|
||||
break;
|
||||
}
|
||||
if (signal_pending(current)) {
|
||||
retval = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
#ifdef ISDN_DEBUG_MODEM_OPEN
|
||||
printk(KERN_DEBUG "isdn_tty_block_til_ready blocking: ttyi%d, count = %d\n",
|
||||
info->line, info->count);
|
||||
#endif
|
||||
schedule();
|
||||
}
|
||||
current->state = TASK_RUNNING;
|
||||
remove_wait_queue(&info->open_wait, &wait);
|
||||
if (!tty_hung_up_p(filp))
|
||||
info->count++;
|
||||
info->blocked_open--;
|
||||
#ifdef ISDN_DEBUG_MODEM_OPEN
|
||||
printk(KERN_DEBUG "isdn_tty_block_til_ready after blocking: ttyi%d, count = %d\n",
|
||||
info->line, info->count);
|
||||
#endif
|
||||
if (retval)
|
||||
return retval;
|
||||
info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is called whenever a serial port is opened. It
|
||||
|
@ -1589,23 +1495,22 @@ isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info *
|
|||
static int
|
||||
isdn_tty_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
struct tty_port *port;
|
||||
modem_info *info;
|
||||
int retval;
|
||||
|
||||
info = &dev->mdm.info[tty->index];
|
||||
if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
|
||||
return -ENODEV;
|
||||
if (!try_module_get(info->owner)) {
|
||||
printk(KERN_WARNING "%s: cannot reserve module\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
port = &info->port;
|
||||
#ifdef ISDN_DEBUG_MODEM_OPEN
|
||||
printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name,
|
||||
info->count);
|
||||
port->count);
|
||||
#endif
|
||||
info->count++;
|
||||
port->count++;
|
||||
tty->driver_data = info;
|
||||
info->tty = tty;
|
||||
port->tty = tty;
|
||||
tty->port = port;
|
||||
/*
|
||||
* Start up serial port
|
||||
*/
|
||||
|
@ -1614,15 +1519,13 @@ isdn_tty_open(struct tty_struct *tty, struct file *filp)
|
|||
#ifdef ISDN_DEBUG_MODEM_OPEN
|
||||
printk(KERN_DEBUG "isdn_tty_open return after startup\n");
|
||||
#endif
|
||||
module_put(info->owner);
|
||||
return retval;
|
||||
}
|
||||
retval = isdn_tty_block_til_ready(tty, filp, info);
|
||||
retval = tty_port_block_til_ready(port, tty, filp);
|
||||
if (retval) {
|
||||
#ifdef ISDN_DEBUG_MODEM_OPEN
|
||||
printk(KERN_DEBUG "isdn_tty_open return after isdn_tty_block_til_ready \n");
|
||||
#endif
|
||||
module_put(info->owner);
|
||||
return retval;
|
||||
}
|
||||
#ifdef ISDN_DEBUG_MODEM_OPEN
|
||||
|
@ -1639,6 +1542,7 @@ static void
|
|||
isdn_tty_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
modem_info *info = (modem_info *) tty->driver_data;
|
||||
struct tty_port *port = &info->port;
|
||||
ulong timeout;
|
||||
|
||||
if (!info || isdn_tty_paranoia_check(info, tty->name, "isdn_tty_close"))
|
||||
|
@ -1649,7 +1553,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
|
|||
#endif
|
||||
return;
|
||||
}
|
||||
if ((tty->count == 1) && (info->count != 1)) {
|
||||
if ((tty->count == 1) && (port->count != 1)) {
|
||||
/*
|
||||
* Uh, oh. tty->count is 1, which means that the tty
|
||||
* structure will be freed. Info->count should always
|
||||
|
@ -1658,30 +1562,21 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
|
|||
* serial port won't be shutdown.
|
||||
*/
|
||||
printk(KERN_ERR "isdn_tty_close: bad port count; tty->count is 1, "
|
||||
"info->count is %d\n", info->count);
|
||||
info->count = 1;
|
||||
"info->count is %d\n", port->count);
|
||||
port->count = 1;
|
||||
}
|
||||
if (--info->count < 0) {
|
||||
if (--port->count < 0) {
|
||||
printk(KERN_ERR "isdn_tty_close: bad port count for ttyi%d: %d\n",
|
||||
info->line, info->count);
|
||||
info->count = 0;
|
||||
info->line, port->count);
|
||||
port->count = 0;
|
||||
}
|
||||
if (info->count) {
|
||||
if (port->count) {
|
||||
#ifdef ISDN_DEBUG_MODEM_OPEN
|
||||
printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n");
|
||||
#endif
|
||||
module_put(info->owner);
|
||||
return;
|
||||
}
|
||||
info->flags |= ISDN_ASYNC_CLOSING;
|
||||
/*
|
||||
* Save the termios structure, since this port may have
|
||||
* separate termios for callout and dialin.
|
||||
*/
|
||||
if (info->flags & ISDN_ASYNC_NORMAL_ACTIVE)
|
||||
info->normal_termios = *tty->termios;
|
||||
if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
|
||||
info->callout_termios = *tty->termios;
|
||||
port->flags |= ASYNC_CLOSING;
|
||||
|
||||
tty->closing = 1;
|
||||
/*
|
||||
|
@ -1690,7 +1585,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
|
|||
* interrupt driver to stop checking the data ready bit in the
|
||||
* line status register.
|
||||
*/
|
||||
if (info->flags & ISDN_ASYNC_INITIALIZED) {
|
||||
if (port->flags & ASYNC_INITIALIZED) {
|
||||
tty_wait_until_sent_from_close(tty, 3000); /* 30 seconds timeout */
|
||||
/*
|
||||
* Before we drop DTR, make sure the UART transmitter
|
||||
|
@ -1708,16 +1603,10 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
|
|||
isdn_tty_shutdown(info);
|
||||
isdn_tty_flush_buffer(tty);
|
||||
tty_ldisc_flush(tty);
|
||||
info->tty = NULL;
|
||||
port->tty = NULL;
|
||||
info->ncarrier = 0;
|
||||
tty->closing = 0;
|
||||
module_put(info->owner);
|
||||
if (info->blocked_open) {
|
||||
msleep_interruptible(500);
|
||||
wake_up_interruptible(&info->open_wait);
|
||||
}
|
||||
info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CLOSING);
|
||||
wake_up_interruptible(&info->close_wait);
|
||||
|
||||
tty_port_close_end(port, tty);
|
||||
#ifdef ISDN_DEBUG_MODEM_OPEN
|
||||
printk(KERN_DEBUG "isdn_tty_close normal exit\n");
|
||||
#endif
|
||||
|
@ -1730,14 +1619,15 @@ static void
|
|||
isdn_tty_hangup(struct tty_struct *tty)
|
||||
{
|
||||
modem_info *info = (modem_info *) tty->driver_data;
|
||||
struct tty_port *port = &info->port;
|
||||
|
||||
if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_hangup"))
|
||||
return;
|
||||
isdn_tty_shutdown(info);
|
||||
info->count = 0;
|
||||
info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE);
|
||||
info->tty = NULL;
|
||||
wake_up_interruptible(&info->open_wait);
|
||||
port->count = 0;
|
||||
port->flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
port->tty = NULL;
|
||||
wake_up_interruptible(&port->open_wait);
|
||||
}
|
||||
|
||||
/* This routine initializes all emulator-data.
|
||||
|
@ -1864,6 +1754,16 @@ static const struct tty_operations modem_ops = {
|
|||
.tiocmset = isdn_tty_tiocmset,
|
||||
};
|
||||
|
||||
static int isdn_tty_carrier_raised(struct tty_port *port)
|
||||
{
|
||||
modem_info *info = container_of(port, modem_info, port);
|
||||
return info->msr & UART_MSR_DCD;
|
||||
}
|
||||
|
||||
static const struct tty_port_operations isdn_tty_port_ops = {
|
||||
.carrier_raised = isdn_tty_carrier_raised,
|
||||
};
|
||||
|
||||
int
|
||||
isdn_tty_modem_init(void)
|
||||
{
|
||||
|
@ -1899,9 +1799,8 @@ isdn_tty_modem_init(void)
|
|||
goto err_unregister;
|
||||
}
|
||||
#endif
|
||||
#ifdef MODULE
|
||||
info->owner = THIS_MODULE;
|
||||
#endif
|
||||
tty_port_init(&info->port);
|
||||
info->port.ops = &isdn_tty_port_ops;
|
||||
spin_lock_init(&info->readlock);
|
||||
sprintf(info->last_cause, "0000");
|
||||
sprintf(info->last_num, "none");
|
||||
|
@ -1913,12 +1812,7 @@ isdn_tty_modem_init(void)
|
|||
isdn_tty_modem_reset_regs(info, 1);
|
||||
info->magic = ISDN_ASYNC_MAGIC;
|
||||
info->line = i;
|
||||
info->tty = NULL;
|
||||
info->x_char = 0;
|
||||
info->count = 0;
|
||||
info->blocked_open = 0;
|
||||
init_waitqueue_head(&info->open_wait);
|
||||
init_waitqueue_head(&info->close_wait);
|
||||
info->isdn_driver = -1;
|
||||
info->isdn_channel = -1;
|
||||
info->drv_index = -1;
|
||||
|
@ -1930,13 +1824,15 @@ isdn_tty_modem_init(void)
|
|||
#ifdef CONFIG_ISDN_AUDIO
|
||||
skb_queue_head_init(&info->dtmf_queue);
|
||||
#endif
|
||||
if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, GFP_KERNEL))) {
|
||||
info->port.xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5,
|
||||
GFP_KERNEL);
|
||||
if (!info->port.xmit_buf) {
|
||||
printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
|
||||
retval = -ENOMEM;
|
||||
goto err_unregister;
|
||||
}
|
||||
/* Make room for T.70 header */
|
||||
info->xmit_buf += 4;
|
||||
info->port.xmit_buf += 4;
|
||||
}
|
||||
return 0;
|
||||
err_unregister:
|
||||
|
@ -1945,7 +1841,7 @@ err_unregister:
|
|||
#ifdef CONFIG_ISDN_TTY_FAX
|
||||
kfree(info->fax);
|
||||
#endif
|
||||
kfree(info->xmit_buf - 4);
|
||||
kfree(info->port.xmit_buf - 4);
|
||||
}
|
||||
tty_unregister_driver(m->tty_modem);
|
||||
err:
|
||||
|
@ -1966,7 +1862,7 @@ isdn_tty_exit(void)
|
|||
#ifdef CONFIG_ISDN_TTY_FAX
|
||||
kfree(info->fax);
|
||||
#endif
|
||||
kfree(info->xmit_buf - 4);
|
||||
kfree(info->port.xmit_buf - 4);
|
||||
}
|
||||
tty_unregister_driver(dev->mdm.tty_modem);
|
||||
put_tty_driver(dev->mdm.tty_modem);
|
||||
|
@ -2068,7 +1964,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
|
|||
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
|
||||
modem_info *info = &dev->mdm.info[i];
|
||||
|
||||
if (info->count == 0)
|
||||
if (info->port.count == 0)
|
||||
continue;
|
||||
if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */
|
||||
(info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */
|
||||
|
@ -2076,12 +1972,12 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
|
|||
#ifdef ISDN_DEBUG_MODEM_ICALL
|
||||
printk(KERN_DEBUG "m_fi: match1 wret=%d\n", wret);
|
||||
printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx,
|
||||
info->flags, info->isdn_driver, info->isdn_channel,
|
||||
dev->usage[idx]);
|
||||
info->port.flags, info->isdn_driver,
|
||||
info->isdn_channel, dev->usage[idx]);
|
||||
#endif
|
||||
if (
|
||||
#ifndef FIX_FILE_TRANSFER
|
||||
(info->flags & ISDN_ASYNC_NORMAL_ACTIVE) &&
|
||||
(info->port.flags & ASYNC_NORMAL_ACTIVE) &&
|
||||
#endif
|
||||
(info->isdn_driver == -1) &&
|
||||
(info->isdn_channel == -1) &&
|
||||
|
@ -2120,8 +2016,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
|
|||
return (wret == 2) ? 3 : 0;
|
||||
}
|
||||
|
||||
#define TTY_IS_ACTIVE(info) \
|
||||
(info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE))
|
||||
#define TTY_IS_ACTIVE(info) (info->port.flags & ASYNC_NORMAL_ACTIVE)
|
||||
|
||||
int
|
||||
isdn_tty_stat_callback(int i, isdn_ctrl *c)
|
||||
|
@ -2212,9 +2107,9 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
|
|||
* for incoming call of this device when
|
||||
* DCD follow the state of incoming carrier
|
||||
*/
|
||||
if (info->blocked_open &&
|
||||
if (info->port.blocked_open &&
|
||||
(info->emu.mdmreg[REG_DCD] & BIT_DCD)) {
|
||||
wake_up_interruptible(&info->open_wait);
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
}
|
||||
|
||||
/* Schedule CONNECT-Message to any tty
|
||||
|
@ -2222,7 +2117,8 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
|
|||
* set DCD-bit of its modem-status.
|
||||
*/
|
||||
if (TTY_IS_ACTIVE(info) ||
|
||||
(info->blocked_open && (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
|
||||
(info->port.blocked_open &&
|
||||
(info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
|
||||
info->msr |= UART_MSR_DCD;
|
||||
info->emu.charge = 0;
|
||||
if (info->dialing & 0xf)
|
||||
|
@ -2339,8 +2235,8 @@ isdn_tty_at_cout(char *msg, modem_info *info)
|
|||
l = strlen(msg);
|
||||
|
||||
spin_lock_irqsave(&info->readlock, flags);
|
||||
tty = info->tty;
|
||||
if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) {
|
||||
tty = info->port.tty;
|
||||
if ((info->port.flags & ASYNC_CLOSING) || (!tty)) {
|
||||
spin_unlock_irqrestore(&info->readlock, flags);
|
||||
return;
|
||||
}
|
||||
|
@ -2490,15 +2386,15 @@ isdn_tty_modem_result(int code, modem_info *info)
|
|||
case RESULT_NO_CARRIER:
|
||||
#ifdef ISDN_DEBUG_MODEM_HUP
|
||||
printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
|
||||
(info->flags & ISDN_ASYNC_CLOSING),
|
||||
(!info->tty));
|
||||
(info->port.flags & ASYNC_CLOSING),
|
||||
(!info->port.tty));
|
||||
#endif
|
||||
m->mdmreg[REG_RINGCNT] = 0;
|
||||
del_timer(&info->nc_timer);
|
||||
info->ncarrier = 0;
|
||||
if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
|
||||
if ((info->port.flags & ASYNC_CLOSING) || (!info->port.tty))
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ISDN_AUDIO
|
||||
if (info->vonline & 1) {
|
||||
#ifdef ISDN_DEBUG_MODEM_VOICE
|
||||
|
@ -2629,14 +2525,11 @@ isdn_tty_modem_result(int code, modem_info *info)
|
|||
}
|
||||
}
|
||||
if (code == RESULT_NO_CARRIER) {
|
||||
if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
|
||||
if ((info->port.flags & ASYNC_CLOSING) || (!info->port.tty))
|
||||
return;
|
||||
}
|
||||
if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
|
||||
(!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
|
||||
(info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
|
||||
tty_hangup(info->tty);
|
||||
}
|
||||
|
||||
if (info->port.flags & ASYNC_CHECK_CD)
|
||||
tty_hangup(info->port.tty);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3803,19 +3696,19 @@ isdn_tty_modem_escape(void)
|
|||
int midx;
|
||||
|
||||
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
|
||||
if (USG_MODEM(dev->usage[i]))
|
||||
if ((midx = dev->m_idx[i]) >= 0) {
|
||||
modem_info *info = &dev->mdm.info[midx];
|
||||
if (info->online) {
|
||||
ton = 1;
|
||||
if ((info->emu.pluscount == 3) &&
|
||||
time_after(jiffies , info->emu.lastplus + PLUSWAIT2)) {
|
||||
info->emu.pluscount = 0;
|
||||
info->online = 0;
|
||||
isdn_tty_modem_result(RESULT_OK, info);
|
||||
}
|
||||
if (USG_MODEM(dev->usage[i]) && (midx = dev->m_idx[i]) >= 0) {
|
||||
modem_info *info = &dev->mdm.info[midx];
|
||||
if (info->online) {
|
||||
ton = 1;
|
||||
if ((info->emu.pluscount == 3) &&
|
||||
time_after(jiffies,
|
||||
info->emu.lastplus + PLUSWAIT2)) {
|
||||
info->emu.pluscount = 0;
|
||||
info->online = 0;
|
||||
isdn_tty_modem_result(RESULT_OK, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton);
|
||||
}
|
||||
|
||||
|
@ -3873,15 +3766,14 @@ isdn_tty_carrier_timeout(void)
|
|||
|
||||
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
|
||||
modem_info *info = &dev->mdm.info[i];
|
||||
if (info->dialing) {
|
||||
if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
|
||||
info->dialing = 0;
|
||||
isdn_tty_modem_result(RESULT_NO_CARRIER, info);
|
||||
isdn_tty_modem_hup(info, 1);
|
||||
}
|
||||
else
|
||||
ton = 1;
|
||||
}
|
||||
if (!info->dialing)
|
||||
continue;
|
||||
if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
|
||||
info->dialing = 0;
|
||||
isdn_tty_modem_result(RESULT_NO_CARRIER, info);
|
||||
isdn_tty_modem_hup(info, 1);
|
||||
} else
|
||||
ton = 1;
|
||||
}
|
||||
isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton);
|
||||
}
|
||||
|
|
|
@ -106,13 +106,6 @@
|
|||
|
||||
#define MAX_RX_URBS 2
|
||||
|
||||
static inline struct hso_serial *get_serial_by_tty(struct tty_struct *tty)
|
||||
{
|
||||
if (tty)
|
||||
return tty->driver_data;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Debugging functions */
|
||||
/*****************************************************************************/
|
||||
|
@ -255,9 +248,8 @@ struct hso_serial {
|
|||
u8 dtr_state;
|
||||
unsigned tx_urb_used:1;
|
||||
|
||||
struct tty_port port;
|
||||
/* from usb_serial_port */
|
||||
struct tty_struct *tty;
|
||||
int open_count;
|
||||
spinlock_t serial_lock;
|
||||
|
||||
int (*write_data) (struct hso_serial *serial);
|
||||
|
@ -1114,7 +1106,7 @@ static void hso_init_termios(struct ktermios *termios)
|
|||
static void _hso_serial_set_termios(struct tty_struct *tty,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct hso_serial *serial = get_serial_by_tty(tty);
|
||||
struct hso_serial *serial = tty->driver_data;
|
||||
struct ktermios *termios;
|
||||
|
||||
if (!serial) {
|
||||
|
@ -1190,7 +1182,7 @@ static void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial)
|
|||
struct urb *urb;
|
||||
|
||||
urb = serial->rx_urb[0];
|
||||
if (serial->open_count > 0) {
|
||||
if (serial->port.count > 0) {
|
||||
count = put_rxbuf_data(urb, serial);
|
||||
if (count == -1)
|
||||
return;
|
||||
|
@ -1226,7 +1218,7 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb)
|
|||
DUMP1(urb->transfer_buffer, urb->actual_length);
|
||||
|
||||
/* Anyone listening? */
|
||||
if (serial->open_count == 0)
|
||||
if (serial->port.count == 0)
|
||||
return;
|
||||
|
||||
if (status == 0) {
|
||||
|
@ -1268,7 +1260,7 @@ static void hso_unthrottle_tasklet(struct hso_serial *serial)
|
|||
|
||||
static void hso_unthrottle(struct tty_struct *tty)
|
||||
{
|
||||
struct hso_serial *serial = get_serial_by_tty(tty);
|
||||
struct hso_serial *serial = tty->driver_data;
|
||||
|
||||
tasklet_hi_schedule(&serial->unthrottle_tasklet);
|
||||
}
|
||||
|
@ -1304,15 +1296,12 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
|
|||
kref_get(&serial->parent->ref);
|
||||
|
||||
/* setup */
|
||||
spin_lock_irq(&serial->serial_lock);
|
||||
tty->driver_data = serial;
|
||||
tty_kref_put(serial->tty);
|
||||
serial->tty = tty_kref_get(tty);
|
||||
spin_unlock_irq(&serial->serial_lock);
|
||||
tty_port_tty_set(&serial->port, tty);
|
||||
|
||||
/* check for port already opened, if not set the termios */
|
||||
serial->open_count++;
|
||||
if (serial->open_count == 1) {
|
||||
serial->port.count++;
|
||||
if (serial->port.count == 1) {
|
||||
serial->rx_state = RX_IDLE;
|
||||
/* Force default termio settings */
|
||||
_hso_serial_set_termios(tty, NULL);
|
||||
|
@ -1324,7 +1313,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
|
|||
result = hso_start_serial_device(serial->parent, GFP_KERNEL);
|
||||
if (result) {
|
||||
hso_stop_serial_device(serial->parent);
|
||||
serial->open_count--;
|
||||
serial->port.count--;
|
||||
kref_put(&serial->parent->ref, hso_serial_ref_free);
|
||||
}
|
||||
} else {
|
||||
|
@ -1361,17 +1350,11 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
|
|||
|
||||
/* reset the rts and dtr */
|
||||
/* do the actual close */
|
||||
serial->open_count--;
|
||||
serial->port.count--;
|
||||
|
||||
if (serial->open_count <= 0) {
|
||||
serial->open_count = 0;
|
||||
spin_lock_irq(&serial->serial_lock);
|
||||
if (serial->tty == tty) {
|
||||
serial->tty->driver_data = NULL;
|
||||
serial->tty = NULL;
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
spin_unlock_irq(&serial->serial_lock);
|
||||
if (serial->port.count <= 0) {
|
||||
serial->port.count = 0;
|
||||
tty_port_tty_set(&serial->port, NULL);
|
||||
if (!usb_gone)
|
||||
hso_stop_serial_device(serial->parent);
|
||||
tasklet_kill(&serial->unthrottle_tasklet);
|
||||
|
@ -1390,7 +1373,7 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
|
|||
static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf,
|
||||
int count)
|
||||
{
|
||||
struct hso_serial *serial = get_serial_by_tty(tty);
|
||||
struct hso_serial *serial = tty->driver_data;
|
||||
int space, tx_bytes;
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -1422,7 +1405,7 @@ out:
|
|||
/* how much room is there for writing */
|
||||
static int hso_serial_write_room(struct tty_struct *tty)
|
||||
{
|
||||
struct hso_serial *serial = get_serial_by_tty(tty);
|
||||
struct hso_serial *serial = tty->driver_data;
|
||||
int room;
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -1437,7 +1420,7 @@ static int hso_serial_write_room(struct tty_struct *tty)
|
|||
/* setup the term */
|
||||
static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
|
||||
{
|
||||
struct hso_serial *serial = get_serial_by_tty(tty);
|
||||
struct hso_serial *serial = tty->driver_data;
|
||||
unsigned long flags;
|
||||
|
||||
if (old)
|
||||
|
@ -1446,7 +1429,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
|
|||
|
||||
/* the actual setup */
|
||||
spin_lock_irqsave(&serial->serial_lock, flags);
|
||||
if (serial->open_count)
|
||||
if (serial->port.count)
|
||||
_hso_serial_set_termios(tty, old);
|
||||
else
|
||||
tty->termios = old;
|
||||
|
@ -1458,7 +1441,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
|
|||
/* how many characters in the buffer */
|
||||
static int hso_serial_chars_in_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct hso_serial *serial = get_serial_by_tty(tty);
|
||||
struct hso_serial *serial = tty->driver_data;
|
||||
int chars;
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -1629,7 +1612,7 @@ static int hso_get_count(struct tty_struct *tty,
|
|||
struct serial_icounter_struct *icount)
|
||||
{
|
||||
struct uart_icount cnow;
|
||||
struct hso_serial *serial = get_serial_by_tty(tty);
|
||||
struct hso_serial *serial = tty->driver_data;
|
||||
struct hso_tiocmget *tiocmget = serial->tiocmget;
|
||||
|
||||
memset(icount, 0, sizeof(struct serial_icounter_struct));
|
||||
|
@ -1659,7 +1642,7 @@ static int hso_get_count(struct tty_struct *tty,
|
|||
static int hso_serial_tiocmget(struct tty_struct *tty)
|
||||
{
|
||||
int retval;
|
||||
struct hso_serial *serial = get_serial_by_tty(tty);
|
||||
struct hso_serial *serial = tty->driver_data;
|
||||
struct hso_tiocmget *tiocmget;
|
||||
u16 UART_state_bitmap;
|
||||
|
||||
|
@ -1693,7 +1676,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty,
|
|||
int val = 0;
|
||||
unsigned long flags;
|
||||
int if_num;
|
||||
struct hso_serial *serial = get_serial_by_tty(tty);
|
||||
struct hso_serial *serial = tty->driver_data;
|
||||
|
||||
/* sanity check */
|
||||
if (!serial) {
|
||||
|
@ -1733,7 +1716,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty,
|
|||
static int hso_serial_ioctl(struct tty_struct *tty,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct hso_serial *serial = get_serial_by_tty(tty);
|
||||
struct hso_serial *serial = tty->driver_data;
|
||||
int ret = 0;
|
||||
D4("IOCTL cmd: %d, arg: %ld", cmd, arg);
|
||||
|
||||
|
@ -1905,7 +1888,7 @@ static void intr_callback(struct urb *urb)
|
|||
D1("Pending read interrupt on port %d\n", i);
|
||||
spin_lock(&serial->serial_lock);
|
||||
if (serial->rx_state == RX_IDLE &&
|
||||
serial->open_count > 0) {
|
||||
serial->port.count > 0) {
|
||||
/* Setup and send a ctrl req read on
|
||||
* port i */
|
||||
if (!serial->rx_urb_filled[0]) {
|
||||
|
@ -1954,14 +1937,13 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
|
|||
|
||||
spin_lock(&serial->serial_lock);
|
||||
serial->tx_urb_used = 0;
|
||||
tty = tty_kref_get(serial->tty);
|
||||
spin_unlock(&serial->serial_lock);
|
||||
if (status) {
|
||||
handle_usb_error(status, __func__, serial->parent);
|
||||
tty_kref_put(tty);
|
||||
return;
|
||||
}
|
||||
hso_put_activity(serial->parent);
|
||||
tty = tty_port_tty_get(&serial->port);
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
|
@ -2001,7 +1983,6 @@ static void ctrl_callback(struct urb *urb)
|
|||
struct hso_serial *serial = urb->context;
|
||||
struct usb_ctrlrequest *req;
|
||||
int status = urb->status;
|
||||
struct tty_struct *tty;
|
||||
|
||||
/* sanity check */
|
||||
if (!serial)
|
||||
|
@ -2009,11 +1990,9 @@ static void ctrl_callback(struct urb *urb)
|
|||
|
||||
spin_lock(&serial->serial_lock);
|
||||
serial->tx_urb_used = 0;
|
||||
tty = tty_kref_get(serial->tty);
|
||||
spin_unlock(&serial->serial_lock);
|
||||
if (status) {
|
||||
handle_usb_error(status, __func__, serial->parent);
|
||||
tty_kref_put(tty);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2031,13 +2010,15 @@ static void ctrl_callback(struct urb *urb)
|
|||
put_rxbuf_data_and_resubmit_ctrl_urb(serial);
|
||||
spin_unlock(&serial->serial_lock);
|
||||
} else {
|
||||
struct tty_struct *tty = tty_port_tty_get(&serial->port);
|
||||
hso_put_activity(serial->parent);
|
||||
if (tty)
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
/* response to a write command */
|
||||
hso_kick_transmit(serial);
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
/* handle RX data for serial port */
|
||||
|
@ -2053,8 +2034,7 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
|
|||
return -2;
|
||||
}
|
||||
|
||||
/* All callers to put_rxbuf_data hold serial_lock */
|
||||
tty = tty_kref_get(serial->tty);
|
||||
tty = tty_port_tty_get(&serial->port);
|
||||
|
||||
/* Push data to tty */
|
||||
if (tty) {
|
||||
|
@ -2074,12 +2054,12 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
|
|||
write_length_remaining -= curr_write_len;
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
if (write_length_remaining == 0) {
|
||||
serial->curr_rx_urb_offset = 0;
|
||||
serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
return write_length_remaining;
|
||||
}
|
||||
|
||||
|
@ -2320,6 +2300,7 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
|
|||
serial->minor = minor;
|
||||
serial->magic = HSO_SERIAL_MAGIC;
|
||||
spin_lock_init(&serial->serial_lock);
|
||||
tty_port_init(&serial->port);
|
||||
serial->num_rx_urbs = num_urbs;
|
||||
|
||||
/* RX, allocate urb and initialize */
|
||||
|
@ -3098,7 +3079,7 @@ static int hso_resume(struct usb_interface *iface)
|
|||
/* Start all serial ports */
|
||||
for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
|
||||
if (serial_table[i] && (serial_table[i]->interface == iface)) {
|
||||
if (dev2ser(serial_table[i])->open_count) {
|
||||
if (dev2ser(serial_table[i])->port.count) {
|
||||
result =
|
||||
hso_start_serial_device(serial_table[i], GFP_NOIO);
|
||||
hso_kick_transmit(dev2ser(serial_table[i]));
|
||||
|
@ -3172,13 +3153,12 @@ static void hso_free_interface(struct usb_interface *interface)
|
|||
if (serial_table[i] &&
|
||||
(serial_table[i]->interface == interface)) {
|
||||
hso_dev = dev2ser(serial_table[i]);
|
||||
spin_lock_irq(&hso_dev->serial_lock);
|
||||
tty = tty_kref_get(hso_dev->tty);
|
||||
spin_unlock_irq(&hso_dev->serial_lock);
|
||||
if (tty)
|
||||
tty = tty_port_tty_get(&hso_dev->port);
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
mutex_lock(&hso_dev->parent->mutex);
|
||||
tty_kref_put(tty);
|
||||
hso_dev->parent->usb_gone = 1;
|
||||
mutex_unlock(&hso_dev->parent->mutex);
|
||||
kref_put(&serial_table[i]->ref, hso_serial_ref_free);
|
||||
|
@ -3313,7 +3293,6 @@ static int __init hso_init(void)
|
|||
return -ENOMEM;
|
||||
|
||||
/* fill in all needed values */
|
||||
tty_drv->magic = TTY_DRIVER_MAGIC;
|
||||
tty_drv->driver_name = driver_name;
|
||||
tty_drv->name = tty_filename;
|
||||
|
||||
|
@ -3334,7 +3313,7 @@ static int __init hso_init(void)
|
|||
if (result) {
|
||||
printk(KERN_ERR "%s - tty_register_driver failed(%d)\n",
|
||||
__func__, result);
|
||||
return result;
|
||||
goto err_free_tty;
|
||||
}
|
||||
|
||||
/* register this module as an usb driver */
|
||||
|
@ -3342,13 +3321,16 @@ static int __init hso_init(void)
|
|||
if (result) {
|
||||
printk(KERN_ERR "Could not register hso driver? error: %d\n",
|
||||
result);
|
||||
/* cleanup serial interface */
|
||||
tty_unregister_driver(tty_drv);
|
||||
return result;
|
||||
goto err_unreg_tty;
|
||||
}
|
||||
|
||||
/* done */
|
||||
return 0;
|
||||
err_unreg_tty:
|
||||
tty_unregister_driver(tty_drv);
|
||||
err_free_tty:
|
||||
put_tty_driver(tty_drv);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void __exit hso_exit(void)
|
||||
|
@ -3356,6 +3338,7 @@ static void __exit hso_exit(void)
|
|||
printk(KERN_INFO "hso: unloaded\n");
|
||||
|
||||
tty_unregister_driver(tty_drv);
|
||||
put_tty_driver(tty_drv);
|
||||
/* deregister the usb driver */
|
||||
usb_deregister(&hso_driver);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/serial.h> /* ASYNC_* flags */
|
||||
#include <linux/slab.h>
|
||||
#include <asm/ccwdev.h>
|
||||
#include <asm/cio.h>
|
||||
|
@ -44,14 +45,11 @@
|
|||
#define RAW3215_TIMEOUT HZ/10 /* time for delayed output */
|
||||
|
||||
#define RAW3215_FIXED 1 /* 3215 console device is not be freed */
|
||||
#define RAW3215_ACTIVE 2 /* set if the device is in use */
|
||||
#define RAW3215_WORKING 4 /* set if a request is being worked on */
|
||||
#define RAW3215_THROTTLED 8 /* set if reading is disabled */
|
||||
#define RAW3215_STOPPED 16 /* set if writing is disabled */
|
||||
#define RAW3215_CLOSING 32 /* set while in close process */
|
||||
#define RAW3215_TIMER_RUNS 64 /* set if the output delay timer is on */
|
||||
#define RAW3215_FLUSHING 128 /* set to flush buffer (no delay) */
|
||||
#define RAW3215_FROZEN 256 /* set if 3215 is frozen for suspend */
|
||||
|
||||
#define TAB_STOP_SIZE 8 /* tab stop size */
|
||||
|
||||
|
@ -76,6 +74,7 @@ struct raw3215_req {
|
|||
} __attribute__ ((aligned(8)));
|
||||
|
||||
struct raw3215_info {
|
||||
struct tty_port port;
|
||||
struct ccw_device *cdev; /* device for tty driver */
|
||||
spinlock_t *lock; /* pointer to irq lock */
|
||||
int flags; /* state flags */
|
||||
|
@ -84,7 +83,6 @@ struct raw3215_info {
|
|||
int head; /* first free byte in output buffer */
|
||||
int count; /* number of bytes in output buffer */
|
||||
int written; /* number of bytes in write requests */
|
||||
struct tty_struct *tty; /* pointer to tty structure if present */
|
||||
struct raw3215_req *queued_read; /* pointer to queued read requests */
|
||||
struct raw3215_req *queued_write;/* pointer to queued write requests */
|
||||
struct tasklet_struct tlet; /* tasklet to invoke tty_wakeup */
|
||||
|
@ -293,7 +291,7 @@ static void raw3215_timeout(unsigned long __data)
|
|||
if (raw->flags & RAW3215_TIMER_RUNS) {
|
||||
del_timer(&raw->timer);
|
||||
raw->flags &= ~RAW3215_TIMER_RUNS;
|
||||
if (!(raw->flags & RAW3215_FROZEN)) {
|
||||
if (!(raw->port.flags & ASYNC_SUSPENDED)) {
|
||||
raw3215_mk_write_req(raw);
|
||||
raw3215_start_io(raw);
|
||||
}
|
||||
|
@ -309,7 +307,8 @@ static void raw3215_timeout(unsigned long __data)
|
|||
*/
|
||||
static inline void raw3215_try_io(struct raw3215_info *raw)
|
||||
{
|
||||
if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FROZEN))
|
||||
if (!(raw->port.flags & ASYNC_INITIALIZED) ||
|
||||
(raw->port.flags & ASYNC_SUSPENDED))
|
||||
return;
|
||||
if (raw->queued_read != NULL)
|
||||
raw3215_start_io(raw);
|
||||
|
@ -324,10 +323,7 @@ static inline void raw3215_try_io(struct raw3215_info *raw)
|
|||
}
|
||||
} else if (!(raw->flags & RAW3215_TIMER_RUNS)) {
|
||||
/* delay small writes */
|
||||
init_timer(&raw->timer);
|
||||
raw->timer.expires = RAW3215_TIMEOUT + jiffies;
|
||||
raw->timer.data = (unsigned long) raw;
|
||||
raw->timer.function = raw3215_timeout;
|
||||
add_timer(&raw->timer);
|
||||
raw->flags |= RAW3215_TIMER_RUNS;
|
||||
}
|
||||
|
@ -340,17 +336,21 @@ static inline void raw3215_try_io(struct raw3215_info *raw)
|
|||
static void raw3215_wakeup(unsigned long data)
|
||||
{
|
||||
struct raw3215_info *raw = (struct raw3215_info *) data;
|
||||
tty_wakeup(raw->tty);
|
||||
struct tty_struct *tty;
|
||||
|
||||
tty = tty_port_tty_get(&raw->port);
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to start the next IO and wake up processes waiting on the tty.
|
||||
*/
|
||||
static void raw3215_next_io(struct raw3215_info *raw)
|
||||
static void raw3215_next_io(struct raw3215_info *raw, struct tty_struct *tty)
|
||||
{
|
||||
raw3215_mk_write_req(raw);
|
||||
raw3215_try_io(raw);
|
||||
if (raw->tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE)
|
||||
if (tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE)
|
||||
tasklet_schedule(&raw->tlet);
|
||||
}
|
||||
|
||||
|
@ -368,10 +368,11 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
|
|||
|
||||
raw = dev_get_drvdata(&cdev->dev);
|
||||
req = (struct raw3215_req *) intparm;
|
||||
tty = tty_port_tty_get(&raw->port);
|
||||
cstat = irb->scsw.cmd.cstat;
|
||||
dstat = irb->scsw.cmd.dstat;
|
||||
if (cstat != 0)
|
||||
raw3215_next_io(raw);
|
||||
raw3215_next_io(raw, tty);
|
||||
if (dstat & 0x01) { /* we got a unit exception */
|
||||
dstat &= ~0x01; /* we can ignore it */
|
||||
}
|
||||
|
@ -381,13 +382,13 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
|
|||
break;
|
||||
/* Attention interrupt, someone hit the enter key */
|
||||
raw3215_mk_read_req(raw);
|
||||
raw3215_next_io(raw);
|
||||
raw3215_next_io(raw, tty);
|
||||
break;
|
||||
case 0x08:
|
||||
case 0x0C:
|
||||
/* Channel end interrupt. */
|
||||
if ((raw = req->info) == NULL)
|
||||
return; /* That shouldn't happen ... */
|
||||
goto put_tty; /* That shouldn't happen ... */
|
||||
if (req->type == RAW3215_READ) {
|
||||
/* store residual count, then wait for device end */
|
||||
req->residual = irb->scsw.cmd.count;
|
||||
|
@ -397,11 +398,10 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
|
|||
case 0x04:
|
||||
/* Device end interrupt. */
|
||||
if ((raw = req->info) == NULL)
|
||||
return; /* That shouldn't happen ... */
|
||||
if (req->type == RAW3215_READ && raw->tty != NULL) {
|
||||
goto put_tty; /* That shouldn't happen ... */
|
||||
if (req->type == RAW3215_READ && tty != NULL) {
|
||||
unsigned int cchar;
|
||||
|
||||
tty = raw->tty;
|
||||
count = 160 - req->residual;
|
||||
EBCASC(raw->inbuf, count);
|
||||
cchar = ctrlchar_handle(raw->inbuf, count, tty);
|
||||
|
@ -411,7 +411,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
|
|||
|
||||
case CTRLCHAR_CTRL:
|
||||
tty_insert_flip_char(tty, cchar, TTY_NORMAL);
|
||||
tty_flip_buffer_push(raw->tty);
|
||||
tty_flip_buffer_push(tty);
|
||||
break;
|
||||
|
||||
case CTRLCHAR_NONE:
|
||||
|
@ -424,7 +424,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
|
|||
} else
|
||||
count -= 2;
|
||||
tty_insert_flip_string(tty, raw->inbuf, count);
|
||||
tty_flip_buffer_push(raw->tty);
|
||||
tty_flip_buffer_push(tty);
|
||||
break;
|
||||
}
|
||||
} else if (req->type == RAW3215_WRITE) {
|
||||
|
@ -439,7 +439,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
|
|||
raw->queued_read == NULL) {
|
||||
wake_up_interruptible(&raw->empty_wait);
|
||||
}
|
||||
raw3215_next_io(raw);
|
||||
raw3215_next_io(raw, tty);
|
||||
break;
|
||||
default:
|
||||
/* Strange interrupt, I'll do my best to clean up */
|
||||
|
@ -451,9 +451,10 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
|
|||
raw->flags &= ~RAW3215_WORKING;
|
||||
raw3215_free_req(req);
|
||||
}
|
||||
raw3215_next_io(raw);
|
||||
raw3215_next_io(raw, tty);
|
||||
}
|
||||
return;
|
||||
put_tty:
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -487,7 +488,7 @@ static void raw3215_make_room(struct raw3215_info *raw, unsigned int length)
|
|||
/* While console is frozen for suspend we have no other
|
||||
* choice but to drop message from the buffer to make
|
||||
* room for even more messages. */
|
||||
if (raw->flags & RAW3215_FROZEN) {
|
||||
if (raw->port.flags & ASYNC_SUSPENDED) {
|
||||
raw3215_drop_line(raw);
|
||||
continue;
|
||||
}
|
||||
|
@ -609,10 +610,10 @@ static int raw3215_startup(struct raw3215_info *raw)
|
|||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (raw->flags & RAW3215_ACTIVE)
|
||||
if (raw->port.flags & ASYNC_INITIALIZED)
|
||||
return 0;
|
||||
raw->line_pos = 0;
|
||||
raw->flags |= RAW3215_ACTIVE;
|
||||
raw->port.flags |= ASYNC_INITIALIZED;
|
||||
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
|
||||
raw3215_try_io(raw);
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
|
||||
|
@ -628,14 +629,15 @@ static void raw3215_shutdown(struct raw3215_info *raw)
|
|||
DECLARE_WAITQUEUE(wait, current);
|
||||
unsigned long flags;
|
||||
|
||||
if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FIXED))
|
||||
if (!(raw->port.flags & ASYNC_INITIALIZED) ||
|
||||
(raw->flags & RAW3215_FIXED))
|
||||
return;
|
||||
/* Wait for outstanding requests, then free irq */
|
||||
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
|
||||
if ((raw->flags & RAW3215_WORKING) ||
|
||||
raw->queued_write != NULL ||
|
||||
raw->queued_read != NULL) {
|
||||
raw->flags |= RAW3215_CLOSING;
|
||||
raw->port.flags |= ASYNC_CLOSING;
|
||||
add_wait_queue(&raw->empty_wait, &wait);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
|
||||
|
@ -643,11 +645,41 @@ static void raw3215_shutdown(struct raw3215_info *raw)
|
|||
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
|
||||
remove_wait_queue(&raw->empty_wait, &wait);
|
||||
set_current_state(TASK_RUNNING);
|
||||
raw->flags &= ~(RAW3215_ACTIVE | RAW3215_CLOSING);
|
||||
raw->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING);
|
||||
}
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
|
||||
}
|
||||
|
||||
static struct raw3215_info *raw3215_alloc_info(void)
|
||||
{
|
||||
struct raw3215_info *info;
|
||||
|
||||
info = kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA);
|
||||
if (!info)
|
||||
return NULL;
|
||||
|
||||
info->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
|
||||
info->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA);
|
||||
if (!info->buffer || !info->inbuf) {
|
||||
kfree(info);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
setup_timer(&info->timer, raw3215_timeout, (unsigned long)info);
|
||||
init_waitqueue_head(&info->empty_wait);
|
||||
tasklet_init(&info->tlet, raw3215_wakeup, (unsigned long)info);
|
||||
tty_port_init(&info->port);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static void raw3215_free_info(struct raw3215_info *raw)
|
||||
{
|
||||
kfree(raw->inbuf);
|
||||
kfree(raw->buffer);
|
||||
kfree(raw);
|
||||
}
|
||||
|
||||
static int raw3215_probe (struct ccw_device *cdev)
|
||||
{
|
||||
struct raw3215_info *raw;
|
||||
|
@ -656,11 +688,15 @@ static int raw3215_probe (struct ccw_device *cdev)
|
|||
/* Console is special. */
|
||||
if (raw3215[0] && (raw3215[0] == dev_get_drvdata(&cdev->dev)))
|
||||
return 0;
|
||||
raw = kmalloc(sizeof(struct raw3215_info) +
|
||||
RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA);
|
||||
|
||||
raw = raw3215_alloc_info();
|
||||
if (raw == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
raw->cdev = cdev;
|
||||
dev_set_drvdata(&cdev->dev, raw);
|
||||
cdev->handler = raw3215_irq;
|
||||
|
||||
spin_lock(&raw3215_device_lock);
|
||||
for (line = 0; line < NR_3215; line++) {
|
||||
if (!raw3215[line]) {
|
||||
|
@ -670,28 +706,10 @@ static int raw3215_probe (struct ccw_device *cdev)
|
|||
}
|
||||
spin_unlock(&raw3215_device_lock);
|
||||
if (line == NR_3215) {
|
||||
kfree(raw);
|
||||
raw3215_free_info(raw);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
raw->cdev = cdev;
|
||||
raw->inbuf = (char *) raw + sizeof(struct raw3215_info);
|
||||
memset(raw, 0, sizeof(struct raw3215_info));
|
||||
raw->buffer = kmalloc(RAW3215_BUFFER_SIZE,
|
||||
GFP_KERNEL|GFP_DMA);
|
||||
if (raw->buffer == NULL) {
|
||||
spin_lock(&raw3215_device_lock);
|
||||
raw3215[line] = NULL;
|
||||
spin_unlock(&raw3215_device_lock);
|
||||
kfree(raw);
|
||||
return -ENOMEM;
|
||||
}
|
||||
init_waitqueue_head(&raw->empty_wait);
|
||||
tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
|
||||
|
||||
dev_set_drvdata(&cdev->dev, raw);
|
||||
cdev->handler = raw3215_irq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -703,8 +721,7 @@ static void raw3215_remove (struct ccw_device *cdev)
|
|||
raw = dev_get_drvdata(&cdev->dev);
|
||||
if (raw) {
|
||||
dev_set_drvdata(&cdev->dev, NULL);
|
||||
kfree(raw->buffer);
|
||||
kfree(raw);
|
||||
raw3215_free_info(raw);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -741,7 +758,7 @@ static int raw3215_pm_stop(struct ccw_device *cdev)
|
|||
raw = dev_get_drvdata(&cdev->dev);
|
||||
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
|
||||
raw3215_make_room(raw, RAW3215_BUFFER_SIZE);
|
||||
raw->flags |= RAW3215_FROZEN;
|
||||
raw->port.flags |= ASYNC_SUSPENDED;
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
|
||||
return 0;
|
||||
}
|
||||
|
@ -754,7 +771,7 @@ static int raw3215_pm_start(struct ccw_device *cdev)
|
|||
/* Allow I/O again and flush output buffer. */
|
||||
raw = dev_get_drvdata(&cdev->dev);
|
||||
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
|
||||
raw->flags &= ~RAW3215_FROZEN;
|
||||
raw->port.flags &= ~ASYNC_SUSPENDED;
|
||||
raw->flags |= RAW3215_FLUSHING;
|
||||
raw3215_try_io(raw);
|
||||
raw->flags &= ~RAW3215_FLUSHING;
|
||||
|
@ -827,7 +844,7 @@ static void con3215_flush(void)
|
|||
unsigned long flags;
|
||||
|
||||
raw = raw3215[0]; /* console 3215 is the first one */
|
||||
if (raw->flags & RAW3215_FROZEN)
|
||||
if (raw->port.flags & ASYNC_SUSPENDED)
|
||||
/* The console is still frozen for suspend. */
|
||||
if (ccw_device_force_console())
|
||||
/* Forcing didn't work, no panic message .. */
|
||||
|
@ -897,23 +914,16 @@ static int __init con3215_init(void)
|
|||
if (IS_ERR(cdev))
|
||||
return -ENODEV;
|
||||
|
||||
raw3215[0] = raw = (struct raw3215_info *)
|
||||
kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA);
|
||||
raw->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
|
||||
raw->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA);
|
||||
raw3215[0] = raw = raw3215_alloc_info();
|
||||
raw->cdev = cdev;
|
||||
dev_set_drvdata(&cdev->dev, raw);
|
||||
cdev->handler = raw3215_irq;
|
||||
|
||||
raw->flags |= RAW3215_FIXED;
|
||||
init_waitqueue_head(&raw->empty_wait);
|
||||
tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
|
||||
|
||||
/* Request the console irq */
|
||||
if (raw3215_startup(raw) != 0) {
|
||||
kfree(raw->inbuf);
|
||||
kfree(raw->buffer);
|
||||
kfree(raw);
|
||||
raw3215_free_info(raw);
|
||||
raw3215[0] = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -940,7 +950,7 @@ static int tty3215_open(struct tty_struct *tty, struct file * filp)
|
|||
return -ENODEV;
|
||||
|
||||
tty->driver_data = raw;
|
||||
raw->tty = tty;
|
||||
tty_port_tty_set(&raw->port, tty);
|
||||
|
||||
tty->low_latency = 0; /* don't use bottom half for pushing chars */
|
||||
/*
|
||||
|
@ -971,7 +981,7 @@ static void tty3215_close(struct tty_struct *tty, struct file * filp)
|
|||
raw3215_shutdown(raw);
|
||||
tasklet_kill(&raw->tlet);
|
||||
tty->closing = 0;
|
||||
raw->tty = NULL;
|
||||
tty_port_tty_set(&raw->port, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -199,7 +199,7 @@ handle_diacr(struct kbd_data *kbd, unsigned int ch)
|
|||
if (ch == ' ' || ch == d)
|
||||
return d;
|
||||
|
||||
kbd_put_queue(kbd->tty, d);
|
||||
kbd_put_queue(kbd->port, d);
|
||||
return ch;
|
||||
}
|
||||
|
||||
|
@ -221,7 +221,7 @@ k_self(struct kbd_data *kbd, unsigned char value)
|
|||
{
|
||||
if (kbd->diacr)
|
||||
value = handle_diacr(kbd, value);
|
||||
kbd_put_queue(kbd->tty, value);
|
||||
kbd_put_queue(kbd->port, value);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -239,7 +239,7 @@ static void
|
|||
k_fn(struct kbd_data *kbd, unsigned char value)
|
||||
{
|
||||
if (kbd->func_table[value])
|
||||
kbd_puts_queue(kbd->tty, kbd->func_table[value]);
|
||||
kbd_puts_queue(kbd->port, kbd->func_table[value]);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -257,20 +257,20 @@ k_spec(struct kbd_data *kbd, unsigned char value)
|
|||
* but we need only 16 bits here
|
||||
*/
|
||||
static void
|
||||
to_utf8(struct tty_struct *tty, ushort c)
|
||||
to_utf8(struct tty_port *port, ushort c)
|
||||
{
|
||||
if (c < 0x80)
|
||||
/* 0******* */
|
||||
kbd_put_queue(tty, c);
|
||||
kbd_put_queue(port, c);
|
||||
else if (c < 0x800) {
|
||||
/* 110***** 10****** */
|
||||
kbd_put_queue(tty, 0xc0 | (c >> 6));
|
||||
kbd_put_queue(tty, 0x80 | (c & 0x3f));
|
||||
kbd_put_queue(port, 0xc0 | (c >> 6));
|
||||
kbd_put_queue(port, 0x80 | (c & 0x3f));
|
||||
} else {
|
||||
/* 1110**** 10****** 10****** */
|
||||
kbd_put_queue(tty, 0xe0 | (c >> 12));
|
||||
kbd_put_queue(tty, 0x80 | ((c >> 6) & 0x3f));
|
||||
kbd_put_queue(tty, 0x80 | (c & 0x3f));
|
||||
kbd_put_queue(port, 0xe0 | (c >> 12));
|
||||
kbd_put_queue(port, 0x80 | ((c >> 6) & 0x3f));
|
||||
kbd_put_queue(port, 0x80 | (c & 0x3f));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -283,7 +283,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
|
|||
unsigned short keysym;
|
||||
unsigned char type, value;
|
||||
|
||||
if (!kbd || !kbd->tty)
|
||||
if (!kbd)
|
||||
return;
|
||||
|
||||
if (keycode >= 384)
|
||||
|
@ -323,7 +323,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
|
|||
#endif
|
||||
(*k_handler[type])(kbd, value);
|
||||
} else
|
||||
to_utf8(kbd->tty, keysym);
|
||||
to_utf8(kbd->port, keysym);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -457,6 +457,7 @@ do_kdgkb_ioctl(struct kbd_data *kbd, struct kbsentry __user *u_kbs,
|
|||
|
||||
int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
void __user *argp;
|
||||
unsigned int ct;
|
||||
int perm;
|
||||
|
@ -467,7 +468,10 @@ int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)
|
|||
* To have permissions to do most of the vt ioctls, we either have
|
||||
* to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
|
||||
*/
|
||||
perm = current->signal->tty == kbd->tty || capable(CAP_SYS_TTY_CONFIG);
|
||||
tty = tty_port_tty_get(kbd->port);
|
||||
/* FIXME this test is pretty racy */
|
||||
perm = current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG);
|
||||
tty_kref_put(tty);
|
||||
switch (cmd) {
|
||||
case KDGKBTYPE:
|
||||
return put_user(KB_101, (char __user *)argp);
|
||||
|
|
|
@ -21,7 +21,7 @@ typedef void (fn_handler_fn)(struct kbd_data *);
|
|||
*/
|
||||
|
||||
struct kbd_data {
|
||||
struct tty_struct *tty;
|
||||
struct tty_port *port;
|
||||
unsigned short **key_maps;
|
||||
char **func_table;
|
||||
fn_handler_fn **fn_handler;
|
||||
|
@ -42,16 +42,24 @@ int kbd_ioctl(struct kbd_data *, unsigned int, unsigned long);
|
|||
* Helper Functions.
|
||||
*/
|
||||
static inline void
|
||||
kbd_put_queue(struct tty_struct *tty, int ch)
|
||||
kbd_put_queue(struct tty_port *port, int ch)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(port);
|
||||
if (!tty)
|
||||
return;
|
||||
tty_insert_flip_char(tty, ch, 0);
|
||||
tty_schedule_flip(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
static inline void
|
||||
kbd_puts_queue(struct tty_struct *tty, char *cp)
|
||||
kbd_puts_queue(struct tty_port *port, char *cp)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(port);
|
||||
if (!tty)
|
||||
return;
|
||||
while (*cp)
|
||||
tty_insert_flip_char(tty, *cp++, 0);
|
||||
tty_schedule_flip(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ static struct sclp_buffer *sclp_ttybuf;
|
|||
/* Timer for delayed output of console messages. */
|
||||
static struct timer_list sclp_tty_timer;
|
||||
|
||||
static struct tty_struct *sclp_tty;
|
||||
static struct tty_port sclp_port;
|
||||
static unsigned char sclp_tty_chars[SCLP_TTY_BUF_SIZE];
|
||||
static unsigned short int sclp_tty_chars_count;
|
||||
|
||||
|
@ -64,7 +64,7 @@ static int sclp_tty_columns = 80;
|
|||
static int
|
||||
sclp_tty_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
sclp_tty = tty;
|
||||
tty_port_tty_set(&sclp_port, tty);
|
||||
tty->driver_data = NULL;
|
||||
tty->low_latency = 0;
|
||||
return 0;
|
||||
|
@ -76,7 +76,7 @@ sclp_tty_close(struct tty_struct *tty, struct file *filp)
|
|||
{
|
||||
if (tty->count > 1)
|
||||
return;
|
||||
sclp_tty = NULL;
|
||||
tty_port_tty_set(&sclp_port, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -108,6 +108,7 @@ sclp_tty_write_room (struct tty_struct *tty)
|
|||
static void
|
||||
sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
void *page;
|
||||
|
||||
|
@ -126,8 +127,10 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
|
|||
spin_unlock_irqrestore(&sclp_tty_lock, flags);
|
||||
} while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback));
|
||||
/* check if the tty needs a wake up call */
|
||||
if (sclp_tty != NULL) {
|
||||
tty_wakeup(sclp_tty);
|
||||
tty = tty_port_tty_get(&sclp_port);
|
||||
if (tty != NULL) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -326,21 +329,22 @@ sclp_tty_flush_buffer(struct tty_struct *tty)
|
|||
static void
|
||||
sclp_tty_input(unsigned char* buf, unsigned int count)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(&sclp_port);
|
||||
unsigned int cchar;
|
||||
|
||||
/*
|
||||
* If this tty driver is currently closed
|
||||
* then throw the received input away.
|
||||
*/
|
||||
if (sclp_tty == NULL)
|
||||
if (tty == NULL)
|
||||
return;
|
||||
cchar = ctrlchar_handle(buf, count, sclp_tty);
|
||||
cchar = ctrlchar_handle(buf, count, tty);
|
||||
switch (cchar & CTRLCHAR_MASK) {
|
||||
case CTRLCHAR_SYSRQ:
|
||||
break;
|
||||
case CTRLCHAR_CTRL:
|
||||
tty_insert_flip_char(sclp_tty, cchar, TTY_NORMAL);
|
||||
tty_flip_buffer_push(sclp_tty);
|
||||
tty_insert_flip_char(tty, cchar, TTY_NORMAL);
|
||||
tty_flip_buffer_push(tty);
|
||||
break;
|
||||
case CTRLCHAR_NONE:
|
||||
/* send (normal) input to line discipline */
|
||||
|
@ -348,13 +352,14 @@ sclp_tty_input(unsigned char* buf, unsigned int count)
|
|||
(strncmp((const char *) buf + count - 2, "^n", 2) &&
|
||||
strncmp((const char *) buf + count - 2, "\252n", 2))) {
|
||||
/* add the auto \n */
|
||||
tty_insert_flip_string(sclp_tty, buf, count);
|
||||
tty_insert_flip_char(sclp_tty, '\n', TTY_NORMAL);
|
||||
tty_insert_flip_string(tty, buf, count);
|
||||
tty_insert_flip_char(tty, '\n', TTY_NORMAL);
|
||||
} else
|
||||
tty_insert_flip_string(sclp_tty, buf, count - 2);
|
||||
tty_flip_buffer_push(sclp_tty);
|
||||
tty_insert_flip_string(tty, buf, count - 2);
|
||||
tty_flip_buffer_push(tty);
|
||||
break;
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -543,7 +548,7 @@ sclp_tty_init(void)
|
|||
sclp_tty_tolower = 1;
|
||||
}
|
||||
sclp_tty_chars_count = 0;
|
||||
sclp_tty = NULL;
|
||||
tty_port_init(&sclp_port);
|
||||
|
||||
rc = sclp_register(&sclp_input_event);
|
||||
if (rc) {
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
#define SCLP_VT220_DEVICE_NAME "ttysclp"
|
||||
#define SCLP_VT220_CONSOLE_NAME "ttyS"
|
||||
#define SCLP_VT220_CONSOLE_INDEX 1 /* console=ttyS1 */
|
||||
#define SCLP_VT220_BUF_SIZE 80
|
||||
|
||||
/* Representation of a single write request */
|
||||
struct sclp_vt220_request {
|
||||
|
@ -56,8 +55,7 @@ struct sclp_vt220_sccb {
|
|||
/* Structures and data needed to register tty driver */
|
||||
static struct tty_driver *sclp_vt220_driver;
|
||||
|
||||
/* The tty_struct that the kernel associated with us */
|
||||
static struct tty_struct *sclp_vt220_tty;
|
||||
static struct tty_port sclp_vt220_port;
|
||||
|
||||
/* Lock to protect internal data from concurrent access */
|
||||
static spinlock_t sclp_vt220_lock;
|
||||
|
@ -116,6 +114,7 @@ static struct sclp_register sclp_vt220_register = {
|
|||
static void
|
||||
sclp_vt220_process_queue(struct sclp_vt220_request *request)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
void *page;
|
||||
|
||||
|
@ -141,8 +140,10 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request)
|
|||
if (request == NULL && sclp_vt220_flush_later)
|
||||
sclp_vt220_emit_current();
|
||||
/* Check if the tty needs a wake up call */
|
||||
if (sclp_vt220_tty != NULL) {
|
||||
tty_wakeup(sclp_vt220_tty);
|
||||
tty = tty_port_tty_get(&sclp_vt220_port);
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -460,11 +461,12 @@ sclp_vt220_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
|||
static void
|
||||
sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(&sclp_vt220_port);
|
||||
char *buffer;
|
||||
unsigned int count;
|
||||
|
||||
/* Ignore input if device is not open */
|
||||
if (sclp_vt220_tty == NULL)
|
||||
if (tty == NULL)
|
||||
return;
|
||||
|
||||
buffer = (char *) ((addr_t) evbuf + sizeof(struct evbuf_header));
|
||||
|
@ -478,10 +480,11 @@ sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
|
|||
/* Send input to line discipline */
|
||||
buffer++;
|
||||
count--;
|
||||
tty_insert_flip_string(sclp_vt220_tty, buffer, count);
|
||||
tty_flip_buffer_push(sclp_vt220_tty);
|
||||
tty_insert_flip_string(tty, buffer, count);
|
||||
tty_flip_buffer_push(tty);
|
||||
break;
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -491,10 +494,7 @@ static int
|
|||
sclp_vt220_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
if (tty->count == 1) {
|
||||
sclp_vt220_tty = tty;
|
||||
tty->driver_data = kmalloc(SCLP_VT220_BUF_SIZE, GFP_KERNEL);
|
||||
if (tty->driver_data == NULL)
|
||||
return -ENOMEM;
|
||||
tty_port_tty_set(&sclp_vt220_port, tty);
|
||||
tty->low_latency = 0;
|
||||
if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
|
||||
tty->winsize.ws_row = 24;
|
||||
|
@ -510,11 +510,8 @@ sclp_vt220_open(struct tty_struct *tty, struct file *filp)
|
|||
static void
|
||||
sclp_vt220_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
if (tty->count == 1) {
|
||||
sclp_vt220_tty = NULL;
|
||||
kfree(tty->driver_data);
|
||||
tty->driver_data = NULL;
|
||||
}
|
||||
if (tty->count == 1)
|
||||
tty_port_tty_set(&sclp_vt220_port, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -635,9 +632,9 @@ static int __init __sclp_vt220_init(int num_pages)
|
|||
INIT_LIST_HEAD(&sclp_vt220_empty);
|
||||
INIT_LIST_HEAD(&sclp_vt220_outqueue);
|
||||
init_timer(&sclp_vt220_timer);
|
||||
tty_port_init(&sclp_vt220_port);
|
||||
sclp_vt220_current_request = NULL;
|
||||
sclp_vt220_buffered_chars = 0;
|
||||
sclp_vt220_tty = NULL;
|
||||
sclp_vt220_flush_later = 0;
|
||||
|
||||
/* Allocate pages for output buffering */
|
||||
|
|
|
@ -61,7 +61,7 @@ struct tty3270_line {
|
|||
*/
|
||||
struct tty3270 {
|
||||
struct raw3270_view view;
|
||||
struct tty_struct *tty; /* Pointer to tty structure */
|
||||
struct tty_port port;
|
||||
void **freemem_pages; /* Array of pages used for freemem. */
|
||||
struct list_head freemem; /* List of free memory for strings. */
|
||||
|
||||
|
@ -324,9 +324,8 @@ tty3270_blank_line(struct tty3270 *tp)
|
|||
static void
|
||||
tty3270_write_callback(struct raw3270_request *rq, void *data)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
|
||||
|
||||
tp = (struct tty3270 *) rq->view;
|
||||
if (rq->rc != 0) {
|
||||
/* Write wasn't successful. Refresh all. */
|
||||
tp->update_flags = TTY_UPDATE_ALL;
|
||||
|
@ -450,10 +449,9 @@ tty3270_rcl_add(struct tty3270 *tp, char *input, int len)
|
|||
static void
|
||||
tty3270_rcl_backward(struct kbd_data *kbd)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
|
||||
struct string *s;
|
||||
|
||||
tp = kbd->tty->driver_data;
|
||||
spin_lock_bh(&tp->view.lock);
|
||||
if (tp->inattr == TF_INPUT) {
|
||||
if (tp->rcl_walk && tp->rcl_walk->prev != &tp->rcl_lines)
|
||||
|
@ -478,9 +476,8 @@ tty3270_rcl_backward(struct kbd_data *kbd)
|
|||
static void
|
||||
tty3270_exit_tty(struct kbd_data *kbd)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
|
||||
|
||||
tp = kbd->tty->driver_data;
|
||||
raw3270_deactivate_view(&tp->view);
|
||||
}
|
||||
|
||||
|
@ -490,10 +487,9 @@ tty3270_exit_tty(struct kbd_data *kbd)
|
|||
static void
|
||||
tty3270_scroll_forward(struct kbd_data *kbd)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
|
||||
int nr_up;
|
||||
|
||||
tp = kbd->tty->driver_data;
|
||||
spin_lock_bh(&tp->view.lock);
|
||||
nr_up = tp->nr_up - tp->view.rows + 2;
|
||||
if (nr_up < 0)
|
||||
|
@ -513,10 +509,9 @@ tty3270_scroll_forward(struct kbd_data *kbd)
|
|||
static void
|
||||
tty3270_scroll_backward(struct kbd_data *kbd)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
|
||||
int nr_up;
|
||||
|
||||
tp = kbd->tty->driver_data;
|
||||
spin_lock_bh(&tp->view.lock);
|
||||
nr_up = tp->nr_up + tp->view.rows - 2;
|
||||
if (nr_up + tp->view.rows - 2 > tp->nr_lines)
|
||||
|
@ -537,11 +532,10 @@ static void
|
|||
tty3270_read_tasklet(struct raw3270_request *rrq)
|
||||
{
|
||||
static char kreset_data = TW_KR;
|
||||
struct tty3270 *tp;
|
||||
struct tty3270 *tp = container_of(rrq->view, struct tty3270, view);
|
||||
char *input;
|
||||
int len;
|
||||
|
||||
tp = (struct tty3270 *) rrq->view;
|
||||
spin_lock_bh(&tp->view.lock);
|
||||
/*
|
||||
* Two AID keys are special: For 0x7d (enter) the input line
|
||||
|
@ -577,13 +571,10 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
|
|||
raw3270_request_add_data(tp->kreset, &kreset_data, 1);
|
||||
raw3270_start(&tp->view, tp->kreset);
|
||||
|
||||
/* Emit input string. */
|
||||
if (tp->tty) {
|
||||
while (len-- > 0)
|
||||
kbd_keycode(tp->kbd, *input++);
|
||||
/* Emit keycode for AID byte. */
|
||||
kbd_keycode(tp->kbd, 256 + tp->input->string[0]);
|
||||
}
|
||||
while (len-- > 0)
|
||||
kbd_keycode(tp->kbd, *input++);
|
||||
/* Emit keycode for AID byte. */
|
||||
kbd_keycode(tp->kbd, 256 + tp->input->string[0]);
|
||||
|
||||
raw3270_request_reset(rrq);
|
||||
xchg(&tp->read, rrq);
|
||||
|
@ -596,9 +587,10 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
|
|||
static void
|
||||
tty3270_read_callback(struct raw3270_request *rq, void *data)
|
||||
{
|
||||
struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
|
||||
raw3270_get_view(rq->view);
|
||||
/* Schedule tasklet to pass input to tty. */
|
||||
tasklet_schedule(&((struct tty3270 *) rq->view)->readlet);
|
||||
tasklet_schedule(&tp->readlet);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -635,9 +627,8 @@ tty3270_issue_read(struct tty3270 *tp, int lock)
|
|||
static int
|
||||
tty3270_activate(struct raw3270_view *view)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
struct tty3270 *tp = container_of(view, struct tty3270, view);
|
||||
|
||||
tp = (struct tty3270 *) view;
|
||||
tp->update_flags = TTY_UPDATE_ALL;
|
||||
tty3270_set_timer(tp, 1);
|
||||
return 0;
|
||||
|
@ -646,9 +637,8 @@ tty3270_activate(struct raw3270_view *view)
|
|||
static void
|
||||
tty3270_deactivate(struct raw3270_view *view)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
struct tty3270 *tp = container_of(view, struct tty3270, view);
|
||||
|
||||
tp = (struct tty3270 *) view;
|
||||
del_timer(&tp->timer);
|
||||
}
|
||||
|
||||
|
@ -690,6 +680,17 @@ tty3270_alloc_view(void)
|
|||
if (!tp->freemem_pages)
|
||||
goto out_tp;
|
||||
INIT_LIST_HEAD(&tp->freemem);
|
||||
INIT_LIST_HEAD(&tp->lines);
|
||||
INIT_LIST_HEAD(&tp->update);
|
||||
INIT_LIST_HEAD(&tp->rcl_lines);
|
||||
tp->rcl_max = 20;
|
||||
tty_port_init(&tp->port);
|
||||
setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update,
|
||||
(unsigned long) tp);
|
||||
tasklet_init(&tp->readlet,
|
||||
(void (*)(unsigned long)) tty3270_read_tasklet,
|
||||
(unsigned long) tp->read);
|
||||
|
||||
for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) {
|
||||
tp->freemem_pages[pages] = (void *)
|
||||
__get_free_pages(GFP_KERNEL|GFP_DMA, 0);
|
||||
|
@ -794,16 +795,15 @@ tty3270_free_screen(struct tty3270 *tp)
|
|||
static void
|
||||
tty3270_release(struct raw3270_view *view)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
struct tty_struct *tty;
|
||||
struct tty3270 *tp = container_of(view, struct tty3270, view);
|
||||
struct tty_struct *tty = tty_port_tty_get(&tp->port);
|
||||
|
||||
tp = (struct tty3270 *) view;
|
||||
tty = tp->tty;
|
||||
if (tty) {
|
||||
tty->driver_data = NULL;
|
||||
tp->tty = tp->kbd->tty = NULL;
|
||||
tty_port_tty_set(&tp->port, NULL);
|
||||
tty_hangup(tty);
|
||||
raw3270_put_view(&tp->view);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -813,8 +813,9 @@ tty3270_release(struct raw3270_view *view)
|
|||
static void
|
||||
tty3270_free(struct raw3270_view *view)
|
||||
{
|
||||
tty3270_free_screen((struct tty3270 *) view);
|
||||
tty3270_free_view((struct tty3270 *) view);
|
||||
struct tty3270 *tp = container_of(view, struct tty3270, view);
|
||||
tty3270_free_screen(tp);
|
||||
tty3270_free_view(tp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -823,14 +824,13 @@ tty3270_free(struct raw3270_view *view)
|
|||
static void
|
||||
tty3270_del_views(void)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < tty3270_max_index; i++) {
|
||||
tp = (struct tty3270 *)
|
||||
struct raw3270_view *view =
|
||||
raw3270_find_view(&tty3270_fn, i + RAW3270_FIRSTMINOR);
|
||||
if (!IS_ERR(tp))
|
||||
raw3270_del_view(&tp->view);
|
||||
if (!IS_ERR(view))
|
||||
raw3270_del_view(view);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -848,22 +848,23 @@ static struct raw3270_fn tty3270_fn = {
|
|||
static int
|
||||
tty3270_open(struct tty_struct *tty, struct file * filp)
|
||||
{
|
||||
struct raw3270_view *view;
|
||||
struct tty3270 *tp;
|
||||
int i, rc;
|
||||
|
||||
if (tty->count > 1)
|
||||
return 0;
|
||||
/* Check if the tty3270 is already there. */
|
||||
tp = (struct tty3270 *)
|
||||
raw3270_find_view(&tty3270_fn,
|
||||
view = raw3270_find_view(&tty3270_fn,
|
||||
tty->index + RAW3270_FIRSTMINOR);
|
||||
if (!IS_ERR(tp)) {
|
||||
if (!IS_ERR(view)) {
|
||||
tp = container_of(view, struct tty3270, view);
|
||||
tty->driver_data = tp;
|
||||
tty->winsize.ws_row = tp->view.rows - 2;
|
||||
tty->winsize.ws_col = tp->view.cols;
|
||||
tty->low_latency = 0;
|
||||
tp->tty = tty;
|
||||
tp->kbd->tty = tty;
|
||||
/* why to reassign? */
|
||||
tty_port_tty_set(&tp->port, tty);
|
||||
tp->inattr = TF_INPUT;
|
||||
return 0;
|
||||
}
|
||||
|
@ -871,7 +872,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
|
|||
tty3270_max_index = tty->index + 1;
|
||||
|
||||
/* Quick exit if there is no device for tty->index. */
|
||||
if (PTR_ERR(tp) == -ENODEV)
|
||||
if (PTR_ERR(view) == -ENODEV)
|
||||
return -ENODEV;
|
||||
|
||||
/* Allocate tty3270 structure on first open. */
|
||||
|
@ -879,16 +880,6 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
|
|||
if (IS_ERR(tp))
|
||||
return PTR_ERR(tp);
|
||||
|
||||
INIT_LIST_HEAD(&tp->lines);
|
||||
INIT_LIST_HEAD(&tp->update);
|
||||
INIT_LIST_HEAD(&tp->rcl_lines);
|
||||
tp->rcl_max = 20;
|
||||
setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update,
|
||||
(unsigned long) tp);
|
||||
tasklet_init(&tp->readlet,
|
||||
(void (*)(unsigned long)) tty3270_read_tasklet,
|
||||
(unsigned long) tp->read);
|
||||
|
||||
rc = raw3270_add_view(&tp->view, &tty3270_fn,
|
||||
tty->index + RAW3270_FIRSTMINOR);
|
||||
if (rc) {
|
||||
|
@ -903,7 +894,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
|
|||
return rc;
|
||||
}
|
||||
|
||||
tp->tty = tty;
|
||||
tty_port_tty_set(&tp->port, tty);
|
||||
tty->low_latency = 0;
|
||||
tty->driver_data = tp;
|
||||
tty->winsize.ws_row = tp->view.rows - 2;
|
||||
|
@ -917,7 +908,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
|
|||
for (i = 0; i < tp->view.rows - 2; i++)
|
||||
tty3270_blank_line(tp);
|
||||
|
||||
tp->kbd->tty = tty;
|
||||
tp->kbd->port = &tp->port;
|
||||
tp->kbd->fn_handler[KVAL(K_INCRCONSOLE)] = tty3270_exit_tty;
|
||||
tp->kbd->fn_handler[KVAL(K_SCROLLBACK)] = tty3270_scroll_backward;
|
||||
tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward;
|
||||
|
@ -935,14 +926,13 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
|
|||
static void
|
||||
tty3270_close(struct tty_struct *tty, struct file * filp)
|
||||
{
|
||||
struct tty3270 *tp;
|
||||
struct tty3270 *tp = tty->driver_data;
|
||||
|
||||
if (tty->count > 1)
|
||||
return;
|
||||
tp = (struct tty3270 *) tty->driver_data;
|
||||
if (tp) {
|
||||
tty->driver_data = NULL;
|
||||
tp->tty = tp->kbd->tty = NULL;
|
||||
tty_port_tty_set(&tp->port, NULL);
|
||||
raw3270_put_view(&tp->view);
|
||||
}
|
||||
}
|
||||
|
@ -1391,7 +1381,7 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
|
|||
tty3270_lf(tp);
|
||||
break;
|
||||
case 'Z': /* Respond ID. */
|
||||
kbd_puts_queue(tp->tty, "\033[?6c");
|
||||
kbd_puts_queue(&tp->port, "\033[?6c");
|
||||
break;
|
||||
case '7': /* Save cursor position. */
|
||||
tp->saved_cx = tp->cx;
|
||||
|
@ -1437,11 +1427,11 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
|
|||
tp->esc_state = ESnormal;
|
||||
if (ch == 'n' && !tp->esc_ques) {
|
||||
if (tp->esc_par[0] == 5) /* Status report. */
|
||||
kbd_puts_queue(tp->tty, "\033[0n");
|
||||
kbd_puts_queue(&tp->port, "\033[0n");
|
||||
else if (tp->esc_par[0] == 6) { /* Cursor report. */
|
||||
char buf[40];
|
||||
sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1);
|
||||
kbd_puts_queue(tp->tty, buf);
|
||||
kbd_puts_queue(&tp->port, buf);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1513,12 +1503,13 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
|
|||
* String write routine for 3270 ttys
|
||||
*/
|
||||
static void
|
||||
tty3270_do_write(struct tty3270 *tp, const unsigned char *buf, int count)
|
||||
tty3270_do_write(struct tty3270 *tp, struct tty_struct *tty,
|
||||
const unsigned char *buf, int count)
|
||||
{
|
||||
int i_msg, i;
|
||||
|
||||
spin_lock_bh(&tp->view.lock);
|
||||
for (i_msg = 0; !tp->tty->stopped && i_msg < count; i_msg++) {
|
||||
for (i_msg = 0; !tty->stopped && i_msg < count; i_msg++) {
|
||||
if (tp->esc_state != 0) {
|
||||
/* Continue escape sequence. */
|
||||
tty3270_escape_sequence(tp, buf[i_msg]);
|
||||
|
@ -1595,10 +1586,10 @@ tty3270_write(struct tty_struct * tty,
|
|||
if (!tp)
|
||||
return 0;
|
||||
if (tp->char_count > 0) {
|
||||
tty3270_do_write(tp, tp->char_buf, tp->char_count);
|
||||
tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
|
||||
tp->char_count = 0;
|
||||
}
|
||||
tty3270_do_write(tp, buf, count);
|
||||
tty3270_do_write(tp, tty, buf, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
@ -1629,7 +1620,7 @@ tty3270_flush_chars(struct tty_struct *tty)
|
|||
if (!tp)
|
||||
return;
|
||||
if (tp->char_count > 0) {
|
||||
tty3270_do_write(tp, tp->char_buf, tp->char_count);
|
||||
tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
|
||||
tp->char_count = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1859,9 +1859,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
|
|||
printk("block_til_ready blocking: ttys%d, count = %d\n",
|
||||
info->line, state->count);
|
||||
#endif
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
schedule();
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
}
|
||||
current->state = TASK_RUNNING;
|
||||
remove_wait_queue(&info->open_wait, &wait);
|
||||
|
|
|
@ -1033,7 +1033,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
|
|||
if (!retinfo)
|
||||
return -EFAULT;
|
||||
memset(&tmp, 0, sizeof(tmp));
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
tmp.line = tty->index;
|
||||
tmp.port = state->port;
|
||||
tmp.flags = state->tport.flags;
|
||||
|
@ -1042,7 +1042,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
|
|||
tmp.close_delay = state->tport.close_delay;
|
||||
tmp.closing_wait = state->tport.closing_wait;
|
||||
tmp.custom_divisor = state->custom_divisor;
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
|
@ -1059,12 +1059,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
|
|||
if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
|
||||
return -EFAULT;
|
||||
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) ||
|
||||
new_serial.custom_divisor != state->custom_divisor;
|
||||
if (new_serial.irq || new_serial.port != state->port ||
|
||||
new_serial.xmit_fifo_size != state->xmit_fifo_size) {
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -1074,7 +1074,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
|
|||
(new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
|
||||
((new_serial.flags & ~ASYNC_USR_MASK) !=
|
||||
(port->flags & ~ASYNC_USR_MASK))) {
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
return -EPERM;
|
||||
}
|
||||
port->flags = ((port->flags & ~ASYNC_USR_MASK) |
|
||||
|
@ -1084,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
|
|||
}
|
||||
|
||||
if (new_serial.baud_base < 9600) {
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -1116,7 +1116,7 @@ check_and_exit:
|
|||
}
|
||||
} else
|
||||
retval = startup(tty, state);
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,9 +62,7 @@ static inline uint32_t bfin_write_emudat_chars(char a, char b, char c, char d)
|
|||
|
||||
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 struct tty_port port;
|
||||
static volatile struct circ_buf bfin_jc_write_buf;
|
||||
|
||||
static int
|
||||
|
@ -73,18 +71,21 @@ bfin_jc_emudat_manager(void *arg)
|
|||
uint32_t inbound_len = 0, outbound_len = 0;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
struct tty_struct *tty = tty_port_tty_get(&port);
|
||||
/* no one left to give data to, so sleep */
|
||||
if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) {
|
||||
if (tty == NULL && circ_empty(&bfin_jc_write_buf)) {
|
||||
pr_debug("waiting for readers\n");
|
||||
__set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
schedule();
|
||||
__set_current_state(TASK_RUNNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* no data available, so just chill */
|
||||
if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) {
|
||||
pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n",
|
||||
inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head);
|
||||
tty_kref_put(tty);
|
||||
if (inbound_len)
|
||||
schedule();
|
||||
else
|
||||
|
@ -94,9 +95,6 @@ bfin_jc_emudat_manager(void *arg)
|
|||
|
||||
/* 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) {
|
||||
|
@ -110,7 +108,6 @@ bfin_jc_emudat_manager(void *arg)
|
|||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&bfin_jc_tty_mutex);
|
||||
}
|
||||
|
||||
/* if outgoing data is ready, post it */
|
||||
|
@ -120,7 +117,6 @@ bfin_jc_emudat_manager(void *arg)
|
|||
bfin_write_emudat(outbound_len);
|
||||
pr_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 =
|
||||
|
@ -132,14 +128,12 @@ bfin_jc_emudat_manager(void *arg)
|
|||
);
|
||||
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);
|
||||
pr_debug(" outgoing data: 0x%08x (pushing %zu)\n", emudat, ate);
|
||||
}
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
__set_current_state(TASK_RUNNING);
|
||||
|
@ -149,24 +143,28 @@ bfin_jc_emudat_manager(void *arg)
|
|||
static int
|
||||
bfin_jc_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
mutex_lock(&bfin_jc_tty_mutex);
|
||||
pr_debug("open %lu\n", bfin_jc_count);
|
||||
++bfin_jc_count;
|
||||
bfin_jc_tty = tty;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port.lock, flags);
|
||||
port.count++;
|
||||
spin_unlock_irqrestore(&port.lock, flags);
|
||||
tty_port_tty_set(&port, 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);
|
||||
pr_debug("close %lu\n", bfin_jc_count);
|
||||
if (--bfin_jc_count == 0)
|
||||
bfin_jc_tty = NULL;
|
||||
unsigned long flags;
|
||||
bool last;
|
||||
|
||||
spin_lock_irqsave(&port.lock, flags);
|
||||
last = --port.count == 0;
|
||||
spin_unlock_irqrestore(&port.lock, flags);
|
||||
if (last)
|
||||
tty_port_tty_set(&port, 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 */
|
||||
|
@ -242,6 +240,8 @@ static int __init bfin_jc_init(void)
|
|||
{
|
||||
int ret;
|
||||
|
||||
tty_port_init(&port);
|
||||
|
||||
bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME);
|
||||
if (IS_ERR(bfin_jc_kthread))
|
||||
return PTR_ERR(bfin_jc_kthread);
|
||||
|
|
|
@ -1599,7 +1599,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
|
|||
* If the port is the middle of closing, bail out now
|
||||
*/
|
||||
if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
|
||||
wait_event_interruptible_tty(info->port.close_wait,
|
||||
wait_event_interruptible_tty(tty, info->port.close_wait,
|
||||
!(info->port.flags & ASYNC_CLOSING));
|
||||
return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
|
||||
}
|
||||
|
|
|
@ -107,7 +107,7 @@ static struct hvc_struct *hvc_get_by_index(int index)
|
|||
list_for_each_entry(hp, &hvc_structs, next) {
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
if (hp->index == index) {
|
||||
kref_get(&hp->kref);
|
||||
tty_port_get(&hp->port);
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
spin_unlock(&hvc_structs_lock);
|
||||
return hp;
|
||||
|
@ -229,9 +229,9 @@ static int __init hvc_console_init(void)
|
|||
console_initcall(hvc_console_init);
|
||||
|
||||
/* callback when the kboject ref count reaches zero. */
|
||||
static void destroy_hvc_struct(struct kref *kref)
|
||||
static void hvc_port_destruct(struct tty_port *port)
|
||||
{
|
||||
struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref);
|
||||
struct hvc_struct *hp = container_of(port, struct hvc_struct, port);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock(&hvc_structs_lock);
|
||||
|
@ -264,7 +264,7 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops)
|
|||
/* make sure no no tty has been registered in this index */
|
||||
hp = hvc_get_by_index(index);
|
||||
if (hp) {
|
||||
kref_put(&hp->kref, destroy_hvc_struct);
|
||||
tty_port_put(&hp->port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -313,20 +313,17 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
|
|||
if (!(hp = hvc_get_by_index(tty->index)))
|
||||
return -ENODEV;
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
spin_lock_irqsave(&hp->port.lock, flags);
|
||||
/* Check and then increment for fast path open. */
|
||||
if (hp->count++ > 0) {
|
||||
tty_kref_get(tty);
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
if (hp->port.count++ > 0) {
|
||||
spin_unlock_irqrestore(&hp->port.lock, flags);
|
||||
hvc_kick();
|
||||
return 0;
|
||||
} /* else count == 0 */
|
||||
spin_unlock_irqrestore(&hp->port.lock, flags);
|
||||
|
||||
tty->driver_data = hp;
|
||||
|
||||
hp->tty = tty_kref_get(tty);
|
||||
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
tty_port_tty_set(&hp->port, tty);
|
||||
|
||||
if (hp->ops->notifier_add)
|
||||
rc = hp->ops->notifier_add(hp, hp->data);
|
||||
|
@ -338,12 +335,9 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
|
|||
* tty fields and return the kref reference.
|
||||
*/
|
||||
if (rc) {
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
hp->tty = NULL;
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
tty_kref_put(tty);
|
||||
tty_port_tty_set(&hp->port, NULL);
|
||||
tty->driver_data = NULL;
|
||||
kref_put(&hp->kref, destroy_hvc_struct);
|
||||
tty_port_put(&hp->port);
|
||||
printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
|
||||
}
|
||||
/* Force wakeup of the polling thread */
|
||||
|
@ -370,12 +364,12 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
|
|||
|
||||
hp = tty->driver_data;
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
spin_lock_irqsave(&hp->port.lock, flags);
|
||||
|
||||
if (--hp->count == 0) {
|
||||
if (--hp->port.count == 0) {
|
||||
spin_unlock_irqrestore(&hp->port.lock, flags);
|
||||
/* We are done with the tty pointer now. */
|
||||
hp->tty = NULL;
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
tty_port_tty_set(&hp->port, NULL);
|
||||
|
||||
if (hp->ops->notifier_del)
|
||||
hp->ops->notifier_del(hp, hp->data);
|
||||
|
@ -390,14 +384,13 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
|
|||
*/
|
||||
tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT);
|
||||
} else {
|
||||
if (hp->count < 0)
|
||||
if (hp->port.count < 0)
|
||||
printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
|
||||
hp->vtermno, hp->count);
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
hp->vtermno, hp->port.count);
|
||||
spin_unlock_irqrestore(&hp->port.lock, flags);
|
||||
}
|
||||
|
||||
tty_kref_put(tty);
|
||||
kref_put(&hp->kref, destroy_hvc_struct);
|
||||
tty_port_put(&hp->port);
|
||||
}
|
||||
|
||||
static void hvc_hangup(struct tty_struct *tty)
|
||||
|
@ -412,32 +405,31 @@ static void hvc_hangup(struct tty_struct *tty)
|
|||
/* cancel pending tty resize work */
|
||||
cancel_work_sync(&hp->tty_resize);
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
spin_lock_irqsave(&hp->port.lock, flags);
|
||||
|
||||
/*
|
||||
* The N_TTY line discipline has problems such that in a close vs
|
||||
* open->hangup case this can be called after the final close so prevent
|
||||
* that from happening for now.
|
||||
*/
|
||||
if (hp->count <= 0) {
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
if (hp->port.count <= 0) {
|
||||
spin_unlock_irqrestore(&hp->port.lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
temp_open_count = hp->count;
|
||||
hp->count = 0;
|
||||
hp->n_outbuf = 0;
|
||||
hp->tty = NULL;
|
||||
temp_open_count = hp->port.count;
|
||||
hp->port.count = 0;
|
||||
spin_unlock_irqrestore(&hp->port.lock, flags);
|
||||
tty_port_tty_set(&hp->port, NULL);
|
||||
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
hp->n_outbuf = 0;
|
||||
|
||||
if (hp->ops->notifier_hangup)
|
||||
hp->ops->notifier_hangup(hp, hp->data);
|
||||
|
||||
while(temp_open_count) {
|
||||
--temp_open_count;
|
||||
tty_kref_put(tty);
|
||||
kref_put(&hp->kref, destroy_hvc_struct);
|
||||
tty_port_put(&hp->port);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -478,7 +470,8 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
|
|||
if (!hp)
|
||||
return -EPIPE;
|
||||
|
||||
if (hp->count <= 0)
|
||||
/* FIXME what's this (unprotected) check for? */
|
||||
if (hp->port.count <= 0)
|
||||
return -EIO;
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
|
@ -526,13 +519,12 @@ static void hvc_set_winsz(struct work_struct *work)
|
|||
|
||||
hp = container_of(work, struct hvc_struct, tty_resize);
|
||||
|
||||
spin_lock_irqsave(&hp->lock, hvc_flags);
|
||||
if (!hp->tty) {
|
||||
spin_unlock_irqrestore(&hp->lock, hvc_flags);
|
||||
tty = tty_port_tty_get(&hp->port);
|
||||
if (!tty)
|
||||
return;
|
||||
}
|
||||
ws = hp->ws;
|
||||
tty = tty_kref_get(hp->tty);
|
||||
|
||||
spin_lock_irqsave(&hp->lock, hvc_flags);
|
||||
ws = hp->ws;
|
||||
spin_unlock_irqrestore(&hp->lock, hvc_flags);
|
||||
|
||||
tty_do_resize(tty, &ws);
|
||||
|
@ -601,7 +593,7 @@ int hvc_poll(struct hvc_struct *hp)
|
|||
}
|
||||
|
||||
/* No tty attached, just skip */
|
||||
tty = tty_kref_get(hp->tty);
|
||||
tty = tty_port_tty_get(&hp->port);
|
||||
if (tty == NULL)
|
||||
goto bail;
|
||||
|
||||
|
@ -681,8 +673,7 @@ int hvc_poll(struct hvc_struct *hp)
|
|||
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
if (tty)
|
||||
tty_kref_put(tty);
|
||||
tty_kref_put(tty);
|
||||
|
||||
return poll_mask;
|
||||
}
|
||||
|
@ -817,6 +808,10 @@ static const struct tty_operations hvc_ops = {
|
|||
#endif
|
||||
};
|
||||
|
||||
static const struct tty_port_operations hvc_port_ops = {
|
||||
.destruct = hvc_port_destruct,
|
||||
};
|
||||
|
||||
struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
|
||||
const struct hv_ops *ops,
|
||||
int outbuf_size)
|
||||
|
@ -842,7 +837,8 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
|
|||
hp->outbuf_size = outbuf_size;
|
||||
hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
|
||||
|
||||
kref_init(&hp->kref);
|
||||
tty_port_init(&hp->port);
|
||||
hp->port.ops = &hvc_port_ops;
|
||||
|
||||
INIT_WORK(&hp->tty_resize, hvc_set_winsz);
|
||||
spin_lock_init(&hp->lock);
|
||||
|
@ -875,9 +871,9 @@ int hvc_remove(struct hvc_struct *hp)
|
|||
unsigned long flags;
|
||||
struct tty_struct *tty;
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
tty = tty_kref_get(hp->tty);
|
||||
tty = tty_port_tty_get(&hp->port);
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
if (hp->index < MAX_NR_HVC_CONSOLES)
|
||||
vtermnos[hp->index] = -1;
|
||||
|
||||
|
@ -891,7 +887,7 @@ int hvc_remove(struct hvc_struct *hp)
|
|||
* kref cause it to be removed, which will probably be the tty_vhangup
|
||||
* below.
|
||||
*/
|
||||
kref_put(&hp->kref, destroy_hvc_struct);
|
||||
tty_port_put(&hp->port);
|
||||
|
||||
/*
|
||||
* This function call will auto chain call hvc_hangup.
|
||||
|
|
|
@ -46,10 +46,9 @@
|
|||
#define HVC_ALLOC_TTY_ADAPTERS 8
|
||||
|
||||
struct hvc_struct {
|
||||
struct tty_port port;
|
||||
spinlock_t lock;
|
||||
int index;
|
||||
struct tty_struct *tty;
|
||||
int count;
|
||||
int do_wakeup;
|
||||
char *outbuf;
|
||||
int outbuf_size;
|
||||
|
@ -61,7 +60,6 @@ struct hvc_struct {
|
|||
struct winsize ws;
|
||||
struct work_struct tty_resize;
|
||||
struct list_head next;
|
||||
struct kref kref; /* ref count & hvc_struct lifetime */
|
||||
};
|
||||
|
||||
/* implemented by a low level driver */
|
||||
|
|
|
@ -430,9 +430,9 @@ static int __devinit xencons_probe(struct xenbus_device *dev,
|
|||
if (devid == 0)
|
||||
return -ENODEV;
|
||||
|
||||
info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
|
||||
info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
|
||||
if (!info)
|
||||
goto error_nomem;
|
||||
return -ENOMEM;
|
||||
dev_set_drvdata(&dev->dev, info);
|
||||
info->xbdev = dev;
|
||||
info->vtermno = xenbus_devid_to_vtermno(devid);
|
||||
|
|
|
@ -261,6 +261,7 @@ static DEFINE_SPINLOCK(hvcs_pi_lock);
|
|||
|
||||
/* One vty-server per hvcs_struct */
|
||||
struct hvcs_struct {
|
||||
struct tty_port port;
|
||||
spinlock_t lock;
|
||||
|
||||
/*
|
||||
|
@ -269,9 +270,6 @@ struct hvcs_struct {
|
|||
*/
|
||||
unsigned int index;
|
||||
|
||||
struct tty_struct *tty;
|
||||
int open_count;
|
||||
|
||||
/*
|
||||
* Used to tell the driver kernel_thread what operations need to take
|
||||
* place upon this hvcs_struct instance.
|
||||
|
@ -290,12 +288,11 @@ struct hvcs_struct {
|
|||
int chars_in_buffer;
|
||||
|
||||
/*
|
||||
* Any variable below the kref is valid before a tty is connected and
|
||||
* Any variable below is valid before a tty is connected and
|
||||
* stays valid after the tty is disconnected. These shouldn't be
|
||||
* whacked until the kobject refcount reaches zero though some entries
|
||||
* may be changed via sysfs initiatives.
|
||||
*/
|
||||
struct kref kref; /* ref count & hvcs_struct lifetime */
|
||||
int connected; /* is the vty-server currently connected to a vty? */
|
||||
uint32_t p_unit_address; /* partner unit address */
|
||||
uint32_t p_partition_ID; /* partner partition ID */
|
||||
|
@ -304,9 +301,6 @@ struct hvcs_struct {
|
|||
struct vio_dev *vdev;
|
||||
};
|
||||
|
||||
/* Required to back map a kref to its containing object */
|
||||
#define from_kref(k) container_of(k, struct hvcs_struct, kref)
|
||||
|
||||
static LIST_HEAD(hvcs_structs);
|
||||
static DEFINE_SPINLOCK(hvcs_structs_lock);
|
||||
static DEFINE_MUTEX(hvcs_init_mutex);
|
||||
|
@ -422,7 +416,7 @@ static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribut
|
|||
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
|
||||
if (hvcsd->open_count > 0) {
|
||||
if (hvcsd->port.count > 0) {
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
printk(KERN_INFO "HVCS: vterm state unchanged. "
|
||||
"The hvcs device node is still in use.\n");
|
||||
|
@ -564,7 +558,7 @@ static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance)
|
|||
static void hvcs_try_write(struct hvcs_struct *hvcsd)
|
||||
{
|
||||
uint32_t unit_address = hvcsd->vdev->unit_address;
|
||||
struct tty_struct *tty = hvcsd->tty;
|
||||
struct tty_struct *tty = hvcsd->port.tty;
|
||||
int sent;
|
||||
|
||||
if (hvcsd->todo_mask & HVCS_TRY_WRITE) {
|
||||
|
@ -602,7 +596,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
|
|||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
|
||||
unit_address = hvcsd->vdev->unit_address;
|
||||
tty = hvcsd->tty;
|
||||
tty = hvcsd->port.tty;
|
||||
|
||||
hvcs_try_write(hvcsd);
|
||||
|
||||
|
@ -701,10 +695,9 @@ static void hvcs_return_index(int index)
|
|||
hvcs_index_list[index] = -1;
|
||||
}
|
||||
|
||||
/* callback when the kref ref count reaches zero */
|
||||
static void destroy_hvcs_struct(struct kref *kref)
|
||||
static void hvcs_destruct_port(struct tty_port *p)
|
||||
{
|
||||
struct hvcs_struct *hvcsd = from_kref(kref);
|
||||
struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port);
|
||||
struct vio_dev *vdev;
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -741,6 +734,10 @@ static void destroy_hvcs_struct(struct kref *kref)
|
|||
kfree(hvcsd);
|
||||
}
|
||||
|
||||
static const struct tty_port_operations hvcs_port_ops = {
|
||||
.destruct = hvcs_destruct_port,
|
||||
};
|
||||
|
||||
static int hvcs_get_index(void)
|
||||
{
|
||||
int i;
|
||||
|
@ -789,10 +786,9 @@ static int __devinit hvcs_probe(
|
|||
if (!hvcsd)
|
||||
return -ENODEV;
|
||||
|
||||
|
||||
tty_port_init(&hvcsd->port);
|
||||
hvcsd->port.ops = &hvcs_port_ops;
|
||||
spin_lock_init(&hvcsd->lock);
|
||||
/* Automatically incs the refcount the first time */
|
||||
kref_init(&hvcsd->kref);
|
||||
|
||||
hvcsd->vdev = dev;
|
||||
dev_set_drvdata(&dev->dev, hvcsd);
|
||||
|
@ -852,7 +848,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
|
|||
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
|
||||
tty = hvcsd->tty;
|
||||
tty = hvcsd->port.tty;
|
||||
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
|
||||
|
@ -860,7 +856,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
|
|||
* Let the last holder of this object cause it to be removed, which
|
||||
* would probably be tty_hangup below.
|
||||
*/
|
||||
kref_put(&hvcsd->kref, destroy_hvcs_struct);
|
||||
tty_port_put(&hvcsd->port);
|
||||
|
||||
/*
|
||||
* The hangup is a scheduled function which will auto chain call
|
||||
|
@ -1094,7 +1090,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index)
|
|||
list_for_each_entry(hvcsd, &hvcs_structs, next) {
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
if (hvcsd->index == index) {
|
||||
kref_get(&hvcsd->kref);
|
||||
tty_port_get(&hvcsd->port);
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
spin_unlock(&hvcs_structs_lock);
|
||||
return hvcsd;
|
||||
|
@ -1138,8 +1134,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
|
|||
if ((retval = hvcs_partner_connect(hvcsd)))
|
||||
goto error_release;
|
||||
|
||||
hvcsd->open_count = 1;
|
||||
hvcsd->tty = tty;
|
||||
hvcsd->port.count = 1;
|
||||
hvcsd->port.tty = tty;
|
||||
tty->driver_data = hvcsd;
|
||||
|
||||
memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
|
||||
|
@ -1160,7 +1156,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
|
|||
* and will grab the spinlock and free the connection if it fails.
|
||||
*/
|
||||
if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) {
|
||||
kref_put(&hvcsd->kref, destroy_hvcs_struct);
|
||||
tty_port_put(&hvcsd->port);
|
||||
printk(KERN_WARNING "HVCS: enable device failed.\n");
|
||||
return rc;
|
||||
}
|
||||
|
@ -1171,8 +1167,8 @@ fast_open:
|
|||
hvcsd = tty->driver_data;
|
||||
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
kref_get(&hvcsd->kref);
|
||||
hvcsd->open_count++;
|
||||
tty_port_get(&hvcsd->port);
|
||||
hvcsd->port.count++;
|
||||
hvcsd->todo_mask |= HVCS_SCHED_READ;
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
|
||||
|
@ -1186,7 +1182,7 @@ open_success:
|
|||
|
||||
error_release:
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
kref_put(&hvcsd->kref, destroy_hvcs_struct);
|
||||
tty_port_put(&hvcsd->port);
|
||||
|
||||
printk(KERN_WARNING "HVCS: partner connect failed.\n");
|
||||
return retval;
|
||||
|
@ -1216,7 +1212,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
|
|||
hvcsd = tty->driver_data;
|
||||
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
if (--hvcsd->open_count == 0) {
|
||||
if (--hvcsd->port.count == 0) {
|
||||
|
||||
vio_disable_interrupts(hvcsd->vdev);
|
||||
|
||||
|
@ -1225,7 +1221,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
|
|||
* execute any operations on the TTY even though it is obligated
|
||||
* to deliver any pending I/O to the hypervisor.
|
||||
*/
|
||||
hvcsd->tty = NULL;
|
||||
hvcsd->port.tty = NULL;
|
||||
|
||||
irq = hvcsd->vdev->irq;
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
|
@ -1240,16 +1236,16 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
|
|||
tty->driver_data = NULL;
|
||||
|
||||
free_irq(irq, hvcsd);
|
||||
kref_put(&hvcsd->kref, destroy_hvcs_struct);
|
||||
tty_port_put(&hvcsd->port);
|
||||
return;
|
||||
} else if (hvcsd->open_count < 0) {
|
||||
} else if (hvcsd->port.count < 0) {
|
||||
printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
|
||||
" is missmanaged.\n",
|
||||
hvcsd->vdev->unit_address, hvcsd->open_count);
|
||||
hvcsd->vdev->unit_address, hvcsd->port.count);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
kref_put(&hvcsd->kref, destroy_hvcs_struct);
|
||||
tty_port_put(&hvcsd->port);
|
||||
}
|
||||
|
||||
static void hvcs_hangup(struct tty_struct * tty)
|
||||
|
@ -1261,7 +1257,7 @@ static void hvcs_hangup(struct tty_struct * tty)
|
|||
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
/* Preserve this so that we know how many kref refs to put */
|
||||
temp_open_count = hvcsd->open_count;
|
||||
temp_open_count = hvcsd->port.count;
|
||||
|
||||
/*
|
||||
* Don't kref put inside the spinlock because the destruction
|
||||
|
@ -1273,10 +1269,10 @@ static void hvcs_hangup(struct tty_struct * tty)
|
|||
hvcsd->todo_mask = 0;
|
||||
|
||||
/* I don't think the tty needs the hvcs_struct pointer after a hangup */
|
||||
hvcsd->tty->driver_data = NULL;
|
||||
hvcsd->tty = NULL;
|
||||
tty->driver_data = NULL;
|
||||
hvcsd->port.tty = NULL;
|
||||
|
||||
hvcsd->open_count = 0;
|
||||
hvcsd->port.count = 0;
|
||||
|
||||
/* This will drop any buffered data on the floor which is OK in a hangup
|
||||
* scenario. */
|
||||
|
@ -1301,7 +1297,7 @@ static void hvcs_hangup(struct tty_struct * tty)
|
|||
* NOTE: If this hangup was signaled from user space then the
|
||||
* final put will never happen.
|
||||
*/
|
||||
kref_put(&hvcsd->kref, destroy_hvcs_struct);
|
||||
tty_port_put(&hvcsd->port);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1347,7 +1343,7 @@ static int hvcs_write(struct tty_struct *tty,
|
|||
* the middle of a write operation? This is a crummy place to do this
|
||||
* but we want to keep it all in the spinlock.
|
||||
*/
|
||||
if (hvcsd->open_count <= 0) {
|
||||
if (hvcsd->port.count <= 0) {
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -1421,7 +1417,7 @@ static int hvcs_write_room(struct tty_struct *tty)
|
|||
{
|
||||
struct hvcs_struct *hvcsd = tty->driver_data;
|
||||
|
||||
if (!hvcsd || hvcsd->open_count <= 0)
|
||||
if (!hvcsd || hvcsd->port.count <= 0)
|
||||
return 0;
|
||||
|
||||
return HVCS_BUFF_LEN - hvcsd->chars_in_buffer;
|
||||
|
|
|
@ -69,14 +69,13 @@
|
|||
#define __ALIGNED__ __attribute__((__aligned__(sizeof(long))))
|
||||
|
||||
struct hvsi_struct {
|
||||
struct tty_port port;
|
||||
struct delayed_work writer;
|
||||
struct work_struct handshaker;
|
||||
wait_queue_head_t emptyq; /* woken when outbuf is emptied */
|
||||
wait_queue_head_t stateq; /* woken when HVSI state changes */
|
||||
spinlock_t lock;
|
||||
int index;
|
||||
struct tty_struct *tty;
|
||||
int count;
|
||||
uint8_t throttle_buf[128];
|
||||
uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */
|
||||
/* inbuf is for packet reassembly. leave a little room for leftovers. */
|
||||
|
@ -237,7 +236,7 @@ static int hvsi_read(struct hvsi_struct *hp, char *buf, int count)
|
|||
}
|
||||
|
||||
static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
|
||||
struct tty_struct **to_hangup, struct hvsi_struct **to_handshake)
|
||||
struct tty_struct *tty, struct hvsi_struct **to_handshake)
|
||||
{
|
||||
struct hvsi_control *header = (struct hvsi_control *)packet;
|
||||
|
||||
|
@ -247,9 +246,8 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
|
|||
/* CD went away; no more connection */
|
||||
pr_debug("hvsi%i: CD dropped\n", hp->index);
|
||||
hp->mctrl &= TIOCM_CD;
|
||||
/* If userland hasn't done an open(2) yet, hp->tty is NULL. */
|
||||
if (hp->tty && !(hp->tty->flags & CLOCAL))
|
||||
*to_hangup = hp->tty;
|
||||
if (tty && !C_CLOCAL(tty))
|
||||
tty_hangup(tty);
|
||||
}
|
||||
break;
|
||||
case VSV_CLOSE_PROTOCOL:
|
||||
|
@ -331,7 +329,8 @@ static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet)
|
|||
}
|
||||
}
|
||||
|
||||
static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
|
||||
static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty,
|
||||
const char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -347,7 +346,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
|
|||
continue;
|
||||
}
|
||||
#endif /* CONFIG_MAGIC_SYSRQ */
|
||||
tty_insert_flip_char(hp->tty, c, 0);
|
||||
tty_insert_flip_char(tty, c, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -360,7 +359,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
|
|||
* revisited.
|
||||
*/
|
||||
#define TTY_THRESHOLD_THROTTLE 128
|
||||
static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
|
||||
static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty,
|
||||
const uint8_t *packet)
|
||||
{
|
||||
const struct hvsi_header *header = (const struct hvsi_header *)packet;
|
||||
|
@ -371,14 +370,14 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
|
|||
pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data);
|
||||
|
||||
if (datalen == 0)
|
||||
return NULL;
|
||||
return false;
|
||||
|
||||
if (overflow > 0) {
|
||||
pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__);
|
||||
datalen = TTY_THRESHOLD_THROTTLE;
|
||||
}
|
||||
|
||||
hvsi_insert_chars(hp, data, datalen);
|
||||
hvsi_insert_chars(hp, tty, data, datalen);
|
||||
|
||||
if (overflow > 0) {
|
||||
/*
|
||||
|
@ -390,7 +389,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
|
|||
hp->n_throttle = overflow;
|
||||
}
|
||||
|
||||
return hp->tty;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -399,14 +398,13 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
|
|||
* machine during console handshaking (in which case tty = NULL and we ignore
|
||||
* incoming data).
|
||||
*/
|
||||
static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
|
||||
struct tty_struct **hangup, struct hvsi_struct **handshake)
|
||||
static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty,
|
||||
struct hvsi_struct **handshake)
|
||||
{
|
||||
uint8_t *packet = hp->inbuf;
|
||||
int chunklen;
|
||||
bool flip = false;
|
||||
|
||||
*flip = NULL;
|
||||
*hangup = NULL;
|
||||
*handshake = NULL;
|
||||
|
||||
chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ);
|
||||
|
@ -440,12 +438,12 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
|
|||
case VS_DATA_PACKET_HEADER:
|
||||
if (!is_open(hp))
|
||||
break;
|
||||
if (hp->tty == NULL)
|
||||
if (tty == NULL)
|
||||
break; /* no tty buffer to put data in */
|
||||
*flip = hvsi_recv_data(hp, packet);
|
||||
flip = hvsi_recv_data(hp, tty, packet);
|
||||
break;
|
||||
case VS_CONTROL_PACKET_HEADER:
|
||||
hvsi_recv_control(hp, packet, hangup, handshake);
|
||||
hvsi_recv_control(hp, packet, tty, handshake);
|
||||
break;
|
||||
case VS_QUERY_RESPONSE_PACKET_HEADER:
|
||||
hvsi_recv_response(hp, packet);
|
||||
|
@ -462,28 +460,26 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
|
|||
|
||||
packet += len_packet(packet);
|
||||
|
||||
if (*hangup || *handshake) {
|
||||
pr_debug("%s: hangup or handshake\n", __func__);
|
||||
/*
|
||||
* we need to send the hangup now before receiving any more data.
|
||||
* If we get "data, hangup, data", we can't deliver the second
|
||||
* data before the hangup.
|
||||
*/
|
||||
if (*handshake) {
|
||||
pr_debug("%s: handshake\n", __func__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
compact_inbuf(hp, packet);
|
||||
|
||||
if (flip)
|
||||
tty_flip_buffer_push(tty);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void hvsi_send_overflow(struct hvsi_struct *hp)
|
||||
static void hvsi_send_overflow(struct hvsi_struct *hp, struct tty_struct *tty)
|
||||
{
|
||||
pr_debug("%s: delivering %i bytes overflow\n", __func__,
|
||||
hp->n_throttle);
|
||||
|
||||
hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle);
|
||||
hvsi_insert_chars(hp, tty, hp->throttle_buf, hp->n_throttle);
|
||||
hp->n_throttle = 0;
|
||||
}
|
||||
|
||||
|
@ -494,35 +490,20 @@ static void hvsi_send_overflow(struct hvsi_struct *hp)
|
|||
static irqreturn_t hvsi_interrupt(int irq, void *arg)
|
||||
{
|
||||
struct hvsi_struct *hp = (struct hvsi_struct *)arg;
|
||||
struct tty_struct *flip;
|
||||
struct tty_struct *hangup;
|
||||
struct hvsi_struct *handshake;
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
int again = 1;
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
tty = tty_port_tty_get(&hp->port);
|
||||
|
||||
while (again) {
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
again = hvsi_load_chunk(hp, &flip, &hangup, &handshake);
|
||||
again = hvsi_load_chunk(hp, tty, &handshake);
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
|
||||
/*
|
||||
* we have to call tty_flip_buffer_push() and tty_hangup() outside our
|
||||
* spinlock. But we also have to keep going until we've read all the
|
||||
* available data.
|
||||
*/
|
||||
|
||||
if (flip) {
|
||||
/* there was data put in the tty flip buffer */
|
||||
tty_flip_buffer_push(flip);
|
||||
flip = NULL;
|
||||
}
|
||||
|
||||
if (hangup) {
|
||||
tty_hangup(hangup);
|
||||
}
|
||||
|
||||
if (handshake) {
|
||||
pr_debug("hvsi%i: attempting re-handshake\n", handshake->index);
|
||||
schedule_work(&handshake->handshaker);
|
||||
|
@ -530,18 +511,15 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg)
|
|||
}
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
if (hp->tty && hp->n_throttle
|
||||
&& (!test_bit(TTY_THROTTLED, &hp->tty->flags))) {
|
||||
/* we weren't hung up and we weren't throttled, so we can deliver the
|
||||
* rest now */
|
||||
flip = hp->tty;
|
||||
hvsi_send_overflow(hp);
|
||||
if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
/* we weren't hung up and we weren't throttled, so we can
|
||||
* deliver the rest now */
|
||||
hvsi_send_overflow(hp, tty);
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
|
||||
if (flip) {
|
||||
tty_flip_buffer_push(flip);
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -749,9 +727,9 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp)
|
|||
if (hp->state == HVSI_FSP_DIED)
|
||||
return -EIO;
|
||||
|
||||
tty_port_tty_set(&hp->port, tty);
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
hp->tty = tty;
|
||||
hp->count++;
|
||||
hp->port.count++;
|
||||
atomic_set(&hp->seqno, 0);
|
||||
h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
|
@ -808,8 +786,8 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp)
|
|||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
|
||||
if (--hp->count == 0) {
|
||||
hp->tty = NULL;
|
||||
if (--hp->port.count == 0) {
|
||||
tty_port_tty_set(&hp->port, NULL);
|
||||
hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */
|
||||
|
||||
/* only close down connection if it is not the console */
|
||||
|
@ -841,9 +819,9 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp)
|
|||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
}
|
||||
} else if (hp->count < 0)
|
||||
} else if (hp->port.count < 0)
|
||||
printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n",
|
||||
hp - hvsi_ports, hp->count);
|
||||
hp - hvsi_ports, hp->port.count);
|
||||
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
}
|
||||
|
@ -855,12 +833,11 @@ static void hvsi_hangup(struct tty_struct *tty)
|
|||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
tty_port_tty_set(&hp->port, NULL);
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
|
||||
hp->count = 0;
|
||||
hp->port.count = 0;
|
||||
hp->n_outbuf = 0;
|
||||
hp->tty = NULL;
|
||||
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
}
|
||||
|
||||
|
@ -888,6 +865,7 @@ static void hvsi_write_worker(struct work_struct *work)
|
|||
{
|
||||
struct hvsi_struct *hp =
|
||||
container_of(work, struct hvsi_struct, writer.work);
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
#ifdef DEBUG
|
||||
static long start_j = 0;
|
||||
|
@ -921,7 +899,11 @@ static void hvsi_write_worker(struct work_struct *work)
|
|||
start_j = 0;
|
||||
#endif /* DEBUG */
|
||||
wake_up_all(&hp->emptyq);
|
||||
tty_wakeup(hp->tty);
|
||||
tty = tty_port_tty_get(&hp->port);
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -966,8 +948,8 @@ static int hvsi_write(struct tty_struct *tty,
|
|||
* and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls
|
||||
* will see there is no room in outbuf and return.
|
||||
*/
|
||||
while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) {
|
||||
int chunksize = min(count, hvsi_write_room(hp->tty));
|
||||
while ((count > 0) && (hvsi_write_room(tty) > 0)) {
|
||||
int chunksize = min(count, hvsi_write_room(tty));
|
||||
|
||||
BUG_ON(hp->n_outbuf < 0);
|
||||
memcpy(hp->outbuf + hp->n_outbuf, source, chunksize);
|
||||
|
@ -1014,19 +996,16 @@ static void hvsi_unthrottle(struct tty_struct *tty)
|
|||
{
|
||||
struct hvsi_struct *hp = tty->driver_data;
|
||||
unsigned long flags;
|
||||
int shouldflip = 0;
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
if (hp->n_throttle) {
|
||||
hvsi_send_overflow(hp);
|
||||
shouldflip = 1;
|
||||
hvsi_send_overflow(hp, tty);
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
|
||||
if (shouldflip)
|
||||
tty_flip_buffer_push(hp->tty);
|
||||
|
||||
h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
|
||||
}
|
||||
|
@ -1228,6 +1207,7 @@ static int __init hvsi_console_init(void)
|
|||
init_waitqueue_head(&hp->emptyq);
|
||||
init_waitqueue_head(&hp->stateq);
|
||||
spin_lock_init(&hp->lock);
|
||||
tty_port_init(&hp->port);
|
||||
hp->index = hvsi_count;
|
||||
hp->inbuf_end = hp->inbuf;
|
||||
hp->state = HVSI_CLOSED;
|
||||
|
|
|
@ -377,7 +377,7 @@ int hvsilib_open(struct hvsi_priv *pv, struct hvc_struct *hp)
|
|||
pr_devel("HVSI@%x: open !\n", pv->termno);
|
||||
|
||||
/* Keep track of the tty data structure */
|
||||
pv->tty = tty_kref_get(hp->tty);
|
||||
pv->tty = tty_port_tty_get(&hp->port);
|
||||
|
||||
hvsilib_establish(pv);
|
||||
|
||||
|
|
|
@ -44,14 +44,13 @@
|
|||
#define TTYTYPE_RAS_RAW (2)
|
||||
|
||||
struct ipw_tty {
|
||||
struct tty_port port;
|
||||
int index;
|
||||
struct ipw_hardware *hardware;
|
||||
unsigned int channel_idx;
|
||||
unsigned int secondary_channel_idx;
|
||||
int tty_type;
|
||||
struct ipw_network *network;
|
||||
struct tty_struct *linux_tty;
|
||||
int open_count;
|
||||
unsigned int control_lines;
|
||||
struct mutex ipw_tty_mutex;
|
||||
int tx_bytes_queued;
|
||||
|
@ -73,23 +72,6 @@ static char *tty_type_name(int tty_type)
|
|||
return channel_names[tty_type];
|
||||
}
|
||||
|
||||
static void report_registering(struct ipw_tty *tty)
|
||||
{
|
||||
char *iftype = tty_type_name(tty->tty_type);
|
||||
|
||||
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
|
||||
": registering %s device ttyIPWp%d\n", iftype, tty->index);
|
||||
}
|
||||
|
||||
static void report_deregistering(struct ipw_tty *tty)
|
||||
{
|
||||
char *iftype = tty_type_name(tty->tty_type);
|
||||
|
||||
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
|
||||
": deregistering %s device ttyIPWp%d\n", iftype,
|
||||
tty->index);
|
||||
}
|
||||
|
||||
static struct ipw_tty *get_tty(int index)
|
||||
{
|
||||
/*
|
||||
|
@ -117,12 +99,12 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
|
|||
mutex_unlock(&tty->ipw_tty_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (tty->open_count == 0)
|
||||
if (tty->port.count == 0)
|
||||
tty->tx_bytes_queued = 0;
|
||||
|
||||
tty->open_count++;
|
||||
tty->port.count++;
|
||||
|
||||
tty->linux_tty = linux_tty;
|
||||
tty->port.tty = linux_tty;
|
||||
linux_tty->driver_data = tty;
|
||||
linux_tty->low_latency = 1;
|
||||
|
||||
|
@ -136,13 +118,13 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
|
|||
|
||||
static void do_ipw_close(struct ipw_tty *tty)
|
||||
{
|
||||
tty->open_count--;
|
||||
tty->port.count--;
|
||||
|
||||
if (tty->open_count == 0) {
|
||||
struct tty_struct *linux_tty = tty->linux_tty;
|
||||
if (tty->port.count == 0) {
|
||||
struct tty_struct *linux_tty = tty->port.tty;
|
||||
|
||||
if (linux_tty != NULL) {
|
||||
tty->linux_tty = NULL;
|
||||
tty->port.tty = NULL;
|
||||
linux_tty->driver_data = NULL;
|
||||
|
||||
if (tty->tty_type == TTYTYPE_MODEM)
|
||||
|
@ -159,7 +141,7 @@ static void ipw_hangup(struct tty_struct *linux_tty)
|
|||
return;
|
||||
|
||||
mutex_lock(&tty->ipw_tty_mutex);
|
||||
if (tty->open_count == 0) {
|
||||
if (tty->port.count == 0) {
|
||||
mutex_unlock(&tty->ipw_tty_mutex);
|
||||
return;
|
||||
}
|
||||
|
@ -182,13 +164,13 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
|
|||
int work = 0;
|
||||
|
||||
mutex_lock(&tty->ipw_tty_mutex);
|
||||
linux_tty = tty->linux_tty;
|
||||
linux_tty = tty->port.tty;
|
||||
if (linux_tty == NULL) {
|
||||
mutex_unlock(&tty->ipw_tty_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tty->open_count) {
|
||||
if (!tty->port.count) {
|
||||
mutex_unlock(&tty->ipw_tty_mutex);
|
||||
return;
|
||||
}
|
||||
|
@ -230,7 +212,7 @@ static int ipw_write(struct tty_struct *linux_tty,
|
|||
return -ENODEV;
|
||||
|
||||
mutex_lock(&tty->ipw_tty_mutex);
|
||||
if (!tty->open_count) {
|
||||
if (!tty->port.count) {
|
||||
mutex_unlock(&tty->ipw_tty_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -270,7 +252,7 @@ static int ipw_write_room(struct tty_struct *linux_tty)
|
|||
if (!tty)
|
||||
return -ENODEV;
|
||||
|
||||
if (!tty->open_count)
|
||||
if (!tty->port.count)
|
||||
return -EINVAL;
|
||||
|
||||
room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
|
||||
|
@ -312,7 +294,7 @@ static int ipw_chars_in_buffer(struct tty_struct *linux_tty)
|
|||
if (!tty)
|
||||
return 0;
|
||||
|
||||
if (!tty->open_count)
|
||||
if (!tty->port.count)
|
||||
return 0;
|
||||
|
||||
return tty->tx_bytes_queued;
|
||||
|
@ -393,7 +375,7 @@ static int ipw_tiocmget(struct tty_struct *linux_tty)
|
|||
if (!tty)
|
||||
return -ENODEV;
|
||||
|
||||
if (!tty->open_count)
|
||||
if (!tty->port.count)
|
||||
return -EINVAL;
|
||||
|
||||
return get_control_lines(tty);
|
||||
|
@ -409,7 +391,7 @@ ipw_tiocmset(struct tty_struct *linux_tty,
|
|||
if (!tty)
|
||||
return -ENODEV;
|
||||
|
||||
if (!tty->open_count)
|
||||
if (!tty->port.count)
|
||||
return -EINVAL;
|
||||
|
||||
return set_control_lines(tty, set, clear);
|
||||
|
@ -423,7 +405,7 @@ static int ipw_ioctl(struct tty_struct *linux_tty,
|
|||
if (!tty)
|
||||
return -ENODEV;
|
||||
|
||||
if (!tty->open_count)
|
||||
if (!tty->port.count)
|
||||
return -EINVAL;
|
||||
|
||||
/* FIXME: Exactly how is the tty object locked here .. */
|
||||
|
@ -492,6 +474,7 @@ static int add_tty(int j,
|
|||
ttys[j]->network = network;
|
||||
ttys[j]->tty_type = tty_type;
|
||||
mutex_init(&ttys[j]->ipw_tty_mutex);
|
||||
tty_port_init(&ttys[j]->port);
|
||||
|
||||
tty_register_device(ipw_tty_driver, j, NULL);
|
||||
ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
|
||||
|
@ -500,8 +483,12 @@ static int add_tty(int j,
|
|||
ipwireless_associate_network_tty(network,
|
||||
secondary_channel_idx,
|
||||
ttys[j]);
|
||||
if (get_tty(j) == ttys[j])
|
||||
report_registering(ttys[j]);
|
||||
/* check if we provide raw device (if loopback is enabled) */
|
||||
if (get_tty(j))
|
||||
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
|
||||
": registering %s device ttyIPWp%d\n",
|
||||
tty_type_name(tty_type), j);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -560,19 +547,21 @@ void ipwireless_tty_free(struct ipw_tty *tty)
|
|||
|
||||
if (ttyj) {
|
||||
mutex_lock(&ttyj->ipw_tty_mutex);
|
||||
if (get_tty(j) == ttyj)
|
||||
report_deregistering(ttyj);
|
||||
if (get_tty(j))
|
||||
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
|
||||
": deregistering %s device ttyIPWp%d\n",
|
||||
tty_type_name(ttyj->tty_type), j);
|
||||
ttyj->closing = 1;
|
||||
if (ttyj->linux_tty != NULL) {
|
||||
if (ttyj->port.tty != NULL) {
|
||||
mutex_unlock(&ttyj->ipw_tty_mutex);
|
||||
tty_hangup(ttyj->linux_tty);
|
||||
/* Wait till the tty_hangup has completed */
|
||||
flush_work_sync(&ttyj->linux_tty->hangup_work);
|
||||
tty_vhangup(ttyj->port.tty);
|
||||
/* FIXME: Exactly how is the tty object locked here
|
||||
against a parallel ioctl etc */
|
||||
/* FIXME2: hangup does not mean all processes
|
||||
* are gone */
|
||||
mutex_lock(&ttyj->ipw_tty_mutex);
|
||||
}
|
||||
while (ttyj->open_count)
|
||||
while (ttyj->port.count)
|
||||
do_ipw_close(ttyj);
|
||||
ipwireless_disassociate_network_ttys(network,
|
||||
ttyj->channel_idx);
|
||||
|
@ -661,8 +650,8 @@ ipwireless_tty_notify_control_line_change(struct ipw_tty *tty,
|
|||
*/
|
||||
if ((old_control_lines & IPW_CONTROL_LINE_DCD)
|
||||
&& !(tty->control_lines & IPW_CONTROL_LINE_DCD)
|
||||
&& tty->linux_tty) {
|
||||
tty_hangup(tty->linux_tty);
|
||||
&& tty->port.tty) {
|
||||
tty_hangup(tty->port.tty);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2326,7 +2326,7 @@ static const struct tty_operations mxser_ops = {
|
|||
.get_icount = mxser_get_icount,
|
||||
};
|
||||
|
||||
struct tty_port_operations mxser_port_ops = {
|
||||
static struct tty_port_operations mxser_port_ops = {
|
||||
.carrier_raised = mxser_carrier_raised,
|
||||
.dtr_rts = mxser_dtr_rts,
|
||||
.activate = mxser_activate,
|
||||
|
|
|
@ -1065,7 +1065,8 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
|
|||
|
||||
TRACE_L("read()");
|
||||
|
||||
tty_lock();
|
||||
/* FIXME: should use a private lock */
|
||||
tty_lock(tty);
|
||||
|
||||
pClient = findClient(pInfo, task_pid(current));
|
||||
if (pClient) {
|
||||
|
@ -1077,7 +1078,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
|
|||
goto unlock;
|
||||
}
|
||||
/* block until there is a message: */
|
||||
wait_event_interruptible_tty(pInfo->read_wait,
|
||||
wait_event_interruptible_tty(tty, pInfo->read_wait,
|
||||
(pMsg = remove_msg(pInfo, pClient)));
|
||||
}
|
||||
|
||||
|
@ -1107,7 +1108,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
|
|||
}
|
||||
ret = -EPERM;
|
||||
unlock:
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1156,7 +1157,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
|
|||
pHeader->locks = 0;
|
||||
pHeader->owner = NULL;
|
||||
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
|
||||
pClient = findClient(pInfo, task_pid(current));
|
||||
if (pClient) {
|
||||
|
@ -1175,7 +1176,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
|
|||
add_tx_queue(pInfo, pHeader);
|
||||
trigger_transmit(pInfo);
|
||||
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
|
|||
int retval;
|
||||
size_t n;
|
||||
unsigned long flags;
|
||||
bool is_eof;
|
||||
|
||||
retval = 0;
|
||||
spin_lock_irqsave(&tty->read_lock, flags);
|
||||
|
@ -1639,15 +1640,15 @@ static int copy_from_read_buf(struct tty_struct *tty,
|
|||
if (n) {
|
||||
retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
|
||||
n -= retval;
|
||||
is_eof = n == 1 &&
|
||||
tty->read_buf[tty->read_tail] == EOF_CHAR(tty);
|
||||
tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
|
||||
spin_lock_irqsave(&tty->read_lock, flags);
|
||||
tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
|
||||
tty->read_cnt -= n;
|
||||
/* Turn single EOF into zero-length read */
|
||||
if (L_EXTPROC(tty) && tty->icanon && n == 1) {
|
||||
if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
|
||||
n--;
|
||||
}
|
||||
if (L_EXTPROC(tty) && tty->icanon && is_eof && !tty->read_cnt)
|
||||
n = 0;
|
||||
spin_unlock_irqrestore(&tty->read_lock, flags);
|
||||
*b += n;
|
||||
*nr -= n;
|
||||
|
|
|
@ -26,11 +26,13 @@
|
|||
#include <linux/bitops.h>
|
||||
#include <linux/devpts_fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
|
||||
#ifdef CONFIG_UNIX98_PTYS
|
||||
static struct tty_driver *ptm_driver;
|
||||
static struct tty_driver *pts_driver;
|
||||
static DEFINE_MUTEX(devpts_mutex);
|
||||
#endif
|
||||
|
||||
static void pty_close(struct tty_struct *tty, struct file *filp)
|
||||
|
@ -45,6 +47,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
|
|||
wake_up_interruptible(&tty->read_wait);
|
||||
wake_up_interruptible(&tty->write_wait);
|
||||
tty->packet = 0;
|
||||
/* Review - krefs on tty_link ?? */
|
||||
if (!tty->link)
|
||||
return;
|
||||
tty->link->packet = 0;
|
||||
|
@ -54,12 +57,15 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
|
|||
if (tty->driver->subtype == PTY_TYPE_MASTER) {
|
||||
set_bit(TTY_OTHER_CLOSED, &tty->flags);
|
||||
#ifdef CONFIG_UNIX98_PTYS
|
||||
if (tty->driver == ptm_driver)
|
||||
if (tty->driver == ptm_driver) {
|
||||
mutex_lock(&devpts_mutex);
|
||||
devpts_pty_kill(tty->link);
|
||||
mutex_unlock(&devpts_mutex);
|
||||
}
|
||||
#endif
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
tty_vhangup(tty->link);
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -475,13 +481,17 @@ static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
|
|||
* @idx: tty index
|
||||
*
|
||||
* Look up a pty master device. Called under the tty_mutex for now.
|
||||
* This provides our locking.
|
||||
* This provides our locking for the tty pointer.
|
||||
*/
|
||||
|
||||
static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
|
||||
struct inode *pts_inode, int idx)
|
||||
{
|
||||
struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
|
||||
struct tty_struct *tty;
|
||||
|
||||
mutex_lock(&devpts_mutex);
|
||||
tty = devpts_get_tty(pts_inode, idx);
|
||||
mutex_unlock(&devpts_mutex);
|
||||
/* Master must be open before slave */
|
||||
if (!tty)
|
||||
return ERR_PTR(-EIO);
|
||||
|
@ -613,24 +623,29 @@ static int ptmx_open(struct inode *inode, struct file *filp)
|
|||
return retval;
|
||||
|
||||
/* find a device that is not in use. */
|
||||
tty_lock();
|
||||
mutex_lock(&devpts_mutex);
|
||||
index = devpts_new_index(inode);
|
||||
tty_unlock();
|
||||
if (index < 0) {
|
||||
retval = index;
|
||||
goto err_file;
|
||||
}
|
||||
|
||||
mutex_unlock(&devpts_mutex);
|
||||
|
||||
mutex_lock(&tty_mutex);
|
||||
tty_lock();
|
||||
mutex_lock(&devpts_mutex);
|
||||
tty = tty_init_dev(ptm_driver, index);
|
||||
mutex_unlock(&tty_mutex);
|
||||
|
||||
if (IS_ERR(tty)) {
|
||||
retval = PTR_ERR(tty);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* The tty returned here is locked so we can safely
|
||||
drop the mutex */
|
||||
mutex_unlock(&devpts_mutex);
|
||||
mutex_unlock(&tty_mutex);
|
||||
|
||||
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
|
||||
|
||||
tty_add_file(tty, filp);
|
||||
|
@ -643,16 +658,17 @@ static int ptmx_open(struct inode *inode, struct file *filp)
|
|||
if (retval)
|
||||
goto err_release;
|
||||
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
return 0;
|
||||
err_release:
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
tty_release(inode, filp);
|
||||
return retval;
|
||||
out:
|
||||
mutex_unlock(&tty_mutex);
|
||||
devpts_kill_index(inode, index);
|
||||
tty_unlock();
|
||||
err_file:
|
||||
mutex_unlock(&devpts_mutex);
|
||||
tty_free_file(filp);
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <asm/dbg.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/timer.h>
|
||||
|
@ -56,8 +57,6 @@
|
|||
#endif /* CONFIG_M68VZ328 */
|
||||
#endif /* CONFIG_M68EZ328 */
|
||||
|
||||
#include "68328serial.h"
|
||||
|
||||
/* Turn off usage of real serial interrupt code, to "support" Copilot */
|
||||
#ifdef CONFIG_XCOPILOT_BUGS
|
||||
#undef USE_INTS
|
||||
|
@ -65,33 +64,82 @@
|
|||
#define USE_INTS
|
||||
#endif
|
||||
|
||||
/*
|
||||
* I believe this is the optimal setting that reduces the number of interrupts.
|
||||
* At high speeds the output might become a little "bursted" (use USTCNT_TXHE
|
||||
* if that bothers you), but in most cases it will not, since we try to
|
||||
* transmit characters every time rs_interrupt is called. Thus, quite often
|
||||
* you'll see that a receive interrupt occures before the transmit one.
|
||||
* -- Vladimir Gurevich
|
||||
*/
|
||||
#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
|
||||
|
||||
/*
|
||||
* 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
|
||||
* "Old data interrupt" which occures whenever the data stay in the FIFO
|
||||
* longer than 30 bits time. This allows us to use FIFO without compromising
|
||||
* latency. '328 does not have this feature and without the real 328-based
|
||||
* board I would assume that RXRE is the safest setting.
|
||||
*
|
||||
* For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
|
||||
* interrupts. RXFE (receive queue full) causes the system to lose data
|
||||
* at least at 115200 baud
|
||||
*
|
||||
* If your board is busy doing other stuff, you might consider to use
|
||||
* RXRE (data ready intrrupt) instead.
|
||||
*
|
||||
* The other option is to make these INTR masks run-time configurable, so
|
||||
* that people can dynamically adapt them according to the current usage.
|
||||
* -- Vladimir Gurevich
|
||||
*/
|
||||
|
||||
/* (es) */
|
||||
#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
|
||||
#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
|
||||
#elif defined(CONFIG_M68328)
|
||||
#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
|
||||
#else
|
||||
#error Please, define the Rx interrupt events for your CPU
|
||||
#endif
|
||||
/* (/es) */
|
||||
|
||||
/*
|
||||
* This is our internal structure for each serial port's state.
|
||||
*/
|
||||
struct m68k_serial {
|
||||
struct tty_port tport;
|
||||
char is_cons; /* Is this our console. */
|
||||
int magic;
|
||||
int baud_base;
|
||||
int port;
|
||||
int irq;
|
||||
int type; /* UART type */
|
||||
int custom_divisor;
|
||||
int x_char; /* xon/xoff character */
|
||||
int line;
|
||||
unsigned char *xmit_buf;
|
||||
int xmit_head;
|
||||
int xmit_tail;
|
||||
int xmit_cnt;
|
||||
};
|
||||
|
||||
#define SERIAL_MAGIC 0x5301
|
||||
|
||||
/*
|
||||
* Define the number of ports supported and their irqs.
|
||||
*/
|
||||
#define NR_PORTS 1
|
||||
|
||||
static struct m68k_serial m68k_soft[NR_PORTS];
|
||||
|
||||
static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS;
|
||||
static unsigned int uart_irqs[NR_PORTS] = { UART_IRQ_NUM };
|
||||
|
||||
/* multiple ports are contiguous in memory */
|
||||
m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR;
|
||||
|
||||
struct tty_struct m68k_ttys;
|
||||
struct m68k_serial *m68k_consinfo = 0;
|
||||
|
||||
#define M68K_CLOCK (16667000) /* FIXME: 16MHz is likely wrong */
|
||||
|
||||
struct tty_driver *serial_driver;
|
||||
|
||||
/* number of characters left in xmit buffer before we ask for more */
|
||||
#define WAKEUP_CHARS 256
|
||||
|
||||
/* Debugging... DEBUG_INTR is bad to use when one of the zs
|
||||
* lines is your console ;(
|
||||
*/
|
||||
#undef SERIAL_DEBUG_INTR
|
||||
#undef SERIAL_DEBUG_OPEN
|
||||
#undef SERIAL_DEBUG_FLOW
|
||||
|
||||
#define RS_ISR_PASS_LIMIT 256
|
||||
|
||||
static void change_speed(struct m68k_serial *info);
|
||||
static void change_speed(struct m68k_serial *info, struct tty_struct *tty);
|
||||
|
||||
/*
|
||||
* Setup for console. Argument comes from the boot command line.
|
||||
|
@ -143,17 +191,6 @@ static int baud_table[] = {
|
|||
0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
|
||||
9600, 19200, 38400, 57600, 115200, 0 };
|
||||
|
||||
/* Sets or clears DTR/RTS on the requested line */
|
||||
static inline void m68k_rtsdtr(struct m68k_serial *ss, int set)
|
||||
{
|
||||
if (set) {
|
||||
/* set the RTS/CTS line */
|
||||
} else {
|
||||
/* clear it */
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Utility routines */
|
||||
static inline int get_baud(struct m68k_serial *ss)
|
||||
{
|
||||
|
@ -189,7 +226,8 @@ static void rs_stop(struct tty_struct *tty)
|
|||
|
||||
static int rs_put_char(char ch)
|
||||
{
|
||||
int flags, loops = 0;
|
||||
unsigned long flags;
|
||||
int loops = 0;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
|
@ -224,28 +262,9 @@ static void rs_start(struct tty_struct *tty)
|
|||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/* Drop into either the boot monitor or kadb upon receiving a break
|
||||
* from keyboard/console input.
|
||||
*/
|
||||
static void batten_down_hatches(void)
|
||||
static void receive_chars(struct m68k_serial *info, struct tty_struct *tty,
|
||||
unsigned short rx)
|
||||
{
|
||||
/* Drop into the debugger */
|
||||
}
|
||||
|
||||
static void status_handle(struct m68k_serial *info, unsigned short status)
|
||||
{
|
||||
/* If this is console input and this is a
|
||||
* 'break asserted' status change interrupt
|
||||
* see if we can drop into the debugger
|
||||
*/
|
||||
if((status & URX_BREAK) && info->break_abort)
|
||||
batten_down_hatches();
|
||||
return;
|
||||
}
|
||||
|
||||
static void receive_chars(struct m68k_serial *info, unsigned short rx)
|
||||
{
|
||||
struct tty_struct *tty = info->tty;
|
||||
m68328_uart *uart = &uart_addr[info->line];
|
||||
unsigned char ch, flag;
|
||||
|
||||
|
@ -259,7 +278,6 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx)
|
|||
|
||||
if(info->is_cons) {
|
||||
if(URX_BREAK & rx) { /* whee, break received */
|
||||
status_handle(info, rx);
|
||||
return;
|
||||
#ifdef CONFIG_MAGIC_SYSRQ
|
||||
} else if (ch == 0x10) { /* ^P */
|
||||
|
@ -280,16 +298,13 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx)
|
|||
|
||||
flag = TTY_NORMAL;
|
||||
|
||||
if(rx & URX_PARITY_ERROR) {
|
||||
if (rx & URX_PARITY_ERROR)
|
||||
flag = TTY_PARITY;
|
||||
status_handle(info, rx);
|
||||
} else if(rx & URX_OVRUN) {
|
||||
else if (rx & URX_OVRUN)
|
||||
flag = TTY_OVERRUN;
|
||||
status_handle(info, rx);
|
||||
} else if(rx & URX_FRAME_ERROR) {
|
||||
else if (rx & URX_FRAME_ERROR)
|
||||
flag = TTY_FRAME;
|
||||
status_handle(info, rx);
|
||||
}
|
||||
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
#ifndef CONFIG_XCOPILOT_BUGS
|
||||
} while((rx = uart->urx.w) & URX_DATA_READY);
|
||||
|
@ -301,7 +316,7 @@ clear_and_exit:
|
|||
return;
|
||||
}
|
||||
|
||||
static void transmit_chars(struct m68k_serial *info)
|
||||
static void transmit_chars(struct m68k_serial *info, struct tty_struct *tty)
|
||||
{
|
||||
m68328_uart *uart = &uart_addr[info->line];
|
||||
|
||||
|
@ -312,7 +327,7 @@ static void transmit_chars(struct m68k_serial *info)
|
|||
goto clear_and_return;
|
||||
}
|
||||
|
||||
if((info->xmit_cnt <= 0) || info->tty->stopped) {
|
||||
if ((info->xmit_cnt <= 0) || !tty || tty->stopped) {
|
||||
/* That's peculiar... TX ints off */
|
||||
uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
|
||||
goto clear_and_return;
|
||||
|
@ -340,6 +355,7 @@ clear_and_return:
|
|||
irqreturn_t rs_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct m68k_serial *info = dev_id;
|
||||
struct tty_struct *tty = tty_port_tty_get(&info->tport);
|
||||
m68328_uart *uart;
|
||||
unsigned short rx;
|
||||
unsigned short tx;
|
||||
|
@ -350,20 +366,24 @@ irqreturn_t rs_interrupt(int irq, void *dev_id)
|
|||
#ifdef USE_INTS
|
||||
tx = uart->utx.w;
|
||||
|
||||
if (rx & URX_DATA_READY) receive_chars(info, rx);
|
||||
if (tx & UTX_TX_AVAIL) transmit_chars(info);
|
||||
if (rx & URX_DATA_READY)
|
||||
receive_chars(info, tty, rx);
|
||||
if (tx & UTX_TX_AVAIL)
|
||||
transmit_chars(info, tty);
|
||||
#else
|
||||
receive_chars(info, rx);
|
||||
receive_chars(info, tty, rx);
|
||||
#endif
|
||||
tty_kref_put(tty);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int startup(struct m68k_serial * info)
|
||||
static int startup(struct m68k_serial *info, struct tty_struct *tty)
|
||||
{
|
||||
m68328_uart *uart = &uart_addr[info->line];
|
||||
unsigned long flags;
|
||||
|
||||
if (info->flags & S_INITIALIZED)
|
||||
if (info->tport.flags & ASYNC_INITIALIZED)
|
||||
return 0;
|
||||
|
||||
if (!info->xmit_buf) {
|
||||
|
@ -380,7 +400,6 @@ static int startup(struct m68k_serial * info)
|
|||
*/
|
||||
|
||||
uart->ustcnt = USTCNT_UEN;
|
||||
info->xmit_fifo_size = 1;
|
||||
uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN;
|
||||
(void)uart->urx.w;
|
||||
|
||||
|
@ -394,17 +413,17 @@ static int startup(struct m68k_serial * info)
|
|||
uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;
|
||||
#endif
|
||||
|
||||
if (info->tty)
|
||||
clear_bit(TTY_IO_ERROR, &info->tty->flags);
|
||||
if (tty)
|
||||
clear_bit(TTY_IO_ERROR, &tty->flags);
|
||||
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
|
||||
|
||||
/*
|
||||
* and set the speed of the serial port
|
||||
*/
|
||||
|
||||
change_speed(info);
|
||||
change_speed(info, tty);
|
||||
|
||||
info->flags |= S_INITIALIZED;
|
||||
info->tport.flags |= ASYNC_INITIALIZED;
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
}
|
||||
|
@ -413,13 +432,13 @@ static int startup(struct m68k_serial * info)
|
|||
* This routine will shutdown a serial port; interrupts are disabled, and
|
||||
* DTR is dropped if the hangup on close termio flag is on.
|
||||
*/
|
||||
static void shutdown(struct m68k_serial * info)
|
||||
static void shutdown(struct m68k_serial *info, struct tty_struct *tty)
|
||||
{
|
||||
m68328_uart *uart = &uart_addr[info->line];
|
||||
unsigned long flags;
|
||||
|
||||
uart->ustcnt = 0; /* All off! */
|
||||
if (!(info->flags & S_INITIALIZED))
|
||||
if (!(info->tport.flags & ASYNC_INITIALIZED))
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
@ -429,10 +448,10 @@ static void shutdown(struct m68k_serial * info)
|
|||
info->xmit_buf = 0;
|
||||
}
|
||||
|
||||
if (info->tty)
|
||||
set_bit(TTY_IO_ERROR, &info->tty->flags);
|
||||
if (tty)
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
|
||||
info->flags &= ~S_INITIALIZED;
|
||||
info->tport.flags &= ~ASYNC_INITIALIZED;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
|
@ -488,7 +507,7 @@ struct {
|
|||
* This routine is called to set the UART divisor registers to match
|
||||
* the specified baud rate for a serial port.
|
||||
*/
|
||||
static void change_speed(struct m68k_serial *info)
|
||||
static void change_speed(struct m68k_serial *info, struct tty_struct *tty)
|
||||
{
|
||||
m68328_uart *uart = &uart_addr[info->line];
|
||||
unsigned short port;
|
||||
|
@ -496,9 +515,7 @@ static void change_speed(struct m68k_serial *info)
|
|||
unsigned cflag;
|
||||
int i;
|
||||
|
||||
if (!info->tty || !info->tty->termios)
|
||||
return;
|
||||
cflag = info->tty->termios->c_cflag;
|
||||
cflag = tty->termios->c_cflag;
|
||||
if (!(port = info->port))
|
||||
return;
|
||||
|
||||
|
@ -510,7 +527,6 @@ static void change_speed(struct m68k_serial *info)
|
|||
i = (i & ~CBAUDEX) + B38400;
|
||||
}
|
||||
|
||||
info->baud = baud_table[i];
|
||||
uart->ubaud = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) |
|
||||
PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
|
||||
|
||||
|
@ -807,10 +823,10 @@ static int get_serial_info(struct m68k_serial * info,
|
|||
tmp.line = info->line;
|
||||
tmp.port = info->port;
|
||||
tmp.irq = info->irq;
|
||||
tmp.flags = info->flags;
|
||||
tmp.flags = info->tport.flags;
|
||||
tmp.baud_base = info->baud_base;
|
||||
tmp.close_delay = info->close_delay;
|
||||
tmp.closing_wait = info->closing_wait;
|
||||
tmp.close_delay = info->tport.close_delay;
|
||||
tmp.closing_wait = info->tport.closing_wait;
|
||||
tmp.custom_divisor = info->custom_divisor;
|
||||
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
|
||||
return -EFAULT;
|
||||
|
@ -818,9 +834,10 @@ static int get_serial_info(struct m68k_serial * info,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int set_serial_info(struct m68k_serial * info,
|
||||
static int set_serial_info(struct m68k_serial *info, struct tty_struct *tty,
|
||||
struct serial_struct * new_info)
|
||||
{
|
||||
struct tty_port *port = &info->tport;
|
||||
struct serial_struct new_serial;
|
||||
struct m68k_serial old_info;
|
||||
int retval = 0;
|
||||
|
@ -834,17 +851,17 @@ static int set_serial_info(struct m68k_serial * info,
|
|||
if (!capable(CAP_SYS_ADMIN)) {
|
||||
if ((new_serial.baud_base != info->baud_base) ||
|
||||
(new_serial.type != info->type) ||
|
||||
(new_serial.close_delay != info->close_delay) ||
|
||||
((new_serial.flags & ~S_USR_MASK) !=
|
||||
(info->flags & ~S_USR_MASK)))
|
||||
(new_serial.close_delay != port->close_delay) ||
|
||||
((new_serial.flags & ~ASYNC_USR_MASK) !=
|
||||
(port->flags & ~ASYNC_USR_MASK)))
|
||||
return -EPERM;
|
||||
info->flags = ((info->flags & ~S_USR_MASK) |
|
||||
(new_serial.flags & S_USR_MASK));
|
||||
port->flags = ((port->flags & ~ASYNC_USR_MASK) |
|
||||
(new_serial.flags & ASYNC_USR_MASK));
|
||||
info->custom_divisor = new_serial.custom_divisor;
|
||||
goto check_and_exit;
|
||||
}
|
||||
|
||||
if (info->count > 1)
|
||||
if (port->count > 1)
|
||||
return -EBUSY;
|
||||
|
||||
/*
|
||||
|
@ -853,14 +870,14 @@ static int set_serial_info(struct m68k_serial * info,
|
|||
*/
|
||||
|
||||
info->baud_base = new_serial.baud_base;
|
||||
info->flags = ((info->flags & ~S_FLAGS) |
|
||||
(new_serial.flags & S_FLAGS));
|
||||
port->flags = ((port->flags & ~ASYNC_FLAGS) |
|
||||
(new_serial.flags & ASYNC_FLAGS));
|
||||
info->type = new_serial.type;
|
||||
info->close_delay = new_serial.close_delay;
|
||||
info->closing_wait = new_serial.closing_wait;
|
||||
port->close_delay = new_serial.close_delay;
|
||||
port->closing_wait = new_serial.closing_wait;
|
||||
|
||||
check_and_exit:
|
||||
retval = startup(info);
|
||||
retval = startup(info, tty);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -946,7 +963,7 @@ static int rs_ioctl(struct tty_struct *tty,
|
|||
return get_serial_info(info,
|
||||
(struct serial_struct *) arg);
|
||||
case TIOCSSERIAL:
|
||||
return set_serial_info(info,
|
||||
return set_serial_info(info, tty,
|
||||
(struct serial_struct *) arg);
|
||||
case TIOCSERGETLSR: /* Get line status register */
|
||||
return get_lsr_info(info, (unsigned int *) arg);
|
||||
|
@ -965,7 +982,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
|||
{
|
||||
struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
|
||||
|
||||
change_speed(info);
|
||||
change_speed(info, tty);
|
||||
|
||||
if ((old_termios->c_cflag & CRTSCTS) &&
|
||||
!(tty->termios->c_cflag & CRTSCTS)) {
|
||||
|
@ -988,6 +1005,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
|||
static void rs_close(struct tty_struct *tty, struct file * filp)
|
||||
{
|
||||
struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
|
||||
struct tty_port *port = &info->tport;
|
||||
m68328_uart *uart = &uart_addr[info->line];
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -1001,7 +1019,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
|
|||
return;
|
||||
}
|
||||
|
||||
if ((tty->count == 1) && (info->count != 1)) {
|
||||
if ((tty->count == 1) && (port->count != 1)) {
|
||||
/*
|
||||
* Uh, oh. tty->count is 1, which means that the tty
|
||||
* structure will be freed. Info->count should always
|
||||
|
@ -1010,26 +1028,26 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
|
|||
* serial port won't be shutdown.
|
||||
*/
|
||||
printk("rs_close: bad serial port count; tty->count is 1, "
|
||||
"info->count is %d\n", info->count);
|
||||
info->count = 1;
|
||||
"port->count is %d\n", port->count);
|
||||
port->count = 1;
|
||||
}
|
||||
if (--info->count < 0) {
|
||||
if (--port->count < 0) {
|
||||
printk("rs_close: bad serial port count for ttyS%d: %d\n",
|
||||
info->line, info->count);
|
||||
info->count = 0;
|
||||
info->line, port->count);
|
||||
port->count = 0;
|
||||
}
|
||||
if (info->count) {
|
||||
if (port->count) {
|
||||
local_irq_restore(flags);
|
||||
return;
|
||||
}
|
||||
info->flags |= S_CLOSING;
|
||||
port->flags |= ASYNC_CLOSING;
|
||||
/*
|
||||
* Now we wait for the transmit buffer to clear; and we notify
|
||||
* the line discipline to only process XON/XOFF characters.
|
||||
*/
|
||||
tty->closing = 1;
|
||||
if (info->closing_wait != S_CLOSING_WAIT_NONE)
|
||||
tty_wait_until_sent(tty, info->closing_wait);
|
||||
if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
|
||||
tty_wait_until_sent(tty, port->closing_wait);
|
||||
/*
|
||||
* At this point we stop accepting input. To do this, we
|
||||
* disable the receive line status interrupts, and tell the
|
||||
|
@ -1040,13 +1058,12 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
|
|||
uart->ustcnt &= ~USTCNT_RXEN;
|
||||
uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK);
|
||||
|
||||
shutdown(info);
|
||||
shutdown(info, tty);
|
||||
rs_flush_buffer(tty);
|
||||
|
||||
tty_ldisc_flush(tty);
|
||||
tty->closing = 0;
|
||||
info->event = 0;
|
||||
info->tty = NULL;
|
||||
tty_port_tty_set(&info->tport, NULL);
|
||||
#warning "This is not and has never been valid so fix it"
|
||||
#if 0
|
||||
if (tty->ldisc.num != ldiscs[N_TTY].num) {
|
||||
|
@ -1058,14 +1075,13 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
|
|||
(tty->ldisc.open)(tty);
|
||||
}
|
||||
#endif
|
||||
if (info->blocked_open) {
|
||||
if (info->close_delay) {
|
||||
msleep_interruptible(jiffies_to_msecs(info->close_delay));
|
||||
}
|
||||
wake_up_interruptible(&info->open_wait);
|
||||
if (port->blocked_open) {
|
||||
if (port->close_delay)
|
||||
msleep_interruptible(jiffies_to_msecs(port->close_delay));
|
||||
wake_up_interruptible(&port->open_wait);
|
||||
}
|
||||
info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING);
|
||||
wake_up_interruptible(&info->close_wait);
|
||||
port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
|
||||
wake_up_interruptible(&port->close_wait);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
|
@ -1080,106 +1096,13 @@ void rs_hangup(struct tty_struct *tty)
|
|||
return;
|
||||
|
||||
rs_flush_buffer(tty);
|
||||
shutdown(info);
|
||||
info->event = 0;
|
||||
info->count = 0;
|
||||
info->flags &= ~S_NORMAL_ACTIVE;
|
||||
info->tty = NULL;
|
||||
wake_up_interruptible(&info->open_wait);
|
||||
shutdown(info, tty);
|
||||
info->tport.count = 0;
|
||||
info->tport.flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
tty_port_tty_set(&info->tport, NULL);
|
||||
wake_up_interruptible(&info->tport.open_wait);
|
||||
}
|
||||
|
||||
/*
|
||||
* ------------------------------------------------------------
|
||||
* rs_open() and friends
|
||||
* ------------------------------------------------------------
|
||||
*/
|
||||
static int block_til_ready(struct tty_struct *tty, struct file * filp,
|
||||
struct m68k_serial *info)
|
||||
{
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
int retval;
|
||||
int do_clocal = 0;
|
||||
|
||||
/*
|
||||
* If the device is in the middle of being closed, then block
|
||||
* until it's done, and then try again.
|
||||
*/
|
||||
if (info->flags & S_CLOSING) {
|
||||
interruptible_sleep_on(&info->close_wait);
|
||||
#ifdef SERIAL_DO_RESTART
|
||||
if (info->flags & S_HUP_NOTIFY)
|
||||
return -EAGAIN;
|
||||
else
|
||||
return -ERESTARTSYS;
|
||||
#else
|
||||
return -EAGAIN;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* If non-blocking mode is set, or the port is not enabled,
|
||||
* then make the check up front and then exit.
|
||||
*/
|
||||
if ((filp->f_flags & O_NONBLOCK) ||
|
||||
(tty->flags & (1 << TTY_IO_ERROR))) {
|
||||
info->flags |= S_NORMAL_ACTIVE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tty->termios->c_cflag & CLOCAL)
|
||||
do_clocal = 1;
|
||||
|
||||
/*
|
||||
* Block waiting for the carrier detect and the line to become
|
||||
* free (i.e., not in use by the callout). While we are in
|
||||
* this loop, info->count is dropped by one, so that
|
||||
* rs_close() knows when to free things. We restore it upon
|
||||
* exit, either normal or abnormal.
|
||||
*/
|
||||
retval = 0;
|
||||
add_wait_queue(&info->open_wait, &wait);
|
||||
|
||||
info->count--;
|
||||
info->blocked_open++;
|
||||
while (1) {
|
||||
local_irq_disable();
|
||||
m68k_rtsdtr(info, 1);
|
||||
local_irq_enable();
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
if (tty_hung_up_p(filp) ||
|
||||
!(info->flags & S_INITIALIZED)) {
|
||||
#ifdef SERIAL_DO_RESTART
|
||||
if (info->flags & S_HUP_NOTIFY)
|
||||
retval = -EAGAIN;
|
||||
else
|
||||
retval = -ERESTARTSYS;
|
||||
#else
|
||||
retval = -EAGAIN;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
if (!(info->flags & S_CLOSING) && do_clocal)
|
||||
break;
|
||||
if (signal_pending(current)) {
|
||||
retval = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
tty_unlock();
|
||||
schedule();
|
||||
tty_lock();
|
||||
}
|
||||
current->state = TASK_RUNNING;
|
||||
remove_wait_queue(&info->open_wait, &wait);
|
||||
if (!tty_hung_up_p(filp))
|
||||
info->count++;
|
||||
info->blocked_open--;
|
||||
|
||||
if (retval)
|
||||
return retval;
|
||||
info->flags |= S_NORMAL_ACTIVE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is called whenever a serial port is opened. It
|
||||
* enables interrupts for a serial port, linking in its S structure into
|
||||
|
@ -1196,18 +1119,18 @@ int rs_open(struct tty_struct *tty, struct file * filp)
|
|||
if (serial_paranoia_check(info, tty->name, "rs_open"))
|
||||
return -ENODEV;
|
||||
|
||||
info->count++;
|
||||
info->tport.count++;
|
||||
tty->driver_data = info;
|
||||
info->tty = tty;
|
||||
tty_port_tty_set(&info->tport, tty);
|
||||
|
||||
/*
|
||||
* Start up serial port
|
||||
*/
|
||||
retval = startup(info);
|
||||
retval = startup(info, tty);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return block_til_ready(tty, filp, info);
|
||||
return tty_port_block_til_ready(&info->tport, tty, filp);
|
||||
}
|
||||
|
||||
/* Finally, routines used to initialize the serial driver. */
|
||||
|
@ -1235,11 +1158,15 @@ static const struct tty_operations rs_ops = {
|
|||
.set_ldisc = rs_set_ldisc,
|
||||
};
|
||||
|
||||
static const struct tty_port_operations rs_port_ops = {
|
||||
};
|
||||
|
||||
/* rs_init inits the driver */
|
||||
static int __init
|
||||
rs68328_init(void)
|
||||
{
|
||||
int flags, i;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
struct m68k_serial *info;
|
||||
|
||||
serial_driver = alloc_tty_driver(NR_PORTS);
|
||||
|
@ -1273,19 +1200,13 @@ rs68328_init(void)
|
|||
for(i=0;i<NR_PORTS;i++) {
|
||||
|
||||
info = &m68k_soft[i];
|
||||
tty_port_init(&info->tport);
|
||||
info->tport.ops = &rs_port_ops;
|
||||
info->magic = SERIAL_MAGIC;
|
||||
info->port = (int) &uart_addr[i];
|
||||
info->tty = NULL;
|
||||
info->irq = uart_irqs[i];
|
||||
info->custom_divisor = 16;
|
||||
info->close_delay = 50;
|
||||
info->closing_wait = 3000;
|
||||
info->x_char = 0;
|
||||
info->event = 0;
|
||||
info->count = 0;
|
||||
info->blocked_open = 0;
|
||||
init_waitqueue_head(&info->open_wait);
|
||||
init_waitqueue_head(&info->close_wait);
|
||||
info->line = i;
|
||||
info->is_cons = 1; /* Means shortcuts work */
|
||||
|
||||
|
|
|
@ -1,186 +0,0 @@
|
|||
/* 68328serial.h: Definitions for the mc68328 serial driver.
|
||||
*
|
||||
* Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu>
|
||||
* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
|
||||
* Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org>
|
||||
* Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com>
|
||||
*
|
||||
* VZ Support/Fixes Evan Stawnyczy <e@lineo.ca>
|
||||
*/
|
||||
|
||||
#ifndef _MC683XX_SERIAL_H
|
||||
#define _MC683XX_SERIAL_H
|
||||
|
||||
|
||||
struct serial_struct {
|
||||
int type;
|
||||
int line;
|
||||
int port;
|
||||
int irq;
|
||||
int flags;
|
||||
int xmit_fifo_size;
|
||||
int custom_divisor;
|
||||
int baud_base;
|
||||
unsigned short close_delay;
|
||||
char reserved_char[2];
|
||||
int hub6; /* FIXME: We don't have AT&T Hub6 boards! */
|
||||
unsigned short closing_wait; /* time to wait before closing */
|
||||
unsigned short closing_wait2; /* no longer used... */
|
||||
int reserved[4];
|
||||
};
|
||||
|
||||
/*
|
||||
* For the close wait times, 0 means wait forever for serial port to
|
||||
* flush its output. 65535 means don't wait at all.
|
||||
*/
|
||||
#define S_CLOSING_WAIT_INF 0
|
||||
#define S_CLOSING_WAIT_NONE 65535
|
||||
|
||||
/*
|
||||
* Definitions for S_struct (and serial_struct) flags field
|
||||
*/
|
||||
#define S_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
|
||||
on the callout port */
|
||||
#define S_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
|
||||
#define S_SAK 0x0004 /* Secure Attention Key (Orange book) */
|
||||
#define S_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
|
||||
|
||||
#define S_SPD_MASK 0x0030
|
||||
#define S_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
|
||||
|
||||
#define S_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
|
||||
#define S_SPD_CUST 0x0030 /* Use user-specified divisor */
|
||||
|
||||
#define S_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
|
||||
#define S_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
|
||||
#define S_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
|
||||
#define S_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
|
||||
#define S_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
|
||||
|
||||
#define S_FLAGS 0x0FFF /* Possible legal S flags */
|
||||
#define S_USR_MASK 0x0430 /* Legal flags that non-privileged
|
||||
* users can set or reset */
|
||||
|
||||
/* Internal flags used only by kernel/chr_drv/serial.c */
|
||||
#define S_INITIALIZED 0x80000000 /* Serial port was initialized */
|
||||
#define S_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
|
||||
#define S_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
|
||||
#define S_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
|
||||
#define S_CLOSING 0x08000000 /* Serial port is closing */
|
||||
#define S_CTS_FLOW 0x04000000 /* Do CTS flow control */
|
||||
#define S_CHECK_CD 0x02000000 /* i.e., CLOCAL */
|
||||
|
||||
/* Software state per channel */
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/*
|
||||
* I believe this is the optimal setting that reduces the number of interrupts.
|
||||
* At high speeds the output might become a little "bursted" (use USTCNT_TXHE
|
||||
* if that bothers you), but in most cases it will not, since we try to
|
||||
* transmit characters every time rs_interrupt is called. Thus, quite often
|
||||
* you'll see that a receive interrupt occures before the transmit one.
|
||||
* -- Vladimir Gurevich
|
||||
*/
|
||||
#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
|
||||
|
||||
/*
|
||||
* 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
|
||||
* "Old data interrupt" which occures whenever the data stay in the FIFO
|
||||
* longer than 30 bits time. This allows us to use FIFO without compromising
|
||||
* latency. '328 does not have this feature and without the real 328-based
|
||||
* board I would assume that RXRE is the safest setting.
|
||||
*
|
||||
* For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
|
||||
* interrupts. RXFE (receive queue full) causes the system to lose data
|
||||
* at least at 115200 baud
|
||||
*
|
||||
* If your board is busy doing other stuff, you might consider to use
|
||||
* RXRE (data ready intrrupt) instead.
|
||||
*
|
||||
* The other option is to make these INTR masks run-time configurable, so
|
||||
* that people can dynamically adapt them according to the current usage.
|
||||
* -- Vladimir Gurevich
|
||||
*/
|
||||
|
||||
/* (es) */
|
||||
#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
|
||||
#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
|
||||
#elif defined(CONFIG_M68328)
|
||||
#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
|
||||
#else
|
||||
#error Please, define the Rx interrupt events for your CPU
|
||||
#endif
|
||||
/* (/es) */
|
||||
|
||||
/*
|
||||
* This is our internal structure for each serial port's state.
|
||||
*
|
||||
* Many fields are paralleled by the structure used by the serial_struct
|
||||
* structure.
|
||||
*
|
||||
* For definitions of the flags field, see tty.h
|
||||
*/
|
||||
|
||||
struct m68k_serial {
|
||||
char soft_carrier; /* Use soft carrier on this channel */
|
||||
char break_abort; /* Is serial console in, so process brk/abrt */
|
||||
char is_cons; /* Is this our console. */
|
||||
|
||||
/* We need to know the current clock divisor
|
||||
* to read the bps rate the chip has currently
|
||||
* loaded.
|
||||
*/
|
||||
unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */
|
||||
int baud;
|
||||
int magic;
|
||||
int baud_base;
|
||||
int port;
|
||||
int irq;
|
||||
int flags; /* defined in tty.h */
|
||||
int type; /* UART type */
|
||||
struct tty_struct *tty;
|
||||
int read_status_mask;
|
||||
int ignore_status_mask;
|
||||
int timeout;
|
||||
int xmit_fifo_size;
|
||||
int custom_divisor;
|
||||
int x_char; /* xon/xoff character */
|
||||
int close_delay;
|
||||
unsigned short closing_wait;
|
||||
unsigned short closing_wait2;
|
||||
unsigned long event;
|
||||
unsigned long last_active;
|
||||
int line;
|
||||
int count; /* # of fd on device */
|
||||
int blocked_open; /* # of blocked opens */
|
||||
unsigned char *xmit_buf;
|
||||
int xmit_head;
|
||||
int xmit_tail;
|
||||
int xmit_cnt;
|
||||
wait_queue_head_t open_wait;
|
||||
wait_queue_head_t close_wait;
|
||||
};
|
||||
|
||||
|
||||
#define SERIAL_MAGIC 0x5301
|
||||
|
||||
/*
|
||||
* The size of the serial xmit buffer is 1 page, or 4096 bytes
|
||||
*/
|
||||
#define SERIAL_XMIT_SIZE 4096
|
||||
|
||||
/*
|
||||
* Events are used to schedule things to happen at timer-interrupt
|
||||
* time, instead of at rs interrupt time.
|
||||
*/
|
||||
#define RS_EVENT_WRITE_WAKEUP 0
|
||||
|
||||
/*
|
||||
* Define the number of ports supported and their irqs.
|
||||
*/
|
||||
#define NR_PORTS 1
|
||||
#define UART_IRQ_DEFNS {UART_IRQ_NUM}
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* !(_MC683XX_SERIAL_H) */
|
|
@ -284,7 +284,20 @@ static const struct serial8250_config uart_config[] = {
|
|||
},
|
||||
};
|
||||
|
||||
#if defined(CONFIG_MIPS_ALCHEMY)
|
||||
/* Uart divisor latch read */
|
||||
static int default_serial_dl_read(struct uart_8250_port *up)
|
||||
{
|
||||
return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8;
|
||||
}
|
||||
|
||||
/* Uart divisor latch write */
|
||||
static void default_serial_dl_write(struct uart_8250_port *up, int value)
|
||||
{
|
||||
serial_out(up, UART_DLL, value & 0xff);
|
||||
serial_out(up, UART_DLM, value >> 8 & 0xff);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MIPS_ALCHEMY
|
||||
|
||||
/* Au1x00 UART hardware has a weird register layout */
|
||||
static const u8 au_io_in_map[] = {
|
||||
|
@ -305,22 +318,32 @@ static const u8 au_io_out_map[] = {
|
|||
[UART_MCR] = 6,
|
||||
};
|
||||
|
||||
/* sane hardware needs no mapping */
|
||||
static inline int map_8250_in_reg(struct uart_port *p, int offset)
|
||||
static unsigned int au_serial_in(struct uart_port *p, int offset)
|
||||
{
|
||||
if (p->iotype != UPIO_AU)
|
||||
return offset;
|
||||
return au_io_in_map[offset];
|
||||
offset = au_io_in_map[offset] << p->regshift;
|
||||
return __raw_readl(p->membase + offset);
|
||||
}
|
||||
|
||||
static inline int map_8250_out_reg(struct uart_port *p, int offset)
|
||||
static void au_serial_out(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
if (p->iotype != UPIO_AU)
|
||||
return offset;
|
||||
return au_io_out_map[offset];
|
||||
offset = au_io_out_map[offset] << p->regshift;
|
||||
__raw_writel(value, p->membase + offset);
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_SERIAL_8250_RM9K)
|
||||
/* Au1x00 haven't got a standard divisor latch */
|
||||
static int au_serial_dl_read(struct uart_8250_port *up)
|
||||
{
|
||||
return __raw_readl(up->port.membase + 0x28);
|
||||
}
|
||||
|
||||
static void au_serial_dl_write(struct uart_8250_port *up, int value)
|
||||
{
|
||||
__raw_writel(value, up->port.membase + 0x28);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_RM9K
|
||||
|
||||
static const u8
|
||||
regmap_in[8] = {
|
||||
|
@ -344,87 +367,79 @@ static const u8
|
|||
[UART_SCR] = 0x2c
|
||||
};
|
||||
|
||||
static inline int map_8250_in_reg(struct uart_port *p, int offset)
|
||||
static unsigned int rm9k_serial_in(struct uart_port *p, int offset)
|
||||
{
|
||||
if (p->iotype != UPIO_RM9000)
|
||||
return offset;
|
||||
return regmap_in[offset];
|
||||
offset = regmap_in[offset] << p->regshift;
|
||||
return readl(p->membase + offset);
|
||||
}
|
||||
|
||||
static inline int map_8250_out_reg(struct uart_port *p, int offset)
|
||||
static void rm9k_serial_out(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
if (p->iotype != UPIO_RM9000)
|
||||
return offset;
|
||||
return regmap_out[offset];
|
||||
offset = regmap_out[offset] << p->regshift;
|
||||
writel(value, p->membase + offset);
|
||||
}
|
||||
|
||||
#else
|
||||
static int rm9k_serial_dl_read(struct uart_8250_port *up)
|
||||
{
|
||||
return ((__raw_readl(up->port.membase + 0x10) << 8) |
|
||||
(__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff;
|
||||
}
|
||||
|
||||
/* sane hardware needs no mapping */
|
||||
#define map_8250_in_reg(up, offset) (offset)
|
||||
#define map_8250_out_reg(up, offset) (offset)
|
||||
static void rm9k_serial_dl_write(struct uart_8250_port *up, int value)
|
||||
{
|
||||
__raw_writel(value, up->port.membase + 0x08);
|
||||
__raw_writel(value >> 8, up->port.membase + 0x10);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static unsigned int hub6_serial_in(struct uart_port *p, int offset)
|
||||
{
|
||||
offset = map_8250_in_reg(p, offset) << p->regshift;
|
||||
offset = offset << p->regshift;
|
||||
outb(p->hub6 - 1 + offset, p->iobase);
|
||||
return inb(p->iobase + 1);
|
||||
}
|
||||
|
||||
static void hub6_serial_out(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
offset = map_8250_out_reg(p, offset) << p->regshift;
|
||||
offset = offset << p->regshift;
|
||||
outb(p->hub6 - 1 + offset, p->iobase);
|
||||
outb(value, p->iobase + 1);
|
||||
}
|
||||
|
||||
static unsigned int mem_serial_in(struct uart_port *p, int offset)
|
||||
{
|
||||
offset = map_8250_in_reg(p, offset) << p->regshift;
|
||||
offset = offset << p->regshift;
|
||||
return readb(p->membase + offset);
|
||||
}
|
||||
|
||||
static void mem_serial_out(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
offset = map_8250_out_reg(p, offset) << p->regshift;
|
||||
offset = offset << p->regshift;
|
||||
writeb(value, p->membase + offset);
|
||||
}
|
||||
|
||||
static void mem32_serial_out(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
offset = map_8250_out_reg(p, offset) << p->regshift;
|
||||
offset = offset << p->regshift;
|
||||
writel(value, p->membase + offset);
|
||||
}
|
||||
|
||||
static unsigned int mem32_serial_in(struct uart_port *p, int offset)
|
||||
{
|
||||
offset = map_8250_in_reg(p, offset) << p->regshift;
|
||||
offset = offset << p->regshift;
|
||||
return readl(p->membase + offset);
|
||||
}
|
||||
|
||||
static unsigned int au_serial_in(struct uart_port *p, int offset)
|
||||
{
|
||||
offset = map_8250_in_reg(p, offset) << p->regshift;
|
||||
return __raw_readl(p->membase + offset);
|
||||
}
|
||||
|
||||
static void au_serial_out(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
offset = map_8250_out_reg(p, offset) << p->regshift;
|
||||
__raw_writel(value, p->membase + offset);
|
||||
}
|
||||
|
||||
static unsigned int io_serial_in(struct uart_port *p, int offset)
|
||||
{
|
||||
offset = map_8250_in_reg(p, offset) << p->regshift;
|
||||
offset = offset << p->regshift;
|
||||
return inb(p->iobase + offset);
|
||||
}
|
||||
|
||||
static void io_serial_out(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
offset = map_8250_out_reg(p, offset) << p->regshift;
|
||||
offset = offset << p->regshift;
|
||||
outb(value, p->iobase + offset);
|
||||
}
|
||||
|
||||
|
@ -434,6 +449,10 @@ static void set_io_from_upio(struct uart_port *p)
|
|||
{
|
||||
struct uart_8250_port *up =
|
||||
container_of(p, struct uart_8250_port, port);
|
||||
|
||||
up->dl_read = default_serial_dl_read;
|
||||
up->dl_write = default_serial_dl_write;
|
||||
|
||||
switch (p->iotype) {
|
||||
case UPIO_HUB6:
|
||||
p->serial_in = hub6_serial_in;
|
||||
|
@ -445,16 +464,28 @@ static void set_io_from_upio(struct uart_port *p)
|
|||
p->serial_out = mem_serial_out;
|
||||
break;
|
||||
|
||||
case UPIO_RM9000:
|
||||
case UPIO_MEM32:
|
||||
p->serial_in = mem32_serial_in;
|
||||
p->serial_out = mem32_serial_out;
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_RM9K
|
||||
case UPIO_RM9000:
|
||||
p->serial_in = rm9k_serial_in;
|
||||
p->serial_out = rm9k_serial_out;
|
||||
up->dl_read = rm9k_serial_dl_read;
|
||||
up->dl_write = rm9k_serial_dl_write;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MIPS_ALCHEMY
|
||||
case UPIO_AU:
|
||||
p->serial_in = au_serial_in;
|
||||
p->serial_out = au_serial_out;
|
||||
up->dl_read = au_serial_dl_read;
|
||||
up->dl_write = au_serial_dl_write;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
p->serial_in = io_serial_in;
|
||||
|
@ -481,59 +512,6 @@ serial_port_out_sync(struct uart_port *p, int offset, int value)
|
|||
}
|
||||
}
|
||||
|
||||
/* Uart divisor latch read */
|
||||
static inline int _serial_dl_read(struct uart_8250_port *up)
|
||||
{
|
||||
return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8;
|
||||
}
|
||||
|
||||
/* Uart divisor latch write */
|
||||
static inline void _serial_dl_write(struct uart_8250_port *up, int value)
|
||||
{
|
||||
serial_out(up, UART_DLL, value & 0xff);
|
||||
serial_out(up, UART_DLM, value >> 8 & 0xff);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MIPS_ALCHEMY)
|
||||
/* Au1x00 haven't got a standard divisor latch */
|
||||
static int serial_dl_read(struct uart_8250_port *up)
|
||||
{
|
||||
if (up->port.iotype == UPIO_AU)
|
||||
return __raw_readl(up->port.membase + 0x28);
|
||||
else
|
||||
return _serial_dl_read(up);
|
||||
}
|
||||
|
||||
static void serial_dl_write(struct uart_8250_port *up, int value)
|
||||
{
|
||||
if (up->port.iotype == UPIO_AU)
|
||||
__raw_writel(value, up->port.membase + 0x28);
|
||||
else
|
||||
_serial_dl_write(up, value);
|
||||
}
|
||||
#elif defined(CONFIG_SERIAL_8250_RM9K)
|
||||
static int serial_dl_read(struct uart_8250_port *up)
|
||||
{
|
||||
return (up->port.iotype == UPIO_RM9000) ?
|
||||
(((__raw_readl(up->port.membase + 0x10) << 8) |
|
||||
(__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) :
|
||||
_serial_dl_read(up);
|
||||
}
|
||||
|
||||
static void serial_dl_write(struct uart_8250_port *up, int value)
|
||||
{
|
||||
if (up->port.iotype == UPIO_RM9000) {
|
||||
__raw_writel(value, up->port.membase + 0x08);
|
||||
__raw_writel(value >> 8, up->port.membase + 0x10);
|
||||
} else {
|
||||
_serial_dl_write(up, value);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define serial_dl_read(up) _serial_dl_read(up)
|
||||
#define serial_dl_write(up, value) _serial_dl_write(up, value)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* For the 16C950
|
||||
*/
|
||||
|
@ -568,6 +546,16 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
|
|||
}
|
||||
}
|
||||
|
||||
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
|
||||
{
|
||||
unsigned char fcr;
|
||||
|
||||
serial8250_clear_fifos(p);
|
||||
fcr = uart_config[p->port.type].fcr;
|
||||
serial_out(p, UART_FCR, fcr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
|
||||
|
||||
/*
|
||||
* IER sleep support. UARTs which have EFRs need the "extended
|
||||
* capability" bit enabled. Note that on XR16C850s, we need to
|
||||
|
@ -1331,27 +1319,6 @@ static void serial8250_enable_ms(struct uart_port *port)
|
|||
serial_port_out(port, UART_IER, up->ier);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the Tegra rx fifo after a break
|
||||
*
|
||||
* FIXME: This needs to become a port specific callback once we have a
|
||||
* framework for this
|
||||
*/
|
||||
static void clear_rx_fifo(struct uart_8250_port *up)
|
||||
{
|
||||
unsigned int status, tmout = 10000;
|
||||
do {
|
||||
status = serial_in(up, UART_LSR);
|
||||
if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
|
||||
status = serial_in(up, UART_RX);
|
||||
else
|
||||
break;
|
||||
if (--tmout == 0)
|
||||
break;
|
||||
udelay(1);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* serial8250_rx_chars: processes according to the passed in LSR
|
||||
* value, and returns the remaining LSR bits not handled
|
||||
|
@ -1386,19 +1353,9 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
|
|||
up->lsr_saved_flags = 0;
|
||||
|
||||
if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
|
||||
/*
|
||||
* For statistics only
|
||||
*/
|
||||
if (lsr & UART_LSR_BI) {
|
||||
lsr &= ~(UART_LSR_FE | UART_LSR_PE);
|
||||
port->icount.brk++;
|
||||
/*
|
||||
* If tegra port then clear the rx fifo to
|
||||
* accept another break/character.
|
||||
*/
|
||||
if (port->type == PORT_TEGRA)
|
||||
clear_rx_fifo(up);
|
||||
|
||||
/*
|
||||
* We do the SysRQ and SAK checking
|
||||
* here because otherwise the break
|
||||
|
@ -2280,10 +2237,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
quot++;
|
||||
|
||||
if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {
|
||||
if (baud < 2400)
|
||||
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
|
||||
else
|
||||
fcr = uart_config[port->type].fcr;
|
||||
fcr = uart_config[port->type].fcr;
|
||||
if (baud < 2400) {
|
||||
fcr &= ~UART_FCR_TRIGGER_MASK;
|
||||
fcr |= UART_FCR_TRIGGER_1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3037,6 +2995,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
|
|||
port.serial_in = p->serial_in;
|
||||
port.serial_out = p->serial_out;
|
||||
port.handle_irq = p->handle_irq;
|
||||
port.handle_break = p->handle_break;
|
||||
port.set_termios = p->set_termios;
|
||||
port.pm = p->pm;
|
||||
port.dev = &dev->dev;
|
||||
|
@ -3152,6 +3111,84 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* serial8250_register_8250_port - register a serial port
|
||||
* @port: serial port template
|
||||
*
|
||||
* Configure the serial port specified by the request. If the
|
||||
* port exists and is in use, it is hung up and unregistered
|
||||
* first.
|
||||
*
|
||||
* The port is then probed and if necessary the IRQ is autodetected
|
||||
* If this fails an error is returned.
|
||||
*
|
||||
* On success the port is ready to use and the line number is returned.
|
||||
*/
|
||||
int serial8250_register_8250_port(struct uart_8250_port *up)
|
||||
{
|
||||
struct uart_8250_port *uart;
|
||||
int ret = -ENOSPC;
|
||||
|
||||
if (up->port.uartclk == 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&serial_mutex);
|
||||
|
||||
uart = serial8250_find_match_or_unused(&up->port);
|
||||
if (uart) {
|
||||
uart_remove_one_port(&serial8250_reg, &uart->port);
|
||||
|
||||
uart->port.iobase = up->port.iobase;
|
||||
uart->port.membase = up->port.membase;
|
||||
uart->port.irq = up->port.irq;
|
||||
uart->port.irqflags = up->port.irqflags;
|
||||
uart->port.uartclk = up->port.uartclk;
|
||||
uart->port.fifosize = up->port.fifosize;
|
||||
uart->port.regshift = up->port.regshift;
|
||||
uart->port.iotype = up->port.iotype;
|
||||
uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
|
||||
uart->port.mapbase = up->port.mapbase;
|
||||
uart->port.private_data = up->port.private_data;
|
||||
if (up->port.dev)
|
||||
uart->port.dev = up->port.dev;
|
||||
|
||||
if (up->port.flags & UPF_FIXED_TYPE)
|
||||
serial8250_init_fixed_type_port(uart, up->port.type);
|
||||
|
||||
set_io_from_upio(&uart->port);
|
||||
/* Possibly override default I/O functions. */
|
||||
if (up->port.serial_in)
|
||||
uart->port.serial_in = up->port.serial_in;
|
||||
if (up->port.serial_out)
|
||||
uart->port.serial_out = up->port.serial_out;
|
||||
if (up->port.handle_irq)
|
||||
uart->port.handle_irq = up->port.handle_irq;
|
||||
/* Possibly override set_termios call */
|
||||
if (up->port.set_termios)
|
||||
uart->port.set_termios = up->port.set_termios;
|
||||
if (up->port.pm)
|
||||
uart->port.pm = up->port.pm;
|
||||
if (up->port.handle_break)
|
||||
uart->port.handle_break = up->port.handle_break;
|
||||
if (up->dl_read)
|
||||
uart->dl_read = up->dl_read;
|
||||
if (up->dl_write)
|
||||
uart->dl_write = up->dl_write;
|
||||
|
||||
if (serial8250_isa_config != NULL)
|
||||
serial8250_isa_config(0, &uart->port,
|
||||
&uart->capabilities);
|
||||
|
||||
ret = uart_add_one_port(&serial8250_reg, &uart->port);
|
||||
if (ret == 0)
|
||||
ret = uart->port.line;
|
||||
}
|
||||
mutex_unlock(&serial_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(serial8250_register_8250_port);
|
||||
|
||||
/**
|
||||
* serial8250_register_port - register a serial port
|
||||
* @port: serial port template
|
||||
|
@ -3167,60 +3204,11 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
|
|||
*/
|
||||
int serial8250_register_port(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *uart;
|
||||
int ret = -ENOSPC;
|
||||
struct uart_8250_port up;
|
||||
|
||||
if (port->uartclk == 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&serial_mutex);
|
||||
|
||||
uart = serial8250_find_match_or_unused(port);
|
||||
if (uart) {
|
||||
uart_remove_one_port(&serial8250_reg, &uart->port);
|
||||
|
||||
uart->port.iobase = port->iobase;
|
||||
uart->port.membase = port->membase;
|
||||
uart->port.irq = port->irq;
|
||||
uart->port.irqflags = port->irqflags;
|
||||
uart->port.uartclk = port->uartclk;
|
||||
uart->port.fifosize = port->fifosize;
|
||||
uart->port.regshift = port->regshift;
|
||||
uart->port.iotype = port->iotype;
|
||||
uart->port.flags = port->flags | UPF_BOOT_AUTOCONF;
|
||||
uart->port.mapbase = port->mapbase;
|
||||
uart->port.private_data = port->private_data;
|
||||
if (port->dev)
|
||||
uart->port.dev = port->dev;
|
||||
|
||||
if (port->flags & UPF_FIXED_TYPE)
|
||||
serial8250_init_fixed_type_port(uart, port->type);
|
||||
|
||||
set_io_from_upio(&uart->port);
|
||||
/* Possibly override default I/O functions. */
|
||||
if (port->serial_in)
|
||||
uart->port.serial_in = port->serial_in;
|
||||
if (port->serial_out)
|
||||
uart->port.serial_out = port->serial_out;
|
||||
if (port->handle_irq)
|
||||
uart->port.handle_irq = port->handle_irq;
|
||||
/* Possibly override set_termios call */
|
||||
if (port->set_termios)
|
||||
uart->port.set_termios = port->set_termios;
|
||||
if (port->pm)
|
||||
uart->port.pm = port->pm;
|
||||
|
||||
if (serial8250_isa_config != NULL)
|
||||
serial8250_isa_config(0, &uart->port,
|
||||
&uart->capabilities);
|
||||
|
||||
ret = uart_add_one_port(&serial8250_reg, &uart->port);
|
||||
if (ret == 0)
|
||||
ret = uart->port.line;
|
||||
}
|
||||
mutex_unlock(&serial_mutex);
|
||||
|
||||
return ret;
|
||||
memset(&up, 0, sizeof(up));
|
||||
memcpy(&up.port, port, sizeof(*port));
|
||||
return serial8250_register_8250_port(&up);
|
||||
}
|
||||
EXPORT_SYMBOL(serial8250_register_port);
|
||||
|
||||
|
|
|
@ -37,6 +37,10 @@ struct uart_8250_port {
|
|||
unsigned char lsr_saved_flags;
|
||||
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
|
||||
unsigned char msr_saved_flags;
|
||||
|
||||
/* 8250 specific callbacks */
|
||||
int (*dl_read)(struct uart_8250_port *);
|
||||
void (*dl_write)(struct uart_8250_port *, int);
|
||||
};
|
||||
|
||||
struct old_serial_port {
|
||||
|
@ -96,6 +100,18 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value)
|
|||
up->port.serial_out(&up->port, offset, value);
|
||||
}
|
||||
|
||||
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p);
|
||||
|
||||
static inline int serial_dl_read(struct uart_8250_port *up)
|
||||
{
|
||||
return up->dl_read(up);
|
||||
}
|
||||
|
||||
static inline void serial_dl_write(struct uart_8250_port *up, int value)
|
||||
{
|
||||
up->dl_write(up, value);
|
||||
}
|
||||
|
||||
#if defined(__alpha__) && !defined(CONFIG_PCI)
|
||||
/*
|
||||
* Digital did something really horribly wrong with the OUT1 and OUT2
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* Renesas Emma Mobile 8250 driver
|
||||
*
|
||||
* Copyright (C) 2012 Magnus Damm
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
#define UART_DLL_EM 9
|
||||
#define UART_DLM_EM 10
|
||||
|
||||
struct serial8250_em_priv {
|
||||
struct clk *sclk;
|
||||
int line;
|
||||
};
|
||||
|
||||
static void serial8250_em_serial_out(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
switch (offset) {
|
||||
case UART_TX: /* TX @ 0x00 */
|
||||
writeb(value, p->membase);
|
||||
break;
|
||||
case UART_FCR: /* FCR @ 0x0c (+1) */
|
||||
case UART_LCR: /* LCR @ 0x10 (+1) */
|
||||
case UART_MCR: /* MCR @ 0x14 (+1) */
|
||||
case UART_SCR: /* SCR @ 0x20 (+1) */
|
||||
writel(value, p->membase + ((offset + 1) << 2));
|
||||
break;
|
||||
case UART_IER: /* IER @ 0x04 */
|
||||
value &= 0x0f; /* only 4 valid bits - not Xscale */
|
||||
/* fall-through */
|
||||
case UART_DLL_EM: /* DLL @ 0x24 (+9) */
|
||||
case UART_DLM_EM: /* DLM @ 0x28 (+9) */
|
||||
writel(value, p->membase + (offset << 2));
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int serial8250_em_serial_in(struct uart_port *p, int offset)
|
||||
{
|
||||
switch (offset) {
|
||||
case UART_RX: /* RX @ 0x00 */
|
||||
return readb(p->membase);
|
||||
case UART_MCR: /* MCR @ 0x14 (+1) */
|
||||
case UART_LSR: /* LSR @ 0x18 (+1) */
|
||||
case UART_MSR: /* MSR @ 0x1c (+1) */
|
||||
case UART_SCR: /* SCR @ 0x20 (+1) */
|
||||
return readl(p->membase + ((offset + 1) << 2));
|
||||
case UART_IER: /* IER @ 0x04 */
|
||||
case UART_IIR: /* IIR @ 0x08 */
|
||||
case UART_DLL_EM: /* DLL @ 0x24 (+9) */
|
||||
case UART_DLM_EM: /* DLM @ 0x28 (+9) */
|
||||
return readl(p->membase + (offset << 2));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serial8250_em_serial_dl_read(struct uart_8250_port *up)
|
||||
{
|
||||
return serial_in(up, UART_DLL_EM) | serial_in(up, UART_DLM_EM) << 8;
|
||||
}
|
||||
|
||||
static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value)
|
||||
{
|
||||
serial_out(up, UART_DLL_EM, value & 0xff);
|
||||
serial_out(up, UART_DLM_EM, value >> 8 & 0xff);
|
||||
}
|
||||
|
||||
static int __devinit serial8250_em_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
struct serial8250_em_priv *priv;
|
||||
struct uart_8250_port up;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!regs || !irq) {
|
||||
dev_err(&pdev->dev, "missing registers or irq\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
dev_err(&pdev->dev, "unable to allocate private data\n");
|
||||
ret = -ENOMEM;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
priv->sclk = clk_get(&pdev->dev, "sclk");
|
||||
if (IS_ERR(priv->sclk)) {
|
||||
dev_err(&pdev->dev, "unable to get clock\n");
|
||||
ret = PTR_ERR(priv->sclk);
|
||||
goto err1;
|
||||
}
|
||||
|
||||
memset(&up, 0, sizeof(up));
|
||||
up.port.mapbase = regs->start;
|
||||
up.port.irq = irq->start;
|
||||
up.port.type = PORT_UNKNOWN;
|
||||
up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP;
|
||||
up.port.dev = &pdev->dev;
|
||||
up.port.private_data = priv;
|
||||
|
||||
clk_enable(priv->sclk);
|
||||
up.port.uartclk = clk_get_rate(priv->sclk);
|
||||
|
||||
up.port.iotype = UPIO_MEM32;
|
||||
up.port.serial_in = serial8250_em_serial_in;
|
||||
up.port.serial_out = serial8250_em_serial_out;
|
||||
up.dl_read = serial8250_em_serial_dl_read;
|
||||
up.dl_write = serial8250_em_serial_dl_write;
|
||||
|
||||
ret = serial8250_register_8250_port(&up);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "unable to register 8250 port\n");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
priv->line = ret;
|
||||
platform_set_drvdata(pdev, priv);
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
clk_disable(priv->sclk);
|
||||
clk_put(priv->sclk);
|
||||
err1:
|
||||
kfree(priv);
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit serial8250_em_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct serial8250_em_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
serial8250_unregister_port(priv->line);
|
||||
clk_disable(priv->sclk);
|
||||
clk_put(priv->sclk);
|
||||
kfree(priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id serial8250_em_dt_ids[] __devinitconst = {
|
||||
{ .compatible = "renesas,em-uart", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, serial8250_em_dt_ids);
|
||||
|
||||
static struct platform_driver serial8250_em_platform_driver = {
|
||||
.driver = {
|
||||
.name = "serial8250-em",
|
||||
.of_match_table = serial8250_em_dt_ids,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = serial8250_em_probe,
|
||||
.remove = __devexit_p(serial8250_em_remove),
|
||||
};
|
||||
|
||||
module_platform_driver(serial8250_em_platform_driver);
|
||||
|
||||
MODULE_AUTHOR("Magnus Damm");
|
||||
MODULE_DESCRIPTION("Renesas Emma Mobile 8250 Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/8250_pci.h>
|
||||
#include <linux/bitops.h>
|
||||
|
@ -1092,11 +1093,49 @@ static int skip_tx_en_setup(struct serial_private *priv,
|
|||
return pci_default_setup(priv, board, port, idx);
|
||||
}
|
||||
|
||||
static void kt_handle_break(struct uart_port *p)
|
||||
{
|
||||
struct uart_8250_port *up =
|
||||
container_of(p, struct uart_8250_port, port);
|
||||
/*
|
||||
* On receipt of a BI, serial device in Intel ME (Intel
|
||||
* management engine) needs to have its fifos cleared for sane
|
||||
* SOL (Serial Over Lan) output.
|
||||
*/
|
||||
serial8250_clear_and_reinit_fifos(up);
|
||||
}
|
||||
|
||||
static unsigned int kt_serial_in(struct uart_port *p, int offset)
|
||||
{
|
||||
struct uart_8250_port *up =
|
||||
container_of(p, struct uart_8250_port, port);
|
||||
unsigned int val;
|
||||
|
||||
/*
|
||||
* When the Intel ME (management engine) gets reset its serial
|
||||
* port registers could return 0 momentarily. Functions like
|
||||
* serial8250_console_write, read and save the IER, perform
|
||||
* some operation and then restore it. In order to avoid
|
||||
* setting IER register inadvertently to 0, if the value read
|
||||
* is 0, double check with ier value in uart_8250_port and use
|
||||
* that instead. up->ier should be the same value as what is
|
||||
* currently configured.
|
||||
*/
|
||||
val = inb(p->iobase + offset);
|
||||
if (offset == UART_IER) {
|
||||
if (val == 0)
|
||||
val = up->ier;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static int kt_serial_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
struct uart_port *port, int idx)
|
||||
{
|
||||
port->flags |= UPF_BUG_THRE;
|
||||
port->serial_in = kt_serial_in;
|
||||
port->handle_break = kt_handle_break;
|
||||
return skip_tx_en_setup(priv, board, port, idx);
|
||||
}
|
||||
|
||||
|
@ -1609,54 +1648,72 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
|
|||
{
|
||||
.vendor = PCI_VENDOR_ID_INTEL,
|
||||
.device = 0x8811,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.init = pci_eg20t_init,
|
||||
.setup = pci_default_setup,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_INTEL,
|
||||
.device = 0x8812,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.init = pci_eg20t_init,
|
||||
.setup = pci_default_setup,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_INTEL,
|
||||
.device = 0x8813,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.init = pci_eg20t_init,
|
||||
.setup = pci_default_setup,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_INTEL,
|
||||
.device = 0x8814,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.init = pci_eg20t_init,
|
||||
.setup = pci_default_setup,
|
||||
},
|
||||
{
|
||||
.vendor = 0x10DB,
|
||||
.device = 0x8027,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.init = pci_eg20t_init,
|
||||
.setup = pci_default_setup,
|
||||
},
|
||||
{
|
||||
.vendor = 0x10DB,
|
||||
.device = 0x8028,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.init = pci_eg20t_init,
|
||||
.setup = pci_default_setup,
|
||||
},
|
||||
{
|
||||
.vendor = 0x10DB,
|
||||
.device = 0x8029,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.init = pci_eg20t_init,
|
||||
.setup = pci_default_setup,
|
||||
},
|
||||
{
|
||||
.vendor = 0x10DB,
|
||||
.device = 0x800C,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.init = pci_eg20t_init,
|
||||
.setup = pci_default_setup,
|
||||
},
|
||||
{
|
||||
.vendor = 0x10DB,
|
||||
.device = 0x800D,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.init = pci_eg20t_init,
|
||||
.setup = pci_default_setup,
|
||||
},
|
||||
|
@ -2775,6 +2832,12 @@ void pciserial_suspend_ports(struct serial_private *priv)
|
|||
for (i = 0; i < priv->nr; i++)
|
||||
if (priv->line[i] >= 0)
|
||||
serial8250_suspend_port(priv->line[i]);
|
||||
|
||||
/*
|
||||
* Ensure that every init quirk is properly torn down
|
||||
*/
|
||||
if (priv->quirk->exit)
|
||||
priv->quirk->exit(priv->dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pciserial_suspend_ports);
|
||||
|
||||
|
|
|
@ -278,3 +278,11 @@ config SERIAL_8250_DW
|
|||
help
|
||||
Selecting this option will enable handling of the extra features
|
||||
present in the Synopsys DesignWare APB UART.
|
||||
|
||||
config SERIAL_8250_EM
|
||||
tristate "Support for Emma Mobile intergrated serial port"
|
||||
depends on SERIAL_8250 && ARM && HAVE_CLK
|
||||
help
|
||||
Selecting this option will add support for the integrated serial
|
||||
port hardware found on the Emma Mobile line of processors.
|
||||
If unsure, say N.
|
||||
|
|
|
@ -18,3 +18,4 @@ obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
|
|||
obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
|
||||
obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
|
||||
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
|
||||
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
|
||||
|
|
|
@ -68,30 +68,6 @@
|
|||
#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
|
||||
#define UART_DUMMY_DR_RX (1 << 16)
|
||||
|
||||
|
||||
#define UART_WA_SAVE_NR 14
|
||||
|
||||
static void pl011_lockup_wa(unsigned long data);
|
||||
static const u32 uart_wa_reg[UART_WA_SAVE_NR] = {
|
||||
ST_UART011_DMAWM,
|
||||
ST_UART011_TIMEOUT,
|
||||
ST_UART011_LCRH_RX,
|
||||
UART011_IBRD,
|
||||
UART011_FBRD,
|
||||
ST_UART011_LCRH_TX,
|
||||
UART011_IFLS,
|
||||
ST_UART011_XFCR,
|
||||
ST_UART011_XON1,
|
||||
ST_UART011_XON2,
|
||||
ST_UART011_XOFF1,
|
||||
ST_UART011_XOFF2,
|
||||
UART011_CR,
|
||||
UART011_IMSC
|
||||
};
|
||||
|
||||
static u32 uart_wa_regdata[UART_WA_SAVE_NR];
|
||||
static DECLARE_TASKLET(pl011_lockup_tlet, pl011_lockup_wa, 0);
|
||||
|
||||
/* There is by now at least one vendor with differing details, so handle it */
|
||||
struct vendor_data {
|
||||
unsigned int ifls;
|
||||
|
@ -101,6 +77,7 @@ struct vendor_data {
|
|||
bool oversampling;
|
||||
bool interrupt_may_hang; /* vendor-specific */
|
||||
bool dma_threshold;
|
||||
bool cts_event_workaround;
|
||||
};
|
||||
|
||||
static struct vendor_data vendor_arm = {
|
||||
|
@ -110,6 +87,7 @@ static struct vendor_data vendor_arm = {
|
|||
.lcrh_rx = UART011_LCRH,
|
||||
.oversampling = false,
|
||||
.dma_threshold = false,
|
||||
.cts_event_workaround = false,
|
||||
};
|
||||
|
||||
static struct vendor_data vendor_st = {
|
||||
|
@ -120,6 +98,7 @@ static struct vendor_data vendor_st = {
|
|||
.oversampling = true,
|
||||
.interrupt_may_hang = true,
|
||||
.dma_threshold = true,
|
||||
.cts_event_workaround = true,
|
||||
};
|
||||
|
||||
static struct uart_amba_port *amba_ports[UART_NR];
|
||||
|
@ -1055,69 +1034,6 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
|
|||
#define pl011_dma_flush_buffer NULL
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* pl011_lockup_wa
|
||||
* This workaround aims to break the deadlock situation
|
||||
* when after long transfer over uart in hardware flow
|
||||
* control, uart interrupt registers cannot be cleared.
|
||||
* Hence uart transfer gets blocked.
|
||||
*
|
||||
* It is seen that during such deadlock condition ICR
|
||||
* don't get cleared even on multiple write. This leads
|
||||
* pass_counter to decrease and finally reach zero. This
|
||||
* can be taken as trigger point to run this UART_BT_WA.
|
||||
*
|
||||
*/
|
||||
static void pl011_lockup_wa(unsigned long data)
|
||||
{
|
||||
struct uart_amba_port *uap = amba_ports[0];
|
||||
void __iomem *base = uap->port.membase;
|
||||
struct circ_buf *xmit = &uap->port.state->xmit;
|
||||
struct tty_struct *tty = uap->port.state->port.tty;
|
||||
int buf_empty_retries = 200;
|
||||
int loop;
|
||||
|
||||
/* Stop HCI layer from submitting data for tx */
|
||||
tty->hw_stopped = 1;
|
||||
while (!uart_circ_empty(xmit)) {
|
||||
if (buf_empty_retries-- == 0)
|
||||
break;
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
/* Backup registers */
|
||||
for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
|
||||
uart_wa_regdata[loop] = readl(base + uart_wa_reg[loop]);
|
||||
|
||||
/* Disable UART so that FIFO data is flushed out */
|
||||
writew(0x00, uap->port.membase + UART011_CR);
|
||||
|
||||
/* Soft reset UART module */
|
||||
if (uap->port.dev->platform_data) {
|
||||
struct amba_pl011_data *plat;
|
||||
|
||||
plat = uap->port.dev->platform_data;
|
||||
if (plat->reset)
|
||||
plat->reset();
|
||||
}
|
||||
|
||||
/* Restore registers */
|
||||
for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
|
||||
writew(uart_wa_regdata[loop] ,
|
||||
uap->port.membase + uart_wa_reg[loop]);
|
||||
|
||||
/* Initialise the old status of the modem signals */
|
||||
uap->old_status = readw(uap->port.membase + UART01x_FR) &
|
||||
UART01x_FR_MODEM_ANY;
|
||||
|
||||
if (readl(base + UART011_MIS) & 0x2)
|
||||
printk(KERN_EMERG "UART_BT_WA: ***FAILED***\n");
|
||||
|
||||
/* Start Tx/Rx */
|
||||
tty->hw_stopped = 0;
|
||||
}
|
||||
|
||||
static void pl011_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
||||
|
@ -1246,12 +1162,26 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
|
|||
unsigned long flags;
|
||||
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
|
||||
int handled = 0;
|
||||
unsigned int dummy_read;
|
||||
|
||||
spin_lock_irqsave(&uap->port.lock, flags);
|
||||
|
||||
status = readw(uap->port.membase + UART011_MIS);
|
||||
if (status) {
|
||||
do {
|
||||
if (uap->vendor->cts_event_workaround) {
|
||||
/* workaround to make sure that all bits are unlocked.. */
|
||||
writew(0x00, uap->port.membase + UART011_ICR);
|
||||
|
||||
/*
|
||||
* WA: introduce 26ns(1 uart clk) delay before W1C;
|
||||
* single apb access will incur 2 pclk(133.12Mhz) delay,
|
||||
* so add 2 dummy reads
|
||||
*/
|
||||
dummy_read = readw(uap->port.membase + UART011_ICR);
|
||||
dummy_read = readw(uap->port.membase + UART011_ICR);
|
||||
}
|
||||
|
||||
writew(status & ~(UART011_TXIS|UART011_RTIS|
|
||||
UART011_RXIS),
|
||||
uap->port.membase + UART011_ICR);
|
||||
|
@ -1268,11 +1198,8 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
|
|||
if (status & UART011_TXIS)
|
||||
pl011_tx_chars(uap);
|
||||
|
||||
if (pass_counter-- == 0) {
|
||||
if (uap->interrupt_may_hang)
|
||||
tasklet_schedule(&pl011_lockup_tlet);
|
||||
if (pass_counter-- == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
status = readw(uap->port.membase + UART011_MIS);
|
||||
} while (status != 0);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Blackfin On-Chip Serial Driver
|
||||
*
|
||||
* Copyright 2006-2010 Analog Devices Inc.
|
||||
* Copyright 2006-2011 Analog Devices Inc.
|
||||
*
|
||||
* Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
|
@ -35,10 +35,6 @@
|
|||
#include <asm/portmux.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/dma.h>
|
||||
|
||||
#define port_membase(uart) (((struct bfin_serial_port *)(uart))->port.membase)
|
||||
#define get_lsr_cache(uart) (((struct bfin_serial_port *)(uart))->lsr)
|
||||
#define put_lsr_cache(uart, v) (((struct bfin_serial_port *)(uart))->lsr = (v))
|
||||
#include <asm/bfin_serial.h>
|
||||
|
||||
#ifdef CONFIG_SERIAL_BFIN_MODULE
|
||||
|
@ -166,7 +162,7 @@ static void bfin_serial_stop_tx(struct uart_port *port)
|
|||
uart->tx_count = 0;
|
||||
uart->tx_done = 1;
|
||||
#else
|
||||
#ifdef CONFIG_BF54x
|
||||
#if defined(CONFIG_BF54x) || defined(CONFIG_BF60x)
|
||||
/* Clear TFI bit */
|
||||
UART_PUT_LSR(uart, TFI);
|
||||
#endif
|
||||
|
@ -337,7 +333,7 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
|
|||
struct circ_buf *xmit = &uart->port.state->xmit;
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
|
||||
#ifdef CONFIG_BF54x
|
||||
#if defined(CONFIG_BF54x) || defined(CONFIG_BF60x)
|
||||
/* Clear TFI bit */
|
||||
UART_PUT_LSR(uart, TFI);
|
||||
#endif
|
||||
|
@ -536,7 +532,7 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
|
|||
*/
|
||||
UART_CLEAR_IER(uart, ETBEI);
|
||||
uart->port.icount.tx += uart->tx_count;
|
||||
if (!uart_circ_empty(xmit)) {
|
||||
if (!(xmit->tail == 0 && xmit->head == 0)) {
|
||||
xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
|
@ -553,7 +549,7 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
|
|||
static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
|
||||
{
|
||||
struct bfin_serial_port *uart = dev_id;
|
||||
unsigned short irqstat;
|
||||
unsigned int irqstat;
|
||||
int x_pos, pos;
|
||||
|
||||
spin_lock(&uart->rx_lock);
|
||||
|
@ -586,7 +582,7 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
|
|||
static unsigned int bfin_serial_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
|
||||
unsigned short lsr;
|
||||
unsigned int lsr;
|
||||
|
||||
lsr = UART_GET_LSR(uart);
|
||||
if (lsr & TEMT)
|
||||
|
@ -598,7 +594,7 @@ static unsigned int bfin_serial_tx_empty(struct uart_port *port)
|
|||
static void bfin_serial_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
|
||||
u16 lcr = UART_GET_LCR(uart);
|
||||
u32 lcr = UART_GET_LCR(uart);
|
||||
if (break_state)
|
||||
lcr |= SB;
|
||||
else
|
||||
|
@ -745,7 +741,7 @@ static int bfin_serial_startup(struct uart_port *port)
|
|||
}
|
||||
|
||||
/* CTS RTS PINs are negative assertive. */
|
||||
UART_PUT_MCR(uart, ACTS);
|
||||
UART_PUT_MCR(uart, UART_GET_MCR(uart) | ACTS);
|
||||
UART_SET_IER(uart, EDSSI);
|
||||
}
|
||||
#endif
|
||||
|
@ -803,7 +799,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
|
||||
unsigned long flags;
|
||||
unsigned int baud, quot;
|
||||
unsigned short val, ier, lcr = 0;
|
||||
unsigned int ier, lcr = 0;
|
||||
|
||||
switch (termios->c_cflag & CSIZE) {
|
||||
case CS8:
|
||||
|
@ -875,26 +871,23 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
|
||||
/* Disable UART */
|
||||
ier = UART_GET_IER(uart);
|
||||
UART_PUT_GCTL(uart, UART_GET_GCTL(uart) & ~UCEN);
|
||||
UART_DISABLE_INTS(uart);
|
||||
|
||||
/* Set DLAB in LCR to Access DLL and DLH */
|
||||
/* Set DLAB in LCR to Access CLK */
|
||||
UART_SET_DLAB(uart);
|
||||
|
||||
UART_PUT_DLL(uart, quot & 0xFF);
|
||||
UART_PUT_DLH(uart, (quot >> 8) & 0xFF);
|
||||
UART_PUT_CLK(uart, quot);
|
||||
SSYNC();
|
||||
|
||||
/* Clear DLAB in LCR to Access THR RBR IER */
|
||||
UART_CLEAR_DLAB(uart);
|
||||
|
||||
UART_PUT_LCR(uart, lcr);
|
||||
UART_PUT_LCR(uart, (UART_GET_LCR(uart) & ~LCR_MASK) | lcr);
|
||||
|
||||
/* Enable UART */
|
||||
UART_ENABLE_INTS(uart, ier);
|
||||
|
||||
val = UART_GET_GCTL(uart);
|
||||
val |= UCEN;
|
||||
UART_PUT_GCTL(uart, val);
|
||||
UART_PUT_GCTL(uart, UART_GET_GCTL(uart) | UCEN);
|
||||
|
||||
/* Port speed changed, update the per-port timeout. */
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
|
@ -954,17 +947,17 @@ bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
|
|||
static void bfin_serial_set_ldisc(struct uart_port *port, int ld)
|
||||
{
|
||||
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
|
||||
unsigned short val;
|
||||
unsigned int val;
|
||||
|
||||
switch (ld) {
|
||||
case N_IRDA:
|
||||
val = UART_GET_GCTL(uart);
|
||||
val |= (IREN | RPOLC);
|
||||
val |= (UMOD_IRDA | RPOLC);
|
||||
UART_PUT_GCTL(uart, val);
|
||||
break;
|
||||
default:
|
||||
val = UART_GET_GCTL(uart);
|
||||
val &= ~(IREN | RPOLC);
|
||||
val &= ~(UMOD_MASK | RPOLC);
|
||||
UART_PUT_GCTL(uart, val);
|
||||
}
|
||||
}
|
||||
|
@ -972,13 +965,13 @@ static void bfin_serial_set_ldisc(struct uart_port *port, int ld)
|
|||
static void bfin_serial_reset_irda(struct uart_port *port)
|
||||
{
|
||||
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
|
||||
unsigned short val;
|
||||
unsigned int val;
|
||||
|
||||
val = UART_GET_GCTL(uart);
|
||||
val &= ~(IREN | RPOLC);
|
||||
val &= ~(UMOD_MASK | RPOLC);
|
||||
UART_PUT_GCTL(uart, val);
|
||||
SSYNC();
|
||||
val |= (IREN | RPOLC);
|
||||
val |= (UMOD_IRDA | RPOLC);
|
||||
UART_PUT_GCTL(uart, val);
|
||||
SSYNC();
|
||||
}
|
||||
|
@ -1070,12 +1063,12 @@ static void __init
|
|||
bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
|
||||
int *parity, int *bits)
|
||||
{
|
||||
unsigned short status;
|
||||
unsigned int status;
|
||||
|
||||
status = UART_GET_IER(uart) & (ERBFI | ETBEI);
|
||||
if (status == (ERBFI | ETBEI)) {
|
||||
/* ok, the port was enabled */
|
||||
u16 lcr, dlh, dll;
|
||||
u32 lcr, clk;
|
||||
|
||||
lcr = UART_GET_LCR(uart);
|
||||
|
||||
|
@ -1086,30 +1079,17 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
|
|||
else
|
||||
*parity = 'o';
|
||||
}
|
||||
switch (lcr & 0x03) {
|
||||
case 0:
|
||||
*bits = 5;
|
||||
break;
|
||||
case 1:
|
||||
*bits = 6;
|
||||
break;
|
||||
case 2:
|
||||
*bits = 7;
|
||||
break;
|
||||
case 3:
|
||||
*bits = 8;
|
||||
break;
|
||||
}
|
||||
/* Set DLAB in LCR to Access DLL and DLH */
|
||||
*bits = ((lcr & WLS_MASK) >> WLS_OFFSET) + 5;
|
||||
|
||||
/* Set DLAB in LCR to Access CLK */
|
||||
UART_SET_DLAB(uart);
|
||||
|
||||
dll = UART_GET_DLL(uart);
|
||||
dlh = UART_GET_DLH(uart);
|
||||
clk = UART_GET_CLK(uart);
|
||||
|
||||
/* Clear DLAB in LCR to Access THR RBR IER */
|
||||
UART_CLEAR_DLAB(uart);
|
||||
|
||||
*baud = get_sclk() / (16*(dll | dlh << 8));
|
||||
*baud = get_sclk() / (16*clk);
|
||||
}
|
||||
pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits);
|
||||
}
|
||||
|
|
|
@ -952,19 +952,6 @@ static const struct control_pins e100_modem_pins[NR_PORTS] =
|
|||
/* Input */
|
||||
#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask)
|
||||
|
||||
|
||||
/*
|
||||
* tmp_buf is used as a temporary buffer by serial_write. We need to
|
||||
* lock it in case the memcpy_fromfs blocks while swapping in a page,
|
||||
* and some other program tries to do a serial write at the same time.
|
||||
* Since the lock will only come under contention when the system is
|
||||
* swapping and available memory is low, it makes sense to share one
|
||||
* buffer across all the serial ports, since it significantly saves
|
||||
* memory if large numbers of serial ports are open.
|
||||
*/
|
||||
static unsigned char *tmp_buf;
|
||||
static DEFINE_MUTEX(tmp_buf_mutex);
|
||||
|
||||
/* Calculate the chartime depending on baudrate, numbor of bits etc. */
|
||||
static void update_char_time(struct e100_serial * info)
|
||||
{
|
||||
|
@ -3150,7 +3137,7 @@ static int rs_raw_write(struct tty_struct *tty,
|
|||
|
||||
/* first some sanity checks */
|
||||
|
||||
if (!tty || !info->xmit.buf || !tmp_buf)
|
||||
if (!tty || !info->xmit.buf)
|
||||
return 0;
|
||||
|
||||
#ifdef SERIAL_DEBUG_DATA
|
||||
|
@ -3989,7 +3976,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
|||
*/
|
||||
if (tty_hung_up_p(filp) ||
|
||||
(info->flags & ASYNC_CLOSING)) {
|
||||
wait_event_interruptible_tty(info->close_wait,
|
||||
wait_event_interruptible_tty(tty, info->close_wait,
|
||||
!(info->flags & ASYNC_CLOSING));
|
||||
#ifdef SERIAL_DO_RESTART
|
||||
if (info->flags & ASYNC_HUP_NOTIFY)
|
||||
|
@ -4065,9 +4052,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
|||
printk("block_til_ready blocking: ttyS%d, count = %d\n",
|
||||
info->line, info->count);
|
||||
#endif
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
schedule();
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
}
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&info->open_wait, &wait);
|
||||
|
@ -4106,7 +4093,6 @@ rs_open(struct tty_struct *tty, struct file * filp)
|
|||
{
|
||||
struct e100_serial *info;
|
||||
int retval;
|
||||
unsigned long page;
|
||||
int allocated_resources = 0;
|
||||
|
||||
info = rs_table + tty->index;
|
||||
|
@ -4124,23 +4110,12 @@ rs_open(struct tty_struct *tty, struct file * filp)
|
|||
|
||||
tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY);
|
||||
|
||||
if (!tmp_buf) {
|
||||
page = get_zeroed_page(GFP_KERNEL);
|
||||
if (!page) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (tmp_buf)
|
||||
free_page(page);
|
||||
else
|
||||
tmp_buf = (unsigned char *) page;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the port is in the middle of closing, bail out now
|
||||
*/
|
||||
if (tty_hung_up_p(filp) ||
|
||||
(info->flags & ASYNC_CLOSING)) {
|
||||
wait_event_interruptible_tty(info->close_wait,
|
||||
wait_event_interruptible_tty(tty, info->close_wait,
|
||||
!(info->flags & ASYNC_CLOSING));
|
||||
#ifdef SERIAL_DO_RESTART
|
||||
return ((info->flags & ASYNC_HUP_NOTIFY) ?
|
||||
|
@ -4487,6 +4462,7 @@ static int __init rs_init(void)
|
|||
info->enabled = 0;
|
||||
}
|
||||
}
|
||||
tty_port_init(&info->port);
|
||||
info->uses_dma_in = 0;
|
||||
info->uses_dma_out = 0;
|
||||
info->line = i;
|
||||
|
|
|
@ -370,6 +370,8 @@ static void mxs_auart_settermios(struct uart_port *u,
|
|||
|
||||
writel(ctrl, u->membase + AUART_LINECTRL);
|
||||
writel(ctrl2, u->membase + AUART_CTRL2);
|
||||
|
||||
uart_update_timeout(u, termios->c_cflag, baud);
|
||||
}
|
||||
|
||||
static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
|
||||
|
|
|
@ -12,10 +12,13 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_serial.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/nwpserial.h>
|
||||
|
||||
|
@ -24,6 +27,26 @@ struct of_serial_info {
|
|||
int line;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA
|
||||
void tegra_serial_handle_break(struct uart_port *p)
|
||||
{
|
||||
unsigned int status, tmout = 10000;
|
||||
|
||||
do {
|
||||
status = p->serial_in(p, UART_LSR);
|
||||
if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
|
||||
status = p->serial_in(p, UART_RX);
|
||||
else
|
||||
break;
|
||||
if (--tmout == 0)
|
||||
break;
|
||||
udelay(1);
|
||||
} while (1);
|
||||
}
|
||||
/* FIXME remove this export when tegra finishes conversion to open firmware */
|
||||
EXPORT_SYMBOL_GPL(tegra_serial_handle_break);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Fill a struct uart_port for a given device node
|
||||
*/
|
||||
|
@ -84,6 +107,9 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
|
|||
| UPF_FIXED_PORT | UPF_FIXED_TYPE;
|
||||
port->dev = &ofdev->dev;
|
||||
|
||||
if (type == PORT_TEGRA)
|
||||
port->handle_break = tegra_serial_handle_break;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,13 @@
|
|||
#include <plat/dmtimer.h>
|
||||
#include <plat/omap-serial.h>
|
||||
|
||||
#define UART_BUILD_REVISION(x, y) (((x) << 8) | (y))
|
||||
|
||||
#define OMAP_UART_REV_42 0x0402
|
||||
#define OMAP_UART_REV_46 0x0406
|
||||
#define OMAP_UART_REV_52 0x0502
|
||||
#define OMAP_UART_REV_63 0x0603
|
||||
|
||||
#define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/
|
||||
|
||||
/* SCR register bitmasks */
|
||||
|
@ -53,6 +60,17 @@
|
|||
#define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT 6
|
||||
#define OMAP_UART_FCR_RX_FIFO_TRIG_MASK (0x3 << 6)
|
||||
|
||||
/* MVR register bitmasks */
|
||||
#define OMAP_UART_MVR_SCHEME_SHIFT 30
|
||||
|
||||
#define OMAP_UART_LEGACY_MVR_MAJ_MASK 0xf0
|
||||
#define OMAP_UART_LEGACY_MVR_MAJ_SHIFT 4
|
||||
#define OMAP_UART_LEGACY_MVR_MIN_MASK 0x0f
|
||||
|
||||
#define OMAP_UART_MVR_MAJ_MASK 0x700
|
||||
#define OMAP_UART_MVR_MAJ_SHIFT 8
|
||||
#define OMAP_UART_MVR_MIN_MASK 0x3f
|
||||
|
||||
static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
|
||||
|
||||
/* Forward declaration of functions */
|
||||
|
@ -1346,6 +1364,59 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
|
|||
return;
|
||||
}
|
||||
|
||||
static void omap_serial_fill_features_erratas(struct uart_omap_port *up)
|
||||
{
|
||||
u32 mvr, scheme;
|
||||
u16 revision, major, minor;
|
||||
|
||||
mvr = serial_in(up, UART_OMAP_MVER);
|
||||
|
||||
/* Check revision register scheme */
|
||||
scheme = mvr >> OMAP_UART_MVR_SCHEME_SHIFT;
|
||||
|
||||
switch (scheme) {
|
||||
case 0: /* Legacy Scheme: OMAP2/3 */
|
||||
/* MINOR_REV[0:4], MAJOR_REV[4:7] */
|
||||
major = (mvr & OMAP_UART_LEGACY_MVR_MAJ_MASK) >>
|
||||
OMAP_UART_LEGACY_MVR_MAJ_SHIFT;
|
||||
minor = (mvr & OMAP_UART_LEGACY_MVR_MIN_MASK);
|
||||
break;
|
||||
case 1:
|
||||
/* New Scheme: OMAP4+ */
|
||||
/* MINOR_REV[0:5], MAJOR_REV[8:10] */
|
||||
major = (mvr & OMAP_UART_MVR_MAJ_MASK) >>
|
||||
OMAP_UART_MVR_MAJ_SHIFT;
|
||||
minor = (mvr & OMAP_UART_MVR_MIN_MASK);
|
||||
break;
|
||||
default:
|
||||
dev_warn(&up->pdev->dev,
|
||||
"Unknown %s revision, defaulting to highest\n",
|
||||
up->name);
|
||||
/* highest possible revision */
|
||||
major = 0xff;
|
||||
minor = 0xff;
|
||||
}
|
||||
|
||||
/* normalize revision for the driver */
|
||||
revision = UART_BUILD_REVISION(major, minor);
|
||||
|
||||
switch (revision) {
|
||||
case OMAP_UART_REV_46:
|
||||
up->errata |= (UART_ERRATA_i202_MDR1_ACCESS |
|
||||
UART_ERRATA_i291_DMA_FORCEIDLE);
|
||||
break;
|
||||
case OMAP_UART_REV_52:
|
||||
up->errata |= (UART_ERRATA_i202_MDR1_ACCESS |
|
||||
UART_ERRATA_i291_DMA_FORCEIDLE);
|
||||
break;
|
||||
case OMAP_UART_REV_63:
|
||||
up->errata |= UART_ERRATA_i202_MDR1_ACCESS;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
|
||||
{
|
||||
struct omap_uart_port_info *omap_up_info;
|
||||
|
@ -1439,7 +1510,6 @@ static int serial_omap_probe(struct platform_device *pdev)
|
|||
"%d\n", DEFAULT_CLK_SPEED);
|
||||
}
|
||||
up->uart_dma.uart_base = mem->start;
|
||||
up->errata = omap_up_info->errata;
|
||||
|
||||
if (omap_up_info->dma_enabled) {
|
||||
up->uart_dma.uart_dma_tx = dma_tx->start;
|
||||
|
@ -1469,6 +1539,8 @@ static int serial_omap_probe(struct platform_device *pdev)
|
|||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
omap_serial_fill_features_erratas(up);
|
||||
|
||||
ui[up->port.line] = up;
|
||||
serial_omap_add_console_port(up);
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ enum {
|
|||
PCH_UART_HANDLED_RX_ERR_INT_SHIFT,
|
||||
PCH_UART_HANDLED_RX_TRG_INT_SHIFT,
|
||||
PCH_UART_HANDLED_MS_INT_SHIFT,
|
||||
PCH_UART_HANDLED_LS_INT_SHIFT,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -63,6 +64,8 @@ enum {
|
|||
PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1))
|
||||
#define PCH_UART_HANDLED_MS_INT (1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1))
|
||||
|
||||
#define PCH_UART_HANDLED_LS_INT (1<<((PCH_UART_HANDLED_LS_INT_SHIFT)<<1))
|
||||
|
||||
#define PCH_UART_RBR 0x00
|
||||
#define PCH_UART_THR 0x00
|
||||
|
||||
|
@ -229,7 +232,6 @@ struct eg20t_port {
|
|||
int start_tx;
|
||||
int start_rx;
|
||||
int tx_empty;
|
||||
int int_dis_flag;
|
||||
int trigger;
|
||||
int trigger_level;
|
||||
struct pch_uart_buffer rxbuf;
|
||||
|
@ -237,7 +239,6 @@ struct eg20t_port {
|
|||
unsigned int fcr;
|
||||
unsigned int mcr;
|
||||
unsigned int use_dma;
|
||||
unsigned int use_dma_flag;
|
||||
struct dma_async_tx_descriptor *desc_tx;
|
||||
struct dma_async_tx_descriptor *desc_rx;
|
||||
struct pch_dma_slave param_tx;
|
||||
|
@ -560,14 +561,10 @@ static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf,
|
|||
return i;
|
||||
}
|
||||
|
||||
static unsigned int pch_uart_hal_get_iid(struct eg20t_port *priv)
|
||||
static unsigned char pch_uart_hal_get_iid(struct eg20t_port *priv)
|
||||
{
|
||||
unsigned int iir;
|
||||
int ret;
|
||||
|
||||
iir = ioread8(priv->membase + UART_IIR);
|
||||
ret = (iir & (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP));
|
||||
return ret;
|
||||
return ioread8(priv->membase + UART_IIR) &\
|
||||
(PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP);
|
||||
}
|
||||
|
||||
static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv)
|
||||
|
@ -666,10 +663,13 @@ static void pch_free_dma(struct uart_port *port)
|
|||
dma_release_channel(priv->chan_rx);
|
||||
priv->chan_rx = NULL;
|
||||
}
|
||||
if (sg_dma_address(&priv->sg_rx))
|
||||
dma_free_coherent(port->dev, port->fifosize,
|
||||
sg_virt(&priv->sg_rx),
|
||||
sg_dma_address(&priv->sg_rx));
|
||||
|
||||
if (priv->rx_buf_dma) {
|
||||
dma_free_coherent(port->dev, port->fifosize, priv->rx_buf_virt,
|
||||
priv->rx_buf_dma);
|
||||
priv->rx_buf_virt = NULL;
|
||||
priv->rx_buf_dma = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -1053,12 +1053,17 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
|
|||
unsigned int handled;
|
||||
u8 lsr;
|
||||
int ret = 0;
|
||||
unsigned int iid;
|
||||
unsigned char iid;
|
||||
unsigned long flags;
|
||||
int next = 1;
|
||||
u8 msr;
|
||||
|
||||
spin_lock_irqsave(&priv->port.lock, flags);
|
||||
handled = 0;
|
||||
while ((iid = pch_uart_hal_get_iid(priv)) > 1) {
|
||||
while (next) {
|
||||
iid = pch_uart_hal_get_iid(priv);
|
||||
if (iid & PCH_UART_IIR_IP) /* No Interrupt */
|
||||
break;
|
||||
switch (iid) {
|
||||
case PCH_UART_IID_RLS: /* Receiver Line Status */
|
||||
lsr = pch_uart_hal_get_line_status(priv);
|
||||
|
@ -1066,6 +1071,8 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
|
|||
UART_LSR_PE | UART_LSR_OE)) {
|
||||
pch_uart_err_ir(priv, lsr);
|
||||
ret = PCH_UART_HANDLED_RX_ERR_INT;
|
||||
} else {
|
||||
ret = PCH_UART_HANDLED_LS_INT;
|
||||
}
|
||||
break;
|
||||
case PCH_UART_IID_RDR: /* Received Data Ready */
|
||||
|
@ -1092,20 +1099,22 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
|
|||
ret = handle_tx(priv);
|
||||
break;
|
||||
case PCH_UART_IID_MS: /* Modem Status */
|
||||
ret = PCH_UART_HANDLED_MS_INT;
|
||||
msr = pch_uart_hal_get_modem(priv);
|
||||
next = 0; /* MS ir prioirty is the lowest. So, MS ir
|
||||
means final interrupt */
|
||||
if ((msr & UART_MSR_ANY_DELTA) == 0)
|
||||
break;
|
||||
ret |= PCH_UART_HANDLED_MS_INT;
|
||||
break;
|
||||
default: /* Never junp to this label */
|
||||
dev_err(priv->port.dev, "%s:iid=%d (%lu)\n", __func__,
|
||||
dev_err(priv->port.dev, "%s:iid=%02x (%lu)\n", __func__,
|
||||
iid, jiffies);
|
||||
ret = -1;
|
||||
next = 0;
|
||||
break;
|
||||
}
|
||||
handled |= (unsigned int)ret;
|
||||
}
|
||||
if (handled == 0 && iid <= 1) {
|
||||
if (priv->int_dis_flag)
|
||||
priv->int_dis_flag = 0;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&priv->port.lock, flags);
|
||||
return IRQ_RETVAL(handled);
|
||||
|
@ -1200,7 +1209,6 @@ static void pch_uart_stop_rx(struct uart_port *port)
|
|||
priv = container_of(port, struct eg20t_port, port);
|
||||
priv->start_rx = 0;
|
||||
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
|
||||
priv->int_dis_flag = 1;
|
||||
}
|
||||
|
||||
/* Enable the modem status interrupts. */
|
||||
|
@ -1447,7 +1455,6 @@ static int pch_uart_verify_port(struct uart_port *port,
|
|||
__func__);
|
||||
return -EOPNOTSUPP;
|
||||
#endif
|
||||
priv->use_dma_flag = 1;
|
||||
dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n");
|
||||
if (!priv->use_dma)
|
||||
pch_request_dma(port);
|
||||
|
|
|
@ -2282,6 +2282,7 @@ void uart_unregister_driver(struct uart_driver *drv)
|
|||
tty_unregister_driver(p);
|
||||
put_tty_driver(p);
|
||||
kfree(drv->state);
|
||||
drv->state = NULL;
|
||||
drv->tty_driver = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -3338,9 +3338,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
|
|||
printk("%s(%d):block_til_ready blocking on %s count=%d\n",
|
||||
__FILE__,__LINE__, tty->driver->name, port->count );
|
||||
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
schedule();
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
}
|
||||
|
||||
set_current_state(TASK_RUNNING);
|
||||
|
|
|
@ -3336,9 +3336,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
|
|||
}
|
||||
|
||||
DBGINFO(("%s block_til_ready wait\n", tty->driver->name));
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
schedule();
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
}
|
||||
|
||||
set_current_state(TASK_RUNNING);
|
||||
|
|
|
@ -3357,9 +3357,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
|
|||
printk("%s(%d):%s block_til_ready() count=%d\n",
|
||||
__FILE__,__LINE__, tty->driver->name, port->count );
|
||||
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
schedule();
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
}
|
||||
|
||||
set_current_state(TASK_RUNNING);
|
||||
|
|
|
@ -185,25 +185,19 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
|
|||
/* Should possibly check if this fails for the largest buffer we
|
||||
have queued and recycle that ? */
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_buffer_request_room - grow tty buffer if needed
|
||||
* __tty_buffer_request_room - grow tty buffer if needed
|
||||
* @tty: tty structure
|
||||
* @size: size desired
|
||||
*
|
||||
* Make at least size bytes of linear space available for the tty
|
||||
* buffer. If we fail return the size we managed to find.
|
||||
*
|
||||
* Locking: Takes tty->buf.lock
|
||||
* Locking: Caller must hold tty->buf.lock
|
||||
*/
|
||||
int tty_buffer_request_room(struct tty_struct *tty, size_t size)
|
||||
static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)
|
||||
{
|
||||
struct tty_buffer *b, *n;
|
||||
int left;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&tty->buf.lock, flags);
|
||||
|
||||
/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
|
||||
remove this conditional if its worth it. This would be invisible
|
||||
to the callers */
|
||||
|
@ -225,9 +219,30 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
|
|||
size = left;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&tty->buf.lock, flags);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tty_buffer_request_room - grow tty buffer if needed
|
||||
* @tty: tty structure
|
||||
* @size: size desired
|
||||
*
|
||||
* Make at least size bytes of linear space available for the tty
|
||||
* buffer. If we fail return the size we managed to find.
|
||||
*
|
||||
* Locking: Takes tty->buf.lock
|
||||
*/
|
||||
int tty_buffer_request_room(struct tty_struct *tty, size_t size)
|
||||
{
|
||||
unsigned long flags;
|
||||
int length;
|
||||
|
||||
spin_lock_irqsave(&tty->buf.lock, flags);
|
||||
length = __tty_buffer_request_room(tty, size);
|
||||
spin_unlock_irqrestore(&tty->buf.lock, flags);
|
||||
return length;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_buffer_request_room);
|
||||
|
||||
/**
|
||||
|
@ -249,14 +264,22 @@ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
|
|||
int copied = 0;
|
||||
do {
|
||||
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
|
||||
int space = tty_buffer_request_room(tty, goal);
|
||||
struct tty_buffer *tb = tty->buf.tail;
|
||||
int space;
|
||||
unsigned long flags;
|
||||
struct tty_buffer *tb;
|
||||
|
||||
spin_lock_irqsave(&tty->buf.lock, flags);
|
||||
space = __tty_buffer_request_room(tty, goal);
|
||||
tb = tty->buf.tail;
|
||||
/* If there is no space then tb may be NULL */
|
||||
if (unlikely(space == 0))
|
||||
if (unlikely(space == 0)) {
|
||||
spin_unlock_irqrestore(&tty->buf.lock, flags);
|
||||
break;
|
||||
}
|
||||
memcpy(tb->char_buf_ptr + tb->used, chars, space);
|
||||
memset(tb->flag_buf_ptr + tb->used, flag, space);
|
||||
tb->used += space;
|
||||
spin_unlock_irqrestore(&tty->buf.lock, flags);
|
||||
copied += space;
|
||||
chars += space;
|
||||
/* There is a small chance that we need to split the data over
|
||||
|
@ -286,14 +309,22 @@ int tty_insert_flip_string_flags(struct tty_struct *tty,
|
|||
int copied = 0;
|
||||
do {
|
||||
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
|
||||
int space = tty_buffer_request_room(tty, goal);
|
||||
struct tty_buffer *tb = tty->buf.tail;
|
||||
int space;
|
||||
unsigned long __flags;
|
||||
struct tty_buffer *tb;
|
||||
|
||||
spin_lock_irqsave(&tty->buf.lock, __flags);
|
||||
space = __tty_buffer_request_room(tty, goal);
|
||||
tb = tty->buf.tail;
|
||||
/* If there is no space then tb may be NULL */
|
||||
if (unlikely(space == 0))
|
||||
if (unlikely(space == 0)) {
|
||||
spin_unlock_irqrestore(&tty->buf.lock, __flags);
|
||||
break;
|
||||
}
|
||||
memcpy(tb->char_buf_ptr + tb->used, chars, space);
|
||||
memcpy(tb->flag_buf_ptr + tb->used, flags, space);
|
||||
tb->used += space;
|
||||
spin_unlock_irqrestore(&tty->buf.lock, __flags);
|
||||
copied += space;
|
||||
chars += space;
|
||||
flags += space;
|
||||
|
@ -344,13 +375,20 @@ EXPORT_SYMBOL(tty_schedule_flip);
|
|||
int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
|
||||
size_t size)
|
||||
{
|
||||
int space = tty_buffer_request_room(tty, size);
|
||||
int space;
|
||||
unsigned long flags;
|
||||
struct tty_buffer *tb;
|
||||
|
||||
spin_lock_irqsave(&tty->buf.lock, flags);
|
||||
space = __tty_buffer_request_room(tty, size);
|
||||
|
||||
tb = tty->buf.tail;
|
||||
if (likely(space)) {
|
||||
struct tty_buffer *tb = tty->buf.tail;
|
||||
*chars = tb->char_buf_ptr + tb->used;
|
||||
memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
|
||||
tb->used += space;
|
||||
}
|
||||
spin_unlock_irqrestore(&tty->buf.lock, flags);
|
||||
return space;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
|
||||
|
@ -374,13 +412,20 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
|
|||
int tty_prepare_flip_string_flags(struct tty_struct *tty,
|
||||
unsigned char **chars, char **flags, size_t size)
|
||||
{
|
||||
int space = tty_buffer_request_room(tty, size);
|
||||
int space;
|
||||
unsigned long __flags;
|
||||
struct tty_buffer *tb;
|
||||
|
||||
spin_lock_irqsave(&tty->buf.lock, __flags);
|
||||
space = __tty_buffer_request_room(tty, size);
|
||||
|
||||
tb = tty->buf.tail;
|
||||
if (likely(space)) {
|
||||
struct tty_buffer *tb = tty->buf.tail;
|
||||
*chars = tb->char_buf_ptr + tb->used;
|
||||
*flags = tb->flag_buf_ptr + tb->used;
|
||||
tb->used += space;
|
||||
}
|
||||
spin_unlock_irqrestore(&tty->buf.lock, __flags);
|
||||
return space;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
|
||||
|
|
|
@ -185,6 +185,7 @@ void free_tty_struct(struct tty_struct *tty)
|
|||
put_device(tty->dev);
|
||||
kfree(tty->write_buf);
|
||||
tty_buffer_free_all(tty);
|
||||
tty->magic = 0xDEADDEAD;
|
||||
kfree(tty);
|
||||
}
|
||||
|
||||
|
@ -573,7 +574,7 @@ void __tty_hangup(struct tty_struct *tty)
|
|||
}
|
||||
spin_unlock(&redirect_lock);
|
||||
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
|
||||
/* some functions below drop BTM, so we need this bit */
|
||||
set_bit(TTY_HUPPING, &tty->flags);
|
||||
|
@ -666,7 +667,7 @@ void __tty_hangup(struct tty_struct *tty)
|
|||
clear_bit(TTY_HUPPING, &tty->flags);
|
||||
tty_ldisc_enable(tty);
|
||||
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
|
||||
if (f)
|
||||
fput(f);
|
||||
|
@ -855,10 +856,11 @@ void disassociate_ctty(int on_exit)
|
|||
*/
|
||||
void no_tty(void)
|
||||
{
|
||||
/* FIXME: Review locking here. The tty_lock never covered any race
|
||||
between a new association and proc_clear_tty but possible we need
|
||||
to protect against this anyway */
|
||||
struct task_struct *tsk = current;
|
||||
tty_lock();
|
||||
disassociate_ctty(0);
|
||||
tty_unlock();
|
||||
proc_clear_tty(tsk);
|
||||
}
|
||||
|
||||
|
@ -1102,12 +1104,12 @@ void tty_write_message(struct tty_struct *tty, char *msg)
|
|||
{
|
||||
if (tty) {
|
||||
mutex_lock(&tty->atomic_write_lock);
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
tty->ops->write(tty, msg, strlen(msg));
|
||||
} else
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
tty_write_unlock(tty);
|
||||
}
|
||||
return;
|
||||
|
@ -1402,6 +1404,7 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
|
|||
}
|
||||
initialize_tty_struct(tty, driver, idx);
|
||||
|
||||
tty_lock(tty);
|
||||
retval = tty_driver_install_tty(driver, tty);
|
||||
if (retval < 0)
|
||||
goto err_deinit_tty;
|
||||
|
@ -1414,9 +1417,11 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
|
|||
retval = tty_ldisc_setup(tty, tty->link);
|
||||
if (retval)
|
||||
goto err_release_tty;
|
||||
/* Return the tty locked so that it cannot vanish under the caller */
|
||||
return tty;
|
||||
|
||||
err_deinit_tty:
|
||||
tty_unlock(tty);
|
||||
deinitialize_tty_struct(tty);
|
||||
free_tty_struct(tty);
|
||||
err_module_put:
|
||||
|
@ -1425,6 +1430,7 @@ err_module_put:
|
|||
|
||||
/* call the tty release_tty routine to clean out this slot */
|
||||
err_release_tty:
|
||||
tty_unlock(tty);
|
||||
printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, "
|
||||
"clearing slot %d\n", idx);
|
||||
release_tty(tty, idx);
|
||||
|
@ -1627,7 +1633,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
if (tty_paranoia_check(tty, inode, __func__))
|
||||
return 0;
|
||||
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
check_tty_count(tty, __func__);
|
||||
|
||||
__tty_fasync(-1, filp, 0);
|
||||
|
@ -1636,10 +1642,11 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||
tty->driver->subtype == PTY_TYPE_MASTER);
|
||||
devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
|
||||
/* Review: parallel close */
|
||||
o_tty = tty->link;
|
||||
|
||||
if (tty_release_checks(tty, o_tty, idx)) {
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1651,7 +1658,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
if (tty->ops->close)
|
||||
tty->ops->close(tty, filp);
|
||||
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
/*
|
||||
* Sanity check: if tty->count is going to zero, there shouldn't be
|
||||
* any waiters on tty->read_wait or tty->write_wait. We test the
|
||||
|
@ -1674,7 +1681,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
opens on /dev/tty */
|
||||
|
||||
mutex_lock(&tty_mutex);
|
||||
tty_lock();
|
||||
tty_lock_pair(tty, o_tty);
|
||||
tty_closing = tty->count <= 1;
|
||||
o_tty_closing = o_tty &&
|
||||
(o_tty->count <= (pty_master ? 1 : 0));
|
||||
|
@ -1705,7 +1712,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
|
||||
printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",
|
||||
__func__, tty_name(tty, buf));
|
||||
tty_unlock();
|
||||
tty_unlock_pair(tty, o_tty);
|
||||
mutex_unlock(&tty_mutex);
|
||||
schedule();
|
||||
}
|
||||
|
@ -1768,7 +1775,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
|
||||
/* check whether both sides are closing ... */
|
||||
if (!tty_closing || (o_tty && !o_tty_closing)) {
|
||||
tty_unlock();
|
||||
tty_unlock_pair(tty, o_tty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1781,14 +1788,16 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
tty_ldisc_release(tty, o_tty);
|
||||
/*
|
||||
* The release_tty function takes care of the details of clearing
|
||||
* the slots and preserving the termios structure.
|
||||
* the slots and preserving the termios structure. The tty_unlock_pair
|
||||
* should be safe as we keep a kref while the tty is locked (so the
|
||||
* unlock never unlocks a freed tty).
|
||||
*/
|
||||
release_tty(tty, idx);
|
||||
tty_unlock_pair(tty, o_tty);
|
||||
|
||||
/* Make this pty number available for reallocation */
|
||||
if (devpts)
|
||||
devpts_kill_index(inode, idx);
|
||||
tty_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1800,6 +1809,9 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
*
|
||||
* We cannot return driver and index like for the other nodes because
|
||||
* devpts will not work then. It expects inodes to be from devpts FS.
|
||||
*
|
||||
* We need to move to returning a refcounted object from all the lookup
|
||||
* paths including this one.
|
||||
*/
|
||||
static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
|
||||
{
|
||||
|
@ -1816,6 +1828,7 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
|
|||
/* noctty = 1; */
|
||||
tty_kref_put(tty);
|
||||
/* FIXME: we put a reference and return a TTY! */
|
||||
/* This is only safe because the caller holds tty_mutex */
|
||||
return tty;
|
||||
}
|
||||
|
||||
|
@ -1888,6 +1901,9 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
|
|||
* Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev.
|
||||
* tty->count should protect the rest.
|
||||
* ->siglock protects ->signal/->sighand
|
||||
*
|
||||
* Note: the tty_unlock/lock cases without a ref are only safe due to
|
||||
* tty_mutex
|
||||
*/
|
||||
|
||||
static int tty_open(struct inode *inode, struct file *filp)
|
||||
|
@ -1911,8 +1927,7 @@ retry_open:
|
|||
retval = 0;
|
||||
|
||||
mutex_lock(&tty_mutex);
|
||||
tty_lock();
|
||||
|
||||
/* This is protected by the tty_mutex */
|
||||
tty = tty_open_current_tty(device, filp);
|
||||
if (IS_ERR(tty)) {
|
||||
retval = PTR_ERR(tty);
|
||||
|
@ -1933,17 +1948,19 @@ retry_open:
|
|||
}
|
||||
|
||||
if (tty) {
|
||||
tty_lock(tty);
|
||||
retval = tty_reopen(tty);
|
||||
if (retval)
|
||||
if (retval < 0) {
|
||||
tty_unlock(tty);
|
||||
tty = ERR_PTR(retval);
|
||||
} else
|
||||
}
|
||||
} else /* Returns with the tty_lock held for now */
|
||||
tty = tty_init_dev(driver, index);
|
||||
|
||||
mutex_unlock(&tty_mutex);
|
||||
if (driver)
|
||||
tty_driver_kref_put(driver);
|
||||
if (IS_ERR(tty)) {
|
||||
tty_unlock();
|
||||
retval = PTR_ERR(tty);
|
||||
goto err_file;
|
||||
}
|
||||
|
@ -1972,7 +1989,7 @@ retry_open:
|
|||
printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__,
|
||||
retval, tty->name);
|
||||
#endif
|
||||
tty_unlock(); /* need to call tty_release without BTM */
|
||||
tty_unlock(tty); /* need to call tty_release without BTM */
|
||||
tty_release(inode, filp);
|
||||
if (retval != -ERESTARTSYS)
|
||||
return retval;
|
||||
|
@ -1984,17 +2001,15 @@ retry_open:
|
|||
/*
|
||||
* Need to reset f_op in case a hangup happened.
|
||||
*/
|
||||
tty_lock();
|
||||
if (filp->f_op == &hung_up_tty_fops)
|
||||
filp->f_op = &tty_fops;
|
||||
tty_unlock();
|
||||
goto retry_open;
|
||||
}
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
|
||||
|
||||
mutex_lock(&tty_mutex);
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
if (!noctty &&
|
||||
current->signal->leader &&
|
||||
|
@ -2002,11 +2017,10 @@ retry_open:
|
|||
tty->session == NULL)
|
||||
__proc_set_tty(current, tty);
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
mutex_unlock(&tty_mutex);
|
||||
return 0;
|
||||
err_unlock:
|
||||
tty_unlock();
|
||||
mutex_unlock(&tty_mutex);
|
||||
/* after locks to avoid deadlock */
|
||||
if (!IS_ERR_OR_NULL(driver))
|
||||
|
@ -2089,10 +2103,13 @@ out:
|
|||
|
||||
static int tty_fasync(int fd, struct file *filp, int on)
|
||||
{
|
||||
struct tty_struct *tty = file_tty(filp);
|
||||
int retval;
|
||||
tty_lock();
|
||||
|
||||
tty_lock(tty);
|
||||
retval = __tty_fasync(fd, filp, on);
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -2929,6 +2946,7 @@ void initialize_tty_struct(struct tty_struct *tty,
|
|||
tty->pgrp = NULL;
|
||||
tty->overrun_time = jiffies;
|
||||
tty_buffer_init(tty);
|
||||
mutex_init(&tty->legacy_mutex);
|
||||
mutex_init(&tty->termios_mutex);
|
||||
mutex_init(&tty->ldisc_mutex);
|
||||
init_waitqueue_head(&tty->write_wait);
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
|
||||
static DEFINE_SPINLOCK(tty_ldisc_lock);
|
||||
static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
|
||||
static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_idle);
|
||||
/* Line disc dispatch table */
|
||||
static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
|
||||
|
||||
|
@ -65,7 +64,7 @@ static void put_ldisc(struct tty_ldisc *ld)
|
|||
return;
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
wake_up(&tty_ldisc_idle);
|
||||
wake_up(&ld->wq_idle);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -200,6 +199,8 @@ static struct tty_ldisc *tty_ldisc_get(int disc)
|
|||
|
||||
ld->ops = ldops;
|
||||
atomic_set(&ld->users, 1);
|
||||
init_waitqueue_head(&ld->wq_idle);
|
||||
|
||||
return ld;
|
||||
}
|
||||
|
||||
|
@ -538,7 +539,7 @@ static void tty_ldisc_flush_works(struct tty_struct *tty)
|
|||
static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)
|
||||
{
|
||||
long ret;
|
||||
ret = wait_event_timeout(tty_ldisc_idle,
|
||||
ret = wait_event_timeout(tty->ldisc->wq_idle,
|
||||
atomic_read(&tty->ldisc->users) == 1, timeout);
|
||||
return ret > 0 ? 0 : -EBUSY;
|
||||
}
|
||||
|
@ -567,7 +568,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|||
if (IS_ERR(new_ldisc))
|
||||
return PTR_ERR(new_ldisc);
|
||||
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
/*
|
||||
* We need to look at the tty locking here for pty/tty pairs
|
||||
* when both sides try to change in parallel.
|
||||
|
@ -581,12 +582,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|||
*/
|
||||
|
||||
if (tty->ldisc->ops->num == ldisc) {
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
tty_ldisc_put(new_ldisc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
/*
|
||||
* Problem: What do we do if this blocks ?
|
||||
* We could deadlock here
|
||||
|
@ -594,7 +595,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|||
|
||||
tty_wait_until_sent(tty, 0);
|
||||
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
|
||||
/*
|
||||
|
@ -604,10 +605,10 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|||
|
||||
while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
wait_event(tty_ldisc_wait,
|
||||
test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
}
|
||||
|
||||
|
@ -622,7 +623,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|||
|
||||
o_ldisc = tty->ldisc;
|
||||
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
/*
|
||||
* Make sure we don't change while someone holds a
|
||||
* reference to the line discipline. The TTY_LDISC bit
|
||||
|
@ -649,7 +650,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|||
|
||||
retval = tty_ldisc_wait_idle(tty, 5 * HZ);
|
||||
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
|
||||
/* handle wait idle failure locked */
|
||||
|
@ -664,7 +665,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|||
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
tty_ldisc_put(new_ldisc);
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -707,7 +708,7 @@ enable:
|
|||
if (o_work)
|
||||
schedule_work(&o_tty->buf.work);
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -815,11 +816,11 @@ void tty_ldisc_hangup(struct tty_struct *tty)
|
|||
* need to wait for another function taking the BTM
|
||||
*/
|
||||
clear_bit(TTY_LDISC, &tty->flags);
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
cancel_work_sync(&tty->buf.work);
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
retry:
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
|
||||
/* At this point we have a closed ldisc and we want to
|
||||
|
@ -830,7 +831,7 @@ retry:
|
|||
if (atomic_read(&tty->ldisc->users) != 1) {
|
||||
char cur_n[TASK_COMM_LEN], tty_n[64];
|
||||
long timeout = 3 * HZ;
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
|
||||
while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
|
||||
timeout = MAX_SCHEDULE_TIMEOUT;
|
||||
|
@ -911,10 +912,10 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
|
|||
* race with the set_ldisc code path.
|
||||
*/
|
||||
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
tty_ldisc_halt(tty);
|
||||
tty_ldisc_flush_works(tty);
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
/*
|
||||
|
|
|
@ -4,29 +4,59 @@
|
|||
#include <linux/semaphore.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
/*
|
||||
* The 'big tty mutex'
|
||||
*
|
||||
* This mutex is taken and released by tty_lock() and tty_unlock(),
|
||||
* replacing the older big kernel lock.
|
||||
* It can no longer be taken recursively, and does not get
|
||||
* released implicitly while sleeping.
|
||||
*
|
||||
* Don't use in new code.
|
||||
*/
|
||||
static DEFINE_MUTEX(big_tty_mutex);
|
||||
/* Legacy tty mutex glue */
|
||||
|
||||
/*
|
||||
* Getting the big tty mutex.
|
||||
*/
|
||||
void __lockfunc tty_lock(void)
|
||||
|
||||
void __lockfunc tty_lock(struct tty_struct *tty)
|
||||
{
|
||||
mutex_lock(&big_tty_mutex);
|
||||
if (tty->magic != TTY_MAGIC) {
|
||||
printk(KERN_ERR "L Bad %p\n", tty);
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
tty_kref_get(tty);
|
||||
mutex_lock(&tty->legacy_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_lock);
|
||||
|
||||
void __lockfunc tty_unlock(void)
|
||||
void __lockfunc tty_unlock(struct tty_struct *tty)
|
||||
{
|
||||
mutex_unlock(&big_tty_mutex);
|
||||
if (tty->magic != TTY_MAGIC) {
|
||||
printk(KERN_ERR "U Bad %p\n", tty);
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
mutex_unlock(&tty->legacy_mutex);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_unlock);
|
||||
|
||||
/*
|
||||
* Getting the big tty mutex for a pair of ttys with lock ordering
|
||||
* On a non pty/tty pair tty2 can be NULL which is just fine.
|
||||
*/
|
||||
void __lockfunc tty_lock_pair(struct tty_struct *tty,
|
||||
struct tty_struct *tty2)
|
||||
{
|
||||
if (tty < tty2) {
|
||||
tty_lock(tty);
|
||||
tty_lock(tty2);
|
||||
} else {
|
||||
if (tty2 && tty2 != tty)
|
||||
tty_lock(tty2);
|
||||
tty_lock(tty);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(tty_lock_pair);
|
||||
|
||||
void __lockfunc tty_unlock_pair(struct tty_struct *tty,
|
||||
struct tty_struct *tty2)
|
||||
{
|
||||
tty_unlock(tty);
|
||||
if (tty2 && tty2 != tty)
|
||||
tty_unlock(tty2);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_unlock_pair);
|
||||
|
|
|
@ -230,7 +230,7 @@ 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) {
|
||||
wait_event_interruptible_tty(port->close_wait,
|
||||
wait_event_interruptible_tty(tty, port->close_wait,
|
||||
!(port->flags & ASYNC_CLOSING));
|
||||
if (port->flags & ASYNC_HUP_NOTIFY)
|
||||
return -EAGAIN;
|
||||
|
@ -296,9 +296,9 @@ int tty_port_block_til_ready(struct tty_port *port,
|
|||
retval = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
schedule();
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
}
|
||||
finish_wait(&port->open_wait, &wait);
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/tty.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/consolemap.h>
|
||||
#include <linux/vt_kern.h>
|
||||
|
||||
|
@ -312,6 +313,7 @@ int con_set_trans_old(unsigned char __user * arg)
|
|||
if (!access_ok(VERIFY_READ, arg, E_TABSZ))
|
||||
return -EFAULT;
|
||||
|
||||
console_lock();
|
||||
for (i=0; i<E_TABSZ ; i++) {
|
||||
unsigned char uc;
|
||||
__get_user(uc, arg+i);
|
||||
|
@ -319,6 +321,7 @@ int con_set_trans_old(unsigned char __user * arg)
|
|||
}
|
||||
|
||||
update_user_maps();
|
||||
console_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -330,11 +333,13 @@ int con_get_trans_old(unsigned char __user * arg)
|
|||
if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
|
||||
return -EFAULT;
|
||||
|
||||
console_lock();
|
||||
for (i=0; i<E_TABSZ ; i++)
|
||||
{
|
||||
ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
|
||||
__put_user((ch & ~0xff) ? 0 : ch, arg+i);
|
||||
}
|
||||
{
|
||||
ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
|
||||
__put_user((ch & ~0xff) ? 0 : ch, arg+i);
|
||||
}
|
||||
console_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -346,6 +351,7 @@ int con_set_trans_new(ushort __user * arg)
|
|||
if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
|
||||
return -EFAULT;
|
||||
|
||||
console_lock();
|
||||
for (i=0; i<E_TABSZ ; i++) {
|
||||
unsigned short us;
|
||||
__get_user(us, arg+i);
|
||||
|
@ -353,6 +359,7 @@ int con_set_trans_new(ushort __user * arg)
|
|||
}
|
||||
|
||||
update_user_maps();
|
||||
console_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -364,8 +371,10 @@ int con_get_trans_new(ushort __user * arg)
|
|||
if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
|
||||
return -EFAULT;
|
||||
|
||||
console_lock();
|
||||
for (i=0; i<E_TABSZ ; i++)
|
||||
__put_user(p[i], arg+i);
|
||||
console_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -407,6 +416,7 @@ static void con_release_unimap(struct uni_pagedir *p)
|
|||
}
|
||||
}
|
||||
|
||||
/* Caller must hold the console lock */
|
||||
void con_free_unimap(struct vc_data *vc)
|
||||
{
|
||||
struct uni_pagedir *p;
|
||||
|
@ -487,17 +497,21 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* ui is a leftover from using a hashtable, but might be used again */
|
||||
int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
|
||||
/* ui is a leftover from using a hashtable, but might be used again
|
||||
Caller must hold the lock */
|
||||
static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
|
||||
{
|
||||
struct uni_pagedir *p, *q;
|
||||
|
||||
|
||||
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
||||
if (p && p->readonly) return -EIO;
|
||||
if (p && p->readonly)
|
||||
return -EIO;
|
||||
|
||||
if (!p || --p->refcount) {
|
||||
q = kzalloc(sizeof(*p), GFP_KERNEL);
|
||||
if (!q) {
|
||||
if (p) p->refcount++;
|
||||
if (p)
|
||||
p->refcount++;
|
||||
return -ENOMEM;
|
||||
}
|
||||
q->refcount=1;
|
||||
|
@ -511,23 +525,43 @@ int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
|
||||
{
|
||||
int ret;
|
||||
console_lock();
|
||||
ret = con_do_clear_unimap(vc, ui);
|
||||
console_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
||||
{
|
||||
int err = 0, err1, i;
|
||||
struct uni_pagedir *p, *q;
|
||||
|
||||
console_lock();
|
||||
|
||||
/* Save original vc_unipagdir_loc in case we allocate a new one */
|
||||
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
||||
if (p->readonly) return -EIO;
|
||||
if (p->readonly) {
|
||||
console_unlock();
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!ct) return 0;
|
||||
if (!ct) {
|
||||
console_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (p->refcount > 1) {
|
||||
int j, k;
|
||||
u16 **p1, *p2, l;
|
||||
|
||||
err1 = con_clear_unimap(vc, NULL);
|
||||
if (err1) return err1;
|
||||
err1 = con_do_clear_unimap(vc, NULL);
|
||||
if (err1) {
|
||||
console_unlock();
|
||||
return err1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since refcount was > 1, con_clear_unimap() allocated a
|
||||
|
@ -558,7 +592,8 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
|||
*vc->vc_uni_pagedir_loc = (unsigned long)p;
|
||||
con_release_unimap(q);
|
||||
kfree(q);
|
||||
return err1;
|
||||
console_unlock();
|
||||
return err1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -592,21 +627,30 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
|||
/*
|
||||
* Merge with fontmaps of any other virtual consoles.
|
||||
*/
|
||||
if (con_unify_unimap(vc, p))
|
||||
if (con_unify_unimap(vc, p)) {
|
||||
console_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i <= 3; i++)
|
||||
set_inverse_transl(vc, p, i); /* Update inverse translations */
|
||||
set_inverse_trans_unicode(vc, p);
|
||||
|
||||
|
||||
console_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
|
||||
The representation used was the most compact I could come up
|
||||
with. This routine is executed at sys_setup time, and when the
|
||||
PIO_FONTRESET ioctl is called. */
|
||||
|
||||
/**
|
||||
* con_set_default_unimap - set default unicode map
|
||||
* @vc: the console we are updating
|
||||
*
|
||||
* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
|
||||
* The representation used was the most compact I could come up
|
||||
* with. This routine is executed at video setup, and when the
|
||||
* PIO_FONTRESET ioctl is called.
|
||||
*
|
||||
* The caller must hold the console lock
|
||||
*/
|
||||
int con_set_default_unimap(struct vc_data *vc)
|
||||
{
|
||||
int i, j, err = 0, err1;
|
||||
|
@ -617,6 +661,7 @@ int con_set_default_unimap(struct vc_data *vc)
|
|||
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
||||
if (p == dflt)
|
||||
return 0;
|
||||
|
||||
dflt->refcount++;
|
||||
*vc->vc_uni_pagedir_loc = (unsigned long)dflt;
|
||||
if (p && !--p->refcount) {
|
||||
|
@ -628,8 +673,9 @@ int con_set_default_unimap(struct vc_data *vc)
|
|||
|
||||
/* The default font is always 256 characters */
|
||||
|
||||
err = con_clear_unimap(vc, NULL);
|
||||
if (err) return err;
|
||||
err = con_do_clear_unimap(vc, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
||||
q = dfont_unitable;
|
||||
|
@ -654,6 +700,13 @@ int con_set_default_unimap(struct vc_data *vc)
|
|||
}
|
||||
EXPORT_SYMBOL(con_set_default_unimap);
|
||||
|
||||
/**
|
||||
* con_copy_unimap - copy unimap between two vts
|
||||
* @dst_vc: target
|
||||
* @src_vt: source
|
||||
*
|
||||
* The caller must hold the console lock when invoking this method
|
||||
*/
|
||||
int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
|
||||
{
|
||||
struct uni_pagedir *q;
|
||||
|
@ -668,13 +721,23 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
|
|||
*dst_vc->vc_uni_pagedir_loc = (long)q;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(con_copy_unimap);
|
||||
|
||||
/**
|
||||
* con_get_unimap - get the unicode map
|
||||
* @vc: the console to read from
|
||||
*
|
||||
* Read the console unicode data for this console. Called from the ioctl
|
||||
* handlers.
|
||||
*/
|
||||
int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
|
||||
{
|
||||
int i, j, k, ect;
|
||||
u16 **p1, *p2;
|
||||
struct uni_pagedir *p;
|
||||
|
||||
console_lock();
|
||||
|
||||
ect = 0;
|
||||
if (*vc->vc_uni_pagedir_loc) {
|
||||
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
||||
|
@ -694,22 +757,19 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
|
|||
}
|
||||
}
|
||||
__put_user(ect, uct);
|
||||
console_unlock();
|
||||
return ((ect <= ct) ? 0 : -ENOMEM);
|
||||
}
|
||||
|
||||
void con_protect_unimap(struct vc_data *vc, int rdonly)
|
||||
{
|
||||
struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
|
||||
|
||||
if (p)
|
||||
p->readonly = rdonly;
|
||||
}
|
||||
|
||||
/*
|
||||
* Always use USER_MAP. These functions are used by the keyboard,
|
||||
* which shouldn't be affected by G0/G1 switching, etc.
|
||||
* If the user map still contains default values, i.e. the
|
||||
* direct-to-font mapping, then assume user is using Latin1.
|
||||
*
|
||||
* FIXME: at some point we need to decide if we want to lock the table
|
||||
* update element itself via the keyboard_event_lock for consistency with the
|
||||
* keyboard driver as well as the consoles
|
||||
*/
|
||||
/* may be called during an interrupt */
|
||||
u32 conv_8bit_to_uni(unsigned char c)
|
||||
|
@ -777,4 +837,3 @@ console_map_init(void)
|
|||
con_set_default_unimap(vc_cons[i].d);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(con_copy_unimap);
|
||||
|
|
|
@ -3892,36 +3892,6 @@ static void set_palette(struct vc_data *vc)
|
|||
vc->vc_sw->con_set_palette(vc, color_table);
|
||||
}
|
||||
|
||||
static int set_get_cmap(unsigned char __user *arg, int set)
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
if (set) {
|
||||
get_user(default_red[i], arg++);
|
||||
get_user(default_grn[i], arg++);
|
||||
get_user(default_blu[i], arg++);
|
||||
} else {
|
||||
put_user(default_red[i], arg++);
|
||||
put_user(default_grn[i], arg++);
|
||||
put_user(default_blu[i], arg++);
|
||||
}
|
||||
if (set) {
|
||||
for (i = 0; i < MAX_NR_CONSOLES; i++)
|
||||
if (vc_cons_allocated(i)) {
|
||||
for (j = k = 0; j < 16; j++) {
|
||||
vc_cons[i].d->vc_palette[k++] = default_red[j];
|
||||
vc_cons[i].d->vc_palette[k++] = default_grn[j];
|
||||
vc_cons[i].d->vc_palette[k++] = default_blu[j];
|
||||
}
|
||||
set_palette(vc_cons[i].d);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load palette into the DAC registers. arg points to a colour
|
||||
* map, 3 bytes per colour, 16 colours, range from 0 to 255.
|
||||
|
@ -3929,24 +3899,50 @@ static int set_get_cmap(unsigned char __user *arg, int set)
|
|||
|
||||
int con_set_cmap(unsigned char __user *arg)
|
||||
{
|
||||
int rc;
|
||||
int i, j, k;
|
||||
unsigned char colormap[3*16];
|
||||
|
||||
if (copy_from_user(colormap, arg, sizeof(colormap)))
|
||||
return -EFAULT;
|
||||
|
||||
console_lock();
|
||||
rc = set_get_cmap (arg,1);
|
||||
for (i = k = 0; i < 16; i++) {
|
||||
default_red[i] = colormap[k++];
|
||||
default_grn[i] = colormap[k++];
|
||||
default_blu[i] = colormap[k++];
|
||||
}
|
||||
for (i = 0; i < MAX_NR_CONSOLES; i++) {
|
||||
if (!vc_cons_allocated(i))
|
||||
continue;
|
||||
for (j = k = 0; j < 16; j++) {
|
||||
vc_cons[i].d->vc_palette[k++] = default_red[j];
|
||||
vc_cons[i].d->vc_palette[k++] = default_grn[j];
|
||||
vc_cons[i].d->vc_palette[k++] = default_blu[j];
|
||||
}
|
||||
set_palette(vc_cons[i].d);
|
||||
}
|
||||
console_unlock();
|
||||
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int con_get_cmap(unsigned char __user *arg)
|
||||
{
|
||||
int rc;
|
||||
int i, k;
|
||||
unsigned char colormap[3*16];
|
||||
|
||||
console_lock();
|
||||
rc = set_get_cmap (arg,0);
|
||||
for (i = k = 0; i < 16; i++) {
|
||||
colormap[k++] = default_red[i];
|
||||
colormap[k++] = default_grn[i];
|
||||
colormap[k++] = default_blu[i];
|
||||
}
|
||||
console_unlock();
|
||||
|
||||
return rc;
|
||||
if (copy_to_user(arg, colormap, sizeof(colormap)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reset_palette(struct vc_data *vc)
|
||||
|
|
|
@ -910,7 +910,9 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
ret = con_font_op(vc_cons[fg_console].d, &op);
|
||||
if (ret)
|
||||
break;
|
||||
console_lock();
|
||||
con_set_default_unimap(vc_cons[fg_console].d);
|
||||
console_unlock();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@ -934,33 +936,23 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
case PIO_SCRNMAP:
|
||||
if (!perm)
|
||||
ret = -EPERM;
|
||||
else {
|
||||
tty_lock();
|
||||
else
|
||||
ret = con_set_trans_old(up);
|
||||
tty_unlock();
|
||||
}
|
||||
break;
|
||||
|
||||
case GIO_SCRNMAP:
|
||||
tty_lock();
|
||||
ret = con_get_trans_old(up);
|
||||
tty_unlock();
|
||||
break;
|
||||
|
||||
case PIO_UNISCRNMAP:
|
||||
if (!perm)
|
||||
ret = -EPERM;
|
||||
else {
|
||||
tty_lock();
|
||||
else
|
||||
ret = con_set_trans_new(up);
|
||||
tty_unlock();
|
||||
}
|
||||
break;
|
||||
|
||||
case GIO_UNISCRNMAP:
|
||||
tty_lock();
|
||||
ret = con_get_trans_new(up);
|
||||
tty_unlock();
|
||||
break;
|
||||
|
||||
case PIO_UNIMAPCLR:
|
||||
|
@ -970,19 +962,14 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
|
||||
if (ret)
|
||||
ret = -EFAULT;
|
||||
else {
|
||||
tty_lock();
|
||||
else
|
||||
con_clear_unimap(vc, &ui);
|
||||
tty_unlock();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PIO_UNIMAP:
|
||||
case GIO_UNIMAP:
|
||||
tty_lock();
|
||||
ret = do_unimap_ioctl(cmd, up, perm, vc);
|
||||
tty_unlock();
|
||||
break;
|
||||
|
||||
case VT_LOCKSWITCH:
|
||||
|
@ -1196,9 +1183,7 @@ long vt_compat_ioctl(struct tty_struct *tty,
|
|||
|
||||
case PIO_UNIMAP:
|
||||
case GIO_UNIMAP:
|
||||
tty_lock();
|
||||
ret = compat_unimap_ioctl(cmd, up, perm, vc);
|
||||
tty_unlock();
|
||||
break;
|
||||
|
||||
/*
|
||||
|
|
|
@ -94,17 +94,14 @@ struct gs_buf {
|
|||
* (and thus for each /dev/ node).
|
||||
*/
|
||||
struct gs_port {
|
||||
struct tty_port port;
|
||||
spinlock_t port_lock; /* guard port_* access */
|
||||
|
||||
struct gserial *port_usb;
|
||||
struct tty_struct *port_tty;
|
||||
|
||||
unsigned open_count;
|
||||
bool openclose; /* open/close in progress */
|
||||
u8 port_num;
|
||||
|
||||
wait_queue_head_t close_wait; /* wait for last close */
|
||||
|
||||
struct list_head read_pool;
|
||||
int read_started;
|
||||
int read_allocated;
|
||||
|
@ -412,8 +409,8 @@ __acquires(&port->port_lock)
|
|||
break;
|
||||
}
|
||||
|
||||
if (do_tty_wake && port->port_tty)
|
||||
tty_wakeup(port->port_tty);
|
||||
if (do_tty_wake && port->port.tty)
|
||||
tty_wakeup(port->port.tty);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -435,7 +432,7 @@ __acquires(&port->port_lock)
|
|||
struct tty_struct *tty;
|
||||
|
||||
/* no more rx if closed */
|
||||
tty = port->port_tty;
|
||||
tty = port->port.tty;
|
||||
if (!tty)
|
||||
break;
|
||||
|
||||
|
@ -488,7 +485,7 @@ static void gs_rx_push(unsigned long _port)
|
|||
|
||||
/* hand any queued data to the tty */
|
||||
spin_lock_irq(&port->port_lock);
|
||||
tty = port->port_tty;
|
||||
tty = port->port.tty;
|
||||
while (!list_empty(queue)) {
|
||||
struct usb_request *req;
|
||||
|
||||
|
@ -699,7 +696,7 @@ static int gs_start_io(struct gs_port *port)
|
|||
|
||||
/* unblock any pending writes into our circular buffer */
|
||||
if (started) {
|
||||
tty_wakeup(port->port_tty);
|
||||
tty_wakeup(port->port.tty);
|
||||
} else {
|
||||
gs_free_requests(ep, head, &port->read_allocated);
|
||||
gs_free_requests(port->port_usb->in, &port->write_pool,
|
||||
|
@ -734,9 +731,9 @@ static int gs_open(struct tty_struct *tty, struct file *file)
|
|||
spin_lock_irq(&port->port_lock);
|
||||
|
||||
/* already open? Great. */
|
||||
if (port->open_count) {
|
||||
if (port->port.count) {
|
||||
status = 0;
|
||||
port->open_count++;
|
||||
port->port.count++;
|
||||
|
||||
/* currently opening/closing? wait ... */
|
||||
} else if (port->openclose) {
|
||||
|
@ -793,9 +790,9 @@ static int gs_open(struct tty_struct *tty, struct file *file)
|
|||
/* REVISIT maybe wait for "carrier detect" */
|
||||
|
||||
tty->driver_data = port;
|
||||
port->port_tty = tty;
|
||||
port->port.tty = tty;
|
||||
|
||||
port->open_count = 1;
|
||||
port->port.count = 1;
|
||||
port->openclose = false;
|
||||
|
||||
/* if connected, start the I/O stream */
|
||||
|
@ -837,11 +834,11 @@ static void gs_close(struct tty_struct *tty, struct file *file)
|
|||
|
||||
spin_lock_irq(&port->port_lock);
|
||||
|
||||
if (port->open_count != 1) {
|
||||
if (port->open_count == 0)
|
||||
if (port->port.count != 1) {
|
||||
if (port->port.count == 0)
|
||||
WARN_ON(1);
|
||||
else
|
||||
--port->open_count;
|
||||
--port->port.count;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
@ -851,7 +848,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
|
|||
* and sleep if necessary
|
||||
*/
|
||||
port->openclose = true;
|
||||
port->open_count = 0;
|
||||
port->port.count = 0;
|
||||
|
||||
gser = port->port_usb;
|
||||
if (gser && gser->disconnect)
|
||||
|
@ -879,14 +876,14 @@ static void gs_close(struct tty_struct *tty, struct file *file)
|
|||
gs_buf_clear(&port->port_write_buf);
|
||||
|
||||
tty->driver_data = NULL;
|
||||
port->port_tty = NULL;
|
||||
port->port.tty = NULL;
|
||||
|
||||
port->openclose = false;
|
||||
|
||||
pr_debug("gs_close: ttyGS%d (%p,%p) done!\n",
|
||||
port->port_num, tty, file);
|
||||
|
||||
wake_up_interruptible(&port->close_wait);
|
||||
wake_up_interruptible(&port->port.close_wait);
|
||||
exit:
|
||||
spin_unlock_irq(&port->port_lock);
|
||||
}
|
||||
|
@ -1034,8 +1031,8 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
|
|||
if (port == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
tty_port_init(&port->port);
|
||||
spin_lock_init(&port->port_lock);
|
||||
init_waitqueue_head(&port->close_wait);
|
||||
init_waitqueue_head(&port->drain_wait);
|
||||
|
||||
tasklet_init(&port->push, gs_rx_push, (unsigned long) port);
|
||||
|
@ -1155,7 +1152,7 @@ static int gs_closed(struct gs_port *port)
|
|||
int cond;
|
||||
|
||||
spin_lock_irq(&port->port_lock);
|
||||
cond = (port->open_count == 0) && !port->openclose;
|
||||
cond = (port->port.count == 0) && !port->openclose;
|
||||
spin_unlock_irq(&port->port_lock);
|
||||
return cond;
|
||||
}
|
||||
|
@ -1194,7 +1191,7 @@ void gserial_cleanup(void)
|
|||
tasklet_kill(&port->push);
|
||||
|
||||
/* wait for old opens to finish */
|
||||
wait_event(port->close_wait, gs_closed(port));
|
||||
wait_event(port->port.close_wait, gs_closed(port));
|
||||
|
||||
WARN_ON(port->port_usb != NULL);
|
||||
|
||||
|
@ -1268,7 +1265,7 @@ int gserial_connect(struct gserial *gser, u8 port_num)
|
|||
/* if it's already open, start I/O ... and notify the serial
|
||||
* protocol about open/close status (connect/disconnect).
|
||||
*/
|
||||
if (port->open_count) {
|
||||
if (port->port.count) {
|
||||
pr_debug("gserial_connect: start ttyGS%d\n", port->port_num);
|
||||
gs_start_io(port);
|
||||
if (gser->connect)
|
||||
|
@ -1315,10 +1312,10 @@ void gserial_disconnect(struct gserial *gser)
|
|||
|
||||
port->port_usb = NULL;
|
||||
gser->ioport = NULL;
|
||||
if (port->open_count > 0 || port->openclose) {
|
||||
if (port->port.count > 0 || port->openclose) {
|
||||
wake_up_interruptible(&port->drain_wait);
|
||||
if (port->port_tty)
|
||||
tty_hangup(port->port_tty);
|
||||
if (port->port.tty)
|
||||
tty_hangup(port->port.tty);
|
||||
}
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
|
||||
|
@ -1331,7 +1328,7 @@ void gserial_disconnect(struct gserial *gser)
|
|||
|
||||
/* finally, free any unused/unusable I/O buffers */
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
if (port->open_count == 0 && !port->openclose)
|
||||
if (port->port.count == 0 && !port->openclose)
|
||||
gs_buf_free(&port->port_write_buf);
|
||||
gs_free_requests(gser->out, &port->read_pool, NULL);
|
||||
gs_free_requests(gser->out, &port->read_queue, NULL);
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* Copyright (C) 1998 R.E.Wolff@BitWizard.nl
|
||||
*
|
||||
* written for the SX serial driver.
|
||||
* Contains the code that should be shared over all the serial drivers.
|
||||
*
|
||||
* Version 0.1 -- December, 1998.
|
||||
*/
|
||||
|
@ -12,45 +11,8 @@
|
|||
#ifndef GENERIC_SERIAL_H
|
||||
#define GENERIC_SERIAL_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/tty.h>
|
||||
|
||||
struct real_driver {
|
||||
void (*disable_tx_interrupts) (void *);
|
||||
void (*enable_tx_interrupts) (void *);
|
||||
void (*disable_rx_interrupts) (void *);
|
||||
void (*enable_rx_interrupts) (void *);
|
||||
void (*shutdown_port) (void*);
|
||||
int (*set_real_termios) (void*);
|
||||
int (*chars_in_buffer) (void*);
|
||||
void (*close) (void*);
|
||||
void (*hungup) (void*);
|
||||
void (*getserial) (void*, struct serial_struct *sp);
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct gs_port {
|
||||
int magic;
|
||||
struct tty_port port;
|
||||
unsigned char *xmit_buf;
|
||||
int xmit_head;
|
||||
int xmit_tail;
|
||||
int xmit_cnt;
|
||||
struct mutex port_write_mutex;
|
||||
unsigned long event;
|
||||
unsigned short closing_wait;
|
||||
int close_delay;
|
||||
struct real_driver *rd;
|
||||
int wakeup_chars;
|
||||
int baud_base;
|
||||
int baud;
|
||||
int custom_divisor;
|
||||
spinlock_t driver_lock;
|
||||
};
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#warning Use of this header is deprecated.
|
||||
#warning Since nobody sets the constants defined here for you, you should not, in any case, use them. Including the header is thus pointless.
|
||||
|
||||
/* Flags */
|
||||
/* Warning: serial.h defines some ASYNC_ flags, they say they are "only"
|
||||
|
@ -60,8 +22,6 @@ struct gs_port {
|
|||
#define GS_RX_INTEN 0x00400000
|
||||
#define GS_ACTIVE 0x00200000
|
||||
|
||||
|
||||
|
||||
#define GS_TYPE_NORMAL 1
|
||||
|
||||
#define GS_DEBUG_FLUSH 0x00000001
|
||||
|
@ -72,24 +32,4 @@ struct gs_port {
|
|||
#define GS_DEBUG_FLOW 0x00000020
|
||||
#define GS_DEBUG_WRITE 0x00000040
|
||||
|
||||
#ifdef __KERNEL__
|
||||
int gs_put_char(struct tty_struct *tty, unsigned char ch);
|
||||
int gs_write(struct tty_struct *tty,
|
||||
const unsigned char *buf, int count);
|
||||
int gs_write_room(struct tty_struct *tty);
|
||||
int gs_chars_in_buffer(struct tty_struct *tty);
|
||||
void gs_flush_buffer(struct tty_struct *tty);
|
||||
void gs_flush_chars(struct tty_struct *tty);
|
||||
void gs_stop(struct tty_struct *tty);
|
||||
void gs_start(struct tty_struct *tty);
|
||||
void gs_hangup(struct tty_struct *tty);
|
||||
int gs_block_til_ready(void *port, struct file *filp);
|
||||
void gs_close(struct tty_struct *tty, struct file *filp);
|
||||
void gs_set_termios (struct tty_struct * tty,
|
||||
struct ktermios * old_termios);
|
||||
int gs_init_port(struct gs_port *port);
|
||||
int gs_setserial(struct gs_port *port, struct serial_struct __user *sp);
|
||||
int gs_getserial(struct gs_port *port, struct serial_struct __user *sp);
|
||||
void gs_got_break(struct gs_port *port);
|
||||
#endif /* __KERNEL__ */
|
||||
#endif
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#define __ISDN_H__
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/tty.h>
|
||||
|
||||
#define ISDN_MAX_DRIVERS 32
|
||||
#define ISDN_MAX_CHANNELS 64
|
||||
|
@ -392,21 +393,8 @@ typedef struct isdn_net_dev_s {
|
|||
/*======================= Start of ISDN-tty stuff ===========================*/
|
||||
|
||||
#define ISDN_ASYNC_MAGIC 0x49344C01 /* for paranoia-checking */
|
||||
#define ISDN_ASYNC_INITIALIZED 0x80000000 /* port was initialized */
|
||||
#define ISDN_ASYNC_CALLOUT_ACTIVE 0x40000000 /* Call out device active */
|
||||
#define ISDN_ASYNC_NORMAL_ACTIVE 0x20000000 /* Normal device active */
|
||||
#define ISDN_ASYNC_CLOSING 0x08000000 /* Serial port is closing */
|
||||
#define ISDN_ASYNC_CTS_FLOW 0x04000000 /* Do CTS flow control */
|
||||
#define ISDN_ASYNC_CHECK_CD 0x02000000 /* i.e., CLOCAL */
|
||||
#define ISDN_ASYNC_HUP_NOTIFY 0x0001 /* Notify tty on hangups/closes */
|
||||
#define ISDN_ASYNC_SESSION_LOCKOUT 0x0100 /* Lock cua opens on session */
|
||||
#define ISDN_ASYNC_PGRP_LOCKOUT 0x0200 /* Lock cua opens on pgrp */
|
||||
#define ISDN_ASYNC_CALLOUT_NOHUP 0x0400 /* No hangup for cui */
|
||||
#define ISDN_ASYNC_SPLIT_TERMIOS 0x0008 /* Sep. termios for dialin/out */
|
||||
#define ISDN_SERIAL_XMIT_SIZE 1024 /* Default bufsize for write */
|
||||
#define ISDN_SERIAL_XMIT_MAX 4000 /* Maximum bufsize for write */
|
||||
#define ISDN_SERIAL_TYPE_NORMAL 1
|
||||
#define ISDN_SERIAL_TYPE_CALLOUT 2
|
||||
|
||||
#ifdef CONFIG_ISDN_AUDIO
|
||||
/* For using sk_buffs with audio we need some private variables
|
||||
|
@ -448,17 +436,12 @@ typedef struct atemu {
|
|||
/* Private data (similar to async_struct in <linux/serial.h>) */
|
||||
typedef struct modem_info {
|
||||
int magic;
|
||||
struct module *owner;
|
||||
int flags; /* defined in tty.h */
|
||||
struct tty_port port;
|
||||
int x_char; /* xon/xoff character */
|
||||
int mcr; /* Modem control register */
|
||||
int msr; /* Modem status register */
|
||||
int lsr; /* Line status register */
|
||||
int line;
|
||||
int count; /* # of fd on device */
|
||||
int blocked_open; /* # of blocked opens */
|
||||
long session; /* Session of opening process */
|
||||
long pgrp; /* pgrp of opening process */
|
||||
int online; /* 1 = B-Channel is up, drop data */
|
||||
/* 2 = B-Channel is up, deliver d.*/
|
||||
int dialing; /* Dial in progress or ATA */
|
||||
|
@ -478,7 +461,6 @@ typedef struct modem_info {
|
|||
int send_outstanding;/* # of outstanding send-requests */
|
||||
int xmit_size; /* max. # of chars in xmit_buf */
|
||||
int xmit_count; /* # of chars in xmit_buf */
|
||||
unsigned char *xmit_buf; /* transmit buffer */
|
||||
struct sk_buff_head xmit_queue; /* transmit queue */
|
||||
atomic_t xmit_lock; /* Semaphore for isdn_tty_write */
|
||||
#ifdef CONFIG_ISDN_AUDIO
|
||||
|
@ -496,11 +478,7 @@ typedef struct modem_info {
|
|||
struct T30_s *fax; /* T30 Fax Group 3 data/interface */
|
||||
int faxonline; /* Fax-channel status */
|
||||
#endif
|
||||
struct tty_struct *tty; /* Pointer to corresponding tty */
|
||||
atemu emu; /* AT-emulator data */
|
||||
struct ktermios normal_termios; /* For saving termios structs */
|
||||
struct ktermios callout_termios;
|
||||
wait_queue_head_t open_wait, close_wait;
|
||||
spinlock_t readlock;
|
||||
} modem_info;
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef __LINUX_OF_SERIAL_H
|
||||
#define __LINUX_OF_SERIAL_H
|
||||
|
||||
/*
|
||||
* FIXME remove this file when tegra finishes conversion to open firmware,
|
||||
* expectation is that all quirks will then be self-contained in
|
||||
* drivers/tty/serial/of_serial.c.
|
||||
*/
|
||||
#ifdef CONFIG_ARCH_TEGRA
|
||||
extern void tegra_serial_handle_break(struct uart_port *port);
|
||||
#else
|
||||
static inline void tegra_serial_handle_break(struct uart_port *port)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LINUX_OF_SERIAL */
|
|
@ -38,6 +38,7 @@ struct plat_serial8250_port {
|
|||
int (*handle_irq)(struct uart_port *);
|
||||
void (*pm)(struct uart_port *, unsigned int state,
|
||||
unsigned old);
|
||||
void (*handle_break)(struct uart_port *);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -68,6 +69,7 @@ enum {
|
|||
struct uart_port;
|
||||
struct uart_8250_port;
|
||||
|
||||
int serial8250_register_8250_port(struct uart_8250_port *);
|
||||
int serial8250_register_port(struct uart_port *);
|
||||
void serial8250_unregister_port(int line);
|
||||
void serial8250_suspend_port(int line);
|
||||
|
|
|
@ -310,6 +310,7 @@ struct uart_port {
|
|||
int (*handle_irq)(struct uart_port *);
|
||||
void (*pm)(struct uart_port *, unsigned int state,
|
||||
unsigned int old);
|
||||
void (*handle_break)(struct uart_port *);
|
||||
unsigned int irq; /* irq number */
|
||||
unsigned long irqflags; /* irq flags */
|
||||
unsigned int uartclk; /* base uart clock */
|
||||
|
@ -533,6 +534,10 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
|
|||
static inline int uart_handle_break(struct uart_port *port)
|
||||
{
|
||||
struct uart_state *state = port->state;
|
||||
|
||||
if (port->handle_break)
|
||||
port->handle_break(port);
|
||||
|
||||
#ifdef SUPPORT_SYSRQ
|
||||
if (port->cons && port->cons->index == port->line) {
|
||||
if (!port->sysrq) {
|
||||
|
|
|
@ -268,6 +268,7 @@ struct tty_struct {
|
|||
struct mutex ldisc_mutex;
|
||||
struct tty_ldisc *ldisc;
|
||||
|
||||
struct mutex legacy_mutex;
|
||||
struct mutex termios_mutex;
|
||||
spinlock_t ctrl_lock;
|
||||
/* Termios values are protected by the termios mutex */
|
||||
|
@ -605,8 +606,12 @@ extern long vt_compat_ioctl(struct tty_struct *tty,
|
|||
|
||||
/* tty_mutex.c */
|
||||
/* functions for preparation of BKL removal */
|
||||
extern void __lockfunc tty_lock(void) __acquires(tty_lock);
|
||||
extern void __lockfunc tty_unlock(void) __releases(tty_lock);
|
||||
extern void __lockfunc tty_lock(struct tty_struct *tty);
|
||||
extern void __lockfunc tty_unlock(struct tty_struct *tty);
|
||||
extern void __lockfunc tty_lock_pair(struct tty_struct *tty,
|
||||
struct tty_struct *tty2);
|
||||
extern void __lockfunc tty_unlock_pair(struct tty_struct *tty,
|
||||
struct tty_struct *tty2);
|
||||
|
||||
/*
|
||||
* this shall be called only from where BTM is held (like close)
|
||||
|
@ -621,9 +626,9 @@ extern void __lockfunc tty_unlock(void) __releases(tty_lock);
|
|||
static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
|
||||
long timeout)
|
||||
{
|
||||
tty_unlock(); /* tty->ops->close holds the BTM, drop it while waiting */
|
||||
tty_unlock(tty); /* tty->ops->close holds the BTM, drop it while waiting */
|
||||
tty_wait_until_sent(tty, timeout);
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -638,16 +643,16 @@ static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
|
|||
*
|
||||
* Do not use in new code.
|
||||
*/
|
||||
#define wait_event_interruptible_tty(wq, condition) \
|
||||
#define wait_event_interruptible_tty(tty, wq, condition) \
|
||||
({ \
|
||||
int __ret = 0; \
|
||||
if (!(condition)) { \
|
||||
__wait_event_interruptible_tty(wq, condition, __ret); \
|
||||
__wait_event_interruptible_tty(tty, wq, condition, __ret); \
|
||||
} \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
#define __wait_event_interruptible_tty(wq, condition, ret) \
|
||||
#define __wait_event_interruptible_tty(tty, wq, condition, ret) \
|
||||
do { \
|
||||
DEFINE_WAIT(__wait); \
|
||||
\
|
||||
|
@ -656,9 +661,9 @@ do { \
|
|||
if (condition) \
|
||||
break; \
|
||||
if (!signal_pending(current)) { \
|
||||
tty_unlock(); \
|
||||
tty_unlock(tty); \
|
||||
schedule(); \
|
||||
tty_lock(); \
|
||||
tty_lock(tty); \
|
||||
continue; \
|
||||
} \
|
||||
ret = -ERESTARTSYS; \
|
||||
|
|
|
@ -110,6 +110,7 @@
|
|||
#include <linux/fs.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/pps_kernel.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
struct tty_ldisc_ops {
|
||||
int magic;
|
||||
|
@ -154,6 +155,7 @@ struct tty_ldisc_ops {
|
|||
struct tty_ldisc {
|
||||
struct tty_ldisc_ops *ops;
|
||||
atomic_t users;
|
||||
wait_queue_head_t wq_idle;
|
||||
};
|
||||
|
||||
#define TTY_LDISC_MAGIC 0x5403
|
||||
|
|
|
@ -70,7 +70,6 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list);
|
|||
int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list);
|
||||
int con_set_default_unimap(struct vc_data *vc);
|
||||
void con_free_unimap(struct vc_data *vc);
|
||||
void con_protect_unimap(struct vc_data *vc, int rdonly);
|
||||
int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc);
|
||||
|
||||
#define vc_translate(vc, c) ((vc)->vc_translate[(c) | \
|
||||
|
|
|
@ -48,13 +48,12 @@
|
|||
static struct tty_driver *rfcomm_tty_driver;
|
||||
|
||||
struct rfcomm_dev {
|
||||
struct tty_port port;
|
||||
struct list_head list;
|
||||
atomic_t refcnt;
|
||||
|
||||
char name[12];
|
||||
int id;
|
||||
unsigned long flags;
|
||||
atomic_t opened;
|
||||
int err;
|
||||
|
||||
bdaddr_t src;
|
||||
|
@ -64,9 +63,7 @@ struct rfcomm_dev {
|
|||
uint modem_status;
|
||||
|
||||
struct rfcomm_dlc *dlc;
|
||||
struct tty_struct *tty;
|
||||
wait_queue_head_t wait;
|
||||
struct work_struct wakeup_task;
|
||||
|
||||
struct device *tty_dev;
|
||||
|
||||
|
@ -82,11 +79,18 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
|
|||
static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
|
||||
static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
|
||||
|
||||
static void rfcomm_tty_wakeup(struct work_struct *work);
|
||||
|
||||
/* ---- Device functions ---- */
|
||||
static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
|
||||
|
||||
/*
|
||||
* The reason this isn't actually a race, as you no doubt have a little voice
|
||||
* screaming at you in your head, is that the refcount should never actually
|
||||
* reach zero unless the device has already been taken off the list, in
|
||||
* rfcomm_dev_del(). And if that's not true, we'll hit the BUG() in
|
||||
* rfcomm_dev_destruct() anyway.
|
||||
*/
|
||||
static void rfcomm_dev_destruct(struct tty_port *port)
|
||||
{
|
||||
struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port);
|
||||
struct rfcomm_dlc *dlc = dev->dlc;
|
||||
|
||||
BT_DBG("dev %p dlc %p", dev, dlc);
|
||||
|
@ -113,23 +117,9 @@ static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
|
|||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
static inline void rfcomm_dev_hold(struct rfcomm_dev *dev)
|
||||
{
|
||||
atomic_inc(&dev->refcnt);
|
||||
}
|
||||
|
||||
static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
|
||||
{
|
||||
/* The reason this isn't actually a race, as you no
|
||||
doubt have a little voice screaming at you in your
|
||||
head, is that the refcount should never actually
|
||||
reach zero unless the device has already been taken
|
||||
off the list, in rfcomm_dev_del(). And if that's not
|
||||
true, we'll hit the BUG() in rfcomm_dev_destruct()
|
||||
anyway. */
|
||||
if (atomic_dec_and_test(&dev->refcnt))
|
||||
rfcomm_dev_destruct(dev);
|
||||
}
|
||||
static const struct tty_port_operations rfcomm_port_ops = {
|
||||
.destruct = rfcomm_dev_destruct,
|
||||
};
|
||||
|
||||
static struct rfcomm_dev *__rfcomm_dev_get(int id)
|
||||
{
|
||||
|
@ -154,7 +144,7 @@ static inline struct rfcomm_dev *rfcomm_dev_get(int id)
|
|||
if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
|
||||
dev = NULL;
|
||||
else
|
||||
rfcomm_dev_hold(dev);
|
||||
tty_port_get(&dev->port);
|
||||
}
|
||||
|
||||
spin_unlock(&rfcomm_dev_lock);
|
||||
|
@ -241,7 +231,6 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
|
|||
sprintf(dev->name, "rfcomm%d", dev->id);
|
||||
|
||||
list_add(&dev->list, head);
|
||||
atomic_set(&dev->refcnt, 1);
|
||||
|
||||
bacpy(&dev->src, &req->src);
|
||||
bacpy(&dev->dst, &req->dst);
|
||||
|
@ -250,10 +239,9 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
|
|||
dev->flags = req->flags &
|
||||
((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
|
||||
|
||||
atomic_set(&dev->opened, 0);
|
||||
|
||||
tty_port_init(&dev->port);
|
||||
dev->port.ops = &rfcomm_port_ops;
|
||||
init_waitqueue_head(&dev->wait);
|
||||
INIT_WORK(&dev->wakeup_task, rfcomm_tty_wakeup);
|
||||
|
||||
skb_queue_head_init(&dev->pending);
|
||||
|
||||
|
@ -320,18 +308,23 @@ free:
|
|||
|
||||
static void rfcomm_dev_del(struct rfcomm_dev *dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
BT_DBG("dev %p", dev);
|
||||
|
||||
BUG_ON(test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags));
|
||||
|
||||
if (atomic_read(&dev->opened) > 0)
|
||||
spin_lock_irqsave(&dev->port.lock, flags);
|
||||
if (dev->port.count > 0) {
|
||||
spin_unlock_irqrestore(&dev->port.lock, flags);
|
||||
return;
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->port.lock, flags);
|
||||
|
||||
spin_lock(&rfcomm_dev_lock);
|
||||
list_del_init(&dev->list);
|
||||
spin_unlock(&rfcomm_dev_lock);
|
||||
|
||||
rfcomm_dev_put(dev);
|
||||
tty_port_put(&dev->port);
|
||||
}
|
||||
|
||||
/* ---- Send buffer ---- */
|
||||
|
@ -345,15 +338,16 @@ static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc)
|
|||
static void rfcomm_wfree(struct sk_buff *skb)
|
||||
{
|
||||
struct rfcomm_dev *dev = (void *) skb->sk;
|
||||
struct tty_struct *tty = dev->port.tty;
|
||||
atomic_sub(skb->truesize, &dev->wmem_alloc);
|
||||
if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
|
||||
queue_work(system_nrt_wq, &dev->wakeup_task);
|
||||
rfcomm_dev_put(dev);
|
||||
if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags) && tty)
|
||||
tty_wakeup(tty);
|
||||
tty_port_put(&dev->port);
|
||||
}
|
||||
|
||||
static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
|
||||
{
|
||||
rfcomm_dev_hold(dev);
|
||||
tty_port_get(&dev->port);
|
||||
atomic_add(skb->truesize, &dev->wmem_alloc);
|
||||
skb->sk = (void *) dev;
|
||||
skb->destructor = rfcomm_wfree;
|
||||
|
@ -432,7 +426,7 @@ static int rfcomm_release_dev(void __user *arg)
|
|||
return -ENODEV;
|
||||
|
||||
if (dev->flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) {
|
||||
rfcomm_dev_put(dev);
|
||||
tty_port_put(&dev->port);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
|
@ -440,12 +434,12 @@ static int rfcomm_release_dev(void __user *arg)
|
|||
rfcomm_dlc_close(dev->dlc, 0);
|
||||
|
||||
/* Shut down TTY synchronously before freeing rfcomm_dev */
|
||||
if (dev->tty)
|
||||
tty_vhangup(dev->tty);
|
||||
if (dev->port.tty)
|
||||
tty_vhangup(dev->port.tty);
|
||||
|
||||
if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
|
||||
rfcomm_dev_del(dev);
|
||||
rfcomm_dev_put(dev);
|
||||
tty_port_put(&dev->port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -523,7 +517,7 @@ static int rfcomm_get_dev_info(void __user *arg)
|
|||
if (copy_to_user(arg, &di, sizeof(di)))
|
||||
err = -EFAULT;
|
||||
|
||||
rfcomm_dev_put(dev);
|
||||
tty_port_put(&dev->port);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -559,7 +553,7 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
|
|||
return;
|
||||
}
|
||||
|
||||
tty = dev->tty;
|
||||
tty = dev->port.tty;
|
||||
if (!tty || !skb_queue_empty(&dev->pending)) {
|
||||
skb_queue_tail(&dev->pending, skb);
|
||||
return;
|
||||
|
@ -585,13 +579,13 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
|
|||
wake_up_interruptible(&dev->wait);
|
||||
|
||||
if (dlc->state == BT_CLOSED) {
|
||||
if (!dev->tty) {
|
||||
if (!dev->port.tty) {
|
||||
if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
|
||||
/* Drop DLC lock here to avoid deadlock
|
||||
* 1. rfcomm_dev_get will take rfcomm_dev_lock
|
||||
* but in rfcomm_dev_add there's lock order:
|
||||
* rfcomm_dev_lock -> dlc lock
|
||||
* 2. rfcomm_dev_put will deadlock if it's
|
||||
* 2. tty_port_put will deadlock if it's
|
||||
* the last reference
|
||||
*/
|
||||
rfcomm_dlc_unlock(dlc);
|
||||
|
@ -601,11 +595,11 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
|
|||
}
|
||||
|
||||
rfcomm_dev_del(dev);
|
||||
rfcomm_dev_put(dev);
|
||||
tty_port_put(&dev->port);
|
||||
rfcomm_dlc_lock(dlc);
|
||||
}
|
||||
} else
|
||||
tty_hangup(dev->tty);
|
||||
tty_hangup(dev->port.tty);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -618,8 +612,8 @@ static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
|
|||
BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig);
|
||||
|
||||
if ((dev->modem_status & TIOCM_CD) && !(v24_sig & RFCOMM_V24_DV)) {
|
||||
if (dev->tty && !C_CLOCAL(dev->tty))
|
||||
tty_hangup(dev->tty);
|
||||
if (dev->port.tty && !C_CLOCAL(dev->port.tty))
|
||||
tty_hangup(dev->port.tty);
|
||||
}
|
||||
|
||||
dev->modem_status =
|
||||
|
@ -630,21 +624,9 @@ static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
|
|||
}
|
||||
|
||||
/* ---- TTY functions ---- */
|
||||
static void rfcomm_tty_wakeup(struct work_struct *work)
|
||||
{
|
||||
struct rfcomm_dev *dev = container_of(work, struct rfcomm_dev,
|
||||
wakeup_task);
|
||||
struct tty_struct *tty = dev->tty;
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
BT_DBG("dev %p tty %p", dev, tty);
|
||||
tty_wakeup(tty);
|
||||
}
|
||||
|
||||
static void rfcomm_tty_copy_pending(struct rfcomm_dev *dev)
|
||||
{
|
||||
struct tty_struct *tty = dev->tty;
|
||||
struct tty_struct *tty = dev->port.tty;
|
||||
struct sk_buff *skb;
|
||||
int inserted = 0;
|
||||
|
||||
|
@ -671,6 +653,7 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
|
|||
DECLARE_WAITQUEUE(wait, current);
|
||||
struct rfcomm_dev *dev;
|
||||
struct rfcomm_dlc *dlc;
|
||||
unsigned long flags;
|
||||
int err, id;
|
||||
|
||||
id = tty->index;
|
||||
|
@ -686,10 +669,14 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
|
|||
return -ENODEV;
|
||||
|
||||
BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst),
|
||||
dev->channel, atomic_read(&dev->opened));
|
||||
dev->channel, dev->port.count);
|
||||
|
||||
if (atomic_inc_return(&dev->opened) > 1)
|
||||
spin_lock_irqsave(&dev->port.lock, flags);
|
||||
if (++dev->port.count > 1) {
|
||||
spin_unlock_irqrestore(&dev->port.lock, flags);
|
||||
return 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->port.lock, flags);
|
||||
|
||||
dlc = dev->dlc;
|
||||
|
||||
|
@ -697,7 +684,7 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
|
|||
|
||||
rfcomm_dlc_lock(dlc);
|
||||
tty->driver_data = dev;
|
||||
dev->tty = tty;
|
||||
dev->port.tty = tty;
|
||||
rfcomm_dlc_unlock(dlc);
|
||||
set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
|
||||
|
||||
|
@ -723,9 +710,9 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
|
|||
break;
|
||||
}
|
||||
|
||||
tty_unlock();
|
||||
tty_unlock(tty);
|
||||
schedule();
|
||||
tty_lock();
|
||||
tty_lock(tty);
|
||||
}
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&dev->wait, &wait);
|
||||
|
@ -744,13 +731,17 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
|
|||
static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
|
||||
unsigned long flags;
|
||||
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc,
|
||||
atomic_read(&dev->opened));
|
||||
dev->port.count);
|
||||
|
||||
if (atomic_dec_and_test(&dev->opened)) {
|
||||
spin_lock_irqsave(&dev->port.lock, flags);
|
||||
if (!--dev->port.count) {
|
||||
spin_unlock_irqrestore(&dev->port.lock, flags);
|
||||
if (dev->tty_dev->parent)
|
||||
device_move(dev->tty_dev, NULL, DPM_ORDER_DEV_LAST);
|
||||
|
||||
|
@ -758,11 +749,10 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
|
|||
rfcomm_dlc_close(dev->dlc, 0);
|
||||
|
||||
clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
|
||||
cancel_work_sync(&dev->wakeup_task);
|
||||
|
||||
rfcomm_dlc_lock(dev->dlc);
|
||||
tty->driver_data = NULL;
|
||||
dev->tty = NULL;
|
||||
dev->port.tty = NULL;
|
||||
rfcomm_dlc_unlock(dev->dlc);
|
||||
|
||||
if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) {
|
||||
|
@ -770,11 +760,12 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
|
|||
list_del_init(&dev->list);
|
||||
spin_unlock(&rfcomm_dev_lock);
|
||||
|
||||
rfcomm_dev_put(dev);
|
||||
tty_port_put(&dev->port);
|
||||
}
|
||||
}
|
||||
} else
|
||||
spin_unlock_irqrestore(&dev->port.lock, flags);
|
||||
|
||||
rfcomm_dev_put(dev);
|
||||
tty_port_put(&dev->port);
|
||||
}
|
||||
|
||||
static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
||||
|
@ -1083,7 +1074,7 @@ static void rfcomm_tty_hangup(struct tty_struct *tty)
|
|||
if (rfcomm_dev_get(dev->id) == NULL)
|
||||
return;
|
||||
rfcomm_dev_del(dev);
|
||||
rfcomm_dev_put(dev);
|
||||
tty_port_put(&dev->port);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче