tty/serial patches for 3.9-rc1

Here's the big tty/serial driver patches for 3.9-rc1.
 
 More tty port rework and fixes from Jiri here, as well as lots of
 individual serial driver updates and fixes.
 
 All of these have been in the linux-next tree for a while.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.19 (GNU/Linux)
 
 iEYEABECAAYFAlEmZYQACgkQMUfUDdst+ylJDgCg0B0nMevUUdM4hLvxunbbiyXM
 HUEAoIOedqriNNPvX4Bwy0hjeOEaWx0g
 =vi6x
 -----END PGP SIGNATURE-----

Merge tag 'tty-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty/serial patches from Greg Kroah-Hartman:
 "Here's the big tty/serial driver patches for 3.9-rc1.

  More tty port rework and fixes from Jiri here, as well as lots of
  individual serial driver updates and fixes.

  All of these have been in the linux-next tree for a while."

* tag 'tty-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (140 commits)
  tty: mxser: improve error handling in mxser_probe() and mxser_module_init()
  serial: imx: fix uninitialized variable warning
  serial: tegra: assume CONFIG_OF
  TTY: do not update atime/mtime on read/write
  lguest: select CONFIG_TTY to build properly.
  ARM defconfigs: add missing inclusions of linux/platform_device.h
  fb/exynos: include platform_device.h
  ARM: sa1100/assabet: include platform_device.h directly
  serial: imx: Fix recursive locking bug
  pps: Fix build breakage from decoupling pps from tty
  tty: Remove ancient hardpps()
  pps: Additional cleanups in uart_handle_dcd_change
  pps: Move timestamp read into PPS code proper
  pps: Don't crash the machine when exiting will do
  pps: Fix a use-after free bug when unregistering a source.
  pps: Use pps_lookup_dev to reduce ldisc coupling
  pps: Add pps_lookup_dev() function
  tty: serial: uartlite: Support uartlite on big and little endian systems
  tty: serial: uartlite: Fix sparse and checkpatch warnings
  serial/arc-uart: Miscll DT related updates (Grant's review comments)
  ...

Fix up trivial conflicts, mostly just due to the TTY config option
clashing with the EXPERIMENTAL removal.
This commit is contained in:
Linus Torvalds 2013-02-21 13:41:04 -08:00
commit 21eaab6d19
267 changed files with 6865 additions and 2528 deletions

View File

@ -0,0 +1,24 @@
NVIDIA Tegra20/Tegra30 high speed (DMA based) UART controller driver.
Required properties:
- compatible : should be "nvidia,tegra30-hsuart", "nvidia,tegra20-hsuart".
- reg: Should contain UART controller registers location and length.
- interrupts: Should contain UART controller interrupts.
- nvidia,dma-request-selector : The Tegra DMA controller's phandle and
request selector for this UART controller.
Optional properties:
- nvidia,enable-modem-interrupt: Enable modem interrupts. Should be enable
only if all 8 lines of UART controller are pinmuxed.
Example:
serial@70006000 {
compatible = "nvidia,tegra30-hsuart", "nvidia,tegra20-hsuart";
reg = <0x70006000 0x40>;
reg-shift = <2>;
interrupts = <0 36 0x04>;
nvidia,dma-request-selector = <&apbdma 8>;
nvidia,enable-modem-interrupt;
status = "disabled";
};

View File

@ -0,0 +1,26 @@
* Synopsys ARC UART : Non standard UART used in some of the ARC FPGA boards
Required properties:
- compatible : "snps,arc-uart"
- reg : offset and length of the register set for the device.
- interrupts : device interrupt
- clock-frequency : the input clock frequency for the UART
- current-speed : baud rate for UART
e.g.
arcuart0: serial@c0fc1000 {
compatible = "snps,arc-uart";
reg = <0xc0fc1000 0x100>;
interrupts = <5>;
clock-frequency = <80000000>;
current-speed = <115200>;
status = "okay";
};
Note: Each port should have an alias correctly numbered in "aliases" node.
e.g.
aliases {
serial0 = &arcuart0;
};

View File

@ -5,10 +5,16 @@ Required properties:
- reg : Address and length of the register set - reg : Address and length of the register set
- interrupts : Should contain uart interrupt - interrupts : Should contain uart interrupt
Optional properties:
- location : Decides the location of the USART I/O pins.
Allowed range : [0 .. 5]
Default: 0
Example: Example:
uart@0x4000c400 { uart@0x4000c400 {
compatible = "efm32,uart"; compatible = "efm32,uart";
reg = <0x4000c400 0x400>; reg = <0x4000c400 0x400>;
interrupts = <15>; interrupts = <15>;
location = <0>;
}; };

View File

@ -133,6 +133,16 @@ hardware.
Interrupts: locally disabled. Interrupts: locally disabled.
This call must not sleep This call must not sleep
send_xchar(port,ch)
Transmit a high priority character, even if the port is stopped.
This is used to implement XON/XOFF flow control and tcflow(). If
the serial driver does not implement this function, the tty core
will append the character to the circular buffer and then call
start_tx() / stop_tx() to flush the data out.
Locking: none.
Interrupts: caller dependent.
stop_rx(port) stop_rx(port)
Stop receiving characters; the port is in the process of Stop receiving characters; the port is in the process of
being closed. being closed.
@ -242,9 +252,8 @@ hardware.
pm(port,state,oldstate) pm(port,state,oldstate)
Perform any power management related activities on the specified Perform any power management related activities on the specified
port. State indicates the new state (defined by ACPI D0-D3), port. State indicates the new state (defined by
oldstate indicates the previous state. Essentially, D0 means enum uart_pm_state), oldstate indicates the previous state.
fully on, D3 means powered down.
This function should not be used to grab any resources. This function should not be used to grab any resources.
@ -255,6 +264,10 @@ hardware.
Locking: none. Locking: none.
Interrupts: caller dependent. Interrupts: caller dependent.
set_wake(port,state)
Enable/disable power management wakeup on serial activity. Not
currently implemented.
type(port) type(port)
Return a pointer to a string constant describing the specified Return a pointer to a string constant describing the specified
port, or return NULL, in which case the string 'unknown' is port, or return NULL, in which case the string 'unknown' is
@ -307,6 +320,31 @@ hardware.
Locking: none. Locking: none.
Interrupts: caller dependent. Interrupts: caller dependent.
poll_init(port)
Called by kgdb to perform the minimal hardware initialization needed
to support poll_put_char() and poll_get_char(). Unlike ->startup()
this should not request interrupts.
Locking: tty_mutex and tty_port->mutex taken.
Interrupts: n/a.
poll_put_char(port,ch)
Called by kgdb to write a single character directly to the serial
port. It can and should block until there is space in the TX FIFO.
Locking: none.
Interrupts: caller dependent.
This call must not sleep
poll_get_char(port)
Called by kgdb to read a single character directly from the serial
port. If data is available, it should be returned; otherwise
the function should return NO_POLL_CHAR immediately.
Locking: none.
Interrupts: caller dependent.
This call must not sleep
Other functions Other functions
--------------- ---------------

View File

@ -124,6 +124,7 @@ choice
config ALPHA_GENERIC config ALPHA_GENERIC
bool "Generic" bool "Generic"
depends on TTY
help help
A generic kernel will run on all supported Alpha hardware. A generic kernel will run on all supported Alpha hardware.
@ -490,6 +491,7 @@ config VGA_HOSE
config ALPHA_SRM config ALPHA_SRM
bool "Use SRM as bootloader" if ALPHA_CABRIOLET || ALPHA_AVANTI_CH || ALPHA_EB64P || ALPHA_PC164 || ALPHA_TAKARA || ALPHA_EB164 || ALPHA_ALCOR || ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_NAUTILUS || ALPHA_NONAME bool "Use SRM as bootloader" if ALPHA_CABRIOLET || ALPHA_AVANTI_CH || ALPHA_EB64P || ALPHA_PC164 || ALPHA_TAKARA || ALPHA_EB164 || ALPHA_ALCOR || ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_NAUTILUS || ALPHA_NONAME
depends on TTY
default y if ALPHA_JENSEN || ALPHA_MIKASA || ALPHA_SABLE || ALPHA_LYNX || ALPHA_NORITAKE || ALPHA_DP264 || ALPHA_RAWHIDE || ALPHA_EIGER || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_SHARK || ALPHA_MARVEL default y if ALPHA_JENSEN || ALPHA_MIKASA || ALPHA_SABLE || ALPHA_LYNX || ALPHA_NORITAKE || ALPHA_DP264 || ALPHA_RAWHIDE || ALPHA_EIGER || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_SHARK || ALPHA_MARVEL
---help--- ---help---
There are two different types of booting firmware on Alphas: SRM, There are two different types of booting firmware on Alphas: SRM,

View File

@ -44,7 +44,7 @@ typedef union _srmcons_result {
/* called with callback_lock held */ /* called with callback_lock held */
static int static int
srmcons_do_receive_chars(struct tty_struct *tty) srmcons_do_receive_chars(struct tty_port *port)
{ {
srmcons_result result; srmcons_result result;
int count = 0, loops = 0; int count = 0, loops = 0;
@ -52,13 +52,13 @@ srmcons_do_receive_chars(struct tty_struct *tty)
do { do {
result.as_long = callback_getc(0); result.as_long = callback_getc(0);
if (result.bits.status < 2) { if (result.bits.status < 2) {
tty_insert_flip_char(tty, (char)result.bits.c, 0); tty_insert_flip_char(port, (char)result.bits.c, 0);
count++; count++;
} }
} while((result.bits.status & 1) && (++loops < 10)); } while((result.bits.status & 1) && (++loops < 10));
if (count) if (count)
tty_schedule_flip(tty); tty_schedule_flip(port);
return count; return count;
} }
@ -73,7 +73,7 @@ srmcons_receive_chars(unsigned long data)
local_irq_save(flags); local_irq_save(flags);
if (spin_trylock(&srmcons_callback_lock)) { if (spin_trylock(&srmcons_callback_lock)) {
if (!srmcons_do_receive_chars(port->tty)) if (!srmcons_do_receive_chars(port))
incr = 100; incr = 100;
spin_unlock(&srmcons_callback_lock); spin_unlock(&srmcons_callback_lock);
} }
@ -88,7 +88,7 @@ srmcons_receive_chars(unsigned long data)
/* called with callback_lock held */ /* called with callback_lock held */
static int static int
srmcons_do_write(struct tty_struct *tty, const char *buf, int count) srmcons_do_write(struct tty_port *port, const char *buf, int count)
{ {
static char str_cr[1] = "\r"; static char str_cr[1] = "\r";
long c, remaining = count; long c, remaining = count;
@ -113,10 +113,10 @@ srmcons_do_write(struct tty_struct *tty, const char *buf, int count)
cur += result.bits.c; cur += result.bits.c;
/* /*
* Check for pending input iff a tty was provided * Check for pending input iff a tty port was provided
*/ */
if (tty) if (port)
srmcons_do_receive_chars(tty); srmcons_do_receive_chars(port);
} }
while (need_cr) { while (need_cr) {
@ -135,7 +135,7 @@ srmcons_write(struct tty_struct *tty,
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&srmcons_callback_lock, flags); spin_lock_irqsave(&srmcons_callback_lock, flags);
srmcons_do_write(tty, (const char *) buf, count); srmcons_do_write(tty->port, (const char *) buf, count);
spin_unlock_irqrestore(&srmcons_callback_lock, flags); spin_unlock_irqrestore(&srmcons_callback_lock, flags);
return count; return count;

View File

@ -45,6 +45,38 @@
compatible = "fixed-clock"; compatible = "fixed-clock";
clock-frequency = <24000000>; clock-frequency = <24000000>;
}; };
clkuart0: uart0 {
#clock-cells = <0>;
compatible = "via,vt8500-device-clock";
clocks = <&ref24>;
enable-reg = <0x250>;
enable-bit = <1>;
};
clkuart1: uart1 {
#clock-cells = <0>;
compatible = "via,vt8500-device-clock";
clocks = <&ref24>;
enable-reg = <0x250>;
enable-bit = <2>;
};
clkuart2: uart2 {
#clock-cells = <0>;
compatible = "via,vt8500-device-clock";
clocks = <&ref24>;
enable-reg = <0x250>;
enable-bit = <3>;
};
clkuart3: uart3 {
#clock-cells = <0>;
compatible = "via,vt8500-device-clock";
clocks = <&ref24>;
enable-reg = <0x250>;
enable-bit = <4>;
};
}; };
}; };
@ -83,28 +115,28 @@
compatible = "via,vt8500-uart"; compatible = "via,vt8500-uart";
reg = <0xd8200000 0x1040>; reg = <0xd8200000 0x1040>;
interrupts = <32>; interrupts = <32>;
clocks = <&ref24>; clocks = <&clkuart0>;
}; };
uart@d82b0000 { uart@d82b0000 {
compatible = "via,vt8500-uart"; compatible = "via,vt8500-uart";
reg = <0xd82b0000 0x1040>; reg = <0xd82b0000 0x1040>;
interrupts = <33>; interrupts = <33>;
clocks = <&ref24>; clocks = <&clkuart1>;
}; };
uart@d8210000 { uart@d8210000 {
compatible = "via,vt8500-uart"; compatible = "via,vt8500-uart";
reg = <0xd8210000 0x1040>; reg = <0xd8210000 0x1040>;
interrupts = <47>; interrupts = <47>;
clocks = <&ref24>; clocks = <&clkuart2>;
}; };
uart@d82c0000 { uart@d82c0000 {
compatible = "via,vt8500-uart"; compatible = "via,vt8500-uart";
reg = <0xd82c0000 0x1040>; reg = <0xd82c0000 0x1040>;
interrupts = <50>; interrupts = <50>;
clocks = <&ref24>; clocks = <&clkuart3>;
}; };
rtc@d8100000 { rtc@d8100000 {

View File

@ -59,6 +59,54 @@
compatible = "fixed-clock"; compatible = "fixed-clock";
clock-frequency = <24000000>; clock-frequency = <24000000>;
}; };
clkuart0: uart0 {
#clock-cells = <0>;
compatible = "via,vt8500-device-clock";
clocks = <&ref24>;
enable-reg = <0x250>;
enable-bit = <1>;
};
clkuart1: uart1 {
#clock-cells = <0>;
compatible = "via,vt8500-device-clock";
clocks = <&ref24>;
enable-reg = <0x250>;
enable-bit = <2>;
};
clkuart2: uart2 {
#clock-cells = <0>;
compatible = "via,vt8500-device-clock";
clocks = <&ref24>;
enable-reg = <0x250>;
enable-bit = <3>;
};
clkuart3: uart3 {
#clock-cells = <0>;
compatible = "via,vt8500-device-clock";
clocks = <&ref24>;
enable-reg = <0x250>;
enable-bit = <4>;
};
clkuart4: uart4 {
#clock-cells = <0>;
compatible = "via,vt8500-device-clock";
clocks = <&ref24>;
enable-reg = <0x250>;
enable-bit = <22>;
};
clkuart5: uart5 {
#clock-cells = <0>;
compatible = "via,vt8500-device-clock";
clocks = <&ref24>;
enable-reg = <0x250>;
enable-bit = <23>;
};
}; };
}; };
@ -96,42 +144,42 @@
compatible = "via,vt8500-uart"; compatible = "via,vt8500-uart";
reg = <0xd8200000 0x1040>; reg = <0xd8200000 0x1040>;
interrupts = <32>; interrupts = <32>;
clocks = <&ref24>; clocks = <&clkuart0>;
}; };
uart@d82b0000 { uart@d82b0000 {
compatible = "via,vt8500-uart"; compatible = "via,vt8500-uart";
reg = <0xd82b0000 0x1040>; reg = <0xd82b0000 0x1040>;
interrupts = <33>; interrupts = <33>;
clocks = <&ref24>; clocks = <&clkuart1>;
}; };
uart@d8210000 { uart@d8210000 {
compatible = "via,vt8500-uart"; compatible = "via,vt8500-uart";
reg = <0xd8210000 0x1040>; reg = <0xd8210000 0x1040>;
interrupts = <47>; interrupts = <47>;
clocks = <&ref24>; clocks = <&clkuart2>;
}; };
uart@d82c0000 { uart@d82c0000 {
compatible = "via,vt8500-uart"; compatible = "via,vt8500-uart";
reg = <0xd82c0000 0x1040>; reg = <0xd82c0000 0x1040>;
interrupts = <50>; interrupts = <50>;
clocks = <&ref24>; clocks = <&clkuart3>;
}; };
uart@d8370000 { uart@d8370000 {
compatible = "via,vt8500-uart"; compatible = "via,vt8500-uart";
reg = <0xd8370000 0x1040>; reg = <0xd8370000 0x1040>;
interrupts = <31>; interrupts = <31>;
clocks = <&ref24>; clocks = <&clkuart4>;
}; };
uart@d8380000 { uart@d8380000 {
compatible = "via,vt8500-uart"; compatible = "via,vt8500-uart";
reg = <0xd8380000 0x1040>; reg = <0xd8380000 0x1040>;
interrupts = <30>; interrupts = <30>;
clocks = <&ref24>; clocks = <&clkuart5>;
}; };
rtc@d8100000 { rtc@d8100000 {

View File

@ -75,6 +75,22 @@
reg = <0x204>; reg = <0x204>;
}; };
clkuart0: uart0 {
#clock-cells = <0>;
compatible = "via,vt8500-device-clock";
clocks = <&ref24>;
enable-reg = <0x250>;
enable-bit = <1>;
};
clkuart1: uart1 {
#clock-cells = <0>;
compatible = "via,vt8500-device-clock";
clocks = <&ref24>;
enable-reg = <0x250>;
enable-bit = <2>;
};
arm: arm { arm: arm {
#clock-cells = <0>; #clock-cells = <0>;
compatible = "via,vt8500-device-clock"; compatible = "via,vt8500-device-clock";
@ -128,14 +144,14 @@
compatible = "via,vt8500-uart"; compatible = "via,vt8500-uart";
reg = <0xd8200000 0x1040>; reg = <0xd8200000 0x1040>;
interrupts = <32>; interrupts = <32>;
clocks = <&ref24>; clocks = <&clkuart0>;
}; };
uart@d82b0000 { uart@d82b0000 {
compatible = "via,vt8500-uart"; compatible = "via,vt8500-uart";
reg = <0xd82b0000 0x1040>; reg = <0xd82b0000 0x1040>;
interrupts = <33>; interrupts = <33>;
clocks = <&ref24>; clocks = <&clkuart1>;
}; };
rtc@d8100000 { rtc@d8100000 {

View File

@ -44,14 +44,14 @@
compatible = "xlnx,xuartps"; compatible = "xlnx,xuartps";
reg = <0xE0000000 0x1000>; reg = <0xE0000000 0x1000>;
interrupts = <0 27 4>; interrupts = <0 27 4>;
clock = <50000000>; clocks = <&uart_clk 0>;
}; };
uart1: uart@e0001000 { uart1: uart@e0001000 {
compatible = "xlnx,xuartps"; compatible = "xlnx,xuartps";
reg = <0xE0001000 0x1000>; reg = <0xE0001000 0x1000>;
interrupts = <0 50 4>; interrupts = <0 50 4>;
clock = <50000000>; clocks = <&uart_clk 1>;
}; };
slcr: slcr@f8000000 { slcr: slcr@f8000000 {

View File

@ -16,6 +16,7 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/platform_data/sa11x0-serial.h> #include <linux/platform_data/sa11x0-serial.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/mfd/ucb1x00.h> #include <linux/mfd/ucb1x00.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>

View File

@ -15,6 +15,7 @@
#define __ASM_PLAT_ADC_H __FILE__ #define __ASM_PLAT_ADC_H __FILE__
struct s3c_adc_client; struct s3c_adc_client;
struct platform_device;
extern int s3c_adc_start(struct s3c_adc_client *client, extern int s3c_adc_start(struct s3c_adc_client *client,
unsigned int channel, unsigned int nr_samples); unsigned int channel, unsigned int nr_samples);

View File

@ -8,6 +8,7 @@ config HP_SIMETH
config HP_SIMSERIAL config HP_SIMSERIAL
bool "Simulated serial driver support" bool "Simulated serial driver support"
depends on TTY
config HP_SIMSERIAL_CONSOLE config HP_SIMSERIAL_CONSOLE
bool "Console for HP simulator" bool "Console for HP simulator"

View File

@ -53,7 +53,7 @@ struct tty_driver *hp_simserial_driver;
static struct console *console; static struct console *console;
static void receive_chars(struct tty_struct *tty) static void receive_chars(struct tty_port *port)
{ {
unsigned char ch; unsigned char ch;
static unsigned char seen_esc = 0; static unsigned char seen_esc = 0;
@ -81,10 +81,10 @@ static void receive_chars(struct tty_struct *tty)
} }
seen_esc = 0; seen_esc = 0;
if (tty_insert_flip_char(tty, ch, TTY_NORMAL) == 0) if (tty_insert_flip_char(port, ch, TTY_NORMAL) == 0)
break; break;
} }
tty_flip_buffer_push(tty); tty_flip_buffer_push(port);
} }
/* /*
@ -93,18 +93,9 @@ static void receive_chars(struct tty_struct *tty)
static irqreturn_t rs_interrupt_single(int irq, void *dev_id) static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
{ {
struct serial_state *info = dev_id; struct serial_state *info = dev_id;
struct tty_struct *tty = tty_port_tty_get(&info->port);
if (!tty) { receive_chars(&info->port);
printk(KERN_INFO "%s: tty=0 problem\n", __func__);
return IRQ_NONE;
}
/*
* pretty simple in our case, because we only get interrupts
* on inbound traffic
*/
receive_chars(tty);
tty_kref_put(tty);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -435,7 +426,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
struct tty_port *port = &info->port; struct tty_port *port = &info->port;
tty->driver_data = info; tty->driver_data = info;
tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
/* /*
* figure out which console to use (should be one already) * figure out which console to use (should be one already)

View File

@ -41,7 +41,7 @@ config NFBLOCK
config NFCON config NFCON
tristate "NatFeat console driver" tristate "NatFeat console driver"
depends on NATFEAT depends on TTY && NATFEAT
help help
Say Y to include support for the ARAnyM NatFeat console driver Say Y to include support for the ARAnyM NatFeat console driver
which allows the console output to be redirected to the stderr which allows the console output to be redirected to the stderr

View File

@ -118,7 +118,7 @@ static struct resource sc26xx_rsrc[] = {
} }
}; };
#include <linux/platform_data/sccnxp.h> #include <linux/platform_data/serial-sccnxp.h>
static struct sccnxp_pdata sccnxp_data = { static struct sccnxp_pdata sccnxp_data = {
.reg_shift = 2, .reg_shift = 2,

View File

@ -524,7 +524,7 @@ static int mask_test_and_clear(volatile u8 *ptr, u8 mask)
static void mn10300_serial_receive_interrupt(struct mn10300_serial_port *port) static void mn10300_serial_receive_interrupt(struct mn10300_serial_port *port)
{ {
struct uart_icount *icount = &port->uart.icount; struct uart_icount *icount = &port->uart.icount;
struct tty_struct *tty = port->uart.state->port.tty; struct tty_port *tport = &port->uart.state->port;
unsigned ix; unsigned ix;
int count; int count;
u8 st, ch, push, status, overrun; u8 st, ch, push, status, overrun;
@ -534,10 +534,10 @@ static void mn10300_serial_receive_interrupt(struct mn10300_serial_port *port)
push = 0; push = 0;
count = CIRC_CNT(port->rx_inp, port->rx_outp, MNSC_BUFFER_SIZE); count = CIRC_CNT(port->rx_inp, port->rx_outp, MNSC_BUFFER_SIZE);
count = tty_buffer_request_room(tty, count); count = tty_buffer_request_room(tport, count);
if (count == 0) { if (count == 0) {
if (!tty->low_latency) if (!tport->low_latency)
tty_flip_buffer_push(tty); tty_flip_buffer_push(tport);
return; return;
} }
@ -545,8 +545,8 @@ try_again:
/* pull chars out of the hat */ /* pull chars out of the hat */
ix = ACCESS_ONCE(port->rx_outp); ix = ACCESS_ONCE(port->rx_outp);
if (CIRC_CNT(port->rx_inp, ix, MNSC_BUFFER_SIZE) == 0) { if (CIRC_CNT(port->rx_inp, ix, MNSC_BUFFER_SIZE) == 0) {
if (push && !tty->low_latency) if (push && !tport->low_latency)
tty_flip_buffer_push(tty); tty_flip_buffer_push(tport);
return; return;
} }
@ -666,19 +666,19 @@ insert:
else else
flag = TTY_NORMAL; flag = TTY_NORMAL;
tty_insert_flip_char(tty, ch, flag); tty_insert_flip_char(tport, ch, flag);
} }
/* overrun is special, since it's reported immediately, and doesn't /* overrun is special, since it's reported immediately, and doesn't
* affect the current character * affect the current character
*/ */
if (overrun) if (overrun)
tty_insert_flip_char(tty, 0, TTY_OVERRUN); tty_insert_flip_char(tport, 0, TTY_OVERRUN);
count--; count--;
if (count <= 0) { if (count <= 0) {
if (!tty->low_latency) if (!tport->low_latency)
tty_flip_buffer_push(tty); tty_flip_buffer_push(tport);
return; return;
} }

View File

@ -21,6 +21,7 @@ config PARISC
select HAVE_MOD_ARCH_SPECIFIC select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_RELA select MODULES_USE_ELF_RELA
select CLONE_BACKWARDS select CLONE_BACKWARDS
select TTY # Needed for pdc_cons.c
help help
The PA-RISC microprocessor is designed by Hewlett-Packard and used The PA-RISC microprocessor is designed by Hewlett-Packard and used

View File

@ -138,23 +138,17 @@ static const struct tty_operations pdc_console_tty_ops = {
static void pdc_console_poll(unsigned long unused) static void pdc_console_poll(unsigned long unused)
{ {
int data, count = 0; int data, count = 0;
struct tty_struct *tty = tty_port_tty_get(&tty_port);
if (!tty)
return;
while (1) { while (1) {
data = pdc_console_poll_key(NULL); data = pdc_console_poll_key(NULL);
if (data == -1) if (data == -1)
break; break;
tty_insert_flip_char(tty, data & 0xFF, TTY_NORMAL); tty_insert_flip_char(&tty_port, data & 0xFF, TTY_NORMAL);
count ++; count ++;
} }
if (count) if (count)
tty_flip_buffer_push(tty); tty_flip_buffer_push(&tty_port);
tty_kref_put(tty);
if (pdc_cons.flags & CON_ENABLED) if (pdc_cons.flags & CON_ENABLED)
mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY); mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY);

View File

@ -5,6 +5,7 @@
#include <linux/kgdb.h> #include <linux/kgdb.h>
#include <linux/kdebug.h> #include <linux/kdebug.h>
#include <linux/sched.h>
#include <asm/kdebug.h> #include <asm/kdebug.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>

View File

@ -121,6 +121,7 @@ config DEBUG_COPY_FROM_USER
def_bool n def_bool n
config HVC_TILE config HVC_TILE
depends on TTY
select HVC_DRIVER select HVC_DRIVER
def_bool y def_bool y

View File

@ -12,6 +12,7 @@ config UML
select GENERIC_CPU_DEVICES select GENERIC_CPU_DEVICES
select GENERIC_IO select GENERIC_IO
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select TTY # Needed for line.c
config MMU config MMU
bool bool

View File

@ -27,8 +27,7 @@ struct chan {
void *data; void *data;
}; };
extern void chan_interrupt(struct line *line, extern void chan_interrupt(struct line *line, int irq);
struct tty_struct *tty, int irq);
extern int parse_chan_pair(char *str, struct line *line, int device, extern int parse_chan_pair(char *str, struct line *line, int device,
const struct chan_opts *opts, char **error_out); const struct chan_opts *opts, char **error_out);
extern int write_chan(struct chan *chan, const char *buf, int len, extern int write_chan(struct chan *chan, const char *buf, int len,

View File

@ -81,12 +81,6 @@ static const struct chan_ops not_configged_ops = {
}; };
#endif /* CONFIG_NOCONFIG_CHAN */ #endif /* CONFIG_NOCONFIG_CHAN */
static void tty_receive_char(struct tty_struct *tty, char ch)
{
if (tty)
tty_insert_flip_char(tty, ch, TTY_NORMAL);
}
static int open_one_chan(struct chan *chan) static int open_one_chan(struct chan *chan)
{ {
int fd, err; int fd, err;
@ -137,11 +131,9 @@ void chan_enable_winch(struct chan *chan, struct tty_struct *tty)
static void line_timer_cb(struct work_struct *work) static void line_timer_cb(struct work_struct *work)
{ {
struct line *line = container_of(work, struct line, task.work); struct line *line = container_of(work, struct line, task.work);
struct tty_struct *tty = tty_port_tty_get(&line->port);
if (!line->throttled) if (!line->throttled)
chan_interrupt(line, tty, line->driver->read_irq); chan_interrupt(line, line->driver->read_irq);
tty_kref_put(tty);
} }
int enable_chan(struct line *line) int enable_chan(struct line *line)
@ -552,8 +544,9 @@ int parse_chan_pair(char *str, struct line *line, int device,
return 0; return 0;
} }
void chan_interrupt(struct line *line, struct tty_struct *tty, int irq) void chan_interrupt(struct line *line, int irq)
{ {
struct tty_port *port = &line->port;
struct chan *chan = line->chan_in; struct chan *chan = line->chan_in;
int err; int err;
char c; char c;
@ -562,21 +555,24 @@ void chan_interrupt(struct line *line, struct tty_struct *tty, int irq)
goto out; goto out;
do { do {
if (tty && !tty_buffer_request_room(tty, 1)) { if (!tty_buffer_request_room(port, 1)) {
schedule_delayed_work(&line->task, 1); schedule_delayed_work(&line->task, 1);
goto out; goto out;
} }
err = chan->ops->read(chan->fd, &c, chan->data); err = chan->ops->read(chan->fd, &c, chan->data);
if (err > 0) if (err > 0)
tty_receive_char(tty, c); tty_insert_flip_char(port, c, TTY_NORMAL);
} while (err > 0); } while (err > 0);
if (err == 0) if (err == 0)
reactivate_fd(chan->fd, irq); reactivate_fd(chan->fd, irq);
if (err == -EIO) { if (err == -EIO) {
if (chan->primary) { if (chan->primary) {
if (tty != NULL) struct tty_struct *tty = tty_port_tty_get(&line->port);
if (tty != NULL) {
tty_hangup(tty); tty_hangup(tty);
tty_kref_put(tty);
}
if (line->chan_out != chan) if (line->chan_out != chan)
close_one_chan(line->chan_out, 1); close_one_chan(line->chan_out, 1);
} }
@ -585,6 +581,5 @@ void chan_interrupt(struct line *line, struct tty_struct *tty, int irq)
return; return;
} }
out: out:
if (tty) tty_flip_buffer_push(port);
tty_flip_buffer_push(tty);
} }

View File

@ -19,11 +19,10 @@ static irqreturn_t line_interrupt(int irq, void *data)
{ {
struct chan *chan = data; struct chan *chan = data;
struct line *line = chan->line; struct line *line = chan->line;
struct tty_struct *tty = tty_port_tty_get(&line->port);
if (line) if (line)
chan_interrupt(line, tty, irq); chan_interrupt(line, irq);
tty_kref_put(tty);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -234,7 +233,7 @@ void line_unthrottle(struct tty_struct *tty)
struct line *line = tty->driver_data; struct line *line = tty->driver_data;
line->throttled = 0; line->throttled = 0;
chan_interrupt(line, tty, line->driver->read_irq); chan_interrupt(line, line->driver->read_irq);
/* /*
* Maybe there is enough stuff pending that calling the interrupt * Maybe there is enough stuff pending that calling the interrupt

View File

@ -2,6 +2,7 @@ config LGUEST_GUEST
bool "Lguest guest support" bool "Lguest guest support"
select PARAVIRT select PARAVIRT
depends on X86_32 depends on X86_32
select TTY
select VIRTUALIZATION select VIRTUALIZATION
select VIRTIO select VIRTIO
select VIRTIO_CONSOLE select VIRTIO_CONSOLE

View File

@ -132,6 +132,7 @@ choice
config XTENSA_PLATFORM_ISS config XTENSA_PLATFORM_ISS
bool "ISS" bool "ISS"
depends on TTY
select XTENSA_CALIBRATE_CCOUNT select XTENSA_CALIBRATE_CCOUNT
select SERIAL_CONSOLE select SERIAL_CONSOLE
select XTENSA_ISS_NETWORK select XTENSA_ISS_NETWORK

View File

@ -58,7 +58,8 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
tty->port = &serial_port; tty->port = &serial_port;
spin_lock(&timer_lock); spin_lock(&timer_lock);
if (tty->count == 1) { if (tty->count == 1) {
setup_timer(&serial_timer, rs_poll, (unsigned long)tty); setup_timer(&serial_timer, rs_poll,
(unsigned long)&serial_port);
mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE); mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE);
} }
spin_unlock(&timer_lock); spin_unlock(&timer_lock);
@ -97,8 +98,7 @@ static int rs_write(struct tty_struct * tty,
static void rs_poll(unsigned long priv) static void rs_poll(unsigned long priv)
{ {
struct tty_struct* tty = (struct tty_struct*) priv; struct tty_port *port = (struct tty_port *)priv;
struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
int i = 0; int i = 0;
unsigned char c; unsigned char c;
@ -107,12 +107,12 @@ static void rs_poll(unsigned long priv)
while (__simc(SYS_select_one, 0, XTISS_SELECT_ONE_READ, (int)&tv,0,0)){ while (__simc(SYS_select_one, 0, XTISS_SELECT_ONE_READ, (int)&tv,0,0)){
__simc (SYS_read, 0, (unsigned long)&c, 1, 0, 0); __simc (SYS_read, 0, (unsigned long)&c, 1, 0, 0);
tty_insert_flip_char(tty, c, TTY_NORMAL); tty_insert_flip_char(port, c, TTY_NORMAL);
i++; i++;
} }
if (i) if (i)
tty_flip_buffer_push(tty); tty_flip_buffer_push(port);
mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE); mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE);

View File

@ -26,6 +26,7 @@ config BT_HCIBTSDIO
config BT_HCIUART config BT_HCIUART
tristate "HCI UART driver" tristate "HCI UART driver"
depends on TTY
help help
Bluetooth HCI UART driver. Bluetooth HCI UART driver.
This driver is required if you want to use Bluetooth devices with This driver is required if you want to use Bluetooth devices with

View File

@ -53,7 +53,7 @@ source "drivers/tty/serial/Kconfig"
config TTY_PRINTK config TTY_PRINTK
bool "TTY driver to output user messages via printk" bool "TTY driver to output user messages via printk"
depends on EXPERT depends on EXPERT && TTY
default n default n
---help--- ---help---
If you say Y here, the support for writing user messages (i.e. If you say Y here, the support for writing user messages (i.e.
@ -159,7 +159,7 @@ source "drivers/tty/hvc/Kconfig"
config VIRTIO_CONSOLE config VIRTIO_CONSOLE
tristate "Virtio console" tristate "Virtio console"
depends on VIRTIO depends on VIRTIO && TTY
select HVC_DRIVER select HVC_DRIVER
help help
Virtio console for use with lguest and other hypervisors. Virtio console for use with lguest and other hypervisors.
@ -392,6 +392,7 @@ config XILINX_HWICAP
config R3964 config R3964
tristate "Siemens R3964 line discipline" tristate "Siemens R3964 line discipline"
depends on TTY
---help--- ---help---
This driver allows synchronous communication with devices using the This driver allows synchronous communication with devices using the
Siemens R3964 packet protocol. Unless you are dealing with special Siemens R3964 packet protocol. Unless you are dealing with special
@ -439,7 +440,7 @@ source "drivers/char/pcmcia/Kconfig"
config MWAVE config MWAVE
tristate "ACP Modem (Mwave) support" tristate "ACP Modem (Mwave) support"
depends on X86 depends on X86 && TTY
select SERIAL_8250 select SERIAL_8250
---help--- ---help---
The ACP modem (Mwave) for Linux is a WinModem. It is composed of a The ACP modem (Mwave) for Linux is a WinModem. It is composed of a

View File

@ -7,7 +7,7 @@ menu "PCMCIA character devices"
config SYNCLINK_CS config SYNCLINK_CS
tristate "SyncLink PC Card support" tristate "SyncLink PC Card support"
depends on PCMCIA depends on PCMCIA && TTY
help help
Enable support for the SyncLink PC Card serial adapter, running Enable support for the SyncLink PC Card serial adapter, running
asynchronous and HDLC communications up to 512Kbps. The port is asynchronous and HDLC communications up to 512Kbps. The port is
@ -45,7 +45,7 @@ config CARDMAN_4040
config IPWIRELESS config IPWIRELESS
tristate "IPWireless 3G UMTS PCMCIA card support" tristate "IPWireless 3G UMTS PCMCIA card support"
depends on PCMCIA && NETDEVICES depends on PCMCIA && NETDEVICES && TTY
select PPP select PPP
help help
This is a driver for 3G UMTS PCMCIA card from IPWireless company. In This is a driver for 3G UMTS PCMCIA card from IPWireless company. In

View File

@ -210,7 +210,7 @@ typedef struct _mgslpc_info {
char testing_irq; char testing_irq;
unsigned int init_error; /* startup error (DIAGS) */ unsigned int init_error; /* startup error (DIAGS) */
char flag_buf[MAX_ASYNC_BUFFER_SIZE]; char *flag_buf;
bool drop_rts_on_tx_done; bool drop_rts_on_tx_done;
struct _input_signal_events input_signal_events; struct _input_signal_events input_signal_events;
@ -765,9 +765,6 @@ static void bh_handler(struct work_struct *work)
struct tty_struct *tty; struct tty_struct *tty;
int action; int action;
if (!info)
return;
if (debug_level >= DEBUG_LEVEL_BH) if (debug_level >= DEBUG_LEVEL_BH)
printk( "%s(%d):bh_handler(%s) entry\n", printk( "%s(%d):bh_handler(%s) entry\n",
__FILE__,__LINE__,info->device_name); __FILE__,__LINE__,info->device_name);
@ -886,21 +883,14 @@ static void rx_ready_hdlc(MGSLPC_INFO *info, int eom)
issue_command(info, CHA, CMD_RXFIFO); issue_command(info, CHA, CMD_RXFIFO);
} }
static void rx_ready_async(MGSLPC_INFO *info, int tcd, struct tty_struct *tty) static void rx_ready_async(MGSLPC_INFO *info, int tcd)
{ {
struct tty_port *port = &info->port;
unsigned char data, status, flag; unsigned char data, status, flag;
int fifo_count; int fifo_count;
int work = 0; int work = 0;
struct mgsl_icount *icount = &info->icount; struct mgsl_icount *icount = &info->icount;
if (!tty) {
/* tty is not available anymore */
issue_command(info, CHA, CMD_RXRESET);
if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):rx_ready_async(tty=NULL)\n",__FILE__,__LINE__);
return;
}
if (tcd) { if (tcd) {
/* early termination, get FIFO count from RBCL register */ /* early termination, get FIFO count from RBCL register */
fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f); fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f);
@ -913,7 +903,7 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd, struct tty_struct *tty)
} else } else
fifo_count = 32; fifo_count = 32;
tty_buffer_request_room(tty, fifo_count); tty_buffer_request_room(port, fifo_count);
/* Flush received async data to receive data buffer. */ /* Flush received async data to receive data buffer. */
while (fifo_count) { while (fifo_count) {
data = read_reg(info, CHA + RXFIFO); data = read_reg(info, CHA + RXFIFO);
@ -944,7 +934,7 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd, struct tty_struct *tty)
else if (status & BIT6) else if (status & BIT6)
flag = TTY_FRAME; flag = TTY_FRAME;
} }
work += tty_insert_flip_char(tty, data, flag); work += tty_insert_flip_char(port, data, flag);
} }
issue_command(info, CHA, CMD_RXFIFO); issue_command(info, CHA, CMD_RXFIFO);
@ -957,7 +947,7 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd, struct tty_struct *tty)
} }
if (work) if (work)
tty_flip_buffer_push(tty); tty_flip_buffer_push(port);
} }
@ -1217,7 +1207,7 @@ static irqreturn_t mgslpc_isr(int dummy, void *dev_id)
if (info->params.mode == MGSL_MODE_HDLC) if (info->params.mode == MGSL_MODE_HDLC)
rx_ready_hdlc(info, isr & IRQ_RXEOM); rx_ready_hdlc(info, isr & IRQ_RXEOM);
else else
rx_ready_async(info, isr & IRQ_RXEOM, tty); rx_ready_async(info, isr & IRQ_RXEOM);
} }
/* transmit IRQs */ /* transmit IRQs */
@ -1353,7 +1343,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
reset_device(info); reset_device(info);
if (!tty || tty->termios.c_cflag & HUPCL) { if (!tty || tty->termios.c_cflag & HUPCL) {
info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
set_signals(info); set_signals(info);
} }
@ -1415,12 +1405,12 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty)
cflag = tty->termios.c_cflag; cflag = tty->termios.c_cflag;
/* if B0 rate (hangup) specified then negate DTR and RTS */ /* if B0 rate (hangup) specified then negate RTS and DTR */
/* otherwise assert DTR and RTS */ /* otherwise assert RTS and DTR */
if (cflag & CBAUD) if (cflag & CBAUD)
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR;
else else
info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
/* byte size and parity */ /* byte size and parity */
@ -2311,7 +2301,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
/* Handle transition to B0 status */ /* Handle transition to B0 status */
if (old_termios->c_cflag & CBAUD && if (old_termios->c_cflag & CBAUD &&
!(tty->termios.c_cflag & CBAUD)) { !(tty->termios.c_cflag & CBAUD)) {
info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
spin_lock_irqsave(&info->lock,flags); spin_lock_irqsave(&info->lock,flags);
set_signals(info); set_signals(info);
spin_unlock_irqrestore(&info->lock,flags); spin_unlock_irqrestore(&info->lock,flags);
@ -2474,9 +2464,9 @@ static void dtr_rts(struct tty_port *port, int onoff)
spin_lock_irqsave(&info->lock,flags); spin_lock_irqsave(&info->lock,flags);
if (onoff) if (onoff)
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR;
else else
info->serial_signals &= ~SerialSignal_RTS + SerialSignal_DTR; info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
set_signals(info); set_signals(info);
spin_unlock_irqrestore(&info->lock,flags); spin_unlock_irqrestore(&info->lock,flags);
} }
@ -2521,7 +2511,7 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
goto cleanup; goto cleanup;
} }
tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
spin_lock_irqsave(&info->netlock, flags); spin_lock_irqsave(&info->netlock, flags);
if (info->netcount) { if (info->netcount) {
@ -2674,6 +2664,14 @@ static int rx_alloc_buffers(MGSLPC_INFO *info)
if (info->rx_buf == NULL) if (info->rx_buf == NULL)
return -ENOMEM; return -ENOMEM;
/* unused flag buffer to satisfy receive_buf calling interface */
info->flag_buf = kzalloc(info->max_frame_size, GFP_KERNEL);
if (!info->flag_buf) {
kfree(info->rx_buf);
info->rx_buf = NULL;
return -ENOMEM;
}
rx_reset_buffers(info); rx_reset_buffers(info);
return 0; return 0;
} }
@ -2682,6 +2680,8 @@ static void rx_free_buffers(MGSLPC_INFO *info)
{ {
kfree(info->rx_buf); kfree(info->rx_buf);
info->rx_buf = NULL; info->rx_buf = NULL;
kfree(info->flag_buf);
info->flag_buf = NULL;
} }
static int claim_resources(MGSLPC_INFO *info) static int claim_resources(MGSLPC_INFO *info)
@ -3575,8 +3575,8 @@ static void get_signals(MGSLPC_INFO *info)
{ {
unsigned char status = 0; unsigned char status = 0;
/* preserve DTR and RTS */ /* preserve RTS and DTR */
info->serial_signals &= SerialSignal_DTR + SerialSignal_RTS; info->serial_signals &= SerialSignal_RTS | SerialSignal_DTR;
if (read_reg(info, CHB + VSTR) & BIT7) if (read_reg(info, CHB + VSTR) & BIT7)
info->serial_signals |= SerialSignal_DCD; info->serial_signals |= SerialSignal_DCD;
@ -3590,7 +3590,7 @@ static void get_signals(MGSLPC_INFO *info)
info->serial_signals |= SerialSignal_DSR; info->serial_signals |= SerialSignal_DSR;
} }
/* Set the state of DTR and RTS based on contents of /* Set the state of RTS and DTR based on contents of
* serial_signals member of device extension. * serial_signals member of device extension.
*/ */
static void set_signals(MGSLPC_INFO *info) static void set_signals(MGSLPC_INFO *info)
@ -4009,8 +4009,8 @@ static int hdlcdev_open(struct net_device *dev)
spin_unlock_irqrestore(&info->netlock, flags); spin_unlock_irqrestore(&info->netlock, flags);
return rc; return rc;
} }
/* assert DTR and RTS, apply hardware settings */ /* assert RTS and DTR, apply hardware settings */
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR;
mgslpc_program_hw(info, tty); mgslpc_program_hw(info, tty);
tty_kref_put(tty); tty_kref_put(tty);

View File

@ -27,6 +27,7 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_crtc.h> #include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>

View File

@ -802,6 +802,7 @@ config I2C_PARPORT_LIGHT
config I2C_TAOS_EVM config I2C_TAOS_EVM
tristate "TAOS evaluation module" tristate "TAOS evaluation module"
depends on TTY
select SERIO select SERIO
select SERIO_SERPORT select SERIO_SERPORT
default n default n

View File

@ -36,6 +36,7 @@ config SERIO_I8042
config SERIO_SERPORT config SERIO_SERPORT
tristate "Serial port line discipline" tristate "Serial port line discipline"
default y default y
depends on TTY
help help
Say Y here if you plan to use an input device (mouse, joystick, Say Y here if you plan to use an input device (mouse, joystick,
tablet, 6dof) that communicates over the RS232 serial (COM) port. tablet, 6dof) that communicates over the RS232 serial (COM) port.

View File

@ -1,6 +1,6 @@
config SERIAL_IPOCTAL config SERIAL_IPOCTAL
tristate "IndustryPack IP-OCTAL uart support" tristate "IndustryPack IP-OCTAL uart support"
depends on IPACK_BUS depends on IPACK_BUS && TTY
help help
This driver supports the IPOCTAL serial port device for the IndustryPack bus. This driver supports the IPOCTAL serial port device for the IndustryPack bus.
default n default n

View File

@ -133,9 +133,9 @@ static int ipoctal_get_icount(struct tty_struct *tty,
return 0; return 0;
} }
static void ipoctal_irq_rx(struct ipoctal_channel *channel, static void ipoctal_irq_rx(struct ipoctal_channel *channel, u8 sr)
struct tty_struct *tty, u8 sr)
{ {
struct tty_port *port = &channel->tty_port;
unsigned char value; unsigned char value;
unsigned char flag = TTY_NORMAL; unsigned char flag = TTY_NORMAL;
u8 isr; u8 isr;
@ -149,7 +149,7 @@ static void ipoctal_irq_rx(struct ipoctal_channel *channel,
if (sr & SR_OVERRUN_ERROR) { if (sr & SR_OVERRUN_ERROR) {
channel->stats.overrun_err++; channel->stats.overrun_err++;
/* Overrun doesn't affect the current character*/ /* Overrun doesn't affect the current character*/
tty_insert_flip_char(tty, 0, TTY_OVERRUN); tty_insert_flip_char(port, 0, TTY_OVERRUN);
} }
if (sr & SR_PARITY_ERROR) { if (sr & SR_PARITY_ERROR) {
channel->stats.parity_err++; channel->stats.parity_err++;
@ -165,7 +165,7 @@ static void ipoctal_irq_rx(struct ipoctal_channel *channel,
flag = TTY_BREAK; flag = TTY_BREAK;
} }
} }
tty_insert_flip_char(tty, value, flag); tty_insert_flip_char(port, value, flag);
/* Check if there are more characters in RX FIFO /* Check if there are more characters in RX FIFO
* If there are more, the isr register for this channel * If there are more, the isr register for this channel
@ -175,7 +175,7 @@ static void ipoctal_irq_rx(struct ipoctal_channel *channel,
sr = ioread8(&channel->regs->r.sr); sr = ioread8(&channel->regs->r.sr);
} while (isr & channel->isr_rx_rdy_mask); } while (isr & channel->isr_rx_rdy_mask);
tty_flip_buffer_push(tty); tty_flip_buffer_push(port);
} }
static void ipoctal_irq_tx(struct ipoctal_channel *channel) static void ipoctal_irq_tx(struct ipoctal_channel *channel)
@ -208,15 +208,11 @@ static void ipoctal_irq_tx(struct ipoctal_channel *channel)
static void ipoctal_irq_channel(struct ipoctal_channel *channel) static void ipoctal_irq_channel(struct ipoctal_channel *channel)
{ {
u8 isr, sr; u8 isr, sr;
struct tty_struct *tty;
/* If there is no client, skip the check */ /* If there is no client, skip the check */
if (!atomic_read(&channel->open)) if (!atomic_read(&channel->open))
return; return;
tty = tty_port_tty_get(&channel->tty_port);
if (!tty)
return;
/* The HW is organized in pair of channels. See which register we need /* The HW is organized in pair of channels. See which register we need
* to read from */ * to read from */
isr = ioread8(&channel->block_regs->r.isr); isr = ioread8(&channel->block_regs->r.isr);
@ -235,14 +231,13 @@ static void ipoctal_irq_channel(struct ipoctal_channel *channel)
/* RX data */ /* RX data */
if ((isr & channel->isr_rx_rdy_mask) && (sr & SR_RX_READY)) if ((isr & channel->isr_rx_rdy_mask) && (sr & SR_RX_READY))
ipoctal_irq_rx(channel, tty, sr); ipoctal_irq_rx(channel, sr);
/* TX of each character */ /* TX of each character */
if ((isr & channel->isr_tx_rdy_mask) && (sr & SR_TX_READY)) if ((isr & channel->isr_tx_rdy_mask) && (sr & SR_TX_READY))
ipoctal_irq_tx(channel); ipoctal_irq_tx(channel);
tty_flip_buffer_push(tty); tty_flip_buffer_push(&channel->tty_port);
tty_kref_put(tty);
} }
static irqreturn_t ipoctal_irq_handler(void *arg) static irqreturn_t ipoctal_irq_handler(void *arg)

View File

@ -22,6 +22,7 @@ if ISDN
menuconfig ISDN_I4L menuconfig ISDN_I4L
tristate "Old ISDN4Linux (deprecated)" tristate "Old ISDN4Linux (deprecated)"
depends on TTY
---help--- ---help---
This driver allows you to use an ISDN adapter for networking This driver allows you to use an ISDN adapter for networking
connections and as dialin/out device. The isdn-tty's have a built connections and as dialin/out device. The isdn-tty's have a built

View File

@ -18,6 +18,7 @@ config CAPI_TRACE
config ISDN_CAPI_MIDDLEWARE config ISDN_CAPI_MIDDLEWARE
bool "CAPI2.0 Middleware support" bool "CAPI2.0 Middleware support"
depends on TTY
help help
This option will enhance the capabilities of the /dev/capi20 This option will enhance the capabilities of the /dev/capi20
interface. It will provide a means of moving a data connection, interface. It will provide a means of moving a data connection,

View File

@ -1,5 +1,6 @@
menuconfig ISDN_DRV_GIGASET menuconfig ISDN_DRV_GIGASET
tristate "Siemens Gigaset support" tristate "Siemens Gigaset support"
depends on TTY
select CRC_CCITT select CRC_CCITT
select BITREVERSE select BITREVERSE
help help

View File

@ -134,7 +134,7 @@ static int if_open(struct tty_struct *tty, struct file *filp)
if (cs->port.count == 1) { if (cs->port.count == 1) {
tty_port_tty_set(&cs->port, tty); tty_port_tty_set(&cs->port, tty);
tty->low_latency = 1; cs->port.low_latency = 1;
} }
mutex_unlock(&cs->mutex); mutex_unlock(&cs->mutex);
@ -546,16 +546,8 @@ void gigaset_if_free(struct cardstate *cs)
void gigaset_if_receive(struct cardstate *cs, void gigaset_if_receive(struct cardstate *cs,
unsigned char *buffer, size_t len) unsigned char *buffer, size_t len)
{ {
struct tty_struct *tty = tty_port_tty_get(&cs->port); tty_insert_flip_string(&cs->port, buffer, len);
tty_flip_buffer_push(&cs->port);
if (tty == NULL) {
gig_dbg(DEBUG_IF, "receive on closed device");
return;
}
tty_insert_flip_string(tty, buffer, len);
tty_flip_buffer_push(tty);
tty_kref_put(tty);
} }
EXPORT_SYMBOL_GPL(gigaset_if_receive); EXPORT_SYMBOL_GPL(gigaset_if_receive);

View File

@ -76,6 +76,7 @@ config MISDN_NETJET
tristate "Support for NETJet cards" tristate "Support for NETJet cards"
depends on MISDN depends on MISDN
depends on PCI depends on PCI
depends on TTY
select MISDN_IPAC select MISDN_IPAC
select ISDN_HDLC select ISDN_HDLC
select ISDN_I4L select ISDN_I4L

View File

@ -876,7 +876,7 @@ isdn_readbchan(int di, int channel, u_char *buf, u_char *fp, int len, wait_queue
* of the mapping (di,ch)<->minor, happen during the sleep? --he * of the mapping (di,ch)<->minor, happen during the sleep? --he
*/ */
int int
isdn_readbchan_tty(int di, int channel, struct tty_struct *tty, int cisco_hack) isdn_readbchan_tty(int di, int channel, struct tty_port *port, int cisco_hack)
{ {
int count; int count;
int count_pull; int count_pull;
@ -891,7 +891,7 @@ isdn_readbchan_tty(int di, int channel, struct tty_struct *tty, int cisco_hack)
if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
return 0; return 0;
len = tty_buffer_request_room(tty, dev->drv[di]->rcvcount[channel]); len = tty_buffer_request_room(port, dev->drv[di]->rcvcount[channel]);
if (len == 0) if (len == 0)
return len; return len;
@ -912,7 +912,7 @@ isdn_readbchan_tty(int di, int channel, struct tty_struct *tty, int cisco_hack)
while ((count_pull < skb->len) && (len > 0)) { while ((count_pull < skb->len) && (len > 0)) {
/* push every character but the last to the tty buffer directly */ /* push every character but the last to the tty buffer directly */
if (count_put) if (count_put)
tty_insert_flip_char(tty, last, TTY_NORMAL); tty_insert_flip_char(port, last, TTY_NORMAL);
len--; len--;
if (dev->drv[di]->DLEflag & DLEmask) { if (dev->drv[di]->DLEflag & DLEmask) {
last = DLE; last = DLE;
@ -940,7 +940,7 @@ isdn_readbchan_tty(int di, int channel, struct tty_struct *tty, int cisco_hack)
} }
count_put = count_pull; count_put = count_pull;
if (count_put > 1) if (count_put > 1)
tty_insert_flip_string(tty, skb->data, count_put - 1); tty_insert_flip_string(port, skb->data, count_put - 1);
last = skb->data[count_put - 1]; last = skb->data[count_put - 1];
len -= count_put; len -= count_put;
#ifdef CONFIG_ISDN_AUDIO #ifdef CONFIG_ISDN_AUDIO
@ -952,16 +952,16 @@ isdn_readbchan_tty(int di, int channel, struct tty_struct *tty, int cisco_hack)
* Now we can dequeue it. * Now we can dequeue it.
*/ */
if (cisco_hack) if (cisco_hack)
tty_insert_flip_char(tty, last, 0xFF); tty_insert_flip_char(port, last, 0xFF);
else else
tty_insert_flip_char(tty, last, TTY_NORMAL); tty_insert_flip_char(port, last, TTY_NORMAL);
#ifdef CONFIG_ISDN_AUDIO #ifdef CONFIG_ISDN_AUDIO
ISDN_AUDIO_SKB_LOCK(skb) = 0; ISDN_AUDIO_SKB_LOCK(skb) = 0;
#endif #endif
skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]); skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
dev_kfree_skb(skb); dev_kfree_skb(skb);
} else { } else {
tty_insert_flip_char(tty, last, TTY_NORMAL); tty_insert_flip_char(port, last, TTY_NORMAL);
/* Not yet emptied this buff, so it /* Not yet emptied this buff, so it
* must stay in the queue, for further calls * must stay in the queue, for further calls
* but we pull off the data we got until now. * but we pull off the data we got until now.

View File

@ -37,7 +37,7 @@ extern void isdn_timer_ctrl(int tf, int onoff);
extern void isdn_unexclusive_channel(int di, int ch); extern void isdn_unexclusive_channel(int di, int ch);
extern int isdn_getnum(char **); extern int isdn_getnum(char **);
extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *); extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
extern int isdn_readbchan_tty(int, int, struct tty_struct *, int); extern int isdn_readbchan_tty(int, int, struct tty_port *, int);
extern int isdn_get_free_channel(int, int, int, int, int, char *); extern int isdn_get_free_channel(int, int, int, int, int, char *);
extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *); extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
extern int register_isdn(isdn_if *i); extern int register_isdn(isdn_if *i);

View File

@ -60,18 +60,14 @@ static int si2bit[8] =
static int static int
isdn_tty_try_read(modem_info *info, struct sk_buff *skb) isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
{ {
struct tty_port *port = &info->port;
int c; int c;
int len; int len;
struct tty_struct *tty;
char last; char last;
if (!info->online) if (!info->online)
return 0; return 0;
tty = info->port.tty;
if (!tty)
return 0;
if (!(info->mcr & UART_MCR_RTS)) if (!(info->mcr & UART_MCR_RTS))
return 0; return 0;
@ -81,7 +77,7 @@ isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
#endif #endif
; ;
c = tty_buffer_request_room(tty, len); c = tty_buffer_request_room(port, len);
if (c < len) if (c < len)
return 0; return 0;
@ -91,25 +87,25 @@ isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
unsigned char *dp = skb->data; unsigned char *dp = skb->data;
while (--l) { while (--l) {
if (*dp == DLE) if (*dp == DLE)
tty_insert_flip_char(tty, DLE, 0); tty_insert_flip_char(port, DLE, 0);
tty_insert_flip_char(tty, *dp++, 0); tty_insert_flip_char(port, *dp++, 0);
} }
if (*dp == DLE) if (*dp == DLE)
tty_insert_flip_char(tty, DLE, 0); tty_insert_flip_char(port, DLE, 0);
last = *dp; last = *dp;
} else { } else {
#endif #endif
if (len > 1) if (len > 1)
tty_insert_flip_string(tty, skb->data, len - 1); tty_insert_flip_string(port, skb->data, len - 1);
last = skb->data[len - 1]; last = skb->data[len - 1];
#ifdef CONFIG_ISDN_AUDIO #ifdef CONFIG_ISDN_AUDIO
} }
#endif #endif
if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP) if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
tty_insert_flip_char(tty, last, 0xFF); tty_insert_flip_char(port, last, 0xFF);
else else
tty_insert_flip_char(tty, last, TTY_NORMAL); tty_insert_flip_char(port, last, TTY_NORMAL);
tty_flip_buffer_push(tty); tty_flip_buffer_push(port);
kfree_skb(skb); kfree_skb(skb);
return 1; return 1;
@ -126,7 +122,6 @@ isdn_tty_readmodem(void)
int midx; int midx;
int i; int i;
int r; int r;
struct tty_struct *tty;
modem_info *info; modem_info *info;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) { for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
@ -144,20 +139,21 @@ isdn_tty_readmodem(void)
if ((info->vonline & 1) && (info->emu.vpar[1])) if ((info->vonline & 1) && (info->emu.vpar[1]))
isdn_audio_eval_silence(info); isdn_audio_eval_silence(info);
#endif #endif
tty = info->port.tty; if (info->mcr & UART_MCR_RTS) {
if (tty) { /* CISCO AsyncPPP Hack */
if (info->mcr & UART_MCR_RTS) { if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
/* CISCO AsyncPPP Hack */ r = isdn_readbchan_tty(info->isdn_driver,
if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP)) info->isdn_channel,
r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 0); &info->port, 0);
else else
r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 1); r = isdn_readbchan_tty(info->isdn_driver,
if (r) info->isdn_channel,
tty_flip_buffer_push(tty); &info->port, 1);
} else if (r)
r = 1; tty_flip_buffer_push(&info->port);
} else } else
r = 1; r = 1;
if (r) { if (r) {
info->rcvsched = 0; info->rcvsched = 0;
resched = 1; resched = 1;
@ -2229,7 +2225,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
void void
isdn_tty_at_cout(char *msg, modem_info *info) isdn_tty_at_cout(char *msg, modem_info *info)
{ {
struct tty_struct *tty; struct tty_port *port = &info->port;
atemu *m = &info->emu; atemu *m = &info->emu;
char *p; char *p;
char c; char c;
@ -2246,15 +2242,14 @@ isdn_tty_at_cout(char *msg, modem_info *info)
l = strlen(msg); l = strlen(msg);
spin_lock_irqsave(&info->readlock, flags); spin_lock_irqsave(&info->readlock, flags);
tty = info->port.tty; if (port->flags & ASYNC_CLOSING) {
if ((info->port.flags & ASYNC_CLOSING) || (!tty)) {
spin_unlock_irqrestore(&info->readlock, flags); spin_unlock_irqrestore(&info->readlock, flags);
return; return;
} }
/* use queue instead of direct, if online and */ /* use queue instead of direct, if online and */
/* data is in queue or buffer is full */ /* data is in queue or buffer is full */
if (info->online && ((tty_buffer_request_room(tty, l) < l) || if (info->online && ((tty_buffer_request_room(port, l) < l) ||
!skb_queue_empty(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel]))) { !skb_queue_empty(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel]))) {
skb = alloc_skb(l, GFP_ATOMIC); skb = alloc_skb(l, GFP_ATOMIC);
if (!skb) { if (!skb) {
@ -2285,7 +2280,7 @@ isdn_tty_at_cout(char *msg, modem_info *info)
if (skb) { if (skb) {
*sp++ = c; *sp++ = c;
} else { } else {
if (tty_insert_flip_char(tty, c, TTY_NORMAL) == 0) if (tty_insert_flip_char(port, c, TTY_NORMAL) == 0)
break; break;
} }
} }
@ -2299,7 +2294,7 @@ isdn_tty_at_cout(char *msg, modem_info *info)
} else { } else {
spin_unlock_irqrestore(&info->readlock, flags); spin_unlock_irqrestore(&info->readlock, flags);
tty_flip_buffer_push(tty); tty_flip_buffer_push(port);
} }
} }

View File

@ -1,6 +1,6 @@
config LGUEST config LGUEST
tristate "Linux hypervisor example code" tristate "Linux hypervisor example code"
depends on X86_32 && EVENTFD depends on X86_32 && EVENTFD && TTY
select HVC_DRIVER select HVC_DRIVER
---help--- ---help---
This is a very simple module which allows you to run This is a very simple module which allows you to run

View File

@ -4,7 +4,7 @@
menu "Texas Instruments WL128x FM driver (ST based)" menu "Texas Instruments WL128x FM driver (ST based)"
config RADIO_WL128X config RADIO_WL128X
tristate "Texas Instruments WL128x FM Radio" tristate "Texas Instruments WL128x FM Radio"
depends on VIDEO_V4L2 && RFKILL && GPIOLIB depends on VIDEO_V4L2 && RFKILL && GPIOLIB && TTY
select TI_ST if NET select TI_ST if NET
help help
Choose Y here if you have this FM radio chip. Choose Y here if you have this FM radio chip.

View File

@ -127,7 +127,7 @@ config PHANTOM
config INTEL_MID_PTI config INTEL_MID_PTI
tristate "Parallel Trace Interface for MIPI P1149.7 cJTAG standard" tristate "Parallel Trace Interface for MIPI P1149.7 cJTAG standard"
depends on PCI depends on PCI && TTY
default n default n
help help
The PTI (Parallel Trace Interface) driver directs The PTI (Parallel Trace Interface) driver directs

View File

@ -5,7 +5,7 @@
menu "Texas Instruments shared transport line discipline" menu "Texas Instruments shared transport line discipline"
config TI_ST config TI_ST
tristate "Shared transport core driver" tristate "Shared transport core driver"
depends on NET && GPIOLIB depends on NET && GPIOLIB && TTY
select FW_LOADER select FW_LOADER
help help
This enables the shared transport core driver for TI This enables the shared transport core driver for TI

View File

@ -52,6 +52,7 @@ config MMC_BLOCK_BOUNCE
config SDIO_UART config SDIO_UART
tristate "SDIO UART/GPS class support" tristate "SDIO UART/GPS class support"
depends on TTY
help help
SDIO function driver for SDIO cards that implements the UART SDIO function driver for SDIO cards that implements the UART
class, as well as the GPS class which appears like a UART. class, as well as the GPS class which appears like a UART.

View File

@ -381,7 +381,6 @@ static void sdio_uart_stop_rx(struct sdio_uart_port *port)
static void sdio_uart_receive_chars(struct sdio_uart_port *port, static void sdio_uart_receive_chars(struct sdio_uart_port *port,
unsigned int *status) unsigned int *status)
{ {
struct tty_struct *tty = tty_port_tty_get(&port->port);
unsigned int ch, flag; unsigned int ch, flag;
int max_count = 256; int max_count = 256;
@ -418,23 +417,19 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port,
} }
if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0) if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0)
if (tty) tty_insert_flip_char(&port->port, ch, flag);
tty_insert_flip_char(tty, ch, flag);
/* /*
* Overrun is special. Since it's reported immediately, * Overrun is special. Since it's reported immediately,
* it doesn't affect the current character. * it doesn't affect the current character.
*/ */
if (*status & ~port->ignore_status_mask & UART_LSR_OE) if (*status & ~port->ignore_status_mask & UART_LSR_OE)
if (tty) tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
*status = sdio_in(port, UART_LSR); *status = sdio_in(port, UART_LSR);
} while ((*status & UART_LSR_DR) && (max_count-- > 0)); } while ((*status & UART_LSR_DR) && (max_count-- > 0));
if (tty) {
tty_flip_buffer_push(tty); tty_flip_buffer_push(&port->port);
tty_kref_put(tty);
}
} }
static void sdio_uart_transmit_chars(struct sdio_uart_port *port) static void sdio_uart_transmit_chars(struct sdio_uart_port *port)

View File

@ -6,7 +6,7 @@ comment "CAIF transport drivers"
config CAIF_TTY config CAIF_TTY
tristate "CAIF TTY transport driver" tristate "CAIF TTY transport driver"
depends on CAIF depends on CAIF && TTY
default n default n
---help--- ---help---
The CAIF TTY transport driver is a Line Discipline (ldisc) The CAIF TTY transport driver is a Line Discipline (ldisc)

View File

@ -91,7 +91,7 @@ static inline void update_tty_status(struct ser_device *ser)
ser->tty->hw_stopped << 4 | ser->tty->hw_stopped << 4 |
ser->tty->flow_stopped << 3 | ser->tty->flow_stopped << 3 |
ser->tty->packet << 2 | ser->tty->packet << 2 |
ser->tty->low_latency << 1 | ser->tty->port->low_latency << 1 |
ser->tty->warned; ser->tty->warned;
} }
static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty) static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty)

View File

@ -11,6 +11,7 @@ config CAN_VCAN
config CAN_SLCAN config CAN_SLCAN
tristate "Serial / USB serial CAN Adaptors (slcan)" tristate "Serial / USB serial CAN Adaptors (slcan)"
depends on TTY
---help--- ---help---
CAN driver for several 'low cost' CAN interfaces that are attached CAN driver for several 'low cost' CAN interfaces that are attached
via serial lines or via USB-to-serial adapters using the LAWICEL via serial lines or via USB-to-serial adapters using the LAWICEL

View File

@ -1,6 +1,6 @@
config MKISS config MKISS
tristate "Serial port KISS driver" tristate "Serial port KISS driver"
depends on AX25 depends on AX25 && TTY
select CRC16 select CRC16
---help--- ---help---
KISS is a protocol used for the exchange of data between a computer KISS is a protocol used for the exchange of data between a computer
@ -18,7 +18,7 @@ config MKISS
config 6PACK config 6PACK
tristate "Serial port 6PACK driver" tristate "Serial port 6PACK driver"
depends on AX25 depends on AX25 && TTY
---help--- ---help---
6pack is a transmission protocol for the data exchange between your 6pack is a transmission protocol for the data exchange between your
PC and your TNC (the Terminal Node Controller acts as a kind of PC and your TNC (the Terminal Node Controller acts as a kind of

View File

@ -5,7 +5,7 @@ comment "SIR device drivers"
config IRTTY_SIR config IRTTY_SIR
tristate "IrTTY (uses Linux serial driver)" tristate "IrTTY (uses Linux serial driver)"
depends on IRDA depends on IRDA && TTY
help help
Say Y here if you want to build support for the IrTTY line Say Y here if you want to build support for the IrTTY line
discipline. To compile it as a module, choose M here: the module discipline. To compile it as a module, choose M here: the module

View File

@ -210,7 +210,7 @@ static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t
* been received, which can now be decapsulated and delivered for * been received, which can now be decapsulated and delivered for
* further processing * further processing
* *
* calling context depends on underlying driver and tty->low_latency! * calling context depends on underlying driver and tty->port->low_latency!
* for example (low_latency: 1 / 0): * for example (low_latency: 1 / 0):
* serial.c: uart-interrupt / softint * serial.c: uart-interrupt / softint
* usbserial: urb-complete-interrupt / softint * usbserial: urb-complete-interrupt / softint

View File

@ -147,6 +147,7 @@ config PPPOL2TP
Support for PPP-over-L2TP socket family. L2TP is a protocol Support for PPP-over-L2TP socket family. L2TP is a protocol
used by ISPs and enterprises to tunnel PPP traffic over UDP used by ISPs and enterprises to tunnel PPP traffic over UDP
tunnels. L2TP is replacing PPTP for VPN uses. tunnels. L2TP is replacing PPTP for VPN uses.
if TTY
config PPP_ASYNC config PPP_ASYNC
tristate "PPP support for async serial ports" tristate "PPP support for async serial ports"
@ -172,4 +173,6 @@ config PPP_SYNC_TTY
To compile this driver as a module, choose M here. To compile this driver as a module, choose M here.
endif # TTY
endif # PPP endif # PPP

View File

@ -4,6 +4,7 @@
config SLIP config SLIP
tristate "SLIP (serial line) support" tristate "SLIP (serial line) support"
depends on TTY
---help--- ---help---
Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to
connect to your Internet service provider or to connect to some connect to your Internet service provider or to connect to some

View File

@ -443,7 +443,7 @@ config USB_NET_QMI_WWAN
config USB_HSO config USB_HSO
tristate "Option USB High Speed Mobile Devices" tristate "Option USB High Speed Mobile Devices"
depends on USB && RFKILL depends on USB && RFKILL && TTY
default n default n
help help
Choose this option if you have an Option HSDPA/HSUPA card. Choose this option if you have an Option HSDPA/HSUPA card.
@ -491,7 +491,7 @@ config USB_SIERRA_NET
config USB_VL600 config USB_VL600
tristate "LG VL600 modem dongle" tristate "LG VL600 modem dongle"
depends on USB_NET_CDCETHER depends on USB_NET_CDCETHER && TTY
select USB_ACM select USB_ACM
help help
Select this if you want to use an LG Electronics 4G/LTE usb modem Select this if you want to use an LG Electronics 4G/LTE usb modem

View File

@ -2035,25 +2035,23 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
tty = tty_port_tty_get(&serial->port); tty = tty_port_tty_get(&serial->port);
/* Push data to tty */ /* Push data to tty */
if (tty) { write_length_remaining = urb->actual_length -
write_length_remaining = urb->actual_length - serial->curr_rx_urb_offset;
serial->curr_rx_urb_offset; D1("data to push to tty");
D1("data to push to tty"); while (write_length_remaining) {
while (write_length_remaining) { if (tty && test_bit(TTY_THROTTLED, &tty->flags)) {
if (test_bit(TTY_THROTTLED, &tty->flags)) { tty_kref_put(tty);
tty_kref_put(tty); return -1;
return -1;
}
curr_write_len = tty_insert_flip_string
(tty, urb->transfer_buffer +
serial->curr_rx_urb_offset,
write_length_remaining);
serial->curr_rx_urb_offset += curr_write_len;
write_length_remaining -= curr_write_len;
tty_flip_buffer_push(tty);
} }
tty_kref_put(tty); curr_write_len = tty_insert_flip_string(&serial->port,
urb->transfer_buffer + serial->curr_rx_urb_offset,
write_length_remaining);
serial->curr_rx_urb_offset += curr_write_len;
write_length_remaining -= curr_write_len;
tty_flip_buffer_push(&serial->port);
} }
tty_kref_put(tty);
if (write_length_remaining == 0) { if (write_length_remaining == 0) {
serial->curr_rx_urb_offset = 0; serial->curr_rx_urb_offset = 0;
serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;

View File

@ -375,7 +375,7 @@ config LAPBETHER
config X25_ASY config X25_ASY
tristate "X.25 async driver" tristate "X.25 async driver"
depends on LAPB && X25 depends on LAPB && X25 && TTY
---help--- ---help---
Send and receive X.25 frames over regular asynchronous serial Send and receive X.25 frames over regular asynchronous serial
lines such as telephone lines equipped with ordinary modems. lines such as telephone lines equipped with ordinary modems.

View File

@ -63,6 +63,7 @@ enum parport_pc_pci_cards {
timedia_9079b, timedia_9079b,
timedia_9079c, timedia_9079c,
wch_ch353_2s1p, wch_ch353_2s1p,
sunix_2s1p,
}; };
/* each element directly indexed from enum list, above */ /* each element directly indexed from enum list, above */
@ -148,8 +149,12 @@ static struct parport_pc_pci cards[] = {
/* timedia_9079b */ { 1, { { 2, 3 }, } }, /* timedia_9079b */ { 1, { { 2, 3 }, } },
/* timedia_9079c */ { 1, { { 2, 3 }, } }, /* timedia_9079c */ { 1, { { 2, 3 }, } },
/* wch_ch353_2s1p*/ { 1, { { 2, -1}, } }, /* wch_ch353_2s1p*/ { 1, { { 2, -1}, } },
/* sunix_2s1p */ { 1, { { 3, -1 }, } },
}; };
#define PCI_VENDOR_ID_SUNIX 0x1fd4
#define PCI_DEVICE_ID_SUNIX_1999 0x1999
static struct pci_device_id parport_serial_pci_tbl[] = { static struct pci_device_id parport_serial_pci_tbl[] = {
/* PCI cards */ /* PCI cards */
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_110L, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_110L,
@ -246,8 +251,18 @@ static struct pci_device_id parport_serial_pci_tbl[] = {
{ 0x1409, 0x7168, 0x1409, 0xb079, 0, 0, timedia_9079a }, { 0x1409, 0x7168, 0x1409, 0xb079, 0, 0, timedia_9079a },
{ 0x1409, 0x7168, 0x1409, 0xc079, 0, 0, timedia_9079b }, { 0x1409, 0x7168, 0x1409, 0xc079, 0, 0, timedia_9079b },
{ 0x1409, 0x7168, 0x1409, 0xd079, 0, 0, timedia_9079c }, { 0x1409, 0x7168, 0x1409, 0xd079, 0, 0, timedia_9079c },
/* WCH CARDS */ /* WCH CARDS */
{ 0x4348, 0x7053, 0x4348, 0x3253, 0, 0, wch_ch353_2s1p}, { 0x4348, 0x7053, 0x4348, 0x3253, 0, 0, wch_ch353_2s1p},
/*
* More SUNIX variations. At least one of these has part number
* '5079A but subdevice 0x102. That board reports 0x0708 as
* its PCI Class.
*/
{ PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, PCI_VENDOR_ID_SUNIX,
0x0102, 0, 0, sunix_2s1p },
{ 0, } /* terminate list */ { 0, } /* terminate list */
}; };
MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl); MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl);
@ -470,6 +485,12 @@ static struct pciserial_board pci_parport_serial_boards[] = {
.base_baud = 115200, .base_baud = 115200,
.uart_offset = 8, .uart_offset = 8,
}, },
[sunix_2s1p] = {
.flags = FL_BASE0|FL_BASE_BARS,
.num_ports = 2,
.base_baud = 921600,
.uart_offset = 8,
},
}; };
struct parport_serial_private { struct parport_serial_private {

View File

@ -17,7 +17,7 @@ config PPS_CLIENT_KTIMER
config PPS_CLIENT_LDISC config PPS_CLIENT_LDISC
tristate "PPS line discipline" tristate "PPS line discipline"
depends on PPS depends on PPS && TTY
help help
If you say yes here you get support for a PPS source connected If you say yes here you get support for a PPS source connected
with the CD (Carrier Detect) pin of your serial port. with the CD (Carrier Detect) pin of your serial port.

View File

@ -25,18 +25,27 @@
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/pps_kernel.h> #include <linux/pps_kernel.h>
#include <linux/bug.h>
#define PPS_TTY_MAGIC 0x0001 #define PPS_TTY_MAGIC 0x0001
static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status, static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status)
struct pps_event_time *ts)
{ {
struct pps_device *pps = (struct pps_device *)tty->disc_data; struct pps_device *pps;
struct pps_event_time ts;
BUG_ON(pps == NULL); pps_get_ts(&ts);
pps = pps_lookup_dev(tty);
/*
* This should never fail, but the ldisc locking is very
* convoluted, so don't crash just in case.
*/
if (WARN_ON_ONCE(pps == NULL))
return;
/* Now do the PPS event report */ /* Now do the PPS event report */
pps_event(pps, ts, status ? PPS_CAPTUREASSERT : pps_event(pps, &ts, status ? PPS_CAPTUREASSERT :
PPS_CAPTURECLEAR, NULL); PPS_CAPTURECLEAR, NULL);
dev_dbg(pps->dev, "PPS %s at %lu\n", dev_dbg(pps->dev, "PPS %s at %lu\n",
@ -67,9 +76,9 @@ static int pps_tty_open(struct tty_struct *tty)
pr_err("cannot register PPS source \"%s\"\n", info.path); pr_err("cannot register PPS source \"%s\"\n", info.path);
return -ENOMEM; return -ENOMEM;
} }
tty->disc_data = pps; pps->lookup_cookie = tty;
/* Should open N_TTY ldisc too */ /* Now open the base class N_TTY ldisc */
ret = alias_n_tty_open(tty); ret = alias_n_tty_open(tty);
if (ret < 0) { if (ret < 0) {
pr_err("cannot open tty ldisc \"%s\"\n", info.path); pr_err("cannot open tty ldisc \"%s\"\n", info.path);
@ -81,7 +90,6 @@ static int pps_tty_open(struct tty_struct *tty)
return 0; return 0;
err_unregister: err_unregister:
tty->disc_data = NULL;
pps_unregister_source(pps); pps_unregister_source(pps);
return ret; return ret;
} }
@ -90,11 +98,13 @@ static void (*alias_n_tty_close)(struct tty_struct *tty);
static void pps_tty_close(struct tty_struct *tty) static void pps_tty_close(struct tty_struct *tty)
{ {
struct pps_device *pps = (struct pps_device *)tty->disc_data; struct pps_device *pps = pps_lookup_dev(tty);
alias_n_tty_close(tty); alias_n_tty_close(tty);
tty->disc_data = NULL; if (WARN_ON(!pps))
return;
dev_info(pps->dev, "removed\n"); dev_info(pps->dev, "removed\n");
pps_unregister_source(pps); pps_unregister_source(pps);
} }

View File

@ -247,12 +247,15 @@ static int pps_cdev_open(struct inode *inode, struct file *file)
struct pps_device *pps = container_of(inode->i_cdev, struct pps_device *pps = container_of(inode->i_cdev,
struct pps_device, cdev); struct pps_device, cdev);
file->private_data = pps; file->private_data = pps;
kobject_get(&pps->dev->kobj);
return 0; return 0;
} }
static int pps_cdev_release(struct inode *inode, struct file *file) static int pps_cdev_release(struct inode *inode, struct file *file)
{ {
struct pps_device *pps = container_of(inode->i_cdev,
struct pps_device, cdev);
kobject_put(&pps->dev->kobj);
return 0; return 0;
} }
@ -274,8 +277,10 @@ static void pps_device_destruct(struct device *dev)
{ {
struct pps_device *pps = dev_get_drvdata(dev); struct pps_device *pps = dev_get_drvdata(dev);
/* release id here to protect others from using it while it's cdev_del(&pps->cdev);
* still in use */
/* Now we can release the ID for re-use */
pr_debug("deallocating pps%d\n", pps->id);
mutex_lock(&pps_idr_lock); mutex_lock(&pps_idr_lock);
idr_remove(&pps_idr, pps->id); idr_remove(&pps_idr, pps->id);
mutex_unlock(&pps_idr_lock); mutex_unlock(&pps_idr_lock);
@ -332,6 +337,7 @@ int pps_register_cdev(struct pps_device *pps)
goto del_cdev; goto del_cdev;
} }
/* Override the release function with our own */
pps->dev->release = pps_device_destruct; pps->dev->release = pps_device_destruct;
pr_debug("source %s got cdev (%d:%d)\n", pps->info.name, pr_debug("source %s got cdev (%d:%d)\n", pps->info.name,
@ -352,10 +358,43 @@ free_idr:
void pps_unregister_cdev(struct pps_device *pps) void pps_unregister_cdev(struct pps_device *pps)
{ {
pr_debug("unregistering pps%d\n", pps->id);
pps->lookup_cookie = NULL;
device_destroy(pps_class, pps->dev->devt); device_destroy(pps_class, pps->dev->devt);
cdev_del(&pps->cdev);
} }
/*
* Look up a pps device by magic cookie.
* The cookie is usually a pointer to some enclosing device, but this
* code doesn't care; you should never be dereferencing it.
*
* This is a bit of a kludge that is currently used only by the PPS
* serial line discipline. It may need to be tweaked when a second user
* is found.
*
* There is no function interface for setting the lookup_cookie field.
* It's initialized to NULL when the pps device is created, and if a
* client wants to use it, just fill it in afterward.
*
* The cookie is automatically set to NULL in pps_unregister_source()
* so that it will not be used again, even if the pps device cannot
* be removed from the idr due to pending references holding the minor
* number in use.
*/
struct pps_device *pps_lookup_dev(void const *cookie)
{
struct pps_device *pps;
unsigned id;
rcu_read_lock();
idr_for_each_entry(&pps_idr, pps, id)
if (cookie == pps->lookup_cookie)
break;
rcu_read_unlock();
return pps;
}
EXPORT_SYMBOL(pps_lookup_dev);
/* /*
* Module stuff * Module stuff
*/ */

View File

@ -11,7 +11,7 @@ config TN3270
config TN3270_TTY config TN3270_TTY
def_tristate y def_tristate y
prompt "Support for tty input/output on 3270 terminals" prompt "Support for tty input/output on 3270 terminals"
depends on TN3270 depends on TN3270 && TTY
help help
Include support for using an IBM 3270 terminal as a Linux tty. Include support for using an IBM 3270 terminal as a Linux tty.
@ -33,7 +33,7 @@ config TN3270_CONSOLE
config TN3215 config TN3215
def_bool y def_bool y
prompt "Support for 3215 line mode terminal" prompt "Support for 3215 line mode terminal"
depends on CCW depends on CCW && TTY
help help
Include support for IBM 3215 line-mode terminals. Include support for IBM 3215 line-mode terminals.
@ -51,7 +51,7 @@ config CCW_CONSOLE
config SCLP_TTY config SCLP_TTY
def_bool y def_bool y
prompt "Support for SCLP line mode terminal" prompt "Support for SCLP line mode terminal"
depends on S390 depends on S390 && TTY
help help
Include support for IBM SCLP line-mode terminals. Include support for IBM SCLP line-mode terminals.
@ -66,7 +66,7 @@ config SCLP_CONSOLE
config SCLP_VT220_TTY config SCLP_VT220_TTY
def_bool y def_bool y
prompt "Support for SCLP VT220-compatible terminal" prompt "Support for SCLP VT220-compatible terminal"
depends on S390 depends on S390 && TTY
help help
Include support for an IBM SCLP VT220-compatible terminal. Include support for an IBM SCLP VT220-compatible terminal.

View File

@ -412,8 +412,9 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
break; break;
case CTRLCHAR_CTRL: case CTRLCHAR_CTRL:
tty_insert_flip_char(tty, cchar, TTY_NORMAL); tty_insert_flip_char(&raw->port, cchar,
tty_flip_buffer_push(tty); TTY_NORMAL);
tty_flip_buffer_push(&raw->port);
break; break;
case CTRLCHAR_NONE: case CTRLCHAR_NONE:
@ -425,8 +426,9 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
count++; count++;
} else } else
count -= 2; count -= 2;
tty_insert_flip_string(tty, raw->inbuf, count); tty_insert_flip_string(&raw->port, raw->inbuf,
tty_flip_buffer_push(tty); count);
tty_flip_buffer_push(&raw->port);
break; break;
} }
} else if (req->type == RAW3215_WRITE) { } else if (req->type == RAW3215_WRITE) {
@ -970,7 +972,7 @@ static int tty3215_open(struct tty_struct *tty, struct file * filp)
tty_port_tty_set(&raw->port, tty); tty_port_tty_set(&raw->port, tty);
tty->low_latency = 0; /* don't use bottom half for pushing chars */ raw->port.low_latency = 0; /* don't use bottom half for pushing chars */
/* /*
* Start up 3215 device * Start up 3215 device
*/ */

View File

@ -43,22 +43,14 @@ int kbd_ioctl(struct kbd_data *, unsigned int, unsigned long);
static inline void static inline void
kbd_put_queue(struct tty_port *port, int ch) kbd_put_queue(struct tty_port *port, int ch)
{ {
struct tty_struct *tty = tty_port_tty_get(port); tty_insert_flip_char(port, ch, 0);
if (!tty) tty_schedule_flip(port);
return;
tty_insert_flip_char(tty, ch, 0);
tty_schedule_flip(tty);
tty_kref_put(tty);
} }
static inline void static inline void
kbd_puts_queue(struct tty_port *port, 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) while (*cp)
tty_insert_flip_char(tty, *cp++, 0); tty_insert_flip_char(port, *cp++, 0);
tty_schedule_flip(tty); tty_schedule_flip(port);
tty_kref_put(tty);
} }

View File

@ -65,7 +65,7 @@ sclp_tty_open(struct tty_struct *tty, struct file *filp)
{ {
tty_port_tty_set(&sclp_port, tty); tty_port_tty_set(&sclp_port, tty);
tty->driver_data = NULL; tty->driver_data = NULL;
tty->low_latency = 0; sclp_port.low_latency = 0;
return 0; return 0;
} }
@ -342,8 +342,8 @@ sclp_tty_input(unsigned char* buf, unsigned int count)
case CTRLCHAR_SYSRQ: case CTRLCHAR_SYSRQ:
break; break;
case CTRLCHAR_CTRL: case CTRLCHAR_CTRL:
tty_insert_flip_char(tty, cchar, TTY_NORMAL); tty_insert_flip_char(&sclp_port, cchar, TTY_NORMAL);
tty_flip_buffer_push(tty); tty_flip_buffer_push(&sclp_port);
break; break;
case CTRLCHAR_NONE: case CTRLCHAR_NONE:
/* send (normal) input to line discipline */ /* send (normal) input to line discipline */
@ -351,11 +351,11 @@ sclp_tty_input(unsigned char* buf, unsigned int count)
(strncmp((const char *) buf + count - 2, "^n", 2) && (strncmp((const char *) buf + count - 2, "^n", 2) &&
strncmp((const char *) buf + count - 2, "\252n", 2))) { strncmp((const char *) buf + count - 2, "\252n", 2))) {
/* add the auto \n */ /* add the auto \n */
tty_insert_flip_string(tty, buf, count); tty_insert_flip_string(&sclp_port, buf, count);
tty_insert_flip_char(tty, '\n', TTY_NORMAL); tty_insert_flip_char(&sclp_port, '\n', TTY_NORMAL);
} else } else
tty_insert_flip_string(tty, buf, count - 2); tty_insert_flip_string(&sclp_port, buf, count - 2);
tty_flip_buffer_push(tty); tty_flip_buffer_push(&sclp_port);
break; break;
} }
tty_kref_put(tty); tty_kref_put(tty);

View File

@ -461,14 +461,9 @@ sclp_vt220_write(struct tty_struct *tty, const unsigned char *buf, int count)
static void static void
sclp_vt220_receiver_fn(struct evbuf_header *evbuf) sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
{ {
struct tty_struct *tty = tty_port_tty_get(&sclp_vt220_port);
char *buffer; char *buffer;
unsigned int count; unsigned int count;
/* Ignore input if device is not open */
if (tty == NULL)
return;
buffer = (char *) ((addr_t) evbuf + sizeof(struct evbuf_header)); buffer = (char *) ((addr_t) evbuf + sizeof(struct evbuf_header));
count = evbuf->length - sizeof(struct evbuf_header); count = evbuf->length - sizeof(struct evbuf_header);
@ -480,11 +475,10 @@ sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
/* Send input to line discipline */ /* Send input to line discipline */
buffer++; buffer++;
count--; count--;
tty_insert_flip_string(tty, buffer, count); tty_insert_flip_string(&sclp_vt220_port, buffer, count);
tty_flip_buffer_push(tty); tty_flip_buffer_push(&sclp_vt220_port);
break; break;
} }
tty_kref_put(tty);
} }
/* /*
@ -495,7 +489,7 @@ sclp_vt220_open(struct tty_struct *tty, struct file *filp)
{ {
if (tty->count == 1) { if (tty->count == 1) {
tty_port_tty_set(&sclp_vt220_port, tty); tty_port_tty_set(&sclp_vt220_port, tty);
tty->low_latency = 0; sclp_vt220_port.low_latency = 0;
if (!tty->winsize.ws_row && !tty->winsize.ws_col) { if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
tty->winsize.ws_row = 24; tty->winsize.ws_row = 24;
tty->winsize.ws_col = 80; tty->winsize.ws_col = 80;

View File

@ -860,7 +860,7 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
tty->driver_data = tp; tty->driver_data = tp;
tty->winsize.ws_row = tp->view.rows - 2; tty->winsize.ws_row = tp->view.rows - 2;
tty->winsize.ws_col = tp->view.cols; tty->winsize.ws_col = tp->view.cols;
tty->low_latency = 0; tp->port.low_latency = 0;
/* why to reassign? */ /* why to reassign? */
tty_port_tty_set(&tp->port, tty); tty_port_tty_set(&tp->port, tty);
tp->inattr = TF_INPUT; tp->inattr = TF_INPUT;
@ -893,7 +893,7 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
} }
tty_port_tty_set(&tp->port, tty); tty_port_tty_set(&tp->port, tty);
tty->low_latency = 0; tp->port.low_latency = 0;
tty->winsize.ws_row = tp->view.rows - 2; tty->winsize.ws_row = tp->view.rows - 2;
tty->winsize.ws_col = tp->view.cols; tty->winsize.ws_col = tp->view.cols;

View File

@ -2,7 +2,7 @@ if USB_GADGET
config USB_G_CCG config USB_G_CCG
tristate "Configurable Composite Gadget (STAGING)" tristate "Configurable Composite Gadget (STAGING)"
depends on STAGING && BLOCK && NET && !USB_ZERO && !USB_ZERO_HNPTEST && !USB_AUDIO && !GADGET_UAC1 && !USB_ETH && !USB_ETH_RNDIS && !USB_ETH_EEM && !USB_G_NCM && !USB_GADGETFS && !USB_FUNCTIONFS && !USB_FUNCTIONFS_ETH && !USB_FUNCTIONFS_RNDIS && !USB_FUNCTIONFS_GENERIC && !USB_FILE_STORAGE && !USB_FILE_STORAGE_TEST && !USB_MASS_STORAGE && !USB_G_SERIAL && !USB_MIDI_GADGET && !USB_G_PRINTER && !USB_CDC_COMPOSITE && !USB_G_NOKIA && !USB_G_ACM_MS && !USB_G_MULTI && !USB_G_MULTI_RNDIS && !USB_G_MULTI_CDC && !USB_G_HID && !USB_G_DBGP && !USB_G_WEBCAM depends on STAGING && BLOCK && NET && !USB_ZERO && !USB_ZERO_HNPTEST && !USB_AUDIO && !GADGET_UAC1 && !USB_ETH && !USB_ETH_RNDIS && !USB_ETH_EEM && !USB_G_NCM && !USB_GADGETFS && !USB_FUNCTIONFS && !USB_FUNCTIONFS_ETH && !USB_FUNCTIONFS_RNDIS && !USB_FUNCTIONFS_GENERIC && !USB_FILE_STORAGE && !USB_FILE_STORAGE_TEST && !USB_MASS_STORAGE && !USB_G_SERIAL && !USB_MIDI_GADGET && !USB_G_PRINTER && !USB_CDC_COMPOSITE && !USB_G_NOKIA && !USB_G_ACM_MS && !USB_G_MULTI && !USB_G_MULTI_RNDIS && !USB_G_MULTI_CDC && !USB_G_HID && !USB_G_DBGP && !USB_G_WEBCAM && TTY
help help
The Configurable Composite Gadget supports multiple USB The Configurable Composite Gadget supports multiple USB
functions: acm, mass storage, rndis and FunctionFS. functions: acm, mass storage, rndis and FunctionFS.

View File

@ -491,12 +491,8 @@ static void gs_rx_push(unsigned long _port)
req = list_first_entry(queue, struct usb_request, list); req = list_first_entry(queue, struct usb_request, list);
/* discard data if tty was closed */
if (!tty)
goto recycle;
/* leave data queued if tty was rx throttled */ /* leave data queued if tty was rx throttled */
if (test_bit(TTY_THROTTLED, &tty->flags)) if (tty && test_bit(TTY_THROTTLED, &tty->flags))
break; break;
switch (req->status) { switch (req->status) {
@ -529,7 +525,7 @@ static void gs_rx_push(unsigned long _port)
size -= n; size -= n;
} }
count = tty_insert_flip_string(tty, packet, size); count = tty_insert_flip_string(&port->port, packet, size);
if (count) if (count)
do_push = true; do_push = true;
if (count != size) { if (count != size) {
@ -542,7 +538,6 @@ static void gs_rx_push(unsigned long _port)
} }
port->n_read = 0; port->n_read = 0;
} }
recycle:
list_move(&req->list, &port->read_pool); list_move(&req->list, &port->read_pool);
port->read_started--; port->read_started--;
} }
@ -550,8 +545,8 @@ recycle:
/* Push from tty to ldisc; without low_latency set this is handled by /* Push from tty to ldisc; without low_latency set this is handled by
* a workqueue, so we won't get callbacks and can hold port_lock * a workqueue, so we won't get callbacks and can hold port_lock
*/ */
if (tty && do_push) if (do_push)
tty_flip_buffer_push(tty); tty_flip_buffer_push(&port->port);
/* We want our data queue to become empty ASAP, keeping data /* We want our data queue to become empty ASAP, keeping data

View File

@ -1,7 +1,7 @@
config DGRP config DGRP
tristate "Digi Realport driver" tristate "Digi Realport driver"
default n default n
depends on SYSFS depends on SYSFS && TTY
---help--- ---help---
Support for Digi Realport devices. These devices allow you to Support for Digi Realport devices. These devices allow you to
access remote serial ports as if they are local tty devices. This access remote serial ports as if they are local tty devices. This

View File

@ -37,6 +37,7 @@
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/device.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/tty_flip.h> #include <linux/tty_flip.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
@ -211,7 +212,7 @@ static void dgrp_input(struct ch_struct *ch)
data_len = (ch->ch_rin - ch->ch_rout) & RBUF_MASK; data_len = (ch->ch_rin - ch->ch_rout) & RBUF_MASK;
/* len is the amount of data we are going to transfer here */ /* len is the amount of data we are going to transfer here */
len = tty_buffer_request_room(tty, data_len); len = tty_buffer_request_room(&ch->port, data_len);
/* Check DPA flow control */ /* Check DPA flow control */
if ((nd->nd_dpa_debug) && if ((nd->nd_dpa_debug) &&
@ -232,9 +233,9 @@ static void dgrp_input(struct ch_struct *ch)
(nd->nd_dpa_port == PORT_NUM(MINOR(tty_devnum(tty))))) (nd->nd_dpa_port == PORT_NUM(MINOR(tty_devnum(tty)))))
dgrp_dpa_data(nd, 1, myflipbuf, len); dgrp_dpa_data(nd, 1, myflipbuf, len);
tty_insert_flip_string_flags(tty, myflipbuf, tty_insert_flip_string_flags(&ch->port, myflipbuf,
myflipflagbuf, len); myflipflagbuf, len);
tty_flip_buffer_push(tty); tty_flip_buffer_push(&ch->port);
ch->ch_rxcount += len; ch->ch_rxcount += len;
} }
@ -2956,9 +2957,9 @@ check_query:
I_BRKINT(ch->ch_tun.un_tty) && I_BRKINT(ch->ch_tun.un_tty) &&
!(I_IGNBRK(ch->ch_tun.un_tty))) { !(I_IGNBRK(ch->ch_tun.un_tty))) {
tty_buffer_request_room(ch->ch_tun.un_tty, 1); tty_buffer_request_room(&ch->port, 1);
tty_insert_flip_char(ch->ch_tun.un_tty, 0, TTY_BREAK); tty_insert_flip_char(&ch->port, 0, TTY_BREAK);
tty_flip_buffer_push(ch->ch_tun.un_tty); tty_flip_buffer_push(&ch->port);
} }

View File

@ -39,6 +39,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/tty_flip.h> #include <linux/tty_flip.h>
#include <linux/device.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>

View File

@ -1,6 +1,6 @@
config FIREWIRE_SERIAL config FIREWIRE_SERIAL
tristate "TTY over Firewire" tristate "TTY over Firewire"
depends on FIREWIRE depends on FIREWIRE && TTY
help help
This enables TTY over IEEE 1394, providing high-speed serial This enables TTY over IEEE 1394, providing high-speed serial
connectivity to cabled peers. This driver implements a connectivity to cabled peers. This driver implements a

View File

@ -500,16 +500,11 @@ static void fwtty_do_hangup(struct work_struct *work)
static void fwtty_emit_breaks(struct work_struct *work) static void fwtty_emit_breaks(struct work_struct *work)
{ {
struct fwtty_port *port = to_port(to_delayed_work(work), emit_breaks); struct fwtty_port *port = to_port(to_delayed_work(work), emit_breaks);
struct tty_struct *tty;
static const char buf[16]; static const char buf[16];
unsigned long now = jiffies; unsigned long now = jiffies;
unsigned long elapsed = now - port->break_last; unsigned long elapsed = now - port->break_last;
int n, t, c, brk = 0; int n, t, c, brk = 0;
tty = tty_port_tty_get(&port->port);
if (!tty)
return;
/* generate breaks at the line rate (but at least 1) */ /* generate breaks at the line rate (but at least 1) */
n = (elapsed * port->cps) / HZ + 1; n = (elapsed * port->cps) / HZ + 1;
port->break_last = now; port->break_last = now;
@ -518,15 +513,14 @@ static void fwtty_emit_breaks(struct work_struct *work)
while (n) { while (n) {
t = min(n, 16); t = min(n, 16);
c = tty_insert_flip_string_fixed_flag(tty, buf, TTY_BREAK, t); c = tty_insert_flip_string_fixed_flag(&port->port, buf,
TTY_BREAK, t);
n -= c; n -= c;
brk += c; brk += c;
if (c < t) if (c < t)
break; break;
} }
tty_flip_buffer_push(tty); tty_flip_buffer_push(&port->port);
tty_kref_put(tty);
if (port->mstatus & (UART_LSR_BI << 24)) if (port->mstatus & (UART_LSR_BI << 24))
schedule_delayed_work(&port->emit_breaks, FREQ_BREAKS); schedule_delayed_work(&port->emit_breaks, FREQ_BREAKS);
@ -540,13 +534,9 @@ static void fwtty_pushrx(struct work_struct *work)
struct buffered_rx *buf, *next; struct buffered_rx *buf, *next;
int n, c = 0; int n, c = 0;
tty = tty_port_tty_get(&port->port);
if (!tty)
return;
spin_lock_bh(&port->lock); spin_lock_bh(&port->lock);
list_for_each_entry_safe(buf, next, &port->buf_list, list) { list_for_each_entry_safe(buf, next, &port->buf_list, list) {
n = tty_insert_flip_string_fixed_flag(tty, buf->data, n = tty_insert_flip_string_fixed_flag(&port->port, buf->data,
TTY_NORMAL, buf->n); TTY_NORMAL, buf->n);
c += n; c += n;
port->buffered -= n; port->buffered -= n;
@ -555,7 +545,11 @@ static void fwtty_pushrx(struct work_struct *work)
memmove(buf->data, buf->data + n, buf->n - n); memmove(buf->data, buf->data + n, buf->n - n);
buf->n -= n; buf->n -= n;
} }
__fwtty_throttle(port, tty); tty = tty_port_tty_get(&port->port);
if (tty) {
__fwtty_throttle(port, tty);
tty_kref_put(tty);
}
break; break;
} else { } else {
list_del(&buf->list); list_del(&buf->list);
@ -563,13 +557,11 @@ static void fwtty_pushrx(struct work_struct *work)
} }
} }
if (c > 0) if (c > 0)
tty_flip_buffer_push(tty); tty_flip_buffer_push(&port->port);
if (list_empty(&port->buf_list)) if (list_empty(&port->buf_list))
clear_bit(BUFFERING_RX, &port->flags); clear_bit(BUFFERING_RX, &port->flags);
spin_unlock_bh(&port->lock); spin_unlock_bh(&port->lock);
tty_kref_put(tty);
} }
static int fwtty_buffer_rx(struct fwtty_port *port, unsigned char *d, size_t n) static int fwtty_buffer_rx(struct fwtty_port *port, unsigned char *d, size_t n)
@ -607,10 +599,6 @@ static int fwtty_rx(struct fwtty_port *port, unsigned char *data, size_t len)
unsigned lsr; unsigned lsr;
int err = 0; int err = 0;
tty = tty_port_tty_get(&port->port);
if (!tty)
return -ENOENT;
fwtty_dbg(port, "%d", n); fwtty_dbg(port, "%d", n);
profile_size_distrib(port->stats.reads, n); profile_size_distrib(port->stats.reads, n);
@ -630,7 +618,7 @@ static int fwtty_rx(struct fwtty_port *port, unsigned char *data, size_t len)
lsr &= port->status_mask; lsr &= port->status_mask;
if (lsr & ~port->ignore_mask & UART_LSR_OE) { if (lsr & ~port->ignore_mask & UART_LSR_OE) {
if (!tty_insert_flip_char(tty, 0, TTY_OVERRUN)) { if (!tty_insert_flip_char(&port->port, 0, TTY_OVERRUN)) {
err = -EIO; err = -EIO;
goto out; goto out;
} }
@ -644,18 +632,23 @@ static int fwtty_rx(struct fwtty_port *port, unsigned char *data, size_t len)
} }
if (!test_bit(BUFFERING_RX, &port->flags)) { if (!test_bit(BUFFERING_RX, &port->flags)) {
c = tty_insert_flip_string_fixed_flag(tty, data, TTY_NORMAL, n); c = tty_insert_flip_string_fixed_flag(&port->port, data,
TTY_NORMAL, n);
if (c > 0) if (c > 0)
tty_flip_buffer_push(tty); tty_flip_buffer_push(&port->port);
n -= c; n -= c;
if (n) { if (n) {
/* start buffering and throttling */ /* start buffering and throttling */
n -= fwtty_buffer_rx(port, &data[c], n); n -= fwtty_buffer_rx(port, &data[c], n);
spin_lock_bh(&port->lock); tty = tty_port_tty_get(&port->port);
__fwtty_throttle(port, tty); if (tty) {
spin_unlock_bh(&port->lock); spin_lock_bh(&port->lock);
__fwtty_throttle(port, tty);
spin_unlock_bh(&port->lock);
tty_kref_put(tty);
}
} }
} else } else
n -= fwtty_buffer_rx(port, data, n); n -= fwtty_buffer_rx(port, data, n);
@ -666,8 +659,6 @@ static int fwtty_rx(struct fwtty_port *port, unsigned char *data, size_t len)
} }
out: out:
tty_kref_put(tty);
port->icount.rx += len; port->icount.rx += len;
port->stats.lost += n; port->stats.lost += n;
return err; return err;

View File

@ -1,8 +1,7 @@
config SB105X config SB105X
tristate "SystemBase PCI Multiport UART" tristate "SystemBase PCI Multiport UART"
select SERIAL_CORE select SERIAL_CORE
depends on PCI depends on PCI && X86 && TTY && BROKEN
depends on X86
help help
A driver for the SystemBase Multi-2/PCI serial card A driver for the SystemBase Multi-2/PCI serial card

View File

@ -255,12 +255,11 @@ static void ProcessModemStatus(struct quatech_port *qt_port,
wake_up_interruptible(&qt_port->wait); wake_up_interruptible(&qt_port->wait);
} }
static void ProcessRxChar(struct tty_struct *tty, struct usb_serial_port *port, static void ProcessRxChar(struct usb_serial_port *port, unsigned char data)
unsigned char data)
{ {
struct urb *urb = port->read_urb; struct urb *urb = port->read_urb;
if (urb->actual_length) if (urb->actual_length)
tty_insert_flip_char(tty, data, TTY_NORMAL); tty_insert_flip_char(&port->port, data, TTY_NORMAL);
} }
static void qt_write_bulk_callback(struct urb *urb) static void qt_write_bulk_callback(struct urb *urb)
@ -291,8 +290,7 @@ static void qt_interrupt_callback(struct urb *urb)
/* FIXME */ /* FIXME */
} }
static void qt_status_change_check(struct tty_struct *tty, static void qt_status_change_check(struct urb *urb,
struct urb *urb,
struct quatech_port *qt_port, struct quatech_port *qt_port,
struct usb_serial_port *port) struct usb_serial_port *port)
{ {
@ -335,8 +333,8 @@ static void qt_status_change_check(struct tty_struct *tty,
case 0xff: case 0xff:
dev_dbg(&port->dev, "No status sequence.\n"); dev_dbg(&port->dev, "No status sequence.\n");
ProcessRxChar(tty, port, data[i]); ProcessRxChar(port, data[i]);
ProcessRxChar(tty, port, data[i + 1]); ProcessRxChar(port, data[i + 1]);
i += 2; i += 2;
break; break;
@ -345,11 +343,11 @@ static void qt_status_change_check(struct tty_struct *tty,
continue; continue;
} }
if (tty && urb->actual_length) if (urb->actual_length)
tty_insert_flip_char(tty, data[i], TTY_NORMAL); tty_insert_flip_char(&port->port, data[i], TTY_NORMAL);
} }
tty_flip_buffer_push(tty); tty_flip_buffer_push(&port->port);
} }
static void qt_read_bulk_callback(struct urb *urb) static void qt_read_bulk_callback(struct urb *urb)
@ -358,7 +356,6 @@ static void qt_read_bulk_callback(struct urb *urb)
struct usb_serial_port *port = urb->context; struct usb_serial_port *port = urb->context;
struct usb_serial *serial = get_usb_serial(port, __func__); struct usb_serial *serial = get_usb_serial(port, __func__);
struct quatech_port *qt_port = qt_get_port_private(port); struct quatech_port *qt_port = qt_get_port_private(port);
struct tty_struct *tty;
int result; int result;
if (urb->status) { if (urb->status) {
@ -369,27 +366,23 @@ static void qt_read_bulk_callback(struct urb *urb)
return; return;
} }
tty = tty_port_tty_get(&port->port);
if (!tty)
return;
dev_dbg(&port->dev, dev_dbg(&port->dev,
"%s - port->RxHolding = %d\n", __func__, qt_port->RxHolding); "%s - port->RxHolding = %d\n", __func__, qt_port->RxHolding);
if (port_paranoia_check(port, __func__) != 0) { if (port_paranoia_check(port, __func__) != 0) {
qt_port->ReadBulkStopped = 1; qt_port->ReadBulkStopped = 1;
goto exit; return;
} }
if (!serial) if (!serial)
goto exit; return;
if (qt_port->closePending == 1) { if (qt_port->closePending == 1) {
/* Were closing , stop reading */ /* Were closing , stop reading */
dev_dbg(&port->dev, dev_dbg(&port->dev,
"%s - (qt_port->closepending == 1\n", __func__); "%s - (qt_port->closepending == 1\n", __func__);
qt_port->ReadBulkStopped = 1; qt_port->ReadBulkStopped = 1;
goto exit; return;
} }
/* /*
@ -399,7 +392,7 @@ static void qt_read_bulk_callback(struct urb *urb)
*/ */
if (qt_port->RxHolding == 1) { if (qt_port->RxHolding == 1) {
qt_port->ReadBulkStopped = 1; qt_port->ReadBulkStopped = 1;
goto exit; return;
} }
if (urb->status) { if (urb->status) {
@ -408,11 +401,11 @@ static void qt_read_bulk_callback(struct urb *urb)
dev_dbg(&port->dev, dev_dbg(&port->dev,
"%s - nonzero read bulk status received: %d\n", "%s - nonzero read bulk status received: %d\n",
__func__, urb->status); __func__, urb->status);
goto exit; return;
} }
if (urb->actual_length) if (urb->actual_length)
qt_status_change_check(tty, urb, qt_port, port); qt_status_change_check(urb, qt_port, port);
/* Continue trying to always read */ /* Continue trying to always read */
usb_fill_bulk_urb(port->read_urb, serial->dev, usb_fill_bulk_urb(port->read_urb, serial->dev,
@ -428,14 +421,12 @@ static void qt_read_bulk_callback(struct urb *urb)
__func__, result); __func__, result);
else { else {
if (urb->actual_length) { if (urb->actual_length) {
tty_flip_buffer_push(tty); tty_flip_buffer_push(&port->port);
tty_schedule_flip(tty); tty_schedule_flip(&port->port);
} }
} }
schedule_work(&port->work); schedule_work(&port->work);
exit:
tty_kref_put(tty);
} }
/* /*

View File

@ -2,6 +2,7 @@
#include <linux/consolemap.h> #include <linux/consolemap.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/device.h> /* for dev_warn */
#include <linux/selection.h> #include <linux/selection.h>
#include "speakup.h" #include "speakup.h"

View File

@ -1,3 +1,14 @@
config TTY
bool "Enable TTY" if EXPERT
default y
---help---
Allows you to remove TTY support which can save space, and
blocks features that require TTY from inclusion in the kernel.
TTY is required for any text terminals or serial port
communication. Most users should leave this enabled.
if TTY
config VT config VT
bool "Virtual terminal" if EXPERT bool "Virtual terminal" if EXPERT
depends on !S390 && !UML depends on !S390 && !UML
@ -388,3 +399,24 @@ config PPC_EARLY_DEBUG_EHV_BC_HANDLE
If the number you specify is not a valid byte channel handle, then If the number you specify is not a valid byte channel handle, then
there simply will be no early console output. This is true also there simply will be no early console output. This is true also
if you don't boot under a hypervisor at all. if you don't boot under a hypervisor at all.
config GOLDFISH_TTY
tristate "Goldfish TTY Driver"
depends on GOLDFISH
help
Console and system TTY driver for the Goldfish virtual platform.
config DA_TTY
bool "DA TTY"
depends on METAG_DA
select SERIAL_NONSTANDARD
help
This enables a TTY on a Dash channel.
config DA_CONSOLE
bool "DA Console"
depends on DA_TTY
help
This enables a console on a Dash channel.
endif # TTY

View File

@ -1,4 +1,4 @@
obj-y += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \ obj-$(CONFIG_TTY) += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
tty_buffer.o tty_port.o tty_mutex.o tty_buffer.o tty_port.o tty_mutex.o
obj-$(CONFIG_LEGACY_PTYS) += pty.o obj-$(CONFIG_LEGACY_PTYS) += pty.o
obj-$(CONFIG_UNIX98_PTYS) += pty.o obj-$(CONFIG_UNIX98_PTYS) += pty.o
@ -27,5 +27,7 @@ obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o
obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o
obj-$(CONFIG_SYNCLINK) += synclink.o obj-$(CONFIG_SYNCLINK) += synclink.o
obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o
obj-$(CONFIG_GOLDFISH_TTY) += goldfish.o
obj-$(CONFIG_DA_TTY) += metag_da.o
obj-y += ipwireless/ obj-y += ipwireless/

View File

@ -251,7 +251,6 @@ static void receive_chars(struct serial_state *info)
{ {
int status; int status;
int serdatr; int serdatr;
struct tty_struct *tty = info->tport.tty;
unsigned char ch, flag; unsigned char ch, flag;
struct async_icount *icount; struct async_icount *icount;
int oe = 0; int oe = 0;
@ -314,7 +313,7 @@ static void receive_chars(struct serial_state *info)
#endif #endif
flag = TTY_BREAK; flag = TTY_BREAK;
if (info->tport.flags & ASYNC_SAK) if (info->tport.flags & ASYNC_SAK)
do_SAK(tty); do_SAK(info->tport.tty);
} else if (status & UART_LSR_PE) } else if (status & UART_LSR_PE)
flag = TTY_PARITY; flag = TTY_PARITY;
else if (status & UART_LSR_FE) else if (status & UART_LSR_FE)
@ -328,10 +327,10 @@ static void receive_chars(struct serial_state *info)
oe = 1; oe = 1;
} }
} }
tty_insert_flip_char(tty, ch, flag); tty_insert_flip_char(&info->tport, ch, flag);
if (oe == 1) if (oe == 1)
tty_insert_flip_char(tty, 0, TTY_OVERRUN); tty_insert_flip_char(&info->tport, 0, TTY_OVERRUN);
tty_flip_buffer_push(tty); tty_flip_buffer_push(&info->tport);
out: out:
return; return;
} }
@ -394,11 +393,6 @@ static void check_modem_status(struct serial_state *info)
icount->dsr++; icount->dsr++;
if (dstatus & SER_DCD) { if (dstatus & SER_DCD) {
icount->dcd++; icount->dcd++;
#ifdef CONFIG_HARD_PPS
if ((port->flags & ASYNC_HARDPPS_CD) &&
!(status & SER_DCD))
hardpps();
#endif
} }
if (dstatus & SER_CTS) if (dstatus & SER_CTS)
icount->cts++; icount->cts++;
@ -1099,7 +1093,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
state->custom_divisor = new_serial.custom_divisor; state->custom_divisor = new_serial.custom_divisor;
port->close_delay = new_serial.close_delay * HZ/100; port->close_delay = new_serial.close_delay * HZ/100;
port->closing_wait = new_serial.closing_wait * HZ/100; port->closing_wait = new_serial.closing_wait * HZ/100;
tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
check_and_exit: check_and_exit:
if (port->flags & ASYNC_INITIALIZED) { if (port->flags & ASYNC_INITIALIZED) {
@ -1528,7 +1522,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
if (serial_paranoia_check(info, tty->name, "rs_open")) if (serial_paranoia_check(info, tty->name, "rs_open"))
return -ENODEV; return -ENODEV;
tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
retval = startup(tty, info); retval = startup(tty, info);
if (retval) { if (retval) {

View File

@ -95,18 +95,16 @@ bfin_jc_emudat_manager(void *arg)
/* if incoming data is ready, eat it */ /* if incoming data is ready, eat it */
if (bfin_read_DBGSTAT() & EMUDIF) { if (bfin_read_DBGSTAT() & EMUDIF) {
if (tty != NULL) { uint32_t emudat = bfin_read_emudat();
uint32_t emudat = bfin_read_emudat(); if (inbound_len == 0) {
if (inbound_len == 0) { pr_debug("incoming length: 0x%08x\n", emudat);
pr_debug("incoming length: 0x%08x\n", emudat); inbound_len = emudat;
inbound_len = emudat; } else {
} else { size_t num_chars = (4 <= inbound_len ? 4 : inbound_len);
size_t num_chars = (4 <= inbound_len ? 4 : inbound_len); pr_debug(" incoming data: 0x%08x (pushing %zu)\n", emudat, num_chars);
pr_debug(" incoming data: 0x%08x (pushing %zu)\n", emudat, num_chars); inbound_len -= num_chars;
inbound_len -= num_chars; tty_insert_flip_string(&port, (unsigned char *)&emudat, num_chars);
tty_insert_flip_string(tty, (unsigned char *)&emudat, num_chars); tty_flip_buffer_push(&port);
tty_flip_buffer_push(tty);
}
} }
} }

View File

@ -441,7 +441,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
void __iomem *base_addr) void __iomem *base_addr)
{ {
struct cyclades_port *info; struct cyclades_port *info;
struct tty_struct *tty; struct tty_port *port;
int len, index = cinfo->bus_index; int len, index = cinfo->bus_index;
u8 ivr, save_xir, channel, save_car, data, char_count; u8 ivr, save_xir, channel, save_car, data, char_count;
@ -452,22 +452,11 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
save_xir = readb(base_addr + (CyRIR << index)); save_xir = readb(base_addr + (CyRIR << index));
channel = save_xir & CyIRChannel; channel = save_xir & CyIRChannel;
info = &cinfo->ports[channel + chip * 4]; info = &cinfo->ports[channel + chip * 4];
port = &info->port;
save_car = cyy_readb(info, CyCAR); save_car = cyy_readb(info, CyCAR);
cyy_writeb(info, CyCAR, save_xir); cyy_writeb(info, CyCAR, save_xir);
ivr = cyy_readb(info, CyRIVR) & CyIVRMask; ivr = cyy_readb(info, CyRIVR) & CyIVRMask;
tty = tty_port_tty_get(&info->port);
/* if there is nowhere to put the data, discard it */
if (tty == NULL) {
if (ivr == CyIVRRxEx) { /* exception */
data = cyy_readb(info, CyRDSR);
} else { /* normal character reception */
char_count = cyy_readb(info, CyRDCR);
while (char_count--)
data = cyy_readb(info, CyRDSR);
}
goto end;
}
/* there is an open port for this data */ /* there is an open port for this data */
if (ivr == CyIVRRxEx) { /* exception */ if (ivr == CyIVRRxEx) { /* exception */
data = cyy_readb(info, CyRDSR); data = cyy_readb(info, CyRDSR);
@ -484,40 +473,45 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
if (data & info->ignore_status_mask) { if (data & info->ignore_status_mask) {
info->icount.rx++; info->icount.rx++;
tty_kref_put(tty);
return; return;
} }
if (tty_buffer_request_room(tty, 1)) { if (tty_buffer_request_room(port, 1)) {
if (data & info->read_status_mask) { if (data & info->read_status_mask) {
if (data & CyBREAK) { if (data & CyBREAK) {
tty_insert_flip_char(tty, tty_insert_flip_char(port,
cyy_readb(info, CyRDSR), cyy_readb(info, CyRDSR),
TTY_BREAK); TTY_BREAK);
info->icount.rx++; info->icount.rx++;
if (info->port.flags & ASYNC_SAK) if (port->flags & ASYNC_SAK) {
do_SAK(tty); struct tty_struct *tty =
tty_port_tty_get(port);
if (tty) {
do_SAK(tty);
tty_kref_put(tty);
}
}
} else if (data & CyFRAME) { } else if (data & CyFRAME) {
tty_insert_flip_char(tty, tty_insert_flip_char(port,
cyy_readb(info, CyRDSR), cyy_readb(info, CyRDSR),
TTY_FRAME); TTY_FRAME);
info->icount.rx++; info->icount.rx++;
info->idle_stats.frame_errs++; info->idle_stats.frame_errs++;
} else if (data & CyPARITY) { } else if (data & CyPARITY) {
/* Pieces of seven... */ /* Pieces of seven... */
tty_insert_flip_char(tty, tty_insert_flip_char(port,
cyy_readb(info, CyRDSR), cyy_readb(info, CyRDSR),
TTY_PARITY); TTY_PARITY);
info->icount.rx++; info->icount.rx++;
info->idle_stats.parity_errs++; info->idle_stats.parity_errs++;
} else if (data & CyOVERRUN) { } else if (data & CyOVERRUN) {
tty_insert_flip_char(tty, 0, tty_insert_flip_char(port, 0,
TTY_OVERRUN); TTY_OVERRUN);
info->icount.rx++; info->icount.rx++;
/* If the flip buffer itself is /* If the flip buffer itself is
overflowing, we still lose overflowing, we still lose
the next incoming character. the next incoming character.
*/ */
tty_insert_flip_char(tty, tty_insert_flip_char(port,
cyy_readb(info, CyRDSR), cyy_readb(info, CyRDSR),
TTY_FRAME); TTY_FRAME);
info->icount.rx++; info->icount.rx++;
@ -527,12 +521,12 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
/* } else if(data & CyTIMEOUT) { */ /* } else if(data & CyTIMEOUT) { */
/* } else if(data & CySPECHAR) { */ /* } else if(data & CySPECHAR) { */
} else { } else {
tty_insert_flip_char(tty, 0, tty_insert_flip_char(port, 0,
TTY_NORMAL); TTY_NORMAL);
info->icount.rx++; info->icount.rx++;
} }
} else { } else {
tty_insert_flip_char(tty, 0, TTY_NORMAL); tty_insert_flip_char(port, 0, TTY_NORMAL);
info->icount.rx++; info->icount.rx++;
} }
} else { } else {
@ -552,10 +546,10 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
info->mon.char_max = char_count; info->mon.char_max = char_count;
info->mon.char_last = char_count; info->mon.char_last = char_count;
#endif #endif
len = tty_buffer_request_room(tty, char_count); len = tty_buffer_request_room(port, char_count);
while (len--) { while (len--) {
data = cyy_readb(info, CyRDSR); data = cyy_readb(info, CyRDSR);
tty_insert_flip_char(tty, data, TTY_NORMAL); tty_insert_flip_char(port, data, TTY_NORMAL);
info->idle_stats.recv_bytes++; info->idle_stats.recv_bytes++;
info->icount.rx++; info->icount.rx++;
#ifdef CY_16Y_HACK #ifdef CY_16Y_HACK
@ -564,9 +558,8 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
} }
info->idle_stats.recv_idle = jiffies; info->idle_stats.recv_idle = jiffies;
} }
tty_schedule_flip(tty); tty_schedule_flip(port);
tty_kref_put(tty);
end:
/* end of service */ /* end of service */
cyy_writeb(info, CyRIR, save_xir & 0x3f); cyy_writeb(info, CyRIR, save_xir & 0x3f);
cyy_writeb(info, CyCAR, save_car); cyy_writeb(info, CyCAR, save_car);
@ -924,10 +917,11 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
return 0; return 0;
} /* cyz_issue_cmd */ } /* cyz_issue_cmd */
static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty) static void cyz_handle_rx(struct cyclades_port *info)
{ {
struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
struct cyclades_card *cinfo = info->card; struct cyclades_card *cinfo = info->card;
struct tty_port *port = &info->port;
unsigned int char_count; unsigned int char_count;
int len; int len;
#ifdef BLOCKMOVE #ifdef BLOCKMOVE
@ -946,80 +940,77 @@ static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty)
else else
char_count = rx_put - rx_get + rx_bufsize; char_count = rx_put - rx_get + rx_bufsize;
if (char_count) { if (!char_count)
return;
#ifdef CY_ENABLE_MONITORING #ifdef CY_ENABLE_MONITORING
info->mon.int_count++; info->mon.int_count++;
info->mon.char_count += char_count; info->mon.char_count += char_count;
if (char_count > info->mon.char_max) if (char_count > info->mon.char_max)
info->mon.char_max = char_count; info->mon.char_max = char_count;
info->mon.char_last = char_count; info->mon.char_last = char_count;
#endif #endif
if (tty == NULL) {
/* flush received characters */
new_rx_get = (new_rx_get + char_count) &
(rx_bufsize - 1);
info->rflush_count++;
} else {
#ifdef BLOCKMOVE #ifdef BLOCKMOVE
/* we'd like to use memcpy(t, f, n) and memset(s, c, count) /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
for performance, but because of buffer boundaries, there for performance, but because of buffer boundaries, there
may be several steps to the operation */ may be several steps to the operation */
while (1) { while (1) {
len = tty_prepare_flip_string(tty, &buf, len = tty_prepare_flip_string(port, &buf,
char_count); char_count);
if (!len) if (!len)
break; break;
len = min_t(unsigned int, min(len, char_count), len = min_t(unsigned int, min(len, char_count),
rx_bufsize - new_rx_get); rx_bufsize - new_rx_get);
memcpy_fromio(buf, cinfo->base_addr + memcpy_fromio(buf, cinfo->base_addr +
rx_bufaddr + new_rx_get, len); rx_bufaddr + new_rx_get, len);
new_rx_get = (new_rx_get + len) & new_rx_get = (new_rx_get + len) &
(rx_bufsize - 1); (rx_bufsize - 1);
char_count -= len; char_count -= len;
info->icount.rx += len; info->icount.rx += len;
info->idle_stats.recv_bytes += len; info->idle_stats.recv_bytes += len;
} }
#else #else
len = tty_buffer_request_room(tty, char_count); len = tty_buffer_request_room(port, char_count);
while (len--) { while (len--) {
data = readb(cinfo->base_addr + rx_bufaddr + data = readb(cinfo->base_addr + rx_bufaddr +
new_rx_get); new_rx_get);
new_rx_get = (new_rx_get + 1) & new_rx_get = (new_rx_get + 1) &
(rx_bufsize - 1); (rx_bufsize - 1);
tty_insert_flip_char(tty, data, TTY_NORMAL); tty_insert_flip_char(port, data, TTY_NORMAL);
info->idle_stats.recv_bytes++; info->idle_stats.recv_bytes++;
info->icount.rx++; info->icount.rx++;
} }
#endif #endif
#ifdef CONFIG_CYZ_INTR #ifdef CONFIG_CYZ_INTR
/* Recalculate the number of chars in the RX buffer and issue /* Recalculate the number of chars in the RX buffer and issue
a cmd in case it's higher than the RX high water mark */ a cmd in case it's higher than the RX high water mark */
rx_put = readl(&buf_ctrl->rx_put); rx_put = readl(&buf_ctrl->rx_put);
if (rx_put >= rx_get) if (rx_put >= rx_get)
char_count = rx_put - rx_get; char_count = rx_put - rx_get;
else else
char_count = rx_put - rx_get + rx_bufsize; char_count = rx_put - rx_get + rx_bufsize;
if (char_count >= readl(&buf_ctrl->rx_threshold) && if (char_count >= readl(&buf_ctrl->rx_threshold) &&
!timer_pending(&cyz_rx_full_timer[ !timer_pending(&cyz_rx_full_timer[
info->line])) info->line]))
mod_timer(&cyz_rx_full_timer[info->line], mod_timer(&cyz_rx_full_timer[info->line],
jiffies + 1); jiffies + 1);
#endif #endif
info->idle_stats.recv_idle = jiffies; info->idle_stats.recv_idle = jiffies;
tty_schedule_flip(tty); tty_schedule_flip(&info->port);
}
/* Update rx_get */ /* Update rx_get */
cy_writel(&buf_ctrl->rx_get, new_rx_get); cy_writel(&buf_ctrl->rx_get, new_rx_get);
}
} }
static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty) static void cyz_handle_tx(struct cyclades_port *info)
{ {
struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl; struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
struct cyclades_card *cinfo = info->card; struct cyclades_card *cinfo = info->card;
struct tty_struct *tty;
u8 data; u8 data;
unsigned int char_count; unsigned int char_count;
#ifdef BLOCKMOVE #ifdef BLOCKMOVE
@ -1039,63 +1030,63 @@ static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty)
else else
char_count = tx_get - tx_put - 1; char_count = tx_get - tx_put - 1;
if (char_count) { if (!char_count)
return;
tty = tty_port_tty_get(&info->port);
if (tty == NULL)
goto ztxdone;
if (tty == NULL) if (info->x_char) { /* send special char */
goto ztxdone; data = info->x_char;
if (info->x_char) { /* send special char */ cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
data = info->x_char; tx_put = (tx_put + 1) & (tx_bufsize - 1);
info->x_char = 0;
cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data); char_count--;
tx_put = (tx_put + 1) & (tx_bufsize - 1); info->icount.tx++;
info->x_char = 0;
char_count--;
info->icount.tx++;
}
#ifdef BLOCKMOVE
while (0 < (small_count = min_t(unsigned int,
tx_bufsize - tx_put, min_t(unsigned int,
(SERIAL_XMIT_SIZE - info->xmit_tail),
min_t(unsigned int, info->xmit_cnt,
char_count))))) {
memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr +
tx_put),
&info->port.xmit_buf[info->xmit_tail],
small_count);
tx_put = (tx_put + small_count) & (tx_bufsize - 1);
char_count -= small_count;
info->icount.tx += small_count;
info->xmit_cnt -= small_count;
info->xmit_tail = (info->xmit_tail + small_count) &
(SERIAL_XMIT_SIZE - 1);
}
#else
while (info->xmit_cnt && char_count) {
data = info->port.xmit_buf[info->xmit_tail];
info->xmit_cnt--;
info->xmit_tail = (info->xmit_tail + 1) &
(SERIAL_XMIT_SIZE - 1);
cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
tx_put = (tx_put + 1) & (tx_bufsize - 1);
char_count--;
info->icount.tx++;
}
#endif
tty_wakeup(tty);
ztxdone:
/* Update tx_put */
cy_writel(&buf_ctrl->tx_put, tx_put);
} }
#ifdef BLOCKMOVE
while (0 < (small_count = min_t(unsigned int,
tx_bufsize - tx_put, min_t(unsigned int,
(SERIAL_XMIT_SIZE - info->xmit_tail),
min_t(unsigned int, info->xmit_cnt,
char_count))))) {
memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr + tx_put),
&info->port.xmit_buf[info->xmit_tail],
small_count);
tx_put = (tx_put + small_count) & (tx_bufsize - 1);
char_count -= small_count;
info->icount.tx += small_count;
info->xmit_cnt -= small_count;
info->xmit_tail = (info->xmit_tail + small_count) &
(SERIAL_XMIT_SIZE - 1);
}
#else
while (info->xmit_cnt && char_count) {
data = info->port.xmit_buf[info->xmit_tail];
info->xmit_cnt--;
info->xmit_tail = (info->xmit_tail + 1) &
(SERIAL_XMIT_SIZE - 1);
cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
tx_put = (tx_put + 1) & (tx_bufsize - 1);
char_count--;
info->icount.tx++;
}
#endif
tty_wakeup(tty);
tty_kref_put(tty);
ztxdone:
/* Update tx_put */
cy_writel(&buf_ctrl->tx_put, tx_put);
} }
static void cyz_handle_cmd(struct cyclades_card *cinfo) static void cyz_handle_cmd(struct cyclades_card *cinfo)
{ {
struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl; struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
struct tty_struct *tty;
struct cyclades_port *info; struct cyclades_port *info;
__u32 channel, param, fw_ver; __u32 channel, param, fw_ver;
__u8 cmd; __u8 cmd;
@ -1108,23 +1099,20 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
special_count = 0; special_count = 0;
delta_count = 0; delta_count = 0;
info = &cinfo->ports[channel]; info = &cinfo->ports[channel];
tty = tty_port_tty_get(&info->port);
if (tty == NULL)
continue;
switch (cmd) { switch (cmd) {
case C_CM_PR_ERROR: case C_CM_PR_ERROR:
tty_insert_flip_char(tty, 0, TTY_PARITY); tty_insert_flip_char(&info->port, 0, TTY_PARITY);
info->icount.rx++; info->icount.rx++;
special_count++; special_count++;
break; break;
case C_CM_FR_ERROR: case C_CM_FR_ERROR:
tty_insert_flip_char(tty, 0, TTY_FRAME); tty_insert_flip_char(&info->port, 0, TTY_FRAME);
info->icount.rx++; info->icount.rx++;
special_count++; special_count++;
break; break;
case C_CM_RXBRK: case C_CM_RXBRK:
tty_insert_flip_char(tty, 0, TTY_BREAK); tty_insert_flip_char(&info->port, 0, TTY_BREAK);
info->icount.rx++; info->icount.rx++;
special_count++; special_count++;
break; break;
@ -1136,8 +1124,14 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
readl(&info->u.cyz.ch_ctrl->rs_status); readl(&info->u.cyz.ch_ctrl->rs_status);
if (dcd & C_RS_DCD) if (dcd & C_RS_DCD)
wake_up_interruptible(&info->port.open_wait); wake_up_interruptible(&info->port.open_wait);
else else {
tty_hangup(tty); struct tty_struct *tty;
tty = tty_port_tty_get(&info->port);
if (tty) {
tty_hangup(tty);
tty_kref_put(tty);
}
}
} }
break; break;
case C_CM_MCTS: case C_CM_MCTS:
@ -1166,7 +1160,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, " printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
"port %ld\n", info->card, channel); "port %ld\n", info->card, channel);
#endif #endif
cyz_handle_rx(info, tty); cyz_handle_rx(info);
break; break;
case C_CM_TXBEMPTY: case C_CM_TXBEMPTY:
case C_CM_TXLOWWM: case C_CM_TXLOWWM:
@ -1176,7 +1170,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, " printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
"port %ld\n", info->card, channel); "port %ld\n", info->card, channel);
#endif #endif
cyz_handle_tx(info, tty); cyz_handle_tx(info);
break; break;
#endif /* CONFIG_CYZ_INTR */ #endif /* CONFIG_CYZ_INTR */
case C_CM_FATAL: case C_CM_FATAL:
@ -1188,8 +1182,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
if (delta_count) if (delta_count)
wake_up_interruptible(&info->port.delta_msr_wait); wake_up_interruptible(&info->port.delta_msr_wait);
if (special_count) if (special_count)
tty_schedule_flip(tty); tty_schedule_flip(&info->port);
tty_kref_put(tty);
} }
} }
@ -1255,17 +1248,11 @@ static void cyz_poll(unsigned long arg)
cyz_handle_cmd(cinfo); cyz_handle_cmd(cinfo);
for (port = 0; port < cinfo->nports; port++) { for (port = 0; port < cinfo->nports; port++) {
struct tty_struct *tty;
info = &cinfo->ports[port]; info = &cinfo->ports[port];
tty = tty_port_tty_get(&info->port);
/* OK to pass NULL to the handle functions below.
They need to drop the data in that case. */
if (!info->throttle) if (!info->throttle)
cyz_handle_rx(info, tty); cyz_handle_rx(info);
cyz_handle_tx(info, tty); cyz_handle_tx(info);
tty_kref_put(tty);
} }
/* poll every 'cyz_polling_cycle' period */ /* poll every 'cyz_polling_cycle' period */
expires = jiffies + cyz_polling_cycle; expires = jiffies + cyz_polling_cycle;

View File

@ -371,22 +371,17 @@ console_initcall(ehv_bc_console_init);
static irqreturn_t ehv_bc_tty_rx_isr(int irq, void *data) static irqreturn_t ehv_bc_tty_rx_isr(int irq, void *data)
{ {
struct ehv_bc_data *bc = data; struct ehv_bc_data *bc = data;
struct tty_struct *ttys = tty_port_tty_get(&bc->port);
unsigned int rx_count, tx_count, len; unsigned int rx_count, tx_count, len;
int count; int count;
char buffer[EV_BYTE_CHANNEL_MAX_BYTES]; char buffer[EV_BYTE_CHANNEL_MAX_BYTES];
int ret; int ret;
/* ttys could be NULL during a hangup */
if (!ttys)
return IRQ_HANDLED;
/* Find out how much data needs to be read, and then ask the TTY layer /* Find out how much data needs to be read, and then ask the TTY layer
* if it can handle that much. We want to ensure that every byte we * if it can handle that much. We want to ensure that every byte we
* read from the byte channel will be accepted by the TTY layer. * read from the byte channel will be accepted by the TTY layer.
*/ */
ev_byte_channel_poll(bc->handle, &rx_count, &tx_count); ev_byte_channel_poll(bc->handle, &rx_count, &tx_count);
count = tty_buffer_request_room(ttys, rx_count); count = tty_buffer_request_room(&bc->port, rx_count);
/* 'count' is the maximum amount of data the TTY layer can accept at /* 'count' is the maximum amount of data the TTY layer can accept at
* this time. However, during testing, I was never able to get 'count' * this time. However, during testing, I was never able to get 'count'
@ -407,7 +402,7 @@ static irqreturn_t ehv_bc_tty_rx_isr(int irq, void *data)
*/ */
/* Pass the received data to the tty layer. */ /* Pass the received data to the tty layer. */
ret = tty_insert_flip_string(ttys, buffer, len); ret = tty_insert_flip_string(&bc->port, buffer, len);
/* 'ret' is the number of bytes that the TTY layer accepted. /* 'ret' is the number of bytes that the TTY layer accepted.
* If it's not equal to 'len', then it means the buffer is * If it's not equal to 'len', then it means the buffer is
@ -422,9 +417,7 @@ static irqreturn_t ehv_bc_tty_rx_isr(int irq, void *data)
} }
/* Tell the tty layer that we're done. */ /* Tell the tty layer that we're done. */
tty_flip_buffer_push(ttys); tty_flip_buffer_push(&bc->port);
tty_kref_put(ttys);
return IRQ_HANDLED; return IRQ_HANDLED;
} }

328
drivers/tty/goldfish.c Normal file
View File

@ -0,0 +1,328 @@
/*
* Copyright (C) 2007 Google, Inc.
* Copyright (C) 2012 Intel, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/console.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/module.h>
enum {
GOLDFISH_TTY_PUT_CHAR = 0x00,
GOLDFISH_TTY_BYTES_READY = 0x04,
GOLDFISH_TTY_CMD = 0x08,
GOLDFISH_TTY_DATA_PTR = 0x10,
GOLDFISH_TTY_DATA_LEN = 0x14,
GOLDFISH_TTY_CMD_INT_DISABLE = 0,
GOLDFISH_TTY_CMD_INT_ENABLE = 1,
GOLDFISH_TTY_CMD_WRITE_BUFFER = 2,
GOLDFISH_TTY_CMD_READ_BUFFER = 3,
};
struct goldfish_tty {
struct tty_port port;
spinlock_t lock;
void __iomem *base;
u32 irq;
int opencount;
struct console console;
};
static DEFINE_MUTEX(goldfish_tty_lock);
static struct tty_driver *goldfish_tty_driver;
static u32 goldfish_tty_line_count = 8;
static u32 goldfish_tty_current_line_count;
static struct goldfish_tty *goldfish_ttys;
static void goldfish_tty_do_write(int line, const char *buf, unsigned count)
{
unsigned long irq_flags;
struct goldfish_tty *qtty = &goldfish_ttys[line];
void __iomem *base = qtty->base;
spin_lock_irqsave(&qtty->lock, irq_flags);
writel((u32)buf, base + GOLDFISH_TTY_DATA_PTR);
writel(count, base + GOLDFISH_TTY_DATA_LEN);
writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_CMD);
spin_unlock_irqrestore(&qtty->lock, irq_flags);
}
static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)
{
struct platform_device *pdev = dev_id;
struct goldfish_tty *qtty = &goldfish_ttys[pdev->id];
void __iomem *base = qtty->base;
unsigned long irq_flags;
unsigned char *buf;
u32 count;
count = readl(base + GOLDFISH_TTY_BYTES_READY);
if(count == 0)
return IRQ_NONE;
count = tty_prepare_flip_string(&qtty->port, &buf, count);
spin_lock_irqsave(&qtty->lock, irq_flags);
writel((u32)buf, base + GOLDFISH_TTY_DATA_PTR);
writel(count, base + GOLDFISH_TTY_DATA_LEN);
writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_CMD);
spin_unlock_irqrestore(&qtty->lock, irq_flags);
tty_schedule_flip(&qtty->port);
return IRQ_HANDLED;
}
static int goldfish_tty_activate(struct tty_port *port, struct tty_struct *tty)
{
struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port);
writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_CMD);
return 0;
}
static void goldfish_tty_shutdown(struct tty_port *port)
{
struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port);
writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_CMD);
}
static int goldfish_tty_open(struct tty_struct * tty, struct file * filp)
{
struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
return tty_port_open(&qtty->port, tty, filp);
}
static void goldfish_tty_close(struct tty_struct * tty, struct file * filp)
{
tty_port_close(tty->port, tty, filp);
}
static void goldfish_tty_hangup(struct tty_struct *tty)
{
tty_port_hangup(tty->port);
}
static int goldfish_tty_write(struct tty_struct * tty, const unsigned char *buf, int count)
{
goldfish_tty_do_write(tty->index, buf, count);
return count;
}
static int goldfish_tty_write_room(struct tty_struct *tty)
{
return 0x10000;
}
static int goldfish_tty_chars_in_buffer(struct tty_struct *tty)
{
struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
void __iomem *base = qtty->base;
return readl(base + GOLDFISH_TTY_BYTES_READY);
}
static void goldfish_tty_console_write(struct console *co, const char *b, unsigned count)
{
goldfish_tty_do_write(co->index, b, count);
}
static struct tty_driver *goldfish_tty_console_device(struct console *c, int *index)
{
*index = c->index;
return goldfish_tty_driver;
}
static int goldfish_tty_console_setup(struct console *co, char *options)
{
if((unsigned)co->index > goldfish_tty_line_count)
return -ENODEV;
if(goldfish_ttys[co->index].base == 0)
return -ENODEV;
return 0;
}
static struct tty_port_operations goldfish_port_ops = {
.activate = goldfish_tty_activate,
.shutdown = goldfish_tty_shutdown
};
static struct tty_operations goldfish_tty_ops = {
.open = goldfish_tty_open,
.close = goldfish_tty_close,
.hangup = goldfish_tty_hangup,
.write = goldfish_tty_write,
.write_room = goldfish_tty_write_room,
.chars_in_buffer = goldfish_tty_chars_in_buffer,
};
static int goldfish_tty_create_driver(void)
{
int ret;
struct tty_driver *tty;
goldfish_ttys = kzalloc(sizeof(*goldfish_ttys) * goldfish_tty_line_count, GFP_KERNEL);
if(goldfish_ttys == NULL) {
ret = -ENOMEM;
goto err_alloc_goldfish_ttys_failed;
}
tty = alloc_tty_driver(goldfish_tty_line_count);
if(tty == NULL) {
ret = -ENOMEM;
goto err_alloc_tty_driver_failed;
}
tty->driver_name = "goldfish";
tty->name = "ttyGF";
tty->type = TTY_DRIVER_TYPE_SERIAL;
tty->subtype = SERIAL_TYPE_NORMAL;
tty->init_termios = tty_std_termios;
tty->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(tty, &goldfish_tty_ops);
ret = tty_register_driver(tty);
if(ret)
goto err_tty_register_driver_failed;
goldfish_tty_driver = tty;
return 0;
err_tty_register_driver_failed:
put_tty_driver(tty);
err_alloc_tty_driver_failed:
kfree(goldfish_ttys);
goldfish_ttys = NULL;
err_alloc_goldfish_ttys_failed:
return ret;
}
static void goldfish_tty_delete_driver(void)
{
tty_unregister_driver(goldfish_tty_driver);
put_tty_driver(goldfish_tty_driver);
goldfish_tty_driver = NULL;
kfree(goldfish_ttys);
goldfish_ttys = NULL;
}
static int goldfish_tty_probe(struct platform_device *pdev)
{
struct goldfish_tty *qtty;
int ret = -EINVAL;
int i;
struct resource *r;
struct device *ttydev;
void __iomem *base;
u32 irq;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if(r == NULL)
return -EINVAL;
base = ioremap(r->start, 0x1000);
if (base == NULL)
pr_err("goldfish_tty: unable to remap base\n");
r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if(r == NULL)
goto err_unmap;
irq = r->start;
if(pdev->id >= goldfish_tty_line_count)
goto err_unmap;
mutex_lock(&goldfish_tty_lock);
if(goldfish_tty_current_line_count == 0) {
ret = goldfish_tty_create_driver();
if(ret)
goto err_create_driver_failed;
}
goldfish_tty_current_line_count++;
qtty = &goldfish_ttys[pdev->id];
spin_lock_init(&qtty->lock);
tty_port_init(&qtty->port);
qtty->port.ops = &goldfish_port_ops;
qtty->base = base;
qtty->irq = irq;
writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_CMD);
ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, "goldfish_tty", pdev);
if(ret)
goto err_request_irq_failed;
ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver,
pdev->id, &pdev->dev);
if(IS_ERR(ttydev)) {
ret = PTR_ERR(ttydev);
goto err_tty_register_device_failed;
}
strcpy(qtty->console.name, "ttyGF");
qtty->console.write = goldfish_tty_console_write;
qtty->console.device = goldfish_tty_console_device;
qtty->console.setup = goldfish_tty_console_setup;
qtty->console.flags = CON_PRINTBUFFER;
qtty->console.index = pdev->id;
register_console(&qtty->console);
mutex_unlock(&goldfish_tty_lock);
return 0;
tty_unregister_device(goldfish_tty_driver, i);
err_tty_register_device_failed:
free_irq(irq, pdev);
err_request_irq_failed:
goldfish_tty_current_line_count--;
if(goldfish_tty_current_line_count == 0)
goldfish_tty_delete_driver();
err_create_driver_failed:
mutex_unlock(&goldfish_tty_lock);
err_unmap:
iounmap(base);
return ret;
}
static int goldfish_tty_remove(struct platform_device *pdev)
{
struct goldfish_tty *qtty;
mutex_lock(&goldfish_tty_lock);
qtty = &goldfish_ttys[pdev->id];
unregister_console(&qtty->console);
tty_unregister_device(goldfish_tty_driver, pdev->id);
iounmap(qtty->base);
qtty->base = 0;
free_irq(qtty->irq, pdev);
goldfish_tty_current_line_count--;
if(goldfish_tty_current_line_count == 0)
goldfish_tty_delete_driver();
mutex_unlock(&goldfish_tty_lock);
return 0;
}
static struct platform_driver goldfish_tty_platform_driver = {
.probe = goldfish_tty_probe,
.remove = goldfish_tty_remove,
.driver = {
.name = "goldfish_tty"
}
};
module_platform_driver(goldfish_tty_platform_driver);
MODULE_LICENSE("GPL v2");

View File

@ -1,3 +1,5 @@
if TTY
config HVC_DRIVER config HVC_DRIVER
bool bool
help help
@ -119,3 +121,4 @@ config HVCS
which will also be compiled when this driver is built as a which will also be compiled when this driver is built as a
module. module.
endif # TTY

View File

@ -629,7 +629,7 @@ int hvc_poll(struct hvc_struct *hp)
/* Read data if any */ /* Read data if any */
for (;;) { for (;;) {
int count = tty_buffer_request_room(tty, N_INBUF); int count = tty_buffer_request_room(&hp->port, N_INBUF);
/* If flip is full, just reschedule a later read */ /* If flip is full, just reschedule a later read */
if (count == 0) { if (count == 0) {
@ -672,7 +672,7 @@ int hvc_poll(struct hvc_struct *hp)
} }
} }
#endif /* CONFIG_MAGIC_SYSRQ */ #endif /* CONFIG_MAGIC_SYSRQ */
tty_insert_flip_char(tty, buf[i], 0); tty_insert_flip_char(&hp->port, buf[i], 0);
} }
read_total += n; read_total += n;
@ -691,7 +691,7 @@ int hvc_poll(struct hvc_struct *hp)
a minimum for performance. */ a minimum for performance. */
timeout = MIN_TIMEOUT; timeout = MIN_TIMEOUT;
tty_flip_buffer_push(tty); tty_flip_buffer_push(&hp->port);
} }
tty_kref_put(tty); tty_kref_put(tty);

View File

@ -609,11 +609,11 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
/* remove the read masks */ /* remove the read masks */
hvcsd->todo_mask &= ~(HVCS_READ_MASK); hvcsd->todo_mask &= ~(HVCS_READ_MASK);
if (tty_buffer_request_room(tty, HVCS_BUFF_LEN) >= HVCS_BUFF_LEN) { if (tty_buffer_request_room(&hvcsd->port, HVCS_BUFF_LEN) >= HVCS_BUFF_LEN) {
got = hvc_get_chars(unit_address, got = hvc_get_chars(unit_address,
&buf[0], &buf[0],
HVCS_BUFF_LEN); HVCS_BUFF_LEN);
tty_insert_flip_string(tty, buf, got); tty_insert_flip_string(&hvcsd->port, buf, got);
} }
/* Give the TTY time to process the data we just sent. */ /* Give the TTY time to process the data we just sent. */
@ -623,7 +623,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
spin_unlock_irqrestore(&hvcsd->lock, flags); spin_unlock_irqrestore(&hvcsd->lock, flags);
/* This is synch because tty->low_latency == 1 */ /* This is synch because tty->low_latency == 1 */
if(got) if(got)
tty_flip_buffer_push(tty); tty_flip_buffer_push(&hvcsd->port);
if (!got) { if (!got) {
/* Do this _after_ the flip_buffer_push */ /* Do this _after_ the flip_buffer_push */

View File

@ -329,8 +329,7 @@ static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet)
} }
} }
static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty, static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
const char *buf, int len)
{ {
int i; int i;
@ -346,7 +345,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty,
continue; continue;
} }
#endif /* CONFIG_MAGIC_SYSRQ */ #endif /* CONFIG_MAGIC_SYSRQ */
tty_insert_flip_char(tty, c, 0); tty_insert_flip_char(&hp->port, c, 0);
} }
} }
@ -359,8 +358,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty,
* revisited. * revisited.
*/ */
#define TTY_THRESHOLD_THROTTLE 128 #define TTY_THRESHOLD_THROTTLE 128
static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty, static bool hvsi_recv_data(struct hvsi_struct *hp, const uint8_t *packet)
const uint8_t *packet)
{ {
const struct hvsi_header *header = (const struct hvsi_header *)packet; const struct hvsi_header *header = (const struct hvsi_header *)packet;
const uint8_t *data = packet + sizeof(struct hvsi_header); const uint8_t *data = packet + sizeof(struct hvsi_header);
@ -377,7 +375,7 @@ static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty,
datalen = TTY_THRESHOLD_THROTTLE; datalen = TTY_THRESHOLD_THROTTLE;
} }
hvsi_insert_chars(hp, tty, data, datalen); hvsi_insert_chars(hp, data, datalen);
if (overflow > 0) { if (overflow > 0) {
/* /*
@ -438,9 +436,7 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty,
case VS_DATA_PACKET_HEADER: case VS_DATA_PACKET_HEADER:
if (!is_open(hp)) if (!is_open(hp))
break; break;
if (tty == NULL) flip = hvsi_recv_data(hp, packet);
break; /* no tty buffer to put data in */
flip = hvsi_recv_data(hp, tty, packet);
break; break;
case VS_CONTROL_PACKET_HEADER: case VS_CONTROL_PACKET_HEADER:
hvsi_recv_control(hp, packet, tty, handshake); hvsi_recv_control(hp, packet, tty, handshake);
@ -469,17 +465,17 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty,
compact_inbuf(hp, packet); compact_inbuf(hp, packet);
if (flip) if (flip)
tty_flip_buffer_push(tty); tty_flip_buffer_push(&hp->port);
return 1; return 1;
} }
static void hvsi_send_overflow(struct hvsi_struct *hp, struct tty_struct *tty) static void hvsi_send_overflow(struct hvsi_struct *hp)
{ {
pr_debug("%s: delivering %i bytes overflow\n", __func__, pr_debug("%s: delivering %i bytes overflow\n", __func__,
hp->n_throttle); hp->n_throttle);
hvsi_insert_chars(hp, tty, hp->throttle_buf, hp->n_throttle); hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle);
hp->n_throttle = 0; hp->n_throttle = 0;
} }
@ -514,8 +510,8 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg)
if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) { if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) {
/* we weren't hung up and we weren't throttled, so we can /* we weren't hung up and we weren't throttled, so we can
* deliver the rest now */ * deliver the rest now */
hvsi_send_overflow(hp, tty); hvsi_send_overflow(hp);
tty_flip_buffer_push(tty); tty_flip_buffer_push(&hp->port);
} }
spin_unlock_irqrestore(&hp->lock, flags); spin_unlock_irqrestore(&hp->lock, flags);
@ -1001,8 +997,8 @@ static void hvsi_unthrottle(struct tty_struct *tty)
spin_lock_irqsave(&hp->lock, flags); spin_lock_irqsave(&hp->lock, flags);
if (hp->n_throttle) { if (hp->n_throttle) {
hvsi_send_overflow(hp, tty); hvsi_send_overflow(hp);
tty_flip_buffer_push(tty); tty_flip_buffer_push(&hp->port);
} }
spin_unlock_irqrestore(&hp->lock, flags); spin_unlock_irqrestore(&hp->lock, flags);
@ -1187,9 +1183,7 @@ static int __init hvsi_console_init(void)
hvsi_wait = poll_for_state; /* no irqs yet; must poll */ hvsi_wait = poll_for_state; /* no irqs yet; must poll */
/* search device tree for vty nodes */ /* search device tree for vty nodes */
for (vty = of_find_compatible_node(NULL, "serial", "hvterm-protocol"); for_each_compatible_node(vty, "serial", "hvterm-protocol") {
vty != NULL;
vty = of_find_compatible_node(vty, "serial", "hvterm-protocol")) {
struct hvsi_struct *hp; struct hvsi_struct *hp;
const uint32_t *vtermno, *irq; const uint32_t *vtermno, *irq;

View File

@ -106,7 +106,7 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
tty->port.tty = linux_tty; tty->port.tty = linux_tty;
linux_tty->driver_data = tty; linux_tty->driver_data = tty;
linux_tty->low_latency = 1; tty->port.low_latency = 1;
if (tty->tty_type == TTYTYPE_MODEM) if (tty->tty_type == TTYTYPE_MODEM)
ipwireless_ppp_open(tty->network); ipwireless_ppp_open(tty->network);
@ -160,15 +160,9 @@ static void ipw_close(struct tty_struct *linux_tty, struct file *filp)
void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data, void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
unsigned int length) unsigned int length)
{ {
struct tty_struct *linux_tty;
int work = 0; int work = 0;
mutex_lock(&tty->ipw_tty_mutex); mutex_lock(&tty->ipw_tty_mutex);
linux_tty = tty->port.tty;
if (linux_tty == NULL) {
mutex_unlock(&tty->ipw_tty_mutex);
return;
}
if (!tty->port.count) { if (!tty->port.count) {
mutex_unlock(&tty->ipw_tty_mutex); mutex_unlock(&tty->ipw_tty_mutex);
@ -176,7 +170,7 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
} }
mutex_unlock(&tty->ipw_tty_mutex); mutex_unlock(&tty->ipw_tty_mutex);
work = tty_insert_flip_string(linux_tty, data, length); work = tty_insert_flip_string(&tty->port, data, length);
if (work != length) if (work != length)
printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
@ -187,7 +181,7 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
* This may sleep if ->low_latency is set * This may sleep if ->low_latency is set
*/ */
if (work) if (work)
tty_flip_buffer_push(linux_tty); tty_flip_buffer_push(&tty->port);
} }
static void ipw_write_packet_sent_callback(void *callback_data, static void ipw_write_packet_sent_callback(void *callback_data,

View File

@ -634,10 +634,10 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
break; break;
case 1: /* Received Break !!! */ case 1: /* Received Break !!! */
tty_insert_flip_char(tty, 0, TTY_BREAK); tty_insert_flip_char(&port->port, 0, TTY_BREAK);
if (port->port.flags & ASYNC_SAK) if (port->port.flags & ASYNC_SAK)
do_SAK(tty); do_SAK(tty);
tty_flip_buffer_push(tty); tty_flip_buffer_push(&port->port);
break; break;
case 2: /* Statistics */ case 2: /* Statistics */
@ -650,15 +650,15 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
break; break;
} }
} else { /* Data Packet */ } else { /* Data Packet */
count = tty_prepare_flip_string(&port->port, &rp,
count = tty_prepare_flip_string(tty, &rp, byte_count & ~1); byte_count & ~1);
pr_debug("%s: Can rx %d of %d bytes.\n", pr_debug("%s: Can rx %d of %d bytes.\n",
__func__, count, byte_count); __func__, count, byte_count);
word_count = count >> 1; word_count = count >> 1;
insw(base, rp, word_count); insw(base, rp, word_count);
byte_count -= (word_count << 1); byte_count -= (word_count << 1);
if (count & 0x0001) { if (count & 0x0001) {
tty_insert_flip_char(tty, inw(base) & 0xff, tty_insert_flip_char(&port->port, inw(base) & 0xff,
TTY_NORMAL); TTY_NORMAL);
byte_count -= 2; byte_count -= 2;
} }
@ -671,7 +671,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
byte_count -= 2; byte_count -= 2;
} }
} }
tty_flip_buffer_push(tty); tty_flip_buffer_push(&port->port);
} }
outw(0x0000, base+0x04); /* enable interrupts */ outw(0x0000, base+0x04); /* enable interrupts */
spin_unlock(&card->card_lock); spin_unlock(&card->card_lock);

677
drivers/tty/metag_da.c Normal file
View File

@ -0,0 +1,677 @@
/*
* dashtty.c - tty driver for Dash channels interface.
*
* Copyright (C) 2007,2008,2012 Imagination Technologies
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*
*/
#include <linux/atomic.h>
#include <linux/completion.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/serial.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/uaccess.h>
#include <asm/da.h>
/* Channel error codes */
#define CONAOK 0
#define CONERR 1
#define CONBAD 2
#define CONPRM 3
#define CONADR 4
#define CONCNT 5
#define CONCBF 6
#define CONCBE 7
#define CONBSY 8
/* Default channel for the console */
#define CONSOLE_CHANNEL 1
#define NUM_TTY_CHANNELS 6
/* Auto allocate */
#define DA_TTY_MAJOR 0
/* A speedy poll rate helps the userland debug process connection response.
* But, if you set it too high then no other userland processes get much
* of a look in.
*/
#define DA_TTY_POLL (HZ / 50)
/*
* A short put delay improves latency but has a high throughput overhead
*/
#define DA_TTY_PUT_DELAY (HZ / 100)
static atomic_t num_channels_need_poll = ATOMIC_INIT(0);
static struct timer_list poll_timer;
static struct tty_driver *channel_driver;
static struct timer_list put_timer;
static struct task_struct *dashtty_thread;
#define RX_BUF_SIZE 1024
enum {
INCHR = 1,
OUTCHR,
RDBUF,
WRBUF,
RDSTAT
};
/**
* struct dashtty_port - Wrapper struct for dashtty tty_port.
* @port: TTY port data
* @rx_lock: Lock for rx_buf.
* This protects between the poll timer and user context.
* It's also held during read SWITCH operations.
* @rx_buf: Read buffer
* @xmit_lock: Lock for xmit_*, and port.xmit_buf.
* This protects between user context and kernel thread.
* It's also held during write SWITCH operations.
* @xmit_cnt: Size of xmit buffer contents
* @xmit_head: Head of xmit buffer where data is written
* @xmit_tail: Tail of xmit buffer where data is read
* @xmit_empty: Completion for xmit buffer being empty
*/
struct dashtty_port {
struct tty_port port;
spinlock_t rx_lock;
void *rx_buf;
struct mutex xmit_lock;
unsigned int xmit_cnt;
unsigned int xmit_head;
unsigned int xmit_tail;
struct completion xmit_empty;
};
static struct dashtty_port dashtty_ports[NUM_TTY_CHANNELS];
static atomic_t dashtty_xmit_cnt = ATOMIC_INIT(0);
static wait_queue_head_t dashtty_waitqueue;
/*
* Low-level DA channel access routines
*/
static int chancall(int in_bios_function, int in_channel,
int in_arg2, void *in_arg3,
void *in_arg4)
{
register int bios_function asm("D1Ar1") = in_bios_function;
register int channel asm("D0Ar2") = in_channel;
register int arg2 asm("D1Ar3") = in_arg2;
register void *arg3 asm("D0Ar4") = in_arg3;
register void *arg4 asm("D1Ar5") = in_arg4;
register int bios_call asm("D0Ar6") = 3;
register int result asm("D0Re0");
asm volatile (
"MSETL [A0StP++], %6,%4,%2\n\t"
"ADD A0StP, A0StP, #8\n\t"
"SWITCH #0x0C30208\n\t"
"GETD %0, [A0StP+#-8]\n\t"
"SUB A0StP, A0StP, #(4*6)+8\n\t"
: "=d" (result) /* outs */
: "d" (bios_function),
"d" (channel),
"d" (arg2),
"d" (arg3),
"d" (arg4),
"d" (bios_call) /* ins */
: "memory");
return result;
}
/*
* Attempts to fetch count bytes from channel and returns actual count.
*/
static int fetch_data(unsigned int channel)
{
struct dashtty_port *dport = &dashtty_ports[channel];
int received = 0;
spin_lock_bh(&dport->rx_lock);
/* check the port isn't being shut down */
if (!dport->rx_buf)
goto unlock;
if (chancall(RDBUF, channel, RX_BUF_SIZE,
(void *)dport->rx_buf, &received) == CONAOK) {
if (received) {
int space;
unsigned char *cbuf;
space = tty_prepare_flip_string(&dport->port, &cbuf,
received);
if (space <= 0)
goto unlock;
memcpy(cbuf, dport->rx_buf, space);
tty_flip_buffer_push(&dport->port);
}
}
unlock:
spin_unlock_bh(&dport->rx_lock);
return received;
}
/**
* find_channel_to_poll() - Returns number of the next channel to poll.
* Returns: The number of the next channel to poll, or -1 if none need
* polling.
*/
static int find_channel_to_poll(void)
{
static int last_polled_channel;
int last = last_polled_channel;
int chan;
struct dashtty_port *dport;
for (chan = last + 1; ; ++chan) {
if (chan >= NUM_TTY_CHANNELS)
chan = 0;
dport = &dashtty_ports[chan];
if (dport->rx_buf) {
last_polled_channel = chan;
return chan;
}
if (chan == last)
break;
}
return -1;
}
/**
* put_channel_data() - Write out a block of channel data.
* @chan: DA channel number.
*
* Write a single block of data out to the debug adapter. If the circular buffer
* is wrapped then only the first block is written.
*
* Returns: 1 if the remote buffer was too full to accept data.
* 0 otherwise.
*/
static int put_channel_data(unsigned int chan)
{
struct dashtty_port *dport;
struct tty_struct *tty;
int number_written;
unsigned int count = 0;
dport = &dashtty_ports[chan];
mutex_lock(&dport->xmit_lock);
if (dport->xmit_cnt) {
count = min((unsigned int)(SERIAL_XMIT_SIZE - dport->xmit_tail),
dport->xmit_cnt);
chancall(WRBUF, chan, count,
dport->port.xmit_buf + dport->xmit_tail,
&number_written);
dport->xmit_cnt -= number_written;
if (!dport->xmit_cnt) {
/* reset pointers to avoid wraps */
dport->xmit_head = 0;
dport->xmit_tail = 0;
complete(&dport->xmit_empty);
} else {
dport->xmit_tail += number_written;
if (dport->xmit_tail >= SERIAL_XMIT_SIZE)
dport->xmit_tail -= SERIAL_XMIT_SIZE;
}
atomic_sub(number_written, &dashtty_xmit_cnt);
}
mutex_unlock(&dport->xmit_lock);
/* if we've made more data available, wake up tty */
if (count && number_written) {
tty = tty_port_tty_get(&dport->port);
if (tty) {
tty_wakeup(tty);
tty_kref_put(tty);
}
}
/* did the write fail? */
return count && !number_written;
}
/**
* put_data() - Kernel thread to write out blocks of channel data to DA.
* @arg: Unused.
*
* This kernel thread runs while @dashtty_xmit_cnt != 0, and loops over the
* channels to write out any buffered data. If any of the channels stall due to
* the remote buffer being full, a hold off happens to allow the debugger to
* drain the buffer.
*/
static int put_data(void *arg)
{
unsigned int chan, stall;
__set_current_state(TASK_RUNNING);
while (!kthread_should_stop()) {
/*
* For each channel see if there's anything to transmit in the
* port's xmit_buf.
*/
stall = 0;
for (chan = 0; chan < NUM_TTY_CHANNELS; ++chan)
stall += put_channel_data(chan);
/*
* If some of the buffers are full, hold off for a short while
* to allow them to empty.
*/
if (stall)
msleep(25);
wait_event_interruptible(dashtty_waitqueue,
atomic_read(&dashtty_xmit_cnt));
}
return 0;
}
/*
* This gets called every DA_TTY_POLL and polls the channels for data
*/
static void dashtty_timer(unsigned long ignored)
{
int channel;
/* If there are no ports open do nothing and don't poll again. */
if (!atomic_read(&num_channels_need_poll))
return;
channel = find_channel_to_poll();
/* Did we find a channel to poll? */
if (channel >= 0)
fetch_data(channel);
mod_timer_pinned(&poll_timer, jiffies + DA_TTY_POLL);
}
static void add_poll_timer(struct timer_list *poll_timer)
{
setup_timer(poll_timer, dashtty_timer, 0);
poll_timer->expires = jiffies + DA_TTY_POLL;
/*
* Always attach the timer to the boot CPU. The DA channels are per-CPU
* so all polling should be from a single CPU.
*/
add_timer_on(poll_timer, 0);
}
static int dashtty_port_activate(struct tty_port *port, struct tty_struct *tty)
{
struct dashtty_port *dport = container_of(port, struct dashtty_port,
port);
void *rx_buf;
/* Allocate the buffer we use for writing data */
if (tty_port_alloc_xmit_buf(port) < 0)
goto err;
/* Allocate the buffer we use for reading data */
rx_buf = kzalloc(RX_BUF_SIZE, GFP_KERNEL);
if (!rx_buf)
goto err_free_xmit;
spin_lock_bh(&dport->rx_lock);
dport->rx_buf = rx_buf;
spin_unlock_bh(&dport->rx_lock);
/*
* Don't add the poll timer if we're opening a console. This
* avoids the overhead of polling the Dash but means it is not
* possible to have a login on /dev/console.
*
*/
if (dport != &dashtty_ports[CONSOLE_CHANNEL])
if (atomic_inc_return(&num_channels_need_poll) == 1)
add_poll_timer(&poll_timer);
return 0;
err_free_xmit:
tty_port_free_xmit_buf(port);
err:
return -ENOMEM;
}
static void dashtty_port_shutdown(struct tty_port *port)
{
struct dashtty_port *dport = container_of(port, struct dashtty_port,
port);
void *rx_buf;
unsigned int count;
/* stop reading */
if (dport != &dashtty_ports[CONSOLE_CHANNEL])
if (atomic_dec_and_test(&num_channels_need_poll))
del_timer_sync(&poll_timer);
mutex_lock(&dport->xmit_lock);
count = dport->xmit_cnt;
mutex_unlock(&dport->xmit_lock);
if (count) {
/*
* There's still data to write out, so wake and wait for the
* writer thread to drain the buffer.
*/
del_timer(&put_timer);
wake_up_interruptible(&dashtty_waitqueue);
wait_for_completion(&dport->xmit_empty);
}
/* Null the read buffer (timer could still be running!) */
spin_lock_bh(&dport->rx_lock);
rx_buf = dport->rx_buf;
dport->rx_buf = NULL;
spin_unlock_bh(&dport->rx_lock);
/* Free the read buffer */
kfree(rx_buf);
/* Free the write buffer */
tty_port_free_xmit_buf(port);
}
static const struct tty_port_operations dashtty_port_ops = {
.activate = dashtty_port_activate,
.shutdown = dashtty_port_shutdown,
};
static int dashtty_install(struct tty_driver *driver, struct tty_struct *tty)
{
return tty_port_install(&dashtty_ports[tty->index].port, driver, tty);
}
static int dashtty_open(struct tty_struct *tty, struct file *filp)
{
return tty_port_open(tty->port, tty, filp);
}
static void dashtty_close(struct tty_struct *tty, struct file *filp)
{
return tty_port_close(tty->port, tty, filp);
}
static void dashtty_hangup(struct tty_struct *tty)
{
int channel;
struct dashtty_port *dport;
channel = tty->index;
dport = &dashtty_ports[channel];
/* drop any data in the xmit buffer */
mutex_lock(&dport->xmit_lock);
if (dport->xmit_cnt) {
atomic_sub(dport->xmit_cnt, &dashtty_xmit_cnt);
dport->xmit_cnt = 0;
dport->xmit_head = 0;
dport->xmit_tail = 0;
complete(&dport->xmit_empty);
}
mutex_unlock(&dport->xmit_lock);
tty_port_hangup(tty->port);
}
/**
* dashtty_put_timer() - Delayed wake up of kernel thread.
* @ignored: unused
*
* This timer function wakes up the kernel thread if any data exists in the
* buffers. It is used to delay the expensive writeout until the writer has
* stopped writing.
*/
static void dashtty_put_timer(unsigned long ignored)
{
if (atomic_read(&dashtty_xmit_cnt))
wake_up_interruptible(&dashtty_waitqueue);
}
static int dashtty_write(struct tty_struct *tty, const unsigned char *buf,
int total)
{
int channel, count, block;
struct dashtty_port *dport;
/* Determine the channel */
channel = tty->index;
dport = &dashtty_ports[channel];
/*
* Write to output buffer.
*
* The reason that we asynchronously write the buffer is because if we
* were to write the buffer synchronously then because DA channels are
* per-CPU the buffer would be written to the channel of whatever CPU
* we're running on.
*
* What we actually want to happen is have all input and output done on
* one CPU.
*/
mutex_lock(&dport->xmit_lock);
/* work out how many bytes we can write to the xmit buffer */
total = min(total, (int)(SERIAL_XMIT_SIZE - dport->xmit_cnt));
atomic_add(total, &dashtty_xmit_cnt);
dport->xmit_cnt += total;
/* write the actual bytes (may need splitting if it wraps) */
for (count = total; count; count -= block) {
block = min(count, (int)(SERIAL_XMIT_SIZE - dport->xmit_head));
memcpy(dport->port.xmit_buf + dport->xmit_head, buf, block);
dport->xmit_head += block;
if (dport->xmit_head >= SERIAL_XMIT_SIZE)
dport->xmit_head -= SERIAL_XMIT_SIZE;
buf += block;
}
count = dport->xmit_cnt;
/* xmit buffer no longer empty? */
if (count)
INIT_COMPLETION(dport->xmit_empty);
mutex_unlock(&dport->xmit_lock);
if (total) {
/*
* If the buffer is full, wake up the kthread, otherwise allow
* some more time for the buffer to fill up a bit before waking
* it.
*/
if (count == SERIAL_XMIT_SIZE) {
del_timer(&put_timer);
wake_up_interruptible(&dashtty_waitqueue);
} else {
mod_timer(&put_timer, jiffies + DA_TTY_PUT_DELAY);
}
}
return total;
}
static int dashtty_write_room(struct tty_struct *tty)
{
struct dashtty_port *dport;
int channel;
int room;
channel = tty->index;
dport = &dashtty_ports[channel];
/* report the space in the xmit buffer */
mutex_lock(&dport->xmit_lock);
room = SERIAL_XMIT_SIZE - dport->xmit_cnt;
mutex_unlock(&dport->xmit_lock);
return room;
}
static int dashtty_chars_in_buffer(struct tty_struct *tty)
{
struct dashtty_port *dport;
int channel;
int chars;
channel = tty->index;
dport = &dashtty_ports[channel];
/* report the number of bytes in the xmit buffer */
mutex_lock(&dport->xmit_lock);
chars = dport->xmit_cnt;
mutex_unlock(&dport->xmit_lock);
return chars;
}
static const struct tty_operations dashtty_ops = {
.install = dashtty_install,
.open = dashtty_open,
.close = dashtty_close,
.hangup = dashtty_hangup,
.write = dashtty_write,
.write_room = dashtty_write_room,
.chars_in_buffer = dashtty_chars_in_buffer,
};
static int __init dashtty_init(void)
{
int ret;
int nport;
struct dashtty_port *dport;
if (!metag_da_enabled())
return -ENODEV;
channel_driver = tty_alloc_driver(NUM_TTY_CHANNELS,
TTY_DRIVER_REAL_RAW);
if (IS_ERR(channel_driver))
return PTR_ERR(channel_driver);
channel_driver->driver_name = "metag_da";
channel_driver->name = "ttyDA";
channel_driver->major = DA_TTY_MAJOR;
channel_driver->minor_start = 0;
channel_driver->type = TTY_DRIVER_TYPE_SERIAL;
channel_driver->subtype = SERIAL_TYPE_NORMAL;
channel_driver->init_termios = tty_std_termios;
channel_driver->init_termios.c_cflag |= CLOCAL;
tty_set_operations(channel_driver, &dashtty_ops);
for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) {
dport = &dashtty_ports[nport];
tty_port_init(&dport->port);
dport->port.ops = &dashtty_port_ops;
spin_lock_init(&dport->rx_lock);
mutex_init(&dport->xmit_lock);
/* the xmit buffer starts empty, i.e. completely written */
init_completion(&dport->xmit_empty);
complete(&dport->xmit_empty);
}
setup_timer(&put_timer, dashtty_put_timer, 0);
init_waitqueue_head(&dashtty_waitqueue);
dashtty_thread = kthread_create(put_data, NULL, "ttyDA");
if (IS_ERR(dashtty_thread)) {
pr_err("Couldn't create dashtty thread\n");
ret = PTR_ERR(dashtty_thread);
goto err_destroy_ports;
}
/*
* Bind the writer thread to the boot CPU so it can't migrate.
* DA channels are per-CPU and we want all channel I/O to be on a single
* predictable CPU.
*/
kthread_bind(dashtty_thread, 0);
wake_up_process(dashtty_thread);
ret = tty_register_driver(channel_driver);
if (ret < 0) {
pr_err("Couldn't install dashtty driver: err %d\n",
ret);
goto err_stop_kthread;
}
return 0;
err_stop_kthread:
kthread_stop(dashtty_thread);
err_destroy_ports:
for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) {
dport = &dashtty_ports[nport];
tty_port_destroy(&dport->port);
}
put_tty_driver(channel_driver);
return ret;
}
static void dashtty_exit(void)
{
int nport;
struct dashtty_port *dport;
del_timer_sync(&put_timer);
kthread_stop(dashtty_thread);
del_timer_sync(&poll_timer);
tty_unregister_driver(channel_driver);
for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) {
dport = &dashtty_ports[nport];
tty_port_destroy(&dport->port);
}
put_tty_driver(channel_driver);
}
module_init(dashtty_init);
module_exit(dashtty_exit);
#ifdef CONFIG_DA_CONSOLE
static void dash_console_write(struct console *co, const char *s,
unsigned int count)
{
int actually_written;
chancall(WRBUF, CONSOLE_CHANNEL, count, (void *)s, &actually_written);
}
static struct tty_driver *dash_console_device(struct console *c, int *index)
{
*index = c->index;
return channel_driver;
}
struct console dash_console = {
.name = "ttyDA",
.write = dash_console_write,
.device = dash_console_device,
.flags = CON_PRINTBUFFER,
.index = 1,
};
#endif

View File

@ -1405,7 +1405,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
if (inited && !test_bit(TTY_THROTTLED, &tty->flags) && if (inited && !test_bit(TTY_THROTTLED, &tty->flags) &&
MoxaPortRxQueue(p) > 0) { /* RX */ MoxaPortRxQueue(p) > 0) { /* RX */
MoxaPortReadData(p); MoxaPortReadData(p);
tty_schedule_flip(tty); tty_schedule_flip(&p->port);
} }
} else { } else {
clear_bit(EMPTYWAIT, &p->statusflags); clear_bit(EMPTYWAIT, &p->statusflags);
@ -1429,8 +1429,8 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
goto put; goto put;
if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */ if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */
tty_insert_flip_char(tty, 0, TTY_BREAK); tty_insert_flip_char(&p->port, 0, TTY_BREAK);
tty_schedule_flip(tty); tty_schedule_flip(&p->port);
} }
if (intr & IntrLine) if (intr & IntrLine)
@ -1966,7 +1966,7 @@ static int MoxaPortReadData(struct moxa_port *port)
ofs = baseAddr + DynPage_addr + bufhead + head; ofs = baseAddr + DynPage_addr + bufhead + head;
len = (tail >= head) ? (tail - head) : len = (tail >= head) ? (tail - head) :
(rx_mask + 1 - head); (rx_mask + 1 - head);
len = tty_prepare_flip_string(tty, &dst, len = tty_prepare_flip_string(&port->port, &dst,
min(len, count)); min(len, count));
memcpy_fromio(dst, ofs, len); memcpy_fromio(dst, ofs, len);
head = (head + len) & rx_mask; head = (head + len) & rx_mask;
@ -1978,7 +1978,7 @@ static int MoxaPortReadData(struct moxa_port *port)
while (count > 0) { while (count > 0) {
writew(pageno, baseAddr + Control_reg); writew(pageno, baseAddr + Control_reg);
ofs = baseAddr + DynPage_addr + pageofs; ofs = baseAddr + DynPage_addr + pageofs;
len = tty_prepare_flip_string(tty, &dst, len = tty_prepare_flip_string(&port->port, &dst,
min(Page_size - pageofs, count)); min(Page_size - pageofs, count));
memcpy_fromio(dst, ofs, len); memcpy_fromio(dst, ofs, len);

View File

@ -1264,7 +1264,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
(new_serial.flags & ASYNC_FLAGS)); (new_serial.flags & ASYNC_FLAGS));
port->close_delay = new_serial.close_delay * HZ / 100; port->close_delay = new_serial.close_delay * HZ / 100;
port->closing_wait = new_serial.closing_wait * HZ / 100; port->closing_wait = new_serial.closing_wait * HZ / 100;
tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST && if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
(new_serial.baud_base != info->baud_base || (new_serial.baud_base != info->baud_base ||
new_serial.custom_divisor != new_serial.custom_divisor !=
@ -2079,7 +2079,7 @@ static void mxser_receive_chars(struct tty_struct *tty,
} }
while (gdl--) { while (gdl--) {
ch = inb(port->ioaddr + UART_RX); ch = inb(port->ioaddr + UART_RX);
tty_insert_flip_char(tty, ch, 0); tty_insert_flip_char(&port->port, ch, 0);
cnt++; cnt++;
} }
goto end_intr; goto end_intr;
@ -2118,7 +2118,7 @@ intr_old:
} else } else
flag = TTY_BREAK; flag = TTY_BREAK;
} }
tty_insert_flip_char(tty, ch, flag); tty_insert_flip_char(&port->port, ch, flag);
cnt++; cnt++;
if (cnt >= recv_room) { if (cnt >= recv_room) {
if (!port->ldisc_stop_rx) if (!port->ldisc_stop_rx)
@ -2145,7 +2145,7 @@ end_intr:
* recursive locking. * recursive locking.
*/ */
spin_unlock(&port->slock); spin_unlock(&port->slock);
tty_flip_buffer_push(tty); tty_flip_buffer_push(&port->port);
spin_lock(&port->slock); spin_lock(&port->slock);
} }
@ -2364,7 +2364,6 @@ static void mxser_release_vector(struct mxser_board *brd)
static void mxser_release_ISA_res(struct mxser_board *brd) static void mxser_release_ISA_res(struct mxser_board *brd)
{ {
free_irq(brd->irq, brd);
release_region(brd->ports[0].ioaddr, 8 * brd->info->nports); release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
mxser_release_vector(brd); mxser_release_vector(brd);
} }
@ -2430,6 +2429,7 @@ static void mxser_board_remove(struct mxser_board *brd)
tty_unregister_device(mxvar_sdriver, brd->idx + i); tty_unregister_device(mxvar_sdriver, brd->idx + i);
tty_port_destroy(&brd->ports[i].port); tty_port_destroy(&brd->ports[i].port);
} }
free_irq(brd->irq, brd);
} }
static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd) static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
@ -2554,6 +2554,7 @@ static int mxser_probe(struct pci_dev *pdev,
struct mxser_board *brd; struct mxser_board *brd;
unsigned int i, j; unsigned int i, j;
unsigned long ioaddress; unsigned long ioaddress;
struct device *tty_dev;
int retval = -EINVAL; int retval = -EINVAL;
for (i = 0; i < MXSER_BOARDS; i++) for (i = 0; i < MXSER_BOARDS; i++)
@ -2637,13 +2638,25 @@ static int mxser_probe(struct pci_dev *pdev,
if (retval) if (retval)
goto err_rel3; goto err_rel3;
for (i = 0; i < brd->info->nports; i++) for (i = 0; i < brd->info->nports; i++) {
tty_port_register_device(&brd->ports[i].port, mxvar_sdriver, tty_dev = tty_port_register_device(&brd->ports[i].port,
brd->idx + i, &pdev->dev); mxvar_sdriver, brd->idx + i, &pdev->dev);
if (IS_ERR(tty_dev)) {
retval = PTR_ERR(tty_dev);
for (i--; i >= 0; i--)
tty_unregister_device(mxvar_sdriver,
brd->idx + i);
goto err_relbrd;
}
}
pci_set_drvdata(pdev, brd); pci_set_drvdata(pdev, brd);
return 0; return 0;
err_relbrd:
for (i = 0; i < brd->info->nports; i++)
tty_port_destroy(&brd->ports[i].port);
free_irq(brd->irq, brd);
err_rel3: err_rel3:
pci_release_region(pdev, 3); pci_release_region(pdev, 3);
err_zero: err_zero:
@ -2665,7 +2678,6 @@ static void mxser_remove(struct pci_dev *pdev)
mxser_board_remove(brd); mxser_board_remove(brd);
free_irq(pdev->irq, brd);
pci_release_region(pdev, 2); pci_release_region(pdev, 2);
pci_release_region(pdev, 3); pci_release_region(pdev, 3);
pci_disable_device(pdev); pci_disable_device(pdev);
@ -2683,6 +2695,7 @@ static struct pci_driver mxser_driver = {
static int __init mxser_module_init(void) static int __init mxser_module_init(void)
{ {
struct mxser_board *brd; struct mxser_board *brd;
struct device *tty_dev;
unsigned int b, i, m; unsigned int b, i, m;
int retval; int retval;
@ -2728,14 +2741,29 @@ static int __init mxser_module_init(void)
/* mxser_initbrd will hook ISR. */ /* mxser_initbrd will hook ISR. */
if (mxser_initbrd(brd, NULL) < 0) { if (mxser_initbrd(brd, NULL) < 0) {
mxser_release_ISA_res(brd);
brd->info = NULL; brd->info = NULL;
continue; continue;
} }
brd->idx = m * MXSER_PORTS_PER_BOARD; brd->idx = m * MXSER_PORTS_PER_BOARD;
for (i = 0; i < brd->info->nports; i++) for (i = 0; i < brd->info->nports; i++) {
tty_port_register_device(&brd->ports[i].port, tty_dev = tty_port_register_device(&brd->ports[i].port,
mxvar_sdriver, brd->idx + i, NULL); mxvar_sdriver, brd->idx + i, NULL);
if (IS_ERR(tty_dev)) {
for (i--; i >= 0; i--)
tty_unregister_device(mxvar_sdriver,
brd->idx + i);
for (i = 0; i < brd->info->nports; i++)
tty_port_destroy(&brd->ports[i].port);
free_irq(brd->irq, brd);
mxser_release_ISA_res(brd);
brd->info = NULL;
break;
}
}
if (brd->info == NULL)
continue;
m++; m++;
} }

View File

@ -1067,9 +1067,9 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD)) if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD))
if (!(tty->termios.c_cflag & CLOCAL)) if (!(tty->termios.c_cflag & CLOCAL))
tty_hangup(tty); tty_hangup(tty);
if (brk & 0x01)
tty_insert_flip_char(tty, 0, TTY_BREAK);
} }
if (brk & 0x01)
tty_insert_flip_char(&dlci->port, 0, TTY_BREAK);
dlci->modem_rx = mlines; dlci->modem_rx = mlines;
} }
@ -1137,7 +1137,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen) static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen)
{ {
struct tty_struct *tty; struct tty_port *port;
unsigned int addr = 0 ; unsigned int addr = 0 ;
u8 bits; u8 bits;
int len = clen; int len = clen;
@ -1160,19 +1160,18 @@ static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen)
bits = *dp; bits = *dp;
if ((bits & 1) == 0) if ((bits & 1) == 0)
return; return;
/* See if we have an uplink tty */
tty = tty_port_tty_get(&gsm->dlci[addr]->port);
if (tty) { port = &gsm->dlci[addr]->port;
if (bits & 2)
tty_insert_flip_char(tty, 0, TTY_OVERRUN); if (bits & 2)
if (bits & 4) tty_insert_flip_char(port, 0, TTY_OVERRUN);
tty_insert_flip_char(tty, 0, TTY_PARITY); if (bits & 4)
if (bits & 8) tty_insert_flip_char(port, 0, TTY_PARITY);
tty_insert_flip_char(tty, 0, TTY_FRAME); if (bits & 8)
tty_flip_buffer_push(tty); tty_insert_flip_char(port, 0, TTY_FRAME);
tty_kref_put(tty);
} tty_flip_buffer_push(port);
gsm_control_reply(gsm, CMD_RLS, data, clen); gsm_control_reply(gsm, CMD_RLS, data, clen);
} }
@ -1545,36 +1544,37 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int clen)
{ {
/* krefs .. */ /* krefs .. */
struct tty_port *port = &dlci->port; struct tty_port *port = &dlci->port;
struct tty_struct *tty = tty_port_tty_get(port); struct tty_struct *tty;
unsigned int modem = 0; unsigned int modem = 0;
int len = clen; int len = clen;
if (debug & 16) if (debug & 16)
pr_debug("%d bytes for tty %p\n", len, tty); pr_debug("%d bytes for tty\n", len);
if (tty) { switch (dlci->adaption) {
switch (dlci->adaption) { /* Unsupported types */
/* Unsupported types */ /* Packetised interruptible data */
/* Packetised interruptible data */ case 4:
case 4: break;
break; /* Packetised uininterruptible voice/data */
/* Packetised uininterruptible voice/data */ case 3:
case 3: break;
break; /* Asynchronous serial with line state in each frame */
/* Asynchronous serial with line state in each frame */ case 2:
case 2: while (gsm_read_ea(&modem, *data++) == 0) {
while (gsm_read_ea(&modem, *data++) == 0) { len--;
len--; if (len == 0)
if (len == 0) return;
return;
}
gsm_process_modem(tty, dlci, modem, clen);
/* Line state will go via DLCI 0 controls only */
case 1:
default:
tty_insert_flip_string(tty, data, len);
tty_flip_buffer_push(tty);
} }
tty_kref_put(tty); tty = tty_port_tty_get(port);
if (tty) {
gsm_process_modem(tty, dlci, modem, clen);
tty_kref_put(tty);
}
/* Line state will go via DLCI 0 controls only */
case 1:
default:
tty_insert_flip_string(port, data, len);
tty_flip_buffer_push(port);
} }
} }
@ -1689,6 +1689,8 @@ static inline void dlci_put(struct gsm_dlci *dlci)
tty_port_put(&dlci->port); tty_port_put(&dlci->port);
} }
static void gsm_destroy_network(struct gsm_dlci *dlci);
/** /**
* gsm_dlci_release - release DLCI * gsm_dlci_release - release DLCI
* @dlci: DLCI to destroy * @dlci: DLCI to destroy
@ -1702,9 +1704,19 @@ static void gsm_dlci_release(struct gsm_dlci *dlci)
{ {
struct tty_struct *tty = tty_port_tty_get(&dlci->port); struct tty_struct *tty = tty_port_tty_get(&dlci->port);
if (tty) { if (tty) {
mutex_lock(&dlci->mutex);
gsm_destroy_network(dlci);
mutex_unlock(&dlci->mutex);
/* tty_vhangup needs the tty_lock, so unlock and
relock after doing the hangup. */
tty_unlock(tty);
tty_vhangup(tty); tty_vhangup(tty);
tty_lock(tty);
tty_port_tty_set(&dlci->port, NULL);
tty_kref_put(tty); tty_kref_put(tty);
} }
dlci->state = DLCI_CLOSED;
dlci_put(dlci); dlci_put(dlci);
} }
@ -2947,6 +2959,8 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)
if (dlci == NULL) if (dlci == NULL)
return; return;
if (dlci->state == DLCI_CLOSED)
return;
mutex_lock(&dlci->mutex); mutex_lock(&dlci->mutex);
gsm_destroy_network(dlci); gsm_destroy_network(dlci);
mutex_unlock(&dlci->mutex); mutex_unlock(&dlci->mutex);
@ -2965,6 +2979,8 @@ out:
static void gsmtty_hangup(struct tty_struct *tty) static void gsmtty_hangup(struct tty_struct *tty)
{ {
struct gsm_dlci *dlci = tty->driver_data; struct gsm_dlci *dlci = tty->driver_data;
if (dlci->state == DLCI_CLOSED)
return;
tty_port_hangup(&dlci->port); tty_port_hangup(&dlci->port);
gsm_dlci_begin_close(dlci); gsm_dlci_begin_close(dlci);
} }
@ -2972,9 +2988,12 @@ static void gsmtty_hangup(struct tty_struct *tty)
static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf, static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf,
int len) int len)
{ {
int sent;
struct gsm_dlci *dlci = tty->driver_data; struct gsm_dlci *dlci = tty->driver_data;
if (dlci->state == DLCI_CLOSED)
return -EINVAL;
/* Stuff the bytes into the fifo queue */ /* Stuff the bytes into the fifo queue */
int sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock); sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock);
/* Need to kick the channel */ /* Need to kick the channel */
gsm_dlci_data_kick(dlci); gsm_dlci_data_kick(dlci);
return sent; return sent;
@ -2983,18 +3002,24 @@ static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf,
static int gsmtty_write_room(struct tty_struct *tty) static int gsmtty_write_room(struct tty_struct *tty)
{ {
struct gsm_dlci *dlci = tty->driver_data; struct gsm_dlci *dlci = tty->driver_data;
if (dlci->state == DLCI_CLOSED)
return -EINVAL;
return TX_SIZE - kfifo_len(dlci->fifo); return TX_SIZE - kfifo_len(dlci->fifo);
} }
static int gsmtty_chars_in_buffer(struct tty_struct *tty) static int gsmtty_chars_in_buffer(struct tty_struct *tty)
{ {
struct gsm_dlci *dlci = tty->driver_data; struct gsm_dlci *dlci = tty->driver_data;
if (dlci->state == DLCI_CLOSED)
return -EINVAL;
return kfifo_len(dlci->fifo); return kfifo_len(dlci->fifo);
} }
static void gsmtty_flush_buffer(struct tty_struct *tty) static void gsmtty_flush_buffer(struct tty_struct *tty)
{ {
struct gsm_dlci *dlci = tty->driver_data; struct gsm_dlci *dlci = tty->driver_data;
if (dlci->state == DLCI_CLOSED)
return;
/* Caution needed: If we implement reliable transport classes /* Caution needed: If we implement reliable transport classes
then the data being transmitted can't simply be junked once then the data being transmitted can't simply be junked once
it has first hit the stack. Until then we can just blow it it has first hit the stack. Until then we can just blow it
@ -3013,6 +3038,8 @@ static void gsmtty_wait_until_sent(struct tty_struct *tty, int timeout)
static int gsmtty_tiocmget(struct tty_struct *tty) static int gsmtty_tiocmget(struct tty_struct *tty)
{ {
struct gsm_dlci *dlci = tty->driver_data; struct gsm_dlci *dlci = tty->driver_data;
if (dlci->state == DLCI_CLOSED)
return -EINVAL;
return dlci->modem_rx; return dlci->modem_rx;
} }
@ -3022,6 +3049,8 @@ static int gsmtty_tiocmset(struct tty_struct *tty,
struct gsm_dlci *dlci = tty->driver_data; struct gsm_dlci *dlci = tty->driver_data;
unsigned int modem_tx = dlci->modem_tx; unsigned int modem_tx = dlci->modem_tx;
if (dlci->state == DLCI_CLOSED)
return -EINVAL;
modem_tx &= ~clear; modem_tx &= ~clear;
modem_tx |= set; modem_tx |= set;
@ -3040,6 +3069,8 @@ static int gsmtty_ioctl(struct tty_struct *tty,
struct gsm_netconfig nc; struct gsm_netconfig nc;
int index; int index;
if (dlci->state == DLCI_CLOSED)
return -EINVAL;
switch (cmd) { switch (cmd) {
case GSMIOC_ENABLE_NET: case GSMIOC_ENABLE_NET:
if (copy_from_user(&nc, (void __user *)arg, sizeof(nc))) if (copy_from_user(&nc, (void __user *)arg, sizeof(nc)))
@ -3066,6 +3097,9 @@ static int gsmtty_ioctl(struct tty_struct *tty,
static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old) static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
{ {
struct gsm_dlci *dlci = tty->driver_data;
if (dlci->state == DLCI_CLOSED)
return;
/* For the moment its fixed. In actual fact the speed information /* For the moment its fixed. In actual fact the speed information
for the virtual channel can be propogated in both directions by for the virtual channel can be propogated in both directions by
the RPN control message. This however rapidly gets nasty as we the RPN control message. This however rapidly gets nasty as we
@ -3077,6 +3111,8 @@ static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
static void gsmtty_throttle(struct tty_struct *tty) static void gsmtty_throttle(struct tty_struct *tty)
{ {
struct gsm_dlci *dlci = tty->driver_data; struct gsm_dlci *dlci = tty->driver_data;
if (dlci->state == DLCI_CLOSED)
return;
if (tty->termios.c_cflag & CRTSCTS) if (tty->termios.c_cflag & CRTSCTS)
dlci->modem_tx &= ~TIOCM_DTR; dlci->modem_tx &= ~TIOCM_DTR;
dlci->throttled = 1; dlci->throttled = 1;
@ -3087,6 +3123,8 @@ static void gsmtty_throttle(struct tty_struct *tty)
static void gsmtty_unthrottle(struct tty_struct *tty) static void gsmtty_unthrottle(struct tty_struct *tty)
{ {
struct gsm_dlci *dlci = tty->driver_data; struct gsm_dlci *dlci = tty->driver_data;
if (dlci->state == DLCI_CLOSED)
return;
if (tty->termios.c_cflag & CRTSCTS) if (tty->termios.c_cflag & CRTSCTS)
dlci->modem_tx |= TIOCM_DTR; dlci->modem_tx |= TIOCM_DTR;
dlci->throttled = 0; dlci->throttled = 0;
@ -3098,6 +3136,8 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
{ {
struct gsm_dlci *dlci = tty->driver_data; struct gsm_dlci *dlci = tty->driver_data;
int encode = 0; /* Off */ int encode = 0; /* Off */
if (dlci->state == DLCI_CLOSED)
return -EINVAL;
if (state == -1) /* "On indefinitely" - we can't encode this if (state == -1) /* "On indefinitely" - we can't encode this
properly */ properly */

View File

@ -49,6 +49,7 @@
#include <linux/file.h> #include <linux/file.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/ratelimit.h>
/* number of characters left in xmit buffer before select has we have room */ /* number of characters left in xmit buffer before select has we have room */
@ -100,7 +101,7 @@ struct n_tty_data {
struct mutex atomic_read_lock; struct mutex atomic_read_lock;
struct mutex output_lock; struct mutex output_lock;
struct mutex echo_lock; struct mutex echo_lock;
spinlock_t read_lock; raw_spinlock_t read_lock;
}; };
static inline int tty_put_user(struct tty_struct *tty, unsigned char x, static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
@ -182,9 +183,9 @@ static void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
* The problem of stomping on the buffers ends here. * The problem of stomping on the buffers ends here.
* Why didn't anyone see this one coming? --AJK * Why didn't anyone see this one coming? --AJK
*/ */
spin_lock_irqsave(&ldata->read_lock, flags); raw_spin_lock_irqsave(&ldata->read_lock, flags);
put_tty_queue_nolock(c, ldata); put_tty_queue_nolock(c, ldata);
spin_unlock_irqrestore(&ldata->read_lock, flags); raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
} }
/** /**
@ -218,9 +219,9 @@ static void reset_buffer_flags(struct tty_struct *tty)
struct n_tty_data *ldata = tty->disc_data; struct n_tty_data *ldata = tty->disc_data;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&ldata->read_lock, flags); raw_spin_lock_irqsave(&ldata->read_lock, flags);
ldata->read_head = ldata->read_tail = ldata->read_cnt = 0; ldata->read_head = ldata->read_tail = ldata->read_cnt = 0;
spin_unlock_irqrestore(&ldata->read_lock, flags); raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
mutex_lock(&ldata->echo_lock); mutex_lock(&ldata->echo_lock);
ldata->echo_pos = ldata->echo_cnt = ldata->echo_overrun = 0; ldata->echo_pos = ldata->echo_cnt = ldata->echo_overrun = 0;
@ -276,7 +277,7 @@ static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
unsigned long flags; unsigned long flags;
ssize_t n = 0; ssize_t n = 0;
spin_lock_irqsave(&ldata->read_lock, flags); raw_spin_lock_irqsave(&ldata->read_lock, flags);
if (!ldata->icanon) { if (!ldata->icanon) {
n = ldata->read_cnt; n = ldata->read_cnt;
} else if (ldata->canon_data) { } else if (ldata->canon_data) {
@ -284,7 +285,7 @@ static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
ldata->canon_head - ldata->read_tail : ldata->canon_head - ldata->read_tail :
ldata->canon_head + (N_TTY_BUF_SIZE - ldata->read_tail); ldata->canon_head + (N_TTY_BUF_SIZE - ldata->read_tail);
} }
spin_unlock_irqrestore(&ldata->read_lock, flags); raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
return n; return n;
} }
@ -915,19 +916,19 @@ static void eraser(unsigned char c, struct tty_struct *tty)
kill_type = WERASE; kill_type = WERASE;
else { else {
if (!L_ECHO(tty)) { if (!L_ECHO(tty)) {
spin_lock_irqsave(&ldata->read_lock, flags); raw_spin_lock_irqsave(&ldata->read_lock, flags);
ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) & ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) &
(N_TTY_BUF_SIZE - 1)); (N_TTY_BUF_SIZE - 1));
ldata->read_head = ldata->canon_head; ldata->read_head = ldata->canon_head;
spin_unlock_irqrestore(&ldata->read_lock, flags); raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
return; return;
} }
if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) { if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
spin_lock_irqsave(&ldata->read_lock, flags); raw_spin_lock_irqsave(&ldata->read_lock, flags);
ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) & ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) &
(N_TTY_BUF_SIZE - 1)); (N_TTY_BUF_SIZE - 1));
ldata->read_head = ldata->canon_head; ldata->read_head = ldata->canon_head;
spin_unlock_irqrestore(&ldata->read_lock, flags); raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
finish_erasing(ldata); finish_erasing(ldata);
echo_char(KILL_CHAR(tty), tty); echo_char(KILL_CHAR(tty), tty);
/* Add a newline if ECHOK is on and ECHOKE is off. */ /* Add a newline if ECHOK is on and ECHOKE is off. */
@ -961,10 +962,10 @@ static void eraser(unsigned char c, struct tty_struct *tty)
break; break;
} }
cnt = (ldata->read_head - head) & (N_TTY_BUF_SIZE-1); cnt = (ldata->read_head - head) & (N_TTY_BUF_SIZE-1);
spin_lock_irqsave(&ldata->read_lock, flags); raw_spin_lock_irqsave(&ldata->read_lock, flags);
ldata->read_head = head; ldata->read_head = head;
ldata->read_cnt -= cnt; ldata->read_cnt -= cnt;
spin_unlock_irqrestore(&ldata->read_lock, flags); raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
if (L_ECHO(tty)) { if (L_ECHO(tty)) {
if (L_ECHOPRT(tty)) { if (L_ECHOPRT(tty)) {
if (!ldata->erasing) { if (!ldata->erasing) {
@ -1344,12 +1345,12 @@ send_signal:
put_tty_queue(c, ldata); put_tty_queue(c, ldata);
handle_newline: handle_newline:
spin_lock_irqsave(&ldata->read_lock, flags); raw_spin_lock_irqsave(&ldata->read_lock, flags);
set_bit(ldata->read_head, ldata->read_flags); set_bit(ldata->read_head, ldata->read_flags);
put_tty_queue_nolock(c, ldata); put_tty_queue_nolock(c, ldata);
ldata->canon_head = ldata->read_head; ldata->canon_head = ldata->read_head;
ldata->canon_data++; ldata->canon_data++;
spin_unlock_irqrestore(&ldata->read_lock, flags); raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
kill_fasync(&tty->fasync, SIGIO, POLL_IN); kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait)) if (waitqueue_active(&tty->read_wait))
wake_up_interruptible(&tty->read_wait); wake_up_interruptible(&tty->read_wait);
@ -1423,7 +1424,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
unsigned long cpuflags; unsigned long cpuflags;
if (ldata->real_raw) { if (ldata->real_raw) {
spin_lock_irqsave(&ldata->read_lock, cpuflags); raw_spin_lock_irqsave(&ldata->read_lock, cpuflags);
i = min(N_TTY_BUF_SIZE - ldata->read_cnt, i = min(N_TTY_BUF_SIZE - ldata->read_cnt,
N_TTY_BUF_SIZE - ldata->read_head); N_TTY_BUF_SIZE - ldata->read_head);
i = min(count, i); i = min(count, i);
@ -1439,7 +1440,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
memcpy(ldata->read_buf + ldata->read_head, cp, i); memcpy(ldata->read_buf + ldata->read_head, cp, i);
ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1); ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1);
ldata->read_cnt += i; ldata->read_cnt += i;
spin_unlock_irqrestore(&ldata->read_lock, cpuflags); raw_spin_unlock_irqrestore(&ldata->read_lock, cpuflags);
} else { } else {
for (i = count, p = cp, f = fp; i; i--, p++) { for (i = count, p = cp, f = fp; i; i--, p++) {
if (f) if (f)
@ -1635,7 +1636,7 @@ static int n_tty_open(struct tty_struct *tty)
mutex_init(&ldata->atomic_read_lock); mutex_init(&ldata->atomic_read_lock);
mutex_init(&ldata->output_lock); mutex_init(&ldata->output_lock);
mutex_init(&ldata->echo_lock); mutex_init(&ldata->echo_lock);
spin_lock_init(&ldata->read_lock); raw_spin_lock_init(&ldata->read_lock);
/* These are ugly. Currently a malloc failure here can panic */ /* These are ugly. Currently a malloc failure here can panic */
ldata->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL); ldata->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
@ -1703,10 +1704,10 @@ static int copy_from_read_buf(struct tty_struct *tty,
bool is_eof; bool is_eof;
retval = 0; retval = 0;
spin_lock_irqsave(&ldata->read_lock, flags); raw_spin_lock_irqsave(&ldata->read_lock, flags);
n = min(ldata->read_cnt, N_TTY_BUF_SIZE - ldata->read_tail); n = min(ldata->read_cnt, N_TTY_BUF_SIZE - ldata->read_tail);
n = min(*nr, n); n = min(*nr, n);
spin_unlock_irqrestore(&ldata->read_lock, flags); raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
if (n) { if (n) {
retval = copy_to_user(*b, &ldata->read_buf[ldata->read_tail], n); retval = copy_to_user(*b, &ldata->read_buf[ldata->read_tail], n);
n -= retval; n -= retval;
@ -1714,13 +1715,13 @@ static int copy_from_read_buf(struct tty_struct *tty,
ldata->read_buf[ldata->read_tail] == EOF_CHAR(tty); ldata->read_buf[ldata->read_tail] == EOF_CHAR(tty);
tty_audit_add_data(tty, &ldata->read_buf[ldata->read_tail], n, tty_audit_add_data(tty, &ldata->read_buf[ldata->read_tail], n,
ldata->icanon); ldata->icanon);
spin_lock_irqsave(&ldata->read_lock, flags); raw_spin_lock_irqsave(&ldata->read_lock, flags);
ldata->read_tail = (ldata->read_tail + n) & (N_TTY_BUF_SIZE-1); ldata->read_tail = (ldata->read_tail + n) & (N_TTY_BUF_SIZE-1);
ldata->read_cnt -= n; ldata->read_cnt -= n;
/* Turn single EOF into zero-length read */ /* Turn single EOF into zero-length read */
if (L_EXTPROC(tty) && ldata->icanon && is_eof && !ldata->read_cnt) if (L_EXTPROC(tty) && ldata->icanon && is_eof && !ldata->read_cnt)
n = 0; n = 0;
spin_unlock_irqrestore(&ldata->read_lock, flags); raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
*b += n; *b += n;
*nr -= n; *nr -= n;
} }
@ -1900,7 +1901,7 @@ do_it_again:
if (ldata->icanon && !L_EXTPROC(tty)) { if (ldata->icanon && !L_EXTPROC(tty)) {
/* N.B. avoid overrun if nr == 0 */ /* N.B. avoid overrun if nr == 0 */
spin_lock_irqsave(&ldata->read_lock, flags); raw_spin_lock_irqsave(&ldata->read_lock, flags);
while (nr && ldata->read_cnt) { while (nr && ldata->read_cnt) {
int eol; int eol;
@ -1918,25 +1919,25 @@ do_it_again:
if (--ldata->canon_data < 0) if (--ldata->canon_data < 0)
ldata->canon_data = 0; ldata->canon_data = 0;
} }
spin_unlock_irqrestore(&ldata->read_lock, flags); raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
if (!eol || (c != __DISABLED_CHAR)) { if (!eol || (c != __DISABLED_CHAR)) {
if (tty_put_user(tty, c, b++)) { if (tty_put_user(tty, c, b++)) {
retval = -EFAULT; retval = -EFAULT;
b--; b--;
spin_lock_irqsave(&ldata->read_lock, flags); raw_spin_lock_irqsave(&ldata->read_lock, flags);
break; break;
} }
nr--; nr--;
} }
if (eol) { if (eol) {
tty_audit_push(tty); tty_audit_push(tty);
spin_lock_irqsave(&ldata->read_lock, flags); raw_spin_lock_irqsave(&ldata->read_lock, flags);
break; break;
} }
spin_lock_irqsave(&ldata->read_lock, flags); raw_spin_lock_irqsave(&ldata->read_lock, flags);
} }
spin_unlock_irqrestore(&ldata->read_lock, flags); raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
if (retval) if (retval)
break; break;
} else { } else {
@ -2188,7 +2189,7 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = {
* n_tty_inherit_ops - inherit N_TTY methods * n_tty_inherit_ops - inherit N_TTY methods
* @ops: struct tty_ldisc_ops where to save N_TTY methods * @ops: struct tty_ldisc_ops where to save N_TTY methods
* *
* Used by a generic struct tty_ldisc_ops to easily inherit N_TTY * Enables a 'subclass' line discipline to 'inherit' N_TTY
* methods. * methods.
*/ */

Some files were not shown because too many files have changed in this diff Show More