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:
commit
21eaab6d19
|
@ -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";
|
||||||
|
};
|
|
@ -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;
|
||||||
|
};
|
|
@ -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>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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/
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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
Loading…
Reference in New Issue