1
0
Fork 0

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.
hifive-unleashed-5.1
Linus Torvalds 2013-02-21 13:41:04 -08:00
commit 21eaab6d19
267 changed files with 6865 additions and 2528 deletions

View File

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

View File

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

View File

@ -5,10 +5,16 @@ Required properties:
- reg : Address and length of the register set
- 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>;
};

View File

@ -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
---------------

View File

@ -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,

View File

@ -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;

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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>

View File

@ -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);

View File

@ -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"

View File

@ -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)

View File

@ -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

View File

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

View File

@ -524,7 +524,7 @@ static int mask_test_and_clear(volatile u8 *ptr, u8 mask)
static void mn10300_serial_receive_interrupt(struct mn10300_serial_port *port)
{
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;
}

View File

@ -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

View File

@ -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);

View File

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

View File

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

View File

@ -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

View File

@ -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,

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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>

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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,

View File

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

View File

@ -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);

View File

@ -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

View File

@ -876,7 +876,7 @@ isdn_readbchan(int di, int channel, u_char *buf, u_char *fp, int len, wait_queue
* of the mapping (di,ch)<->minor, happen during the sleep? --he
*/
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.

View File

@ -37,7 +37,7 @@ extern void isdn_timer_ctrl(int tf, int onoff);
extern void isdn_unexclusive_channel(int di, int ch);
extern 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);

View File

@ -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);
}
}

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -381,7 +381,6 @@ static void sdio_uart_stop_rx(struct sdio_uart_port *port)
static void sdio_uart_receive_chars(struct sdio_uart_port *port,
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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -210,7 +210,7 @@ static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t
* been received, which can now be decapsulated and delivered for
* 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -2035,25 +2035,23 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
tty = tty_port_tty_get(&serial->port);
/* 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;

View File

@ -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.

View File

@ -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 {

View File

@ -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.

View File

@ -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);
}

View File

@ -247,12 +247,15 @@ static int pps_cdev_open(struct inode *inode, struct file *file)
struct pps_device *pps = container_of(inode->i_cdev,
struct pps_device, 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
*/

View File

@ -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.

View File

@ -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
*/

View File

@ -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);
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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>

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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);
}
/*

View File

@ -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"

View File

@ -1,3 +1,14 @@
config TTY
bool "Enable TTY" if EXPERT
default y
---help---
Allows you to remove TTY support which can save space, and
blocks features that require TTY from inclusion in the kernel.
TTY is required for any text terminals or serial port
communication. Most users should leave this enabled.
if TTY
config VT
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

View File

@ -1,4 +1,4 @@
obj-y += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
obj-$(CONFIG_TTY) += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
tty_buffer.o tty_port.o tty_mutex.o
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/

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;
}

View File

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

View File

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

View File

@ -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);

View File

@ -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 */

View File

@ -329,8 +329,7 @@ static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet)
}
}
static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty,
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;

View File

@ -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,

View File

@ -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);

View File

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

View File

@ -1405,7 +1405,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
if (inited && !test_bit(TTY_THROTTLED, &tty->flags) &&
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);

View File

@ -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++;
}

View File

@ -1067,9 +1067,9 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD))
if (!(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 */

View File

@ -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