forked from Minki/linux
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";
|
||||
};
|
26
Documentation/devicetree/bindings/tty/serial/arc-uart.txt
Normal file
26
Documentation/devicetree/bindings/tty/serial/arc-uart.txt
Normal file
@ -0,0 +1,26 @@
|
||||
* Synopsys ARC UART : Non standard UART used in some of the ARC FPGA boards
|
||||
|
||||
Required properties:
|
||||
- compatible : "snps,arc-uart"
|
||||
- reg : offset and length of the register set for the device.
|
||||
- interrupts : device interrupt
|
||||
- clock-frequency : the input clock frequency for the UART
|
||||
- current-speed : baud rate for UART
|
||||
|
||||
e.g.
|
||||
|
||||
arcuart0: serial@c0fc1000 {
|
||||
compatible = "snps,arc-uart";
|
||||
reg = <0xc0fc1000 0x100>;
|
||||
interrupts = <5>;
|
||||
clock-frequency = <80000000>;
|
||||
current-speed = <115200>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
Note: Each port should have an alias correctly numbered in "aliases" node.
|
||||
|
||||
e.g.
|
||||
aliases {
|
||||
serial0 = &arcuart0;
|
||||
};
|
@ -5,10 +5,16 @@ Required properties:
|
||||
- reg : Address and length of the register set
|
||||
- interrupts : Should contain uart interrupt
|
||||
|
||||
Optional properties:
|
||||
- location : Decides the location of the USART I/O pins.
|
||||
Allowed range : [0 .. 5]
|
||||
Default: 0
|
||||
|
||||
Example:
|
||||
|
||||
uart@0x4000c400 {
|
||||
compatible = "efm32,uart";
|
||||
reg = <0x4000c400 0x400>;
|
||||
interrupts = <15>;
|
||||
location = <0>;
|
||||
};
|
||||
|
@ -133,6 +133,16 @@ hardware.
|
||||
Interrupts: locally disabled.
|
||||
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 receiving characters; the port is in the process of
|
||||
being closed.
|
||||
@ -242,9 +252,8 @@ hardware.
|
||||
|
||||
pm(port,state,oldstate)
|
||||
Perform any power management related activities on the specified
|
||||
port. State indicates the new state (defined by ACPI D0-D3),
|
||||
oldstate indicates the previous state. Essentially, D0 means
|
||||
fully on, D3 means powered down.
|
||||
port. State indicates the new state (defined by
|
||||
enum uart_pm_state), oldstate indicates the previous state.
|
||||
|
||||
This function should not be used to grab any resources.
|
||||
|
||||
@ -255,6 +264,10 @@ hardware.
|
||||
Locking: none.
|
||||
Interrupts: caller dependent.
|
||||
|
||||
set_wake(port,state)
|
||||
Enable/disable power management wakeup on serial activity. Not
|
||||
currently implemented.
|
||||
|
||||
type(port)
|
||||
Return a pointer to a string constant describing the specified
|
||||
port, or return NULL, in which case the string 'unknown' is
|
||||
@ -307,6 +320,31 @@ hardware.
|
||||
Locking: none.
|
||||
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
|
||||
---------------
|
||||
|
||||
|
@ -124,6 +124,7 @@ choice
|
||||
|
||||
config ALPHA_GENERIC
|
||||
bool "Generic"
|
||||
depends on TTY
|
||||
help
|
||||
A generic kernel will run on all supported Alpha hardware.
|
||||
|
||||
@ -490,6 +491,7 @@ config VGA_HOSE
|
||||
|
||||
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
|
||||
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
|
||||
---help---
|
||||
There are two different types of booting firmware on Alphas: SRM,
|
||||
|
@ -44,7 +44,7 @@ typedef union _srmcons_result {
|
||||
|
||||
/* called with callback_lock held */
|
||||
static int
|
||||
srmcons_do_receive_chars(struct tty_struct *tty)
|
||||
srmcons_do_receive_chars(struct tty_port *port)
|
||||
{
|
||||
srmcons_result result;
|
||||
int count = 0, loops = 0;
|
||||
@ -52,13 +52,13 @@ srmcons_do_receive_chars(struct tty_struct *tty)
|
||||
do {
|
||||
result.as_long = callback_getc(0);
|
||||
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++;
|
||||
}
|
||||
} while((result.bits.status & 1) && (++loops < 10));
|
||||
|
||||
if (count)
|
||||
tty_schedule_flip(tty);
|
||||
tty_schedule_flip(port);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -73,7 +73,7 @@ srmcons_receive_chars(unsigned long data)
|
||||
|
||||
local_irq_save(flags);
|
||||
if (spin_trylock(&srmcons_callback_lock)) {
|
||||
if (!srmcons_do_receive_chars(port->tty))
|
||||
if (!srmcons_do_receive_chars(port))
|
||||
incr = 100;
|
||||
spin_unlock(&srmcons_callback_lock);
|
||||
}
|
||||
@ -88,7 +88,7 @@ srmcons_receive_chars(unsigned long data)
|
||||
|
||||
/* called with callback_lock held */
|
||||
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";
|
||||
long c, remaining = count;
|
||||
@ -113,10 +113,10 @@ srmcons_do_write(struct tty_struct *tty, const char *buf, int count)
|
||||
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)
|
||||
srmcons_do_receive_chars(tty);
|
||||
if (port)
|
||||
srmcons_do_receive_chars(port);
|
||||
}
|
||||
|
||||
while (need_cr) {
|
||||
@ -135,7 +135,7 @@ srmcons_write(struct tty_struct *tty,
|
||||
unsigned long 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);
|
||||
|
||||
return count;
|
||||
|
@ -45,6 +45,38 @@
|
||||
compatible = "fixed-clock";
|
||||
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";
|
||||
reg = <0xd8200000 0x1040>;
|
||||
interrupts = <32>;
|
||||
clocks = <&ref24>;
|
||||
clocks = <&clkuart0>;
|
||||
};
|
||||
|
||||
uart@d82b0000 {
|
||||
compatible = "via,vt8500-uart";
|
||||
reg = <0xd82b0000 0x1040>;
|
||||
interrupts = <33>;
|
||||
clocks = <&ref24>;
|
||||
clocks = <&clkuart1>;
|
||||
};
|
||||
|
||||
uart@d8210000 {
|
||||
compatible = "via,vt8500-uart";
|
||||
reg = <0xd8210000 0x1040>;
|
||||
interrupts = <47>;
|
||||
clocks = <&ref24>;
|
||||
clocks = <&clkuart2>;
|
||||
};
|
||||
|
||||
uart@d82c0000 {
|
||||
compatible = "via,vt8500-uart";
|
||||
reg = <0xd82c0000 0x1040>;
|
||||
interrupts = <50>;
|
||||
clocks = <&ref24>;
|
||||
clocks = <&clkuart3>;
|
||||
};
|
||||
|
||||
rtc@d8100000 {
|
||||
|
@ -59,6 +59,54 @@
|
||||
compatible = "fixed-clock";
|
||||
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";
|
||||
reg = <0xd8200000 0x1040>;
|
||||
interrupts = <32>;
|
||||
clocks = <&ref24>;
|
||||
clocks = <&clkuart0>;
|
||||
};
|
||||
|
||||
uart@d82b0000 {
|
||||
compatible = "via,vt8500-uart";
|
||||
reg = <0xd82b0000 0x1040>;
|
||||
interrupts = <33>;
|
||||
clocks = <&ref24>;
|
||||
clocks = <&clkuart1>;
|
||||
};
|
||||
|
||||
uart@d8210000 {
|
||||
compatible = "via,vt8500-uart";
|
||||
reg = <0xd8210000 0x1040>;
|
||||
interrupts = <47>;
|
||||
clocks = <&ref24>;
|
||||
clocks = <&clkuart2>;
|
||||
};
|
||||
|
||||
uart@d82c0000 {
|
||||
compatible = "via,vt8500-uart";
|
||||
reg = <0xd82c0000 0x1040>;
|
||||
interrupts = <50>;
|
||||
clocks = <&ref24>;
|
||||
clocks = <&clkuart3>;
|
||||
};
|
||||
|
||||
uart@d8370000 {
|
||||
compatible = "via,vt8500-uart";
|
||||
reg = <0xd8370000 0x1040>;
|
||||
interrupts = <31>;
|
||||
clocks = <&ref24>;
|
||||
clocks = <&clkuart4>;
|
||||
};
|
||||
|
||||
uart@d8380000 {
|
||||
compatible = "via,vt8500-uart";
|
||||
reg = <0xd8380000 0x1040>;
|
||||
interrupts = <30>;
|
||||
clocks = <&ref24>;
|
||||
clocks = <&clkuart5>;
|
||||
};
|
||||
|
||||
rtc@d8100000 {
|
||||
|
@ -75,6 +75,22 @@
|
||||
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 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "via,vt8500-device-clock";
|
||||
@ -128,14 +144,14 @@
|
||||
compatible = "via,vt8500-uart";
|
||||
reg = <0xd8200000 0x1040>;
|
||||
interrupts = <32>;
|
||||
clocks = <&ref24>;
|
||||
clocks = <&clkuart0>;
|
||||
};
|
||||
|
||||
uart@d82b0000 {
|
||||
compatible = "via,vt8500-uart";
|
||||
reg = <0xd82b0000 0x1040>;
|
||||
interrupts = <33>;
|
||||
clocks = <&ref24>;
|
||||
clocks = <&clkuart1>;
|
||||
};
|
||||
|
||||
rtc@d8100000 {
|
||||
|
@ -44,14 +44,14 @@
|
||||
compatible = "xlnx,xuartps";
|
||||
reg = <0xE0000000 0x1000>;
|
||||
interrupts = <0 27 4>;
|
||||
clock = <50000000>;
|
||||
clocks = <&uart_clk 0>;
|
||||
};
|
||||
|
||||
uart1: uart@e0001000 {
|
||||
compatible = "xlnx,xuartps";
|
||||
reg = <0xE0001000 0x1000>;
|
||||
interrupts = <0 50 4>;
|
||||
clock = <50000000>;
|
||||
clocks = <&uart_clk 1>;
|
||||
};
|
||||
|
||||
slcr: slcr@f8000000 {
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/platform_data/sa11x0-serial.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/ucb1x00.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define __ASM_PLAT_ADC_H __FILE__
|
||||
|
||||
struct s3c_adc_client;
|
||||
struct platform_device;
|
||||
|
||||
extern int s3c_adc_start(struct s3c_adc_client *client,
|
||||
unsigned int channel, unsigned int nr_samples);
|
||||
|
@ -8,6 +8,7 @@ config HP_SIMETH
|
||||
|
||||
config HP_SIMSERIAL
|
||||
bool "Simulated serial driver support"
|
||||
depends on TTY
|
||||
|
||||
config HP_SIMSERIAL_CONSOLE
|
||||
bool "Console for HP simulator"
|
||||
|
@ -53,7 +53,7 @@ struct tty_driver *hp_simserial_driver;
|
||||
|
||||
static struct console *console;
|
||||
|
||||
static void receive_chars(struct tty_struct *tty)
|
||||
static void receive_chars(struct tty_port *port)
|
||||
{
|
||||
unsigned char ch;
|
||||
static unsigned char seen_esc = 0;
|
||||
@ -81,10 +81,10 @@ static void receive_chars(struct tty_struct *tty)
|
||||
}
|
||||
seen_esc = 0;
|
||||
|
||||
if (tty_insert_flip_char(tty, ch, TTY_NORMAL) == 0)
|
||||
if (tty_insert_flip_char(port, ch, TTY_NORMAL) == 0)
|
||||
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)
|
||||
{
|
||||
struct serial_state *info = dev_id;
|
||||
struct tty_struct *tty = tty_port_tty_get(&info->port);
|
||||
|
||||
if (!tty) {
|
||||
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);
|
||||
receive_chars(&info->port);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -435,7 +426,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
|
||||
struct tty_port *port = &info->port;
|
||||
|
||||
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)
|
||||
|
@ -41,7 +41,7 @@ config NFBLOCK
|
||||
|
||||
config NFCON
|
||||
tristate "NatFeat console driver"
|
||||
depends on NATFEAT
|
||||
depends on TTY && NATFEAT
|
||||
help
|
||||
Say Y to include support for the ARAnyM NatFeat console driver
|
||||
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 = {
|
||||
.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)
|
||||
{
|
||||
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;
|
||||
int count;
|
||||
u8 st, ch, push, status, overrun;
|
||||
@ -534,10 +534,10 @@ static void mn10300_serial_receive_interrupt(struct mn10300_serial_port *port)
|
||||
push = 0;
|
||||
|
||||
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 (!tty->low_latency)
|
||||
tty_flip_buffer_push(tty);
|
||||
if (!tport->low_latency)
|
||||
tty_flip_buffer_push(tport);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -545,8 +545,8 @@ try_again:
|
||||
/* pull chars out of the hat */
|
||||
ix = ACCESS_ONCE(port->rx_outp);
|
||||
if (CIRC_CNT(port->rx_inp, ix, MNSC_BUFFER_SIZE) == 0) {
|
||||
if (push && !tty->low_latency)
|
||||
tty_flip_buffer_push(tty);
|
||||
if (push && !tport->low_latency)
|
||||
tty_flip_buffer_push(tport);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -666,19 +666,19 @@ insert:
|
||||
else
|
||||
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
|
||||
* affect the current character
|
||||
*/
|
||||
if (overrun)
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
|
||||
|
||||
count--;
|
||||
if (count <= 0) {
|
||||
if (!tty->low_latency)
|
||||
tty_flip_buffer_push(tty);
|
||||
if (!tport->low_latency)
|
||||
tty_flip_buffer_push(tport);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ config PARISC
|
||||
select HAVE_MOD_ARCH_SPECIFIC
|
||||
select MODULES_USE_ELF_RELA
|
||||
select CLONE_BACKWARDS
|
||||
select TTY # Needed for pdc_cons.c
|
||||
|
||||
help
|
||||
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)
|
||||
{
|
||||
int data, count = 0;
|
||||
struct tty_struct *tty = tty_port_tty_get(&tty_port);
|
||||
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
while (1) {
|
||||
data = pdc_console_poll_key(NULL);
|
||||
if (data == -1)
|
||||
break;
|
||||
tty_insert_flip_char(tty, data & 0xFF, TTY_NORMAL);
|
||||
tty_insert_flip_char(&tty_port, data & 0xFF, TTY_NORMAL);
|
||||
count ++;
|
||||
}
|
||||
|
||||
if (count)
|
||||
tty_flip_buffer_push(tty);
|
||||
|
||||
tty_kref_put(tty);
|
||||
tty_flip_buffer_push(&tty_port);
|
||||
|
||||
if (pdc_cons.flags & CON_ENABLED)
|
||||
mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY);
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <linux/kgdb.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <asm/kdebug.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
@ -121,6 +121,7 @@ config DEBUG_COPY_FROM_USER
|
||||
def_bool n
|
||||
|
||||
config HVC_TILE
|
||||
depends on TTY
|
||||
select HVC_DRIVER
|
||||
def_bool y
|
||||
|
||||
|
@ -12,6 +12,7 @@ config UML
|
||||
select GENERIC_CPU_DEVICES
|
||||
select GENERIC_IO
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select TTY # Needed for line.c
|
||||
|
||||
config MMU
|
||||
bool
|
||||
|
@ -27,8 +27,7 @@ struct chan {
|
||||
void *data;
|
||||
};
|
||||
|
||||
extern void chan_interrupt(struct line *line,
|
||||
struct tty_struct *tty, int irq);
|
||||
extern void chan_interrupt(struct line *line, int irq);
|
||||
extern int parse_chan_pair(char *str, struct line *line, int device,
|
||||
const struct chan_opts *opts, char **error_out);
|
||||
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 */
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
struct line *line = container_of(work, struct line, task.work);
|
||||
struct tty_struct *tty = tty_port_tty_get(&line->port);
|
||||
|
||||
if (!line->throttled)
|
||||
chan_interrupt(line, tty, line->driver->read_irq);
|
||||
tty_kref_put(tty);
|
||||
chan_interrupt(line, line->driver->read_irq);
|
||||
}
|
||||
|
||||
int enable_chan(struct line *line)
|
||||
@ -552,8 +544,9 @@ int parse_chan_pair(char *str, struct line *line, int device,
|
||||
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;
|
||||
int err;
|
||||
char c;
|
||||
@ -562,21 +555,24 @@ void chan_interrupt(struct line *line, struct tty_struct *tty, int irq)
|
||||
goto out;
|
||||
|
||||
do {
|
||||
if (tty && !tty_buffer_request_room(tty, 1)) {
|
||||
if (!tty_buffer_request_room(port, 1)) {
|
||||
schedule_delayed_work(&line->task, 1);
|
||||
goto out;
|
||||
}
|
||||
err = chan->ops->read(chan->fd, &c, chan->data);
|
||||
if (err > 0)
|
||||
tty_receive_char(tty, c);
|
||||
tty_insert_flip_char(port, c, TTY_NORMAL);
|
||||
} while (err > 0);
|
||||
|
||||
if (err == 0)
|
||||
reactivate_fd(chan->fd, irq);
|
||||
if (err == -EIO) {
|
||||
if (chan->primary) {
|
||||
if (tty != NULL)
|
||||
struct tty_struct *tty = tty_port_tty_get(&line->port);
|
||||
if (tty != NULL) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
if (line->chan_out != chan)
|
||||
close_one_chan(line->chan_out, 1);
|
||||
}
|
||||
@ -585,6 +581,5 @@ void chan_interrupt(struct line *line, struct tty_struct *tty, int irq)
|
||||
return;
|
||||
}
|
||||
out:
|
||||
if (tty)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(port);
|
||||
}
|
||||
|
@ -19,11 +19,10 @@ static irqreturn_t line_interrupt(int irq, void *data)
|
||||
{
|
||||
struct chan *chan = data;
|
||||
struct line *line = chan->line;
|
||||
struct tty_struct *tty = tty_port_tty_get(&line->port);
|
||||
|
||||
if (line)
|
||||
chan_interrupt(line, tty, irq);
|
||||
tty_kref_put(tty);
|
||||
chan_interrupt(line, irq);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -234,7 +233,7 @@ void line_unthrottle(struct tty_struct *tty)
|
||||
struct line *line = tty->driver_data;
|
||||
|
||||
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
|
||||
|
@ -2,6 +2,7 @@ config LGUEST_GUEST
|
||||
bool "Lguest guest support"
|
||||
select PARAVIRT
|
||||
depends on X86_32
|
||||
select TTY
|
||||
select VIRTUALIZATION
|
||||
select VIRTIO
|
||||
select VIRTIO_CONSOLE
|
||||
|
@ -132,6 +132,7 @@ choice
|
||||
|
||||
config XTENSA_PLATFORM_ISS
|
||||
bool "ISS"
|
||||
depends on TTY
|
||||
select XTENSA_CALIBRATE_CCOUNT
|
||||
select SERIAL_CONSOLE
|
||||
select XTENSA_ISS_NETWORK
|
||||
|
@ -58,7 +58,8 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
|
||||
tty->port = &serial_port;
|
||||
spin_lock(&timer_lock);
|
||||
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);
|
||||
}
|
||||
spin_unlock(&timer_lock);
|
||||
@ -97,8 +98,7 @@ static int rs_write(struct tty_struct * tty,
|
||||
|
||||
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 };
|
||||
int i = 0;
|
||||
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)){
|
||||
__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++;
|
||||
}
|
||||
|
||||
if (i)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(port);
|
||||
|
||||
|
||||
mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE);
|
||||
|
@ -26,6 +26,7 @@ config BT_HCIBTSDIO
|
||||
|
||||
config BT_HCIUART
|
||||
tristate "HCI UART driver"
|
||||
depends on TTY
|
||||
help
|
||||
Bluetooth HCI UART driver.
|
||||
This driver is required if you want to use Bluetooth devices with
|
||||
|
@ -53,7 +53,7 @@ source "drivers/tty/serial/Kconfig"
|
||||
|
||||
config TTY_PRINTK
|
||||
bool "TTY driver to output user messages via printk"
|
||||
depends on EXPERT
|
||||
depends on EXPERT && TTY
|
||||
default n
|
||||
---help---
|
||||
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
|
||||
tristate "Virtio console"
|
||||
depends on VIRTIO
|
||||
depends on VIRTIO && TTY
|
||||
select HVC_DRIVER
|
||||
help
|
||||
Virtio console for use with lguest and other hypervisors.
|
||||
@ -392,6 +392,7 @@ config XILINX_HWICAP
|
||||
|
||||
config R3964
|
||||
tristate "Siemens R3964 line discipline"
|
||||
depends on TTY
|
||||
---help---
|
||||
This driver allows synchronous communication with devices using the
|
||||
Siemens R3964 packet protocol. Unless you are dealing with special
|
||||
@ -439,7 +440,7 @@ source "drivers/char/pcmcia/Kconfig"
|
||||
|
||||
config MWAVE
|
||||
tristate "ACP Modem (Mwave) support"
|
||||
depends on X86
|
||||
depends on X86 && TTY
|
||||
select SERIAL_8250
|
||||
---help---
|
||||
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
|
||||
tristate "SyncLink PC Card support"
|
||||
depends on PCMCIA
|
||||
depends on PCMCIA && TTY
|
||||
help
|
||||
Enable support for the SyncLink PC Card serial adapter, running
|
||||
asynchronous and HDLC communications up to 512Kbps. The port is
|
||||
@ -45,7 +45,7 @@ config CARDMAN_4040
|
||||
|
||||
config IPWIRELESS
|
||||
tristate "IPWireless 3G UMTS PCMCIA card support"
|
||||
depends on PCMCIA && NETDEVICES
|
||||
depends on PCMCIA && NETDEVICES && TTY
|
||||
select PPP
|
||||
help
|
||||
This is a driver for 3G UMTS PCMCIA card from IPWireless company. In
|
||||
|
@ -210,7 +210,7 @@ typedef struct _mgslpc_info {
|
||||
char testing_irq;
|
||||
unsigned int init_error; /* startup error (DIAGS) */
|
||||
|
||||
char flag_buf[MAX_ASYNC_BUFFER_SIZE];
|
||||
char *flag_buf;
|
||||
bool drop_rts_on_tx_done;
|
||||
|
||||
struct _input_signal_events input_signal_events;
|
||||
@ -765,9 +765,6 @@ static void bh_handler(struct work_struct *work)
|
||||
struct tty_struct *tty;
|
||||
int action;
|
||||
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
if (debug_level >= DEBUG_LEVEL_BH)
|
||||
printk( "%s(%d):bh_handler(%s) entry\n",
|
||||
__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);
|
||||
}
|
||||
|
||||
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;
|
||||
int fifo_count;
|
||||
int work = 0;
|
||||
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) {
|
||||
/* early termination, get FIFO count from RBCL register */
|
||||
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
|
||||
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. */
|
||||
while (fifo_count) {
|
||||
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)
|
||||
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);
|
||||
|
||||
@ -957,7 +947,7 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd, struct tty_struct *tty)
|
||||
}
|
||||
|
||||
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)
|
||||
rx_ready_hdlc(info, isr & IRQ_RXEOM);
|
||||
else
|
||||
rx_ready_async(info, isr & IRQ_RXEOM, tty);
|
||||
rx_ready_async(info, isr & IRQ_RXEOM);
|
||||
}
|
||||
|
||||
/* transmit IRQs */
|
||||
@ -1353,7 +1343,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
|
||||
reset_device(info);
|
||||
|
||||
if (!tty || tty->termios.c_cflag & HUPCL) {
|
||||
info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
|
||||
info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
|
||||
set_signals(info);
|
||||
}
|
||||
|
||||
@ -1415,12 +1405,12 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty)
|
||||
|
||||
cflag = tty->termios.c_cflag;
|
||||
|
||||
/* if B0 rate (hangup) specified then negate DTR and RTS */
|
||||
/* otherwise assert DTR and RTS */
|
||||
/* if B0 rate (hangup) specified then negate RTS and DTR */
|
||||
/* otherwise assert RTS and DTR */
|
||||
if (cflag & CBAUD)
|
||||
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
|
||||
info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR;
|
||||
else
|
||||
info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
|
||||
info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
|
||||
|
||||
/* 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 */
|
||||
if (old_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);
|
||||
set_signals(info);
|
||||
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);
|
||||
if (onoff)
|
||||
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
|
||||
info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR;
|
||||
else
|
||||
info->serial_signals &= ~SerialSignal_RTS + SerialSignal_DTR;
|
||||
info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
|
||||
set_signals(info);
|
||||
spin_unlock_irqrestore(&info->lock,flags);
|
||||
}
|
||||
@ -2521,7 +2511,7 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
|
||||
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);
|
||||
if (info->netcount) {
|
||||
@ -2674,6 +2664,14 @@ static int rx_alloc_buffers(MGSLPC_INFO *info)
|
||||
if (info->rx_buf == NULL)
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
@ -2682,6 +2680,8 @@ static void rx_free_buffers(MGSLPC_INFO *info)
|
||||
{
|
||||
kfree(info->rx_buf);
|
||||
info->rx_buf = NULL;
|
||||
kfree(info->flag_buf);
|
||||
info->flag_buf = NULL;
|
||||
}
|
||||
|
||||
static int claim_resources(MGSLPC_INFO *info)
|
||||
@ -3575,8 +3575,8 @@ static void get_signals(MGSLPC_INFO *info)
|
||||
{
|
||||
unsigned char status = 0;
|
||||
|
||||
/* preserve DTR and RTS */
|
||||
info->serial_signals &= SerialSignal_DTR + SerialSignal_RTS;
|
||||
/* preserve RTS and DTR */
|
||||
info->serial_signals &= SerialSignal_RTS | SerialSignal_DTR;
|
||||
|
||||
if (read_reg(info, CHB + VSTR) & BIT7)
|
||||
info->serial_signals |= SerialSignal_DCD;
|
||||
@ -3590,7 +3590,7 @@ static void get_signals(MGSLPC_INFO *info)
|
||||
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.
|
||||
*/
|
||||
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);
|
||||
return rc;
|
||||
}
|
||||
/* assert DTR and RTS, apply hardware settings */
|
||||
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
|
||||
/* assert RTS and DTR, apply hardware settings */
|
||||
info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR;
|
||||
mgslpc_program_hw(info, tty);
|
||||
tty_kref_put(tty);
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
|
@ -802,6 +802,7 @@ config I2C_PARPORT_LIGHT
|
||||
|
||||
config I2C_TAOS_EVM
|
||||
tristate "TAOS evaluation module"
|
||||
depends on TTY
|
||||
select SERIO
|
||||
select SERIO_SERPORT
|
||||
default n
|
||||
|
@ -36,6 +36,7 @@ config SERIO_I8042
|
||||
config SERIO_SERPORT
|
||||
tristate "Serial port line discipline"
|
||||
default y
|
||||
depends on TTY
|
||||
help
|
||||
Say Y here if you plan to use an input device (mouse, joystick,
|
||||
tablet, 6dof) that communicates over the RS232 serial (COM) port.
|
||||
|
@ -1,6 +1,6 @@
|
||||
config SERIAL_IPOCTAL
|
||||
tristate "IndustryPack IP-OCTAL uart support"
|
||||
depends on IPACK_BUS
|
||||
depends on IPACK_BUS && TTY
|
||||
help
|
||||
This driver supports the IPOCTAL serial port device for the IndustryPack bus.
|
||||
default n
|
||||
|
@ -133,9 +133,9 @@ static int ipoctal_get_icount(struct tty_struct *tty,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ipoctal_irq_rx(struct ipoctal_channel *channel,
|
||||
struct tty_struct *tty, u8 sr)
|
||||
static void ipoctal_irq_rx(struct ipoctal_channel *channel, u8 sr)
|
||||
{
|
||||
struct tty_port *port = &channel->tty_port;
|
||||
unsigned char value;
|
||||
unsigned char flag = TTY_NORMAL;
|
||||
u8 isr;
|
||||
@ -149,7 +149,7 @@ static void ipoctal_irq_rx(struct ipoctal_channel *channel,
|
||||
if (sr & SR_OVERRUN_ERROR) {
|
||||
channel->stats.overrun_err++;
|
||||
/* 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) {
|
||||
channel->stats.parity_err++;
|
||||
@ -165,7 +165,7 @@ static void ipoctal_irq_rx(struct ipoctal_channel *channel,
|
||||
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
|
||||
* 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);
|
||||
} 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)
|
||||
@ -208,15 +208,11 @@ static void ipoctal_irq_tx(struct ipoctal_channel *channel)
|
||||
static void ipoctal_irq_channel(struct ipoctal_channel *channel)
|
||||
{
|
||||
u8 isr, sr;
|
||||
struct tty_struct *tty;
|
||||
|
||||
/* If there is no client, skip the check */
|
||||
if (!atomic_read(&channel->open))
|
||||
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
|
||||
* to read from */
|
||||
isr = ioread8(&channel->block_regs->r.isr);
|
||||
@ -235,14 +231,13 @@ static void ipoctal_irq_channel(struct ipoctal_channel *channel)
|
||||
|
||||
/* RX data */
|
||||
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 */
|
||||
if ((isr & channel->isr_tx_rdy_mask) && (sr & SR_TX_READY))
|
||||
ipoctal_irq_tx(channel);
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
tty_flip_buffer_push(&channel->tty_port);
|
||||
}
|
||||
|
||||
static irqreturn_t ipoctal_irq_handler(void *arg)
|
||||
|
@ -22,6 +22,7 @@ if ISDN
|
||||
|
||||
menuconfig ISDN_I4L
|
||||
tristate "Old ISDN4Linux (deprecated)"
|
||||
depends on TTY
|
||||
---help---
|
||||
This driver allows you to use an ISDN adapter for networking
|
||||
connections and as dialin/out device. The isdn-tty's have a built
|
||||
|
@ -18,6 +18,7 @@ config CAPI_TRACE
|
||||
|
||||
config ISDN_CAPI_MIDDLEWARE
|
||||
bool "CAPI2.0 Middleware support"
|
||||
depends on TTY
|
||||
help
|
||||
This option will enhance the capabilities of the /dev/capi20
|
||||
interface. It will provide a means of moving a data connection,
|
||||
|
@ -1,5 +1,6 @@
|
||||
menuconfig ISDN_DRV_GIGASET
|
||||
tristate "Siemens Gigaset support"
|
||||
depends on TTY
|
||||
select CRC_CCITT
|
||||
select BITREVERSE
|
||||
help
|
||||
|
@ -134,7 +134,7 @@ static int if_open(struct tty_struct *tty, struct file *filp)
|
||||
|
||||
if (cs->port.count == 1) {
|
||||
tty_port_tty_set(&cs->port, tty);
|
||||
tty->low_latency = 1;
|
||||
cs->port.low_latency = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&cs->mutex);
|
||||
@ -546,16 +546,8 @@ void gigaset_if_free(struct cardstate *cs)
|
||||
void gigaset_if_receive(struct cardstate *cs,
|
||||
unsigned char *buffer, size_t len)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(&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);
|
||||
tty_insert_flip_string(&cs->port, buffer, len);
|
||||
tty_flip_buffer_push(&cs->port);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gigaset_if_receive);
|
||||
|
||||
|
@ -76,6 +76,7 @@ config MISDN_NETJET
|
||||
tristate "Support for NETJet cards"
|
||||
depends on MISDN
|
||||
depends on PCI
|
||||
depends on TTY
|
||||
select MISDN_IPAC
|
||||
select ISDN_HDLC
|
||||
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
|
||||
*/
|
||||
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_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]))
|
||||
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)
|
||||
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)) {
|
||||
/* push every character but the last to the tty buffer directly */
|
||||
if (count_put)
|
||||
tty_insert_flip_char(tty, last, TTY_NORMAL);
|
||||
tty_insert_flip_char(port, last, TTY_NORMAL);
|
||||
len--;
|
||||
if (dev->drv[di]->DLEflag & DLEmask) {
|
||||
last = DLE;
|
||||
@ -940,7 +940,7 @@ isdn_readbchan_tty(int di, int channel, struct tty_struct *tty, int cisco_hack)
|
||||
}
|
||||
count_put = count_pull;
|
||||
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];
|
||||
len -= count_put;
|
||||
#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.
|
||||
*/
|
||||
if (cisco_hack)
|
||||
tty_insert_flip_char(tty, last, 0xFF);
|
||||
tty_insert_flip_char(port, last, 0xFF);
|
||||
else
|
||||
tty_insert_flip_char(tty, last, TTY_NORMAL);
|
||||
tty_insert_flip_char(port, last, TTY_NORMAL);
|
||||
#ifdef CONFIG_ISDN_AUDIO
|
||||
ISDN_AUDIO_SKB_LOCK(skb) = 0;
|
||||
#endif
|
||||
skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]);
|
||||
dev_kfree_skb(skb);
|
||||
} else {
|
||||
tty_insert_flip_char(tty, last, TTY_NORMAL);
|
||||
tty_insert_flip_char(port, last, TTY_NORMAL);
|
||||
/* Not yet emptied this buff, so it
|
||||
* must stay in the queue, for further calls
|
||||
* 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 int isdn_getnum(char **);
|
||||
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_writebuf_skb_stub(int, int, int, struct sk_buff *);
|
||||
extern int register_isdn(isdn_if *i);
|
||||
|
@ -60,18 +60,14 @@ static int si2bit[8] =
|
||||
static int
|
||||
isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
|
||||
{
|
||||
struct tty_port *port = &info->port;
|
||||
int c;
|
||||
int len;
|
||||
struct tty_struct *tty;
|
||||
char last;
|
||||
|
||||
if (!info->online)
|
||||
return 0;
|
||||
|
||||
tty = info->port.tty;
|
||||
if (!tty)
|
||||
return 0;
|
||||
|
||||
if (!(info->mcr & UART_MCR_RTS))
|
||||
return 0;
|
||||
|
||||
@ -81,7 +77,7 @@ isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
|
||||
#endif
|
||||
;
|
||||
|
||||
c = tty_buffer_request_room(tty, len);
|
||||
c = tty_buffer_request_room(port, len);
|
||||
if (c < len)
|
||||
return 0;
|
||||
|
||||
@ -91,25 +87,25 @@ isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
|
||||
unsigned char *dp = skb->data;
|
||||
while (--l) {
|
||||
if (*dp == DLE)
|
||||
tty_insert_flip_char(tty, DLE, 0);
|
||||
tty_insert_flip_char(tty, *dp++, 0);
|
||||
tty_insert_flip_char(port, DLE, 0);
|
||||
tty_insert_flip_char(port, *dp++, 0);
|
||||
}
|
||||
if (*dp == DLE)
|
||||
tty_insert_flip_char(tty, DLE, 0);
|
||||
tty_insert_flip_char(port, DLE, 0);
|
||||
last = *dp;
|
||||
} else {
|
||||
#endif
|
||||
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];
|
||||
#ifdef CONFIG_ISDN_AUDIO
|
||||
}
|
||||
#endif
|
||||
if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
|
||||
tty_insert_flip_char(tty, last, 0xFF);
|
||||
tty_insert_flip_char(port, last, 0xFF);
|
||||
else
|
||||
tty_insert_flip_char(tty, last, TTY_NORMAL);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_insert_flip_char(port, last, TTY_NORMAL);
|
||||
tty_flip_buffer_push(port);
|
||||
kfree_skb(skb);
|
||||
|
||||
return 1;
|
||||
@ -126,7 +122,6 @@ isdn_tty_readmodem(void)
|
||||
int midx;
|
||||
int i;
|
||||
int r;
|
||||
struct tty_struct *tty;
|
||||
modem_info *info;
|
||||
|
||||
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
|
||||
@ -144,20 +139,21 @@ isdn_tty_readmodem(void)
|
||||
if ((info->vonline & 1) && (info->emu.vpar[1]))
|
||||
isdn_audio_eval_silence(info);
|
||||
#endif
|
||||
tty = info->port.tty;
|
||||
if (tty) {
|
||||
if (info->mcr & UART_MCR_RTS) {
|
||||
/* CISCO AsyncPPP Hack */
|
||||
if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
|
||||
r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 0);
|
||||
else
|
||||
r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 1);
|
||||
if (r)
|
||||
tty_flip_buffer_push(tty);
|
||||
} else
|
||||
r = 1;
|
||||
if (info->mcr & UART_MCR_RTS) {
|
||||
/* CISCO AsyncPPP Hack */
|
||||
if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
|
||||
r = isdn_readbchan_tty(info->isdn_driver,
|
||||
info->isdn_channel,
|
||||
&info->port, 0);
|
||||
else
|
||||
r = isdn_readbchan_tty(info->isdn_driver,
|
||||
info->isdn_channel,
|
||||
&info->port, 1);
|
||||
if (r)
|
||||
tty_flip_buffer_push(&info->port);
|
||||
} else
|
||||
r = 1;
|
||||
|
||||
if (r) {
|
||||
info->rcvsched = 0;
|
||||
resched = 1;
|
||||
@ -2229,7 +2225,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
|
||||
void
|
||||
isdn_tty_at_cout(char *msg, modem_info *info)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
struct tty_port *port = &info->port;
|
||||
atemu *m = &info->emu;
|
||||
char *p;
|
||||
char c;
|
||||
@ -2246,15 +2242,14 @@ isdn_tty_at_cout(char *msg, modem_info *info)
|
||||
l = strlen(msg);
|
||||
|
||||
spin_lock_irqsave(&info->readlock, flags);
|
||||
tty = info->port.tty;
|
||||
if ((info->port.flags & ASYNC_CLOSING) || (!tty)) {
|
||||
if (port->flags & ASYNC_CLOSING) {
|
||||
spin_unlock_irqrestore(&info->readlock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/* use queue instead of direct, if online and */
|
||||
/* 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 = alloc_skb(l, GFP_ATOMIC);
|
||||
if (!skb) {
|
||||
@ -2285,7 +2280,7 @@ isdn_tty_at_cout(char *msg, modem_info *info)
|
||||
if (skb) {
|
||||
*sp++ = c;
|
||||
} else {
|
||||
if (tty_insert_flip_char(tty, c, TTY_NORMAL) == 0)
|
||||
if (tty_insert_flip_char(port, c, TTY_NORMAL) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2299,7 +2294,7 @@ isdn_tty_at_cout(char *msg, modem_info *info)
|
||||
|
||||
} else {
|
||||
spin_unlock_irqrestore(&info->readlock, flags);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(port);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
config LGUEST
|
||||
tristate "Linux hypervisor example code"
|
||||
depends on X86_32 && EVENTFD
|
||||
depends on X86_32 && EVENTFD && TTY
|
||||
select HVC_DRIVER
|
||||
---help---
|
||||
This is a very simple module which allows you to run
|
||||
|
@ -4,7 +4,7 @@
|
||||
menu "Texas Instruments WL128x FM driver (ST based)"
|
||||
config RADIO_WL128X
|
||||
tristate "Texas Instruments WL128x FM Radio"
|
||||
depends on VIDEO_V4L2 && RFKILL && GPIOLIB
|
||||
depends on VIDEO_V4L2 && RFKILL && GPIOLIB && TTY
|
||||
select TI_ST if NET
|
||||
help
|
||||
Choose Y here if you have this FM radio chip.
|
||||
|
@ -127,7 +127,7 @@ config PHANTOM
|
||||
|
||||
config INTEL_MID_PTI
|
||||
tristate "Parallel Trace Interface for MIPI P1149.7 cJTAG standard"
|
||||
depends on PCI
|
||||
depends on PCI && TTY
|
||||
default n
|
||||
help
|
||||
The PTI (Parallel Trace Interface) driver directs
|
||||
|
@ -5,7 +5,7 @@
|
||||
menu "Texas Instruments shared transport line discipline"
|
||||
config TI_ST
|
||||
tristate "Shared transport core driver"
|
||||
depends on NET && GPIOLIB
|
||||
depends on NET && GPIOLIB && TTY
|
||||
select FW_LOADER
|
||||
help
|
||||
This enables the shared transport core driver for TI
|
||||
|
@ -52,6 +52,7 @@ config MMC_BLOCK_BOUNCE
|
||||
|
||||
config SDIO_UART
|
||||
tristate "SDIO UART/GPS class support"
|
||||
depends on TTY
|
||||
help
|
||||
SDIO function driver for SDIO cards that implements the 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,
|
||||
unsigned int *status)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(&port->port);
|
||||
unsigned int ch, flag;
|
||||
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 (tty)
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
tty_insert_flip_char(&port->port, ch, flag);
|
||||
|
||||
/*
|
||||
* Overrun is special. Since it's reported immediately,
|
||||
* it doesn't affect the current character.
|
||||
*/
|
||||
if (*status & ~port->ignore_status_mask & UART_LSR_OE)
|
||||
if (tty)
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
|
||||
|
||||
*status = sdio_in(port, UART_LSR);
|
||||
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
|
||||
if (tty) {
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(&port->port);
|
||||
}
|
||||
|
||||
static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
|
||||
|
@ -6,7 +6,7 @@ comment "CAIF transport drivers"
|
||||
|
||||
config CAIF_TTY
|
||||
tristate "CAIF TTY transport driver"
|
||||
depends on CAIF
|
||||
depends on CAIF && TTY
|
||||
default n
|
||||
---help---
|
||||
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->flow_stopped << 3 |
|
||||
ser->tty->packet << 2 |
|
||||
ser->tty->low_latency << 1 |
|
||||
ser->tty->port->low_latency << 1 |
|
||||
ser->tty->warned;
|
||||
}
|
||||
static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty)
|
||||
|
@ -11,6 +11,7 @@ config CAN_VCAN
|
||||
|
||||
config CAN_SLCAN
|
||||
tristate "Serial / USB serial CAN Adaptors (slcan)"
|
||||
depends on TTY
|
||||
---help---
|
||||
CAN driver for several 'low cost' CAN interfaces that are attached
|
||||
via serial lines or via USB-to-serial adapters using the LAWICEL
|
||||
|
@ -1,6 +1,6 @@
|
||||
config MKISS
|
||||
tristate "Serial port KISS driver"
|
||||
depends on AX25
|
||||
depends on AX25 && TTY
|
||||
select CRC16
|
||||
---help---
|
||||
KISS is a protocol used for the exchange of data between a computer
|
||||
@ -18,7 +18,7 @@ config MKISS
|
||||
|
||||
config 6PACK
|
||||
tristate "Serial port 6PACK driver"
|
||||
depends on AX25
|
||||
depends on AX25 && TTY
|
||||
---help---
|
||||
6pack is a transmission protocol for the data exchange between your
|
||||
PC and your TNC (the Terminal Node Controller acts as a kind of
|
||||
|
@ -5,7 +5,7 @@ comment "SIR device drivers"
|
||||
|
||||
config IRTTY_SIR
|
||||
tristate "IrTTY (uses Linux serial driver)"
|
||||
depends on IRDA
|
||||
depends on IRDA && TTY
|
||||
help
|
||||
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
|
||||
|
@ -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
|
||||
* 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):
|
||||
* serial.c: uart-interrupt / softint
|
||||
* usbserial: urb-complete-interrupt / softint
|
||||
|
@ -147,6 +147,7 @@ config PPPOL2TP
|
||||
Support for PPP-over-L2TP socket family. L2TP is a protocol
|
||||
used by ISPs and enterprises to tunnel PPP traffic over UDP
|
||||
tunnels. L2TP is replacing PPTP for VPN uses.
|
||||
if TTY
|
||||
|
||||
config PPP_ASYNC
|
||||
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.
|
||||
|
||||
endif # TTY
|
||||
|
||||
endif # PPP
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
config SLIP
|
||||
tristate "SLIP (serial line) support"
|
||||
depends on TTY
|
||||
---help---
|
||||
Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to
|
||||
connect to your Internet service provider or to connect to some
|
||||
|
@ -443,7 +443,7 @@ config USB_NET_QMI_WWAN
|
||||
|
||||
config USB_HSO
|
||||
tristate "Option USB High Speed Mobile Devices"
|
||||
depends on USB && RFKILL
|
||||
depends on USB && RFKILL && TTY
|
||||
default n
|
||||
help
|
||||
Choose this option if you have an Option HSDPA/HSUPA card.
|
||||
@ -491,7 +491,7 @@ config USB_SIERRA_NET
|
||||
|
||||
config USB_VL600
|
||||
tristate "LG VL600 modem dongle"
|
||||
depends on USB_NET_CDCETHER
|
||||
depends on USB_NET_CDCETHER && TTY
|
||||
select USB_ACM
|
||||
help
|
||||
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);
|
||||
|
||||
/* Push data to tty */
|
||||
if (tty) {
|
||||
write_length_remaining = urb->actual_length -
|
||||
serial->curr_rx_urb_offset;
|
||||
D1("data to push to tty");
|
||||
while (write_length_remaining) {
|
||||
if (test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
tty_kref_put(tty);
|
||||
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);
|
||||
write_length_remaining = urb->actual_length -
|
||||
serial->curr_rx_urb_offset;
|
||||
D1("data to push to tty");
|
||||
while (write_length_remaining) {
|
||||
if (tty && test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
tty_kref_put(tty);
|
||||
return -1;
|
||||
}
|
||||
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) {
|
||||
serial->curr_rx_urb_offset = 0;
|
||||
serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
|
||||
|
@ -375,7 +375,7 @@ config LAPBETHER
|
||||
|
||||
config X25_ASY
|
||||
tristate "X.25 async driver"
|
||||
depends on LAPB && X25
|
||||
depends on LAPB && X25 && TTY
|
||||
---help---
|
||||
Send and receive X.25 frames over regular asynchronous serial
|
||||
lines such as telephone lines equipped with ordinary modems.
|
||||
|
@ -63,6 +63,7 @@ enum parport_pc_pci_cards {
|
||||
timedia_9079b,
|
||||
timedia_9079c,
|
||||
wch_ch353_2s1p,
|
||||
sunix_2s1p,
|
||||
};
|
||||
|
||||
/* each element directly indexed from enum list, above */
|
||||
@ -148,8 +149,12 @@ static struct parport_pc_pci cards[] = {
|
||||
/* timedia_9079b */ { 1, { { 2, 3 }, } },
|
||||
/* timedia_9079c */ { 1, { { 2, 3 }, } },
|
||||
/* 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[] = {
|
||||
/* PCI cards */
|
||||
{ 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, 0xc079, 0, 0, timedia_9079b },
|
||||
{ 0x1409, 0x7168, 0x1409, 0xd079, 0, 0, timedia_9079c },
|
||||
|
||||
/* WCH CARDS */
|
||||
{ 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 */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl);
|
||||
@ -470,6 +485,12 @@ static struct pciserial_board pci_parport_serial_boards[] = {
|
||||
.base_baud = 115200,
|
||||
.uart_offset = 8,
|
||||
},
|
||||
[sunix_2s1p] = {
|
||||
.flags = FL_BASE0|FL_BASE_BARS,
|
||||
.num_ports = 2,
|
||||
.base_baud = 921600,
|
||||
.uart_offset = 8,
|
||||
},
|
||||
};
|
||||
|
||||
struct parport_serial_private {
|
||||
|
@ -17,7 +17,7 @@ config PPS_CLIENT_KTIMER
|
||||
|
||||
config PPS_CLIENT_LDISC
|
||||
tristate "PPS line discipline"
|
||||
depends on PPS
|
||||
depends on PPS && TTY
|
||||
help
|
||||
If you say yes here you get support for a PPS source connected
|
||||
with the CD (Carrier Detect) pin of your serial port.
|
||||
|
@ -25,18 +25,27 @@
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/pps_kernel.h>
|
||||
#include <linux/bug.h>
|
||||
|
||||
#define PPS_TTY_MAGIC 0x0001
|
||||
|
||||
static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status,
|
||||
struct pps_event_time *ts)
|
||||
static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status)
|
||||
{
|
||||
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 */
|
||||
pps_event(pps, ts, status ? PPS_CAPTUREASSERT :
|
||||
pps_event(pps, &ts, status ? PPS_CAPTUREASSERT :
|
||||
PPS_CAPTURECLEAR, NULL);
|
||||
|
||||
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);
|
||||
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);
|
||||
if (ret < 0) {
|
||||
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;
|
||||
|
||||
err_unregister:
|
||||
tty->disc_data = NULL;
|
||||
pps_unregister_source(pps);
|
||||
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)
|
||||
{
|
||||
struct pps_device *pps = (struct pps_device *)tty->disc_data;
|
||||
struct pps_device *pps = pps_lookup_dev(tty);
|
||||
|
||||
alias_n_tty_close(tty);
|
||||
|
||||
tty->disc_data = NULL;
|
||||
if (WARN_ON(!pps))
|
||||
return;
|
||||
|
||||
dev_info(pps->dev, "removed\n");
|
||||
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, cdev);
|
||||
file->private_data = pps;
|
||||
|
||||
kobject_get(&pps->dev->kobj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -274,8 +277,10 @@ static void pps_device_destruct(struct device *dev)
|
||||
{
|
||||
struct pps_device *pps = dev_get_drvdata(dev);
|
||||
|
||||
/* release id here to protect others from using it while it's
|
||||
* still in use */
|
||||
cdev_del(&pps->cdev);
|
||||
|
||||
/* Now we can release the ID for re-use */
|
||||
pr_debug("deallocating pps%d\n", pps->id);
|
||||
mutex_lock(&pps_idr_lock);
|
||||
idr_remove(&pps_idr, pps->id);
|
||||
mutex_unlock(&pps_idr_lock);
|
||||
@ -332,6 +337,7 @@ int pps_register_cdev(struct pps_device *pps)
|
||||
goto del_cdev;
|
||||
}
|
||||
|
||||
/* Override the release function with our own */
|
||||
pps->dev->release = pps_device_destruct;
|
||||
|
||||
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)
|
||||
{
|
||||
pr_debug("unregistering pps%d\n", pps->id);
|
||||
pps->lookup_cookie = NULL;
|
||||
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
|
||||
*/
|
||||
|
@ -11,7 +11,7 @@ config TN3270
|
||||
config TN3270_TTY
|
||||
def_tristate y
|
||||
prompt "Support for tty input/output on 3270 terminals"
|
||||
depends on TN3270
|
||||
depends on TN3270 && TTY
|
||||
help
|
||||
Include support for using an IBM 3270 terminal as a Linux tty.
|
||||
|
||||
@ -33,7 +33,7 @@ config TN3270_CONSOLE
|
||||
config TN3215
|
||||
def_bool y
|
||||
prompt "Support for 3215 line mode terminal"
|
||||
depends on CCW
|
||||
depends on CCW && TTY
|
||||
help
|
||||
Include support for IBM 3215 line-mode terminals.
|
||||
|
||||
@ -51,7 +51,7 @@ config CCW_CONSOLE
|
||||
config SCLP_TTY
|
||||
def_bool y
|
||||
prompt "Support for SCLP line mode terminal"
|
||||
depends on S390
|
||||
depends on S390 && TTY
|
||||
help
|
||||
Include support for IBM SCLP line-mode terminals.
|
||||
|
||||
@ -66,7 +66,7 @@ config SCLP_CONSOLE
|
||||
config SCLP_VT220_TTY
|
||||
def_bool y
|
||||
prompt "Support for SCLP VT220-compatible terminal"
|
||||
depends on S390
|
||||
depends on S390 && TTY
|
||||
help
|
||||
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;
|
||||
|
||||
case CTRLCHAR_CTRL:
|
||||
tty_insert_flip_char(tty, cchar, TTY_NORMAL);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_insert_flip_char(&raw->port, cchar,
|
||||
TTY_NORMAL);
|
||||
tty_flip_buffer_push(&raw->port);
|
||||
break;
|
||||
|
||||
case CTRLCHAR_NONE:
|
||||
@ -425,8 +426,9 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
|
||||
count++;
|
||||
} else
|
||||
count -= 2;
|
||||
tty_insert_flip_string(tty, raw->inbuf, count);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_insert_flip_string(&raw->port, raw->inbuf,
|
||||
count);
|
||||
tty_flip_buffer_push(&raw->port);
|
||||
break;
|
||||
}
|
||||
} 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->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
|
||||
*/
|
||||
|
@ -43,22 +43,14 @@ int kbd_ioctl(struct kbd_data *, unsigned int, unsigned long);
|
||||
static inline void
|
||||
kbd_put_queue(struct tty_port *port, int ch)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(port);
|
||||
if (!tty)
|
||||
return;
|
||||
tty_insert_flip_char(tty, ch, 0);
|
||||
tty_schedule_flip(tty);
|
||||
tty_kref_put(tty);
|
||||
tty_insert_flip_char(port, ch, 0);
|
||||
tty_schedule_flip(port);
|
||||
}
|
||||
|
||||
static inline void
|
||||
kbd_puts_queue(struct tty_port *port, char *cp)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(port);
|
||||
if (!tty)
|
||||
return;
|
||||
while (*cp)
|
||||
tty_insert_flip_char(tty, *cp++, 0);
|
||||
tty_schedule_flip(tty);
|
||||
tty_kref_put(tty);
|
||||
tty_insert_flip_char(port, *cp++, 0);
|
||||
tty_schedule_flip(port);
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ sclp_tty_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
tty_port_tty_set(&sclp_port, tty);
|
||||
tty->driver_data = NULL;
|
||||
tty->low_latency = 0;
|
||||
sclp_port.low_latency = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -342,8 +342,8 @@ sclp_tty_input(unsigned char* buf, unsigned int count)
|
||||
case CTRLCHAR_SYSRQ:
|
||||
break;
|
||||
case CTRLCHAR_CTRL:
|
||||
tty_insert_flip_char(tty, cchar, TTY_NORMAL);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_insert_flip_char(&sclp_port, cchar, TTY_NORMAL);
|
||||
tty_flip_buffer_push(&sclp_port);
|
||||
break;
|
||||
case CTRLCHAR_NONE:
|
||||
/* 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, "\252n", 2))) {
|
||||
/* add the auto \n */
|
||||
tty_insert_flip_string(tty, buf, count);
|
||||
tty_insert_flip_char(tty, '\n', TTY_NORMAL);
|
||||
tty_insert_flip_string(&sclp_port, buf, count);
|
||||
tty_insert_flip_char(&sclp_port, '\n', TTY_NORMAL);
|
||||
} else
|
||||
tty_insert_flip_string(tty, buf, count - 2);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_insert_flip_string(&sclp_port, buf, count - 2);
|
||||
tty_flip_buffer_push(&sclp_port);
|
||||
break;
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
|
@ -461,14 +461,9 @@ sclp_vt220_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
||||
static void
|
||||
sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(&sclp_vt220_port);
|
||||
char *buffer;
|
||||
unsigned int count;
|
||||
|
||||
/* Ignore input if device is not open */
|
||||
if (tty == NULL)
|
||||
return;
|
||||
|
||||
buffer = (char *) ((addr_t) evbuf + 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 */
|
||||
buffer++;
|
||||
count--;
|
||||
tty_insert_flip_string(tty, buffer, count);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_insert_flip_string(&sclp_vt220_port, buffer, count);
|
||||
tty_flip_buffer_push(&sclp_vt220_port);
|
||||
break;
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -495,7 +489,7 @@ sclp_vt220_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
if (tty->count == 1) {
|
||||
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) {
|
||||
tty->winsize.ws_row = 24;
|
||||
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->winsize.ws_row = tp->view.rows - 2;
|
||||
tty->winsize.ws_col = tp->view.cols;
|
||||
tty->low_latency = 0;
|
||||
tp->port.low_latency = 0;
|
||||
/* why to reassign? */
|
||||
tty_port_tty_set(&tp->port, tty);
|
||||
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->low_latency = 0;
|
||||
tp->port.low_latency = 0;
|
||||
tty->winsize.ws_row = tp->view.rows - 2;
|
||||
tty->winsize.ws_col = tp->view.cols;
|
||||
|
||||
|
@ -2,7 +2,7 @@ if USB_GADGET
|
||||
|
||||
config USB_G_CCG
|
||||
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
|
||||
The Configurable Composite Gadget supports multiple USB
|
||||
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);
|
||||
|
||||
/* discard data if tty was closed */
|
||||
if (!tty)
|
||||
goto recycle;
|
||||
|
||||
/* leave data queued if tty was rx throttled */
|
||||
if (test_bit(TTY_THROTTLED, &tty->flags))
|
||||
if (tty && test_bit(TTY_THROTTLED, &tty->flags))
|
||||
break;
|
||||
|
||||
switch (req->status) {
|
||||
@ -529,7 +525,7 @@ static void gs_rx_push(unsigned long _port)
|
||||
size -= n;
|
||||
}
|
||||
|
||||
count = tty_insert_flip_string(tty, packet, size);
|
||||
count = tty_insert_flip_string(&port->port, packet, size);
|
||||
if (count)
|
||||
do_push = true;
|
||||
if (count != size) {
|
||||
@ -542,7 +538,6 @@ static void gs_rx_push(unsigned long _port)
|
||||
}
|
||||
port->n_read = 0;
|
||||
}
|
||||
recycle:
|
||||
list_move(&req->list, &port->read_pool);
|
||||
port->read_started--;
|
||||
}
|
||||
@ -550,8 +545,8 @@ recycle:
|
||||
/* 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
|
||||
*/
|
||||
if (tty && do_push)
|
||||
tty_flip_buffer_push(tty);
|
||||
if (do_push)
|
||||
tty_flip_buffer_push(&port->port);
|
||||
|
||||
|
||||
/* We want our data queue to become empty ASAP, keeping data
|
||||
|
@ -1,7 +1,7 @@
|
||||
config DGRP
|
||||
tristate "Digi Realport driver"
|
||||
default n
|
||||
depends on SYSFS
|
||||
depends on SYSFS && TTY
|
||||
---help---
|
||||
Support for Digi Realport devices. These devices allow you to
|
||||
access remote serial ports as if they are local tty devices. This
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.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;
|
||||
|
||||
/* 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 */
|
||||
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)))))
|
||||
dgrp_dpa_data(nd, 1, myflipbuf, len);
|
||||
|
||||
tty_insert_flip_string_flags(tty, myflipbuf,
|
||||
tty_insert_flip_string_flags(&ch->port, myflipbuf,
|
||||
myflipflagbuf, len);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&ch->port);
|
||||
|
||||
ch->ch_rxcount += len;
|
||||
}
|
||||
@ -2956,9 +2957,9 @@ check_query:
|
||||
I_BRKINT(ch->ch_tun.un_tty) &&
|
||||
!(I_IGNBRK(ch->ch_tun.un_tty))) {
|
||||
|
||||
tty_buffer_request_room(ch->ch_tun.un_tty, 1);
|
||||
tty_insert_flip_char(ch->ch_tun.un_tty, 0, TTY_BREAK);
|
||||
tty_flip_buffer_push(ch->ch_tun.un_tty);
|
||||
tty_buffer_request_room(&ch->port, 1);
|
||||
tty_insert_flip_char(&ch->port, 0, TTY_BREAK);
|
||||
tty_flip_buffer_push(&ch->port);
|
||||
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
config FIREWIRE_SERIAL
|
||||
tristate "TTY over Firewire"
|
||||
depends on FIREWIRE
|
||||
depends on FIREWIRE && TTY
|
||||
help
|
||||
This enables TTY over IEEE 1394, providing high-speed serial
|
||||
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)
|
||||
{
|
||||
struct fwtty_port *port = to_port(to_delayed_work(work), emit_breaks);
|
||||
struct tty_struct *tty;
|
||||
static const char buf[16];
|
||||
unsigned long now = jiffies;
|
||||
unsigned long elapsed = now - port->break_last;
|
||||
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) */
|
||||
n = (elapsed * port->cps) / HZ + 1;
|
||||
port->break_last = now;
|
||||
@ -518,15 +513,14 @@ static void fwtty_emit_breaks(struct work_struct *work)
|
||||
|
||||
while (n) {
|
||||
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;
|
||||
brk += c;
|
||||
if (c < t)
|
||||
break;
|
||||
}
|
||||
tty_flip_buffer_push(tty);
|
||||
|
||||
tty_kref_put(tty);
|
||||
tty_flip_buffer_push(&port->port);
|
||||
|
||||
if (port->mstatus & (UART_LSR_BI << 24))
|
||||
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;
|
||||
int n, c = 0;
|
||||
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
spin_lock_bh(&port->lock);
|
||||
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);
|
||||
c += 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);
|
||||
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;
|
||||
} else {
|
||||
list_del(&buf->list);
|
||||
@ -563,13 +557,11 @@ static void fwtty_pushrx(struct work_struct *work)
|
||||
}
|
||||
}
|
||||
if (c > 0)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&port->port);
|
||||
|
||||
if (list_empty(&port->buf_list))
|
||||
clear_bit(BUFFERING_RX, &port->flags);
|
||||
spin_unlock_bh(&port->lock);
|
||||
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
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;
|
||||
int err = 0;
|
||||
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (!tty)
|
||||
return -ENOENT;
|
||||
|
||||
fwtty_dbg(port, "%d", 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;
|
||||
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;
|
||||
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)) {
|
||||
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)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&port->port);
|
||||
n -= c;
|
||||
|
||||
if (n) {
|
||||
/* start buffering and throttling */
|
||||
n -= fwtty_buffer_rx(port, &data[c], n);
|
||||
|
||||
spin_lock_bh(&port->lock);
|
||||
__fwtty_throttle(port, tty);
|
||||
spin_unlock_bh(&port->lock);
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (tty) {
|
||||
spin_lock_bh(&port->lock);
|
||||
__fwtty_throttle(port, tty);
|
||||
spin_unlock_bh(&port->lock);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
} else
|
||||
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:
|
||||
tty_kref_put(tty);
|
||||
|
||||
port->icount.rx += len;
|
||||
port->stats.lost += n;
|
||||
return err;
|
||||
|
@ -1,8 +1,7 @@
|
||||
config SB105X
|
||||
tristate "SystemBase PCI Multiport UART"
|
||||
select SERIAL_CORE
|
||||
depends on PCI
|
||||
depends on X86
|
||||
depends on PCI && X86 && TTY && BROKEN
|
||||
help
|
||||
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);
|
||||
}
|
||||
|
||||
static void ProcessRxChar(struct tty_struct *tty, struct usb_serial_port *port,
|
||||
unsigned char data)
|
||||
static void ProcessRxChar(struct usb_serial_port *port, unsigned char data)
|
||||
{
|
||||
struct urb *urb = port->read_urb;
|
||||
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)
|
||||
@ -291,8 +290,7 @@ static void qt_interrupt_callback(struct urb *urb)
|
||||
/* FIXME */
|
||||
}
|
||||
|
||||
static void qt_status_change_check(struct tty_struct *tty,
|
||||
struct urb *urb,
|
||||
static void qt_status_change_check(struct urb *urb,
|
||||
struct quatech_port *qt_port,
|
||||
struct usb_serial_port *port)
|
||||
{
|
||||
@ -335,8 +333,8 @@ static void qt_status_change_check(struct tty_struct *tty,
|
||||
case 0xff:
|
||||
dev_dbg(&port->dev, "No status sequence.\n");
|
||||
|
||||
ProcessRxChar(tty, port, data[i]);
|
||||
ProcessRxChar(tty, port, data[i + 1]);
|
||||
ProcessRxChar(port, data[i]);
|
||||
ProcessRxChar(port, data[i + 1]);
|
||||
|
||||
i += 2;
|
||||
break;
|
||||
@ -345,11 +343,11 @@ static void qt_status_change_check(struct tty_struct *tty,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tty && urb->actual_length)
|
||||
tty_insert_flip_char(tty, data[i], TTY_NORMAL);
|
||||
if (urb->actual_length)
|
||||
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)
|
||||
@ -358,7 +356,6 @@ static void qt_read_bulk_callback(struct urb *urb)
|
||||
struct usb_serial_port *port = urb->context;
|
||||
struct usb_serial *serial = get_usb_serial(port, __func__);
|
||||
struct quatech_port *qt_port = qt_get_port_private(port);
|
||||
struct tty_struct *tty;
|
||||
int result;
|
||||
|
||||
if (urb->status) {
|
||||
@ -369,27 +366,23 @@ static void qt_read_bulk_callback(struct urb *urb)
|
||||
return;
|
||||
}
|
||||
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
dev_dbg(&port->dev,
|
||||
"%s - port->RxHolding = %d\n", __func__, qt_port->RxHolding);
|
||||
|
||||
if (port_paranoia_check(port, __func__) != 0) {
|
||||
qt_port->ReadBulkStopped = 1;
|
||||
goto exit;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!serial)
|
||||
goto exit;
|
||||
return;
|
||||
|
||||
if (qt_port->closePending == 1) {
|
||||
/* Were closing , stop reading */
|
||||
dev_dbg(&port->dev,
|
||||
"%s - (qt_port->closepending == 1\n", __func__);
|
||||
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) {
|
||||
qt_port->ReadBulkStopped = 1;
|
||||
goto exit;
|
||||
return;
|
||||
}
|
||||
|
||||
if (urb->status) {
|
||||
@ -408,11 +401,11 @@ static void qt_read_bulk_callback(struct urb *urb)
|
||||
dev_dbg(&port->dev,
|
||||
"%s - nonzero read bulk status received: %d\n",
|
||||
__func__, urb->status);
|
||||
goto exit;
|
||||
return;
|
||||
}
|
||||
|
||||
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 */
|
||||
usb_fill_bulk_urb(port->read_urb, serial->dev,
|
||||
@ -428,14 +421,12 @@ static void qt_read_bulk_callback(struct urb *urb)
|
||||
__func__, result);
|
||||
else {
|
||||
if (urb->actual_length) {
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_schedule_flip(tty);
|
||||
tty_flip_buffer_push(&port->port);
|
||||
tty_schedule_flip(&port->port);
|
||||
}
|
||||
}
|
||||
|
||||
schedule_work(&port->work);
|
||||
exit:
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <linux/consolemap.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/device.h> /* for dev_warn */
|
||||
#include <linux/selection.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
|
||||
bool "Virtual terminal" if EXPERT
|
||||
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
|
||||
there simply will be no early console output. This is true also
|
||||
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
|
||||
obj-$(CONFIG_LEGACY_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_SYNCLINK) += synclink.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/
|
||||
|
@ -251,7 +251,6 @@ static void receive_chars(struct serial_state *info)
|
||||
{
|
||||
int status;
|
||||
int serdatr;
|
||||
struct tty_struct *tty = info->tport.tty;
|
||||
unsigned char ch, flag;
|
||||
struct async_icount *icount;
|
||||
int oe = 0;
|
||||
@ -314,7 +313,7 @@ static void receive_chars(struct serial_state *info)
|
||||
#endif
|
||||
flag = TTY_BREAK;
|
||||
if (info->tport.flags & ASYNC_SAK)
|
||||
do_SAK(tty);
|
||||
do_SAK(info->tport.tty);
|
||||
} else if (status & UART_LSR_PE)
|
||||
flag = TTY_PARITY;
|
||||
else if (status & UART_LSR_FE)
|
||||
@ -328,10 +327,10 @@ static void receive_chars(struct serial_state *info)
|
||||
oe = 1;
|
||||
}
|
||||
}
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
tty_insert_flip_char(&info->tport, ch, flag);
|
||||
if (oe == 1)
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_insert_flip_char(&info->tport, 0, TTY_OVERRUN);
|
||||
tty_flip_buffer_push(&info->tport);
|
||||
out:
|
||||
return;
|
||||
}
|
||||
@ -394,11 +393,6 @@ static void check_modem_status(struct serial_state *info)
|
||||
icount->dsr++;
|
||||
if (dstatus & SER_DCD) {
|
||||
icount->dcd++;
|
||||
#ifdef CONFIG_HARD_PPS
|
||||
if ((port->flags & ASYNC_HARDPPS_CD) &&
|
||||
!(status & SER_DCD))
|
||||
hardpps();
|
||||
#endif
|
||||
}
|
||||
if (dstatus & SER_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;
|
||||
port->close_delay = new_serial.close_delay * 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:
|
||||
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"))
|
||||
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);
|
||||
if (retval) {
|
||||
|
@ -95,18 +95,16 @@ bfin_jc_emudat_manager(void *arg)
|
||||
|
||||
/* if incoming data is ready, eat it */
|
||||
if (bfin_read_DBGSTAT() & EMUDIF) {
|
||||
if (tty != NULL) {
|
||||
uint32_t emudat = bfin_read_emudat();
|
||||
if (inbound_len == 0) {
|
||||
pr_debug("incoming length: 0x%08x\n", emudat);
|
||||
inbound_len = emudat;
|
||||
} else {
|
||||
size_t num_chars = (4 <= inbound_len ? 4 : inbound_len);
|
||||
pr_debug(" incoming data: 0x%08x (pushing %zu)\n", emudat, num_chars);
|
||||
inbound_len -= num_chars;
|
||||
tty_insert_flip_string(tty, (unsigned char *)&emudat, num_chars);
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
uint32_t emudat = bfin_read_emudat();
|
||||
if (inbound_len == 0) {
|
||||
pr_debug("incoming length: 0x%08x\n", emudat);
|
||||
inbound_len = emudat;
|
||||
} else {
|
||||
size_t num_chars = (4 <= inbound_len ? 4 : inbound_len);
|
||||
pr_debug(" incoming data: 0x%08x (pushing %zu)\n", emudat, num_chars);
|
||||
inbound_len -= num_chars;
|
||||
tty_insert_flip_string(&port, (unsigned char *)&emudat, num_chars);
|
||||
tty_flip_buffer_push(&port);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -441,7 +441,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
|
||||
void __iomem *base_addr)
|
||||
{
|
||||
struct cyclades_port *info;
|
||||
struct tty_struct *tty;
|
||||
struct tty_port *port;
|
||||
int len, index = cinfo->bus_index;
|
||||
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));
|
||||
channel = save_xir & CyIRChannel;
|
||||
info = &cinfo->ports[channel + chip * 4];
|
||||
port = &info->port;
|
||||
save_car = cyy_readb(info, CyCAR);
|
||||
cyy_writeb(info, CyCAR, save_xir);
|
||||
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 */
|
||||
if (ivr == CyIVRRxEx) { /* exception */
|
||||
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) {
|
||||
info->icount.rx++;
|
||||
tty_kref_put(tty);
|
||||
return;
|
||||
}
|
||||
if (tty_buffer_request_room(tty, 1)) {
|
||||
if (tty_buffer_request_room(port, 1)) {
|
||||
if (data & info->read_status_mask) {
|
||||
if (data & CyBREAK) {
|
||||
tty_insert_flip_char(tty,
|
||||
tty_insert_flip_char(port,
|
||||
cyy_readb(info, CyRDSR),
|
||||
TTY_BREAK);
|
||||
info->icount.rx++;
|
||||
if (info->port.flags & ASYNC_SAK)
|
||||
do_SAK(tty);
|
||||
if (port->flags & ASYNC_SAK) {
|
||||
struct tty_struct *tty =
|
||||
tty_port_tty_get(port);
|
||||
if (tty) {
|
||||
do_SAK(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
} else if (data & CyFRAME) {
|
||||
tty_insert_flip_char(tty,
|
||||
tty_insert_flip_char(port,
|
||||
cyy_readb(info, CyRDSR),
|
||||
TTY_FRAME);
|
||||
info->icount.rx++;
|
||||
info->idle_stats.frame_errs++;
|
||||
} else if (data & CyPARITY) {
|
||||
/* Pieces of seven... */
|
||||
tty_insert_flip_char(tty,
|
||||
tty_insert_flip_char(port,
|
||||
cyy_readb(info, CyRDSR),
|
||||
TTY_PARITY);
|
||||
info->icount.rx++;
|
||||
info->idle_stats.parity_errs++;
|
||||
} else if (data & CyOVERRUN) {
|
||||
tty_insert_flip_char(tty, 0,
|
||||
tty_insert_flip_char(port, 0,
|
||||
TTY_OVERRUN);
|
||||
info->icount.rx++;
|
||||
/* If the flip buffer itself is
|
||||
overflowing, we still lose
|
||||
the next incoming character.
|
||||
*/
|
||||
tty_insert_flip_char(tty,
|
||||
tty_insert_flip_char(port,
|
||||
cyy_readb(info, CyRDSR),
|
||||
TTY_FRAME);
|
||||
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 & CySPECHAR) { */
|
||||
} else {
|
||||
tty_insert_flip_char(tty, 0,
|
||||
tty_insert_flip_char(port, 0,
|
||||
TTY_NORMAL);
|
||||
info->icount.rx++;
|
||||
}
|
||||
} else {
|
||||
tty_insert_flip_char(tty, 0, TTY_NORMAL);
|
||||
tty_insert_flip_char(port, 0, TTY_NORMAL);
|
||||
info->icount.rx++;
|
||||
}
|
||||
} 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_last = char_count;
|
||||
#endif
|
||||
len = tty_buffer_request_room(tty, char_count);
|
||||
len = tty_buffer_request_room(port, char_count);
|
||||
while (len--) {
|
||||
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->icount.rx++;
|
||||
#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;
|
||||
}
|
||||
tty_schedule_flip(tty);
|
||||
tty_kref_put(tty);
|
||||
end:
|
||||
tty_schedule_flip(port);
|
||||
|
||||
/* end of service */
|
||||
cyy_writeb(info, CyRIR, save_xir & 0x3f);
|
||||
cyy_writeb(info, CyCAR, save_car);
|
||||
@ -924,10 +917,11 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
|
||||
return 0;
|
||||
} /* 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 cyclades_card *cinfo = info->card;
|
||||
struct tty_port *port = &info->port;
|
||||
unsigned int char_count;
|
||||
int len;
|
||||
#ifdef BLOCKMOVE
|
||||
@ -946,80 +940,77 @@ static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty)
|
||||
else
|
||||
char_count = rx_put - rx_get + rx_bufsize;
|
||||
|
||||
if (char_count) {
|
||||
if (!char_count)
|
||||
return;
|
||||
|
||||
#ifdef CY_ENABLE_MONITORING
|
||||
info->mon.int_count++;
|
||||
info->mon.char_count += char_count;
|
||||
if (char_count > info->mon.char_max)
|
||||
info->mon.char_max = char_count;
|
||||
info->mon.char_last = char_count;
|
||||
info->mon.int_count++;
|
||||
info->mon.char_count += char_count;
|
||||
if (char_count > info->mon.char_max)
|
||||
info->mon.char_max = char_count;
|
||||
info->mon.char_last = char_count;
|
||||
#endif
|
||||
if (tty == NULL) {
|
||||
/* flush received characters */
|
||||
new_rx_get = (new_rx_get + char_count) &
|
||||
(rx_bufsize - 1);
|
||||
info->rflush_count++;
|
||||
} else {
|
||||
|
||||
#ifdef BLOCKMOVE
|
||||
/* we'd like to use memcpy(t, f, n) and memset(s, c, count)
|
||||
for performance, but because of buffer boundaries, there
|
||||
may be several steps to the operation */
|
||||
while (1) {
|
||||
len = tty_prepare_flip_string(tty, &buf,
|
||||
char_count);
|
||||
if (!len)
|
||||
break;
|
||||
/* we'd like to use memcpy(t, f, n) and memset(s, c, count)
|
||||
for performance, but because of buffer boundaries, there
|
||||
may be several steps to the operation */
|
||||
while (1) {
|
||||
len = tty_prepare_flip_string(port, &buf,
|
||||
char_count);
|
||||
if (!len)
|
||||
break;
|
||||
|
||||
len = min_t(unsigned int, min(len, char_count),
|
||||
rx_bufsize - new_rx_get);
|
||||
len = min_t(unsigned int, min(len, char_count),
|
||||
rx_bufsize - new_rx_get);
|
||||
|
||||
memcpy_fromio(buf, cinfo->base_addr +
|
||||
rx_bufaddr + new_rx_get, len);
|
||||
memcpy_fromio(buf, cinfo->base_addr +
|
||||
rx_bufaddr + new_rx_get, len);
|
||||
|
||||
new_rx_get = (new_rx_get + len) &
|
||||
(rx_bufsize - 1);
|
||||
char_count -= len;
|
||||
info->icount.rx += len;
|
||||
info->idle_stats.recv_bytes += len;
|
||||
}
|
||||
new_rx_get = (new_rx_get + len) &
|
||||
(rx_bufsize - 1);
|
||||
char_count -= len;
|
||||
info->icount.rx += len;
|
||||
info->idle_stats.recv_bytes += len;
|
||||
}
|
||||
#else
|
||||
len = tty_buffer_request_room(tty, char_count);
|
||||
while (len--) {
|
||||
data = readb(cinfo->base_addr + rx_bufaddr +
|
||||
new_rx_get);
|
||||
new_rx_get = (new_rx_get + 1) &
|
||||
(rx_bufsize - 1);
|
||||
tty_insert_flip_char(tty, data, TTY_NORMAL);
|
||||
info->idle_stats.recv_bytes++;
|
||||
info->icount.rx++;
|
||||
}
|
||||
len = tty_buffer_request_room(port, char_count);
|
||||
while (len--) {
|
||||
data = readb(cinfo->base_addr + rx_bufaddr +
|
||||
new_rx_get);
|
||||
new_rx_get = (new_rx_get + 1) &
|
||||
(rx_bufsize - 1);
|
||||
tty_insert_flip_char(port, data, TTY_NORMAL);
|
||||
info->idle_stats.recv_bytes++;
|
||||
info->icount.rx++;
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_CYZ_INTR
|
||||
/* Recalculate the number of chars in the RX buffer and issue
|
||||
a cmd in case it's higher than the RX high water mark */
|
||||
rx_put = readl(&buf_ctrl->rx_put);
|
||||
if (rx_put >= rx_get)
|
||||
char_count = rx_put - rx_get;
|
||||
else
|
||||
char_count = rx_put - rx_get + rx_bufsize;
|
||||
if (char_count >= readl(&buf_ctrl->rx_threshold) &&
|
||||
!timer_pending(&cyz_rx_full_timer[
|
||||
info->line]))
|
||||
mod_timer(&cyz_rx_full_timer[info->line],
|
||||
jiffies + 1);
|
||||
/* Recalculate the number of chars in the RX buffer and issue
|
||||
a cmd in case it's higher than the RX high water mark */
|
||||
rx_put = readl(&buf_ctrl->rx_put);
|
||||
if (rx_put >= rx_get)
|
||||
char_count = rx_put - rx_get;
|
||||
else
|
||||
char_count = rx_put - rx_get + rx_bufsize;
|
||||
if (char_count >= readl(&buf_ctrl->rx_threshold) &&
|
||||
!timer_pending(&cyz_rx_full_timer[
|
||||
info->line]))
|
||||
mod_timer(&cyz_rx_full_timer[info->line],
|
||||
jiffies + 1);
|
||||
#endif
|
||||
info->idle_stats.recv_idle = jiffies;
|
||||
tty_schedule_flip(tty);
|
||||
}
|
||||
/* Update rx_get */
|
||||
cy_writel(&buf_ctrl->rx_get, new_rx_get);
|
||||
}
|
||||
info->idle_stats.recv_idle = jiffies;
|
||||
tty_schedule_flip(&info->port);
|
||||
|
||||
/* Update 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 cyclades_card *cinfo = info->card;
|
||||
struct tty_struct *tty;
|
||||
u8 data;
|
||||
unsigned int char_count;
|
||||
#ifdef BLOCKMOVE
|
||||
@ -1039,63 +1030,63 @@ static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty)
|
||||
else
|
||||
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)
|
||||
goto ztxdone;
|
||||
if (info->x_char) { /* send special char */
|
||||
data = info->x_char;
|
||||
|
||||
if (info->x_char) { /* send special char */
|
||||
data = info->x_char;
|
||||
|
||||
cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
|
||||
tx_put = (tx_put + 1) & (tx_bufsize - 1);
|
||||
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);
|
||||
cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
|
||||
tx_put = (tx_put + 1) & (tx_bufsize - 1);
|
||||
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);
|
||||
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)
|
||||
{
|
||||
struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
|
||||
struct tty_struct *tty;
|
||||
struct cyclades_port *info;
|
||||
__u32 channel, param, fw_ver;
|
||||
__u8 cmd;
|
||||
@ -1108,23 +1099,20 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
|
||||
special_count = 0;
|
||||
delta_count = 0;
|
||||
info = &cinfo->ports[channel];
|
||||
tty = tty_port_tty_get(&info->port);
|
||||
if (tty == NULL)
|
||||
continue;
|
||||
|
||||
switch (cmd) {
|
||||
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++;
|
||||
special_count++;
|
||||
break;
|
||||
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++;
|
||||
special_count++;
|
||||
break;
|
||||
case C_CM_RXBRK:
|
||||
tty_insert_flip_char(tty, 0, TTY_BREAK);
|
||||
tty_insert_flip_char(&info->port, 0, TTY_BREAK);
|
||||
info->icount.rx++;
|
||||
special_count++;
|
||||
break;
|
||||
@ -1136,8 +1124,14 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
|
||||
readl(&info->u.cyz.ch_ctrl->rs_status);
|
||||
if (dcd & C_RS_DCD)
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
else
|
||||
tty_hangup(tty);
|
||||
else {
|
||||
struct tty_struct *tty;
|
||||
tty = tty_port_tty_get(&info->port);
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
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, "
|
||||
"port %ld\n", info->card, channel);
|
||||
#endif
|
||||
cyz_handle_rx(info, tty);
|
||||
cyz_handle_rx(info);
|
||||
break;
|
||||
case C_CM_TXBEMPTY:
|
||||
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, "
|
||||
"port %ld\n", info->card, channel);
|
||||
#endif
|
||||
cyz_handle_tx(info, tty);
|
||||
cyz_handle_tx(info);
|
||||
break;
|
||||
#endif /* CONFIG_CYZ_INTR */
|
||||
case C_CM_FATAL:
|
||||
@ -1188,8 +1182,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
|
||||
if (delta_count)
|
||||
wake_up_interruptible(&info->port.delta_msr_wait);
|
||||
if (special_count)
|
||||
tty_schedule_flip(tty);
|
||||
tty_kref_put(tty);
|
||||
tty_schedule_flip(&info->port);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1255,17 +1248,11 @@ static void cyz_poll(unsigned long arg)
|
||||
cyz_handle_cmd(cinfo);
|
||||
|
||||
for (port = 0; port < cinfo->nports; port++) {
|
||||
struct tty_struct *tty;
|
||||
|
||||
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)
|
||||
cyz_handle_rx(info, tty);
|
||||
cyz_handle_tx(info, tty);
|
||||
tty_kref_put(tty);
|
||||
cyz_handle_rx(info);
|
||||
cyz_handle_tx(info);
|
||||
}
|
||||
/* poll every 'cyz_polling_cycle' period */
|
||||
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)
|
||||
{
|
||||
struct ehv_bc_data *bc = data;
|
||||
struct tty_struct *ttys = tty_port_tty_get(&bc->port);
|
||||
unsigned int rx_count, tx_count, len;
|
||||
int count;
|
||||
char buffer[EV_BYTE_CHANNEL_MAX_BYTES];
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
* 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. */
|
||||
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.
|
||||
* 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. */
|
||||
tty_flip_buffer_push(ttys);
|
||||
|
||||
tty_kref_put(ttys);
|
||||
tty_flip_buffer_push(&bc->port);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
328
drivers/tty/goldfish.c
Normal file
328
drivers/tty/goldfish.c
Normal file
@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Google, Inc.
|
||||
* Copyright (C) 2012 Intel, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/console.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
enum {
|
||||
GOLDFISH_TTY_PUT_CHAR = 0x00,
|
||||
GOLDFISH_TTY_BYTES_READY = 0x04,
|
||||
GOLDFISH_TTY_CMD = 0x08,
|
||||
|
||||
GOLDFISH_TTY_DATA_PTR = 0x10,
|
||||
GOLDFISH_TTY_DATA_LEN = 0x14,
|
||||
|
||||
GOLDFISH_TTY_CMD_INT_DISABLE = 0,
|
||||
GOLDFISH_TTY_CMD_INT_ENABLE = 1,
|
||||
GOLDFISH_TTY_CMD_WRITE_BUFFER = 2,
|
||||
GOLDFISH_TTY_CMD_READ_BUFFER = 3,
|
||||
};
|
||||
|
||||
struct goldfish_tty {
|
||||
struct tty_port port;
|
||||
spinlock_t lock;
|
||||
void __iomem *base;
|
||||
u32 irq;
|
||||
int opencount;
|
||||
struct console console;
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(goldfish_tty_lock);
|
||||
static struct tty_driver *goldfish_tty_driver;
|
||||
static u32 goldfish_tty_line_count = 8;
|
||||
static u32 goldfish_tty_current_line_count;
|
||||
static struct goldfish_tty *goldfish_ttys;
|
||||
|
||||
static void goldfish_tty_do_write(int line, const char *buf, unsigned count)
|
||||
{
|
||||
unsigned long irq_flags;
|
||||
struct goldfish_tty *qtty = &goldfish_ttys[line];
|
||||
void __iomem *base = qtty->base;
|
||||
spin_lock_irqsave(&qtty->lock, irq_flags);
|
||||
writel((u32)buf, base + GOLDFISH_TTY_DATA_PTR);
|
||||
writel(count, base + GOLDFISH_TTY_DATA_LEN);
|
||||
writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_CMD);
|
||||
spin_unlock_irqrestore(&qtty->lock, irq_flags);
|
||||
}
|
||||
|
||||
static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct platform_device *pdev = dev_id;
|
||||
struct goldfish_tty *qtty = &goldfish_ttys[pdev->id];
|
||||
void __iomem *base = qtty->base;
|
||||
unsigned long irq_flags;
|
||||
unsigned char *buf;
|
||||
u32 count;
|
||||
|
||||
count = readl(base + GOLDFISH_TTY_BYTES_READY);
|
||||
if(count == 0)
|
||||
return IRQ_NONE;
|
||||
|
||||
count = tty_prepare_flip_string(&qtty->port, &buf, count);
|
||||
spin_lock_irqsave(&qtty->lock, irq_flags);
|
||||
writel((u32)buf, base + GOLDFISH_TTY_DATA_PTR);
|
||||
writel(count, base + GOLDFISH_TTY_DATA_LEN);
|
||||
writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_CMD);
|
||||
spin_unlock_irqrestore(&qtty->lock, irq_flags);
|
||||
tty_schedule_flip(&qtty->port);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int goldfish_tty_activate(struct tty_port *port, struct tty_struct *tty)
|
||||
{
|
||||
struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port);
|
||||
writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_CMD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void goldfish_tty_shutdown(struct tty_port *port)
|
||||
{
|
||||
struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port);
|
||||
writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_CMD);
|
||||
}
|
||||
|
||||
static int goldfish_tty_open(struct tty_struct * tty, struct file * filp)
|
||||
{
|
||||
struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
|
||||
return tty_port_open(&qtty->port, tty, filp);
|
||||
}
|
||||
|
||||
static void goldfish_tty_close(struct tty_struct * tty, struct file * filp)
|
||||
{
|
||||
tty_port_close(tty->port, tty, filp);
|
||||
}
|
||||
|
||||
static void goldfish_tty_hangup(struct tty_struct *tty)
|
||||
{
|
||||
tty_port_hangup(tty->port);
|
||||
}
|
||||
|
||||
static int goldfish_tty_write(struct tty_struct * tty, const unsigned char *buf, int count)
|
||||
{
|
||||
goldfish_tty_do_write(tty->index, buf, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static int goldfish_tty_write_room(struct tty_struct *tty)
|
||||
{
|
||||
return 0x10000;
|
||||
}
|
||||
|
||||
static int goldfish_tty_chars_in_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
|
||||
void __iomem *base = qtty->base;
|
||||
return readl(base + GOLDFISH_TTY_BYTES_READY);
|
||||
}
|
||||
|
||||
static void goldfish_tty_console_write(struct console *co, const char *b, unsigned count)
|
||||
{
|
||||
goldfish_tty_do_write(co->index, b, count);
|
||||
}
|
||||
|
||||
static struct tty_driver *goldfish_tty_console_device(struct console *c, int *index)
|
||||
{
|
||||
*index = c->index;
|
||||
return goldfish_tty_driver;
|
||||
}
|
||||
|
||||
static int goldfish_tty_console_setup(struct console *co, char *options)
|
||||
{
|
||||
if((unsigned)co->index > goldfish_tty_line_count)
|
||||
return -ENODEV;
|
||||
if(goldfish_ttys[co->index].base == 0)
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct tty_port_operations goldfish_port_ops = {
|
||||
.activate = goldfish_tty_activate,
|
||||
.shutdown = goldfish_tty_shutdown
|
||||
};
|
||||
|
||||
static struct tty_operations goldfish_tty_ops = {
|
||||
.open = goldfish_tty_open,
|
||||
.close = goldfish_tty_close,
|
||||
.hangup = goldfish_tty_hangup,
|
||||
.write = goldfish_tty_write,
|
||||
.write_room = goldfish_tty_write_room,
|
||||
.chars_in_buffer = goldfish_tty_chars_in_buffer,
|
||||
};
|
||||
|
||||
static int goldfish_tty_create_driver(void)
|
||||
{
|
||||
int ret;
|
||||
struct tty_driver *tty;
|
||||
|
||||
goldfish_ttys = kzalloc(sizeof(*goldfish_ttys) * goldfish_tty_line_count, GFP_KERNEL);
|
||||
if(goldfish_ttys == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err_alloc_goldfish_ttys_failed;
|
||||
}
|
||||
tty = alloc_tty_driver(goldfish_tty_line_count);
|
||||
if(tty == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err_alloc_tty_driver_failed;
|
||||
}
|
||||
tty->driver_name = "goldfish";
|
||||
tty->name = "ttyGF";
|
||||
tty->type = TTY_DRIVER_TYPE_SERIAL;
|
||||
tty->subtype = SERIAL_TYPE_NORMAL;
|
||||
tty->init_termios = tty_std_termios;
|
||||
tty->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
|
||||
tty_set_operations(tty, &goldfish_tty_ops);
|
||||
ret = tty_register_driver(tty);
|
||||
if(ret)
|
||||
goto err_tty_register_driver_failed;
|
||||
|
||||
goldfish_tty_driver = tty;
|
||||
return 0;
|
||||
|
||||
err_tty_register_driver_failed:
|
||||
put_tty_driver(tty);
|
||||
err_alloc_tty_driver_failed:
|
||||
kfree(goldfish_ttys);
|
||||
goldfish_ttys = NULL;
|
||||
err_alloc_goldfish_ttys_failed:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void goldfish_tty_delete_driver(void)
|
||||
{
|
||||
tty_unregister_driver(goldfish_tty_driver);
|
||||
put_tty_driver(goldfish_tty_driver);
|
||||
goldfish_tty_driver = NULL;
|
||||
kfree(goldfish_ttys);
|
||||
goldfish_ttys = NULL;
|
||||
}
|
||||
|
||||
static int goldfish_tty_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct goldfish_tty *qtty;
|
||||
int ret = -EINVAL;
|
||||
int i;
|
||||
struct resource *r;
|
||||
struct device *ttydev;
|
||||
void __iomem *base;
|
||||
u32 irq;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if(r == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
base = ioremap(r->start, 0x1000);
|
||||
if (base == NULL)
|
||||
pr_err("goldfish_tty: unable to remap base\n");
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if(r == NULL)
|
||||
goto err_unmap;
|
||||
|
||||
irq = r->start;
|
||||
|
||||
if(pdev->id >= goldfish_tty_line_count)
|
||||
goto err_unmap;
|
||||
|
||||
mutex_lock(&goldfish_tty_lock);
|
||||
if(goldfish_tty_current_line_count == 0) {
|
||||
ret = goldfish_tty_create_driver();
|
||||
if(ret)
|
||||
goto err_create_driver_failed;
|
||||
}
|
||||
goldfish_tty_current_line_count++;
|
||||
|
||||
qtty = &goldfish_ttys[pdev->id];
|
||||
spin_lock_init(&qtty->lock);
|
||||
tty_port_init(&qtty->port);
|
||||
qtty->port.ops = &goldfish_port_ops;
|
||||
qtty->base = base;
|
||||
qtty->irq = irq;
|
||||
|
||||
writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_CMD);
|
||||
|
||||
ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, "goldfish_tty", pdev);
|
||||
if(ret)
|
||||
goto err_request_irq_failed;
|
||||
|
||||
|
||||
ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver,
|
||||
pdev->id, &pdev->dev);
|
||||
if(IS_ERR(ttydev)) {
|
||||
ret = PTR_ERR(ttydev);
|
||||
goto err_tty_register_device_failed;
|
||||
}
|
||||
|
||||
strcpy(qtty->console.name, "ttyGF");
|
||||
qtty->console.write = goldfish_tty_console_write;
|
||||
qtty->console.device = goldfish_tty_console_device;
|
||||
qtty->console.setup = goldfish_tty_console_setup;
|
||||
qtty->console.flags = CON_PRINTBUFFER;
|
||||
qtty->console.index = pdev->id;
|
||||
register_console(&qtty->console);
|
||||
|
||||
mutex_unlock(&goldfish_tty_lock);
|
||||
return 0;
|
||||
|
||||
tty_unregister_device(goldfish_tty_driver, i);
|
||||
err_tty_register_device_failed:
|
||||
free_irq(irq, pdev);
|
||||
err_request_irq_failed:
|
||||
goldfish_tty_current_line_count--;
|
||||
if(goldfish_tty_current_line_count == 0)
|
||||
goldfish_tty_delete_driver();
|
||||
err_create_driver_failed:
|
||||
mutex_unlock(&goldfish_tty_lock);
|
||||
err_unmap:
|
||||
iounmap(base);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int goldfish_tty_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct goldfish_tty *qtty;
|
||||
|
||||
mutex_lock(&goldfish_tty_lock);
|
||||
|
||||
qtty = &goldfish_ttys[pdev->id];
|
||||
unregister_console(&qtty->console);
|
||||
tty_unregister_device(goldfish_tty_driver, pdev->id);
|
||||
iounmap(qtty->base);
|
||||
qtty->base = 0;
|
||||
free_irq(qtty->irq, pdev);
|
||||
goldfish_tty_current_line_count--;
|
||||
if(goldfish_tty_current_line_count == 0)
|
||||
goldfish_tty_delete_driver();
|
||||
mutex_unlock(&goldfish_tty_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver goldfish_tty_platform_driver = {
|
||||
.probe = goldfish_tty_probe,
|
||||
.remove = goldfish_tty_remove,
|
||||
.driver = {
|
||||
.name = "goldfish_tty"
|
||||
}
|
||||
};
|
||||
|
||||
module_platform_driver(goldfish_tty_platform_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
@ -1,3 +1,5 @@
|
||||
if TTY
|
||||
|
||||
config HVC_DRIVER
|
||||
bool
|
||||
help
|
||||
@ -119,3 +121,4 @@ config HVCS
|
||||
which will also be compiled when this driver is built as a
|
||||
module.
|
||||
|
||||
endif # TTY
|
||||
|
@ -629,7 +629,7 @@ int hvc_poll(struct hvc_struct *hp)
|
||||
|
||||
/* Read data if any */
|
||||
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 (count == 0) {
|
||||
@ -672,7 +672,7 @@ int hvc_poll(struct hvc_struct *hp)
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_MAGIC_SYSRQ */
|
||||
tty_insert_flip_char(tty, buf[i], 0);
|
||||
tty_insert_flip_char(&hp->port, buf[i], 0);
|
||||
}
|
||||
|
||||
read_total += n;
|
||||
@ -691,7 +691,7 @@ int hvc_poll(struct hvc_struct *hp)
|
||||
a minimum for performance. */
|
||||
timeout = MIN_TIMEOUT;
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&hp->port);
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
|
||||
|
@ -609,11 +609,11 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
|
||||
/* remove the read masks */
|
||||
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,
|
||||
&buf[0],
|
||||
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. */
|
||||
@ -623,7 +623,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
/* This is synch because tty->low_latency == 1 */
|
||||
if(got)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&hvcsd->port);
|
||||
|
||||
if (!got) {
|
||||
/* 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,
|
||||
const char *buf, int len)
|
||||
static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -346,7 +345,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty,
|
||||
continue;
|
||||
}
|
||||
#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.
|
||||
*/
|
||||
#define TTY_THRESHOLD_THROTTLE 128
|
||||
static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty,
|
||||
const uint8_t *packet)
|
||||
static bool hvsi_recv_data(struct hvsi_struct *hp, const uint8_t *packet)
|
||||
{
|
||||
const struct hvsi_header *header = (const struct hvsi_header *)packet;
|
||||
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;
|
||||
}
|
||||
|
||||
hvsi_insert_chars(hp, tty, data, datalen);
|
||||
hvsi_insert_chars(hp, data, datalen);
|
||||
|
||||
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:
|
||||
if (!is_open(hp))
|
||||
break;
|
||||
if (tty == NULL)
|
||||
break; /* no tty buffer to put data in */
|
||||
flip = hvsi_recv_data(hp, tty, packet);
|
||||
flip = hvsi_recv_data(hp, packet);
|
||||
break;
|
||||
case VS_CONTROL_PACKET_HEADER:
|
||||
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);
|
||||
|
||||
if (flip)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&hp->port);
|
||||
|
||||
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__,
|
||||
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;
|
||||
}
|
||||
|
||||
@ -514,8 +510,8 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg)
|
||||
if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
/* we weren't hung up and we weren't throttled, so we can
|
||||
* deliver the rest now */
|
||||
hvsi_send_overflow(hp, tty);
|
||||
tty_flip_buffer_push(tty);
|
||||
hvsi_send_overflow(hp);
|
||||
tty_flip_buffer_push(&hp->port);
|
||||
}
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
|
||||
@ -1001,8 +997,8 @@ static void hvsi_unthrottle(struct tty_struct *tty)
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
if (hp->n_throttle) {
|
||||
hvsi_send_overflow(hp, tty);
|
||||
tty_flip_buffer_push(tty);
|
||||
hvsi_send_overflow(hp);
|
||||
tty_flip_buffer_push(&hp->port);
|
||||
}
|
||||
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 */
|
||||
|
||||
/* search device tree for vty nodes */
|
||||
for (vty = of_find_compatible_node(NULL, "serial", "hvterm-protocol");
|
||||
vty != NULL;
|
||||
vty = of_find_compatible_node(vty, "serial", "hvterm-protocol")) {
|
||||
for_each_compatible_node(vty, "serial", "hvterm-protocol") {
|
||||
struct hvsi_struct *hp;
|
||||
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;
|
||||
linux_tty->driver_data = tty;
|
||||
linux_tty->low_latency = 1;
|
||||
tty->port.low_latency = 1;
|
||||
|
||||
if (tty->tty_type == TTYTYPE_MODEM)
|
||||
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,
|
||||
unsigned int length)
|
||||
{
|
||||
struct tty_struct *linux_tty;
|
||||
int work = 0;
|
||||
|
||||
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) {
|
||||
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);
|
||||
|
||||
work = tty_insert_flip_string(linux_tty, data, length);
|
||||
work = tty_insert_flip_string(&tty->port, data, length);
|
||||
|
||||
if (work != length)
|
||||
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
|
||||
*/
|
||||
if (work)
|
||||
tty_flip_buffer_push(linux_tty);
|
||||
tty_flip_buffer_push(&tty->port);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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)
|
||||
do_SAK(tty);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&port->port);
|
||||
break;
|
||||
|
||||
case 2: /* Statistics */
|
||||
@ -650,15 +650,15 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
|
||||
break;
|
||||
}
|
||||
} else { /* Data Packet */
|
||||
|
||||
count = tty_prepare_flip_string(tty, &rp, byte_count & ~1);
|
||||
count = tty_prepare_flip_string(&port->port, &rp,
|
||||
byte_count & ~1);
|
||||
pr_debug("%s: Can rx %d of %d bytes.\n",
|
||||
__func__, count, byte_count);
|
||||
word_count = count >> 1;
|
||||
insw(base, rp, word_count);
|
||||
byte_count -= (word_count << 1);
|
||||
if (count & 0x0001) {
|
||||
tty_insert_flip_char(tty, inw(base) & 0xff,
|
||||
tty_insert_flip_char(&port->port, inw(base) & 0xff,
|
||||
TTY_NORMAL);
|
||||
byte_count -= 2;
|
||||
}
|
||||
@ -671,7 +671,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
|
||||
byte_count -= 2;
|
||||
}
|
||||
}
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&port->port);
|
||||
}
|
||||
outw(0x0000, base+0x04); /* enable interrupts */
|
||||
spin_unlock(&card->card_lock);
|
||||
|
677
drivers/tty/metag_da.c
Normal file
677
drivers/tty/metag_da.c
Normal file
@ -0,0 +1,677 @@
|
||||
/*
|
||||
* dashtty.c - tty driver for Dash channels interface.
|
||||
*
|
||||
* Copyright (C) 2007,2008,2012 Imagination Technologies
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_driver.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/da.h>
|
||||
|
||||
/* Channel error codes */
|
||||
#define CONAOK 0
|
||||
#define CONERR 1
|
||||
#define CONBAD 2
|
||||
#define CONPRM 3
|
||||
#define CONADR 4
|
||||
#define CONCNT 5
|
||||
#define CONCBF 6
|
||||
#define CONCBE 7
|
||||
#define CONBSY 8
|
||||
|
||||
/* Default channel for the console */
|
||||
#define CONSOLE_CHANNEL 1
|
||||
|
||||
#define NUM_TTY_CHANNELS 6
|
||||
|
||||
/* Auto allocate */
|
||||
#define DA_TTY_MAJOR 0
|
||||
|
||||
/* A speedy poll rate helps the userland debug process connection response.
|
||||
* But, if you set it too high then no other userland processes get much
|
||||
* of a look in.
|
||||
*/
|
||||
#define DA_TTY_POLL (HZ / 50)
|
||||
|
||||
/*
|
||||
* A short put delay improves latency but has a high throughput overhead
|
||||
*/
|
||||
#define DA_TTY_PUT_DELAY (HZ / 100)
|
||||
|
||||
static atomic_t num_channels_need_poll = ATOMIC_INIT(0);
|
||||
|
||||
static struct timer_list poll_timer;
|
||||
|
||||
static struct tty_driver *channel_driver;
|
||||
|
||||
static struct timer_list put_timer;
|
||||
static struct task_struct *dashtty_thread;
|
||||
|
||||
#define RX_BUF_SIZE 1024
|
||||
|
||||
enum {
|
||||
INCHR = 1,
|
||||
OUTCHR,
|
||||
RDBUF,
|
||||
WRBUF,
|
||||
RDSTAT
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dashtty_port - Wrapper struct for dashtty tty_port.
|
||||
* @port: TTY port data
|
||||
* @rx_lock: Lock for rx_buf.
|
||||
* This protects between the poll timer and user context.
|
||||
* It's also held during read SWITCH operations.
|
||||
* @rx_buf: Read buffer
|
||||
* @xmit_lock: Lock for xmit_*, and port.xmit_buf.
|
||||
* This protects between user context and kernel thread.
|
||||
* It's also held during write SWITCH operations.
|
||||
* @xmit_cnt: Size of xmit buffer contents
|
||||
* @xmit_head: Head of xmit buffer where data is written
|
||||
* @xmit_tail: Tail of xmit buffer where data is read
|
||||
* @xmit_empty: Completion for xmit buffer being empty
|
||||
*/
|
||||
struct dashtty_port {
|
||||
struct tty_port port;
|
||||
spinlock_t rx_lock;
|
||||
void *rx_buf;
|
||||
struct mutex xmit_lock;
|
||||
unsigned int xmit_cnt;
|
||||
unsigned int xmit_head;
|
||||
unsigned int xmit_tail;
|
||||
struct completion xmit_empty;
|
||||
};
|
||||
|
||||
static struct dashtty_port dashtty_ports[NUM_TTY_CHANNELS];
|
||||
|
||||
static atomic_t dashtty_xmit_cnt = ATOMIC_INIT(0);
|
||||
static wait_queue_head_t dashtty_waitqueue;
|
||||
|
||||
/*
|
||||
* Low-level DA channel access routines
|
||||
*/
|
||||
static int chancall(int in_bios_function, int in_channel,
|
||||
int in_arg2, void *in_arg3,
|
||||
void *in_arg4)
|
||||
{
|
||||
register int bios_function asm("D1Ar1") = in_bios_function;
|
||||
register int channel asm("D0Ar2") = in_channel;
|
||||
register int arg2 asm("D1Ar3") = in_arg2;
|
||||
register void *arg3 asm("D0Ar4") = in_arg3;
|
||||
register void *arg4 asm("D1Ar5") = in_arg4;
|
||||
register int bios_call asm("D0Ar6") = 3;
|
||||
register int result asm("D0Re0");
|
||||
|
||||
asm volatile (
|
||||
"MSETL [A0StP++], %6,%4,%2\n\t"
|
||||
"ADD A0StP, A0StP, #8\n\t"
|
||||
"SWITCH #0x0C30208\n\t"
|
||||
"GETD %0, [A0StP+#-8]\n\t"
|
||||
"SUB A0StP, A0StP, #(4*6)+8\n\t"
|
||||
: "=d" (result) /* outs */
|
||||
: "d" (bios_function),
|
||||
"d" (channel),
|
||||
"d" (arg2),
|
||||
"d" (arg3),
|
||||
"d" (arg4),
|
||||
"d" (bios_call) /* ins */
|
||||
: "memory");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempts to fetch count bytes from channel and returns actual count.
|
||||
*/
|
||||
static int fetch_data(unsigned int channel)
|
||||
{
|
||||
struct dashtty_port *dport = &dashtty_ports[channel];
|
||||
int received = 0;
|
||||
|
||||
spin_lock_bh(&dport->rx_lock);
|
||||
/* check the port isn't being shut down */
|
||||
if (!dport->rx_buf)
|
||||
goto unlock;
|
||||
if (chancall(RDBUF, channel, RX_BUF_SIZE,
|
||||
(void *)dport->rx_buf, &received) == CONAOK) {
|
||||
if (received) {
|
||||
int space;
|
||||
unsigned char *cbuf;
|
||||
|
||||
space = tty_prepare_flip_string(&dport->port, &cbuf,
|
||||
received);
|
||||
|
||||
if (space <= 0)
|
||||
goto unlock;
|
||||
|
||||
memcpy(cbuf, dport->rx_buf, space);
|
||||
tty_flip_buffer_push(&dport->port);
|
||||
}
|
||||
}
|
||||
unlock:
|
||||
spin_unlock_bh(&dport->rx_lock);
|
||||
|
||||
return received;
|
||||
}
|
||||
|
||||
/**
|
||||
* find_channel_to_poll() - Returns number of the next channel to poll.
|
||||
* Returns: The number of the next channel to poll, or -1 if none need
|
||||
* polling.
|
||||
*/
|
||||
static int find_channel_to_poll(void)
|
||||
{
|
||||
static int last_polled_channel;
|
||||
int last = last_polled_channel;
|
||||
int chan;
|
||||
struct dashtty_port *dport;
|
||||
|
||||
for (chan = last + 1; ; ++chan) {
|
||||
if (chan >= NUM_TTY_CHANNELS)
|
||||
chan = 0;
|
||||
|
||||
dport = &dashtty_ports[chan];
|
||||
if (dport->rx_buf) {
|
||||
last_polled_channel = chan;
|
||||
return chan;
|
||||
}
|
||||
|
||||
if (chan == last)
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* put_channel_data() - Write out a block of channel data.
|
||||
* @chan: DA channel number.
|
||||
*
|
||||
* Write a single block of data out to the debug adapter. If the circular buffer
|
||||
* is wrapped then only the first block is written.
|
||||
*
|
||||
* Returns: 1 if the remote buffer was too full to accept data.
|
||||
* 0 otherwise.
|
||||
*/
|
||||
static int put_channel_data(unsigned int chan)
|
||||
{
|
||||
struct dashtty_port *dport;
|
||||
struct tty_struct *tty;
|
||||
int number_written;
|
||||
unsigned int count = 0;
|
||||
|
||||
dport = &dashtty_ports[chan];
|
||||
mutex_lock(&dport->xmit_lock);
|
||||
if (dport->xmit_cnt) {
|
||||
count = min((unsigned int)(SERIAL_XMIT_SIZE - dport->xmit_tail),
|
||||
dport->xmit_cnt);
|
||||
chancall(WRBUF, chan, count,
|
||||
dport->port.xmit_buf + dport->xmit_tail,
|
||||
&number_written);
|
||||
dport->xmit_cnt -= number_written;
|
||||
if (!dport->xmit_cnt) {
|
||||
/* reset pointers to avoid wraps */
|
||||
dport->xmit_head = 0;
|
||||
dport->xmit_tail = 0;
|
||||
complete(&dport->xmit_empty);
|
||||
} else {
|
||||
dport->xmit_tail += number_written;
|
||||
if (dport->xmit_tail >= SERIAL_XMIT_SIZE)
|
||||
dport->xmit_tail -= SERIAL_XMIT_SIZE;
|
||||
}
|
||||
atomic_sub(number_written, &dashtty_xmit_cnt);
|
||||
}
|
||||
mutex_unlock(&dport->xmit_lock);
|
||||
|
||||
/* if we've made more data available, wake up tty */
|
||||
if (count && number_written) {
|
||||
tty = tty_port_tty_get(&dport->port);
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
|
||||
/* did the write fail? */
|
||||
return count && !number_written;
|
||||
}
|
||||
|
||||
/**
|
||||
* put_data() - Kernel thread to write out blocks of channel data to DA.
|
||||
* @arg: Unused.
|
||||
*
|
||||
* This kernel thread runs while @dashtty_xmit_cnt != 0, and loops over the
|
||||
* channels to write out any buffered data. If any of the channels stall due to
|
||||
* the remote buffer being full, a hold off happens to allow the debugger to
|
||||
* drain the buffer.
|
||||
*/
|
||||
static int put_data(void *arg)
|
||||
{
|
||||
unsigned int chan, stall;
|
||||
|
||||
__set_current_state(TASK_RUNNING);
|
||||
while (!kthread_should_stop()) {
|
||||
/*
|
||||
* For each channel see if there's anything to transmit in the
|
||||
* port's xmit_buf.
|
||||
*/
|
||||
stall = 0;
|
||||
for (chan = 0; chan < NUM_TTY_CHANNELS; ++chan)
|
||||
stall += put_channel_data(chan);
|
||||
|
||||
/*
|
||||
* If some of the buffers are full, hold off for a short while
|
||||
* to allow them to empty.
|
||||
*/
|
||||
if (stall)
|
||||
msleep(25);
|
||||
|
||||
wait_event_interruptible(dashtty_waitqueue,
|
||||
atomic_read(&dashtty_xmit_cnt));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This gets called every DA_TTY_POLL and polls the channels for data
|
||||
*/
|
||||
static void dashtty_timer(unsigned long ignored)
|
||||
{
|
||||
int channel;
|
||||
|
||||
/* If there are no ports open do nothing and don't poll again. */
|
||||
if (!atomic_read(&num_channels_need_poll))
|
||||
return;
|
||||
|
||||
channel = find_channel_to_poll();
|
||||
|
||||
/* Did we find a channel to poll? */
|
||||
if (channel >= 0)
|
||||
fetch_data(channel);
|
||||
|
||||
mod_timer_pinned(&poll_timer, jiffies + DA_TTY_POLL);
|
||||
}
|
||||
|
||||
static void add_poll_timer(struct timer_list *poll_timer)
|
||||
{
|
||||
setup_timer(poll_timer, dashtty_timer, 0);
|
||||
poll_timer->expires = jiffies + DA_TTY_POLL;
|
||||
|
||||
/*
|
||||
* Always attach the timer to the boot CPU. The DA channels are per-CPU
|
||||
* so all polling should be from a single CPU.
|
||||
*/
|
||||
add_timer_on(poll_timer, 0);
|
||||
}
|
||||
|
||||
static int dashtty_port_activate(struct tty_port *port, struct tty_struct *tty)
|
||||
{
|
||||
struct dashtty_port *dport = container_of(port, struct dashtty_port,
|
||||
port);
|
||||
void *rx_buf;
|
||||
|
||||
/* Allocate the buffer we use for writing data */
|
||||
if (tty_port_alloc_xmit_buf(port) < 0)
|
||||
goto err;
|
||||
|
||||
/* Allocate the buffer we use for reading data */
|
||||
rx_buf = kzalloc(RX_BUF_SIZE, GFP_KERNEL);
|
||||
if (!rx_buf)
|
||||
goto err_free_xmit;
|
||||
|
||||
spin_lock_bh(&dport->rx_lock);
|
||||
dport->rx_buf = rx_buf;
|
||||
spin_unlock_bh(&dport->rx_lock);
|
||||
|
||||
/*
|
||||
* Don't add the poll timer if we're opening a console. This
|
||||
* avoids the overhead of polling the Dash but means it is not
|
||||
* possible to have a login on /dev/console.
|
||||
*
|
||||
*/
|
||||
if (dport != &dashtty_ports[CONSOLE_CHANNEL])
|
||||
if (atomic_inc_return(&num_channels_need_poll) == 1)
|
||||
add_poll_timer(&poll_timer);
|
||||
|
||||
return 0;
|
||||
err_free_xmit:
|
||||
tty_port_free_xmit_buf(port);
|
||||
err:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void dashtty_port_shutdown(struct tty_port *port)
|
||||
{
|
||||
struct dashtty_port *dport = container_of(port, struct dashtty_port,
|
||||
port);
|
||||
void *rx_buf;
|
||||
unsigned int count;
|
||||
|
||||
/* stop reading */
|
||||
if (dport != &dashtty_ports[CONSOLE_CHANNEL])
|
||||
if (atomic_dec_and_test(&num_channels_need_poll))
|
||||
del_timer_sync(&poll_timer);
|
||||
|
||||
mutex_lock(&dport->xmit_lock);
|
||||
count = dport->xmit_cnt;
|
||||
mutex_unlock(&dport->xmit_lock);
|
||||
if (count) {
|
||||
/*
|
||||
* There's still data to write out, so wake and wait for the
|
||||
* writer thread to drain the buffer.
|
||||
*/
|
||||
del_timer(&put_timer);
|
||||
wake_up_interruptible(&dashtty_waitqueue);
|
||||
wait_for_completion(&dport->xmit_empty);
|
||||
}
|
||||
|
||||
/* Null the read buffer (timer could still be running!) */
|
||||
spin_lock_bh(&dport->rx_lock);
|
||||
rx_buf = dport->rx_buf;
|
||||
dport->rx_buf = NULL;
|
||||
spin_unlock_bh(&dport->rx_lock);
|
||||
/* Free the read buffer */
|
||||
kfree(rx_buf);
|
||||
|
||||
/* Free the write buffer */
|
||||
tty_port_free_xmit_buf(port);
|
||||
}
|
||||
|
||||
static const struct tty_port_operations dashtty_port_ops = {
|
||||
.activate = dashtty_port_activate,
|
||||
.shutdown = dashtty_port_shutdown,
|
||||
};
|
||||
|
||||
static int dashtty_install(struct tty_driver *driver, struct tty_struct *tty)
|
||||
{
|
||||
return tty_port_install(&dashtty_ports[tty->index].port, driver, tty);
|
||||
}
|
||||
|
||||
static int dashtty_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
return tty_port_open(tty->port, tty, filp);
|
||||
}
|
||||
|
||||
static void dashtty_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
return tty_port_close(tty->port, tty, filp);
|
||||
}
|
||||
|
||||
static void dashtty_hangup(struct tty_struct *tty)
|
||||
{
|
||||
int channel;
|
||||
struct dashtty_port *dport;
|
||||
|
||||
channel = tty->index;
|
||||
dport = &dashtty_ports[channel];
|
||||
|
||||
/* drop any data in the xmit buffer */
|
||||
mutex_lock(&dport->xmit_lock);
|
||||
if (dport->xmit_cnt) {
|
||||
atomic_sub(dport->xmit_cnt, &dashtty_xmit_cnt);
|
||||
dport->xmit_cnt = 0;
|
||||
dport->xmit_head = 0;
|
||||
dport->xmit_tail = 0;
|
||||
complete(&dport->xmit_empty);
|
||||
}
|
||||
mutex_unlock(&dport->xmit_lock);
|
||||
|
||||
tty_port_hangup(tty->port);
|
||||
}
|
||||
|
||||
/**
|
||||
* dashtty_put_timer() - Delayed wake up of kernel thread.
|
||||
* @ignored: unused
|
||||
*
|
||||
* This timer function wakes up the kernel thread if any data exists in the
|
||||
* buffers. It is used to delay the expensive writeout until the writer has
|
||||
* stopped writing.
|
||||
*/
|
||||
static void dashtty_put_timer(unsigned long ignored)
|
||||
{
|
||||
if (atomic_read(&dashtty_xmit_cnt))
|
||||
wake_up_interruptible(&dashtty_waitqueue);
|
||||
}
|
||||
|
||||
static int dashtty_write(struct tty_struct *tty, const unsigned char *buf,
|
||||
int total)
|
||||
{
|
||||
int channel, count, block;
|
||||
struct dashtty_port *dport;
|
||||
|
||||
/* Determine the channel */
|
||||
channel = tty->index;
|
||||
dport = &dashtty_ports[channel];
|
||||
|
||||
/*
|
||||
* Write to output buffer.
|
||||
*
|
||||
* The reason that we asynchronously write the buffer is because if we
|
||||
* were to write the buffer synchronously then because DA channels are
|
||||
* per-CPU the buffer would be written to the channel of whatever CPU
|
||||
* we're running on.
|
||||
*
|
||||
* What we actually want to happen is have all input and output done on
|
||||
* one CPU.
|
||||
*/
|
||||
mutex_lock(&dport->xmit_lock);
|
||||
/* work out how many bytes we can write to the xmit buffer */
|
||||
total = min(total, (int)(SERIAL_XMIT_SIZE - dport->xmit_cnt));
|
||||
atomic_add(total, &dashtty_xmit_cnt);
|
||||
dport->xmit_cnt += total;
|
||||
/* write the actual bytes (may need splitting if it wraps) */
|
||||
for (count = total; count; count -= block) {
|
||||
block = min(count, (int)(SERIAL_XMIT_SIZE - dport->xmit_head));
|
||||
memcpy(dport->port.xmit_buf + dport->xmit_head, buf, block);
|
||||
dport->xmit_head += block;
|
||||
if (dport->xmit_head >= SERIAL_XMIT_SIZE)
|
||||
dport->xmit_head -= SERIAL_XMIT_SIZE;
|
||||
buf += block;
|
||||
}
|
||||
count = dport->xmit_cnt;
|
||||
/* xmit buffer no longer empty? */
|
||||
if (count)
|
||||
INIT_COMPLETION(dport->xmit_empty);
|
||||
mutex_unlock(&dport->xmit_lock);
|
||||
|
||||
if (total) {
|
||||
/*
|
||||
* If the buffer is full, wake up the kthread, otherwise allow
|
||||
* some more time for the buffer to fill up a bit before waking
|
||||
* it.
|
||||
*/
|
||||
if (count == SERIAL_XMIT_SIZE) {
|
||||
del_timer(&put_timer);
|
||||
wake_up_interruptible(&dashtty_waitqueue);
|
||||
} else {
|
||||
mod_timer(&put_timer, jiffies + DA_TTY_PUT_DELAY);
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
static int dashtty_write_room(struct tty_struct *tty)
|
||||
{
|
||||
struct dashtty_port *dport;
|
||||
int channel;
|
||||
int room;
|
||||
|
||||
channel = tty->index;
|
||||
dport = &dashtty_ports[channel];
|
||||
|
||||
/* report the space in the xmit buffer */
|
||||
mutex_lock(&dport->xmit_lock);
|
||||
room = SERIAL_XMIT_SIZE - dport->xmit_cnt;
|
||||
mutex_unlock(&dport->xmit_lock);
|
||||
|
||||
return room;
|
||||
}
|
||||
|
||||
static int dashtty_chars_in_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct dashtty_port *dport;
|
||||
int channel;
|
||||
int chars;
|
||||
|
||||
channel = tty->index;
|
||||
dport = &dashtty_ports[channel];
|
||||
|
||||
/* report the number of bytes in the xmit buffer */
|
||||
mutex_lock(&dport->xmit_lock);
|
||||
chars = dport->xmit_cnt;
|
||||
mutex_unlock(&dport->xmit_lock);
|
||||
|
||||
return chars;
|
||||
}
|
||||
|
||||
static const struct tty_operations dashtty_ops = {
|
||||
.install = dashtty_install,
|
||||
.open = dashtty_open,
|
||||
.close = dashtty_close,
|
||||
.hangup = dashtty_hangup,
|
||||
.write = dashtty_write,
|
||||
.write_room = dashtty_write_room,
|
||||
.chars_in_buffer = dashtty_chars_in_buffer,
|
||||
};
|
||||
|
||||
static int __init dashtty_init(void)
|
||||
{
|
||||
int ret;
|
||||
int nport;
|
||||
struct dashtty_port *dport;
|
||||
|
||||
if (!metag_da_enabled())
|
||||
return -ENODEV;
|
||||
|
||||
channel_driver = tty_alloc_driver(NUM_TTY_CHANNELS,
|
||||
TTY_DRIVER_REAL_RAW);
|
||||
if (IS_ERR(channel_driver))
|
||||
return PTR_ERR(channel_driver);
|
||||
|
||||
channel_driver->driver_name = "metag_da";
|
||||
channel_driver->name = "ttyDA";
|
||||
channel_driver->major = DA_TTY_MAJOR;
|
||||
channel_driver->minor_start = 0;
|
||||
channel_driver->type = TTY_DRIVER_TYPE_SERIAL;
|
||||
channel_driver->subtype = SERIAL_TYPE_NORMAL;
|
||||
channel_driver->init_termios = tty_std_termios;
|
||||
channel_driver->init_termios.c_cflag |= CLOCAL;
|
||||
|
||||
tty_set_operations(channel_driver, &dashtty_ops);
|
||||
for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) {
|
||||
dport = &dashtty_ports[nport];
|
||||
tty_port_init(&dport->port);
|
||||
dport->port.ops = &dashtty_port_ops;
|
||||
spin_lock_init(&dport->rx_lock);
|
||||
mutex_init(&dport->xmit_lock);
|
||||
/* the xmit buffer starts empty, i.e. completely written */
|
||||
init_completion(&dport->xmit_empty);
|
||||
complete(&dport->xmit_empty);
|
||||
}
|
||||
|
||||
setup_timer(&put_timer, dashtty_put_timer, 0);
|
||||
|
||||
init_waitqueue_head(&dashtty_waitqueue);
|
||||
dashtty_thread = kthread_create(put_data, NULL, "ttyDA");
|
||||
if (IS_ERR(dashtty_thread)) {
|
||||
pr_err("Couldn't create dashtty thread\n");
|
||||
ret = PTR_ERR(dashtty_thread);
|
||||
goto err_destroy_ports;
|
||||
}
|
||||
/*
|
||||
* Bind the writer thread to the boot CPU so it can't migrate.
|
||||
* DA channels are per-CPU and we want all channel I/O to be on a single
|
||||
* predictable CPU.
|
||||
*/
|
||||
kthread_bind(dashtty_thread, 0);
|
||||
wake_up_process(dashtty_thread);
|
||||
|
||||
ret = tty_register_driver(channel_driver);
|
||||
|
||||
if (ret < 0) {
|
||||
pr_err("Couldn't install dashtty driver: err %d\n",
|
||||
ret);
|
||||
goto err_stop_kthread;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_stop_kthread:
|
||||
kthread_stop(dashtty_thread);
|
||||
err_destroy_ports:
|
||||
for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) {
|
||||
dport = &dashtty_ports[nport];
|
||||
tty_port_destroy(&dport->port);
|
||||
}
|
||||
put_tty_driver(channel_driver);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dashtty_exit(void)
|
||||
{
|
||||
int nport;
|
||||
struct dashtty_port *dport;
|
||||
|
||||
del_timer_sync(&put_timer);
|
||||
kthread_stop(dashtty_thread);
|
||||
del_timer_sync(&poll_timer);
|
||||
tty_unregister_driver(channel_driver);
|
||||
for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) {
|
||||
dport = &dashtty_ports[nport];
|
||||
tty_port_destroy(&dport->port);
|
||||
}
|
||||
put_tty_driver(channel_driver);
|
||||
}
|
||||
|
||||
module_init(dashtty_init);
|
||||
module_exit(dashtty_exit);
|
||||
|
||||
#ifdef CONFIG_DA_CONSOLE
|
||||
|
||||
static void dash_console_write(struct console *co, const char *s,
|
||||
unsigned int count)
|
||||
{
|
||||
int actually_written;
|
||||
|
||||
chancall(WRBUF, CONSOLE_CHANNEL, count, (void *)s, &actually_written);
|
||||
}
|
||||
|
||||
static struct tty_driver *dash_console_device(struct console *c, int *index)
|
||||
{
|
||||
*index = c->index;
|
||||
return channel_driver;
|
||||
}
|
||||
|
||||
struct console dash_console = {
|
||||
.name = "ttyDA",
|
||||
.write = dash_console_write,
|
||||
.device = dash_console_device,
|
||||
.flags = CON_PRINTBUFFER,
|
||||
.index = 1,
|
||||
};
|
||||
|
||||
#endif
|
@ -1405,7 +1405,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
|
||||
if (inited && !test_bit(TTY_THROTTLED, &tty->flags) &&
|
||||
MoxaPortRxQueue(p) > 0) { /* RX */
|
||||
MoxaPortReadData(p);
|
||||
tty_schedule_flip(tty);
|
||||
tty_schedule_flip(&p->port);
|
||||
}
|
||||
} else {
|
||||
clear_bit(EMPTYWAIT, &p->statusflags);
|
||||
@ -1429,8 +1429,8 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
|
||||
goto put;
|
||||
|
||||
if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */
|
||||
tty_insert_flip_char(tty, 0, TTY_BREAK);
|
||||
tty_schedule_flip(tty);
|
||||
tty_insert_flip_char(&p->port, 0, TTY_BREAK);
|
||||
tty_schedule_flip(&p->port);
|
||||
}
|
||||
|
||||
if (intr & IntrLine)
|
||||
@ -1966,7 +1966,7 @@ static int MoxaPortReadData(struct moxa_port *port)
|
||||
ofs = baseAddr + DynPage_addr + bufhead + head;
|
||||
len = (tail >= head) ? (tail - head) :
|
||||
(rx_mask + 1 - head);
|
||||
len = tty_prepare_flip_string(tty, &dst,
|
||||
len = tty_prepare_flip_string(&port->port, &dst,
|
||||
min(len, count));
|
||||
memcpy_fromio(dst, ofs, len);
|
||||
head = (head + len) & rx_mask;
|
||||
@ -1978,7 +1978,7 @@ static int MoxaPortReadData(struct moxa_port *port)
|
||||
while (count > 0) {
|
||||
writew(pageno, baseAddr + Control_reg);
|
||||
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));
|
||||
memcpy_fromio(dst, ofs, len);
|
||||
|
||||
|
@ -1264,7 +1264,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
|
||||
(new_serial.flags & ASYNC_FLAGS));
|
||||
port->close_delay = new_serial.close_delay * 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 &&
|
||||
(new_serial.baud_base != info->baud_base ||
|
||||
new_serial.custom_divisor !=
|
||||
@ -2079,7 +2079,7 @@ static void mxser_receive_chars(struct tty_struct *tty,
|
||||
}
|
||||
while (gdl--) {
|
||||
ch = inb(port->ioaddr + UART_RX);
|
||||
tty_insert_flip_char(tty, ch, 0);
|
||||
tty_insert_flip_char(&port->port, ch, 0);
|
||||
cnt++;
|
||||
}
|
||||
goto end_intr;
|
||||
@ -2118,7 +2118,7 @@ intr_old:
|
||||
} else
|
||||
flag = TTY_BREAK;
|
||||
}
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
tty_insert_flip_char(&port->port, ch, flag);
|
||||
cnt++;
|
||||
if (cnt >= recv_room) {
|
||||
if (!port->ldisc_stop_rx)
|
||||
@ -2145,7 +2145,7 @@ end_intr:
|
||||
* recursive locking.
|
||||
*/
|
||||
spin_unlock(&port->slock);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&port->port);
|
||||
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)
|
||||
{
|
||||
free_irq(brd->irq, brd);
|
||||
release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
|
||||
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_port_destroy(&brd->ports[i].port);
|
||||
}
|
||||
free_irq(brd->irq, 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;
|
||||
unsigned int i, j;
|
||||
unsigned long ioaddress;
|
||||
struct device *tty_dev;
|
||||
int retval = -EINVAL;
|
||||
|
||||
for (i = 0; i < MXSER_BOARDS; i++)
|
||||
@ -2637,13 +2638,25 @@ static int mxser_probe(struct pci_dev *pdev,
|
||||
if (retval)
|
||||
goto err_rel3;
|
||||
|
||||
for (i = 0; i < brd->info->nports; i++)
|
||||
tty_port_register_device(&brd->ports[i].port, mxvar_sdriver,
|
||||
brd->idx + i, &pdev->dev);
|
||||
for (i = 0; i < brd->info->nports; i++) {
|
||||
tty_dev = tty_port_register_device(&brd->ports[i].port,
|
||||
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);
|
||||
|
||||
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:
|
||||
pci_release_region(pdev, 3);
|
||||
err_zero:
|
||||
@ -2665,7 +2678,6 @@ static void mxser_remove(struct pci_dev *pdev)
|
||||
|
||||
mxser_board_remove(brd);
|
||||
|
||||
free_irq(pdev->irq, brd);
|
||||
pci_release_region(pdev, 2);
|
||||
pci_release_region(pdev, 3);
|
||||
pci_disable_device(pdev);
|
||||
@ -2683,6 +2695,7 @@ static struct pci_driver mxser_driver = {
|
||||
static int __init mxser_module_init(void)
|
||||
{
|
||||
struct mxser_board *brd;
|
||||
struct device *tty_dev;
|
||||
unsigned int b, i, m;
|
||||
int retval;
|
||||
|
||||
@ -2728,14 +2741,29 @@ static int __init mxser_module_init(void)
|
||||
|
||||
/* mxser_initbrd will hook ISR. */
|
||||
if (mxser_initbrd(brd, NULL) < 0) {
|
||||
mxser_release_ISA_res(brd);
|
||||
brd->info = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
brd->idx = m * MXSER_PORTS_PER_BOARD;
|
||||
for (i = 0; i < brd->info->nports; i++)
|
||||
tty_port_register_device(&brd->ports[i].port,
|
||||
for (i = 0; i < brd->info->nports; i++) {
|
||||
tty_dev = tty_port_register_device(&brd->ports[i].port,
|
||||
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++;
|
||||
}
|
||||
|
@ -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 (!(tty->termios.c_cflag & CLOCAL))
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
struct tty_port *port;
|
||||
unsigned int addr = 0 ;
|
||||
u8 bits;
|
||||
int len = clen;
|
||||
@ -1160,19 +1160,18 @@ static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen)
|
||||
bits = *dp;
|
||||
if ((bits & 1) == 0)
|
||||
return;
|
||||
/* See if we have an uplink tty */
|
||||
tty = tty_port_tty_get(&gsm->dlci[addr]->port);
|
||||
|
||||
if (tty) {
|
||||
if (bits & 2)
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
if (bits & 4)
|
||||
tty_insert_flip_char(tty, 0, TTY_PARITY);
|
||||
if (bits & 8)
|
||||
tty_insert_flip_char(tty, 0, TTY_FRAME);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
port = &gsm->dlci[addr]->port;
|
||||
|
||||
if (bits & 2)
|
||||
tty_insert_flip_char(port, 0, TTY_OVERRUN);
|
||||
if (bits & 4)
|
||||
tty_insert_flip_char(port, 0, TTY_PARITY);
|
||||
if (bits & 8)
|
||||
tty_insert_flip_char(port, 0, TTY_FRAME);
|
||||
|
||||
tty_flip_buffer_push(port);
|
||||
|
||||
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 .. */
|
||||
struct tty_port *port = &dlci->port;
|
||||
struct tty_struct *tty = tty_port_tty_get(port);
|
||||
struct tty_struct *tty;
|
||||
unsigned int modem = 0;
|
||||
int len = clen;
|
||||
|
||||
if (debug & 16)
|
||||
pr_debug("%d bytes for tty %p\n", len, tty);
|
||||
if (tty) {
|
||||
switch (dlci->adaption) {
|
||||
/* Unsupported types */
|
||||
/* Packetised interruptible data */
|
||||
case 4:
|
||||
break;
|
||||
/* Packetised uininterruptible voice/data */
|
||||
case 3:
|
||||
break;
|
||||
/* Asynchronous serial with line state in each frame */
|
||||
case 2:
|
||||
while (gsm_read_ea(&modem, *data++) == 0) {
|
||||
len--;
|
||||
if (len == 0)
|
||||
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);
|
||||
pr_debug("%d bytes for tty\n", len);
|
||||
switch (dlci->adaption) {
|
||||
/* Unsupported types */
|
||||
/* Packetised interruptible data */
|
||||
case 4:
|
||||
break;
|
||||
/* Packetised uininterruptible voice/data */
|
||||
case 3:
|
||||
break;
|
||||
/* Asynchronous serial with line state in each frame */
|
||||
case 2:
|
||||
while (gsm_read_ea(&modem, *data++) == 0) {
|
||||
len--;
|
||||
if (len == 0)
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
static void gsm_destroy_network(struct gsm_dlci *dlci);
|
||||
|
||||
/**
|
||||
* gsm_dlci_release - release DLCI
|
||||
* @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);
|
||||
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_lock(tty);
|
||||
tty_port_tty_set(&dlci->port, NULL);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
dlci->state = DLCI_CLOSED;
|
||||
dlci_put(dlci);
|
||||
}
|
||||
|
||||
@ -2947,6 +2959,8 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)
|
||||
|
||||
if (dlci == NULL)
|
||||
return;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return;
|
||||
mutex_lock(&dlci->mutex);
|
||||
gsm_destroy_network(dlci);
|
||||
mutex_unlock(&dlci->mutex);
|
||||
@ -2965,6 +2979,8 @@ out:
|
||||
static void gsmtty_hangup(struct tty_struct *tty)
|
||||
{
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return;
|
||||
tty_port_hangup(&dlci->port);
|
||||
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,
|
||||
int len)
|
||||
{
|
||||
int sent;
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return -EINVAL;
|
||||
/* 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 */
|
||||
gsm_dlci_data_kick(dlci);
|
||||
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)
|
||||
{
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return -EINVAL;
|
||||
return TX_SIZE - kfifo_len(dlci->fifo);
|
||||
}
|
||||
|
||||
static int gsmtty_chars_in_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return -EINVAL;
|
||||
return kfifo_len(dlci->fifo);
|
||||
}
|
||||
|
||||
static void gsmtty_flush_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return;
|
||||
/* Caution needed: If we implement reliable transport classes
|
||||
then the data being transmitted can't simply be junked once
|
||||
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)
|
||||
{
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return -EINVAL;
|
||||
return dlci->modem_rx;
|
||||
}
|
||||
|
||||
@ -3022,6 +3049,8 @@ static int gsmtty_tiocmset(struct tty_struct *tty,
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
unsigned int modem_tx = dlci->modem_tx;
|
||||
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return -EINVAL;
|
||||
modem_tx &= ~clear;
|
||||
modem_tx |= set;
|
||||
|
||||
@ -3040,6 +3069,8 @@ static int gsmtty_ioctl(struct tty_struct *tty,
|
||||
struct gsm_netconfig nc;
|
||||
int index;
|
||||
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return -EINVAL;
|
||||
switch (cmd) {
|
||||
case GSMIOC_ENABLE_NET:
|
||||
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)
|
||||
{
|
||||
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 virtual channel can be propogated in both directions by
|
||||
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)
|
||||
{
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return;
|
||||
if (tty->termios.c_cflag & CRTSCTS)
|
||||
dlci->modem_tx &= ~TIOCM_DTR;
|
||||
dlci->throttled = 1;
|
||||
@ -3087,6 +3123,8 @@ static void gsmtty_throttle(struct tty_struct *tty)
|
||||
static void gsmtty_unthrottle(struct tty_struct *tty)
|
||||
{
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return;
|
||||
if (tty->termios.c_cflag & CRTSCTS)
|
||||
dlci->modem_tx |= TIOCM_DTR;
|
||||
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;
|
||||
int encode = 0; /* Off */
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return -EINVAL;
|
||||
|
||||
if (state == -1) /* "On indefinitely" - we can't encode this
|
||||
properly */
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include <linux/file.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ratelimit.h>
|
||||
|
||||
|
||||
/* 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 output_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,
|
||||
@ -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.
|
||||
* 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);
|
||||
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;
|
||||
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;
|
||||
spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
|
||||
mutex_lock(&ldata->echo_lock);
|
||||
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;
|
||||
ssize_t n = 0;
|
||||
|
||||
spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
raw_spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
if (!ldata->icanon) {
|
||||
n = ldata->read_cnt;
|
||||
} 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 + (N_TTY_BUF_SIZE - ldata->read_tail);
|
||||
}
|
||||
spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
return n;
|
||||
}
|
||||
|
||||
@ -915,19 +916,19 @@ static void eraser(unsigned char c, struct tty_struct *tty)
|
||||
kill_type = WERASE;
|
||||
else {
|
||||
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) &
|
||||
(N_TTY_BUF_SIZE - 1));
|
||||
ldata->read_head = ldata->canon_head;
|
||||
spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
return;
|
||||
}
|
||||
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) &
|
||||
(N_TTY_BUF_SIZE - 1));
|
||||
ldata->read_head = ldata->canon_head;
|
||||
spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
finish_erasing(ldata);
|
||||
echo_char(KILL_CHAR(tty), tty);
|
||||
/* 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;
|
||||
}
|
||||
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_cnt -= cnt;
|
||||
spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
if (L_ECHO(tty)) {
|
||||
if (L_ECHOPRT(tty)) {
|
||||
if (!ldata->erasing) {
|
||||
@ -1344,12 +1345,12 @@ send_signal:
|
||||
put_tty_queue(c, ldata);
|
||||
|
||||
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);
|
||||
put_tty_queue_nolock(c, ldata);
|
||||
ldata->canon_head = ldata->read_head;
|
||||
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);
|
||||
if (waitqueue_active(&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;
|
||||
|
||||
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,
|
||||
N_TTY_BUF_SIZE - ldata->read_head);
|
||||
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);
|
||||
ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1);
|
||||
ldata->read_cnt += i;
|
||||
spin_unlock_irqrestore(&ldata->read_lock, cpuflags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, cpuflags);
|
||||
} else {
|
||||
for (i = count, p = cp, f = fp; i; i--, p++) {
|
||||
if (f)
|
||||
@ -1635,7 +1636,7 @@ static int n_tty_open(struct tty_struct *tty)
|
||||
mutex_init(&ldata->atomic_read_lock);
|
||||
mutex_init(&ldata->output_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 */
|
||||
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;
|
||||
|
||||
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(*nr, n);
|
||||
spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
if (n) {
|
||||
retval = copy_to_user(*b, &ldata->read_buf[ldata->read_tail], n);
|
||||
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);
|
||||
tty_audit_add_data(tty, &ldata->read_buf[ldata->read_tail], n,
|
||||
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_cnt -= n;
|
||||
/* Turn single EOF into zero-length read */
|
||||
if (L_EXTPROC(tty) && ldata->icanon && is_eof && !ldata->read_cnt)
|
||||
n = 0;
|
||||
spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
*b += n;
|
||||
*nr -= n;
|
||||
}
|
||||
@ -1900,7 +1901,7 @@ do_it_again:
|
||||
|
||||
if (ldata->icanon && !L_EXTPROC(tty)) {
|
||||
/* 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) {
|
||||
int eol;
|
||||
|
||||
@ -1918,25 +1919,25 @@ do_it_again:
|
||||
if (--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 (tty_put_user(tty, c, b++)) {
|
||||
retval = -EFAULT;
|
||||
b--;
|
||||
spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
raw_spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
break;
|
||||
}
|
||||
nr--;
|
||||
}
|
||||
if (eol) {
|
||||
tty_audit_push(tty);
|
||||
spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
raw_spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
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)
|
||||
break;
|
||||
} else {
|
||||
@ -2188,7 +2189,7 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = {
|
||||
* n_tty_inherit_ops - inherit 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.
|
||||
*/
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user