TTY/Serial driver patches for 3.19-rc1
Here's the big tty/serial driver update for 3.19-rc1. There are a number of TTY core changes/fixes in here from Peter Hurley that have all been teted in linux-next for a long time now. There are also the normal serial driver updates as well, full details in the changelog below. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iEYEABECAAYFAlSOD/MACgkQMUfUDdst+ymW+wCfbSzoYMRObIImMPWfoQtxkvvN rpkAnAtyEP/zZIfkQIuKTSH6FJxocF8V =WZt3 -----END PGP SIGNATURE----- Merge tag 'tty-3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty/serial driver updates from Greg KH: "Here's the big tty/serial driver update for 3.19-rc1. There are a number of TTY core changes/fixes in here from Peter Hurley that have all been teted in linux-next for a long time now. There are also the normal serial driver updates as well, full details in the changelog below" * tag 'tty-3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (219 commits) serial: pxa: hold port.lock when reporting modem line changes tty-hvsi_lib: Deletion of an unnecessary check before the function call "tty_kref_put" tty: Deletion of unnecessary checks before two function calls n_tty: Fix read_buf race condition, increment read_head after pushing data serial: of-serial: add PM suspend/resume support Revert "serial: of-serial: add PM suspend/resume support" Revert "serial: of-serial: fix up PM ops on no_console_suspend and port type" serial: 8250: don't attempt a trylock if in sysrq serial: core: Add big-endian iotype serial: samsung: use port->fifosize instead of hardcoded values serial: samsung: prefer to use fifosize from driver data serial: samsung: fix style problems serial: samsung: wait for transfer completion before clock disable serial: icom: fix error return code serial: tegra: clean up tty-flag assignments serial: Fix io address assign flow with Fintek PCI-to-UART Product serial: mxs-auart: fix tx_empty against shift register serial: mxs-auart: fix gpio change detection on interrupt serial: mxs-auart: Fix mxs_auart_set_ldisc() serial: 8250_dw: Use 64-bit access for OCTEON. ...
This commit is contained in:
commit
37da7bbbe8
|
@ -0,0 +1,30 @@
|
|||
* BCM63xx UART
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "brcm,bcm6345-uart"
|
||||
|
||||
- reg: The base address of the UART register bank.
|
||||
|
||||
- interrupts: A single interrupt specifier.
|
||||
|
||||
- clocks: Clock driving the hardware; used to figure out the baud rate
|
||||
divisor.
|
||||
|
||||
Example:
|
||||
|
||||
uart0: serial@14e00520 {
|
||||
compatible = "brcm,bcm6345-uart";
|
||||
reg = <0x14e00520 0x18>;
|
||||
interrupt-parent = <&periph_intc>;
|
||||
interrupts = <2>;
|
||||
clocks = <&periph_clk>;
|
||||
};
|
||||
|
||||
clocks {
|
||||
periph_clk: periph_clk@0 {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <54000000>;
|
||||
};
|
||||
};
|
|
@ -11,8 +11,13 @@ Required properties:
|
|||
- dma-names: "rx" for RX channel, "tx" for TX channel.
|
||||
|
||||
Optional properties:
|
||||
- fsl,uart-has-rtscts : Indicate the UART has RTS and CTS lines,
|
||||
- fsl,uart-has-rtscts : Indicate the UART has RTS and CTS lines
|
||||
for hardware flow control,
|
||||
it also means you enable the DMA support for this UART.
|
||||
- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD
|
||||
line respectively. It will use specified PIO instead of the peripheral
|
||||
function pin for the USART feature.
|
||||
If unsure, don't specify this property.
|
||||
|
||||
Example:
|
||||
auart0: serial@8006a000 {
|
||||
|
@ -21,6 +26,9 @@ auart0: serial@8006a000 {
|
|||
interrupts = <112>;
|
||||
dmas = <&dma_apbx 8>, <&dma_apbx 9>;
|
||||
dma-names = "rx", "tx";
|
||||
cts-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
|
||||
dsr-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>;
|
||||
dcd-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
Note: Each auart port should have an alias correctly numbered in "aliases"
|
||||
|
|
|
@ -10,6 +10,7 @@ Required properties:
|
|||
- "ns16850"
|
||||
- "nvidia,tegra20-uart"
|
||||
- "nxp,lpc3220-uart"
|
||||
- "ralink,rt2880-uart"
|
||||
- "ibm,qpace-nwp-serial"
|
||||
- "altr,16550-FIFO32"
|
||||
- "altr,16550-FIFO64"
|
||||
|
|
|
@ -6,23 +6,35 @@ Required properties:
|
|||
- interrupts: exactly one interrupt specifier
|
||||
|
||||
Optional properties:
|
||||
- pinctrl: When present, must have one state named "default",
|
||||
- pinctrl:
|
||||
When present, must have one state named "default",
|
||||
and may contain a second name named "sleep". The former
|
||||
state sets up pins for ordinary operation whereas
|
||||
the latter state will put the associated pins to sleep
|
||||
when the UART is unused
|
||||
- clocks: When present, the first clock listed must correspond to
|
||||
- clocks:
|
||||
When present, the first clock listed must correspond to
|
||||
the clock named UARTCLK on the IP block, i.e. the clock
|
||||
to the external serial line, whereas the second clock
|
||||
must correspond to the PCLK clocking the internal logic
|
||||
of the block. Just listing one clock (the first one) is
|
||||
deprecated.
|
||||
- clocks-names: When present, the first clock listed must be named
|
||||
- clocks-names:
|
||||
When present, the first clock listed must be named
|
||||
"uartclk" and the second clock listed must be named
|
||||
"apb_pclk"
|
||||
- dmas: When present, may have one or two dma channels.
|
||||
- dmas:
|
||||
When present, may have one or two dma channels.
|
||||
The first one must be named "rx", the second one
|
||||
must be named "tx".
|
||||
- auto-poll:
|
||||
Enables polling when using RX DMA.
|
||||
- poll-rate-ms:
|
||||
Rate at which poll occurs when auto-poll is set,
|
||||
default 100ms.
|
||||
- poll-timeout-ms:
|
||||
Poll timeout when auto-poll is set, default
|
||||
3000ms.
|
||||
|
||||
See also bindings/arm/primecell.txt
|
||||
|
||||
|
|
|
@ -27,27 +27,52 @@ Optional properties:
|
|||
- dmas: Should contain dma specifiers for transmit and receive channels
|
||||
- dma-names: Should contain "tx" for transmit and "rx" for receive channels
|
||||
|
||||
Note: Aliases may be defined to ensure the correct ordering of the UARTs.
|
||||
The alias serialN will result in the UART being assigned port N. If any
|
||||
serialN alias exists, then an alias must exist for each enabled UART. The
|
||||
serialN aliases should be in a .dts file instead of in a .dtsi file.
|
||||
|
||||
Examples:
|
||||
|
||||
A uartdm v1.4 device with dma capabilities.
|
||||
- A uartdm v1.4 device with dma capabilities.
|
||||
|
||||
serial@f991e000 {
|
||||
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
|
||||
reg = <0xf991e000 0x1000>;
|
||||
interrupts = <0 108 0x0>;
|
||||
clocks = <&blsp1_uart2_apps_cxc>, <&blsp1_ahb_cxc>;
|
||||
clock-names = "core", "iface";
|
||||
dmas = <&dma0 0>, <&dma0 1>;
|
||||
dma-names = "tx", "rx";
|
||||
};
|
||||
serial@f991e000 {
|
||||
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
|
||||
reg = <0xf991e000 0x1000>;
|
||||
interrupts = <0 108 0x0>;
|
||||
clocks = <&blsp1_uart2_apps_cxc>, <&blsp1_ahb_cxc>;
|
||||
clock-names = "core", "iface";
|
||||
dmas = <&dma0 0>, <&dma0 1>;
|
||||
dma-names = "tx", "rx";
|
||||
};
|
||||
|
||||
A uartdm v1.3 device without dma capabilities and part of a GSBI complex.
|
||||
- A uartdm v1.3 device without dma capabilities and part of a GSBI complex.
|
||||
|
||||
serial@19c40000 {
|
||||
compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
|
||||
reg = <0x19c40000 0x1000>,
|
||||
<0x19c00000 0x1000>;
|
||||
interrupts = <0 195 0x0>;
|
||||
clocks = <&gsbi5_uart_cxc>, <&gsbi5_ahb_cxc>;
|
||||
clock-names = "core", "iface";
|
||||
};
|
||||
serial@19c40000 {
|
||||
compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
|
||||
reg = <0x19c40000 0x1000>,
|
||||
<0x19c00000 0x1000>;
|
||||
interrupts = <0 195 0x0>;
|
||||
clocks = <&gsbi5_uart_cxc>, <&gsbi5_ahb_cxc>;
|
||||
clock-names = "core", "iface";
|
||||
};
|
||||
|
||||
- serialN alias.
|
||||
|
||||
aliases {
|
||||
serial0 = &uarta;
|
||||
serial1 = &uartc;
|
||||
serial2 = &uartb;
|
||||
};
|
||||
|
||||
uarta: serial@12490000 {
|
||||
status = "ok";
|
||||
};
|
||||
|
||||
uartb: serial@16340000 {
|
||||
status = "ok";
|
||||
};
|
||||
|
||||
uartc: serial@1a240000 {
|
||||
status = "ok";
|
||||
};
|
||||
|
|
|
@ -4,8 +4,7 @@ Required properties:
|
|||
|
||||
- compatible: Must contain one of the following:
|
||||
|
||||
- "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART.
|
||||
- "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART.
|
||||
- "renesas,scif-r7s72100" for R7S72100 (RZ/A1H) SCIF compatible UART.
|
||||
- "renesas,scifa-r8a73a4" for R8A73A4 (R-Mobile APE6) SCIFA compatible UART.
|
||||
- "renesas,scifb-r8a73a4" for R8A73A4 (R-Mobile APE6) SCIFB compatible UART.
|
||||
- "renesas,scifa-r8a7740" for R8A7740 (R-Mobile A1) SCIFA compatible UART.
|
||||
|
@ -20,6 +19,12 @@ Required properties:
|
|||
- "renesas,scifa-r8a7791" for R8A7791 (R-Car M2) SCIFA compatible UART.
|
||||
- "renesas,scifb-r8a7791" for R8A7791 (R-Car M2) SCIFB compatible UART.
|
||||
- "renesas,hscif-r8a7791" for R8A7791 (R-Car M2) HSCIF compatible UART.
|
||||
- "renesas,scif-r8a7794" for R8A7794 (R-Car E2) SCIF compatible UART.
|
||||
- "renesas,scifa-r8a7794" for R8A7794 (R-Car E2) SCIFA compatible UART.
|
||||
- "renesas,scifb-r8a7794" for R8A7794 (R-Car E2) SCIFB compatible UART.
|
||||
- "renesas,hscif-r8a7794" for R8A7794 (R-Car E2) HSCIF compatible UART.
|
||||
- "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART.
|
||||
- "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART.
|
||||
- "renesas,scif" for generic SCIF compatible UART.
|
||||
- "renesas,scifa" for generic SCIFA compatible UART.
|
||||
- "renesas,scifb" for generic SCIFB compatible UART.
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
* CSR SiRFprimaII/atlasVI Universal Synchronous Asynchronous Receiver/Transmitter *
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "sirf,prima2-uart" or "sirf, prima2-usp-uart"
|
||||
- compatible : Should be "sirf,prima2-uart", "sirf, prima2-usp-uart",
|
||||
"sirf,marco-uart" or "sirf,marco-bt-uart" which means
|
||||
uart located in BT module and used for BT.
|
||||
- reg : Offset and length of the register set for the device
|
||||
- interrupts : Should contain uart interrupt
|
||||
- fifosize : Should define hardware rx/tx fifo size
|
||||
|
@ -31,3 +33,15 @@ usp@b0090000 {
|
|||
rts-gpios = <&gpio 15 0>;
|
||||
cts-gpios = <&gpio 46 0>;
|
||||
};
|
||||
|
||||
for uart use in BT module,
|
||||
uart6: uart@11000000 {
|
||||
cell-index = <6>;
|
||||
compatible = "sirf,marco-bt-uart", "sirf,marco-uart";
|
||||
reg = <0x11000000 0x1000>;
|
||||
interrupts = <0 100 0>;
|
||||
clocks = <&clks 138>, <&clks 140>, <&clks 141>;
|
||||
clock-names = "uart", "general", "noc";
|
||||
fifosize = <128>;
|
||||
status = "disabled";
|
||||
}
|
||||
|
|
|
@ -59,7 +59,9 @@ The core driver uses the info->tmpbuf_sem lock to prevent multi-threaded
|
|||
access to the info->tmpbuf bouncebuffer used for port writes.
|
||||
|
||||
The port_sem semaphore is used to protect against ports being added/
|
||||
removed or reconfigured at inappropriate times.
|
||||
removed or reconfigured at inappropriate times. Since v2.6.27, this
|
||||
semaphore has been the 'mutex' member of the tty_port struct, and
|
||||
commonly referred to as the port mutex (or port->mutex).
|
||||
|
||||
|
||||
uart_ops
|
||||
|
@ -248,7 +250,7 @@ hardware.
|
|||
Other flags may be used (eg, xon/xoff characters) if your
|
||||
hardware supports hardware "soft" flow control.
|
||||
|
||||
Locking: none.
|
||||
Locking: caller holds port->mutex
|
||||
Interrupts: caller dependent.
|
||||
This call must not sleep
|
||||
|
||||
|
|
|
@ -8026,6 +8026,12 @@ S: Maintained
|
|||
F: Documentation/serial/rocket.txt
|
||||
F: drivers/tty/rocket*
|
||||
|
||||
ROCKETPORT EXPRESS/INFINITY DRIVER
|
||||
M: Kevin Cernekee <cernekee@gmail.com>
|
||||
L: linux-serial@vger.kernel.org
|
||||
S: Odd Fixes
|
||||
F: drivers/tty/serial/rp2.*
|
||||
|
||||
ROSE NETWORK LAYER
|
||||
M: Ralf Baechle <ralf@linux-mips.org>
|
||||
L: linux-hams@vger.kernel.org
|
||||
|
|
|
@ -9,8 +9,11 @@
|
|||
#ifndef __BFIN_ASM_SERIAL_H__
|
||||
#define __BFIN_ASM_SERIAL_H__
|
||||
|
||||
#include <linux/circ_buf.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <mach/anomaly.h>
|
||||
#include <mach/bfin_serial.h>
|
||||
|
||||
|
@ -25,10 +28,6 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
struct circ_buf;
|
||||
struct timer_list;
|
||||
struct work_struct;
|
||||
|
||||
struct bfin_serial_port {
|
||||
struct uart_port port;
|
||||
unsigned int old_status;
|
||||
|
|
|
@ -632,6 +632,7 @@ static irqreturn_t winch_interrupt(int irq, void *data)
|
|||
int fd = winch->fd;
|
||||
int err;
|
||||
char c;
|
||||
struct pid *pgrp;
|
||||
|
||||
if (fd != -1) {
|
||||
err = generic_read(fd, &c, NULL);
|
||||
|
@ -657,7 +658,10 @@ static irqreturn_t winch_interrupt(int irq, void *data)
|
|||
if (line != NULL) {
|
||||
chan_window_size(line, &tty->winsize.ws_row,
|
||||
&tty->winsize.ws_col);
|
||||
kill_pgrp(tty->pgrp, SIGWINCH, 1);
|
||||
pgrp = tty_get_pgrp(tty);
|
||||
if (pgrp)
|
||||
kill_pgrp(pgrp, SIGWINCH, 1);
|
||||
put_pid(pgrp);
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ enum parport_pc_pci_cards {
|
|||
timedia_9079c,
|
||||
wch_ch353_1s1p,
|
||||
wch_ch353_2s1p,
|
||||
wch_ch382_2s1p,
|
||||
sunix_2s1p,
|
||||
};
|
||||
|
||||
|
@ -151,6 +152,7 @@ static struct parport_pc_pci cards[] = {
|
|||
/* timedia_9079c */ { 1, { { 2, 3 }, } },
|
||||
/* wch_ch353_1s1p*/ { 1, { { 1, -1}, } },
|
||||
/* wch_ch353_2s1p*/ { 1, { { 2, -1}, } },
|
||||
/* wch_ch382_2s1p*/ { 1, { { 2, -1}, } },
|
||||
/* sunix_2s1p */ { 1, { { 3, -1 }, } },
|
||||
};
|
||||
|
||||
|
@ -257,6 +259,7 @@ static struct pci_device_id parport_serial_pci_tbl[] = {
|
|||
/* WCH CARDS */
|
||||
{ 0x4348, 0x5053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, wch_ch353_1s1p},
|
||||
{ 0x4348, 0x7053, 0x4348, 0x3253, 0, 0, wch_ch353_2s1p},
|
||||
{ 0x1c00, 0x3250, 0x1c00, 0x3250, 0, 0, wch_ch382_2s1p},
|
||||
|
||||
/*
|
||||
* More SUNIX variations. At least one of these has part number
|
||||
|
@ -494,6 +497,13 @@ static struct pciserial_board pci_parport_serial_boards[] = {
|
|||
.base_baud = 115200,
|
||||
.uart_offset = 8,
|
||||
},
|
||||
[wch_ch382_2s1p] = {
|
||||
.flags = FL_BASE0,
|
||||
.num_ports = 2,
|
||||
.base_baud = 115200,
|
||||
.uart_offset = 8,
|
||||
.first_offset = 0xC0,
|
||||
},
|
||||
[sunix_2s1p] = {
|
||||
.flags = FL_BASE0|FL_BASE_BARS,
|
||||
.num_ports = 2,
|
||||
|
|
|
@ -309,8 +309,8 @@ static int __init ehv_bc_console_init(void)
|
|||
* handle for udbg.
|
||||
*/
|
||||
if (stdout_bc != CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE)
|
||||
pr_warning("ehv-bc: udbg handle %u is not the stdout handle\n",
|
||||
CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE);
|
||||
pr_warn("ehv-bc: udbg handle %u is not the stdout handle\n",
|
||||
CONFIG_PPC_EARLY_DEBUG_EHV_BC_HANDLE);
|
||||
#endif
|
||||
|
||||
/* add_preferred_console() must be called before register_console(),
|
||||
|
|
|
@ -155,9 +155,9 @@ static struct tty_driver *goldfish_tty_console_device(struct console *c,
|
|||
|
||||
static int goldfish_tty_console_setup(struct console *co, char *options)
|
||||
{
|
||||
if ((unsigned)co->index > goldfish_tty_line_count)
|
||||
if ((unsigned)co->index >= goldfish_tty_line_count)
|
||||
return -ENODEV;
|
||||
if (goldfish_ttys[co->index].base == 0)
|
||||
if (!goldfish_ttys[co->index].base)
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
}
|
||||
|
@ -317,7 +317,7 @@ static int goldfish_tty_remove(struct platform_device *pdev)
|
|||
unregister_console(&qtty->console);
|
||||
tty_unregister_device(goldfish_tty_driver, pdev->id);
|
||||
iounmap(qtty->base);
|
||||
qtty->base = 0;
|
||||
qtty->base = NULL;
|
||||
free_irq(qtty->irq, pdev);
|
||||
goldfish_tty_current_line_count--;
|
||||
if (goldfish_tty_current_line_count == 0)
|
||||
|
|
|
@ -1575,7 +1575,7 @@ static int __init hvcs_module_init(void)
|
|||
*/
|
||||
rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan);
|
||||
if (rc)
|
||||
pr_warning(KERN_ERR "HVCS: Failed to create rescan file (err %d)\n", rc);
|
||||
pr_warning("HVCS: Failed to create rescan file (err %d)\n", rc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -405,8 +405,7 @@ void hvsilib_close(struct hvsi_priv *pv, struct hvc_struct *hp)
|
|||
hvsi_send_close(pv);
|
||||
}
|
||||
|
||||
if (pv->tty)
|
||||
tty_kref_put(pv->tty);
|
||||
tty_kref_put(pv->tty);
|
||||
pv->tty = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -378,9 +378,9 @@ static void swap_packet_bitfield_to_le(unsigned char *data)
|
|||
/*
|
||||
* transform bits from aa.bbb.ccc to ccc.bbb.aa
|
||||
*/
|
||||
ret |= tmp & 0xc0 >> 6;
|
||||
ret |= tmp & 0x38 >> 1;
|
||||
ret |= tmp & 0x07 << 5;
|
||||
ret |= (tmp & 0xc0) >> 6;
|
||||
ret |= (tmp & 0x38) >> 1;
|
||||
ret |= (tmp & 0x07) << 5;
|
||||
*data = ret & 0xff;
|
||||
#endif
|
||||
}
|
||||
|
@ -393,9 +393,9 @@ static void swap_packet_bitfield_from_le(unsigned char *data)
|
|||
/*
|
||||
* transform bits from ccc.bbb.aa to aa.bbb.ccc
|
||||
*/
|
||||
ret |= tmp & 0xe0 >> 5;
|
||||
ret |= tmp & 0x1c << 1;
|
||||
ret |= tmp & 0x03 << 6;
|
||||
ret |= (tmp & 0xe0) >> 5;
|
||||
ret |= (tmp & 0x1c) << 1;
|
||||
ret |= (tmp & 0x03) << 6;
|
||||
*data = ret & 0xff;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -249,7 +249,7 @@ static int lock_card(struct isi_board *card)
|
|||
spin_unlock_irqrestore(&card->card_lock, card->flags);
|
||||
msleep(10);
|
||||
}
|
||||
pr_warning("Failed to lock Card (0x%lx)\n", card->base);
|
||||
pr_warn("Failed to lock Card (0x%lx)\n", card->base);
|
||||
|
||||
return 0; /* Failed to acquire the card! */
|
||||
}
|
||||
|
@ -378,13 +378,13 @@ static inline int __isicom_paranoia_check(struct isi_port const *port,
|
|||
char *name, const char *routine)
|
||||
{
|
||||
if (!port) {
|
||||
pr_warning("Warning: bad isicom magic for dev %s in %s.\n",
|
||||
name, routine);
|
||||
pr_warn("Warning: bad isicom magic for dev %s in %s\n",
|
||||
name, routine);
|
||||
return 1;
|
||||
}
|
||||
if (port->magic != ISICOM_MAGIC) {
|
||||
pr_warning("Warning: NULL isicom port for dev %s in %s.\n",
|
||||
name, routine);
|
||||
pr_warn("Warning: NULL isicom port for dev %s in %s\n",
|
||||
name, routine);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -546,8 +546,8 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
|
|||
byte_count = header & 0xff;
|
||||
|
||||
if (channel + 1 > card->port_count) {
|
||||
pr_warning("%s(0x%lx): %d(channel) > port_count.\n",
|
||||
__func__, base, channel+1);
|
||||
pr_warn("%s(0x%lx): %d(channel) > port_count\n",
|
||||
__func__, base, channel + 1);
|
||||
outw(0x0000, base+0x04); /* enable interrupts */
|
||||
spin_unlock(&card->card_lock);
|
||||
return IRQ_HANDLED;
|
||||
|
|
|
@ -321,7 +321,8 @@ static void n_tty_check_unthrottle(struct tty_struct *tty)
|
|||
|
||||
static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
|
||||
{
|
||||
*read_buf_addr(ldata, ldata->read_head++) = c;
|
||||
*read_buf_addr(ldata, ldata->read_head) = c;
|
||||
ldata->read_head++;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -351,13 +352,13 @@ static void n_tty_packet_mode_flush(struct tty_struct *tty)
|
|||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
if (tty->link->packet) {
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
tty->ctrl_status |= TIOCPKT_FLUSHREAD;
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
if (waitqueue_active(&tty->link->read_wait))
|
||||
wake_up_interruptible(&tty->link->read_wait);
|
||||
}
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2128,7 +2129,6 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
|||
int minimum, time;
|
||||
ssize_t retval = 0;
|
||||
long timeout;
|
||||
unsigned long flags;
|
||||
int packet;
|
||||
|
||||
c = job_control(tty, file);
|
||||
|
@ -2174,10 +2174,10 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
|||
unsigned char cs;
|
||||
if (b != buf)
|
||||
break;
|
||||
spin_lock_irqsave(&tty->link->ctrl_lock, flags);
|
||||
spin_lock_irq(&tty->link->ctrl_lock);
|
||||
cs = tty->link->ctrl_status;
|
||||
tty->link->ctrl_status = 0;
|
||||
spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
|
||||
spin_unlock_irq(&tty->link->ctrl_lock);
|
||||
if (tty_put_user(tty, cs, b++)) {
|
||||
retval = -EFAULT;
|
||||
b--;
|
||||
|
@ -2193,45 +2193,29 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
|||
|
||||
if (!input_available_p(tty, 0)) {
|
||||
if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
|
||||
up_read(&tty->termios_rwsem);
|
||||
tty_flush_to_ldisc(tty);
|
||||
down_read(&tty->termios_rwsem);
|
||||
if (!input_available_p(tty, 0)) {
|
||||
retval = -EIO;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (tty_hung_up_p(file))
|
||||
break;
|
||||
if (!timeout)
|
||||
break;
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
retval = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
if (signal_pending(current)) {
|
||||
retval = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
n_tty_set_room(tty);
|
||||
up_read(&tty->termios_rwsem);
|
||||
|
||||
timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
|
||||
timeout);
|
||||
|
||||
down_read(&tty->termios_rwsem);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Deal with packet mode. */
|
||||
if (packet && b == buf) {
|
||||
if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
|
||||
retval = -EFAULT;
|
||||
b--;
|
||||
retval = -EIO;
|
||||
break;
|
||||
}
|
||||
nr--;
|
||||
if (tty_hung_up_p(file))
|
||||
break;
|
||||
if (!timeout)
|
||||
break;
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
retval = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
if (signal_pending(current)) {
|
||||
retval = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
n_tty_set_room(tty);
|
||||
up_read(&tty->termios_rwsem);
|
||||
|
||||
timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
|
||||
timeout);
|
||||
|
||||
down_read(&tty->termios_rwsem);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ldata->icanon && !L_EXTPROC(tty)) {
|
||||
|
@ -2243,8 +2227,17 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
|||
break;
|
||||
} else {
|
||||
int uncopied;
|
||||
/* The copy function takes the read lock and handles
|
||||
locking internally for this case */
|
||||
|
||||
/* Deal with packet mode. */
|
||||
if (packet && b == buf) {
|
||||
if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
|
||||
retval = -EFAULT;
|
||||
b--;
|
||||
break;
|
||||
}
|
||||
nr--;
|
||||
}
|
||||
|
||||
uncopied = copy_from_read_buf(tty, &b, &nr);
|
||||
uncopied += copy_from_read_buf(tty, &b, &nr);
|
||||
if (uncopied) {
|
||||
|
|
|
@ -47,10 +47,13 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
|
|||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
wake_up_interruptible(&tty->read_wait);
|
||||
wake_up_interruptible(&tty->write_wait);
|
||||
spin_lock_irq(&tty->ctrl_lock);
|
||||
tty->packet = 0;
|
||||
spin_unlock_irq(&tty->ctrl_lock);
|
||||
/* Review - krefs on tty_link ?? */
|
||||
if (!tty->link)
|
||||
return;
|
||||
tty_flush_to_ldisc(tty->link);
|
||||
set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
|
||||
wake_up_interruptible(&tty->link->read_wait);
|
||||
wake_up_interruptible(&tty->link->write_wait);
|
||||
|
@ -64,9 +67,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
|
|||
mutex_unlock(&devpts_mutex);
|
||||
}
|
||||
#endif
|
||||
tty_unlock(tty);
|
||||
tty_vhangup(tty->link);
|
||||
tty_lock(tty);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,21 +179,21 @@ static int pty_get_lock(struct tty_struct *tty, int __user *arg)
|
|||
/* Set the packet mode on a pty */
|
||||
static int pty_set_pktmode(struct tty_struct *tty, int __user *arg)
|
||||
{
|
||||
unsigned long flags;
|
||||
int pktmode;
|
||||
|
||||
if (get_user(pktmode, arg))
|
||||
return -EFAULT;
|
||||
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
spin_lock_irq(&tty->ctrl_lock);
|
||||
if (pktmode) {
|
||||
if (!tty->packet) {
|
||||
tty->packet = 1;
|
||||
tty->link->ctrl_status = 0;
|
||||
smp_mb();
|
||||
tty->packet = 1;
|
||||
}
|
||||
} else
|
||||
tty->packet = 0;
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
spin_unlock_irq(&tty->ctrl_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -207,15 +208,12 @@ static int pty_get_pktmode(struct tty_struct *tty, int __user *arg)
|
|||
/* Send a signal to the slave */
|
||||
static int pty_signal(struct tty_struct *tty, int sig)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct pid *pgrp;
|
||||
|
||||
if (tty->link) {
|
||||
spin_lock_irqsave(&tty->link->ctrl_lock, flags);
|
||||
pgrp = get_pid(tty->link->pgrp);
|
||||
spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
|
||||
|
||||
kill_pgrp(pgrp, sig, 1);
|
||||
pgrp = tty_get_pgrp(tty->link);
|
||||
if (pgrp)
|
||||
kill_pgrp(pgrp, sig, 1);
|
||||
put_pid(pgrp);
|
||||
}
|
||||
return 0;
|
||||
|
@ -224,16 +222,15 @@ static int pty_signal(struct tty_struct *tty, int sig)
|
|||
static void pty_flush_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct tty_struct *to = tty->link;
|
||||
unsigned long flags;
|
||||
|
||||
if (!to)
|
||||
return;
|
||||
/* tty_buffer_flush(to); FIXME */
|
||||
if (to->packet) {
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
spin_lock_irq(&tty->ctrl_lock);
|
||||
tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
|
||||
wake_up_interruptible(&to->read_wait);
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
spin_unlock_irq(&tty->ctrl_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,6 +259,32 @@ out:
|
|||
static void pty_set_termios(struct tty_struct *tty,
|
||||
struct ktermios *old_termios)
|
||||
{
|
||||
/* See if packet mode change of state. */
|
||||
if (tty->link && tty->link->packet) {
|
||||
int extproc = (old_termios->c_lflag & EXTPROC) |
|
||||
(tty->termios.c_lflag & EXTPROC);
|
||||
int old_flow = ((old_termios->c_iflag & IXON) &&
|
||||
(old_termios->c_cc[VSTOP] == '\023') &&
|
||||
(old_termios->c_cc[VSTART] == '\021'));
|
||||
int new_flow = (I_IXON(tty) &&
|
||||
STOP_CHAR(tty) == '\023' &&
|
||||
START_CHAR(tty) == '\021');
|
||||
if ((old_flow != new_flow) || extproc) {
|
||||
spin_lock_irq(&tty->ctrl_lock);
|
||||
if (old_flow != new_flow) {
|
||||
tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
|
||||
if (new_flow)
|
||||
tty->ctrl_status |= TIOCPKT_DOSTOP;
|
||||
else
|
||||
tty->ctrl_status |= TIOCPKT_NOSTOP;
|
||||
}
|
||||
if (extproc)
|
||||
tty->ctrl_status |= TIOCPKT_IOCTL;
|
||||
spin_unlock_irq(&tty->ctrl_lock);
|
||||
wake_up_interruptible(&tty->link->read_wait);
|
||||
}
|
||||
}
|
||||
|
||||
tty->termios.c_cflag &= ~(CSIZE | PARENB);
|
||||
tty->termios.c_cflag |= (CS8 | CREAD);
|
||||
}
|
||||
|
@ -278,7 +301,6 @@ static void pty_set_termios(struct tty_struct *tty,
|
|||
static int pty_resize(struct tty_struct *tty, struct winsize *ws)
|
||||
{
|
||||
struct pid *pgrp, *rpgrp;
|
||||
unsigned long flags;
|
||||
struct tty_struct *pty = tty->link;
|
||||
|
||||
/* For a PTY we need to lock the tty side */
|
||||
|
@ -286,17 +308,9 @@ static int pty_resize(struct tty_struct *tty, struct winsize *ws)
|
|||
if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
|
||||
goto done;
|
||||
|
||||
/* Get the PID values and reference them so we can
|
||||
avoid holding the tty ctrl lock while sending signals.
|
||||
We need to lock these individually however. */
|
||||
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
pgrp = get_pid(tty->pgrp);
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
|
||||
spin_lock_irqsave(&pty->ctrl_lock, flags);
|
||||
rpgrp = get_pid(pty->pgrp);
|
||||
spin_unlock_irqrestore(&pty->ctrl_lock, flags);
|
||||
/* Signal the foreground process group of both ptys */
|
||||
pgrp = tty_get_pgrp(tty);
|
||||
rpgrp = tty_get_pgrp(pty);
|
||||
|
||||
if (pgrp)
|
||||
kill_pgrp(pgrp, SIGWINCH, 1);
|
||||
|
@ -327,26 +341,26 @@ static void pty_start(struct tty_struct *tty)
|
|||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
if (tty->link && tty->link->packet) {
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
tty->ctrl_status &= ~TIOCPKT_STOP;
|
||||
tty->ctrl_status |= TIOCPKT_START;
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
|
||||
}
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
}
|
||||
|
||||
static void pty_stop(struct tty_struct *tty)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
if (tty->link && tty->link->packet) {
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
tty->ctrl_status &= ~TIOCPKT_START;
|
||||
tty->ctrl_status |= TIOCPKT_STOP;
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
|
||||
}
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -368,6 +382,10 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
|
|||
int idx = tty->index;
|
||||
int retval = -ENOMEM;
|
||||
|
||||
/* Opening the slave first has always returned -EIO */
|
||||
if (driver->subtype != PTY_TYPE_MASTER)
|
||||
return -EIO;
|
||||
|
||||
ports[0] = kmalloc(sizeof **ports, GFP_KERNEL);
|
||||
ports[1] = kmalloc(sizeof **ports, GFP_KERNEL);
|
||||
if (!ports[0] || !ports[1])
|
||||
|
@ -380,6 +398,8 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
|
|||
if (!o_tty)
|
||||
goto err_put_module;
|
||||
|
||||
tty_set_lock_subclass(o_tty);
|
||||
|
||||
if (legacy) {
|
||||
/* We always use new tty termios data so we can do this
|
||||
the easy way .. */
|
||||
|
@ -404,8 +424,6 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
|
|||
* Everything allocated ... set up the o_tty structure.
|
||||
*/
|
||||
tty_driver_kref_get(driver->other);
|
||||
if (driver->subtype == PTY_TYPE_MASTER)
|
||||
o_tty->count++;
|
||||
/* Establish the links in both directions */
|
||||
tty->link = o_tty;
|
||||
o_tty->link = tty;
|
||||
|
@ -417,6 +435,7 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
|
|||
|
||||
tty_driver_kref_get(driver);
|
||||
tty->count++;
|
||||
o_tty->count++;
|
||||
return 0;
|
||||
err_free_termios:
|
||||
if (legacy)
|
||||
|
@ -489,7 +508,6 @@ static const struct tty_operations master_pty_ops_bsd = {
|
|||
.flush_buffer = pty_flush_buffer,
|
||||
.chars_in_buffer = pty_chars_in_buffer,
|
||||
.unthrottle = pty_unthrottle,
|
||||
.set_termios = pty_set_termios,
|
||||
.ioctl = pty_bsd_ioctl,
|
||||
.cleanup = pty_cleanup,
|
||||
.resize = pty_resize,
|
||||
|
@ -666,7 +684,6 @@ static const struct tty_operations ptm_unix98_ops = {
|
|||
.flush_buffer = pty_flush_buffer,
|
||||
.chars_in_buffer = pty_chars_in_buffer,
|
||||
.unthrottle = pty_unthrottle,
|
||||
.set_termios = pty_set_termios,
|
||||
.ioctl = pty_unix98_ioctl,
|
||||
.resize = pty_resize,
|
||||
.shutdown = pty_unix98_shutdown,
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
#include <linux/dmaengine.h>
|
||||
|
||||
struct uart_8250_dma {
|
||||
int (*tx_dma)(struct uart_8250_port *p);
|
||||
int (*rx_dma)(struct uart_8250_port *p, unsigned int iir);
|
||||
|
||||
/* Filter function */
|
||||
dma_filter_fn fn;
|
||||
|
||||
|
@ -41,6 +44,8 @@ struct uart_8250_dma {
|
|||
size_t tx_size;
|
||||
|
||||
unsigned char tx_running:1;
|
||||
unsigned char tx_err: 1;
|
||||
unsigned char rx_running:1;
|
||||
};
|
||||
|
||||
struct old_serial_port {
|
||||
|
@ -51,7 +56,7 @@ struct old_serial_port {
|
|||
unsigned int flags;
|
||||
unsigned char hub6;
|
||||
unsigned char io_type;
|
||||
unsigned char *iomem_base;
|
||||
unsigned char __iomem *iomem_base;
|
||||
unsigned short iomem_reg_shift;
|
||||
unsigned long irqflags;
|
||||
};
|
||||
|
@ -114,6 +119,8 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value)
|
|||
}
|
||||
|
||||
struct uart_8250_port *serial8250_get_port(int line);
|
||||
void serial8250_rpm_get(struct uart_8250_port *p);
|
||||
void serial8250_rpm_put(struct uart_8250_port *p);
|
||||
|
||||
#if defined(__alpha__) && !defined(CONFIG_PCI)
|
||||
/*
|
||||
|
|
|
@ -541,23 +541,25 @@ void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
|
||||
|
||||
static void serial8250_rpm_get(struct uart_8250_port *p)
|
||||
void serial8250_rpm_get(struct uart_8250_port *p)
|
||||
{
|
||||
if (!(p->capabilities & UART_CAP_RPM))
|
||||
return;
|
||||
pm_runtime_get_sync(p->port.dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_rpm_get);
|
||||
|
||||
static void serial8250_rpm_put(struct uart_8250_port *p)
|
||||
void serial8250_rpm_put(struct uart_8250_port *p)
|
||||
{
|
||||
if (!(p->capabilities & UART_CAP_RPM))
|
||||
return;
|
||||
pm_runtime_mark_last_busy(p->port.dev);
|
||||
pm_runtime_put_autosuspend(p->port.dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_rpm_put);
|
||||
|
||||
/*
|
||||
* This two wrapper ensure, that enable_runtime_pm_tx() can be called more than
|
||||
* These two wrappers ensure that enable_runtime_pm_tx() can be called more than
|
||||
* once and disable_runtime_pm_tx() will still disable RPM because the fifo is
|
||||
* empty and the HW can idle again.
|
||||
*/
|
||||
|
@ -595,6 +597,7 @@ static void serial8250_rpm_put_tx(struct uart_8250_port *p)
|
|||
*/
|
||||
static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
|
||||
{
|
||||
unsigned char lcr = 0, efr = 0;
|
||||
/*
|
||||
* Exar UARTs have a SLEEP register that enables or disables
|
||||
* each UART to enter sleep mode separately. On the XR17V35x the
|
||||
|
@ -611,6 +614,8 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
|
|||
|
||||
if (p->capabilities & UART_CAP_SLEEP) {
|
||||
if (p->capabilities & UART_CAP_EFR) {
|
||||
lcr = serial_in(p, UART_LCR);
|
||||
efr = serial_in(p, UART_EFR);
|
||||
serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B);
|
||||
serial_out(p, UART_EFR, UART_EFR_ECB);
|
||||
serial_out(p, UART_LCR, 0);
|
||||
|
@ -618,8 +623,8 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
|
|||
serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0);
|
||||
if (p->capabilities & UART_CAP_EFR) {
|
||||
serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B);
|
||||
serial_out(p, UART_EFR, 0);
|
||||
serial_out(p, UART_LCR, 0);
|
||||
serial_out(p, UART_EFR, efr);
|
||||
serial_out(p, UART_LCR, lcr);
|
||||
}
|
||||
}
|
||||
out:
|
||||
|
@ -1350,7 +1355,7 @@ static void serial8250_start_tx(struct uart_port *port)
|
|||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
|
||||
serial8250_rpm_get_tx(up);
|
||||
if (up->dma && !serial8250_tx_dma(up)) {
|
||||
if (up->dma && !up->dma->tx_dma(up)) {
|
||||
return;
|
||||
} else if (!(up->ier & UART_IER_THRI)) {
|
||||
up->ier |= UART_IER_THRI;
|
||||
|
@ -1397,6 +1402,19 @@ static void serial8250_stop_rx(struct uart_port *port)
|
|||
serial8250_rpm_put(up);
|
||||
}
|
||||
|
||||
static void serial8250_disable_ms(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up =
|
||||
container_of(port, struct uart_8250_port, port);
|
||||
|
||||
/* no MSR capabilities */
|
||||
if (up->bugs & UART_BUG_NOMSR)
|
||||
return;
|
||||
|
||||
up->ier &= ~UART_IER_MSI;
|
||||
serial_port_out(port, UART_IER, up->ier);
|
||||
}
|
||||
|
||||
static void serial8250_enable_ms(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
|
@ -1483,7 +1501,7 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
|
|||
|
||||
ignore_char:
|
||||
lsr = serial_in(up, UART_LSR);
|
||||
} while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
|
||||
} while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (--max_count > 0));
|
||||
spin_unlock(&port->lock);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
spin_lock(&port->lock);
|
||||
|
@ -1532,7 +1550,7 @@ void serial8250_tx_chars(struct uart_8250_port *up)
|
|||
DEBUG_INTR("THRE...");
|
||||
|
||||
/*
|
||||
* With RPM enabled, we have to wait once the FIFO is empty before the
|
||||
* With RPM enabled, we have to wait until the FIFO is empty before the
|
||||
* HW can go idle. So we get here once again with empty FIFO and disable
|
||||
* the interrupt and RPM in __stop_tx()
|
||||
*/
|
||||
|
@ -1588,13 +1606,14 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
|
|||
|
||||
if (status & (UART_LSR_DR | UART_LSR_BI)) {
|
||||
if (up->dma)
|
||||
dma_err = serial8250_rx_dma(up, iir);
|
||||
dma_err = up->dma->rx_dma(up, iir);
|
||||
|
||||
if (!up->dma || dma_err)
|
||||
status = serial8250_rx_chars(up, status);
|
||||
}
|
||||
serial8250_modem_status(up);
|
||||
if (!up->dma && (status & UART_LSR_THRE))
|
||||
if ((!up->dma || (up->dma && up->dma->tx_err)) &&
|
||||
(status & UART_LSR_THRE))
|
||||
serial8250_tx_chars(up);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
@ -2603,13 +2622,21 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
}
|
||||
|
||||
static void
|
||||
serial8250_set_ldisc(struct uart_port *port, int new)
|
||||
serial8250_set_ldisc(struct uart_port *port, struct ktermios *termios)
|
||||
{
|
||||
if (new == N_PPS) {
|
||||
if (termios->c_line == N_PPS) {
|
||||
port->flags |= UPF_HARDPPS_CD;
|
||||
spin_lock_irq(&port->lock);
|
||||
serial8250_enable_ms(port);
|
||||
} else
|
||||
spin_unlock_irq(&port->lock);
|
||||
} else {
|
||||
port->flags &= ~UPF_HARDPPS_CD;
|
||||
if (!UART_ENABLE_MS(port, termios->c_cflag)) {
|
||||
spin_lock_irq(&port->lock);
|
||||
serial8250_disable_ms(port);
|
||||
spin_unlock_irq(&port->lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -2634,8 +2661,11 @@ serial8250_pm(struct uart_port *port, unsigned int state,
|
|||
|
||||
static unsigned int serial8250_port_size(struct uart_8250_port *pt)
|
||||
{
|
||||
if (pt->port.iotype == UPIO_AU)
|
||||
if (pt->port.iotype == UPIO_AU) {
|
||||
if (pt->port.type == PORT_RT2880)
|
||||
return 0x100;
|
||||
return 0x1000;
|
||||
}
|
||||
if (is_omap1_8250(pt))
|
||||
return 0x16 << pt->port.regshift;
|
||||
|
||||
|
@ -2975,42 +3005,6 @@ serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int serial8250_ioctl(struct uart_port *port, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct uart_8250_port *up =
|
||||
container_of(port, struct uart_8250_port, port);
|
||||
int ret;
|
||||
struct serial_rs485 rs485_config;
|
||||
|
||||
if (!up->rs485_config)
|
||||
return -ENOIOCTLCMD;
|
||||
|
||||
switch (cmd) {
|
||||
case TIOCSRS485:
|
||||
if (copy_from_user(&rs485_config, (void __user *)arg,
|
||||
sizeof(rs485_config)))
|
||||
return -EFAULT;
|
||||
|
||||
ret = up->rs485_config(up, &rs485_config);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memcpy(&up->rs485, &rs485_config, sizeof(rs485_config));
|
||||
|
||||
return 0;
|
||||
case TIOCGRS485:
|
||||
if (copy_to_user((void __user *)arg, &up->rs485,
|
||||
sizeof(up->rs485)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
static const char *
|
||||
serial8250_type(struct uart_port *port)
|
||||
{
|
||||
|
@ -3042,7 +3036,6 @@ static struct uart_ops serial8250_pops = {
|
|||
.request_port = serial8250_request_port,
|
||||
.config_port = serial8250_config_port,
|
||||
.verify_port = serial8250_verify_port,
|
||||
.ioctl = serial8250_ioctl,
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_get_char = serial8250_get_poll_char,
|
||||
.poll_put_char = serial8250_put_poll_char,
|
||||
|
@ -3198,7 +3191,9 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
|
|||
|
||||
serial8250_rpm_get(up);
|
||||
|
||||
if (port->sysrq || oops_in_progress)
|
||||
if (port->sysrq)
|
||||
locked = 0;
|
||||
else if (oops_in_progress)
|
||||
locked = spin_trylock_irqsave(&port->lock, flags);
|
||||
else
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
@ -3237,7 +3232,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
|
|||
serial8250_rpm_put(up);
|
||||
}
|
||||
|
||||
static int __init serial8250_console_setup(struct console *co, char *options)
|
||||
static int serial8250_console_setup(struct console *co, char *options)
|
||||
{
|
||||
struct uart_port *port;
|
||||
int baud = 9600;
|
||||
|
@ -3585,10 +3580,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
|||
uart->port.fifosize = up->port.fifosize;
|
||||
uart->tx_loadsz = up->tx_loadsz;
|
||||
uart->capabilities = up->capabilities;
|
||||
uart->rs485_config = up->rs485_config;
|
||||
uart->rs485 = up->rs485;
|
||||
uart->port.throttle = up->port.throttle;
|
||||
uart->port.unthrottle = up->port.unthrottle;
|
||||
uart->port.rs485_config = up->port.rs485_config;
|
||||
uart->port.rs485 = up->port.rs485;
|
||||
|
||||
/* Take tx_loadsz from fifosize if it wasn't set separately */
|
||||
if (uart->port.fifosize && !uart->tx_loadsz)
|
||||
|
@ -3623,8 +3618,13 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
|||
uart->dl_read = up->dl_read;
|
||||
if (up->dl_write)
|
||||
uart->dl_write = up->dl_write;
|
||||
if (up->dma)
|
||||
if (up->dma) {
|
||||
uart->dma = up->dma;
|
||||
if (!uart->dma->tx_dma)
|
||||
uart->dma->tx_dma = serial8250_tx_dma;
|
||||
if (!uart->dma->rx_dma)
|
||||
uart->dma->rx_dma = serial8250_rx_dma;
|
||||
}
|
||||
|
||||
if (serial8250_isa_config != NULL)
|
||||
serial8250_isa_config(0, &uart->port,
|
||||
|
|
|
@ -21,6 +21,7 @@ static void __dma_tx_complete(void *param)
|
|||
struct uart_8250_dma *dma = p->dma;
|
||||
struct circ_buf *xmit = &p->port.state->xmit;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
|
||||
UART_XMIT_SIZE, DMA_TO_DEVICE);
|
||||
|
@ -36,8 +37,11 @@ static void __dma_tx_complete(void *param)
|
|||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&p->port);
|
||||
|
||||
if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port))
|
||||
serial8250_tx_dma(p);
|
||||
ret = serial8250_tx_dma(p);
|
||||
if (ret) {
|
||||
p->ier |= UART_IER_THRI;
|
||||
serial_port_out(&p->port, UART_IER, p->ier);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||
}
|
||||
|
@ -53,6 +57,7 @@ static void __dma_rx_complete(void *param)
|
|||
dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
|
||||
dma->rx_size, DMA_FROM_DEVICE);
|
||||
|
||||
dma->rx_running = 0;
|
||||
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
||||
dmaengine_terminate_all(dma->rxchan);
|
||||
|
||||
|
@ -69,6 +74,7 @@ int serial8250_tx_dma(struct uart_8250_port *p)
|
|||
struct uart_8250_dma *dma = p->dma;
|
||||
struct circ_buf *xmit = &p->port.state->xmit;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
int ret;
|
||||
|
||||
if (uart_tx_stopped(&p->port) || dma->tx_running ||
|
||||
uart_circ_empty(xmit))
|
||||
|
@ -80,11 +86,12 @@ int serial8250_tx_dma(struct uart_8250_port *p)
|
|||
dma->tx_addr + xmit->tail,
|
||||
dma->tx_size, DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc)
|
||||
return -EBUSY;
|
||||
if (!desc) {
|
||||
ret = -EBUSY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
dma->tx_running = 1;
|
||||
|
||||
desc->callback = __dma_tx_complete;
|
||||
desc->callback_param = p;
|
||||
|
||||
|
@ -94,19 +101,23 @@ int serial8250_tx_dma(struct uart_8250_port *p)
|
|||
UART_XMIT_SIZE, DMA_TO_DEVICE);
|
||||
|
||||
dma_async_issue_pending(dma->txchan);
|
||||
|
||||
if (dma->tx_err) {
|
||||
dma->tx_err = 0;
|
||||
if (p->ier & UART_IER_THRI) {
|
||||
p->ier &= ~UART_IER_THRI;
|
||||
serial_out(p, UART_IER, p->ier);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
err:
|
||||
dma->tx_err = 1;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_tx_dma);
|
||||
|
||||
int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
||||
{
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
struct dma_tx_state state;
|
||||
int dma_status;
|
||||
|
||||
dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
||||
|
||||
switch (iir & 0x3f) {
|
||||
case UART_IIR_RLSI:
|
||||
|
@ -117,7 +128,7 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
|||
* If RCVR FIFO trigger level was not reached, complete the
|
||||
* transfer and let 8250_core copy the remaining data.
|
||||
*/
|
||||
if (dma_status == DMA_IN_PROGRESS) {
|
||||
if (dma->rx_running) {
|
||||
dmaengine_pause(dma->rxchan);
|
||||
__dma_rx_complete(p);
|
||||
}
|
||||
|
@ -126,7 +137,7 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
|||
break;
|
||||
}
|
||||
|
||||
if (dma_status)
|
||||
if (dma->rx_running)
|
||||
return 0;
|
||||
|
||||
desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
|
||||
|
@ -135,6 +146,7 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
|||
if (!desc)
|
||||
return -EBUSY;
|
||||
|
||||
dma->rx_running = 1;
|
||||
desc->callback = __dma_rx_complete;
|
||||
desc->callback_param = p;
|
||||
|
||||
|
@ -147,7 +159,6 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_rx_dma);
|
||||
|
||||
int serial8250_request_dma(struct uart_8250_port *p)
|
||||
{
|
||||
|
|
|
@ -122,13 +122,44 @@ static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
|
|||
return dw8250_modify_msr(p, offset, value);
|
||||
}
|
||||
|
||||
/* Read Back (rb) version to ensure register access ording. */
|
||||
static void dw8250_serial_out_rb(struct uart_port *p, int offset, int value)
|
||||
#ifdef CONFIG_64BIT
|
||||
static unsigned int dw8250_serial_inq(struct uart_port *p, int offset)
|
||||
{
|
||||
dw8250_serial_out(p, offset, value);
|
||||
dw8250_serial_in(p, UART_LCR);
|
||||
unsigned int value;
|
||||
|
||||
value = (u8)__raw_readq(p->membase + (offset << p->regshift));
|
||||
|
||||
return dw8250_modify_msr(p, offset, value);
|
||||
}
|
||||
|
||||
static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = p->private_data;
|
||||
|
||||
if (offset == UART_MCR)
|
||||
d->last_mcr = value;
|
||||
|
||||
value &= 0xff;
|
||||
__raw_writeq(value, p->membase + (offset << p->regshift));
|
||||
/* Read back to ensure register write ordering. */
|
||||
__raw_readq(p->membase + (UART_LCR << p->regshift));
|
||||
|
||||
/* Make sure LCR write wasn't ignored */
|
||||
if (offset == UART_LCR) {
|
||||
int tries = 1000;
|
||||
while (tries--) {
|
||||
unsigned int lcr = p->serial_in(p, UART_LCR);
|
||||
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
|
||||
return;
|
||||
dw8250_force_idle(p);
|
||||
__raw_writeq(value & 0xff,
|
||||
p->membase + (UART_LCR << p->regshift));
|
||||
}
|
||||
dev_err(p->dev, "Couldn't set LCR to %d\n", value);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_64BIT */
|
||||
|
||||
static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = p->private_data;
|
||||
|
@ -258,22 +289,19 @@ static int dw8250_probe_of(struct uart_port *p,
|
|||
struct uart_8250_port *up = up_to_u8250p(p);
|
||||
u32 val;
|
||||
bool has_ucv = true;
|
||||
int id;
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) {
|
||||
#ifdef __BIG_ENDIAN
|
||||
/*
|
||||
* Low order bits of these 64-bit registers, when
|
||||
* accessed as a byte, are 7 bytes further down in the
|
||||
* address space in big endian mode.
|
||||
*/
|
||||
p->membase += 7;
|
||||
#endif
|
||||
p->serial_out = dw8250_serial_out_rb;
|
||||
p->serial_in = dw8250_serial_inq;
|
||||
p->serial_out = dw8250_serial_outq;
|
||||
p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
|
||||
p->type = PORT_OCTEON;
|
||||
data->usr_reg = 0x27;
|
||||
has_ucv = false;
|
||||
} else if (!of_property_read_u32(np, "reg-io-width", &val)) {
|
||||
} else
|
||||
#endif
|
||||
if (!of_property_read_u32(np, "reg-io-width", &val)) {
|
||||
switch (val) {
|
||||
case 1:
|
||||
break;
|
||||
|
@ -290,9 +318,22 @@ static int dw8250_probe_of(struct uart_port *p,
|
|||
if (has_ucv)
|
||||
dw8250_setup_port(up);
|
||||
|
||||
/* if we have a valid fifosize, try hooking up DMA here */
|
||||
if (p->fifosize) {
|
||||
up->dma = &data->dma;
|
||||
|
||||
up->dma->rxconf.src_maxburst = p->fifosize / 4;
|
||||
up->dma->txconf.dst_maxburst = p->fifosize / 4;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(np, "reg-shift", &val))
|
||||
p->regshift = val;
|
||||
|
||||
/* get index of serial line, if found in DT aliases */
|
||||
id = of_alias_get_id(np, "serial");
|
||||
if (id >= 0)
|
||||
p->line = id;
|
||||
|
||||
/* clock got configured through clk api, all done */
|
||||
if (p->uartclk)
|
||||
return 0;
|
||||
|
|
|
@ -102,10 +102,8 @@ static int serial8250_em_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
dev_err(&pdev->dev, "unable to allocate private data\n");
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
priv->sclk = devm_clk_get(&pdev->dev, "sclk");
|
||||
if (IS_ERR(priv->sclk)) {
|
||||
|
|
|
@ -89,11 +89,11 @@ static int fintek_8250_check_id(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fintek_8250_rs4850_config(struct uart_8250_port *uart,
|
||||
static int fintek_8250_rs485_config(struct uart_port *port,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
uint8_t config = 0;
|
||||
int index = fintek_8250_get_index(uart->port.iobase);
|
||||
int index = fintek_8250_get_index(port->iobase);
|
||||
|
||||
if (index < 0)
|
||||
return -EINVAL;
|
||||
|
@ -134,6 +134,8 @@ static int fintek_8250_rs4850_config(struct uart_8250_port *uart,
|
|||
outb(config, DATA_PORT);
|
||||
fintek_8250_exit_key();
|
||||
|
||||
port->rs485 = *rs485;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -166,7 +168,7 @@ fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
|
|||
uart.port.irq = pnp_irq(dev, 0);
|
||||
uart.port.iobase = pnp_port_start(dev, 0);
|
||||
uart.port.iotype = UPIO_PORT;
|
||||
uart.rs485_config = fintek_8250_rs4850_config;
|
||||
uart.port.rs485_config = fintek_8250_rs485_config;
|
||||
|
||||
uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
|
||||
if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
|
||||
|
|
|
@ -88,10 +88,6 @@ extern int hp300_uart_scode;
|
|||
/*
|
||||
* Parse the bootinfo to find descriptions for headless console and
|
||||
* debug serial ports and register them with the 8250 driver.
|
||||
* This function should be called before serial_console_init() is called
|
||||
* to make sure the serial console will be available for use. IA-64 kernel
|
||||
* calls this function from setup_arch() after the EFI and ACPI tables have
|
||||
* been parsed.
|
||||
*/
|
||||
int __init hp300_setup_serial_console(void)
|
||||
{
|
||||
|
|
|
@ -74,14 +74,14 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
/* Set to next lower baudrate supported */
|
||||
if ((baud == 500000) || (baud == 576000))
|
||||
baud = 460800;
|
||||
quot = DIV_ROUND_CLOSEST(port->uartclk, 4 * baud);
|
||||
quot = DIV_ROUND_UP(port->uartclk, 4 * baud);
|
||||
} else {
|
||||
serial_port_out(port, UART_MTK_HIGHS, 0x3);
|
||||
|
||||
/* Set to highest baudrate supported */
|
||||
if (baud >= 1152000)
|
||||
baud = 921600;
|
||||
quot = (port->uartclk / (256 * baud)) + 1;
|
||||
quot = DIV_ROUND_UP(port->uartclk, 256 * baud);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -79,29 +79,24 @@ setup_port(struct serial_private *priv, struct uart_8250_port *port,
|
|||
int bar, int offset, int regshift)
|
||||
{
|
||||
struct pci_dev *dev = priv->dev;
|
||||
unsigned long base, len;
|
||||
|
||||
if (bar >= PCI_NUM_BAR_RESOURCES)
|
||||
return -EINVAL;
|
||||
|
||||
base = pci_resource_start(dev, bar);
|
||||
|
||||
if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
|
||||
len = pci_resource_len(dev, bar);
|
||||
|
||||
if (!priv->remapped_bar[bar])
|
||||
priv->remapped_bar[bar] = ioremap_nocache(base, len);
|
||||
priv->remapped_bar[bar] = pci_ioremap_bar(dev, bar);
|
||||
if (!priv->remapped_bar[bar])
|
||||
return -ENOMEM;
|
||||
|
||||
port->port.iotype = UPIO_MEM;
|
||||
port->port.iobase = 0;
|
||||
port->port.mapbase = base + offset;
|
||||
port->port.mapbase = pci_resource_start(dev, bar) + offset;
|
||||
port->port.membase = priv->remapped_bar[bar] + offset;
|
||||
port->port.regshift = regshift;
|
||||
} else {
|
||||
port->port.iotype = UPIO_PORT;
|
||||
port->port.iobase = base + offset;
|
||||
port->port.iobase = pci_resource_start(dev, bar) + offset;
|
||||
port->port.mapbase = 0;
|
||||
port->port.membase = NULL;
|
||||
port->port.regshift = 0;
|
||||
|
@ -317,7 +312,6 @@ static void pci_plx9050_exit(struct pci_dev *dev)
|
|||
static void pci_ni8420_exit(struct pci_dev *dev)
|
||||
{
|
||||
void __iomem *p;
|
||||
unsigned long base, len;
|
||||
unsigned int bar = 0;
|
||||
|
||||
if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
|
||||
|
@ -325,9 +319,7 @@ static void pci_ni8420_exit(struct pci_dev *dev)
|
|||
return;
|
||||
}
|
||||
|
||||
base = pci_resource_start(dev, bar);
|
||||
len = pci_resource_len(dev, bar);
|
||||
p = ioremap_nocache(base, len);
|
||||
p = pci_ioremap_bar(dev, bar);
|
||||
if (p == NULL)
|
||||
return;
|
||||
|
||||
|
@ -349,7 +341,6 @@ static void pci_ni8420_exit(struct pci_dev *dev)
|
|||
static void pci_ni8430_exit(struct pci_dev *dev)
|
||||
{
|
||||
void __iomem *p;
|
||||
unsigned long base, len;
|
||||
unsigned int bar = 0;
|
||||
|
||||
if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
|
||||
|
@ -357,9 +348,7 @@ static void pci_ni8430_exit(struct pci_dev *dev)
|
|||
return;
|
||||
}
|
||||
|
||||
base = pci_resource_start(dev, bar);
|
||||
len = pci_resource_len(dev, bar);
|
||||
p = ioremap_nocache(base, len);
|
||||
p = pci_ioremap_bar(dev, bar);
|
||||
if (p == NULL)
|
||||
return;
|
||||
|
||||
|
@ -682,7 +671,6 @@ static int pci_xircom_init(struct pci_dev *dev)
|
|||
static int pci_ni8420_init(struct pci_dev *dev)
|
||||
{
|
||||
void __iomem *p;
|
||||
unsigned long base, len;
|
||||
unsigned int bar = 0;
|
||||
|
||||
if ((pci_resource_flags(dev, bar) & IORESOURCE_MEM) == 0) {
|
||||
|
@ -690,9 +678,7 @@ static int pci_ni8420_init(struct pci_dev *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
base = pci_resource_start(dev, bar);
|
||||
len = pci_resource_len(dev, bar);
|
||||
p = ioremap_nocache(base, len);
|
||||
p = pci_ioremap_bar(dev, bar);
|
||||
if (p == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -714,7 +700,7 @@ static int pci_ni8420_init(struct pci_dev *dev)
|
|||
static int pci_ni8430_init(struct pci_dev *dev)
|
||||
{
|
||||
void __iomem *p;
|
||||
unsigned long base, len;
|
||||
struct pci_bus_region region;
|
||||
u32 device_window;
|
||||
unsigned int bar = 0;
|
||||
|
||||
|
@ -723,14 +709,17 @@ static int pci_ni8430_init(struct pci_dev *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
base = pci_resource_start(dev, bar);
|
||||
len = pci_resource_len(dev, bar);
|
||||
p = ioremap_nocache(base, len);
|
||||
p = pci_ioremap_bar(dev, bar);
|
||||
if (p == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Set device window address and size in BAR0 */
|
||||
device_window = ((base + MITE_IOWBSR1_WIN_OFFSET) & 0xffffff00)
|
||||
/*
|
||||
* Set device window address and size in BAR0, while acknowledging that
|
||||
* the resource structure may contain a translated address that differs
|
||||
* from the address the device responds to.
|
||||
*/
|
||||
pcibios_resource_to_bus(dev->bus, ®ion, &dev->resource[bar]);
|
||||
device_window = ((region.start + MITE_IOWBSR1_WIN_OFFSET) & 0xffffff00)
|
||||
| MITE_IOWBSR1_WENAB | MITE_IOWBSR1_WSIZE;
|
||||
writel(device_window, p + MITE_IOWBSR1);
|
||||
|
||||
|
@ -757,8 +746,8 @@ pci_ni8430_setup(struct serial_private *priv,
|
|||
const struct pciserial_board *board,
|
||||
struct uart_8250_port *port, int idx)
|
||||
{
|
||||
struct pci_dev *dev = priv->dev;
|
||||
void __iomem *p;
|
||||
unsigned long base, len;
|
||||
unsigned int bar, offset = board->first_offset;
|
||||
|
||||
if (idx >= board->num_ports)
|
||||
|
@ -767,9 +756,9 @@ pci_ni8430_setup(struct serial_private *priv,
|
|||
bar = FL_GET_BASE(board->flags);
|
||||
offset += idx * board->uart_offset;
|
||||
|
||||
base = pci_resource_start(priv->dev, bar);
|
||||
len = pci_resource_len(priv->dev, bar);
|
||||
p = ioremap_nocache(base, len);
|
||||
p = pci_ioremap_bar(dev, bar);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
/* enable the transceiver */
|
||||
writeb(readb(p + offset + NI8430_PORTCON) | NI8430_PORTCON_TXVR_ENABLE,
|
||||
|
@ -1002,6 +991,40 @@ static void pci_ite887x_exit(struct pci_dev *dev)
|
|||
release_region(ioport, ITE_887x_IOSIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* EndRun Technologies.
|
||||
* Determine the number of ports available on the device.
|
||||
*/
|
||||
#define PCI_VENDOR_ID_ENDRUN 0x7401
|
||||
#define PCI_DEVICE_ID_ENDRUN_1588 0xe100
|
||||
|
||||
static int pci_endrun_init(struct pci_dev *dev)
|
||||
{
|
||||
u8 __iomem *p;
|
||||
unsigned long deviceID;
|
||||
unsigned int number_uarts = 0;
|
||||
|
||||
/* EndRun device is all 0xexxx */
|
||||
if (dev->vendor == PCI_VENDOR_ID_ENDRUN &&
|
||||
(dev->device & 0xf000) != 0xe000)
|
||||
return 0;
|
||||
|
||||
p = pci_iomap(dev, 0, 5);
|
||||
if (p == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
deviceID = ioread32(p);
|
||||
/* EndRun device */
|
||||
if (deviceID == 0x07000200) {
|
||||
number_uarts = ioread8(p + 4);
|
||||
dev_dbg(&dev->dev,
|
||||
"%d ports detected on EndRun PCI Express device\n",
|
||||
number_uarts);
|
||||
}
|
||||
pci_iounmap(dev, p);
|
||||
return number_uarts;
|
||||
}
|
||||
|
||||
/*
|
||||
* Oxford Semiconductor Inc.
|
||||
* Check that device is part of the Tornado range of devices, then determine
|
||||
|
@ -1531,25 +1554,48 @@ static int pci_fintek_setup(struct serial_private *priv,
|
|||
unsigned long iobase;
|
||||
unsigned long ciobase = 0;
|
||||
u8 config_base;
|
||||
u32 bar_data[3];
|
||||
|
||||
/*
|
||||
* We are supposed to be able to read these from the PCI config space,
|
||||
* but the values there don't seem to match what we need to use, so
|
||||
* just use these hard-coded values for now, as they are correct.
|
||||
* Find each UARTs offset in PCI configuraion space
|
||||
*/
|
||||
switch (idx) {
|
||||
case 0: iobase = 0xe000; config_base = 0x40; break;
|
||||
case 1: iobase = 0xe008; config_base = 0x48; break;
|
||||
case 2: iobase = 0xe010; config_base = 0x50; break;
|
||||
case 3: iobase = 0xe018; config_base = 0x58; break;
|
||||
case 4: iobase = 0xe020; config_base = 0x60; break;
|
||||
case 5: iobase = 0xe028; config_base = 0x68; break;
|
||||
case 6: iobase = 0xe030; config_base = 0x70; break;
|
||||
case 7: iobase = 0xe038; config_base = 0x78; break;
|
||||
case 8: iobase = 0xe040; config_base = 0x80; break;
|
||||
case 9: iobase = 0xe048; config_base = 0x88; break;
|
||||
case 10: iobase = 0xe050; config_base = 0x90; break;
|
||||
case 11: iobase = 0xe058; config_base = 0x98; break;
|
||||
case 0:
|
||||
config_base = 0x40;
|
||||
break;
|
||||
case 1:
|
||||
config_base = 0x48;
|
||||
break;
|
||||
case 2:
|
||||
config_base = 0x50;
|
||||
break;
|
||||
case 3:
|
||||
config_base = 0x58;
|
||||
break;
|
||||
case 4:
|
||||
config_base = 0x60;
|
||||
break;
|
||||
case 5:
|
||||
config_base = 0x68;
|
||||
break;
|
||||
case 6:
|
||||
config_base = 0x70;
|
||||
break;
|
||||
case 7:
|
||||
config_base = 0x78;
|
||||
break;
|
||||
case 8:
|
||||
config_base = 0x80;
|
||||
break;
|
||||
case 9:
|
||||
config_base = 0x88;
|
||||
break;
|
||||
case 10:
|
||||
config_base = 0x90;
|
||||
break;
|
||||
case 11:
|
||||
config_base = 0x98;
|
||||
break;
|
||||
default:
|
||||
/* Unknown number of ports, get out of here */
|
||||
return -EINVAL;
|
||||
|
@ -1560,6 +1606,14 @@ static int pci_fintek_setup(struct serial_private *priv,
|
|||
ciobase = (int)(base + (0x8 * idx));
|
||||
}
|
||||
|
||||
/* Get the io address dispatch from the BIOS */
|
||||
pci_read_config_dword(pdev, 0x24, &bar_data[0]);
|
||||
pci_read_config_dword(pdev, 0x20, &bar_data[1]);
|
||||
pci_read_config_dword(pdev, 0x1c, &bar_data[2]);
|
||||
|
||||
/* Calculate Real IO Port */
|
||||
iobase = (bar_data[idx/4] & 0xffffffe0) + (idx % 4) * 8;
|
||||
|
||||
dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%lx ciobase=0x%lx config_base=0x%2x\n",
|
||||
__func__, idx, iobase, ciobase, config_base);
|
||||
|
||||
|
@ -1760,6 +1814,16 @@ pci_wch_ch353_setup(struct serial_private *priv,
|
|||
return pci_default_setup(priv, board, port, idx);
|
||||
}
|
||||
|
||||
static int
|
||||
pci_wch_ch382_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
struct uart_8250_port *port, int idx)
|
||||
{
|
||||
port->port.flags |= UPF_FIXED_TYPE;
|
||||
port->port.type = PORT_16850;
|
||||
return pci_default_setup(priv, board, port, idx);
|
||||
}
|
||||
|
||||
#define PCI_VENDOR_ID_SBSMODULARIO 0x124B
|
||||
#define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B
|
||||
#define PCI_DEVICE_ID_OCTPRO 0x0001
|
||||
|
@ -1814,6 +1878,8 @@ pci_wch_ch353_setup(struct serial_private *priv,
|
|||
#define PCI_VENDOR_ID_SUNIX 0x1fd4
|
||||
#define PCI_DEVICE_ID_SUNIX_1999 0x1999
|
||||
|
||||
#define PCIE_VENDOR_ID_WCH 0x1c00
|
||||
#define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250
|
||||
|
||||
/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
|
||||
#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584
|
||||
|
@ -2345,6 +2411,17 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
|
|||
.init = pci_netmos_init,
|
||||
.setup = pci_netmos_9900_setup,
|
||||
},
|
||||
/*
|
||||
* EndRun Technologies
|
||||
*/
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_ENDRUN,
|
||||
.device = PCI_ANY_ID,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.init = pci_endrun_init,
|
||||
.setup = pci_default_setup,
|
||||
},
|
||||
/*
|
||||
* For Oxford Semiconductor Tornado based devices
|
||||
*/
|
||||
|
@ -2494,6 +2571,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
|
|||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_wch_ch353_setup,
|
||||
},
|
||||
/* WCH CH382 2S1P card (16750 clone) */
|
||||
{
|
||||
.vendor = PCIE_VENDOR_ID_WCH,
|
||||
.device = PCIE_DEVICE_ID_WCH_CH382_2S1P,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_wch_ch382_setup,
|
||||
},
|
||||
/*
|
||||
* ASIX devices with FIFO bug
|
||||
*/
|
||||
|
@ -2754,6 +2839,7 @@ enum pci_board_num_t {
|
|||
pbn_panacom2,
|
||||
pbn_panacom4,
|
||||
pbn_plx_romulus,
|
||||
pbn_endrun_2_4000000,
|
||||
pbn_oxsemi,
|
||||
pbn_oxsemi_1_4000000,
|
||||
pbn_oxsemi_2_4000000,
|
||||
|
@ -3298,6 +3384,20 @@ static struct pciserial_board pci_boards[] = {
|
|||
.first_offset = 0x03,
|
||||
},
|
||||
|
||||
/*
|
||||
* EndRun Technologies
|
||||
* Uses the size of PCI Base region 0 to
|
||||
* signal now many ports are available
|
||||
* 2 port 952 Uart support
|
||||
*/
|
||||
[pbn_endrun_2_4000000] = {
|
||||
.flags = FL_BASE0,
|
||||
.num_ports = 2,
|
||||
.base_baud = 4000000,
|
||||
.uart_offset = 0x200,
|
||||
.first_offset = 0x1000,
|
||||
},
|
||||
|
||||
/*
|
||||
* This board uses the size of PCI Base region 0 to
|
||||
* signal now many ports are available
|
||||
|
@ -3586,6 +3686,7 @@ static const struct pci_device_id blacklist[] = {
|
|||
/* multi-io cards handled by parport_serial */
|
||||
{ PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */
|
||||
{ PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */
|
||||
{ PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -4170,6 +4271,13 @@ static struct pci_device_id serial_pci_tbl[] = {
|
|||
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
|
||||
0x10b5, 0x106a, 0, 0,
|
||||
pbn_plx_romulus },
|
||||
/*
|
||||
* EndRun Technologies. PCI express device range.
|
||||
* EndRun PTP/1588 has 2 Native UARTs.
|
||||
*/
|
||||
{ PCI_VENDOR_ID_ENDRUN, PCI_DEVICE_ID_ENDRUN_1588,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_endrun_2_4000000 },
|
||||
/*
|
||||
* Quatech cards. These actually have configurable clocks but for
|
||||
* now we just use the default.
|
||||
|
|
|
@ -293,12 +293,21 @@ config SERIAL_8250_EM
|
|||
|
||||
config SERIAL_8250_RT288X
|
||||
bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support"
|
||||
depends on SERIAL_8250 && (SOC_RT288X || SOC_RT305X || SOC_RT3883)
|
||||
depends on SERIAL_8250 && (SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620)
|
||||
help
|
||||
If you have a Ralink RT288x/RT305x SoC based board and want to use the
|
||||
serial port, say Y to this option. The driver can handle up to 2 serial
|
||||
ports. If unsure, say N.
|
||||
|
||||
config SERIAL_8250_OMAP
|
||||
tristate "Support for OMAP internal UART (8250 based driver)"
|
||||
depends on SERIAL_8250 && ARCH_OMAP2PLUS
|
||||
help
|
||||
If you have a machine based on an Texas Instruments OMAP CPU you
|
||||
can enable its onboard serial ports by enabling this option.
|
||||
|
||||
This driver uses ttyS instead of ttyO.
|
||||
|
||||
config SERIAL_8250_FINTEK
|
||||
tristate "Support for Fintek F81216A LPC to 4 UART"
|
||||
depends on SERIAL_8250 && PNP
|
||||
|
|
|
@ -20,5 +20,6 @@ obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
|
|||
obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
|
||||
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
|
||||
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
|
||||
obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o
|
||||
obj-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o
|
||||
obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
|
||||
|
|
|
@ -1029,11 +1029,11 @@ config SERIAL_VR41XX_CONSOLE
|
|||
a console on a serial port, say Y. Otherwise, say N.
|
||||
|
||||
config SERIAL_JSM
|
||||
tristate "Digi International NEO PCI Support"
|
||||
tristate "Digi International NEO and Classic PCI Support"
|
||||
depends on PCI
|
||||
select SERIAL_CORE
|
||||
help
|
||||
This is a driver for Digi International's Neo series
|
||||
This is a driver for Digi International's Neo and Classic series
|
||||
of cards which provide multiple serial ports. You would need
|
||||
something like this to connect more than two modems to your Linux
|
||||
box, for instance in order to become a dial-in server. This driver
|
||||
|
@ -1281,22 +1281,25 @@ config SERIAL_TIMBERDALE
|
|||
Add support for UART controller on timberdale.
|
||||
|
||||
config SERIAL_BCM63XX
|
||||
tristate "bcm63xx serial port support"
|
||||
tristate "Broadcom BCM63xx/BCM33xx UART support"
|
||||
select SERIAL_CORE
|
||||
depends on BCM63XX
|
||||
depends on MIPS || ARM || COMPILE_TEST
|
||||
help
|
||||
If you have a bcm63xx CPU, you can enable its onboard
|
||||
serial port by enabling this options.
|
||||
This enables the driver for the onchip UART core found on
|
||||
the following chipsets:
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called bcm963xx_uart.
|
||||
BCM33xx (cable modem)
|
||||
BCM63xx/BCM63xxx (DSL)
|
||||
BCM68xx (PON)
|
||||
BCM7xxx (STB) - DOCSIS console
|
||||
|
||||
config SERIAL_BCM63XX_CONSOLE
|
||||
bool "Console on bcm63xx serial port"
|
||||
bool "Console on BCM63xx serial port"
|
||||
depends on SERIAL_BCM63XX=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON
|
||||
help
|
||||
If you have enabled the serial port on the bcm63xx CPU
|
||||
If you have enabled the serial port on the BCM63xx CPU
|
||||
you can make it the console by answering Y to this option.
|
||||
|
||||
config SERIAL_GRLIB_GAISLER_APBUART
|
||||
|
@ -1408,6 +1411,7 @@ config SERIAL_MXS_AUART
|
|||
depends on ARCH_MXS
|
||||
tristate "MXS AUART support"
|
||||
select SERIAL_CORE
|
||||
select SERIAL_MCTRL_GPIO if GPIOLIB
|
||||
help
|
||||
This driver supports the MXS Application UART (AUART) port.
|
||||
|
||||
|
|
|
@ -75,7 +75,8 @@ struct uart_amba_port {
|
|||
|
||||
static void pl010_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
unsigned int cr;
|
||||
|
||||
cr = readb(uap->port.membase + UART010_CR);
|
||||
|
@ -85,7 +86,8 @@ static void pl010_stop_tx(struct uart_port *port)
|
|||
|
||||
static void pl010_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
unsigned int cr;
|
||||
|
||||
cr = readb(uap->port.membase + UART010_CR);
|
||||
|
@ -95,7 +97,8 @@ static void pl010_start_tx(struct uart_port *port)
|
|||
|
||||
static void pl010_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
unsigned int cr;
|
||||
|
||||
cr = readb(uap->port.membase + UART010_CR);
|
||||
|
@ -103,11 +106,22 @@ static void pl010_stop_rx(struct uart_port *port)
|
|||
writel(cr, uap->port.membase + UART010_CR);
|
||||
}
|
||||
|
||||
static void pl010_enable_ms(struct uart_port *port)
|
||||
static void pl010_disable_ms(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
||||
unsigned int cr;
|
||||
|
||||
cr = readb(uap->port.membase + UART010_CR);
|
||||
cr &= ~UART010_CR_MSIE;
|
||||
writel(cr, uap->port.membase + UART010_CR);
|
||||
}
|
||||
|
||||
static void pl010_enable_ms(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
unsigned int cr;
|
||||
|
||||
cr = readb(uap->port.membase + UART010_CR);
|
||||
cr |= UART010_CR_MSIE;
|
||||
writel(cr, uap->port.membase + UART010_CR);
|
||||
|
@ -259,14 +273,16 @@ static irqreturn_t pl010_int(int irq, void *dev_id)
|
|||
|
||||
static unsigned int pl010_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
unsigned int status = readb(uap->port.membase + UART01x_FR);
|
||||
return status & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT;
|
||||
}
|
||||
|
||||
static unsigned int pl010_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
unsigned int result = 0;
|
||||
unsigned int status;
|
||||
|
||||
|
@ -283,7 +299,8 @@ static unsigned int pl010_get_mctrl(struct uart_port *port)
|
|||
|
||||
static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
|
||||
if (uap->data)
|
||||
uap->data->set_mctrl(uap->dev, uap->port.membase, mctrl);
|
||||
|
@ -291,7 +308,8 @@ static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
|||
|
||||
static void pl010_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
unsigned long flags;
|
||||
unsigned int lcr_h;
|
||||
|
||||
|
@ -307,7 +325,8 @@ static void pl010_break_ctl(struct uart_port *port, int break_state)
|
|||
|
||||
static int pl010_startup(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
int retval;
|
||||
|
||||
/*
|
||||
|
@ -347,7 +366,8 @@ static int pl010_startup(struct uart_port *port)
|
|||
|
||||
static void pl010_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
|
||||
/*
|
||||
* Free the interrupt
|
||||
|
@ -374,7 +394,8 @@ static void
|
|||
pl010_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
unsigned int lcr_h, old_cr;
|
||||
unsigned long flags;
|
||||
unsigned int baud, quot;
|
||||
|
@ -468,13 +489,21 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
spin_unlock_irqrestore(&uap->port.lock, flags);
|
||||
}
|
||||
|
||||
static void pl010_set_ldisc(struct uart_port *port, int new)
|
||||
static void pl010_set_ldisc(struct uart_port *port, struct ktermios *termios)
|
||||
{
|
||||
if (new == N_PPS) {
|
||||
if (termios->c_line == N_PPS) {
|
||||
port->flags |= UPF_HARDPPS_CD;
|
||||
spin_lock_irq(&port->lock);
|
||||
pl010_enable_ms(port);
|
||||
} else
|
||||
spin_unlock_irq(&port->lock);
|
||||
} else {
|
||||
port->flags &= ~UPF_HARDPPS_CD;
|
||||
if (!UART_ENABLE_MS(port, termios->c_cflag)) {
|
||||
spin_lock_irq(&port->lock);
|
||||
pl010_disable_ms(port);
|
||||
spin_unlock_irq(&port->lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char *pl010_type(struct uart_port *port)
|
||||
|
@ -551,7 +580,8 @@ static struct uart_amba_port *amba_ports[UART_NR];
|
|||
|
||||
static void pl010_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
||||
struct uart_amba_port *uap =
|
||||
container_of(port, struct uart_amba_port, port);
|
||||
unsigned int status;
|
||||
|
||||
do {
|
||||
|
|
|
@ -246,6 +246,7 @@ static int pl011_sgbuf_init(struct dma_chan *chan, struct pl011_sgbuf *sg,
|
|||
sg_set_page(&sg->sg, phys_to_page(dma_addr),
|
||||
PL011_DMA_BUFFER_SIZE, offset_in_page(dma_addr));
|
||||
sg_dma_address(&sg->sg) = dma_addr;
|
||||
sg_dma_len(&sg->sg) = PL011_DMA_BUFFER_SIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -321,10 +322,26 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *
|
|||
.src_maxburst = uap->fifosize >> 2,
|
||||
.device_fc = false,
|
||||
};
|
||||
struct dma_slave_caps caps;
|
||||
|
||||
/*
|
||||
* Some DMA controllers provide information on their capabilities.
|
||||
* If the controller does, check for suitable residue processing
|
||||
* otherwise assime all is well.
|
||||
*/
|
||||
if (0 == dma_get_slave_caps(chan, &caps)) {
|
||||
if (caps.residue_granularity ==
|
||||
DMA_RESIDUE_GRANULARITY_DESCRIPTOR) {
|
||||
dma_release_channel(chan);
|
||||
dev_info(uap->port.dev,
|
||||
"RX DMA disabled - no residue processing\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
dmaengine_slave_config(chan, &rx_conf);
|
||||
uap->dmarx.chan = chan;
|
||||
|
||||
uap->dmarx.auto_poll_rate = false;
|
||||
if (plat && plat->dma_rx_poll_enable) {
|
||||
/* Set poll rate if specified. */
|
||||
if (plat->dma_rx_poll_rate) {
|
||||
|
@ -345,9 +362,24 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *
|
|||
plat->dma_rx_poll_timeout;
|
||||
else
|
||||
uap->dmarx.poll_timeout = 3000;
|
||||
} else
|
||||
uap->dmarx.auto_poll_rate = false;
|
||||
} else if (!plat && dev->of_node) {
|
||||
uap->dmarx.auto_poll_rate = of_property_read_bool(
|
||||
dev->of_node, "auto-poll");
|
||||
if (uap->dmarx.auto_poll_rate) {
|
||||
u32 x;
|
||||
|
||||
if (0 == of_property_read_u32(dev->of_node,
|
||||
"poll-rate-ms", &x))
|
||||
uap->dmarx.poll_rate = x;
|
||||
else
|
||||
uap->dmarx.poll_rate = 100;
|
||||
if (0 == of_property_read_u32(dev->of_node,
|
||||
"poll-timeout-ms", &x))
|
||||
uap->dmarx.poll_timeout = x;
|
||||
else
|
||||
uap->dmarx.poll_timeout = 3000;
|
||||
}
|
||||
}
|
||||
dev_info(uap->port.dev, "DMA channel RX %s\n",
|
||||
dma_chan_name(uap->dmarx.chan));
|
||||
}
|
||||
|
@ -501,7 +533,11 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
|
|||
memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count);
|
||||
else {
|
||||
size_t first = UART_XMIT_SIZE - xmit->tail;
|
||||
size_t second = xmit->head;
|
||||
size_t second;
|
||||
|
||||
if (first > count)
|
||||
first = count;
|
||||
second = count - first;
|
||||
|
||||
memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first);
|
||||
if (second)
|
||||
|
@ -988,7 +1024,7 @@ static void pl011_dma_startup(struct uart_amba_port *uap)
|
|||
if (!uap->dmatx.chan)
|
||||
return;
|
||||
|
||||
uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL);
|
||||
uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL | __GFP_DMA);
|
||||
if (!uap->dmatx.buf) {
|
||||
dev_err(uap->port.dev, "no memory for DMA TX buffer\n");
|
||||
uap->port.fifosize = uap->fifosize;
|
||||
|
@ -1689,6 +1725,8 @@ static void pl011_shutdown(struct uart_port *port)
|
|||
plat->exit();
|
||||
}
|
||||
|
||||
if (uap->port.ops->flush_buffer)
|
||||
uap->port.ops->flush_buffer(port);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -119,7 +119,8 @@ static inline void ar933x_uart_putc(struct ar933x_uart_port *up, int ch)
|
|||
|
||||
static unsigned int ar933x_uart_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
|
||||
struct ar933x_uart_port *up =
|
||||
container_of(port, struct ar933x_uart_port, port);
|
||||
unsigned long flags;
|
||||
unsigned int rdata;
|
||||
|
||||
|
@ -141,21 +142,24 @@ static void ar933x_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
|||
|
||||
static void ar933x_uart_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
|
||||
struct ar933x_uart_port *up =
|
||||
container_of(port, struct ar933x_uart_port, port);
|
||||
|
||||
ar933x_uart_start_tx_interrupt(up);
|
||||
}
|
||||
|
||||
static void ar933x_uart_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
|
||||
struct ar933x_uart_port *up =
|
||||
container_of(port, struct ar933x_uart_port, port);
|
||||
|
||||
ar933x_uart_stop_tx_interrupt(up);
|
||||
}
|
||||
|
||||
static void ar933x_uart_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
|
||||
struct ar933x_uart_port *up =
|
||||
container_of(port, struct ar933x_uart_port, port);
|
||||
|
||||
up->ier &= ~AR933X_UART_INT_RX_VALID;
|
||||
ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
|
||||
|
@ -163,7 +167,8 @@ static void ar933x_uart_stop_rx(struct uart_port *port)
|
|||
|
||||
static void ar933x_uart_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
|
||||
struct ar933x_uart_port *up =
|
||||
container_of(port, struct ar933x_uart_port, port);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
|
@ -231,7 +236,8 @@ static void ar933x_uart_set_termios(struct uart_port *port,
|
|||
struct ktermios *new,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
|
||||
struct ar933x_uart_port *up =
|
||||
container_of(port, struct ar933x_uart_port, port);
|
||||
unsigned int cs;
|
||||
unsigned long flags;
|
||||
unsigned int baud, scale, step;
|
||||
|
@ -404,7 +410,8 @@ static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id)
|
|||
|
||||
static int ar933x_uart_startup(struct uart_port *port)
|
||||
{
|
||||
struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
|
||||
struct ar933x_uart_port *up =
|
||||
container_of(port, struct ar933x_uart_port, port);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
|
@ -430,7 +437,8 @@ static int ar933x_uart_startup(struct uart_port *port)
|
|||
|
||||
static void ar933x_uart_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
|
||||
struct ar933x_uart_port *up =
|
||||
container_of(port, struct ar933x_uart_port, port);
|
||||
|
||||
/* Disable all interrupts */
|
||||
up->ier = 0;
|
||||
|
@ -468,7 +476,8 @@ static void ar933x_uart_config_port(struct uart_port *port, int flags)
|
|||
static int ar933x_uart_verify_port(struct uart_port *port,
|
||||
struct serial_struct *ser)
|
||||
{
|
||||
struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
|
||||
struct ar933x_uart_port *up =
|
||||
container_of(port, struct ar933x_uart_port, port);
|
||||
|
||||
if (ser->type != PORT_UNKNOWN &&
|
||||
ser->type != PORT_AR933X)
|
||||
|
@ -521,7 +530,8 @@ static void ar933x_uart_wait_xmitr(struct ar933x_uart_port *up)
|
|||
|
||||
static void ar933x_uart_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
|
||||
struct ar933x_uart_port *up =
|
||||
container_of(port, struct ar933x_uart_port, port);
|
||||
|
||||
ar933x_uart_wait_xmitr(up);
|
||||
ar933x_uart_putc(up, ch);
|
||||
|
|
|
@ -167,7 +167,6 @@ struct atmel_uart_port {
|
|||
|
||||
struct circ_buf rx_ring;
|
||||
|
||||
struct serial_rs485 rs485; /* rs485 settings */
|
||||
struct mctrl_gpios *gpios;
|
||||
int gpio_irq[UART_GPIO_MAX];
|
||||
unsigned int tx_done_mask;
|
||||
|
@ -290,13 +289,11 @@ static unsigned int atmel_get_lines_status(struct uart_port *port)
|
|||
}
|
||||
|
||||
/* Enable or disable the rs485 support */
|
||||
void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
|
||||
static int atmel_config_rs485(struct uart_port *port,
|
||||
struct serial_rs485 *rs485conf)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
unsigned int mode;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* Disable interrupts */
|
||||
UART_PUT_IDR(port, atmel_port->tx_done_mask);
|
||||
|
@ -306,7 +303,7 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
|
|||
/* Resetting serial mode to RS232 (0x0) */
|
||||
mode &= ~ATMEL_US_USMODE;
|
||||
|
||||
atmel_port->rs485 = *rs485conf;
|
||||
port->rs485 = *rs485conf;
|
||||
|
||||
if (rs485conf->flags & SER_RS485_ENABLED) {
|
||||
dev_dbg(port->dev, "Setting UART to RS485\n");
|
||||
|
@ -327,8 +324,7 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
|
|||
/* Enable interrupts */
|
||||
UART_PUT_IER(port, atmel_port->tx_done_mask);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -372,11 +368,10 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
|
|||
/* Resetting serial mode to RS232 (0x0) */
|
||||
mode &= ~ATMEL_US_USMODE;
|
||||
|
||||
if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
dev_dbg(port->dev, "Setting UART to RS485\n");
|
||||
if ((atmel_port->rs485.delay_rts_after_send) > 0)
|
||||
UART_PUT_TTGR(port,
|
||||
atmel_port->rs485.delay_rts_after_send);
|
||||
if ((port->rs485.delay_rts_after_send) > 0)
|
||||
UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
|
||||
mode |= ATMEL_US_USMODE_RS485;
|
||||
} else {
|
||||
dev_dbg(port->dev, "Setting UART to RS232\n");
|
||||
|
@ -423,8 +418,8 @@ static void atmel_stop_tx(struct uart_port *port)
|
|||
/* Disable interrupts */
|
||||
UART_PUT_IDR(port, atmel_port->tx_done_mask);
|
||||
|
||||
if ((atmel_port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
if ((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(port->rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
atmel_start_rx(port);
|
||||
}
|
||||
|
||||
|
@ -441,8 +436,8 @@ static void atmel_start_tx(struct uart_port *port)
|
|||
really need this.*/
|
||||
return;
|
||||
|
||||
if ((atmel_port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
if ((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(port->rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
atmel_stop_rx(port);
|
||||
|
||||
/* re-enable PDC transmit */
|
||||
|
@ -807,7 +802,7 @@ static void atmel_tx_dma(struct uart_port *port)
|
|||
atmel_port->cookie_tx = dmaengine_submit(desc);
|
||||
|
||||
} else {
|
||||
if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
/* DMA done, stop TX, start RX for RS485 */
|
||||
atmel_start_rx(port);
|
||||
}
|
||||
|
@ -862,9 +857,8 @@ static int atmel_prepare_tx_dma(struct uart_port *port)
|
|||
config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
config.dst_addr = port->mapbase + ATMEL_US_THR;
|
||||
|
||||
ret = dmaengine_device_control(atmel_port->chan_tx,
|
||||
DMA_SLAVE_CONFIG,
|
||||
(unsigned long)&config);
|
||||
ret = dmaengine_slave_config(atmel_port->chan_tx,
|
||||
&config);
|
||||
if (ret) {
|
||||
dev_err(port->dev, "DMA tx slave configuration failed\n");
|
||||
goto chan_err;
|
||||
|
@ -880,32 +874,6 @@ chan_err:
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void atmel_flip_buffer_rx_dma(struct uart_port *port,
|
||||
char *buf, size_t count)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
||||
dma_sync_sg_for_cpu(port->dev,
|
||||
&atmel_port->sg_rx,
|
||||
1,
|
||||
DMA_DEV_TO_MEM);
|
||||
|
||||
tty_insert_flip_string(tport, buf, count);
|
||||
|
||||
dma_sync_sg_for_device(port->dev,
|
||||
&atmel_port->sg_rx,
|
||||
1,
|
||||
DMA_DEV_TO_MEM);
|
||||
/*
|
||||
* Drop the lock here since it might end up calling
|
||||
* uart_start(), which takes the lock.
|
||||
*/
|
||||
spin_unlock(&port->lock);
|
||||
tty_flip_buffer_push(tport);
|
||||
spin_lock(&port->lock);
|
||||
}
|
||||
|
||||
static void atmel_complete_rx_dma(void *arg)
|
||||
{
|
||||
struct uart_port *port = arg;
|
||||
|
@ -934,11 +902,12 @@ static void atmel_release_rx_dma(struct uart_port *port)
|
|||
static void atmel_rx_from_dma(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct circ_buf *ring = &atmel_port->rx_ring;
|
||||
struct dma_chan *chan = atmel_port->chan_rx;
|
||||
struct dma_tx_state state;
|
||||
enum dma_status dmastat;
|
||||
size_t pending, count;
|
||||
size_t count;
|
||||
|
||||
|
||||
/* Reset the UART timeout early so that we don't miss one */
|
||||
|
@ -953,27 +922,68 @@ static void atmel_rx_from_dma(struct uart_port *port)
|
|||
tasklet_schedule(&atmel_port->tasklet);
|
||||
return;
|
||||
}
|
||||
/* current transfer size should no larger than dma buffer */
|
||||
pending = sg_dma_len(&atmel_port->sg_rx) - state.residue;
|
||||
BUG_ON(pending > sg_dma_len(&atmel_port->sg_rx));
|
||||
|
||||
/* CPU claims ownership of RX DMA buffer */
|
||||
dma_sync_sg_for_cpu(port->dev,
|
||||
&atmel_port->sg_rx,
|
||||
1,
|
||||
DMA_DEV_TO_MEM);
|
||||
|
||||
/*
|
||||
* This will take the chars we have so far,
|
||||
* ring->head will record the transfer size, only new bytes come
|
||||
* will insert into the framework.
|
||||
* ring->head points to the end of data already written by the DMA.
|
||||
* ring->tail points to the beginning of data to be read by the
|
||||
* framework.
|
||||
* The current transfer size should not be larger than the dma buffer
|
||||
* length.
|
||||
*/
|
||||
if (pending > ring->head) {
|
||||
count = pending - ring->head;
|
||||
|
||||
atmel_flip_buffer_rx_dma(port, ring->buf + ring->head, count);
|
||||
|
||||
ring->head += count;
|
||||
if (ring->head == sg_dma_len(&atmel_port->sg_rx))
|
||||
ring->head = 0;
|
||||
ring->head = sg_dma_len(&atmel_port->sg_rx) - state.residue;
|
||||
BUG_ON(ring->head > sg_dma_len(&atmel_port->sg_rx));
|
||||
/*
|
||||
* At this point ring->head may point to the first byte right after the
|
||||
* last byte of the dma buffer:
|
||||
* 0 <= ring->head <= sg_dma_len(&atmel_port->sg_rx)
|
||||
*
|
||||
* However ring->tail must always points inside the dma buffer:
|
||||
* 0 <= ring->tail <= sg_dma_len(&atmel_port->sg_rx) - 1
|
||||
*
|
||||
* Since we use a ring buffer, we have to handle the case
|
||||
* where head is lower than tail. In such a case, we first read from
|
||||
* tail to the end of the buffer then reset tail.
|
||||
*/
|
||||
if (ring->head < ring->tail) {
|
||||
count = sg_dma_len(&atmel_port->sg_rx) - ring->tail;
|
||||
|
||||
tty_insert_flip_string(tport, ring->buf + ring->tail, count);
|
||||
ring->tail = 0;
|
||||
port->icount.rx += count;
|
||||
}
|
||||
|
||||
/* Finally we read data from tail to head */
|
||||
if (ring->tail < ring->head) {
|
||||
count = ring->head - ring->tail;
|
||||
|
||||
tty_insert_flip_string(tport, ring->buf + ring->tail, count);
|
||||
/* Wrap ring->head if needed */
|
||||
if (ring->head >= sg_dma_len(&atmel_port->sg_rx))
|
||||
ring->head = 0;
|
||||
ring->tail = ring->head;
|
||||
port->icount.rx += count;
|
||||
}
|
||||
|
||||
/* USART retreives ownership of RX DMA buffer */
|
||||
dma_sync_sg_for_device(port->dev,
|
||||
&atmel_port->sg_rx,
|
||||
1,
|
||||
DMA_DEV_TO_MEM);
|
||||
|
||||
/*
|
||||
* Drop the lock here since it might end up calling
|
||||
* uart_start(), which takes the lock.
|
||||
*/
|
||||
spin_unlock(&port->lock);
|
||||
tty_flip_buffer_push(tport);
|
||||
spin_lock(&port->lock);
|
||||
|
||||
UART_PUT_IER(port, ATMEL_US_TIMEOUT);
|
||||
}
|
||||
|
||||
|
@ -1026,9 +1036,8 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
|
|||
config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
config.src_addr = port->mapbase + ATMEL_US_RHR;
|
||||
|
||||
ret = dmaengine_device_control(atmel_port->chan_rx,
|
||||
DMA_SLAVE_CONFIG,
|
||||
(unsigned long)&config);
|
||||
ret = dmaengine_slave_config(atmel_port->chan_rx,
|
||||
&config);
|
||||
if (ret) {
|
||||
dev_err(port->dev, "DMA rx slave configuration failed\n");
|
||||
goto chan_err;
|
||||
|
@ -1240,8 +1249,8 @@ static void atmel_tx_pdc(struct uart_port *port)
|
|||
/* Enable interrupts */
|
||||
UART_PUT_IER(port, atmel_port->tx_done_mask);
|
||||
} else {
|
||||
if ((atmel_port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(atmel_port->rs485.flags & SER_RS485_RX_DURING_TX)) {
|
||||
if ((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
|
||||
/* DMA done, stop TX, start RX for RS485 */
|
||||
atmel_start_rx(port);
|
||||
}
|
||||
|
@ -1552,7 +1561,7 @@ static int atmel_init_property(struct atmel_uart_port *atmel_port,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void atmel_init_rs485(struct atmel_uart_port *atmel_port,
|
||||
static void atmel_init_rs485(struct uart_port *port,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
|
@ -1563,7 +1572,7 @@ static void atmel_init_rs485(struct atmel_uart_port *atmel_port,
|
|||
/* rs485 properties */
|
||||
if (of_property_read_u32_array(np, "rs485-rts-delay",
|
||||
rs485_delay, 2) == 0) {
|
||||
struct serial_rs485 *rs485conf = &atmel_port->rs485;
|
||||
struct serial_rs485 *rs485conf = &port->rs485;
|
||||
|
||||
rs485conf->delay_rts_before_send = rs485_delay[0];
|
||||
rs485conf->delay_rts_after_send = rs485_delay[1];
|
||||
|
@ -1577,7 +1586,7 @@ static void atmel_init_rs485(struct atmel_uart_port *atmel_port,
|
|||
rs485conf->flags |= SER_RS485_ENABLED;
|
||||
}
|
||||
} else {
|
||||
atmel_port->rs485 = pdata->rs485;
|
||||
port->rs485 = pdata->rs485;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1801,6 +1810,20 @@ free_irq:
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush any TX data submitted for DMA. Called when the TX circular
|
||||
* buffer is reset.
|
||||
*/
|
||||
static void atmel_flush_buffer(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
|
||||
if (atmel_use_pdc_tx(port)) {
|
||||
UART_PUT_TCR(port, 0);
|
||||
atmel_port->pdc_tx.ofs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable the port
|
||||
*/
|
||||
|
@ -1852,20 +1875,8 @@ static void atmel_shutdown(struct uart_port *port)
|
|||
atmel_free_gpio_irq(port);
|
||||
|
||||
atmel_port->ms_irq_enabled = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush any TX data submitted for DMA. Called when the TX circular
|
||||
* buffer is reset.
|
||||
*/
|
||||
static void atmel_flush_buffer(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
|
||||
if (atmel_use_pdc_tx(port)) {
|
||||
UART_PUT_TCR(port, 0);
|
||||
atmel_port->pdc_tx.ofs = 0;
|
||||
}
|
||||
atmel_flush_buffer(port);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1911,7 +1922,6 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
{
|
||||
unsigned long flags;
|
||||
unsigned int mode, imr, quot, baud;
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
|
||||
/* Get current mode register */
|
||||
mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
|
||||
|
@ -2013,10 +2023,9 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
/* Resetting serial mode to RS232 (0x0) */
|
||||
mode &= ~ATMEL_US_USMODE;
|
||||
|
||||
if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
|
||||
if ((atmel_port->rs485.delay_rts_after_send) > 0)
|
||||
UART_PUT_TTGR(port,
|
||||
atmel_port->rs485.delay_rts_after_send);
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
if ((port->rs485.delay_rts_after_send) > 0)
|
||||
UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
|
||||
mode |= ATMEL_US_USMODE_RS485;
|
||||
}
|
||||
|
||||
|
@ -2040,13 +2049,20 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static void atmel_set_ldisc(struct uart_port *port, int new)
|
||||
static void atmel_set_ldisc(struct uart_port *port, struct ktermios *termios)
|
||||
{
|
||||
if (new == N_PPS) {
|
||||
if (termios->c_line == N_PPS) {
|
||||
port->flags |= UPF_HARDPPS_CD;
|
||||
spin_lock_irq(&port->lock);
|
||||
atmel_enable_ms(port);
|
||||
spin_unlock_irq(&port->lock);
|
||||
} else {
|
||||
port->flags &= ~UPF_HARDPPS_CD;
|
||||
if (!UART_ENABLE_MS(port, termios->c_cflag)) {
|
||||
spin_lock_irq(&port->lock);
|
||||
atmel_disable_ms(port);
|
||||
spin_unlock_irq(&port->lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2148,35 +2164,6 @@ static void atmel_poll_put_char(struct uart_port *port, unsigned char ch)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
atmel_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct serial_rs485 rs485conf;
|
||||
|
||||
switch (cmd) {
|
||||
case TIOCSRS485:
|
||||
if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg,
|
||||
sizeof(rs485conf)))
|
||||
return -EFAULT;
|
||||
|
||||
atmel_config_rs485(port, &rs485conf);
|
||||
break;
|
||||
|
||||
case TIOCGRS485:
|
||||
if (copy_to_user((struct serial_rs485 *) arg,
|
||||
&(to_atmel_uart_port(port)->rs485),
|
||||
sizeof(rs485conf)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct uart_ops atmel_pops = {
|
||||
.tx_empty = atmel_tx_empty,
|
||||
.set_mctrl = atmel_set_mctrl,
|
||||
|
@ -2197,7 +2184,6 @@ static struct uart_ops atmel_pops = {
|
|||
.config_port = atmel_config_port,
|
||||
.verify_port = atmel_verify_port,
|
||||
.pm = atmel_serial_pm,
|
||||
.ioctl = atmel_ioctl,
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_get_char = atmel_poll_get_char,
|
||||
.poll_put_char = atmel_poll_put_char,
|
||||
|
@ -2217,7 +2203,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
|
|||
if (!atmel_init_property(atmel_port, pdev))
|
||||
atmel_set_ops(port);
|
||||
|
||||
atmel_init_rs485(atmel_port, pdev);
|
||||
atmel_init_rs485(port, pdev);
|
||||
|
||||
port->iotype = UPIO_MEM;
|
||||
port->flags = UPF_BOOT_AUTOCONF;
|
||||
|
@ -2226,6 +2212,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
|
|||
port->dev = &pdev->dev;
|
||||
port->mapbase = pdev->resource[0].start;
|
||||
port->irq = pdev->resource[1].start;
|
||||
port->rs485_config = atmel_config_rs485;
|
||||
|
||||
tasklet_init(&atmel_port->tasklet, atmel_tasklet_func,
|
||||
(unsigned long)port);
|
||||
|
@ -2260,7 +2247,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
|
|||
}
|
||||
|
||||
/* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
|
||||
if (atmel_port->rs485.flags & SER_RS485_ENABLED)
|
||||
if (port->rs485.flags & SER_RS485_ENABLED)
|
||||
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
|
||||
else if (atmel_use_pdc_tx(port)) {
|
||||
port->fifosize = PDC_BUFFER_SIZE;
|
||||
|
@ -2541,6 +2528,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
|
|||
struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
void *data;
|
||||
int ret = -ENODEV;
|
||||
bool rs485_enabled;
|
||||
|
||||
BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
|
||||
|
||||
|
@ -2588,6 +2576,8 @@ static int atmel_serial_probe(struct platform_device *pdev)
|
|||
port->rx_ring.buf = data;
|
||||
}
|
||||
|
||||
rs485_enabled = port->uart.rs485.flags & SER_RS485_ENABLED;
|
||||
|
||||
ret = uart_add_one_port(&atmel_uart, &port->uart);
|
||||
if (ret)
|
||||
goto err_add_port;
|
||||
|
@ -2606,7 +2596,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
|
|||
device_init_wakeup(&pdev->dev, 1);
|
||||
platform_set_drvdata(pdev, port);
|
||||
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
if (rs485_enabled) {
|
||||
UART_PUT_MR(&port->uart, ATMEL_US_USMODE_NORMAL);
|
||||
UART_PUT_CR(&port->uart, ATMEL_US_RTSEN);
|
||||
}
|
||||
|
|
|
@ -588,20 +588,7 @@ static void bcm_uart_set_termios(struct uart_port *port,
|
|||
*/
|
||||
static int bcm_uart_request_port(struct uart_port *port)
|
||||
{
|
||||
unsigned int size;
|
||||
|
||||
size = UART_REG_SIZE;
|
||||
if (!request_mem_region(port->mapbase, size, "bcm63xx")) {
|
||||
dev_err(port->dev, "Memory region busy\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
port->membase = ioremap(port->mapbase, size);
|
||||
if (!port->membase) {
|
||||
dev_err(port->dev, "Unable to map registers\n");
|
||||
release_mem_region(port->mapbase, size);
|
||||
return -EBUSY;
|
||||
}
|
||||
/* UARTs always present */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -610,8 +597,7 @@ static int bcm_uart_request_port(struct uart_port *port)
|
|||
*/
|
||||
static void bcm_uart_release_port(struct uart_port *port)
|
||||
{
|
||||
release_mem_region(port->mapbase, UART_REG_SIZE);
|
||||
iounmap(port->membase);
|
||||
/* Nothing to release ... */
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -782,6 +768,26 @@ static int __init bcm63xx_console_init(void)
|
|||
|
||||
console_initcall(bcm63xx_console_init);
|
||||
|
||||
static void bcm_early_write(struct console *con, const char *s, unsigned n)
|
||||
{
|
||||
struct earlycon_device *dev = con->data;
|
||||
|
||||
uart_console_write(&dev->port, s, n, bcm_console_putchar);
|
||||
wait_for_xmitr(&dev->port);
|
||||
}
|
||||
|
||||
static int __init bcm_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
if (!device->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
device->con->write = bcm_early_write;
|
||||
return 0;
|
||||
}
|
||||
|
||||
OF_EARLYCON_DECLARE(bcm63xx_uart, "brcm,bcm6345-uart", bcm_early_console_setup);
|
||||
|
||||
#define BCM63XX_CONSOLE (&bcm63xx_console)
|
||||
#else
|
||||
#define BCM63XX_CONSOLE NULL
|
||||
|
@ -813,25 +819,30 @@ static int bcm_uart_probe(struct platform_device *pdev)
|
|||
if (pdev->id < 0 || pdev->id >= BCM63XX_NR_UARTS)
|
||||
return -EINVAL;
|
||||
|
||||
if (ports[pdev->id].membase)
|
||||
port = &ports[pdev->id];
|
||||
if (port->membase)
|
||||
return -EBUSY;
|
||||
memset(port, 0, sizeof(*port));
|
||||
|
||||
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res_mem)
|
||||
return -ENODEV;
|
||||
|
||||
port->mapbase = res_mem->start;
|
||||
port->membase = devm_ioremap_resource(&pdev->dev, res_mem);
|
||||
if (IS_ERR(port->membase))
|
||||
return PTR_ERR(port->membase);
|
||||
|
||||
res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!res_irq)
|
||||
return -ENODEV;
|
||||
|
||||
clk = clk_get(&pdev->dev, "periph");
|
||||
clk = pdev->dev.of_node ? of_clk_get(pdev->dev.of_node, 0) :
|
||||
clk_get(&pdev->dev, "periph");
|
||||
if (IS_ERR(clk))
|
||||
return -ENODEV;
|
||||
|
||||
port = &ports[pdev->id];
|
||||
memset(port, 0, sizeof(*port));
|
||||
port->iotype = UPIO_MEM;
|
||||
port->mapbase = res_mem->start;
|
||||
port->irq = res_irq->start;
|
||||
port->ops = &bcm_uart_ops;
|
||||
port->flags = UPF_BOOT_AUTOCONF;
|
||||
|
@ -905,5 +916,5 @@ module_init(bcm_uart_init);
|
|||
module_exit(bcm_uart_exit);
|
||||
|
||||
MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
|
||||
MODULE_DESCRIPTION("Broadcom 63<xx integrated uart driver");
|
||||
MODULE_DESCRIPTION("Broadcom 63xx integrated uart driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -517,14 +517,15 @@ static void sport_set_termios(struct uart_port *port,
|
|||
up->csize = 5;
|
||||
break;
|
||||
default:
|
||||
pr_warning("requested word length not supported\n");
|
||||
pr_warn("requested word length not supported\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (termios->c_cflag & CSTOPB) {
|
||||
up->stopb = 1;
|
||||
}
|
||||
if (termios->c_cflag & PARENB) {
|
||||
pr_warning("PAREN bits is not supported yet\n");
|
||||
pr_warn("PAREN bit is not supported yet\n");
|
||||
/* up->parib = 1; */
|
||||
}
|
||||
|
||||
|
|
|
@ -944,12 +944,13 @@ bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
|
|||
* Enable the IrDA function if tty->ldisc.num is N_IRDA.
|
||||
* In other cases, disable IrDA function.
|
||||
*/
|
||||
static void bfin_serial_set_ldisc(struct uart_port *port, int ld)
|
||||
static void bfin_serial_set_ldisc(struct uart_port *port,
|
||||
struct ktermios *termios)
|
||||
{
|
||||
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
|
||||
unsigned int val;
|
||||
|
||||
switch (ld) {
|
||||
switch (termios->c_line) {
|
||||
case N_IRDA:
|
||||
val = UART_GET_GCTL(uart);
|
||||
val |= (UMOD_IRDA | RPOLC);
|
||||
|
|
|
@ -225,13 +225,14 @@ static void uart_clps711x_break_ctl(struct uart_port *port, int break_state)
|
|||
writel(ubrlcr, port->membase + UBRLCR_OFFSET);
|
||||
}
|
||||
|
||||
static void uart_clps711x_set_ldisc(struct uart_port *port, int ld)
|
||||
static void uart_clps711x_set_ldisc(struct uart_port *port,
|
||||
struct ktermios *termios)
|
||||
{
|
||||
if (!port->line) {
|
||||
struct clps711x_port *s = dev_get_drvdata(port->dev);
|
||||
|
||||
regmap_update_bits(s->syscon, SYSCON_OFFSET, SYSCON1_SIREN,
|
||||
(ld == N_IRDA) ? SYSCON1_SIREN : 0);
|
||||
(termios->c_line == N_IRDA) ? SYSCON1_SIREN : 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,8 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo);
|
|||
*/
|
||||
static unsigned int cpm_uart_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
struct uart_cpm_port *pinfo =
|
||||
container_of(port, struct uart_cpm_port, port);
|
||||
cbd_t __iomem *bdp = pinfo->tx_bd_base;
|
||||
int ret = 0;
|
||||
|
||||
|
@ -102,7 +103,8 @@ static unsigned int cpm_uart_tx_empty(struct uart_port *port)
|
|||
|
||||
static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
struct uart_cpm_port *pinfo =
|
||||
container_of(port, struct uart_cpm_port, port);
|
||||
|
||||
if (pinfo->gpios[GPIO_RTS] >= 0)
|
||||
gpio_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS));
|
||||
|
@ -113,7 +115,8 @@ static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
|||
|
||||
static unsigned int cpm_uart_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
struct uart_cpm_port *pinfo =
|
||||
container_of(port, struct uart_cpm_port, port);
|
||||
unsigned int mctrl = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
|
||||
|
||||
if (pinfo->gpios[GPIO_CTS] >= 0) {
|
||||
|
@ -144,7 +147,8 @@ static unsigned int cpm_uart_get_mctrl(struct uart_port *port)
|
|||
*/
|
||||
static void cpm_uart_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
struct uart_cpm_port *pinfo =
|
||||
container_of(port, struct uart_cpm_port, port);
|
||||
smc_t __iomem *smcp = pinfo->smcp;
|
||||
scc_t __iomem *sccp = pinfo->sccp;
|
||||
|
||||
|
@ -161,7 +165,8 @@ static void cpm_uart_stop_tx(struct uart_port *port)
|
|||
*/
|
||||
static void cpm_uart_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
struct uart_cpm_port *pinfo =
|
||||
container_of(port, struct uart_cpm_port, port);
|
||||
smc_t __iomem *smcp = pinfo->smcp;
|
||||
scc_t __iomem *sccp = pinfo->sccp;
|
||||
|
||||
|
@ -189,7 +194,8 @@ static void cpm_uart_start_tx(struct uart_port *port)
|
|||
*/
|
||||
static void cpm_uart_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
struct uart_cpm_port *pinfo =
|
||||
container_of(port, struct uart_cpm_port, port);
|
||||
smc_t __iomem *smcp = pinfo->smcp;
|
||||
scc_t __iomem *sccp = pinfo->sccp;
|
||||
|
||||
|
@ -206,7 +212,8 @@ static void cpm_uart_stop_rx(struct uart_port *port)
|
|||
*/
|
||||
static void cpm_uart_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
struct uart_cpm_port *pinfo =
|
||||
container_of(port, struct uart_cpm_port, port);
|
||||
|
||||
pr_debug("CPM uart[%d]:break ctrl, break_state: %d\n", port->line,
|
||||
break_state);
|
||||
|
@ -240,7 +247,8 @@ static void cpm_uart_int_rx(struct uart_port *port)
|
|||
unsigned char ch;
|
||||
u8 *cp;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
struct uart_cpm_port *pinfo =
|
||||
container_of(port, struct uart_cpm_port, port);
|
||||
cbd_t __iomem *bdp;
|
||||
u16 status;
|
||||
unsigned int flg;
|
||||
|
@ -397,7 +405,8 @@ static irqreturn_t cpm_uart_int(int irq, void *data)
|
|||
static int cpm_uart_startup(struct uart_port *port)
|
||||
{
|
||||
int retval;
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
struct uart_cpm_port *pinfo =
|
||||
container_of(port, struct uart_cpm_port, port);
|
||||
|
||||
pr_debug("CPM uart[%d]:startup\n", port->line);
|
||||
|
||||
|
@ -442,7 +451,8 @@ inline void cpm_uart_wait_until_send(struct uart_cpm_port *pinfo)
|
|||
*/
|
||||
static void cpm_uart_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
struct uart_cpm_port *pinfo =
|
||||
container_of(port, struct uart_cpm_port, port);
|
||||
|
||||
pr_debug("CPM uart[%d]:shutdown\n", port->line);
|
||||
|
||||
|
@ -492,7 +502,8 @@ static void cpm_uart_set_termios(struct uart_port *port,
|
|||
unsigned long flags;
|
||||
u16 cval, scval, prev_mode;
|
||||
int bits, sbits;
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
struct uart_cpm_port *pinfo =
|
||||
container_of(port, struct uart_cpm_port, port);
|
||||
smc_t __iomem *smcp = pinfo->smcp;
|
||||
scc_t __iomem *sccp = pinfo->sccp;
|
||||
int maxidl;
|
||||
|
@ -675,7 +686,8 @@ static int cpm_uart_tx_pump(struct uart_port *port)
|
|||
cbd_t __iomem *bdp;
|
||||
u8 *p;
|
||||
int count;
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
struct uart_cpm_port *pinfo =
|
||||
container_of(port, struct uart_cpm_port, port);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
|
||||
/* Handle xon/xoff */
|
||||
|
@ -906,7 +918,8 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
|
|||
*/
|
||||
static int cpm_uart_request_port(struct uart_port *port)
|
||||
{
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
struct uart_cpm_port *pinfo =
|
||||
container_of(port, struct uart_cpm_port, port);
|
||||
int ret;
|
||||
|
||||
pr_debug("CPM uart[%d]:request port\n", port->line);
|
||||
|
@ -938,7 +951,8 @@ static int cpm_uart_request_port(struct uart_port *port)
|
|||
|
||||
static void cpm_uart_release_port(struct uart_port *port)
|
||||
{
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
struct uart_cpm_port *pinfo =
|
||||
container_of(port, struct uart_cpm_port, port);
|
||||
|
||||
if (!(pinfo->flags & FLAG_CONSOLE))
|
||||
cpm_uart_freebuf(pinfo);
|
||||
|
@ -1082,7 +1096,8 @@ static int poll_wait_key(char *obuf, struct uart_cpm_port *pinfo)
|
|||
|
||||
static int cpm_get_poll_char(struct uart_port *port)
|
||||
{
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
struct uart_cpm_port *pinfo =
|
||||
container_of(port, struct uart_cpm_port, port);
|
||||
|
||||
if (!serial_polled) {
|
||||
serial_polled = 1;
|
||||
|
@ -1099,7 +1114,8 @@ static int cpm_get_poll_char(struct uart_port *port)
|
|||
static void cpm_put_poll_char(struct uart_port *port,
|
||||
unsigned char c)
|
||||
{
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
struct uart_cpm_port *pinfo =
|
||||
container_of(port, struct uart_cpm_port, port);
|
||||
static char ch[2];
|
||||
|
||||
ch[0] = (char)c;
|
||||
|
|
|
@ -3675,12 +3675,6 @@ rs_close(struct tty_struct *tty, struct file * filp)
|
|||
return;
|
||||
}
|
||||
info->port.flags |= ASYNC_CLOSING;
|
||||
/*
|
||||
* Save the termios structure, since this port may have
|
||||
* separate termios for callout and dialin.
|
||||
*/
|
||||
if (info->port.flags & ASYNC_NORMAL_ACTIVE)
|
||||
info->normal_termios = tty->termios;
|
||||
/*
|
||||
* Now we wait for the transmit buffer to clear; and we notify
|
||||
* the line discipline to only process XON/XOFF characters.
|
||||
|
@ -4076,11 +4070,6 @@ rs_open(struct tty_struct *tty, struct file * filp)
|
|||
return retval;
|
||||
}
|
||||
|
||||
if ((info->port.count == 1) && (info->port.flags & ASYNC_SPLIT_TERMIOS)) {
|
||||
tty->termios = info->normal_termios;
|
||||
change_speed(info);
|
||||
}
|
||||
|
||||
#ifdef SERIAL_DEBUG_OPEN
|
||||
printk("rs_open ttyS%d successful...\n", info->line);
|
||||
#endif
|
||||
|
@ -4327,7 +4316,6 @@ static int __init rs_init(void)
|
|||
info->custom_divisor = 0;
|
||||
info->x_char = 0;
|
||||
info->event = 0;
|
||||
info->normal_termios = driver->init_termios;
|
||||
info->xmit.buf = NULL;
|
||||
info->xmit.tail = info->xmit.head = 0;
|
||||
info->first_recv_buffer = info->last_recv_buffer = NULL;
|
||||
|
|
|
@ -98,7 +98,6 @@ struct e100_serial {
|
|||
|
||||
struct work_struct work;
|
||||
struct async_icount icount; /* error-statistics etc.*/
|
||||
struct ktermios normal_termios;
|
||||
|
||||
unsigned long char_time_usec; /* The time for 1 char, in usecs */
|
||||
unsigned long flush_time_usec; /* How often we should flush */
|
||||
|
|
|
@ -98,7 +98,7 @@ static int __init parse_options(struct earlycon_device *device,
|
|||
strlcpy(device->options, options, length);
|
||||
}
|
||||
|
||||
if (mmio || mmio32)
|
||||
if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32)
|
||||
pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n",
|
||||
mmio32 ? "32" : "",
|
||||
(unsigned long long)port->mapbase,
|
||||
|
|
|
@ -1786,15 +1786,13 @@ static int lpuart_probe(struct platform_device *pdev)
|
|||
}
|
||||
sport->port.line = ret;
|
||||
sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart");
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
sport->port.mapbase = res->start;
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
sport->port.membase = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(sport->port.membase))
|
||||
return PTR_ERR(sport->port.membase);
|
||||
|
||||
sport->port.mapbase = res->start;
|
||||
sport->port.dev = &pdev->dev;
|
||||
sport->port.type = PORT_LPUART;
|
||||
sport->port.iotype = UPIO_MEM;
|
||||
|
@ -1862,6 +1860,20 @@ static int lpuart_suspend(struct device *dev)
|
|||
static int lpuart_resume(struct device *dev)
|
||||
{
|
||||
struct lpuart_port *sport = dev_get_drvdata(dev);
|
||||
unsigned long temp;
|
||||
|
||||
if (sport->lpuart32) {
|
||||
lpuart32_setup_watermark(sport);
|
||||
temp = lpuart32_read(sport->port.membase + UARTCTRL);
|
||||
temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE |
|
||||
UARTCTRL_TE | UARTCTRL_ILIE);
|
||||
lpuart32_write(temp, sport->port.membase + UARTCTRL);
|
||||
} else {
|
||||
lpuart_setup_watermark(sport);
|
||||
temp = readb(sport->port.membase + UARTCR2);
|
||||
temp |= (UARTCR2_RIE | UARTCR2_TIE | UARTCR2_RE | UARTCR2_TE);
|
||||
writeb(temp, sport->port.membase + UARTCR2);
|
||||
}
|
||||
|
||||
uart_resume_port(&lpuart_reg, &sport->port);
|
||||
|
||||
|
@ -1884,11 +1896,8 @@ static struct platform_driver lpuart_driver = {
|
|||
|
||||
static int __init lpuart_serial_init(void)
|
||||
{
|
||||
int ret;
|
||||
int ret = uart_register_driver(&lpuart_reg);
|
||||
|
||||
pr_info("serial: Freescale lpuart driver\n");
|
||||
|
||||
ret = uart_register_driver(&lpuart_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -1550,8 +1550,10 @@ static int icom_probe(struct pci_dev *dev,
|
|||
|
||||
icom_adapter->base_addr = pci_ioremap_bar(dev, 0);
|
||||
|
||||
if (!icom_adapter->base_addr)
|
||||
if (!icom_adapter->base_addr) {
|
||||
retval = -ENOMEM;
|
||||
goto probe_exit1;
|
||||
}
|
||||
|
||||
/* save off irq and request irq line */
|
||||
if ( (retval = request_irq(dev->irq, icom_interrupt,
|
||||
|
|
|
@ -302,7 +302,7 @@ static inline int is_imx6q_uart(struct imx_port *sport)
|
|||
/*
|
||||
* Save and restore functions for UCR1, UCR2 and UCR3 registers
|
||||
*/
|
||||
#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_IMX_CONSOLE)
|
||||
#if defined(CONFIG_SERIAL_IMX_CONSOLE)
|
||||
static void imx_port_ucrs_save(struct uart_port *port,
|
||||
struct imx_port_ucrs *ucr)
|
||||
{
|
||||
|
@ -991,7 +991,6 @@ static int imx_uart_dma_init(struct imx_port *sport)
|
|||
|
||||
sport->rx_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!sport->rx_buf) {
|
||||
dev_err(dev, "cannot alloc DMA buffer.\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
@ -1076,11 +1075,11 @@ static int imx_startup(struct uart_port *port)
|
|||
|
||||
retval = clk_prepare_enable(sport->clk_per);
|
||||
if (retval)
|
||||
goto error_out1;
|
||||
return retval;
|
||||
retval = clk_prepare_enable(sport->clk_ipg);
|
||||
if (retval) {
|
||||
clk_disable_unprepare(sport->clk_per);
|
||||
goto error_out1;
|
||||
return retval;
|
||||
}
|
||||
|
||||
imx_setup_ufcr(sport, 0);
|
||||
|
@ -1109,37 +1108,6 @@ static int imx_startup(struct uart_port *port)
|
|||
while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
|
||||
udelay(1);
|
||||
|
||||
/*
|
||||
* Allocate the IRQ(s) i.MX1 has three interrupts whereas later
|
||||
* chips only have one interrupt.
|
||||
*/
|
||||
if (sport->txirq > 0) {
|
||||
retval = request_irq(sport->rxirq, imx_rxint, 0,
|
||||
dev_name(port->dev), sport);
|
||||
if (retval)
|
||||
goto error_out1;
|
||||
|
||||
retval = request_irq(sport->txirq, imx_txint, 0,
|
||||
dev_name(port->dev), sport);
|
||||
if (retval)
|
||||
goto error_out2;
|
||||
|
||||
/* do not use RTS IRQ on IrDA */
|
||||
if (!USE_IRDA(sport)) {
|
||||
retval = request_irq(sport->rtsirq, imx_rtsint, 0,
|
||||
dev_name(port->dev), sport);
|
||||
if (retval)
|
||||
goto error_out3;
|
||||
}
|
||||
} else {
|
||||
retval = request_irq(sport->port.irq, imx_int, 0,
|
||||
dev_name(port->dev), sport);
|
||||
if (retval) {
|
||||
free_irq(sport->port.irq, sport);
|
||||
goto error_out1;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
/*
|
||||
* Finally, clear and enable interrupts
|
||||
|
@ -1201,15 +1169,6 @@ static int imx_startup(struct uart_port *port)
|
|||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_out3:
|
||||
if (sport->txirq)
|
||||
free_irq(sport->txirq, sport);
|
||||
error_out2:
|
||||
if (sport->rxirq)
|
||||
free_irq(sport->rxirq, sport);
|
||||
error_out1:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void imx_shutdown(struct uart_port *port)
|
||||
|
@ -1254,17 +1213,6 @@ static void imx_shutdown(struct uart_port *port)
|
|||
*/
|
||||
del_timer_sync(&sport->timer);
|
||||
|
||||
/*
|
||||
* Free the interrupts
|
||||
*/
|
||||
if (sport->txirq > 0) {
|
||||
if (!USE_IRDA(sport))
|
||||
free_irq(sport->rtsirq, sport);
|
||||
free_irq(sport->txirq, sport);
|
||||
free_irq(sport->rxirq, sport);
|
||||
} else
|
||||
free_irq(sport->port.irq, sport);
|
||||
|
||||
/*
|
||||
* Disable all interrupts, port and break condition.
|
||||
*/
|
||||
|
@ -1507,44 +1455,65 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser)
|
|||
}
|
||||
|
||||
#if defined(CONFIG_CONSOLE_POLL)
|
||||
|
||||
static int imx_poll_init(struct uart_port *port)
|
||||
{
|
||||
struct imx_port *sport = (struct imx_port *)port;
|
||||
unsigned long flags;
|
||||
unsigned long temp;
|
||||
int retval;
|
||||
|
||||
retval = clk_prepare_enable(sport->clk_ipg);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = clk_prepare_enable(sport->clk_per);
|
||||
if (retval)
|
||||
clk_disable_unprepare(sport->clk_ipg);
|
||||
|
||||
imx_setup_ufcr(sport, 0);
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
temp = readl(sport->port.membase + UCR1);
|
||||
if (is_imx1_uart(sport))
|
||||
temp |= IMX1_UCR1_UARTCLKEN;
|
||||
temp |= UCR1_UARTEN | UCR1_RRDYEN;
|
||||
temp &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN);
|
||||
writel(temp, sport->port.membase + UCR1);
|
||||
|
||||
temp = readl(sport->port.membase + UCR2);
|
||||
temp |= UCR2_RXEN;
|
||||
writel(temp, sport->port.membase + UCR2);
|
||||
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_poll_get_char(struct uart_port *port)
|
||||
{
|
||||
if (!(readl(port->membase + USR2) & USR2_RDR))
|
||||
if (!(readl_relaxed(port->membase + USR2) & USR2_RDR))
|
||||
return NO_POLL_CHAR;
|
||||
|
||||
return readl(port->membase + URXD0) & URXD_RX_DATA;
|
||||
return readl_relaxed(port->membase + URXD0) & URXD_RX_DATA;
|
||||
}
|
||||
|
||||
static void imx_poll_put_char(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
struct imx_port_ucrs old_ucr;
|
||||
unsigned int status;
|
||||
|
||||
/* save control registers */
|
||||
imx_port_ucrs_save(port, &old_ucr);
|
||||
|
||||
/* disable interrupts */
|
||||
writel(UCR1_UARTEN, port->membase + UCR1);
|
||||
writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI),
|
||||
port->membase + UCR2);
|
||||
writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN),
|
||||
port->membase + UCR3);
|
||||
|
||||
/* drain */
|
||||
do {
|
||||
status = readl(port->membase + USR1);
|
||||
status = readl_relaxed(port->membase + USR1);
|
||||
} while (~status & USR1_TRDY);
|
||||
|
||||
/* write */
|
||||
writel(c, port->membase + URTX0);
|
||||
writel_relaxed(c, port->membase + URTX0);
|
||||
|
||||
/* flush */
|
||||
do {
|
||||
status = readl(port->membase + USR2);
|
||||
status = readl_relaxed(port->membase + USR2);
|
||||
} while (~status & USR2_TXDC);
|
||||
|
||||
/* restore control registers */
|
||||
imx_port_ucrs_restore(port, &old_ucr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1565,6 +1534,7 @@ static struct uart_ops imx_pops = {
|
|||
.config_port = imx_config_port,
|
||||
.verify_port = imx_verify_port,
|
||||
#if defined(CONFIG_CONSOLE_POLL)
|
||||
.poll_init = imx_poll_init,
|
||||
.poll_get_char = imx_poll_get_char,
|
||||
.poll_put_char = imx_poll_put_char,
|
||||
#endif
|
||||
|
@ -1929,6 +1899,36 @@ static int serial_imx_probe(struct platform_device *pdev)
|
|||
|
||||
sport->port.uartclk = clk_get_rate(sport->clk_per);
|
||||
|
||||
/*
|
||||
* Allocate the IRQ(s) i.MX1 has three interrupts whereas later
|
||||
* chips only have one interrupt.
|
||||
*/
|
||||
if (sport->txirq > 0) {
|
||||
ret = devm_request_irq(&pdev->dev, sport->rxirq, imx_rxint, 0,
|
||||
dev_name(&pdev->dev), sport);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, sport->txirq, imx_txint, 0,
|
||||
dev_name(&pdev->dev), sport);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* do not use RTS IRQ on IrDA */
|
||||
if (!USE_IRDA(sport)) {
|
||||
ret = devm_request_irq(&pdev->dev, sport->rtsirq,
|
||||
imx_rtsint, 0,
|
||||
dev_name(&pdev->dev), sport);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
ret = devm_request_irq(&pdev->dev, sport->port.irq, imx_int, 0,
|
||||
dev_name(&pdev->dev), sport);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
imx_ports[sport->port.line] = sport;
|
||||
|
||||
platform_set_drvdata(pdev, sport);
|
||||
|
@ -1959,11 +1959,8 @@ static struct platform_driver serial_imx_driver = {
|
|||
|
||||
static int __init imx_serial_init(void)
|
||||
{
|
||||
int ret;
|
||||
int ret = uart_register_driver(&imx_reg);
|
||||
|
||||
pr_info("Serial: IMX driver\n");
|
||||
|
||||
ret = uart_register_driver(&imx_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -544,7 +544,8 @@ static unsigned int ip22zilog_get_mctrl(struct uart_port *port)
|
|||
/* The port lock is held and interrupts are disabled. */
|
||||
static void ip22zilog_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
|
||||
struct uart_ip22zilog_port *up =
|
||||
container_of(port, struct uart_ip22zilog_port, port);
|
||||
struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
|
||||
unsigned char set_bits, clear_bits;
|
||||
|
||||
|
@ -568,7 +569,8 @@ static void ip22zilog_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
|||
/* The port lock is held and interrupts are disabled. */
|
||||
static void ip22zilog_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
|
||||
struct uart_ip22zilog_port *up =
|
||||
container_of(port, struct uart_ip22zilog_port, port);
|
||||
|
||||
up->flags |= IP22ZILOG_FLAG_TX_STOPPED;
|
||||
}
|
||||
|
@ -576,7 +578,8 @@ static void ip22zilog_stop_tx(struct uart_port *port)
|
|||
/* The port lock is held and interrupts are disabled. */
|
||||
static void ip22zilog_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
|
||||
struct uart_ip22zilog_port *up =
|
||||
container_of(port, struct uart_ip22zilog_port, port);
|
||||
struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
|
||||
unsigned char status;
|
||||
|
||||
|
@ -636,7 +639,8 @@ static void ip22zilog_stop_rx(struct uart_port *port)
|
|||
/* The port lock is held. */
|
||||
static void ip22zilog_enable_ms(struct uart_port *port)
|
||||
{
|
||||
struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
|
||||
struct uart_ip22zilog_port *up =
|
||||
container_of(port, struct uart_ip22zilog_port, port);
|
||||
struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
|
||||
unsigned char new_reg;
|
||||
|
||||
|
@ -652,7 +656,8 @@ static void ip22zilog_enable_ms(struct uart_port *port)
|
|||
/* The port lock is not held. */
|
||||
static void ip22zilog_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
|
||||
struct uart_ip22zilog_port *up =
|
||||
container_of(port, struct uart_ip22zilog_port, port);
|
||||
struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
|
||||
unsigned char set_bits, clear_bits, new_reg;
|
||||
unsigned long flags;
|
||||
|
@ -873,7 +878,8 @@ static void
|
|||
ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct uart_ip22zilog_port *up = (struct uart_ip22zilog_port *) port;
|
||||
struct uart_ip22zilog_port *up =
|
||||
container_of(port, struct uart_ip22zilog_port, port);
|
||||
unsigned long flags;
|
||||
int baud, brg;
|
||||
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
|
||||
obj-$(CONFIG_SERIAL_JSM) += jsm.o
|
||||
|
||||
jsm-objs := jsm_driver.o jsm_neo.o jsm_tty.o
|
||||
jsm-objs := jsm_driver.o jsm_neo.o jsm_tty.o jsm_cls.o
|
||||
|
||||
|
|
|
@ -13,11 +13,6 @@
|
|||
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 * Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
* Contact Information:
|
||||
* Scott H Kilau <Scott_Kilau@digi.com>
|
||||
* Wendy Xiong <wendyx@us.ibm.com>
|
||||
|
@ -68,6 +63,10 @@ do { \
|
|||
#define MAX_STOPS_SENT 5
|
||||
|
||||
/* Board ids */
|
||||
#define PCI_DEVICE_ID_CLASSIC_4 0x0028
|
||||
#define PCI_DEVICE_ID_CLASSIC_8 0x0029
|
||||
#define PCI_DEVICE_ID_CLASSIC_4_422 0x00D0
|
||||
#define PCI_DEVICE_ID_CLASSIC_8_422 0x00D1
|
||||
#define PCI_DEVICE_ID_NEO_4 0x00B0
|
||||
#define PCI_DEVICE_ID_NEO_1_422 0x00CC
|
||||
#define PCI_DEVICE_ID_NEO_1_422_485 0x00CD
|
||||
|
@ -112,21 +111,21 @@ struct jsm_channel;
|
|||
************************************************************************/
|
||||
struct board_ops {
|
||||
irq_handler_t intr;
|
||||
void (*uart_init) (struct jsm_channel *ch);
|
||||
void (*uart_off) (struct jsm_channel *ch);
|
||||
void (*param) (struct jsm_channel *ch);
|
||||
void (*assert_modem_signals) (struct jsm_channel *ch);
|
||||
void (*flush_uart_write) (struct jsm_channel *ch);
|
||||
void (*flush_uart_read) (struct jsm_channel *ch);
|
||||
void (*disable_receiver) (struct jsm_channel *ch);
|
||||
void (*enable_receiver) (struct jsm_channel *ch);
|
||||
void (*send_break) (struct jsm_channel *ch);
|
||||
void (*clear_break) (struct jsm_channel *ch, int);
|
||||
void (*send_start_character) (struct jsm_channel *ch);
|
||||
void (*send_stop_character) (struct jsm_channel *ch);
|
||||
void (*copy_data_from_queue_to_uart) (struct jsm_channel *ch);
|
||||
u32 (*get_uart_bytes_left) (struct jsm_channel *ch);
|
||||
void (*send_immediate_char) (struct jsm_channel *ch, unsigned char);
|
||||
void (*uart_init)(struct jsm_channel *ch);
|
||||
void (*uart_off)(struct jsm_channel *ch);
|
||||
void (*param)(struct jsm_channel *ch);
|
||||
void (*assert_modem_signals)(struct jsm_channel *ch);
|
||||
void (*flush_uart_write)(struct jsm_channel *ch);
|
||||
void (*flush_uart_read)(struct jsm_channel *ch);
|
||||
void (*disable_receiver)(struct jsm_channel *ch);
|
||||
void (*enable_receiver)(struct jsm_channel *ch);
|
||||
void (*send_break)(struct jsm_channel *ch);
|
||||
void (*clear_break)(struct jsm_channel *ch);
|
||||
void (*send_start_character)(struct jsm_channel *ch);
|
||||
void (*send_stop_character)(struct jsm_channel *ch);
|
||||
void (*copy_data_from_queue_to_uart)(struct jsm_channel *ch);
|
||||
u32 (*get_uart_bytes_left)(struct jsm_channel *ch);
|
||||
void (*send_immediate_char)(struct jsm_channel *ch, unsigned char);
|
||||
};
|
||||
|
||||
|
||||
|
@ -189,7 +188,7 @@ struct jsm_board
|
|||
#define CH_LOOPBACK 0x2000 /* Channel is in lookback mode */
|
||||
#define CH_BAUD0 0x08000 /* Used for checking B0 transitions */
|
||||
|
||||
/* Our Read/Error/Write queue sizes */
|
||||
/* Our Read/Error queue sizes */
|
||||
#define RQUEUEMASK 0x1FFF /* 8 K - 1 */
|
||||
#define EQUEUEMASK 0x1FFF /* 8 K - 1 */
|
||||
#define RQUEUESIZE (RQUEUEMASK + 1)
|
||||
|
@ -222,7 +221,10 @@ struct jsm_channel {
|
|||
u8 ch_mostat; /* FEP output modem status */
|
||||
u8 ch_mistat; /* FEP input modem status */
|
||||
|
||||
struct neo_uart_struct __iomem *ch_neo_uart; /* Pointer to the "mapped" UART struct */
|
||||
/* Pointers to the "mapped" UART structs */
|
||||
struct neo_uart_struct __iomem *ch_neo_uart; /* NEO card */
|
||||
struct cls_uart_struct __iomem *ch_cls_uart; /* Classic card */
|
||||
|
||||
u8 ch_cached_lsr; /* Cached value of the LSR register */
|
||||
|
||||
u8 *ch_rqueue; /* Our read queue buffer - malloc'ed */
|
||||
|
@ -254,6 +256,60 @@ struct jsm_channel {
|
|||
u64 ch_xoff_sends; /* Count of xoffs transmitted */
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* Per channel/port Classic UART structures *
|
||||
************************************************************************
|
||||
* Base Structure Entries Usage Meanings to Host *
|
||||
* *
|
||||
* W = read write R = read only *
|
||||
* U = Unused. *
|
||||
************************************************************************/
|
||||
|
||||
struct cls_uart_struct {
|
||||
u8 txrx; /* WR RHR/THR - Holding Reg */
|
||||
u8 ier; /* WR IER - Interrupt Enable Reg */
|
||||
u8 isr_fcr; /* WR ISR/FCR - Interrupt Status Reg/Fifo Control Reg*/
|
||||
u8 lcr; /* WR LCR - Line Control Reg */
|
||||
u8 mcr; /* WR MCR - Modem Control Reg */
|
||||
u8 lsr; /* WR LSR - Line Status Reg */
|
||||
u8 msr; /* WR MSR - Modem Status Reg */
|
||||
u8 spr; /* WR SPR - Scratch Pad Reg */
|
||||
};
|
||||
|
||||
/* Where to read the interrupt register (8bits) */
|
||||
#define UART_CLASSIC_POLL_ADDR_OFFSET 0x40
|
||||
|
||||
#define UART_EXAR654_ENHANCED_REGISTER_SET 0xBF
|
||||
|
||||
#define UART_16654_FCR_TXTRIGGER_8 0x0
|
||||
#define UART_16654_FCR_TXTRIGGER_16 0x10
|
||||
#define UART_16654_FCR_TXTRIGGER_32 0x20
|
||||
#define UART_16654_FCR_TXTRIGGER_56 0x30
|
||||
|
||||
#define UART_16654_FCR_RXTRIGGER_8 0x0
|
||||
#define UART_16654_FCR_RXTRIGGER_16 0x40
|
||||
#define UART_16654_FCR_RXTRIGGER_56 0x80
|
||||
#define UART_16654_FCR_RXTRIGGER_60 0xC0
|
||||
|
||||
#define UART_IIR_CTSRTS 0x20 /* Received CTS/RTS change of state */
|
||||
#define UART_IIR_RDI_TIMEOUT 0x0C /* Receiver data TIMEOUT */
|
||||
|
||||
/*
|
||||
* These are the EXTENDED definitions for the Exar 654's Interrupt
|
||||
* Enable Register.
|
||||
*/
|
||||
#define UART_EXAR654_EFR_ECB 0x10 /* Enhanced control bit */
|
||||
#define UART_EXAR654_EFR_IXON 0x2 /* Receiver compares Xon1/Xoff1 */
|
||||
#define UART_EXAR654_EFR_IXOFF 0x8 /* Transmit Xon1/Xoff1 */
|
||||
#define UART_EXAR654_EFR_RTSDTR 0x40 /* Auto RTS/DTR Flow Control Enable */
|
||||
#define UART_EXAR654_EFR_CTSDSR 0x80 /* Auto CTS/DSR Flow COntrol Enable */
|
||||
|
||||
#define UART_EXAR654_XOFF_DETECT 0x1 /* Indicates whether chip saw an incoming XOFF char */
|
||||
#define UART_EXAR654_XON_DETECT 0x2 /* Indicates whether chip saw an incoming XON char */
|
||||
|
||||
#define UART_EXAR654_IER_XOFF 0x20 /* Xoff Interrupt Enable */
|
||||
#define UART_EXAR654_IER_RTSDTR 0x40 /* Output Interrupt Enable */
|
||||
#define UART_EXAR654_IER_CTSDSR 0x80 /* Input Interrupt Enable */
|
||||
|
||||
/************************************************************************
|
||||
* Per channel/port NEO UART structure *
|
||||
|
@ -374,6 +430,7 @@ struct neo_uart_struct {
|
|||
*/
|
||||
extern struct uart_driver jsm_uart_driver;
|
||||
extern struct board_ops jsm_neo_ops;
|
||||
extern struct board_ops jsm_cls_ops;
|
||||
extern int jsm_debug;
|
||||
|
||||
/*************************************************************************
|
||||
|
|
|
@ -0,0 +1,982 @@
|
|||
/*
|
||||
* Copyright 2003 Digi International (www.digi.com)
|
||||
* Scott H Kilau <Scott_Kilau at digi dot com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
|
||||
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
|
||||
*
|
||||
* This is shared code between Digi's CVS archive and the
|
||||
* Linux Kernel sources.
|
||||
* Changing the source just for reformatting needlessly breaks
|
||||
* our CVS diff history.
|
||||
*
|
||||
* Send any bug fixes/changes to: Eng.Linux at digi dot com.
|
||||
* Thank you.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/delay.h> /* For udelay */
|
||||
#include <linux/io.h> /* For read[bwl]/write[bwl] */
|
||||
#include <linux/serial.h> /* For struct async_serial */
|
||||
#include <linux/serial_reg.h> /* For the various UART offsets */
|
||||
#include <linux/pci.h>
|
||||
#include <linux/tty.h>
|
||||
|
||||
#include "jsm.h" /* Driver main header file */
|
||||
|
||||
static struct {
|
||||
unsigned int rate;
|
||||
unsigned int cflag;
|
||||
} baud_rates[] = {
|
||||
{ 921600, B921600 },
|
||||
{ 460800, B460800 },
|
||||
{ 230400, B230400 },
|
||||
{ 115200, B115200 },
|
||||
{ 57600, B57600 },
|
||||
{ 38400, B38400 },
|
||||
{ 19200, B19200 },
|
||||
{ 9600, B9600 },
|
||||
{ 4800, B4800 },
|
||||
{ 2400, B2400 },
|
||||
{ 1200, B1200 },
|
||||
{ 600, B600 },
|
||||
{ 300, B300 },
|
||||
{ 200, B200 },
|
||||
{ 150, B150 },
|
||||
{ 134, B134 },
|
||||
{ 110, B110 },
|
||||
{ 75, B75 },
|
||||
{ 50, B50 },
|
||||
};
|
||||
|
||||
static void cls_set_cts_flow_control(struct jsm_channel *ch)
|
||||
{
|
||||
u8 lcrb = readb(&ch->ch_cls_uart->lcr);
|
||||
u8 ier = readb(&ch->ch_cls_uart->ier);
|
||||
u8 isr_fcr = 0;
|
||||
|
||||
/*
|
||||
* The Enhanced Register Set may only be accessed when
|
||||
* the Line Control Register is set to 0xBFh.
|
||||
*/
|
||||
writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
|
||||
|
||||
isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
/* Turn on CTS flow control, turn off IXON flow control */
|
||||
isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_CTSDSR);
|
||||
isr_fcr &= ~(UART_EXAR654_EFR_IXON);
|
||||
|
||||
writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
/* Write old LCR value back out, which turns enhanced access off */
|
||||
writeb(lcrb, &ch->ch_cls_uart->lcr);
|
||||
|
||||
/*
|
||||
* Enable interrupts for CTS flow, turn off interrupts for
|
||||
* received XOFF chars
|
||||
*/
|
||||
ier |= (UART_EXAR654_IER_CTSDSR);
|
||||
ier &= ~(UART_EXAR654_IER_XOFF);
|
||||
writeb(ier, &ch->ch_cls_uart->ier);
|
||||
|
||||
/* Set the usual FIFO values */
|
||||
writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 |
|
||||
UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
|
||||
&ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
ch->ch_t_tlevel = 16;
|
||||
}
|
||||
|
||||
static void cls_set_ixon_flow_control(struct jsm_channel *ch)
|
||||
{
|
||||
u8 lcrb = readb(&ch->ch_cls_uart->lcr);
|
||||
u8 ier = readb(&ch->ch_cls_uart->ier);
|
||||
u8 isr_fcr = 0;
|
||||
|
||||
/*
|
||||
* The Enhanced Register Set may only be accessed when
|
||||
* the Line Control Register is set to 0xBFh.
|
||||
*/
|
||||
writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
|
||||
|
||||
isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
/* Turn on IXON flow control, turn off CTS flow control */
|
||||
isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXON);
|
||||
isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR);
|
||||
|
||||
writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
/* Now set our current start/stop chars while in enhanced mode */
|
||||
writeb(ch->ch_startc, &ch->ch_cls_uart->mcr);
|
||||
writeb(0, &ch->ch_cls_uart->lsr);
|
||||
writeb(ch->ch_stopc, &ch->ch_cls_uart->msr);
|
||||
writeb(0, &ch->ch_cls_uart->spr);
|
||||
|
||||
/* Write old LCR value back out, which turns enhanced access off */
|
||||
writeb(lcrb, &ch->ch_cls_uart->lcr);
|
||||
|
||||
/*
|
||||
* Disable interrupts for CTS flow, turn on interrupts for
|
||||
* received XOFF chars
|
||||
*/
|
||||
ier &= ~(UART_EXAR654_IER_CTSDSR);
|
||||
ier |= (UART_EXAR654_IER_XOFF);
|
||||
writeb(ier, &ch->ch_cls_uart->ier);
|
||||
|
||||
/* Set the usual FIFO values */
|
||||
writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
|
||||
UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
|
||||
&ch->ch_cls_uart->isr_fcr);
|
||||
}
|
||||
|
||||
static void cls_set_no_output_flow_control(struct jsm_channel *ch)
|
||||
{
|
||||
u8 lcrb = readb(&ch->ch_cls_uart->lcr);
|
||||
u8 ier = readb(&ch->ch_cls_uart->ier);
|
||||
u8 isr_fcr = 0;
|
||||
|
||||
/*
|
||||
* The Enhanced Register Set may only be accessed when
|
||||
* the Line Control Register is set to 0xBFh.
|
||||
*/
|
||||
writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
|
||||
|
||||
isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
/* Turn off IXON flow control, turn off CTS flow control */
|
||||
isr_fcr |= (UART_EXAR654_EFR_ECB);
|
||||
isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR | UART_EXAR654_EFR_IXON);
|
||||
|
||||
writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
/* Write old LCR value back out, which turns enhanced access off */
|
||||
writeb(lcrb, &ch->ch_cls_uart->lcr);
|
||||
|
||||
/*
|
||||
* Disable interrupts for CTS flow, turn off interrupts for
|
||||
* received XOFF chars
|
||||
*/
|
||||
ier &= ~(UART_EXAR654_IER_CTSDSR);
|
||||
ier &= ~(UART_EXAR654_IER_XOFF);
|
||||
writeb(ier, &ch->ch_cls_uart->ier);
|
||||
|
||||
/* Set the usual FIFO values */
|
||||
writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
|
||||
UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
|
||||
&ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
ch->ch_r_watermark = 0;
|
||||
ch->ch_t_tlevel = 16;
|
||||
ch->ch_r_tlevel = 16;
|
||||
}
|
||||
|
||||
static void cls_set_rts_flow_control(struct jsm_channel *ch)
|
||||
{
|
||||
u8 lcrb = readb(&ch->ch_cls_uart->lcr);
|
||||
u8 ier = readb(&ch->ch_cls_uart->ier);
|
||||
u8 isr_fcr = 0;
|
||||
|
||||
/*
|
||||
* The Enhanced Register Set may only be accessed when
|
||||
* the Line Control Register is set to 0xBFh.
|
||||
*/
|
||||
writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
|
||||
|
||||
isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
/* Turn on RTS flow control, turn off IXOFF flow control */
|
||||
isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_RTSDTR);
|
||||
isr_fcr &= ~(UART_EXAR654_EFR_IXOFF);
|
||||
|
||||
writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
/* Write old LCR value back out, which turns enhanced access off */
|
||||
writeb(lcrb, &ch->ch_cls_uart->lcr);
|
||||
|
||||
/* Enable interrupts for RTS flow */
|
||||
ier |= (UART_EXAR654_IER_RTSDTR);
|
||||
writeb(ier, &ch->ch_cls_uart->ier);
|
||||
|
||||
/* Set the usual FIFO values */
|
||||
writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 |
|
||||
UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
|
||||
&ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
ch->ch_r_watermark = 4;
|
||||
ch->ch_r_tlevel = 8;
|
||||
}
|
||||
|
||||
static void cls_set_ixoff_flow_control(struct jsm_channel *ch)
|
||||
{
|
||||
u8 lcrb = readb(&ch->ch_cls_uart->lcr);
|
||||
u8 ier = readb(&ch->ch_cls_uart->ier);
|
||||
u8 isr_fcr = 0;
|
||||
|
||||
/*
|
||||
* The Enhanced Register Set may only be accessed when
|
||||
* the Line Control Register is set to 0xBFh.
|
||||
*/
|
||||
writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
|
||||
|
||||
isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
/* Turn on IXOFF flow control, turn off RTS flow control */
|
||||
isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXOFF);
|
||||
isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR);
|
||||
|
||||
writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
/* Now set our current start/stop chars while in enhanced mode */
|
||||
writeb(ch->ch_startc, &ch->ch_cls_uart->mcr);
|
||||
writeb(0, &ch->ch_cls_uart->lsr);
|
||||
writeb(ch->ch_stopc, &ch->ch_cls_uart->msr);
|
||||
writeb(0, &ch->ch_cls_uart->spr);
|
||||
|
||||
/* Write old LCR value back out, which turns enhanced access off */
|
||||
writeb(lcrb, &ch->ch_cls_uart->lcr);
|
||||
|
||||
/* Disable interrupts for RTS flow */
|
||||
ier &= ~(UART_EXAR654_IER_RTSDTR);
|
||||
writeb(ier, &ch->ch_cls_uart->ier);
|
||||
|
||||
/* Set the usual FIFO values */
|
||||
writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
|
||||
UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
|
||||
&ch->ch_cls_uart->isr_fcr);
|
||||
}
|
||||
|
||||
static void cls_set_no_input_flow_control(struct jsm_channel *ch)
|
||||
{
|
||||
u8 lcrb = readb(&ch->ch_cls_uart->lcr);
|
||||
u8 ier = readb(&ch->ch_cls_uart->ier);
|
||||
u8 isr_fcr = 0;
|
||||
|
||||
/*
|
||||
* The Enhanced Register Set may only be accessed when
|
||||
* the Line Control Register is set to 0xBFh.
|
||||
*/
|
||||
writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
|
||||
|
||||
isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
/* Turn off IXOFF flow control, turn off RTS flow control */
|
||||
isr_fcr |= (UART_EXAR654_EFR_ECB);
|
||||
isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR | UART_EXAR654_EFR_IXOFF);
|
||||
|
||||
writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
/* Write old LCR value back out, which turns enhanced access off */
|
||||
writeb(lcrb, &ch->ch_cls_uart->lcr);
|
||||
|
||||
/* Disable interrupts for RTS flow */
|
||||
ier &= ~(UART_EXAR654_IER_RTSDTR);
|
||||
writeb(ier, &ch->ch_cls_uart->ier);
|
||||
|
||||
/* Set the usual FIFO values */
|
||||
writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
|
||||
UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
|
||||
&ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
ch->ch_t_tlevel = 16;
|
||||
ch->ch_r_tlevel = 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* cls_clear_break.
|
||||
* Determines whether its time to shut off break condition.
|
||||
*
|
||||
* No locks are assumed to be held when calling this function.
|
||||
* channel lock is held and released in this function.
|
||||
*/
|
||||
static void cls_clear_break(struct jsm_channel *ch)
|
||||
{
|
||||
unsigned long lock_flags;
|
||||
|
||||
spin_lock_irqsave(&ch->ch_lock, lock_flags);
|
||||
|
||||
/* Turn break off, and unset some variables */
|
||||
if (ch->ch_flags & CH_BREAK_SENDING) {
|
||||
u8 temp = readb(&ch->ch_cls_uart->lcr);
|
||||
|
||||
writeb((temp & ~UART_LCR_SBC), &ch->ch_cls_uart->lcr);
|
||||
|
||||
ch->ch_flags &= ~(CH_BREAK_SENDING);
|
||||
jsm_dbg(IOCTL, &ch->ch_bd->pci_dev,
|
||||
"clear break Finishing UART_LCR_SBC! finished: %lx\n",
|
||||
jiffies);
|
||||
}
|
||||
spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
|
||||
}
|
||||
|
||||
static void cls_disable_receiver(struct jsm_channel *ch)
|
||||
{
|
||||
u8 tmp = readb(&ch->ch_cls_uart->ier);
|
||||
|
||||
tmp &= ~(UART_IER_RDI);
|
||||
writeb(tmp, &ch->ch_cls_uart->ier);
|
||||
}
|
||||
|
||||
static void cls_enable_receiver(struct jsm_channel *ch)
|
||||
{
|
||||
u8 tmp = readb(&ch->ch_cls_uart->ier);
|
||||
|
||||
tmp |= (UART_IER_RDI);
|
||||
writeb(tmp, &ch->ch_cls_uart->ier);
|
||||
}
|
||||
|
||||
/* Make the UART raise any of the output signals we want up */
|
||||
static void cls_assert_modem_signals(struct jsm_channel *ch)
|
||||
{
|
||||
if (!ch)
|
||||
return;
|
||||
|
||||
writeb(ch->ch_mostat, &ch->ch_cls_uart->mcr);
|
||||
}
|
||||
|
||||
static void cls_copy_data_from_uart_to_queue(struct jsm_channel *ch)
|
||||
{
|
||||
int qleft = 0;
|
||||
u8 linestatus = 0;
|
||||
u8 error_mask = 0;
|
||||
u16 head;
|
||||
u16 tail;
|
||||
unsigned long flags;
|
||||
|
||||
if (!ch)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&ch->ch_lock, flags);
|
||||
|
||||
/* cache head and tail of queue */
|
||||
head = ch->ch_r_head & RQUEUEMASK;
|
||||
tail = ch->ch_r_tail & RQUEUEMASK;
|
||||
|
||||
/* Get our cached LSR */
|
||||
linestatus = ch->ch_cached_lsr;
|
||||
ch->ch_cached_lsr = 0;
|
||||
|
||||
/* Store how much space we have left in the queue */
|
||||
qleft = tail - head - 1;
|
||||
if (qleft < 0)
|
||||
qleft += RQUEUEMASK + 1;
|
||||
|
||||
/*
|
||||
* Create a mask to determine whether we should
|
||||
* insert the character (if any) into our queue.
|
||||
*/
|
||||
if (ch->ch_c_iflag & IGNBRK)
|
||||
error_mask |= UART_LSR_BI;
|
||||
|
||||
while (1) {
|
||||
/*
|
||||
* Grab the linestatus register, we need to
|
||||
* check to see if there is any data to read
|
||||
*/
|
||||
linestatus = readb(&ch->ch_cls_uart->lsr);
|
||||
|
||||
/* Break out if there is no data to fetch */
|
||||
if (!(linestatus & UART_LSR_DR))
|
||||
break;
|
||||
|
||||
/*
|
||||
* Discard character if we are ignoring the error mask
|
||||
* which in this case is the break signal.
|
||||
*/
|
||||
if (linestatus & error_mask) {
|
||||
u8 discard;
|
||||
|
||||
linestatus = 0;
|
||||
discard = readb(&ch->ch_cls_uart->txrx);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If our queue is full, we have no choice but to drop some
|
||||
* data. The assumption is that HWFLOW or SWFLOW should have
|
||||
* stopped things way way before we got to this point.
|
||||
*
|
||||
* I decided that I wanted to ditch the oldest data first,
|
||||
* I hope thats okay with everyone? Yes? Good.
|
||||
*/
|
||||
while (qleft < 1) {
|
||||
tail = (tail + 1) & RQUEUEMASK;
|
||||
ch->ch_r_tail = tail;
|
||||
ch->ch_err_overrun++;
|
||||
qleft++;
|
||||
}
|
||||
|
||||
ch->ch_equeue[head] = linestatus & (UART_LSR_BI | UART_LSR_PE
|
||||
| UART_LSR_FE);
|
||||
ch->ch_rqueue[head] = readb(&ch->ch_cls_uart->txrx);
|
||||
|
||||
qleft--;
|
||||
|
||||
if (ch->ch_equeue[head] & UART_LSR_PE)
|
||||
ch->ch_err_parity++;
|
||||
if (ch->ch_equeue[head] & UART_LSR_BI)
|
||||
ch->ch_err_break++;
|
||||
if (ch->ch_equeue[head] & UART_LSR_FE)
|
||||
ch->ch_err_frame++;
|
||||
|
||||
/* Add to, and flip head if needed */
|
||||
head = (head + 1) & RQUEUEMASK;
|
||||
ch->ch_rxcount++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write new final heads to channel structure.
|
||||
*/
|
||||
ch->ch_r_head = head & RQUEUEMASK;
|
||||
ch->ch_e_head = head & EQUEUEMASK;
|
||||
|
||||
spin_unlock_irqrestore(&ch->ch_lock, flags);
|
||||
}
|
||||
|
||||
static void cls_copy_data_from_queue_to_uart(struct jsm_channel *ch)
|
||||
{
|
||||
u16 tail;
|
||||
int n;
|
||||
int qlen;
|
||||
u32 len_written = 0;
|
||||
struct circ_buf *circ;
|
||||
|
||||
if (!ch)
|
||||
return;
|
||||
|
||||
circ = &ch->uart_port.state->xmit;
|
||||
|
||||
/* No data to write to the UART */
|
||||
if (uart_circ_empty(circ))
|
||||
return;
|
||||
|
||||
/* If port is "stopped", don't send any data to the UART */
|
||||
if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_BREAK_SENDING))
|
||||
return;
|
||||
|
||||
/* We have to do it this way, because of the EXAR TXFIFO count bug. */
|
||||
if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM)))
|
||||
return;
|
||||
|
||||
n = 32;
|
||||
|
||||
/* cache tail of queue */
|
||||
tail = circ->tail & (UART_XMIT_SIZE - 1);
|
||||
qlen = uart_circ_chars_pending(circ);
|
||||
|
||||
/* Find minimum of the FIFO space, versus queue length */
|
||||
n = min(n, qlen);
|
||||
|
||||
while (n > 0) {
|
||||
writeb(circ->buf[tail], &ch->ch_cls_uart->txrx);
|
||||
tail = (tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
n--;
|
||||
ch->ch_txcount++;
|
||||
len_written++;
|
||||
}
|
||||
|
||||
/* Update the final tail */
|
||||
circ->tail = tail & (UART_XMIT_SIZE - 1);
|
||||
|
||||
if (len_written > ch->ch_t_tlevel)
|
||||
ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
|
||||
|
||||
if (uart_circ_empty(circ))
|
||||
uart_write_wakeup(&ch->uart_port);
|
||||
}
|
||||
|
||||
static void cls_parse_modem(struct jsm_channel *ch, u8 signals)
|
||||
{
|
||||
u8 msignals = signals;
|
||||
|
||||
jsm_dbg(MSIGS, &ch->ch_bd->pci_dev,
|
||||
"neo_parse_modem: port: %d msignals: %x\n",
|
||||
ch->ch_portnum, msignals);
|
||||
|
||||
/*
|
||||
* Scrub off lower bits.
|
||||
* They signify delta's, which I don't care about
|
||||
* Keep DDCD and DDSR though
|
||||
*/
|
||||
msignals &= 0xf8;
|
||||
|
||||
if (msignals & UART_MSR_DDCD)
|
||||
uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD);
|
||||
if (msignals & UART_MSR_DDSR)
|
||||
uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_CTS);
|
||||
|
||||
if (msignals & UART_MSR_DCD)
|
||||
ch->ch_mistat |= UART_MSR_DCD;
|
||||
else
|
||||
ch->ch_mistat &= ~UART_MSR_DCD;
|
||||
|
||||
if (msignals & UART_MSR_DSR)
|
||||
ch->ch_mistat |= UART_MSR_DSR;
|
||||
else
|
||||
ch->ch_mistat &= ~UART_MSR_DSR;
|
||||
|
||||
if (msignals & UART_MSR_RI)
|
||||
ch->ch_mistat |= UART_MSR_RI;
|
||||
else
|
||||
ch->ch_mistat &= ~UART_MSR_RI;
|
||||
|
||||
if (msignals & UART_MSR_CTS)
|
||||
ch->ch_mistat |= UART_MSR_CTS;
|
||||
else
|
||||
ch->ch_mistat &= ~UART_MSR_CTS;
|
||||
|
||||
jsm_dbg(MSIGS, &ch->ch_bd->pci_dev,
|
||||
"Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n",
|
||||
ch->ch_portnum,
|
||||
!!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR),
|
||||
!!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS),
|
||||
!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_CTS),
|
||||
!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DSR),
|
||||
!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_RI),
|
||||
!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DCD));
|
||||
}
|
||||
|
||||
/* Parse the ISR register for the specific port */
|
||||
static inline void cls_parse_isr(struct jsm_board *brd, uint port)
|
||||
{
|
||||
struct jsm_channel *ch;
|
||||
u8 isr = 0;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* No need to verify board pointer, it was already
|
||||
* verified in the interrupt routine.
|
||||
*/
|
||||
|
||||
if (port > brd->nasync)
|
||||
return;
|
||||
|
||||
ch = brd->channels[port];
|
||||
if (!ch)
|
||||
return;
|
||||
|
||||
/* Here we try to figure out what caused the interrupt to happen */
|
||||
while (1) {
|
||||
isr = readb(&ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
/* Bail if no pending interrupt on port */
|
||||
if (isr & UART_IIR_NO_INT)
|
||||
break;
|
||||
|
||||
/* Receive Interrupt pending */
|
||||
if (isr & (UART_IIR_RDI | UART_IIR_RDI_TIMEOUT)) {
|
||||
/* Read data from uart -> queue */
|
||||
cls_copy_data_from_uart_to_queue(ch);
|
||||
jsm_check_queue_flow_control(ch);
|
||||
}
|
||||
|
||||
/* Transmit Hold register empty pending */
|
||||
if (isr & UART_IIR_THRI) {
|
||||
/* Transfer data (if any) from Write Queue -> UART. */
|
||||
spin_lock_irqsave(&ch->ch_lock, flags);
|
||||
ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
|
||||
spin_unlock_irqrestore(&ch->ch_lock, flags);
|
||||
cls_copy_data_from_queue_to_uart(ch);
|
||||
}
|
||||
|
||||
/*
|
||||
* CTS/RTS change of state:
|
||||
* Don't need to do anything, the cls_parse_modem
|
||||
* below will grab the updated modem signals.
|
||||
*/
|
||||
|
||||
/* Parse any modem signal changes */
|
||||
cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr));
|
||||
}
|
||||
}
|
||||
|
||||
/* Channel lock MUST be held before calling this function! */
|
||||
static void cls_flush_uart_write(struct jsm_channel *ch)
|
||||
{
|
||||
u8 tmp = 0;
|
||||
u8 i = 0;
|
||||
|
||||
if (!ch)
|
||||
return;
|
||||
|
||||
writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT),
|
||||
&ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
/* Check to see if the UART feels it completely flushed FIFO */
|
||||
tmp = readb(&ch->ch_cls_uart->isr_fcr);
|
||||
if (tmp & UART_FCR_CLEAR_XMIT) {
|
||||
jsm_dbg(IOCTL, &ch->ch_bd->pci_dev,
|
||||
"Still flushing TX UART... i: %d\n", i);
|
||||
udelay(10);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
|
||||
}
|
||||
|
||||
/* Channel lock MUST be held before calling this function! */
|
||||
static void cls_flush_uart_read(struct jsm_channel *ch)
|
||||
{
|
||||
if (!ch)
|
||||
return;
|
||||
|
||||
/*
|
||||
* For complete POSIX compatibility, we should be purging the
|
||||
* read FIFO in the UART here.
|
||||
*
|
||||
* However, clearing the read FIFO (UART_FCR_CLEAR_RCVR) also
|
||||
* incorrectly flushes write data as well as just basically trashing the
|
||||
* FIFO.
|
||||
*
|
||||
* Presumably, this is a bug in this UART.
|
||||
*/
|
||||
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
static void cls_send_start_character(struct jsm_channel *ch)
|
||||
{
|
||||
if (!ch)
|
||||
return;
|
||||
|
||||
if (ch->ch_startc != __DISABLED_CHAR) {
|
||||
ch->ch_xon_sends++;
|
||||
writeb(ch->ch_startc, &ch->ch_cls_uart->txrx);
|
||||
}
|
||||
}
|
||||
|
||||
static void cls_send_stop_character(struct jsm_channel *ch)
|
||||
{
|
||||
if (!ch)
|
||||
return;
|
||||
|
||||
if (ch->ch_stopc != __DISABLED_CHAR) {
|
||||
ch->ch_xoff_sends++;
|
||||
writeb(ch->ch_stopc, &ch->ch_cls_uart->txrx);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* cls_param()
|
||||
* Send any/all changes to the line to the UART.
|
||||
*/
|
||||
static void cls_param(struct jsm_channel *ch)
|
||||
{
|
||||
u8 lcr = 0;
|
||||
u8 uart_lcr = 0;
|
||||
u8 ier = 0;
|
||||
u32 baud = 9600;
|
||||
int quot = 0;
|
||||
struct jsm_board *bd;
|
||||
int i;
|
||||
unsigned int cflag;
|
||||
|
||||
bd = ch->ch_bd;
|
||||
if (!bd)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If baud rate is zero, flush queues, and set mval to drop DTR.
|
||||
*/
|
||||
if ((ch->ch_c_cflag & (CBAUD)) == 0) {
|
||||
ch->ch_r_head = 0;
|
||||
ch->ch_r_tail = 0;
|
||||
ch->ch_e_head = 0;
|
||||
ch->ch_e_tail = 0;
|
||||
|
||||
cls_flush_uart_write(ch);
|
||||
cls_flush_uart_read(ch);
|
||||
|
||||
/* The baudrate is B0 so all modem lines are to be dropped. */
|
||||
ch->ch_flags |= (CH_BAUD0);
|
||||
ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
|
||||
cls_assert_modem_signals(ch);
|
||||
return;
|
||||
}
|
||||
|
||||
cflag = C_BAUD(ch->uart_port.state->port.tty);
|
||||
baud = 9600;
|
||||
for (i = 0; i < ARRAY_SIZE(baud_rates); i++) {
|
||||
if (baud_rates[i].cflag == cflag) {
|
||||
baud = baud_rates[i].rate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ch->ch_flags & CH_BAUD0)
|
||||
ch->ch_flags &= ~(CH_BAUD0);
|
||||
|
||||
if (ch->ch_c_cflag & PARENB)
|
||||
lcr |= UART_LCR_PARITY;
|
||||
|
||||
if (!(ch->ch_c_cflag & PARODD))
|
||||
lcr |= UART_LCR_EPAR;
|
||||
|
||||
/*
|
||||
* Not all platforms support mark/space parity,
|
||||
* so this will hide behind an ifdef.
|
||||
*/
|
||||
#ifdef CMSPAR
|
||||
if (ch->ch_c_cflag & CMSPAR)
|
||||
lcr |= UART_LCR_SPAR;
|
||||
#endif
|
||||
|
||||
if (ch->ch_c_cflag & CSTOPB)
|
||||
lcr |= UART_LCR_STOP;
|
||||
|
||||
switch (ch->ch_c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
lcr |= UART_LCR_WLEN5;
|
||||
break;
|
||||
case CS6:
|
||||
lcr |= UART_LCR_WLEN6;
|
||||
break;
|
||||
case CS7:
|
||||
lcr |= UART_LCR_WLEN7;
|
||||
break;
|
||||
case CS8:
|
||||
default:
|
||||
lcr |= UART_LCR_WLEN8;
|
||||
break;
|
||||
}
|
||||
|
||||
ier = readb(&ch->ch_cls_uart->ier);
|
||||
uart_lcr = readb(&ch->ch_cls_uart->lcr);
|
||||
|
||||
quot = ch->ch_bd->bd_dividend / baud;
|
||||
|
||||
if (quot != 0) {
|
||||
writeb(UART_LCR_DLAB, &ch->ch_cls_uart->lcr);
|
||||
writeb((quot & 0xff), &ch->ch_cls_uart->txrx);
|
||||
writeb((quot >> 8), &ch->ch_cls_uart->ier);
|
||||
writeb(lcr, &ch->ch_cls_uart->lcr);
|
||||
}
|
||||
|
||||
if (uart_lcr != lcr)
|
||||
writeb(lcr, &ch->ch_cls_uart->lcr);
|
||||
|
||||
if (ch->ch_c_cflag & CREAD)
|
||||
ier |= (UART_IER_RDI | UART_IER_RLSI);
|
||||
|
||||
ier |= (UART_IER_THRI | UART_IER_MSI);
|
||||
|
||||
writeb(ier, &ch->ch_cls_uart->ier);
|
||||
|
||||
if (ch->ch_c_cflag & CRTSCTS)
|
||||
cls_set_cts_flow_control(ch);
|
||||
else if (ch->ch_c_iflag & IXON) {
|
||||
/*
|
||||
* If start/stop is set to disable,
|
||||
* then we should disable flow control.
|
||||
*/
|
||||
if ((ch->ch_startc == __DISABLED_CHAR) ||
|
||||
(ch->ch_stopc == __DISABLED_CHAR))
|
||||
cls_set_no_output_flow_control(ch);
|
||||
else
|
||||
cls_set_ixon_flow_control(ch);
|
||||
} else
|
||||
cls_set_no_output_flow_control(ch);
|
||||
|
||||
if (ch->ch_c_cflag & CRTSCTS)
|
||||
cls_set_rts_flow_control(ch);
|
||||
else if (ch->ch_c_iflag & IXOFF) {
|
||||
/*
|
||||
* If start/stop is set to disable,
|
||||
* then we should disable flow control.
|
||||
*/
|
||||
if ((ch->ch_startc == __DISABLED_CHAR) ||
|
||||
(ch->ch_stopc == __DISABLED_CHAR))
|
||||
cls_set_no_input_flow_control(ch);
|
||||
else
|
||||
cls_set_ixoff_flow_control(ch);
|
||||
} else
|
||||
cls_set_no_input_flow_control(ch);
|
||||
|
||||
cls_assert_modem_signals(ch);
|
||||
|
||||
/* get current status of the modem signals now */
|
||||
cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr));
|
||||
}
|
||||
|
||||
/*
|
||||
* cls_intr()
|
||||
*
|
||||
* Classic specific interrupt handler.
|
||||
*/
|
||||
static irqreturn_t cls_intr(int irq, void *voidbrd)
|
||||
{
|
||||
struct jsm_board *brd = voidbrd;
|
||||
unsigned long lock_flags;
|
||||
unsigned char uart_poll;
|
||||
uint i = 0;
|
||||
|
||||
/* Lock out the slow poller from running on this board. */
|
||||
spin_lock_irqsave(&brd->bd_intr_lock, lock_flags);
|
||||
|
||||
/*
|
||||
* Check the board's global interrupt offset to see if we
|
||||
* acctually do have an interrupt pending on us.
|
||||
*/
|
||||
uart_poll = readb(brd->re_map_membase + UART_CLASSIC_POLL_ADDR_OFFSET);
|
||||
|
||||
jsm_dbg(INTR, &brd->pci_dev, "%s:%d uart_poll: %x\n",
|
||||
__FILE__, __LINE__, uart_poll);
|
||||
|
||||
if (!uart_poll) {
|
||||
jsm_dbg(INTR, &brd->pci_dev,
|
||||
"Kernel interrupted to me, but no pending interrupts...\n");
|
||||
spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
/* At this point, we have at least SOMETHING to service, dig further. */
|
||||
|
||||
/* Parse each port to find out what caused the interrupt */
|
||||
for (i = 0; i < brd->nasync; i++)
|
||||
cls_parse_isr(brd, i);
|
||||
|
||||
spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* Inits UART */
|
||||
static void cls_uart_init(struct jsm_channel *ch)
|
||||
{
|
||||
unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
|
||||
unsigned char isr_fcr = 0;
|
||||
|
||||
writeb(0, &ch->ch_cls_uart->ier);
|
||||
|
||||
/*
|
||||
* The Enhanced Register Set may only be accessed when
|
||||
* the Line Control Register is set to 0xBFh.
|
||||
*/
|
||||
writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
|
||||
|
||||
isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
/* Turn on Enhanced/Extended controls */
|
||||
isr_fcr |= (UART_EXAR654_EFR_ECB);
|
||||
|
||||
writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
|
||||
|
||||
/* Write old LCR value back out, which turns enhanced access off */
|
||||
writeb(lcrb, &ch->ch_cls_uart->lcr);
|
||||
|
||||
/* Clear out UART and FIFO */
|
||||
readb(&ch->ch_cls_uart->txrx);
|
||||
|
||||
writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT),
|
||||
&ch->ch_cls_uart->isr_fcr);
|
||||
udelay(10);
|
||||
|
||||
ch->ch_flags |= (CH_FIFO_ENABLED | CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
|
||||
|
||||
readb(&ch->ch_cls_uart->lsr);
|
||||
readb(&ch->ch_cls_uart->msr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Turns off UART.
|
||||
*/
|
||||
static void cls_uart_off(struct jsm_channel *ch)
|
||||
{
|
||||
/* Stop all interrupts from accurring. */
|
||||
writeb(0, &ch->ch_cls_uart->ier);
|
||||
}
|
||||
|
||||
/*
|
||||
* cls_get_uarts_bytes_left.
|
||||
* Returns 0 is nothing left in the FIFO, returns 1 otherwise.
|
||||
*
|
||||
* The channel lock MUST be held by the calling function.
|
||||
*/
|
||||
static u32 cls_get_uart_bytes_left(struct jsm_channel *ch)
|
||||
{
|
||||
u8 left = 0;
|
||||
u8 lsr = readb(&ch->ch_cls_uart->lsr);
|
||||
|
||||
/* Determine whether the Transmitter is empty or not */
|
||||
if (!(lsr & UART_LSR_TEMT))
|
||||
left = 1;
|
||||
else {
|
||||
ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
|
||||
left = 0;
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
/*
|
||||
* cls_send_break.
|
||||
* Starts sending a break thru the UART.
|
||||
*
|
||||
* The channel lock MUST be held by the calling function.
|
||||
*/
|
||||
static void cls_send_break(struct jsm_channel *ch)
|
||||
{
|
||||
/* Tell the UART to start sending the break */
|
||||
if (!(ch->ch_flags & CH_BREAK_SENDING)) {
|
||||
u8 temp = readb(&ch->ch_cls_uart->lcr);
|
||||
|
||||
writeb((temp | UART_LCR_SBC), &ch->ch_cls_uart->lcr);
|
||||
ch->ch_flags |= (CH_BREAK_SENDING);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* cls_send_immediate_char.
|
||||
* Sends a specific character as soon as possible to the UART,
|
||||
* jumping over any bytes that might be in the write queue.
|
||||
*
|
||||
* The channel lock MUST be held by the calling function.
|
||||
*/
|
||||
static void cls_send_immediate_char(struct jsm_channel *ch, unsigned char c)
|
||||
{
|
||||
writeb(c, &ch->ch_cls_uart->txrx);
|
||||
}
|
||||
|
||||
struct board_ops jsm_cls_ops = {
|
||||
.intr = cls_intr,
|
||||
.uart_init = cls_uart_init,
|
||||
.uart_off = cls_uart_off,
|
||||
.param = cls_param,
|
||||
.assert_modem_signals = cls_assert_modem_signals,
|
||||
.flush_uart_write = cls_flush_uart_write,
|
||||
.flush_uart_read = cls_flush_uart_read,
|
||||
.disable_receiver = cls_disable_receiver,
|
||||
.enable_receiver = cls_enable_receiver,
|
||||
.send_break = cls_send_break,
|
||||
.clear_break = cls_clear_break,
|
||||
.send_start_character = cls_send_start_character,
|
||||
.send_stop_character = cls_send_stop_character,
|
||||
.copy_data_from_queue_to_uart = cls_copy_data_from_queue_to_uart,
|
||||
.get_uart_bytes_left = cls_get_uart_bytes_left,
|
||||
.send_immediate_char = cls_send_immediate_char
|
||||
};
|
||||
|
|
@ -13,11 +13,6 @@
|
|||
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 * Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
* Contact Information:
|
||||
* Scott H Kilau <Scott_Kilau@digi.com>
|
||||
* Wendy Xiong <wendyx@us.ibm.com>
|
||||
|
@ -31,8 +26,7 @@
|
|||
#include "jsm.h"
|
||||
|
||||
MODULE_AUTHOR("Digi International, http://www.digi.com");
|
||||
MODULE_DESCRIPTION("Driver for the Digi International "
|
||||
"Neo PCI based product line");
|
||||
MODULE_DESCRIPTION("Driver for the Digi International Neo and Classic PCI based product line");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_SUPPORTED_DEVICE("jsm");
|
||||
|
||||
|
@ -50,7 +44,7 @@ struct uart_driver jsm_uart_driver = {
|
|||
};
|
||||
|
||||
static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev,
|
||||
pci_channel_state_t state);
|
||||
pci_channel_state_t state);
|
||||
static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev);
|
||||
static void jsm_io_resume(struct pci_dev *pdev);
|
||||
|
||||
|
@ -68,7 +62,7 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
{
|
||||
int rc = 0;
|
||||
struct jsm_board *brd;
|
||||
static int adapter_count = 0;
|
||||
static int adapter_count;
|
||||
|
||||
rc = pci_enable_device(pdev);
|
||||
if (rc) {
|
||||
|
@ -82,10 +76,8 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
goto out_disable_device;
|
||||
}
|
||||
|
||||
brd = kzalloc(sizeof(struct jsm_board), GFP_KERNEL);
|
||||
brd = kzalloc(sizeof(*brd), GFP_KERNEL);
|
||||
if (!brd) {
|
||||
dev_err(&pdev->dev,
|
||||
"memory allocation for board structure failed\n");
|
||||
rc = -ENOMEM;
|
||||
goto out_release_regions;
|
||||
}
|
||||
|
@ -95,7 +87,6 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
brd->pci_dev = pdev;
|
||||
|
||||
switch (pdev->device) {
|
||||
|
||||
case PCI_DEVICE_ID_NEO_2DB9:
|
||||
case PCI_DEVICE_ID_NEO_2DB9PRI:
|
||||
case PCI_DEVICE_ID_NEO_2RJ45:
|
||||
|
@ -104,6 +95,8 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
brd->maxports = 2;
|
||||
break;
|
||||
|
||||
case PCI_DEVICE_ID_CLASSIC_4:
|
||||
case PCI_DEVICE_ID_CLASSIC_4_422:
|
||||
case PCI_DEVICE_ID_NEO_4:
|
||||
case PCIE_DEVICE_ID_NEO_4:
|
||||
case PCIE_DEVICE_ID_NEO_4RJ45:
|
||||
|
@ -111,6 +104,8 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
brd->maxports = 4;
|
||||
break;
|
||||
|
||||
case PCI_DEVICE_ID_CLASSIC_8:
|
||||
case PCI_DEVICE_ID_CLASSIC_8_422:
|
||||
case PCI_DEVICE_ID_DIGI_NEO_8:
|
||||
case PCIE_DEVICE_ID_NEO_8:
|
||||
case PCIE_DEVICE_ID_NEO_8RJ45:
|
||||
|
@ -129,36 +124,109 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
|
||||
brd->irq = pdev->irq;
|
||||
|
||||
jsm_dbg(INIT, &brd->pci_dev, "jsm_found_board - NEO adapter\n");
|
||||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_CLASSIC_4:
|
||||
case PCI_DEVICE_ID_CLASSIC_4_422:
|
||||
case PCI_DEVICE_ID_CLASSIC_8:
|
||||
case PCI_DEVICE_ID_CLASSIC_8_422:
|
||||
|
||||
/* get the PCI Base Address Registers */
|
||||
brd->membase = pci_resource_start(pdev, 0);
|
||||
brd->membase_end = pci_resource_end(pdev, 0);
|
||||
jsm_dbg(INIT, &brd->pci_dev,
|
||||
"jsm_found_board - Classic adapter\n");
|
||||
|
||||
if (brd->membase & 1)
|
||||
brd->membase &= ~3;
|
||||
else
|
||||
brd->membase &= ~15;
|
||||
/*
|
||||
* For PCI ClassicBoards
|
||||
* PCI Local Address (.i.e. "resource" number) space
|
||||
* 0 PLX Memory Mapped Config
|
||||
* 1 PLX I/O Mapped Config
|
||||
* 2 I/O Mapped UARTs and Status
|
||||
* 3 Memory Mapped VPD
|
||||
* 4 Memory Mapped UARTs and Status
|
||||
*/
|
||||
|
||||
/* Assign the board_ops struct */
|
||||
brd->bd_ops = &jsm_neo_ops;
|
||||
/* Get the PCI Base Address Registers */
|
||||
brd->membase = pci_resource_start(pdev, 4);
|
||||
brd->membase_end = pci_resource_end(pdev, 4);
|
||||
|
||||
brd->bd_uart_offset = 0x200;
|
||||
brd->bd_dividend = 921600;
|
||||
if (brd->membase & 0x1)
|
||||
brd->membase &= ~0x3;
|
||||
else
|
||||
brd->membase &= ~0xF;
|
||||
|
||||
brd->re_map_membase = ioremap(brd->membase, pci_resource_len(pdev, 0));
|
||||
if (!brd->re_map_membase) {
|
||||
dev_err(&pdev->dev,
|
||||
"card has no PCI Memory resources, "
|
||||
"failing board.\n");
|
||||
rc = -ENOMEM;
|
||||
goto out_kfree_brd;
|
||||
brd->iobase = pci_resource_start(pdev, 1);
|
||||
brd->iobase_end = pci_resource_end(pdev, 1);
|
||||
brd->iobase = ((unsigned int)(brd->iobase)) & 0xFFFE;
|
||||
|
||||
/* Assign the board_ops struct */
|
||||
brd->bd_ops = &jsm_cls_ops;
|
||||
|
||||
brd->bd_uart_offset = 0x8;
|
||||
brd->bd_dividend = 921600;
|
||||
|
||||
brd->re_map_membase = ioremap(brd->membase,
|
||||
pci_resource_len(pdev, 4));
|
||||
if (!brd->re_map_membase) {
|
||||
dev_err(&pdev->dev,
|
||||
"Card has no PCI Memory resources, failing board.\n");
|
||||
rc = -ENOMEM;
|
||||
goto out_kfree_brd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable Local Interrupt 1 (0x1),
|
||||
* Local Interrupt 1 Polarity Active high (0x2),
|
||||
* Enable PCI interrupt (0x43)
|
||||
*/
|
||||
outb(0x43, brd->iobase + 0x4c);
|
||||
|
||||
break;
|
||||
|
||||
case PCI_DEVICE_ID_NEO_2DB9:
|
||||
case PCI_DEVICE_ID_NEO_2DB9PRI:
|
||||
case PCI_DEVICE_ID_NEO_2RJ45:
|
||||
case PCI_DEVICE_ID_NEO_2RJ45PRI:
|
||||
case PCI_DEVICE_ID_NEO_2_422_485:
|
||||
case PCI_DEVICE_ID_NEO_4:
|
||||
case PCIE_DEVICE_ID_NEO_4:
|
||||
case PCIE_DEVICE_ID_NEO_4RJ45:
|
||||
case PCIE_DEVICE_ID_NEO_4_IBM:
|
||||
case PCI_DEVICE_ID_DIGI_NEO_8:
|
||||
case PCIE_DEVICE_ID_NEO_8:
|
||||
case PCIE_DEVICE_ID_NEO_8RJ45:
|
||||
|
||||
jsm_dbg(INIT, &brd->pci_dev, "jsm_found_board - NEO adapter\n");
|
||||
|
||||
/* get the PCI Base Address Registers */
|
||||
brd->membase = pci_resource_start(pdev, 0);
|
||||
brd->membase_end = pci_resource_end(pdev, 0);
|
||||
|
||||
if (brd->membase & 1)
|
||||
brd->membase &= ~0x3;
|
||||
else
|
||||
brd->membase &= ~0xF;
|
||||
|
||||
/* Assign the board_ops struct */
|
||||
brd->bd_ops = &jsm_neo_ops;
|
||||
|
||||
brd->bd_uart_offset = 0x200;
|
||||
brd->bd_dividend = 921600;
|
||||
|
||||
brd->re_map_membase = ioremap(brd->membase,
|
||||
pci_resource_len(pdev, 0));
|
||||
if (!brd->re_map_membase) {
|
||||
dev_err(&pdev->dev,
|
||||
"Card has no PCI Memory resources, failing board.\n");
|
||||
rc = -ENOMEM;
|
||||
goto out_kfree_brd;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
rc = request_irq(brd->irq, brd->bd_ops->intr,
|
||||
IRQF_SHARED, "JSM", brd);
|
||||
rc = request_irq(brd->irq, brd->bd_ops->intr, IRQF_SHARED, "JSM", brd);
|
||||
if (rc) {
|
||||
printk(KERN_WARNING "Failed to hook IRQ %d\n",brd->irq);
|
||||
dev_warn(&pdev->dev, "Failed to hook IRQ %d\n", brd->irq);
|
||||
goto out_iounmap;
|
||||
}
|
||||
|
||||
|
@ -178,7 +246,7 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
}
|
||||
|
||||
/* Log the information about the board */
|
||||
dev_info(&pdev->dev, "board %d: Digi Neo (rev %d), irq %d\n",
|
||||
dev_info(&pdev->dev, "board %d: Digi Classic/Neo (rev %d), irq %d\n",
|
||||
adapter_count, brd->rev, brd->irq);
|
||||
|
||||
pci_set_drvdata(pdev, brd);
|
||||
|
@ -205,6 +273,18 @@ static void jsm_remove_one(struct pci_dev *pdev)
|
|||
struct jsm_board *brd = pci_get_drvdata(pdev);
|
||||
int i = 0;
|
||||
|
||||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_CLASSIC_4:
|
||||
case PCI_DEVICE_ID_CLASSIC_4_422:
|
||||
case PCI_DEVICE_ID_CLASSIC_8:
|
||||
case PCI_DEVICE_ID_CLASSIC_8_422:
|
||||
/* Tell card not to interrupt anymore. */
|
||||
outb(0x0, brd->iobase + 0x4c);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
jsm_remove_uart_port(brd);
|
||||
|
||||
free_irq(brd->irq, brd);
|
||||
|
@ -239,6 +319,10 @@ static struct pci_device_id jsm_pci_tbl[] = {
|
|||
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4), 0, 0, 11 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4RJ45), 0, 0, 12 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_8RJ45), 0, 0, 13 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_4), 0, 0, 14 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_4_422), 0, 0, 15 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_8), 0, 0, 16 },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_8_422), 0, 0, 17 },
|
||||
{ 0, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, jsm_pci_tbl);
|
||||
|
|
|
@ -13,11 +13,6 @@
|
|||
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 * Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
* Contact Information:
|
||||
* Scott H Kilau <Scott_Kilau@digi.com>
|
||||
* Wendy Xiong <wendyx@us.ibm.com>
|
||||
|
@ -649,7 +644,7 @@ static void neo_flush_uart_write(struct jsm_channel *ch)
|
|||
|
||||
/* Check to see if the UART feels it completely flushed the FIFO. */
|
||||
tmp = readb(&ch->ch_neo_uart->isr_fcr);
|
||||
if (tmp & 4) {
|
||||
if (tmp & UART_FCR_CLEAR_XMIT) {
|
||||
jsm_dbg(IOCTL, &ch->ch_bd->pci_dev,
|
||||
"Still flushing TX UART... i: %d\n", i);
|
||||
udelay(10);
|
||||
|
@ -694,7 +689,7 @@ static void neo_flush_uart_read(struct jsm_channel *ch)
|
|||
/*
|
||||
* No locks are assumed to be held when calling this function.
|
||||
*/
|
||||
static void neo_clear_break(struct jsm_channel *ch, int force)
|
||||
static void neo_clear_break(struct jsm_channel *ch)
|
||||
{
|
||||
unsigned long lock_flags;
|
||||
|
||||
|
@ -1024,27 +1019,24 @@ static void neo_param(struct jsm_channel *ch)
|
|||
lcr |= UART_LCR_STOP;
|
||||
|
||||
switch (ch->ch_c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
lcr |= UART_LCR_WLEN5;
|
||||
break;
|
||||
case CS6:
|
||||
lcr |= UART_LCR_WLEN6;
|
||||
break;
|
||||
case CS7:
|
||||
lcr |= UART_LCR_WLEN7;
|
||||
break;
|
||||
case CS8:
|
||||
default:
|
||||
lcr |= UART_LCR_WLEN8;
|
||||
case CS5:
|
||||
lcr |= UART_LCR_WLEN5;
|
||||
break;
|
||||
case CS6:
|
||||
lcr |= UART_LCR_WLEN6;
|
||||
break;
|
||||
case CS7:
|
||||
lcr |= UART_LCR_WLEN7;
|
||||
break;
|
||||
case CS8:
|
||||
default:
|
||||
lcr |= UART_LCR_WLEN8;
|
||||
break;
|
||||
}
|
||||
|
||||
ier = readb(&ch->ch_neo_uart->ier);
|
||||
uart_lcr = readb(&ch->ch_neo_uart->lcr);
|
||||
|
||||
if (baud == 0)
|
||||
baud = 9600;
|
||||
|
||||
quot = ch->ch_bd->bd_dividend / baud;
|
||||
|
||||
if (quot != 0) {
|
||||
|
|
|
@ -13,11 +13,6 @@
|
|||
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 * Temple Place - Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
* Contact Information:
|
||||
* Scott H Kilau <Scott_Kilau@digi.com>
|
||||
* Ananda Venkatarman <mansarov@us.ibm.com>
|
||||
|
@ -77,7 +72,8 @@ static unsigned int jsm_tty_tx_empty(struct uart_port *port)
|
|||
static unsigned int jsm_tty_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
int result;
|
||||
struct jsm_channel *channel = (struct jsm_channel *)port;
|
||||
struct jsm_channel *channel =
|
||||
container_of(port, struct jsm_channel, uart_port);
|
||||
|
||||
jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
|
||||
|
||||
|
@ -98,7 +94,8 @@ static unsigned int jsm_tty_get_mctrl(struct uart_port *port)
|
|||
*/
|
||||
static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
struct jsm_channel *channel = (struct jsm_channel *)port;
|
||||
struct jsm_channel *channel =
|
||||
container_of(port, struct jsm_channel, uart_port);
|
||||
|
||||
jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
|
||||
|
||||
|
@ -133,7 +130,8 @@ static void jsm_tty_write(struct uart_port *port)
|
|||
|
||||
static void jsm_tty_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct jsm_channel *channel = (struct jsm_channel *)port;
|
||||
struct jsm_channel *channel =
|
||||
container_of(port, struct jsm_channel, uart_port);
|
||||
|
||||
jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
|
||||
|
||||
|
@ -145,7 +143,8 @@ static void jsm_tty_start_tx(struct uart_port *port)
|
|||
|
||||
static void jsm_tty_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct jsm_channel *channel = (struct jsm_channel *)port;
|
||||
struct jsm_channel *channel =
|
||||
container_of(port, struct jsm_channel, uart_port);
|
||||
|
||||
jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
|
||||
|
||||
|
@ -157,7 +156,8 @@ static void jsm_tty_stop_tx(struct uart_port *port)
|
|||
static void jsm_tty_send_xchar(struct uart_port *port, char ch)
|
||||
{
|
||||
unsigned long lock_flags;
|
||||
struct jsm_channel *channel = (struct jsm_channel *)port;
|
||||
struct jsm_channel *channel =
|
||||
container_of(port, struct jsm_channel, uart_port);
|
||||
struct ktermios *termios;
|
||||
|
||||
spin_lock_irqsave(&port->lock, lock_flags);
|
||||
|
@ -172,7 +172,8 @@ static void jsm_tty_send_xchar(struct uart_port *port, char ch)
|
|||
|
||||
static void jsm_tty_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct jsm_channel *channel = (struct jsm_channel *)port;
|
||||
struct jsm_channel *channel =
|
||||
container_of(port, struct jsm_channel, uart_port);
|
||||
|
||||
channel->ch_bd->bd_ops->disable_receiver(channel);
|
||||
}
|
||||
|
@ -180,13 +181,14 @@ static void jsm_tty_stop_rx(struct uart_port *port)
|
|||
static void jsm_tty_break(struct uart_port *port, int break_state)
|
||||
{
|
||||
unsigned long lock_flags;
|
||||
struct jsm_channel *channel = (struct jsm_channel *)port;
|
||||
struct jsm_channel *channel =
|
||||
container_of(port, struct jsm_channel, uart_port);
|
||||
|
||||
spin_lock_irqsave(&port->lock, lock_flags);
|
||||
if (break_state == -1)
|
||||
channel->ch_bd->bd_ops->send_break(channel);
|
||||
else
|
||||
channel->ch_bd->bd_ops->clear_break(channel, 0);
|
||||
channel->ch_bd->bd_ops->clear_break(channel);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, lock_flags);
|
||||
}
|
||||
|
@ -194,7 +196,8 @@ static void jsm_tty_break(struct uart_port *port, int break_state)
|
|||
static int jsm_tty_open(struct uart_port *port)
|
||||
{
|
||||
struct jsm_board *brd;
|
||||
struct jsm_channel *channel = (struct jsm_channel *)port;
|
||||
struct jsm_channel *channel =
|
||||
container_of(port, struct jsm_channel, uart_port);
|
||||
struct ktermios *termios;
|
||||
|
||||
/* Get board pointer from our array of majors we have allocated */
|
||||
|
@ -273,7 +276,8 @@ static void jsm_tty_close(struct uart_port *port)
|
|||
{
|
||||
struct jsm_board *bd;
|
||||
struct ktermios *ts;
|
||||
struct jsm_channel *channel = (struct jsm_channel *)port;
|
||||
struct jsm_channel *channel =
|
||||
container_of(port, struct jsm_channel, uart_port);
|
||||
|
||||
jsm_dbg(CLOSE, &channel->ch_bd->pci_dev, "start\n");
|
||||
|
||||
|
@ -307,7 +311,8 @@ static void jsm_tty_set_termios(struct uart_port *port,
|
|||
struct ktermios *old_termios)
|
||||
{
|
||||
unsigned long lock_flags;
|
||||
struct jsm_channel *channel = (struct jsm_channel *)port;
|
||||
struct jsm_channel *channel =
|
||||
container_of(port, struct jsm_channel, uart_port);
|
||||
|
||||
spin_lock_irqsave(&port->lock, lock_flags);
|
||||
channel->ch_c_cflag = termios->c_cflag;
|
||||
|
@ -415,6 +420,8 @@ int jsm_tty_init(struct jsm_board *brd)
|
|||
|
||||
if (brd->bd_uart_offset == 0x200)
|
||||
ch->ch_neo_uart = vaddr + (brd->bd_uart_offset * i);
|
||||
else
|
||||
ch->ch_cls_uart = vaddr + (brd->bd_uart_offset * i);
|
||||
|
||||
ch->ch_bd = brd;
|
||||
ch->ch_portnum = i;
|
||||
|
|
|
@ -497,8 +497,10 @@ lqasc_type(struct uart_port *port)
|
|||
static void
|
||||
lqasc_release_port(struct uart_port *port)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(port->dev);
|
||||
|
||||
if (port->flags & UPF_IOREMAP) {
|
||||
iounmap(port->membase);
|
||||
devm_iounmap(&pdev->dev, port->membase);
|
||||
port->membase = NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -249,7 +249,8 @@ static void serial_out(struct uart_sio_port *up, int offset, int value)
|
|||
|
||||
static void m32r_sio_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_sio_port *up = (struct uart_sio_port *)port;
|
||||
struct uart_sio_port *up =
|
||||
container_of(port, struct uart_sio_port, port);
|
||||
|
||||
if (up->ier & UART_IER_THRI) {
|
||||
up->ier &= ~UART_IER_THRI;
|
||||
|
@ -260,7 +261,8 @@ static void m32r_sio_stop_tx(struct uart_port *port)
|
|||
static void m32r_sio_start_tx(struct uart_port *port)
|
||||
{
|
||||
#ifdef CONFIG_SERIAL_M32R_PLDSIO
|
||||
struct uart_sio_port *up = (struct uart_sio_port *)port;
|
||||
struct uart_sio_port *up =
|
||||
container_of(port, struct uart_sio_port, port);
|
||||
struct circ_buf *xmit = &up->port.state->xmit;
|
||||
|
||||
if (!(up->ier & UART_IER_THRI)) {
|
||||
|
@ -274,7 +276,8 @@ static void m32r_sio_start_tx(struct uart_port *port)
|
|||
}
|
||||
while((serial_in(up, UART_LSR) & UART_EMPTY) != UART_EMPTY);
|
||||
#else
|
||||
struct uart_sio_port *up = (struct uart_sio_port *)port;
|
||||
struct uart_sio_port *up =
|
||||
container_of(port, struct uart_sio_port, port);
|
||||
|
||||
if (!(up->ier & UART_IER_THRI)) {
|
||||
up->ier |= UART_IER_THRI;
|
||||
|
@ -285,7 +288,8 @@ static void m32r_sio_start_tx(struct uart_port *port)
|
|||
|
||||
static void m32r_sio_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct uart_sio_port *up = (struct uart_sio_port *)port;
|
||||
struct uart_sio_port *up =
|
||||
container_of(port, struct uart_sio_port, port);
|
||||
|
||||
up->ier &= ~UART_IER_RLSI;
|
||||
up->port.read_status_mask &= ~UART_LSR_DR;
|
||||
|
@ -294,7 +298,8 @@ static void m32r_sio_stop_rx(struct uart_port *port)
|
|||
|
||||
static void m32r_sio_enable_ms(struct uart_port *port)
|
||||
{
|
||||
struct uart_sio_port *up = (struct uart_sio_port *)port;
|
||||
struct uart_sio_port *up =
|
||||
container_of(port, struct uart_sio_port, port);
|
||||
|
||||
up->ier |= UART_IER_MSI;
|
||||
serial_out(up, UART_IER, up->ier);
|
||||
|
@ -581,7 +586,8 @@ static void m32r_sio_timeout(unsigned long data)
|
|||
|
||||
static unsigned int m32r_sio_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct uart_sio_port *up = (struct uart_sio_port *)port;
|
||||
struct uart_sio_port *up =
|
||||
container_of(port, struct uart_sio_port, port);
|
||||
unsigned long flags;
|
||||
unsigned int ret;
|
||||
|
||||
|
@ -609,7 +615,8 @@ static void m32r_sio_break_ctl(struct uart_port *port, int break_state)
|
|||
|
||||
static int m32r_sio_startup(struct uart_port *port)
|
||||
{
|
||||
struct uart_sio_port *up = (struct uart_sio_port *)port;
|
||||
struct uart_sio_port *up =
|
||||
container_of(port, struct uart_sio_port, port);
|
||||
int retval;
|
||||
|
||||
sio_init();
|
||||
|
@ -652,7 +659,8 @@ static int m32r_sio_startup(struct uart_port *port)
|
|||
|
||||
static void m32r_sio_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct uart_sio_port *up = (struct uart_sio_port *)port;
|
||||
struct uart_sio_port *up =
|
||||
container_of(port, struct uart_sio_port, port);
|
||||
|
||||
/*
|
||||
* Disable interrupts from this port
|
||||
|
@ -681,7 +689,8 @@ static unsigned int m32r_sio_get_divisor(struct uart_port *port,
|
|||
static void m32r_sio_set_termios(struct uart_port *port,
|
||||
struct ktermios *termios, struct ktermios *old)
|
||||
{
|
||||
struct uart_sio_port *up = (struct uart_sio_port *)port;
|
||||
struct uart_sio_port *up =
|
||||
container_of(port, struct uart_sio_port, port);
|
||||
unsigned char cval = 0;
|
||||
unsigned long flags;
|
||||
unsigned int baud, quot;
|
||||
|
@ -780,7 +789,8 @@ static void m32r_sio_set_termios(struct uart_port *port,
|
|||
static void m32r_sio_pm(struct uart_port *port, unsigned int state,
|
||||
unsigned int oldstate)
|
||||
{
|
||||
struct uart_sio_port *up = (struct uart_sio_port *)port;
|
||||
struct uart_sio_port *up =
|
||||
container_of(port, struct uart_sio_port, port);
|
||||
|
||||
if (up->pm)
|
||||
up->pm(port, state, oldstate);
|
||||
|
@ -825,7 +835,8 @@ m32r_sio_request_std_resource(struct uart_sio_port *up, struct resource **res)
|
|||
|
||||
static void m32r_sio_release_port(struct uart_port *port)
|
||||
{
|
||||
struct uart_sio_port *up = (struct uart_sio_port *)port;
|
||||
struct uart_sio_port *up =
|
||||
container_of(port, struct uart_sio_port, port);
|
||||
unsigned long start, offset = 0, size = 0;
|
||||
|
||||
size <<= up->port.regshift;
|
||||
|
@ -862,7 +873,8 @@ static void m32r_sio_release_port(struct uart_port *port)
|
|||
|
||||
static int m32r_sio_request_port(struct uart_port *port)
|
||||
{
|
||||
struct uart_sio_port *up = (struct uart_sio_port *)port;
|
||||
struct uart_sio_port *up =
|
||||
container_of(port, struct uart_sio_port, port);
|
||||
struct resource *res = NULL;
|
||||
int ret = 0;
|
||||
|
||||
|
@ -889,7 +901,8 @@ static int m32r_sio_request_port(struct uart_port *port)
|
|||
|
||||
static void m32r_sio_config_port(struct uart_port *port, int unused)
|
||||
{
|
||||
struct uart_sio_port *up = (struct uart_sio_port *)port;
|
||||
struct uart_sio_port *up =
|
||||
container_of(port, struct uart_sio_port, port);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
|
@ -1000,7 +1013,8 @@ static inline void wait_for_xmitr(struct uart_sio_port *up)
|
|||
|
||||
static void m32r_sio_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
struct uart_sio_port *up = (struct uart_sio_port *)port;
|
||||
struct uart_sio_port *up =
|
||||
container_of(port, struct uart_sio_port, port);
|
||||
|
||||
wait_for_xmitr(up);
|
||||
sio_out(up, SIOTXB, ch);
|
||||
|
|
|
@ -346,10 +346,13 @@ static int max3109_detect(struct device *dev)
|
|||
unsigned int val = 0;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(s->regmap, MAX310X_REVID_REG, &val);
|
||||
ret = regmap_write(s->regmap, MAX310X_GLOBALCMD_REG,
|
||||
MAX310X_EXTREG_ENBL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regmap_read(s->regmap, MAX310X_REVID_EXTREG, &val);
|
||||
regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, MAX310X_EXTREG_DSBL);
|
||||
if (((val & MAX310x_REV_MASK) != MAX3109_REV_ID)) {
|
||||
dev_err(dev,
|
||||
"%s ID 0x%02x does not match\n", s->devtype->name, val);
|
||||
|
@ -874,55 +877,37 @@ static void max310x_set_termios(struct uart_port *port,
|
|||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
}
|
||||
|
||||
static int max310x_ioctl(struct uart_port *port, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
static int max310x_rs485_config(struct uart_port *port,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
#if defined(TIOCSRS485) && defined(TIOCGRS485)
|
||||
struct serial_rs485 rs485;
|
||||
unsigned int val;
|
||||
|
||||
switch (cmd) {
|
||||
case TIOCSRS485:
|
||||
if (copy_from_user(&rs485, (void __user *)arg, sizeof(rs485)))
|
||||
return -EFAULT;
|
||||
if (rs485.delay_rts_before_send > 0x0f ||
|
||||
rs485.delay_rts_after_send > 0x0f)
|
||||
return -ERANGE;
|
||||
val = (rs485.delay_rts_before_send << 4) |
|
||||
rs485.delay_rts_after_send;
|
||||
max310x_port_write(port, MAX310X_HDPIXDELAY_REG, val);
|
||||
if (rs485.flags & SER_RS485_ENABLED) {
|
||||
max310x_port_update(port, MAX310X_MODE1_REG,
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT,
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT);
|
||||
max310x_port_update(port, MAX310X_MODE2_REG,
|
||||
MAX310X_MODE2_ECHOSUPR_BIT,
|
||||
MAX310X_MODE2_ECHOSUPR_BIT);
|
||||
} else {
|
||||
max310x_port_update(port, MAX310X_MODE1_REG,
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT, 0);
|
||||
max310x_port_update(port, MAX310X_MODE2_REG,
|
||||
MAX310X_MODE2_ECHOSUPR_BIT, 0);
|
||||
}
|
||||
return 0;
|
||||
case TIOCGRS485:
|
||||
memset(&rs485, 0, sizeof(rs485));
|
||||
val = max310x_port_read(port, MAX310X_MODE1_REG);
|
||||
rs485.flags = (val & MAX310X_MODE1_TRNSCVCTRL_BIT) ?
|
||||
SER_RS485_ENABLED : 0;
|
||||
rs485.flags |= SER_RS485_RTS_ON_SEND;
|
||||
val = max310x_port_read(port, MAX310X_HDPIXDELAY_REG);
|
||||
rs485.delay_rts_before_send = val >> 4;
|
||||
rs485.delay_rts_after_send = val & 0x0f;
|
||||
if (copy_to_user((void __user *)arg, &rs485, sizeof(rs485)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (rs485->delay_rts_before_send > 0x0f ||
|
||||
rs485->delay_rts_after_send > 0x0f)
|
||||
return -ERANGE;
|
||||
|
||||
return -ENOIOCTLCMD;
|
||||
val = (rs485->delay_rts_before_send << 4) |
|
||||
rs485->delay_rts_after_send;
|
||||
max310x_port_write(port, MAX310X_HDPIXDELAY_REG, val);
|
||||
if (rs485->flags & SER_RS485_ENABLED) {
|
||||
max310x_port_update(port, MAX310X_MODE1_REG,
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT,
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT);
|
||||
max310x_port_update(port, MAX310X_MODE2_REG,
|
||||
MAX310X_MODE2_ECHOSUPR_BIT,
|
||||
MAX310X_MODE2_ECHOSUPR_BIT);
|
||||
} else {
|
||||
max310x_port_update(port, MAX310X_MODE1_REG,
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT, 0);
|
||||
max310x_port_update(port, MAX310X_MODE2_REG,
|
||||
MAX310X_MODE2_ECHOSUPR_BIT, 0);
|
||||
}
|
||||
|
||||
rs485->flags &= SER_RS485_RTS_ON_SEND | SER_RS485_ENABLED;
|
||||
memset(rs485->padding, 0, sizeof(rs485->padding));
|
||||
port->rs485 = *rs485;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max310x_startup(struct uart_port *port)
|
||||
|
@ -1017,7 +1002,6 @@ static const struct uart_ops max310x_ops = {
|
|||
.release_port = max310x_null_void,
|
||||
.config_port = max310x_config_port,
|
||||
.verify_port = max310x_verify_port,
|
||||
.ioctl = max310x_ioctl,
|
||||
};
|
||||
|
||||
static int __maybe_unused max310x_suspend(struct device *dev)
|
||||
|
@ -1218,6 +1202,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
|
|||
s->p[i].port.iobase = i * 0x20;
|
||||
s->p[i].port.membase = (void __iomem *)~0;
|
||||
s->p[i].port.uartclk = uartclk;
|
||||
s->p[i].port.rs485_config = max310x_rs485_config;
|
||||
s->p[i].port.ops = &max310x_ops;
|
||||
/* Disable all interrupts */
|
||||
max310x_port_write(&s->p[i].port, MAX310X_IRQEN_REG, 0);
|
||||
|
|
|
@ -57,7 +57,6 @@ struct mcf_uart {
|
|||
struct uart_port port;
|
||||
unsigned int sigs; /* Local copy of line sigs */
|
||||
unsigned char imr; /* Local IMR mirror */
|
||||
struct serial_rs485 rs485; /* RS485 settings */
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
|
@ -104,7 +103,7 @@ static void mcf_start_tx(struct uart_port *port)
|
|||
{
|
||||
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
|
||||
|
||||
if (pp->rs485.flags & SER_RS485_ENABLED) {
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
/* Enable Transmitter */
|
||||
writeb(MCFUART_UCR_TXENABLE, port->membase + MCFUART_UCR);
|
||||
/* Manually assert RTS */
|
||||
|
@ -258,12 +257,12 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
mr2 |= MCFUART_MR2_TXCTS;
|
||||
}
|
||||
|
||||
if (pp->rs485.flags & SER_RS485_ENABLED) {
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
dev_dbg(port->dev, "Setting UART to RS485\n");
|
||||
mr2 |= MCFUART_MR2_TXRTS;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
|
||||
writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
|
||||
|
@ -360,7 +359,7 @@ static void mcf_tx_chars(struct mcf_uart *pp)
|
|||
pp->imr &= ~MCFUART_UIR_TXREADY;
|
||||
writeb(pp->imr, port->membase + MCFUART_UIMR);
|
||||
/* Disable TX to negate RTS automatically */
|
||||
if (pp->rs485.flags & SER_RS485_ENABLED)
|
||||
if (port->rs485.flags & SER_RS485_ENABLED)
|
||||
writeb(MCFUART_UCR_TXDISABLE,
|
||||
port->membase + MCFUART_UCR);
|
||||
}
|
||||
|
@ -440,13 +439,11 @@ static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser)
|
|||
/****************************************************************************/
|
||||
|
||||
/* Enable or disable the RS485 support */
|
||||
static void mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
|
||||
static int mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
|
||||
{
|
||||
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
|
||||
unsigned long flags;
|
||||
unsigned char mr1, mr2;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
/* Get mode registers */
|
||||
mr1 = readb(port->membase + MCFUART_UMR);
|
||||
mr2 = readb(port->membase + MCFUART_UMR);
|
||||
|
@ -460,32 +457,8 @@ static void mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
|
|||
}
|
||||
writeb(mr1, port->membase + MCFUART_UMR);
|
||||
writeb(mr2, port->membase + MCFUART_UMR);
|
||||
pp->rs485 = *rs485;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
port->rs485 = *rs485;
|
||||
|
||||
static int mcf_ioctl(struct uart_port *port, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case TIOCSRS485: {
|
||||
struct serial_rs485 rs485;
|
||||
if (copy_from_user(&rs485, (struct serial_rs485 *)arg,
|
||||
sizeof(struct serial_rs485)))
|
||||
return -EFAULT;
|
||||
mcf_config_rs485(port, &rs485);
|
||||
break;
|
||||
}
|
||||
case TIOCGRS485: {
|
||||
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
|
||||
if (copy_to_user((struct serial_rs485 *)arg, &pp->rs485,
|
||||
sizeof(struct serial_rs485)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -510,7 +483,6 @@ static const struct uart_ops mcf_uart_ops = {
|
|||
.release_port = mcf_release_port,
|
||||
.config_port = mcf_config_port,
|
||||
.verify_port = mcf_verify_port,
|
||||
.ioctl = mcf_ioctl,
|
||||
};
|
||||
|
||||
static struct mcf_uart mcf_ports[4];
|
||||
|
@ -538,6 +510,7 @@ int __init early_mcf_setup(struct mcf_platform_uart *platp)
|
|||
port->irq = platp[i].irq;
|
||||
port->uartclk = MCF_BUSCLK;
|
||||
port->flags = UPF_BOOT_AUTOCONF;
|
||||
port->rs485_config = mcf_config_rs485;
|
||||
port->ops = &mcf_uart_ops;
|
||||
}
|
||||
|
||||
|
@ -663,6 +636,7 @@ static int mcf_probe(struct platform_device *pdev)
|
|||
port->uartclk = MCF_BUSCLK;
|
||||
port->ops = &mcf_uart_ops;
|
||||
port->flags = UPF_BOOT_AUTOCONF;
|
||||
port->rs485_config = mcf_config_rs485;
|
||||
|
||||
uart_add_one_port(&mcf_driver, port);
|
||||
}
|
||||
|
|
|
@ -809,6 +809,7 @@ static void men_z135_remove(struct mcb_device *mdev)
|
|||
|
||||
static const struct mcb_device_id men_z135_ids[] = {
|
||||
{ .device = 0x87 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(mcb, men_z135_ids);
|
||||
|
||||
|
|
|
@ -1371,7 +1371,7 @@ static void hsu_global_init(void)
|
|||
hsu->iolen = 0x1000;
|
||||
|
||||
if (!(request_mem_region(hsu->paddr, hsu->iolen, "HSU global")))
|
||||
pr_warning("HSU: error in request mem region\n");
|
||||
pr_warn("HSU: error in request mem region\n");
|
||||
|
||||
hsu->reg = ioremap_nocache((unsigned long)hsu->paddr, hsu->iolen);
|
||||
if (!hsu->reg) {
|
||||
|
|
|
@ -1246,7 +1246,8 @@ static irqreturn_t mpsc_sdma_intr(int irq, void *dev_id)
|
|||
*/
|
||||
static uint mpsc_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
|
||||
struct mpsc_port_info *pi =
|
||||
container_of(port, struct mpsc_port_info, port);
|
||||
ulong iflags;
|
||||
uint rc;
|
||||
|
||||
|
@ -1264,7 +1265,8 @@ static void mpsc_set_mctrl(struct uart_port *port, uint mctrl)
|
|||
|
||||
static uint mpsc_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
|
||||
struct mpsc_port_info *pi =
|
||||
container_of(port, struct mpsc_port_info, port);
|
||||
u32 mflags, status;
|
||||
|
||||
status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m
|
||||
|
@ -1281,7 +1283,8 @@ static uint mpsc_get_mctrl(struct uart_port *port)
|
|||
|
||||
static void mpsc_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
|
||||
struct mpsc_port_info *pi =
|
||||
container_of(port, struct mpsc_port_info, port);
|
||||
|
||||
pr_debug("mpsc_stop_tx[%d]\n", port->line);
|
||||
|
||||
|
@ -1290,7 +1293,8 @@ static void mpsc_stop_tx(struct uart_port *port)
|
|||
|
||||
static void mpsc_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
|
||||
struct mpsc_port_info *pi =
|
||||
container_of(port, struct mpsc_port_info, port);
|
||||
unsigned long iflags;
|
||||
|
||||
spin_lock_irqsave(&pi->tx_lock, iflags);
|
||||
|
@ -1316,7 +1320,8 @@ static void mpsc_start_rx(struct mpsc_port_info *pi)
|
|||
|
||||
static void mpsc_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
|
||||
struct mpsc_port_info *pi =
|
||||
container_of(port, struct mpsc_port_info, port);
|
||||
|
||||
pr_debug("mpsc_stop_rx[%d]: Stopping...\n", port->line);
|
||||
|
||||
|
@ -1338,7 +1343,8 @@ static void mpsc_stop_rx(struct uart_port *port)
|
|||
|
||||
static void mpsc_break_ctl(struct uart_port *port, int ctl)
|
||||
{
|
||||
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
|
||||
struct mpsc_port_info *pi =
|
||||
container_of(port, struct mpsc_port_info, port);
|
||||
ulong flags;
|
||||
u32 v;
|
||||
|
||||
|
@ -1353,7 +1359,8 @@ static void mpsc_break_ctl(struct uart_port *port, int ctl)
|
|||
|
||||
static int mpsc_startup(struct uart_port *port)
|
||||
{
|
||||
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
|
||||
struct mpsc_port_info *pi =
|
||||
container_of(port, struct mpsc_port_info, port);
|
||||
u32 flag = 0;
|
||||
int rc;
|
||||
|
||||
|
@ -1383,7 +1390,8 @@ static int mpsc_startup(struct uart_port *port)
|
|||
|
||||
static void mpsc_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
|
||||
struct mpsc_port_info *pi =
|
||||
container_of(port, struct mpsc_port_info, port);
|
||||
|
||||
pr_debug("mpsc_shutdown[%d]: Shutting down MPSC\n", port->line);
|
||||
|
||||
|
@ -1394,7 +1402,8 @@ static void mpsc_shutdown(struct uart_port *port)
|
|||
static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
|
||||
struct mpsc_port_info *pi =
|
||||
container_of(port, struct mpsc_port_info, port);
|
||||
u32 baud;
|
||||
ulong flags;
|
||||
u32 chr_bits, stop_bits, par;
|
||||
|
@ -1498,7 +1507,8 @@ static int mpsc_request_port(struct uart_port *port)
|
|||
|
||||
static void mpsc_release_port(struct uart_port *port)
|
||||
{
|
||||
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
|
||||
struct mpsc_port_info *pi =
|
||||
container_of(port, struct mpsc_port_info, port);
|
||||
|
||||
if (pi->ready) {
|
||||
mpsc_uninit_rings(pi);
|
||||
|
@ -1513,7 +1523,8 @@ static void mpsc_config_port(struct uart_port *port, int flags)
|
|||
|
||||
static int mpsc_verify_port(struct uart_port *port, struct serial_struct *ser)
|
||||
{
|
||||
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
|
||||
struct mpsc_port_info *pi =
|
||||
container_of(port, struct mpsc_port_info, port);
|
||||
int rc = 0;
|
||||
|
||||
pr_debug("mpsc_verify_port[%d]: Verifying port data\n", pi->port.line);
|
||||
|
@ -1548,7 +1559,8 @@ static void mpsc_put_poll_char(struct uart_port *port,
|
|||
|
||||
static int mpsc_get_poll_char(struct uart_port *port)
|
||||
{
|
||||
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
|
||||
struct mpsc_port_info *pi =
|
||||
container_of(port, struct mpsc_port_info, port);
|
||||
struct mpsc_rx_desc *rxre;
|
||||
u32 cmdstat, bytes_in, i;
|
||||
u8 *bp;
|
||||
|
@ -1648,7 +1660,8 @@ static int mpsc_get_poll_char(struct uart_port *port)
|
|||
static void mpsc_put_poll_char(struct uart_port *port,
|
||||
unsigned char c)
|
||||
{
|
||||
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
|
||||
struct mpsc_port_info *pi =
|
||||
container_of(port, struct mpsc_port_info, port);
|
||||
u32 data;
|
||||
|
||||
data = readl(pi->mpsc_base + MPSC_MPCR);
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
* interrupt for a low speed UART device
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#ifdef CONFIG_MAGIC_SYSRQ
|
||||
#define SUPPORT_SYSRQ
|
||||
#endif
|
||||
|
@ -47,8 +49,6 @@
|
|||
|
||||
#include "mrst_max3110.h"
|
||||
|
||||
#define PR_FMT "mrst_max3110: "
|
||||
|
||||
#define UART_TX_NEEDED 1
|
||||
#define CON_TX_NEEDED 2
|
||||
#define BIT_IRQ_PENDING 3
|
||||
|
@ -127,8 +127,8 @@ static int max3110_out(struct uart_max3110 *max, const u16 out)
|
|||
*obuf = out;
|
||||
ret = max3110_write_then_read(max, obuf, ibuf, 2, 1);
|
||||
if (ret) {
|
||||
pr_warning(PR_FMT "%s(): get err msg %d when sending 0x%x\n",
|
||||
__func__, ret, out);
|
||||
pr_warn("%s: get err msg %d when sending 0x%x\n",
|
||||
__func__, ret, out);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
@ -153,10 +153,8 @@ static int max3110_read_multi(struct uart_max3110 *max)
|
|||
|
||||
blen = M3110_RX_FIFO_DEPTH * sizeof(u16);
|
||||
buf = kzalloc(blen * 2, GFP_KERNEL | GFP_DMA);
|
||||
if (!buf) {
|
||||
pr_warning(PR_FMT "%s(): fail to alloc dma buffer\n", __func__);
|
||||
if (!buf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* tx/rx always have the same length */
|
||||
obuf = buf;
|
||||
|
@ -212,13 +210,13 @@ serial_m3110_con_setup(struct console *co, char *options)
|
|||
int parity = 'n';
|
||||
int flow = 'n';
|
||||
|
||||
pr_info(PR_FMT "setting up console\n");
|
||||
pr_info("setting up console\n");
|
||||
|
||||
if (co->index == -1)
|
||||
co->index = 0;
|
||||
|
||||
if (!max) {
|
||||
pr_err(PR_FMT "pmax is NULL, return");
|
||||
pr_err("pmax is NULL, return\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -296,8 +294,7 @@ static void send_circ_buf(struct uart_max3110 *max,
|
|||
|
||||
ret = max3110_write_then_read(max, obuf, ibuf, blen, 0);
|
||||
if (ret)
|
||||
pr_warning(PR_FMT "%s(): get err msg %d\n",
|
||||
__func__, ret);
|
||||
pr_warn("%s: get err msg %d\n", __func__, ret);
|
||||
|
||||
receive_chars(max, ibuf, len);
|
||||
|
||||
|
@ -411,7 +408,7 @@ static int max3110_main_thread(void *_max)
|
|||
int ret = 0;
|
||||
struct circ_buf *xmit = &max->con_xmit;
|
||||
|
||||
pr_info(PR_FMT "start main thread\n");
|
||||
pr_info("start main thread\n");
|
||||
|
||||
do {
|
||||
wait_event_interruptible(*wq,
|
||||
|
@ -455,7 +452,7 @@ static int max3110_read_thread(void *_max)
|
|||
{
|
||||
struct uart_max3110 *max = _max;
|
||||
|
||||
pr_info(PR_FMT "start read thread\n");
|
||||
pr_info("start read thread\n");
|
||||
do {
|
||||
/*
|
||||
* If can't acquire the mutex, it means the main thread
|
||||
|
@ -481,7 +478,7 @@ static int serial_m3110_startup(struct uart_port *port)
|
|||
int ret = 0;
|
||||
|
||||
if (port->line != 0) {
|
||||
pr_err(PR_FMT "uart port startup failed\n");
|
||||
pr_err("uart port startup failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -504,7 +501,7 @@ static int serial_m3110_startup(struct uart_port *port)
|
|||
if (IS_ERR(max->read_thread)) {
|
||||
ret = PTR_ERR(max->read_thread);
|
||||
max->read_thread = NULL;
|
||||
pr_err(PR_FMT "Can't create read thread!\n");
|
||||
pr_err("Can't create read thread!\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ struct msm_port {
|
|||
unsigned int imr;
|
||||
int is_uartdm;
|
||||
unsigned int old_snap_state;
|
||||
bool break_detected;
|
||||
};
|
||||
|
||||
static inline void wait_for_xmitr(struct uart_port *port)
|
||||
|
@ -126,23 +127,38 @@ static void handle_rx_dm(struct uart_port *port, unsigned int misr)
|
|||
|
||||
while (count > 0) {
|
||||
unsigned char buf[4];
|
||||
int sysrq, r_count, i;
|
||||
|
||||
sr = msm_read(port, UART_SR);
|
||||
if ((sr & UART_SR_RX_READY) == 0) {
|
||||
msm_port->old_snap_state -= count;
|
||||
break;
|
||||
}
|
||||
ioread32_rep(port->membase + UARTDM_RF, buf, 1);
|
||||
if (sr & UART_SR_RX_BREAK) {
|
||||
port->icount.brk++;
|
||||
if (uart_handle_break(port))
|
||||
continue;
|
||||
} else if (sr & UART_SR_PAR_FRAME_ERR)
|
||||
port->icount.frame++;
|
||||
|
||||
/* TODO: handle sysrq */
|
||||
tty_insert_flip_string(tport, buf, min(count, 4));
|
||||
count -= 4;
|
||||
ioread32_rep(port->membase + UARTDM_RF, buf, 1);
|
||||
r_count = min_t(int, count, sizeof(buf));
|
||||
|
||||
for (i = 0; i < r_count; i++) {
|
||||
char flag = TTY_NORMAL;
|
||||
|
||||
if (msm_port->break_detected && buf[i] == 0) {
|
||||
port->icount.brk++;
|
||||
flag = TTY_BREAK;
|
||||
msm_port->break_detected = false;
|
||||
if (uart_handle_break(port))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(port->read_status_mask & UART_SR_RX_BREAK))
|
||||
flag = TTY_NORMAL;
|
||||
|
||||
spin_unlock(&port->lock);
|
||||
sysrq = uart_handle_sysrq_char(port, buf[i]);
|
||||
spin_lock(&port->lock);
|
||||
if (!sysrq)
|
||||
tty_insert_flip_char(tport, buf[i], flag);
|
||||
}
|
||||
count -= r_count;
|
||||
}
|
||||
|
||||
spin_unlock(&port->lock);
|
||||
|
@ -174,6 +190,7 @@ static void handle_rx(struct uart_port *port)
|
|||
while ((sr = msm_read(port, UART_SR)) & UART_SR_RX_READY) {
|
||||
unsigned int c;
|
||||
char flag = TTY_NORMAL;
|
||||
int sysrq;
|
||||
|
||||
c = msm_read(port, UART_RF);
|
||||
|
||||
|
@ -195,7 +212,10 @@ static void handle_rx(struct uart_port *port)
|
|||
else if (sr & UART_SR_PAR_FRAME_ERR)
|
||||
flag = TTY_FRAME;
|
||||
|
||||
if (!uart_handle_sysrq_char(port, c))
|
||||
spin_unlock(&port->lock);
|
||||
sysrq = uart_handle_sysrq_char(port, c);
|
||||
spin_lock(&port->lock);
|
||||
if (!sysrq)
|
||||
tty_insert_flip_char(tport, c, flag);
|
||||
}
|
||||
|
||||
|
@ -287,6 +307,11 @@ static irqreturn_t msm_irq(int irq, void *dev_id)
|
|||
misr = msm_read(port, UART_MISR);
|
||||
msm_write(port, 0, UART_IMR); /* disable interrupt */
|
||||
|
||||
if (misr & UART_IMR_RXBREAK_START) {
|
||||
msm_port->break_detected = true;
|
||||
msm_write(port, UART_CR_CMD_RESET_RXBREAK_START, UART_CR);
|
||||
}
|
||||
|
||||
if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) {
|
||||
if (msm_port->is_uartdm)
|
||||
handle_rx_dm(port, misr);
|
||||
|
@ -402,9 +427,6 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
|
|||
|
||||
entry = msm_find_best_baud(port, baud);
|
||||
|
||||
if (msm_port->is_uartdm)
|
||||
msm_write(port, UART_CR_CMD_RESET_RX, UART_CR);
|
||||
|
||||
msm_write(port, entry->code, UART_CSR);
|
||||
|
||||
/* RX stale watermark */
|
||||
|
@ -421,6 +443,18 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
|
|||
/* set TX watermark */
|
||||
msm_write(port, 10, UART_TFWR);
|
||||
|
||||
msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR);
|
||||
msm_reset(port);
|
||||
|
||||
/* Enable RX and TX */
|
||||
msm_write(port, UART_CR_TX_ENABLE | UART_CR_RX_ENABLE, UART_CR);
|
||||
|
||||
/* turn on RX and CTS interrupts */
|
||||
msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE |
|
||||
UART_IMR_CURRENT_CTS | UART_IMR_RXBREAK_START;
|
||||
|
||||
msm_write(port, msm_port->imr, UART_IMR);
|
||||
|
||||
if (msm_port->is_uartdm) {
|
||||
msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR);
|
||||
msm_write(port, 0xFFFFFF, UARTDM_DMRX);
|
||||
|
@ -467,40 +501,6 @@ static int msm_startup(struct uart_port *port)
|
|||
data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2);
|
||||
data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level;
|
||||
msm_write(port, data, UART_MR1);
|
||||
|
||||
/* make sure that RXSTALE count is non-zero */
|
||||
data = msm_read(port, UART_IPR);
|
||||
if (unlikely(!data)) {
|
||||
data |= UART_IPR_RXSTALE_LAST;
|
||||
data |= UART_IPR_STALE_LSB;
|
||||
msm_write(port, data, UART_IPR);
|
||||
}
|
||||
|
||||
data = 0;
|
||||
if (!port->cons || (port->cons && !(port->cons->flags & CON_ENABLED))) {
|
||||
msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR);
|
||||
msm_reset(port);
|
||||
data = UART_CR_TX_ENABLE;
|
||||
}
|
||||
|
||||
data |= UART_CR_RX_ENABLE;
|
||||
msm_write(port, data, UART_CR); /* enable TX & RX */
|
||||
|
||||
/* Make sure IPR is not 0 to start with*/
|
||||
if (msm_port->is_uartdm)
|
||||
msm_write(port, UART_IPR_STALE_LSB, UART_IPR);
|
||||
|
||||
/* turn on RX and CTS interrupts */
|
||||
msm_port->imr = UART_IMR_RXLEV | UART_IMR_RXSTALE |
|
||||
UART_IMR_CURRENT_CTS;
|
||||
|
||||
if (msm_port->is_uartdm) {
|
||||
msm_write(port, 0xFFFFFF, UARTDM_DMRX);
|
||||
msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR);
|
||||
msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR);
|
||||
}
|
||||
|
||||
msm_write(port, msm_port->imr, UART_IMR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1044,17 +1044,22 @@ static int msm_serial_probe(struct platform_device *pdev)
|
|||
struct resource *resource;
|
||||
struct uart_port *port;
|
||||
const struct of_device_id *id;
|
||||
int irq;
|
||||
int irq, line;
|
||||
|
||||
if (pdev->id == -1)
|
||||
pdev->id = atomic_inc_return(&msm_uart_next_id) - 1;
|
||||
if (pdev->dev.of_node)
|
||||
line = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
else
|
||||
line = pdev->id;
|
||||
|
||||
if (unlikely(pdev->id < 0 || pdev->id >= UART_NR))
|
||||
if (line < 0)
|
||||
line = atomic_inc_return(&msm_uart_next_id) - 1;
|
||||
|
||||
if (unlikely(line < 0 || line >= UART_NR))
|
||||
return -ENXIO;
|
||||
|
||||
dev_info(&pdev->dev, "msm_serial: detected port #%d\n", pdev->id);
|
||||
dev_info(&pdev->dev, "msm_serial: detected port #%d\n", line);
|
||||
|
||||
port = get_port_from_line(pdev->id);
|
||||
port = get_port_from_line(line);
|
||||
port->dev = &pdev->dev;
|
||||
msm_port = UART_TO_MSM(port);
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
#define UART_CR_TX_ENABLE (1 << 2)
|
||||
#define UART_CR_RX_DISABLE (1 << 1)
|
||||
#define UART_CR_RX_ENABLE (1 << 0)
|
||||
#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4))
|
||||
|
||||
#define UART_IMR 0x0014
|
||||
#define UART_IMR_TXLEV (1 << 0)
|
||||
|
@ -72,6 +73,7 @@
|
|||
#define UART_IMR_RXLEV (1 << 4)
|
||||
#define UART_IMR_DELTA_CTS (1 << 5)
|
||||
#define UART_IMR_CURRENT_CTS (1 << 6)
|
||||
#define UART_IMR_RXBREAK_START (1 << 10)
|
||||
|
||||
#define UART_IPR_RXSTALE_LAST 0x20
|
||||
#define UART_IPR_STALE_LSB 0x1F
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_SERIAL_MXS_AUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
||||
#define SUPPORT_SYSRQ
|
||||
#endif
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -38,6 +42,12 @@
|
|||
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/irq.h>
|
||||
#include "serial_mctrl_gpio.h"
|
||||
|
||||
#define MXS_AUART_PORTS 5
|
||||
#define MXS_AUART_FIFO_SIZE 16
|
||||
|
||||
|
@ -139,7 +149,7 @@ struct mxs_auart_port {
|
|||
#define MXS_AUART_DMA_RX_READY 3 /* bit 3 */
|
||||
#define MXS_AUART_RTSCTS 4 /* bit 4 */
|
||||
unsigned long flags;
|
||||
unsigned int ctrl;
|
||||
unsigned int mctrl_prev;
|
||||
enum mxs_auart_type devtype;
|
||||
|
||||
unsigned int irq;
|
||||
|
@ -155,6 +165,10 @@ struct mxs_auart_port {
|
|||
struct scatterlist rx_sgl;
|
||||
struct dma_chan *rx_dma_chan;
|
||||
void *rx_dma_buf;
|
||||
|
||||
struct mctrl_gpios *gpios;
|
||||
int gpio_irq[UART_GPIO_MAX];
|
||||
bool ms_irq_enabled;
|
||||
};
|
||||
|
||||
static struct platform_device_id mxs_auart_devtype[] = {
|
||||
|
@ -414,25 +428,102 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl)
|
|||
ctrl |= AUART_CTRL2_RTS;
|
||||
}
|
||||
|
||||
s->ctrl = mctrl;
|
||||
writel(ctrl, u->membase + AUART_CTRL2);
|
||||
|
||||
mctrl_gpio_set(s->gpios, mctrl);
|
||||
}
|
||||
|
||||
#define MCTRL_ANY_DELTA (TIOCM_RI | TIOCM_DSR | TIOCM_CD | TIOCM_CTS)
|
||||
static u32 mxs_auart_modem_status(struct mxs_auart_port *s, u32 mctrl)
|
||||
{
|
||||
u32 mctrl_diff;
|
||||
|
||||
mctrl_diff = mctrl ^ s->mctrl_prev;
|
||||
s->mctrl_prev = mctrl;
|
||||
if (mctrl_diff & MCTRL_ANY_DELTA && s->ms_irq_enabled &&
|
||||
s->port.state != NULL) {
|
||||
if (mctrl_diff & TIOCM_RI)
|
||||
s->port.icount.rng++;
|
||||
if (mctrl_diff & TIOCM_DSR)
|
||||
s->port.icount.dsr++;
|
||||
if (mctrl_diff & TIOCM_CD)
|
||||
uart_handle_dcd_change(&s->port, mctrl & TIOCM_CD);
|
||||
if (mctrl_diff & TIOCM_CTS)
|
||||
uart_handle_cts_change(&s->port, mctrl & TIOCM_CTS);
|
||||
|
||||
wake_up_interruptible(&s->port.state->port.delta_msr_wait);
|
||||
}
|
||||
return mctrl;
|
||||
}
|
||||
|
||||
static u32 mxs_auart_get_mctrl(struct uart_port *u)
|
||||
{
|
||||
struct mxs_auart_port *s = to_auart_port(u);
|
||||
u32 stat = readl(u->membase + AUART_STAT);
|
||||
int ctrl2 = readl(u->membase + AUART_CTRL2);
|
||||
u32 mctrl = s->ctrl;
|
||||
u32 mctrl = 0;
|
||||
|
||||
mctrl &= ~TIOCM_CTS;
|
||||
if (stat & AUART_STAT_CTS)
|
||||
mctrl |= TIOCM_CTS;
|
||||
|
||||
if (ctrl2 & AUART_CTRL2_RTS)
|
||||
mctrl |= TIOCM_RTS;
|
||||
return mctrl_gpio_get(s->gpios, &mctrl);
|
||||
}
|
||||
|
||||
return mctrl;
|
||||
/*
|
||||
* Enable modem status interrupts
|
||||
*/
|
||||
static void mxs_auart_enable_ms(struct uart_port *port)
|
||||
{
|
||||
struct mxs_auart_port *s = to_auart_port(port);
|
||||
|
||||
/*
|
||||
* Interrupt should not be enabled twice
|
||||
*/
|
||||
if (s->ms_irq_enabled)
|
||||
return;
|
||||
|
||||
s->ms_irq_enabled = true;
|
||||
|
||||
if (s->gpio_irq[UART_GPIO_CTS] >= 0)
|
||||
enable_irq(s->gpio_irq[UART_GPIO_CTS]);
|
||||
/* TODO: enable AUART_INTR_CTSMIEN otherwise */
|
||||
|
||||
if (s->gpio_irq[UART_GPIO_DSR] >= 0)
|
||||
enable_irq(s->gpio_irq[UART_GPIO_DSR]);
|
||||
|
||||
if (s->gpio_irq[UART_GPIO_RI] >= 0)
|
||||
enable_irq(s->gpio_irq[UART_GPIO_RI]);
|
||||
|
||||
if (s->gpio_irq[UART_GPIO_DCD] >= 0)
|
||||
enable_irq(s->gpio_irq[UART_GPIO_DCD]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable modem status interrupts
|
||||
*/
|
||||
static void mxs_auart_disable_ms(struct uart_port *port)
|
||||
{
|
||||
struct mxs_auart_port *s = to_auart_port(port);
|
||||
|
||||
/*
|
||||
* Interrupt should not be disabled twice
|
||||
*/
|
||||
if (!s->ms_irq_enabled)
|
||||
return;
|
||||
|
||||
s->ms_irq_enabled = false;
|
||||
|
||||
if (s->gpio_irq[UART_GPIO_CTS] >= 0)
|
||||
disable_irq(s->gpio_irq[UART_GPIO_CTS]);
|
||||
/* TODO: disable AUART_INTR_CTSMIEN otherwise */
|
||||
|
||||
if (s->gpio_irq[UART_GPIO_DSR] >= 0)
|
||||
disable_irq(s->gpio_irq[UART_GPIO_DSR]);
|
||||
|
||||
if (s->gpio_irq[UART_GPIO_RI] >= 0)
|
||||
disable_irq(s->gpio_irq[UART_GPIO_RI]);
|
||||
|
||||
if (s->gpio_irq[UART_GPIO_DCD] >= 0)
|
||||
disable_irq(s->gpio_irq[UART_GPIO_DCD]);
|
||||
}
|
||||
|
||||
static int mxs_auart_dma_prep_rx(struct mxs_auart_port *s);
|
||||
|
@ -560,6 +651,10 @@ err_out:
|
|||
|
||||
}
|
||||
|
||||
#define RTS_AT_AUART() IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(s->gpios, \
|
||||
UART_GPIO_RTS))
|
||||
#define CTS_AT_AUART() IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(s->gpios, \
|
||||
UART_GPIO_CTS))
|
||||
static void mxs_auart_settermios(struct uart_port *u,
|
||||
struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
|
@ -636,6 +731,7 @@ static void mxs_auart_settermios(struct uart_port *u,
|
|||
ctrl |= AUART_LINECTRL_STP2;
|
||||
|
||||
/* figure out the hardware flow control settings */
|
||||
ctrl2 &= ~(AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN);
|
||||
if (cflag & CRTSCTS) {
|
||||
/*
|
||||
* The DMA has a bug(see errata:2836) in mx23.
|
||||
|
@ -650,9 +746,11 @@ static void mxs_auart_settermios(struct uart_port *u,
|
|||
ctrl2 |= AUART_CTRL2_TXDMAE | AUART_CTRL2_RXDMAE
|
||||
| AUART_CTRL2_DMAONERR;
|
||||
}
|
||||
ctrl2 |= AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN;
|
||||
} else {
|
||||
ctrl2 &= ~(AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN);
|
||||
/* Even if RTS is GPIO line RTSEN can be enabled because
|
||||
* the pinctrl configuration decides about RTS pin function */
|
||||
ctrl2 |= AUART_CTRL2_RTSEN;
|
||||
if (CTS_AT_AUART())
|
||||
ctrl2 |= AUART_CTRL2_CTSEN;
|
||||
}
|
||||
|
||||
/* set baud rate */
|
||||
|
@ -678,12 +776,30 @@ static void mxs_auart_settermios(struct uart_port *u,
|
|||
dev_err(s->dev, "We can not start up the DMA.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* CTS flow-control and modem-status interrupts */
|
||||
if (UART_ENABLE_MS(u, termios->c_cflag))
|
||||
mxs_auart_enable_ms(u);
|
||||
else
|
||||
mxs_auart_disable_ms(u);
|
||||
}
|
||||
|
||||
static void mxs_auart_set_ldisc(struct uart_port *port,
|
||||
struct ktermios *termios)
|
||||
{
|
||||
if (termios->c_line == N_PPS) {
|
||||
port->flags |= UPF_HARDPPS_CD;
|
||||
mxs_auart_enable_ms(port);
|
||||
} else {
|
||||
port->flags &= ~UPF_HARDPPS_CD;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
|
||||
{
|
||||
u32 istat;
|
||||
struct mxs_auart_port *s = context;
|
||||
u32 mctrl_temp = s->mctrl_prev;
|
||||
u32 stat = readl(s->port.membase + AUART_STAT);
|
||||
|
||||
istat = readl(s->port.membase + AUART_INTR);
|
||||
|
@ -695,8 +811,20 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
|
|||
| AUART_INTR_CTSMIS),
|
||||
s->port.membase + AUART_INTR_CLR);
|
||||
|
||||
/*
|
||||
* Dealing with GPIO interrupt
|
||||
*/
|
||||
if (irq == s->gpio_irq[UART_GPIO_CTS] ||
|
||||
irq == s->gpio_irq[UART_GPIO_DCD] ||
|
||||
irq == s->gpio_irq[UART_GPIO_DSR] ||
|
||||
irq == s->gpio_irq[UART_GPIO_RI])
|
||||
mxs_auart_modem_status(s,
|
||||
mctrl_gpio_get(s->gpios, &mctrl_temp));
|
||||
|
||||
if (istat & AUART_INTR_CTSMIS) {
|
||||
uart_handle_cts_change(&s->port, stat & AUART_STAT_CTS);
|
||||
if (CTS_AT_AUART() && s->ms_irq_enabled)
|
||||
uart_handle_cts_change(&s->port,
|
||||
stat & AUART_STAT_CTS);
|
||||
writel(AUART_INTR_CTSMIS,
|
||||
s->port.membase + AUART_INTR_CLR);
|
||||
istat &= ~AUART_INTR_CTSMIS;
|
||||
|
@ -757,6 +885,10 @@ static int mxs_auart_startup(struct uart_port *u)
|
|||
*/
|
||||
writel(AUART_LINECTRL_FEN, u->membase + AUART_LINECTRL_SET);
|
||||
|
||||
/* get initial status of modem lines */
|
||||
mctrl_gpio_get(s->gpios, &s->mctrl_prev);
|
||||
|
||||
s->ms_irq_enabled = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -764,6 +896,8 @@ static void mxs_auart_shutdown(struct uart_port *u)
|
|||
{
|
||||
struct mxs_auart_port *s = to_auart_port(u);
|
||||
|
||||
mxs_auart_disable_ms(u);
|
||||
|
||||
if (auart_dma_enabled(s))
|
||||
mxs_auart_dma_exit(s);
|
||||
|
||||
|
@ -779,10 +913,11 @@ static void mxs_auart_shutdown(struct uart_port *u)
|
|||
|
||||
static unsigned int mxs_auart_tx_empty(struct uart_port *u)
|
||||
{
|
||||
if (readl(u->membase + AUART_STAT) & AUART_STAT_TXFE)
|
||||
if ((readl(u->membase + AUART_STAT) &
|
||||
(AUART_STAT_TXFE | AUART_STAT_BUSY)) == AUART_STAT_TXFE)
|
||||
return TIOCSER_TEMT;
|
||||
else
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mxs_auart_start_tx(struct uart_port *u)
|
||||
|
@ -820,12 +955,14 @@ static struct uart_ops mxs_auart_ops = {
|
|||
.start_tx = mxs_auart_start_tx,
|
||||
.stop_tx = mxs_auart_stop_tx,
|
||||
.stop_rx = mxs_auart_stop_rx,
|
||||
.enable_ms = mxs_auart_enable_ms,
|
||||
.break_ctl = mxs_auart_break_ctl,
|
||||
.set_mctrl = mxs_auart_set_mctrl,
|
||||
.get_mctrl = mxs_auart_get_mctrl,
|
||||
.startup = mxs_auart_startup,
|
||||
.shutdown = mxs_auart_shutdown,
|
||||
.set_termios = mxs_auart_settermios,
|
||||
.set_ldisc = mxs_auart_set_ldisc,
|
||||
.type = mxs_auart_type,
|
||||
.release_port = mxs_auart_release_port,
|
||||
.request_port = mxs_auart_request_port,
|
||||
|
@ -1020,6 +1157,71 @@ static int serial_mxs_probe_dt(struct mxs_auart_port *s,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
struct gpio_desc *gpiod;
|
||||
|
||||
s->gpios = mctrl_gpio_init(dev, 0);
|
||||
if (IS_ERR_OR_NULL(s->gpios))
|
||||
return false;
|
||||
|
||||
/* Block (enabled before) DMA option if RTS or CTS is GPIO line */
|
||||
if (!RTS_AT_AUART() || !CTS_AT_AUART()) {
|
||||
if (test_bit(MXS_AUART_RTSCTS, &s->flags))
|
||||
dev_warn(dev,
|
||||
"DMA and flow control via gpio may cause some problems. DMA disabled!\n");
|
||||
clear_bit(MXS_AUART_RTSCTS, &s->flags);
|
||||
}
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; i++) {
|
||||
gpiod = mctrl_gpio_to_gpiod(s->gpios, i);
|
||||
if (gpiod && (gpiod_get_direction(gpiod) == GPIOF_DIR_IN))
|
||||
s->gpio_irq[i] = gpiod_to_irq(gpiod);
|
||||
else
|
||||
s->gpio_irq[i] = -EINVAL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void mxs_auart_free_gpio_irq(struct mxs_auart_port *s)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
|
||||
for (i = 0; i < UART_GPIO_MAX; i++)
|
||||
if (s->gpio_irq[i] >= 0)
|
||||
free_irq(s->gpio_irq[i], s);
|
||||
}
|
||||
|
||||
static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s)
|
||||
{
|
||||
int *irq = s->gpio_irq;
|
||||
enum mctrl_gpio_idx i;
|
||||
int err = 0;
|
||||
|
||||
for (i = 0; (i < UART_GPIO_MAX) && !err; i++) {
|
||||
if (irq[i] < 0)
|
||||
continue;
|
||||
|
||||
irq_set_status_flags(irq[i], IRQ_NOAUTOEN);
|
||||
err = request_irq(irq[i], mxs_auart_irq_handle,
|
||||
IRQ_TYPE_EDGE_BOTH, dev_name(s->dev), s);
|
||||
if (err)
|
||||
dev_err(s->dev, "%s - Can't get %d irq\n",
|
||||
__func__, irq[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* If something went wrong, rollback.
|
||||
*/
|
||||
while (err && (--i >= 0))
|
||||
if (irq[i] >= 0)
|
||||
free_irq(irq[i], s);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mxs_auart_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *of_id =
|
||||
|
@ -1067,7 +1269,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
|
|||
s->port.type = PORT_IMX;
|
||||
s->port.dev = s->dev = &pdev->dev;
|
||||
|
||||
s->ctrl = 0;
|
||||
s->mctrl_prev = 0;
|
||||
|
||||
s->irq = platform_get_irq(pdev, 0);
|
||||
s->port.irq = s->irq;
|
||||
|
@ -1077,13 +1279,24 @@ static int mxs_auart_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, s);
|
||||
|
||||
if (!mxs_auart_init_gpios(s, &pdev->dev))
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to initialize GPIOs. The serial port may not work as expected\n");
|
||||
|
||||
/*
|
||||
* Get the GPIO lines IRQ
|
||||
*/
|
||||
ret = mxs_auart_request_gpio_irq(s);
|
||||
if (ret)
|
||||
goto out_free_irq;
|
||||
|
||||
auart_port[s->port.line] = s;
|
||||
|
||||
mxs_auart_reset(&s->port);
|
||||
|
||||
ret = uart_add_one_port(&auart_driver, &s->port);
|
||||
if (ret)
|
||||
goto out_free_irq;
|
||||
goto out_free_gpio_irq;
|
||||
|
||||
version = readl(s->port.membase + AUART_VERSION);
|
||||
dev_info(&pdev->dev, "Found APPUART %d.%d.%d\n",
|
||||
|
@ -1092,6 +1305,8 @@ static int mxs_auart_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
|
||||
out_free_gpio_irq:
|
||||
mxs_auart_free_gpio_irq(s);
|
||||
out_free_irq:
|
||||
auart_port[pdev->id] = NULL;
|
||||
free_irq(s->irq, s);
|
||||
|
@ -1111,6 +1326,7 @@ static int mxs_auart_remove(struct platform_device *pdev)
|
|||
|
||||
auart_port[pdev->id] = NULL;
|
||||
|
||||
mxs_auart_free_gpio_irq(s);
|
||||
clk_put(s->clk);
|
||||
free_irq(s->irq, s);
|
||||
kfree(s);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
#include <linux/console.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
|
@ -129,8 +130,15 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
|
|||
|
||||
port->dev = &ofdev->dev;
|
||||
|
||||
if (type == PORT_TEGRA)
|
||||
switch (type) {
|
||||
case PORT_TEGRA:
|
||||
port->handle_break = tegra_serial_handle_break;
|
||||
break;
|
||||
|
||||
case PORT_RT2880:
|
||||
port->iotype = UPIO_AU;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
out:
|
||||
|
@ -240,6 +248,70 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
#ifdef CONFIG_SERIAL_8250
|
||||
static void of_serial_suspend_8250(struct of_serial_info *info)
|
||||
{
|
||||
struct uart_8250_port *port8250 = serial8250_get_port(info->line);
|
||||
struct uart_port *port = &port8250->port;
|
||||
|
||||
serial8250_suspend_port(info->line);
|
||||
if (info->clk && (!uart_console(port) || console_suspend_enabled))
|
||||
clk_disable_unprepare(info->clk);
|
||||
}
|
||||
|
||||
static void of_serial_resume_8250(struct of_serial_info *info)
|
||||
{
|
||||
struct uart_8250_port *port8250 = serial8250_get_port(info->line);
|
||||
struct uart_port *port = &port8250->port;
|
||||
|
||||
if (info->clk && (!uart_console(port) || console_suspend_enabled))
|
||||
clk_prepare_enable(info->clk);
|
||||
|
||||
serial8250_resume_port(info->line);
|
||||
}
|
||||
#else
|
||||
static inline void of_serial_suspend_8250(struct of_serial_info *info)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void of_serial_resume_8250(struct of_serial_info *info)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static int of_serial_suspend(struct device *dev)
|
||||
{
|
||||
struct of_serial_info *info = dev_get_drvdata(dev);
|
||||
|
||||
switch (info->type) {
|
||||
case PORT_8250 ... PORT_MAX_8250:
|
||||
of_serial_suspend_8250(info);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int of_serial_resume(struct device *dev)
|
||||
{
|
||||
struct of_serial_info *info = dev_get_drvdata(dev);
|
||||
|
||||
switch (info->type) {
|
||||
case PORT_8250 ... PORT_MAX_8250:
|
||||
of_serial_resume_8250(info);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
static SIMPLE_DEV_PM_OPS(of_serial_pm_ops, of_serial_suspend, of_serial_resume);
|
||||
|
||||
/*
|
||||
* A few common types, add more as needed.
|
||||
*/
|
||||
|
@ -252,6 +324,7 @@ static struct of_device_id of_platform_serial_table[] = {
|
|||
{ .compatible = "ns16850", .data = (void *)PORT_16850, },
|
||||
{ .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, },
|
||||
{ .compatible = "nxp,lpc3220-uart", .data = (void *)PORT_LPC3220, },
|
||||
{ .compatible = "ralink,rt2880-uart", .data = (void *)PORT_RT2880, },
|
||||
{ .compatible = "altr,16550-FIFO32",
|
||||
.data = (void *)PORT_ALTR_16550_F32, },
|
||||
{ .compatible = "altr,16550-FIFO64",
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
#define OMAP_MAX_HSUART_PORTS 6
|
||||
#define OMAP_MAX_HSUART_PORTS 10
|
||||
|
||||
#define UART_BUILD_REVISION(x, y) (((x) << 8) | (y))
|
||||
|
||||
|
@ -163,7 +163,6 @@ struct uart_omap_port {
|
|||
u8 wakeups_enabled;
|
||||
u32 features;
|
||||
|
||||
struct serial_rs485 rs485;
|
||||
int rts_gpio;
|
||||
|
||||
struct pm_qos_request pm_qos_request;
|
||||
|
@ -316,7 +315,7 @@ static void serial_omap_stop_tx(struct uart_port *port)
|
|||
pm_runtime_get_sync(up->dev);
|
||||
|
||||
/* Handle RS-485 */
|
||||
if (up->rs485.flags & SER_RS485_ENABLED) {
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
if (up->scr & OMAP_UART_SCR_TX_EMPTY) {
|
||||
/* THR interrupt is fired when both TX FIFO and TX
|
||||
* shift register are empty. This means there's nothing
|
||||
|
@ -327,10 +326,12 @@ static void serial_omap_stop_tx(struct uart_port *port)
|
|||
*/
|
||||
up->scr &= ~OMAP_UART_SCR_TX_EMPTY;
|
||||
serial_out(up, UART_OMAP_SCR, up->scr);
|
||||
res = (up->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0;
|
||||
res = (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) ?
|
||||
1 : 0;
|
||||
if (gpio_get_value(up->rts_gpio) != res) {
|
||||
if (up->rs485.delay_rts_after_send > 0)
|
||||
mdelay(up->rs485.delay_rts_after_send);
|
||||
if (port->rs485.delay_rts_after_send > 0)
|
||||
mdelay(
|
||||
port->rs485.delay_rts_after_send);
|
||||
gpio_set_value(up->rts_gpio, res);
|
||||
}
|
||||
} else {
|
||||
|
@ -353,8 +354,8 @@ static void serial_omap_stop_tx(struct uart_port *port)
|
|||
serial_out(up, UART_IER, up->ier);
|
||||
}
|
||||
|
||||
if ((up->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(up->rs485.flags & SER_RS485_RX_DURING_TX)) {
|
||||
if ((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
|
||||
/*
|
||||
* Empty the RX FIFO, we are not interested in anything
|
||||
* received during the half-duplex transmission.
|
||||
|
@ -429,22 +430,22 @@ static void serial_omap_start_tx(struct uart_port *port)
|
|||
pm_runtime_get_sync(up->dev);
|
||||
|
||||
/* Handle RS-485 */
|
||||
if (up->rs485.flags & SER_RS485_ENABLED) {
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
/* Fire THR interrupts when FIFO is below trigger level */
|
||||
up->scr &= ~OMAP_UART_SCR_TX_EMPTY;
|
||||
serial_out(up, UART_OMAP_SCR, up->scr);
|
||||
|
||||
/* if rts not already enabled */
|
||||
res = (up->rs485.flags & SER_RS485_RTS_ON_SEND) ? 1 : 0;
|
||||
res = (port->rs485.flags & SER_RS485_RTS_ON_SEND) ? 1 : 0;
|
||||
if (gpio_get_value(up->rts_gpio) != res) {
|
||||
gpio_set_value(up->rts_gpio, res);
|
||||
if (up->rs485.delay_rts_before_send > 0)
|
||||
mdelay(up->rs485.delay_rts_before_send);
|
||||
if (port->rs485.delay_rts_before_send > 0)
|
||||
mdelay(port->rs485.delay_rts_before_send);
|
||||
}
|
||||
}
|
||||
|
||||
if ((up->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(up->rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
if ((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!(port->rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
serial_omap_stop_rx(port);
|
||||
|
||||
serial_omap_enable_ier_thri(up);
|
||||
|
@ -1355,16 +1356,14 @@ static inline void serial_omap_add_console_port(struct uart_omap_port *up)
|
|||
#endif
|
||||
|
||||
/* Enable or disable the rs485 support */
|
||||
static void
|
||||
static int
|
||||
serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
|
||||
{
|
||||
struct uart_omap_port *up = to_uart_omap_port(port);
|
||||
unsigned long flags;
|
||||
unsigned int mode;
|
||||
int val;
|
||||
|
||||
pm_runtime_get_sync(up->dev);
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
|
||||
/* Disable interrupts from this port */
|
||||
mode = up->ier;
|
||||
|
@ -1372,7 +1371,7 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
|
|||
serial_out(up, UART_IER, 0);
|
||||
|
||||
/* store new config */
|
||||
up->rs485 = *rs485conf;
|
||||
port->rs485 = *rs485conf;
|
||||
|
||||
/*
|
||||
* Just as a precaution, only allow rs485
|
||||
|
@ -1380,12 +1379,12 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
|
|||
*/
|
||||
if (gpio_is_valid(up->rts_gpio)) {
|
||||
/* enable / disable rts */
|
||||
val = (up->rs485.flags & SER_RS485_ENABLED) ?
|
||||
val = (port->rs485.flags & SER_RS485_ENABLED) ?
|
||||
SER_RS485_RTS_AFTER_SEND : SER_RS485_RTS_ON_SEND;
|
||||
val = (up->rs485.flags & val) ? 1 : 0;
|
||||
val = (port->rs485.flags & val) ? 1 : 0;
|
||||
gpio_set_value(up->rts_gpio, val);
|
||||
} else
|
||||
up->rs485.flags &= ~SER_RS485_ENABLED;
|
||||
port->rs485.flags &= ~SER_RS485_ENABLED;
|
||||
|
||||
/* Enable interrupts */
|
||||
up->ier = mode;
|
||||
|
@ -1394,45 +1393,18 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
|
|||
/* If RS-485 is disabled, make sure the THR interrupt is fired when
|
||||
* TX FIFO is below the trigger level.
|
||||
*/
|
||||
if (!(up->rs485.flags & SER_RS485_ENABLED) &&
|
||||
if (!(port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
(up->scr & OMAP_UART_SCR_TX_EMPTY)) {
|
||||
up->scr &= ~OMAP_UART_SCR_TX_EMPTY;
|
||||
serial_out(up, UART_OMAP_SCR, up->scr);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
pm_runtime_mark_last_busy(up->dev);
|
||||
pm_runtime_put_autosuspend(up->dev);
|
||||
}
|
||||
|
||||
static int
|
||||
serial_omap_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct serial_rs485 rs485conf;
|
||||
|
||||
switch (cmd) {
|
||||
case TIOCSRS485:
|
||||
if (copy_from_user(&rs485conf, (void __user *) arg,
|
||||
sizeof(rs485conf)))
|
||||
return -EFAULT;
|
||||
|
||||
serial_omap_config_rs485(port, &rs485conf);
|
||||
break;
|
||||
|
||||
case TIOCGRS485:
|
||||
if (copy_to_user((void __user *) arg,
|
||||
&(to_uart_omap_port(port)->rs485),
|
||||
sizeof(rs485conf)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct uart_ops serial_omap_pops = {
|
||||
.tx_empty = serial_omap_tx_empty,
|
||||
.set_mctrl = serial_omap_set_mctrl,
|
||||
|
@ -1453,7 +1425,6 @@ static struct uart_ops serial_omap_pops = {
|
|||
.request_port = serial_omap_request_port,
|
||||
.config_port = serial_omap_config_port,
|
||||
.verify_port = serial_omap_verify_port,
|
||||
.ioctl = serial_omap_ioctl,
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_put_char = serial_omap_poll_put_char,
|
||||
.poll_get_char = serial_omap_poll_get_char,
|
||||
|
@ -1587,7 +1558,7 @@ static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
|
|||
static int serial_omap_probe_rs485(struct uart_omap_port *up,
|
||||
struct device_node *np)
|
||||
{
|
||||
struct serial_rs485 *rs485conf = &up->rs485;
|
||||
struct serial_rs485 *rs485conf = &up->port.rs485;
|
||||
u32 rs485_delay[2];
|
||||
enum of_gpio_flags flags;
|
||||
int ret;
|
||||
|
@ -1682,14 +1653,21 @@ static int serial_omap_probe(struct platform_device *pdev)
|
|||
up->port.ops = &serial_omap_pops;
|
||||
|
||||
if (pdev->dev.of_node)
|
||||
up->port.line = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
ret = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
else
|
||||
up->port.line = pdev->id;
|
||||
ret = pdev->id;
|
||||
|
||||
if (up->port.line < 0) {
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to get alias/pdev id, errno %d\n",
|
||||
up->port.line);
|
||||
ret = -ENODEV;
|
||||
ret);
|
||||
goto err_port_line;
|
||||
}
|
||||
up->port.line = ret;
|
||||
|
||||
if (up->port.line >= OMAP_MAX_HSUART_PORTS) {
|
||||
dev_err(&pdev->dev, "uart ID %d > MAX %d.\n", up->port.line,
|
||||
OMAP_MAX_HSUART_PORTS);
|
||||
ret = -ENXIO;
|
||||
goto err_port_line;
|
||||
}
|
||||
|
||||
|
@ -1702,6 +1680,7 @@ static int serial_omap_probe(struct platform_device *pdev)
|
|||
up->port.membase = base;
|
||||
up->port.flags = omap_up_info->flags;
|
||||
up->port.uartclk = omap_up_info->uartclk;
|
||||
up->port.rs485_config = serial_omap_config_rs485;
|
||||
if (!up->port.uartclk) {
|
||||
up->port.uartclk = DEFAULT_CLK_SPEED;
|
||||
dev_warn(&pdev->dev,
|
||||
|
@ -1747,8 +1726,6 @@ err_add_port:
|
|||
pm_runtime_disable(&pdev->dev);
|
||||
err_rs485:
|
||||
err_port_line:
|
||||
dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",
|
||||
pdev->id, __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -1352,7 +1352,8 @@ static int pmz_verify_port(struct uart_port *port, struct serial_struct *ser)
|
|||
|
||||
static int pmz_poll_get_char(struct uart_port *port)
|
||||
{
|
||||
struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
|
||||
struct uart_pmac_port *uap =
|
||||
container_of(port, struct uart_pmac_port, port);
|
||||
int tries = 2;
|
||||
|
||||
while (tries) {
|
||||
|
@ -1367,7 +1368,8 @@ static int pmz_poll_get_char(struct uart_port *port)
|
|||
|
||||
static void pmz_poll_put_char(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
|
||||
struct uart_pmac_port *uap =
|
||||
container_of(port, struct uart_pmac_port, port);
|
||||
|
||||
/* Wait for the transmit buffer to empty. */
|
||||
while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
|
||||
|
@ -1954,7 +1956,8 @@ static void __exit exit_pmz(void)
|
|||
|
||||
static void pmz_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
|
||||
struct uart_pmac_port *uap =
|
||||
container_of(port, struct uart_pmac_port, port);
|
||||
|
||||
/* Wait for the transmit buffer to empty. */
|
||||
while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
|
||||
|
|
|
@ -126,7 +126,8 @@ static void pnx8xxx_timeout(unsigned long data)
|
|||
*/
|
||||
static void pnx8xxx_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
|
||||
struct pnx8xxx_port *sport =
|
||||
container_of(port, struct pnx8xxx_port, port);
|
||||
u32 ien;
|
||||
|
||||
/* Disable TX intr */
|
||||
|
@ -142,7 +143,8 @@ static void pnx8xxx_stop_tx(struct uart_port *port)
|
|||
*/
|
||||
static void pnx8xxx_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
|
||||
struct pnx8xxx_port *sport =
|
||||
container_of(port, struct pnx8xxx_port, port);
|
||||
u32 ien;
|
||||
|
||||
/* Clear all pending TX intr */
|
||||
|
@ -158,7 +160,8 @@ static void pnx8xxx_start_tx(struct uart_port *port)
|
|||
*/
|
||||
static void pnx8xxx_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
|
||||
struct pnx8xxx_port *sport =
|
||||
container_of(port, struct pnx8xxx_port, port);
|
||||
u32 ien;
|
||||
|
||||
/* Disable RX intr */
|
||||
|
@ -174,7 +177,8 @@ static void pnx8xxx_stop_rx(struct uart_port *port)
|
|||
*/
|
||||
static void pnx8xxx_enable_ms(struct uart_port *port)
|
||||
{
|
||||
struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
|
||||
struct pnx8xxx_port *sport =
|
||||
container_of(port, struct pnx8xxx_port, port);
|
||||
|
||||
mod_timer(&sport->timer, jiffies);
|
||||
}
|
||||
|
@ -313,14 +317,16 @@ static irqreturn_t pnx8xxx_int(int irq, void *dev_id)
|
|||
*/
|
||||
static unsigned int pnx8xxx_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
|
||||
struct pnx8xxx_port *sport =
|
||||
container_of(port, struct pnx8xxx_port, port);
|
||||
|
||||
return serial_in(sport, PNX8XXX_FIFO) & PNX8XXX_UART_FIFO_TXFIFO_STA ? 0 : TIOCSER_TEMT;
|
||||
}
|
||||
|
||||
static unsigned int pnx8xxx_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
|
||||
struct pnx8xxx_port *sport =
|
||||
container_of(port, struct pnx8xxx_port, port);
|
||||
unsigned int mctrl = TIOCM_DSR;
|
||||
unsigned int msr;
|
||||
|
||||
|
@ -347,7 +353,8 @@ static void pnx8xxx_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
|||
*/
|
||||
static void pnx8xxx_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
|
||||
struct pnx8xxx_port *sport =
|
||||
container_of(port, struct pnx8xxx_port, port);
|
||||
unsigned long flags;
|
||||
unsigned int lcr;
|
||||
|
||||
|
@ -363,7 +370,8 @@ static void pnx8xxx_break_ctl(struct uart_port *port, int break_state)
|
|||
|
||||
static int pnx8xxx_startup(struct uart_port *port)
|
||||
{
|
||||
struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
|
||||
struct pnx8xxx_port *sport =
|
||||
container_of(port, struct pnx8xxx_port, port);
|
||||
int retval;
|
||||
|
||||
/*
|
||||
|
@ -397,7 +405,8 @@ static int pnx8xxx_startup(struct uart_port *port)
|
|||
|
||||
static void pnx8xxx_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
|
||||
struct pnx8xxx_port *sport =
|
||||
container_of(port, struct pnx8xxx_port, port);
|
||||
int lcr;
|
||||
|
||||
/*
|
||||
|
@ -434,7 +443,8 @@ static void
|
|||
pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
|
||||
struct pnx8xxx_port *sport =
|
||||
container_of(port, struct pnx8xxx_port, port);
|
||||
unsigned long flags;
|
||||
unsigned int lcr_fcr, old_ien, baud, quot;
|
||||
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
|
||||
|
@ -551,7 +561,8 @@ pnx8xxx_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
|
||||
static const char *pnx8xxx_type(struct uart_port *port)
|
||||
{
|
||||
struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
|
||||
struct pnx8xxx_port *sport =
|
||||
container_of(port, struct pnx8xxx_port, port);
|
||||
|
||||
return sport->port.type == PORT_PNX8XXX ? "PNX8XXX" : NULL;
|
||||
}
|
||||
|
@ -561,7 +572,8 @@ static const char *pnx8xxx_type(struct uart_port *port)
|
|||
*/
|
||||
static void pnx8xxx_release_port(struct uart_port *port)
|
||||
{
|
||||
struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
|
||||
struct pnx8xxx_port *sport =
|
||||
container_of(port, struct pnx8xxx_port, port);
|
||||
|
||||
release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
|
||||
}
|
||||
|
@ -571,7 +583,8 @@ static void pnx8xxx_release_port(struct uart_port *port)
|
|||
*/
|
||||
static int pnx8xxx_request_port(struct uart_port *port)
|
||||
{
|
||||
struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
|
||||
struct pnx8xxx_port *sport =
|
||||
container_of(port, struct pnx8xxx_port, port);
|
||||
return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
|
||||
"pnx8xxx-uart") != NULL ? 0 : -EBUSY;
|
||||
}
|
||||
|
@ -581,7 +594,8 @@ static int pnx8xxx_request_port(struct uart_port *port)
|
|||
*/
|
||||
static void pnx8xxx_config_port(struct uart_port *port, int flags)
|
||||
{
|
||||
struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
|
||||
struct pnx8xxx_port *sport =
|
||||
container_of(port, struct pnx8xxx_port, port);
|
||||
|
||||
if (flags & UART_CONFIG_TYPE &&
|
||||
pnx8xxx_request_port(&sport->port) == 0)
|
||||
|
@ -596,7 +610,8 @@ static void pnx8xxx_config_port(struct uart_port *port, int flags)
|
|||
static int
|
||||
pnx8xxx_verify_port(struct uart_port *port, struct serial_struct *ser)
|
||||
{
|
||||
struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
|
||||
struct pnx8xxx_port *sport =
|
||||
container_of(port, struct pnx8xxx_port, port);
|
||||
int ret = 0;
|
||||
|
||||
if (ser->type != PORT_UNKNOWN && ser->type != PORT_PNX8XXX)
|
||||
|
@ -662,7 +677,8 @@ static void __init pnx8xxx_init_ports(void)
|
|||
|
||||
static void pnx8xxx_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
struct pnx8xxx_port *sport = (struct pnx8xxx_port *)port;
|
||||
struct pnx8xxx_port *sport =
|
||||
container_of(port, struct pnx8xxx_port, port);
|
||||
int status;
|
||||
|
||||
do {
|
||||
|
|
|
@ -223,6 +223,7 @@ static void serial_pxa_start_tx(struct uart_port *port)
|
|||
}
|
||||
}
|
||||
|
||||
/* should hold up->port.lock */
|
||||
static inline void check_modem_status(struct uart_pxa_port *up)
|
||||
{
|
||||
int status;
|
||||
|
@ -255,12 +256,14 @@ static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id)
|
|||
iir = serial_in(up, UART_IIR);
|
||||
if (iir & UART_IIR_NO_INT)
|
||||
return IRQ_NONE;
|
||||
spin_lock(&up->port.lock);
|
||||
lsr = serial_in(up, UART_LSR);
|
||||
if (lsr & UART_LSR_DR)
|
||||
receive_chars(up, &lsr);
|
||||
check_modem_status(up);
|
||||
if (lsr & UART_LSR_THRE)
|
||||
transmit_chars(up);
|
||||
spin_unlock(&up->port.lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
|
|
@ -142,7 +142,8 @@ static void sa1100_timeout(unsigned long data)
|
|||
*/
|
||||
static void sa1100_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct sa1100_port *sport = (struct sa1100_port *)port;
|
||||
struct sa1100_port *sport =
|
||||
container_of(port, struct sa1100_port, port);
|
||||
u32 utcr3;
|
||||
|
||||
utcr3 = UART_GET_UTCR3(sport);
|
||||
|
@ -155,7 +156,8 @@ static void sa1100_stop_tx(struct uart_port *port)
|
|||
*/
|
||||
static void sa1100_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct sa1100_port *sport = (struct sa1100_port *)port;
|
||||
struct sa1100_port *sport =
|
||||
container_of(port, struct sa1100_port, port);
|
||||
u32 utcr3;
|
||||
|
||||
utcr3 = UART_GET_UTCR3(sport);
|
||||
|
@ -168,7 +170,8 @@ static void sa1100_start_tx(struct uart_port *port)
|
|||
*/
|
||||
static void sa1100_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct sa1100_port *sport = (struct sa1100_port *)port;
|
||||
struct sa1100_port *sport =
|
||||
container_of(port, struct sa1100_port, port);
|
||||
u32 utcr3;
|
||||
|
||||
utcr3 = UART_GET_UTCR3(sport);
|
||||
|
@ -180,7 +183,8 @@ static void sa1100_stop_rx(struct uart_port *port)
|
|||
*/
|
||||
static void sa1100_enable_ms(struct uart_port *port)
|
||||
{
|
||||
struct sa1100_port *sport = (struct sa1100_port *)port;
|
||||
struct sa1100_port *sport =
|
||||
container_of(port, struct sa1100_port, port);
|
||||
|
||||
mod_timer(&sport->timer, jiffies);
|
||||
}
|
||||
|
@ -323,7 +327,8 @@ static irqreturn_t sa1100_int(int irq, void *dev_id)
|
|||
*/
|
||||
static unsigned int sa1100_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct sa1100_port *sport = (struct sa1100_port *)port;
|
||||
struct sa1100_port *sport =
|
||||
container_of(port, struct sa1100_port, port);
|
||||
|
||||
return UART_GET_UTSR1(sport) & UTSR1_TBY ? 0 : TIOCSER_TEMT;
|
||||
}
|
||||
|
@ -342,7 +347,8 @@ static void sa1100_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
|||
*/
|
||||
static void sa1100_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
struct sa1100_port *sport = (struct sa1100_port *)port;
|
||||
struct sa1100_port *sport =
|
||||
container_of(port, struct sa1100_port, port);
|
||||
unsigned long flags;
|
||||
unsigned int utcr3;
|
||||
|
||||
|
@ -358,7 +364,8 @@ static void sa1100_break_ctl(struct uart_port *port, int break_state)
|
|||
|
||||
static int sa1100_startup(struct uart_port *port)
|
||||
{
|
||||
struct sa1100_port *sport = (struct sa1100_port *)port;
|
||||
struct sa1100_port *sport =
|
||||
container_of(port, struct sa1100_port, port);
|
||||
int retval;
|
||||
|
||||
/*
|
||||
|
@ -387,7 +394,8 @@ static int sa1100_startup(struct uart_port *port)
|
|||
|
||||
static void sa1100_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct sa1100_port *sport = (struct sa1100_port *)port;
|
||||
struct sa1100_port *sport =
|
||||
container_of(port, struct sa1100_port, port);
|
||||
|
||||
/*
|
||||
* Stop our timer.
|
||||
|
@ -409,7 +417,8 @@ static void
|
|||
sa1100_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct sa1100_port *sport = (struct sa1100_port *)port;
|
||||
struct sa1100_port *sport =
|
||||
container_of(port, struct sa1100_port, port);
|
||||
unsigned long flags;
|
||||
unsigned int utcr0, old_utcr3, baud, quot;
|
||||
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
|
||||
|
@ -512,7 +521,8 @@ sa1100_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
|
||||
static const char *sa1100_type(struct uart_port *port)
|
||||
{
|
||||
struct sa1100_port *sport = (struct sa1100_port *)port;
|
||||
struct sa1100_port *sport =
|
||||
container_of(port, struct sa1100_port, port);
|
||||
|
||||
return sport->port.type == PORT_SA1100 ? "SA1100" : NULL;
|
||||
}
|
||||
|
@ -522,7 +532,8 @@ static const char *sa1100_type(struct uart_port *port)
|
|||
*/
|
||||
static void sa1100_release_port(struct uart_port *port)
|
||||
{
|
||||
struct sa1100_port *sport = (struct sa1100_port *)port;
|
||||
struct sa1100_port *sport =
|
||||
container_of(port, struct sa1100_port, port);
|
||||
|
||||
release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
|
||||
}
|
||||
|
@ -532,7 +543,8 @@ static void sa1100_release_port(struct uart_port *port)
|
|||
*/
|
||||
static int sa1100_request_port(struct uart_port *port)
|
||||
{
|
||||
struct sa1100_port *sport = (struct sa1100_port *)port;
|
||||
struct sa1100_port *sport =
|
||||
container_of(port, struct sa1100_port, port);
|
||||
|
||||
return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
|
||||
"sa11x0-uart") != NULL ? 0 : -EBUSY;
|
||||
|
@ -543,7 +555,8 @@ static int sa1100_request_port(struct uart_port *port)
|
|||
*/
|
||||
static void sa1100_config_port(struct uart_port *port, int flags)
|
||||
{
|
||||
struct sa1100_port *sport = (struct sa1100_port *)port;
|
||||
struct sa1100_port *sport =
|
||||
container_of(port, struct sa1100_port, port);
|
||||
|
||||
if (flags & UART_CONFIG_TYPE &&
|
||||
sa1100_request_port(&sport->port) == 0)
|
||||
|
@ -558,7 +571,8 @@ static void sa1100_config_port(struct uart_port *port, int flags)
|
|||
static int
|
||||
sa1100_verify_port(struct uart_port *port, struct serial_struct *ser)
|
||||
{
|
||||
struct sa1100_port *sport = (struct sa1100_port *)port;
|
||||
struct sa1100_port *sport =
|
||||
container_of(port, struct sa1100_port, port);
|
||||
int ret = 0;
|
||||
|
||||
if (ser->type != PORT_UNKNOWN && ser->type != PORT_SA1100)
|
||||
|
@ -691,7 +705,8 @@ void __init sa1100_register_uart(int idx, int port)
|
|||
#ifdef CONFIG_SERIAL_SA1100_CONSOLE
|
||||
static void sa1100_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
struct sa1100_port *sport = (struct sa1100_port *)port;
|
||||
struct sa1100_port *sport =
|
||||
container_of(port, struct sa1100_port, port);
|
||||
|
||||
while (!(UART_GET_UTSR1(sport) & UTSR1_TNF))
|
||||
barrier();
|
||||
|
|
|
@ -199,12 +199,14 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port)
|
|||
}
|
||||
}
|
||||
|
||||
static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port)
|
||||
static inline struct s3c24xx_uart_info
|
||||
*s3c24xx_port_to_info(struct uart_port *port)
|
||||
{
|
||||
return to_ourport(port)->info;
|
||||
}
|
||||
|
||||
static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port)
|
||||
static inline struct s3c2410_uartcfg
|
||||
*s3c24xx_port_to_cfg(struct uart_port *port)
|
||||
{
|
||||
struct s3c24xx_uart_port *ourport;
|
||||
|
||||
|
@ -237,7 +239,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id)
|
|||
struct uart_port *port = &ourport->port;
|
||||
unsigned int ufcon, ch, flag, ufstat, uerstat;
|
||||
unsigned long flags;
|
||||
int max_count = 64;
|
||||
int max_count = port->fifosize;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
|
@ -311,14 +313,14 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id)
|
|||
uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
|
||||
ch, flag);
|
||||
|
||||
ignore_char:
|
||||
ignore_char:
|
||||
continue;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
|
||||
out:
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -328,7 +330,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
|
|||
struct uart_port *port = &ourport->port;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned long flags;
|
||||
int count = 256;
|
||||
int count = port->fifosize;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
|
@ -368,7 +370,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
|
|||
if (uart_circ_empty(xmit))
|
||||
s3c24xx_serial_stop_tx(port);
|
||||
|
||||
out:
|
||||
out:
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -519,7 +521,7 @@ static int s3c24xx_serial_startup(struct uart_port *port)
|
|||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
err:
|
||||
s3c24xx_serial_shutdown(port);
|
||||
return ret;
|
||||
}
|
||||
|
@ -559,11 +561,15 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
|
|||
unsigned int old)
|
||||
{
|
||||
struct s3c24xx_uart_port *ourport = to_ourport(port);
|
||||
int timeout = 10000;
|
||||
|
||||
ourport->pm_level = level;
|
||||
|
||||
switch (level) {
|
||||
case 3:
|
||||
while (--timeout && !s3c24xx_serial_txempty_nofifo(port))
|
||||
udelay(100);
|
||||
|
||||
if (!IS_ERR(ourport->baudclk))
|
||||
clk_disable_unprepare(ourport->baudclk);
|
||||
|
||||
|
@ -841,8 +847,8 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
|
|||
*/
|
||||
port->read_status_mask = S3C2410_UERSTAT_OVERRUN;
|
||||
if (termios->c_iflag & INPCK)
|
||||
port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY;
|
||||
|
||||
port->read_status_mask |= S3C2410_UERSTAT_FRAME |
|
||||
S3C2410_UERSTAT_PARITY;
|
||||
/*
|
||||
* Which character status flags should we ignore?
|
||||
*/
|
||||
|
@ -969,10 +975,13 @@ static struct uart_driver s3c24xx_uart_drv = {
|
|||
.minor = S3C24XX_SERIAL_MINOR,
|
||||
};
|
||||
|
||||
static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
|
||||
#define __PORT_LOCK_UNLOCKED(i) \
|
||||
__SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[i].port.lock)
|
||||
static struct s3c24xx_uart_port
|
||||
s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
|
||||
[0] = {
|
||||
.port = {
|
||||
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
|
||||
.lock = __PORT_LOCK_UNLOCKED(0),
|
||||
.iotype = UPIO_MEM,
|
||||
.uartclk = 0,
|
||||
.fifosize = 16,
|
||||
|
@ -983,7 +992,7 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
|
|||
},
|
||||
[1] = {
|
||||
.port = {
|
||||
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
|
||||
.lock = __PORT_LOCK_UNLOCKED(1),
|
||||
.iotype = UPIO_MEM,
|
||||
.uartclk = 0,
|
||||
.fifosize = 16,
|
||||
|
@ -996,7 +1005,7 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
|
|||
|
||||
[2] = {
|
||||
.port = {
|
||||
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
|
||||
.lock = __PORT_LOCK_UNLOCKED(2),
|
||||
.iotype = UPIO_MEM,
|
||||
.uartclk = 0,
|
||||
.fifosize = 16,
|
||||
|
@ -1009,7 +1018,7 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
|
|||
#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
|
||||
[3] = {
|
||||
.port = {
|
||||
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),
|
||||
.lock = __PORT_LOCK_UNLOCKED(3),
|
||||
.iotype = UPIO_MEM,
|
||||
.uartclk = 0,
|
||||
.fifosize = 16,
|
||||
|
@ -1020,6 +1029,7 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS
|
|||
}
|
||||
#endif
|
||||
};
|
||||
#undef __PORT_LOCK_UNLOCKED
|
||||
|
||||
/* s3c24xx_serial_resetport
|
||||
*
|
||||
|
@ -1102,11 +1112,12 @@ static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
|
|||
s3c24xx_serial_set_termios(uport, termios, NULL);
|
||||
}
|
||||
|
||||
exit:
|
||||
exit:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
|
||||
static inline int
|
||||
s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
|
||||
{
|
||||
port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition;
|
||||
|
||||
|
@ -1114,19 +1125,22 @@ static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port
|
|||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
}
|
||||
|
||||
static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
|
||||
static inline void
|
||||
s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
|
||||
{
|
||||
cpufreq_unregister_notifier(&port->freq_transition,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
}
|
||||
|
||||
#else
|
||||
static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
|
||||
static inline int
|
||||
s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
|
||||
static inline void
|
||||
s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
@ -1226,24 +1240,6 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SAMSUNG_CLOCK
|
||||
static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct uart_port *port = s3c24xx_dev_to_port(dev);
|
||||
struct s3c24xx_uart_port *ourport = to_ourport(port);
|
||||
|
||||
if (IS_ERR(ourport->baudclk))
|
||||
return -EINVAL;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "* %s\n",
|
||||
ourport->baudclk->name ?: "(null)");
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
|
||||
#endif
|
||||
|
||||
/* Device driver serial port probe */
|
||||
|
||||
static const struct of_device_id s3c24xx_uart_dt_match[];
|
||||
|
@ -1296,11 +1292,10 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
|
|||
of_property_read_u32(np,
|
||||
"samsung,uart-fifosize", &ourport->port.fifosize);
|
||||
|
||||
if (!ourport->port.fifosize) {
|
||||
ourport->port.fifosize = (ourport->info->fifosize) ?
|
||||
ourport->info->fifosize :
|
||||
ourport->drv_data->fifosize[index];
|
||||
}
|
||||
if (ourport->drv_data->fifosize[index])
|
||||
ourport->port.fifosize = ourport->drv_data->fifosize[index];
|
||||
else if (ourport->info->fifosize)
|
||||
ourport->port.fifosize = ourport->info->fifosize;
|
||||
|
||||
probe_index++;
|
||||
|
||||
|
@ -1329,12 +1324,6 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
|
|||
*/
|
||||
clk_disable_unprepare(ourport->clk);
|
||||
|
||||
#ifdef CONFIG_SAMSUNG_CLOCK
|
||||
ret = device_create_file(&pdev->dev, &dev_attr_clock_source);
|
||||
if (ret < 0)
|
||||
dev_err(&pdev->dev, "failed to add clock source attr.\n");
|
||||
#endif
|
||||
|
||||
ret = s3c24xx_serial_cpufreq_register(ourport);
|
||||
if (ret < 0)
|
||||
dev_err(&pdev->dev, "failed to add cpufreq notifier\n");
|
||||
|
@ -1348,9 +1337,6 @@ static int s3c24xx_serial_remove(struct platform_device *dev)
|
|||
|
||||
if (port) {
|
||||
s3c24xx_serial_cpufreq_deregister(to_ourport(port));
|
||||
#ifdef CONFIG_SAMSUNG_CLOCK
|
||||
device_remove_file(&dev->dev, &dev_attr_clock_source);
|
||||
#endif
|
||||
uart_remove_one_port(&s3c24xx_uart_drv, port);
|
||||
}
|
||||
|
||||
|
|
|
@ -304,8 +304,6 @@ struct sc16is7xx_one {
|
|||
struct uart_port port;
|
||||
struct work_struct tx_work;
|
||||
struct work_struct md_work;
|
||||
|
||||
struct serial_rs485 rs485;
|
||||
};
|
||||
|
||||
struct sc16is7xx_port {
|
||||
|
@ -657,15 +655,15 @@ static void sc16is7xx_stop_tx(struct uart_port* port)
|
|||
struct circ_buf *xmit = &one->port.state->xmit;
|
||||
|
||||
/* handle rs485 */
|
||||
if (one->rs485.flags & SER_RS485_ENABLED) {
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
/* do nothing if current tx not yet completed */
|
||||
int lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG);
|
||||
if (!(lsr & SC16IS7XX_LSR_TEMT_BIT))
|
||||
return;
|
||||
|
||||
if (uart_circ_empty(xmit) &&
|
||||
(one->rs485.delay_rts_after_send > 0))
|
||||
mdelay(one->rs485.delay_rts_after_send);
|
||||
(port->rs485.delay_rts_after_send > 0))
|
||||
mdelay(port->rs485.delay_rts_after_send);
|
||||
}
|
||||
|
||||
sc16is7xx_port_update(port, SC16IS7XX_IER_REG,
|
||||
|
@ -688,9 +686,9 @@ static void sc16is7xx_start_tx(struct uart_port *port)
|
|||
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
|
||||
|
||||
/* handle rs485 */
|
||||
if ((one->rs485.flags & SER_RS485_ENABLED) &&
|
||||
(one->rs485.delay_rts_before_send > 0)) {
|
||||
mdelay(one->rs485.delay_rts_before_send);
|
||||
if ((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
(port->rs485.delay_rts_before_send > 0)) {
|
||||
mdelay(port->rs485.delay_rts_before_send);
|
||||
}
|
||||
|
||||
if (!work_pending(&one->tx_work))
|
||||
|
@ -830,51 +828,20 @@ static void sc16is7xx_set_termios(struct uart_port *port,
|
|||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
}
|
||||
|
||||
#if defined(TIOCSRS485) && defined(TIOCGRS485)
|
||||
static void sc16is7xx_config_rs485(struct uart_port *port,
|
||||
static int sc16is7xx_config_rs485(struct uart_port *port,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
|
||||
|
||||
one->rs485 = *rs485;
|
||||
|
||||
if (one->rs485.flags & SER_RS485_ENABLED) {
|
||||
if (port->rs485.flags & SER_RS485_ENABLED)
|
||||
sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG,
|
||||
SC16IS7XX_EFCR_AUTO_RS485_BIT,
|
||||
SC16IS7XX_EFCR_AUTO_RS485_BIT);
|
||||
} else {
|
||||
else
|
||||
sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG,
|
||||
SC16IS7XX_EFCR_AUTO_RS485_BIT,
|
||||
0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
port->rs485 = *rs485;
|
||||
|
||||
static int sc16is7xx_ioctl(struct uart_port *port, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
#if defined(TIOCSRS485) && defined(TIOCGRS485)
|
||||
struct serial_rs485 rs485;
|
||||
|
||||
switch (cmd) {
|
||||
case TIOCSRS485:
|
||||
if (copy_from_user(&rs485, (void __user *)arg, sizeof(rs485)))
|
||||
return -EFAULT;
|
||||
|
||||
sc16is7xx_config_rs485(port, &rs485);
|
||||
return 0;
|
||||
case TIOCGRS485:
|
||||
if (copy_to_user((void __user *)arg,
|
||||
&(to_sc16is7xx_one(port, port)->rs485),
|
||||
sizeof(rs485)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return -ENOIOCTLCMD;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sc16is7xx_startup(struct uart_port *port)
|
||||
|
@ -1000,7 +967,6 @@ static const struct uart_ops sc16is7xx_ops = {
|
|||
.release_port = sc16is7xx_null_void,
|
||||
.config_port = sc16is7xx_config_port,
|
||||
.verify_port = sc16is7xx_verify_port,
|
||||
.ioctl = sc16is7xx_ioctl,
|
||||
.pm = sc16is7xx_pm,
|
||||
};
|
||||
|
||||
|
@ -1130,6 +1096,7 @@ static int sc16is7xx_probe(struct device *dev,
|
|||
s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
|
||||
s->p[i].port.iotype = UPIO_PORT;
|
||||
s->p[i].port.uartclk = freq;
|
||||
s->p[i].port.rs485_config = sc16is7xx_config_rs485;
|
||||
s->p[i].port.ops = &sc16is7xx_ops;
|
||||
/* Disable all interrupts */
|
||||
sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_IER_REG, 0);
|
||||
|
|
|
@ -319,16 +319,16 @@ static char tegra_uart_decode_rx_error(struct tegra_uart_port *tup,
|
|||
if (unlikely(lsr & TEGRA_UART_LSR_ANY)) {
|
||||
if (lsr & UART_LSR_OE) {
|
||||
/* Overrrun error */
|
||||
flag |= TTY_OVERRUN;
|
||||
flag = TTY_OVERRUN;
|
||||
tup->uport.icount.overrun++;
|
||||
dev_err(tup->uport.dev, "Got overrun errors\n");
|
||||
} else if (lsr & UART_LSR_PE) {
|
||||
/* Parity error */
|
||||
flag |= TTY_PARITY;
|
||||
flag = TTY_PARITY;
|
||||
tup->uport.icount.parity++;
|
||||
dev_err(tup->uport.dev, "Got Parity errors\n");
|
||||
} else if (lsr & UART_LSR_FE) {
|
||||
flag |= TTY_FRAME;
|
||||
flag = TTY_FRAME;
|
||||
tup->uport.icount.frame++;
|
||||
dev_err(tup->uport.dev, "Got frame errors\n");
|
||||
} else if (lsr & UART_LSR_BI) {
|
||||
|
@ -1034,6 +1034,20 @@ fail_rx_dma:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush any TX data submitted for DMA and PIO. Called when the
|
||||
* TX circular buffer is reset.
|
||||
*/
|
||||
static void tegra_uart_flush_buffer(struct uart_port *u)
|
||||
{
|
||||
struct tegra_uart_port *tup = to_tegra_uport(u);
|
||||
|
||||
tup->tx_bytes = 0;
|
||||
if (tup->tx_dma_chan)
|
||||
dmaengine_terminate_all(tup->tx_dma_chan);
|
||||
return;
|
||||
}
|
||||
|
||||
static void tegra_uart_shutdown(struct uart_port *u)
|
||||
{
|
||||
struct tegra_uart_port *tup = to_tegra_uport(u);
|
||||
|
@ -1046,6 +1060,8 @@ static void tegra_uart_shutdown(struct uart_port *u)
|
|||
tegra_uart_dma_channel_free(tup, true);
|
||||
tegra_uart_dma_channel_free(tup, false);
|
||||
free_irq(u->irq, tup);
|
||||
|
||||
tegra_uart_flush_buffer(u);
|
||||
}
|
||||
|
||||
static void tegra_uart_enable_ms(struct uart_port *u)
|
||||
|
@ -1174,20 +1190,6 @@ static void tegra_uart_set_termios(struct uart_port *u,
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush any TX data submitted for DMA and PIO. Called when the
|
||||
* TX circular buffer is reset.
|
||||
*/
|
||||
static void tegra_uart_flush_buffer(struct uart_port *u)
|
||||
{
|
||||
struct tegra_uart_port *tup = to_tegra_uport(u);
|
||||
|
||||
tup->tx_bytes = 0;
|
||||
if (tup->tx_dma_chan)
|
||||
dmaengine_terminate_all(tup->tx_dma_chan);
|
||||
return;
|
||||
}
|
||||
|
||||
static const char *tegra_uart_type(struct uart_port *u)
|
||||
{
|
||||
return TEGRA_UART_TYPE;
|
||||
|
|
|
@ -61,7 +61,7 @@ static void uart_port_shutdown(struct tty_port *port);
|
|||
|
||||
static int uart_dcd_enabled(struct uart_port *uport)
|
||||
{
|
||||
return uport->status & UPSTAT_DCD_ENABLE;
|
||||
return !!(uport->status & UPSTAT_DCD_ENABLE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -436,7 +436,7 @@ uart_get_divisor(struct uart_port *port, unsigned int baud)
|
|||
|
||||
EXPORT_SYMBOL(uart_get_divisor);
|
||||
|
||||
/* FIXME: Consistent locking policy */
|
||||
/* Caller holds port mutex */
|
||||
static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
|
||||
struct ktermios *old_termios)
|
||||
{
|
||||
|
@ -537,9 +537,10 @@ static int uart_write(struct tty_struct *tty,
|
|||
count -= c;
|
||||
ret += c;
|
||||
}
|
||||
|
||||
__uart_start(tty);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
uart_start(tty);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -618,7 +619,7 @@ static void uart_throttle(struct tty_struct *tty)
|
|||
{
|
||||
struct uart_state *state = tty->driver_data;
|
||||
struct uart_port *port = state->uart_port;
|
||||
uint32_t mask = 0;
|
||||
upf_t mask = 0;
|
||||
|
||||
if (I_IXOFF(tty))
|
||||
mask |= UPF_SOFT_FLOW;
|
||||
|
@ -641,7 +642,7 @@ static void uart_unthrottle(struct tty_struct *tty)
|
|||
{
|
||||
struct uart_state *state = tty->driver_data;
|
||||
struct uart_port *port = state->uart_port;
|
||||
uint32_t mask = 0;
|
||||
upf_t mask = 0;
|
||||
|
||||
if (I_IXOFF(tty))
|
||||
mask |= UPF_SOFT_FLOW;
|
||||
|
@ -1151,6 +1152,47 @@ static int uart_get_icount(struct tty_struct *tty,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int uart_get_rs485_config(struct uart_port *port,
|
||||
struct serial_rs485 __user *rs485)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct serial_rs485 aux;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
aux = port->rs485;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
if (copy_to_user(rs485, &aux, sizeof(aux)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uart_set_rs485_config(struct uart_port *port,
|
||||
struct serial_rs485 __user *rs485_user)
|
||||
{
|
||||
struct serial_rs485 rs485;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
if (!port->rs485_config)
|
||||
return -ENOIOCTLCMD;
|
||||
|
||||
if (copy_from_user(&rs485, rs485_user, sizeof(*rs485_user)))
|
||||
return -EFAULT;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
ret = port->rs485_config(port, &rs485);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (copy_to_user(rs485_user, &port->rs485, sizeof(port->rs485)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called via sys_ioctl. We can use spin_lock_irq() here.
|
||||
*/
|
||||
|
@ -1173,11 +1215,15 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd,
|
|||
break;
|
||||
|
||||
case TIOCSSERIAL:
|
||||
down_write(&tty->termios_rwsem);
|
||||
ret = uart_set_info_user(tty, state, uarg);
|
||||
up_write(&tty->termios_rwsem);
|
||||
break;
|
||||
|
||||
case TIOCSERCONFIG:
|
||||
down_write(&tty->termios_rwsem);
|
||||
ret = uart_do_autoconfig(tty, state);
|
||||
up_write(&tty->termios_rwsem);
|
||||
break;
|
||||
|
||||
case TIOCSERGWILD: /* obsolete */
|
||||
|
@ -1217,11 +1263,19 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd,
|
|||
* All these rely on hardware being present and need to be
|
||||
* protected against the tty being hung up.
|
||||
*/
|
||||
|
||||
switch (cmd) {
|
||||
case TIOCSERGETLSR: /* Get line status register */
|
||||
ret = uart_get_lsr_info(tty, state, uarg);
|
||||
break;
|
||||
|
||||
case TIOCGRS485:
|
||||
ret = uart_get_rs485_config(state->uart_port, uarg);
|
||||
break;
|
||||
|
||||
case TIOCSRS485:
|
||||
ret = uart_set_rs485_config(state->uart_port, uarg);
|
||||
break;
|
||||
default: {
|
||||
struct uart_port *uport = state->uart_port;
|
||||
if (uport->ops->ioctl)
|
||||
|
@ -1240,8 +1294,11 @@ static void uart_set_ldisc(struct tty_struct *tty)
|
|||
struct uart_state *state = tty->driver_data;
|
||||
struct uart_port *uport = state->uart_port;
|
||||
|
||||
if (uport->ops->set_ldisc)
|
||||
uport->ops->set_ldisc(uport, tty->termios.c_line);
|
||||
if (uport->ops->set_ldisc) {
|
||||
mutex_lock(&state->port.mutex);
|
||||
uport->ops->set_ldisc(uport, &tty->termios);
|
||||
mutex_unlock(&state->port.mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static void uart_set_termios(struct tty_struct *tty,
|
||||
|
@ -1278,7 +1335,9 @@ static void uart_set_termios(struct tty_struct *tty,
|
|||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&state->port.mutex);
|
||||
uart_change_speed(tty, state, old_termios);
|
||||
mutex_unlock(&state->port.mutex);
|
||||
/* reload cflag from termios; port driver may have overriden flags */
|
||||
cflag = tty->termios.c_cflag;
|
||||
|
||||
|
@ -1331,8 +1390,16 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
|
|||
struct uart_port *uport;
|
||||
unsigned long flags;
|
||||
|
||||
if (!state)
|
||||
if (!state) {
|
||||
struct uart_driver *drv = tty->driver->driver_state;
|
||||
|
||||
state = drv->state + tty->index;
|
||||
port = &state->port;
|
||||
spin_lock_irq(&port->lock);
|
||||
--port->count;
|
||||
spin_unlock_irq(&port->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
uport = state->uart_port;
|
||||
port = &state->port;
|
||||
|
@ -1361,10 +1428,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
|
|||
|
||||
mutex_lock(&port->mutex);
|
||||
uart_shutdown(tty, state);
|
||||
uart_flush_buffer(tty);
|
||||
|
||||
tty_ldisc_flush(tty);
|
||||
|
||||
tty_port_tty_set(port, NULL);
|
||||
tty->closing = 0;
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
@ -1372,8 +1435,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
|
|||
if (port->blocked_open) {
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
if (port->close_delay)
|
||||
msleep_interruptible(
|
||||
jiffies_to_msecs(port->close_delay));
|
||||
msleep_interruptible(jiffies_to_msecs(port->close_delay));
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
} else if (!uart_console(uport)) {
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
@ -1391,6 +1453,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
|
|||
wake_up_interruptible(&port->close_wait);
|
||||
|
||||
mutex_unlock(&port->mutex);
|
||||
|
||||
tty_ldisc_flush(tty);
|
||||
}
|
||||
|
||||
static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
|
||||
|
@ -1552,6 +1616,10 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
|
|||
|
||||
pr_debug("uart_open(%d) called\n", line);
|
||||
|
||||
spin_lock_irq(&port->lock);
|
||||
++port->count;
|
||||
spin_unlock_irq(&port->lock);
|
||||
|
||||
/*
|
||||
* We take the semaphore here to guarantee that we won't be re-entered
|
||||
* while allocating the state structure, or while we request any IRQs
|
||||
|
@ -1564,17 +1632,11 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
|
|||
goto end;
|
||||
}
|
||||
|
||||
port->count++;
|
||||
if (!state->uart_port || state->uart_port->flags & UPF_DEAD) {
|
||||
retval = -ENXIO;
|
||||
goto err_dec_count;
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Once we set tty->driver_data here, we are guaranteed that
|
||||
* uart_close() will decrement the driver module use count.
|
||||
* Any failures from here onwards should not touch the count.
|
||||
*/
|
||||
tty->driver_data = state;
|
||||
state->uart_port->state = state;
|
||||
state->port.low_latency =
|
||||
|
@ -1595,8 +1657,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
|
|||
|
||||
end:
|
||||
return retval;
|
||||
err_dec_count:
|
||||
port->count--;
|
||||
err_unlock:
|
||||
mutex_unlock(&port->mutex);
|
||||
goto end;
|
||||
}
|
||||
|
@ -2092,6 +2153,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
|
|||
break;
|
||||
case UPIO_MEM:
|
||||
case UPIO_MEM32:
|
||||
case UPIO_MEM32BE:
|
||||
case UPIO_AU:
|
||||
case UPIO_TSI:
|
||||
snprintf(address, sizeof(address),
|
||||
|
@ -2339,8 +2401,6 @@ int uart_register_driver(struct uart_driver *drv)
|
|||
|
||||
tty_port_init(port);
|
||||
port->ops = &uart_port_ops;
|
||||
port->close_delay = HZ / 2; /* .5 seconds */
|
||||
port->closing_wait = 30 * HZ;/* 30 seconds */
|
||||
}
|
||||
|
||||
retval = tty_register_driver(normal);
|
||||
|
@ -2589,12 +2649,13 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* Link the port to the driver state table and vice versa */
|
||||
state->uart_port = uport;
|
||||
state->pm_state = UART_PM_STATE_UNDEFINED;
|
||||
|
||||
uport->cons = drv->cons;
|
||||
uport->state = state;
|
||||
|
||||
state->pm_state = UART_PM_STATE_UNDEFINED;
|
||||
uport->cons = drv->cons;
|
||||
|
||||
/*
|
||||
* If this port is a console, then the spinlock is already
|
||||
* initialised.
|
||||
|
@ -2736,6 +2797,7 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2)
|
|||
(port1->hub6 == port2->hub6);
|
||||
case UPIO_MEM:
|
||||
case UPIO_MEM32:
|
||||
case UPIO_MEM32BE:
|
||||
case UPIO_AU:
|
||||
case UPIO_TSI:
|
||||
return (port1->mapbase == port2->mapbase);
|
||||
|
|
|
@ -1812,9 +1812,6 @@ static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq,
|
|||
err = DIV_ROUND_CLOSEST(freq, ((br + 1) * bps * sr *
|
||||
(1 << (2 * c + 1)) / 1000)) -
|
||||
1000;
|
||||
if (err < 0)
|
||||
continue;
|
||||
|
||||
/* Calc recv margin
|
||||
* M: Receive margin (%)
|
||||
* N: Ratio of bit rate to clock (N = sampling rate)
|
||||
|
@ -1829,7 +1826,7 @@ static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq,
|
|||
*/
|
||||
recv_margin = abs((500 -
|
||||
DIV_ROUND_CLOSEST(1000, sr << 1)) / 10);
|
||||
if (min_err > err) {
|
||||
if (abs(min_err) > abs(err)) {
|
||||
min_err = err;
|
||||
recv_max_margin = recv_margin;
|
||||
} else if ((min_err == err) &&
|
||||
|
|
|
@ -1032,10 +1032,19 @@ static void sirfsoc_uart_pm(struct uart_port *port, unsigned int state,
|
|||
unsigned int oldstate)
|
||||
{
|
||||
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
|
||||
if (!state)
|
||||
if (!state) {
|
||||
if (sirfport->is_bt_uart) {
|
||||
clk_prepare_enable(sirfport->clk_noc);
|
||||
clk_prepare_enable(sirfport->clk_general);
|
||||
}
|
||||
clk_prepare_enable(sirfport->clk);
|
||||
else
|
||||
} else {
|
||||
clk_disable_unprepare(sirfport->clk);
|
||||
if (sirfport->is_bt_uart) {
|
||||
clk_disable_unprepare(sirfport->clk_general);
|
||||
clk_disable_unprepare(sirfport->clk_noc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int sirfsoc_uart_startup(struct uart_port *port)
|
||||
|
@ -1378,12 +1387,26 @@ usp_no_flow_control:
|
|||
}
|
||||
port->irq = res->start;
|
||||
|
||||
sirfport->clk = clk_get(&pdev->dev, NULL);
|
||||
sirfport->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(sirfport->clk)) {
|
||||
ret = PTR_ERR(sirfport->clk);
|
||||
goto err;
|
||||
}
|
||||
port->uartclk = clk_get_rate(sirfport->clk);
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "sirf,marco-bt-uart")) {
|
||||
sirfport->clk_general = devm_clk_get(&pdev->dev, "general");
|
||||
if (IS_ERR(sirfport->clk_general)) {
|
||||
ret = PTR_ERR(sirfport->clk_general);
|
||||
goto err;
|
||||
}
|
||||
sirfport->clk_noc = devm_clk_get(&pdev->dev, "noc");
|
||||
if (IS_ERR(sirfport->clk_noc)) {
|
||||
ret = PTR_ERR(sirfport->clk_noc);
|
||||
goto err;
|
||||
}
|
||||
sirfport->is_bt_uart = true;
|
||||
} else
|
||||
sirfport->is_bt_uart = false;
|
||||
|
||||
port->ops = &sirfsoc_uart_ops;
|
||||
spin_lock_init(&port->lock);
|
||||
|
@ -1392,7 +1415,7 @@ usp_no_flow_control:
|
|||
ret = uart_add_one_port(&sirfsoc_uart_drv, port);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Cannot add UART port(%d).\n", pdev->id);
|
||||
goto port_err;
|
||||
goto err;
|
||||
}
|
||||
|
||||
sirfport->rx_dma_chan = dma_request_slave_channel(port->dev, "rx");
|
||||
|
@ -1421,8 +1444,6 @@ alloc_coherent_err:
|
|||
sirfport->rx_dma_items[j].xmit.buf,
|
||||
sirfport->rx_dma_items[j].dma_addr);
|
||||
dma_release_channel(sirfport->rx_dma_chan);
|
||||
port_err:
|
||||
clk_put(sirfport->clk);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
@ -1431,7 +1452,6 @@ static int sirfsoc_uart_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
|
||||
struct uart_port *port = &sirfport->port;
|
||||
clk_put(sirfport->clk);
|
||||
uart_remove_one_port(&sirfsoc_uart_drv, port);
|
||||
if (sirfport->rx_dma_chan) {
|
||||
int i;
|
||||
|
|
|
@ -417,6 +417,10 @@ struct sirfsoc_uart_port {
|
|||
|
||||
struct uart_port port;
|
||||
struct clk *clk;
|
||||
/* UART6 for BT usage in A7DA platform need multi-clock source */
|
||||
bool is_bt_uart;
|
||||
struct clk *clk_general;
|
||||
struct clk *clk_noc;
|
||||
/* for SiRFmarco, there are SET/CLR for UART_INT_EN */
|
||||
bool is_marco;
|
||||
struct sirfsoc_uart_register *uart_reg;
|
||||
|
|
|
@ -345,7 +345,8 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id)
|
|||
/* port->lock is not held. */
|
||||
static unsigned int sunsab_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
|
||||
struct uart_sunsab_port *up =
|
||||
container_of(port, struct uart_sunsab_port, port);
|
||||
int ret;
|
||||
|
||||
/* Do not need a lock for a state test like this. */
|
||||
|
@ -360,7 +361,8 @@ static unsigned int sunsab_tx_empty(struct uart_port *port)
|
|||
/* port->lock held by caller. */
|
||||
static void sunsab_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
|
||||
struct uart_sunsab_port *up =
|
||||
container_of(port, struct uart_sunsab_port, port);
|
||||
|
||||
if (mctrl & TIOCM_RTS) {
|
||||
up->cached_mode &= ~SAB82532_MODE_FRTS;
|
||||
|
@ -383,7 +385,8 @@ static void sunsab_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
|||
/* port->lock is held by caller and interrupts are disabled. */
|
||||
static unsigned int sunsab_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
|
||||
struct uart_sunsab_port *up =
|
||||
container_of(port, struct uart_sunsab_port, port);
|
||||
unsigned char val;
|
||||
unsigned int result;
|
||||
|
||||
|
@ -404,7 +407,8 @@ static unsigned int sunsab_get_mctrl(struct uart_port *port)
|
|||
/* port->lock held by caller. */
|
||||
static void sunsab_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
|
||||
struct uart_sunsab_port *up =
|
||||
container_of(port, struct uart_sunsab_port, port);
|
||||
|
||||
up->interrupt_mask1 |= SAB82532_IMR1_XPR;
|
||||
writeb(up->interrupt_mask1, &up->regs->w.imr1);
|
||||
|
@ -432,7 +436,8 @@ static void sunsab_tx_idle(struct uart_sunsab_port *up)
|
|||
/* port->lock held by caller. */
|
||||
static void sunsab_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
|
||||
struct uart_sunsab_port *up =
|
||||
container_of(port, struct uart_sunsab_port, port);
|
||||
struct circ_buf *xmit = &up->port.state->xmit;
|
||||
int i;
|
||||
|
||||
|
@ -465,7 +470,8 @@ static void sunsab_start_tx(struct uart_port *port)
|
|||
/* port->lock is not held. */
|
||||
static void sunsab_send_xchar(struct uart_port *port, char ch)
|
||||
{
|
||||
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
|
||||
struct uart_sunsab_port *up =
|
||||
container_of(port, struct uart_sunsab_port, port);
|
||||
unsigned long flags;
|
||||
|
||||
if (ch == __DISABLED_CHAR)
|
||||
|
@ -482,7 +488,8 @@ static void sunsab_send_xchar(struct uart_port *port, char ch)
|
|||
/* port->lock held by caller. */
|
||||
static void sunsab_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
|
||||
struct uart_sunsab_port *up =
|
||||
container_of(port, struct uart_sunsab_port, port);
|
||||
|
||||
up->interrupt_mask0 |= SAB82532_IMR0_TCD;
|
||||
writeb(up->interrupt_mask1, &up->regs->w.imr0);
|
||||
|
@ -491,7 +498,8 @@ static void sunsab_stop_rx(struct uart_port *port)
|
|||
/* port->lock is not held. */
|
||||
static void sunsab_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
|
||||
struct uart_sunsab_port *up =
|
||||
container_of(port, struct uart_sunsab_port, port);
|
||||
unsigned long flags;
|
||||
unsigned char val;
|
||||
|
||||
|
@ -514,7 +522,8 @@ static void sunsab_break_ctl(struct uart_port *port, int break_state)
|
|||
/* port->lock is not held. */
|
||||
static int sunsab_startup(struct uart_port *port)
|
||||
{
|
||||
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
|
||||
struct uart_sunsab_port *up =
|
||||
container_of(port, struct uart_sunsab_port, port);
|
||||
unsigned long flags;
|
||||
unsigned char tmp;
|
||||
int err = request_irq(up->port.irq, sunsab_interrupt,
|
||||
|
@ -585,7 +594,8 @@ static int sunsab_startup(struct uart_port *port)
|
|||
/* port->lock is not held. */
|
||||
static void sunsab_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
|
||||
struct uart_sunsab_port *up =
|
||||
container_of(port, struct uart_sunsab_port, port);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
|
@ -771,7 +781,8 @@ static void sunsab_convert_to_sab(struct uart_sunsab_port *up, unsigned int cfla
|
|||
static void sunsab_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
|
||||
struct uart_sunsab_port *up =
|
||||
container_of(port, struct uart_sunsab_port, port);
|
||||
unsigned long flags;
|
||||
unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
|
||||
unsigned int quot = uart_get_divisor(port, baud);
|
||||
|
@ -840,7 +851,8 @@ static struct uart_sunsab_port *sunsab_ports;
|
|||
|
||||
static void sunsab_console_putchar(struct uart_port *port, int c)
|
||||
{
|
||||
struct uart_sunsab_port *up = (struct uart_sunsab_port *)port;
|
||||
struct uart_sunsab_port *up =
|
||||
container_of(port, struct uart_sunsab_port, port);
|
||||
|
||||
sunsab_tec_wait(up);
|
||||
writeb(c, &up->regs->w.tic);
|
||||
|
|
|
@ -264,7 +264,8 @@ static inline void __stop_tx(struct uart_sunsu_port *p)
|
|||
|
||||
static void sunsu_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
|
||||
struct uart_sunsu_port *up =
|
||||
container_of(port, struct uart_sunsu_port, port);
|
||||
|
||||
__stop_tx(up);
|
||||
|
||||
|
@ -279,7 +280,8 @@ static void sunsu_stop_tx(struct uart_port *port)
|
|||
|
||||
static void sunsu_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
|
||||
struct uart_sunsu_port *up =
|
||||
container_of(port, struct uart_sunsu_port, port);
|
||||
|
||||
if (!(up->ier & UART_IER_THRI)) {
|
||||
up->ier |= UART_IER_THRI;
|
||||
|
@ -297,7 +299,8 @@ static void sunsu_start_tx(struct uart_port *port)
|
|||
|
||||
static void sunsu_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
|
||||
struct uart_sunsu_port *up =
|
||||
container_of(port, struct uart_sunsu_port, port);
|
||||
|
||||
up->ier &= ~UART_IER_RLSI;
|
||||
up->port.read_status_mask &= ~UART_LSR_DR;
|
||||
|
@ -306,7 +309,8 @@ static void sunsu_stop_rx(struct uart_port *port)
|
|||
|
||||
static void sunsu_enable_ms(struct uart_port *port)
|
||||
{
|
||||
struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
|
||||
struct uart_sunsu_port *up =
|
||||
container_of(port, struct uart_sunsu_port, port);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
|
@ -543,7 +547,8 @@ static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id)
|
|||
|
||||
static unsigned int sunsu_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
|
||||
struct uart_sunsu_port *up =
|
||||
container_of(port, struct uart_sunsu_port, port);
|
||||
unsigned long flags;
|
||||
unsigned int ret;
|
||||
|
||||
|
@ -556,7 +561,8 @@ static unsigned int sunsu_tx_empty(struct uart_port *port)
|
|||
|
||||
static unsigned int sunsu_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
|
||||
struct uart_sunsu_port *up =
|
||||
container_of(port, struct uart_sunsu_port, port);
|
||||
unsigned char status;
|
||||
unsigned int ret;
|
||||
|
||||
|
@ -576,7 +582,8 @@ static unsigned int sunsu_get_mctrl(struct uart_port *port)
|
|||
|
||||
static void sunsu_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
|
||||
struct uart_sunsu_port *up =
|
||||
container_of(port, struct uart_sunsu_port, port);
|
||||
unsigned char mcr = 0;
|
||||
|
||||
if (mctrl & TIOCM_RTS)
|
||||
|
@ -595,7 +602,8 @@ static void sunsu_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
|||
|
||||
static void sunsu_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
|
||||
struct uart_sunsu_port *up =
|
||||
container_of(port, struct uart_sunsu_port, port);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
|
@ -609,7 +617,8 @@ static void sunsu_break_ctl(struct uart_port *port, int break_state)
|
|||
|
||||
static int sunsu_startup(struct uart_port *port)
|
||||
{
|
||||
struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
|
||||
struct uart_sunsu_port *up =
|
||||
container_of(port, struct uart_sunsu_port, port);
|
||||
unsigned long flags;
|
||||
int retval;
|
||||
|
||||
|
@ -719,7 +728,8 @@ static int sunsu_startup(struct uart_port *port)
|
|||
|
||||
static void sunsu_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
|
||||
struct uart_sunsu_port *up =
|
||||
container_of(port, struct uart_sunsu_port, port);
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
|
@ -767,7 +777,8 @@ static void
|
|||
sunsu_change_speed(struct uart_port *port, unsigned int cflag,
|
||||
unsigned int iflag, unsigned int quot)
|
||||
{
|
||||
struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
|
||||
struct uart_sunsu_port *up =
|
||||
container_of(port, struct uart_sunsu_port, port);
|
||||
unsigned char cval, fcr = 0;
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -918,7 +929,8 @@ static int sunsu_request_port(struct uart_port *port)
|
|||
|
||||
static void sunsu_config_port(struct uart_port *port, int flags)
|
||||
{
|
||||
struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
|
||||
struct uart_sunsu_port *up =
|
||||
container_of(port, struct uart_sunsu_port, port);
|
||||
|
||||
if (flags & UART_CONFIG_TYPE) {
|
||||
/*
|
||||
|
@ -1277,7 +1289,8 @@ static __inline__ void wait_for_xmitr(struct uart_sunsu_port *up)
|
|||
|
||||
static void sunsu_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
struct uart_sunsu_port *up = (struct uart_sunsu_port *)port;
|
||||
struct uart_sunsu_port *up =
|
||||
container_of(port, struct uart_sunsu_port, port);
|
||||
|
||||
wait_for_xmitr(up);
|
||||
serial_out(up, UART_TX, ch);
|
||||
|
|
|
@ -644,7 +644,8 @@ static unsigned int sunzilog_get_mctrl(struct uart_port *port)
|
|||
/* The port lock is held and interrupts are disabled. */
|
||||
static void sunzilog_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
|
||||
struct uart_sunzilog_port *up =
|
||||
container_of(port, struct uart_sunzilog_port, port);
|
||||
struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
|
||||
unsigned char set_bits, clear_bits;
|
||||
|
||||
|
@ -668,7 +669,8 @@ static void sunzilog_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
|||
/* The port lock is held and interrupts are disabled. */
|
||||
static void sunzilog_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
|
||||
struct uart_sunzilog_port *up =
|
||||
container_of(port, struct uart_sunzilog_port, port);
|
||||
|
||||
up->flags |= SUNZILOG_FLAG_TX_STOPPED;
|
||||
}
|
||||
|
@ -676,7 +678,8 @@ static void sunzilog_stop_tx(struct uart_port *port)
|
|||
/* The port lock is held and interrupts are disabled. */
|
||||
static void sunzilog_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
|
||||
struct uart_sunzilog_port *up =
|
||||
container_of(port, struct uart_sunzilog_port, port);
|
||||
struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
|
||||
unsigned char status;
|
||||
|
||||
|
@ -736,7 +739,8 @@ static void sunzilog_stop_rx(struct uart_port *port)
|
|||
/* The port lock is held. */
|
||||
static void sunzilog_enable_ms(struct uart_port *port)
|
||||
{
|
||||
struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
|
||||
struct uart_sunzilog_port *up =
|
||||
container_of(port, struct uart_sunzilog_port, port);
|
||||
struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
|
||||
unsigned char new_reg;
|
||||
|
||||
|
@ -752,7 +756,8 @@ static void sunzilog_enable_ms(struct uart_port *port)
|
|||
/* The port lock is not held. */
|
||||
static void sunzilog_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
|
||||
struct uart_sunzilog_port *up =
|
||||
container_of(port, struct uart_sunzilog_port, port);
|
||||
struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
|
||||
unsigned char set_bits, clear_bits, new_reg;
|
||||
unsigned long flags;
|
||||
|
@ -938,7 +943,8 @@ static void
|
|||
sunzilog_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
|
||||
struct uart_sunzilog_port *up =
|
||||
container_of(port, struct uart_sunzilog_port, port);
|
||||
unsigned long flags;
|
||||
int baud, brg;
|
||||
|
||||
|
@ -998,7 +1004,8 @@ static int sunzilog_verify_port(struct uart_port *port, struct serial_struct *se
|
|||
static int sunzilog_get_poll_char(struct uart_port *port)
|
||||
{
|
||||
unsigned char ch, r1;
|
||||
struct uart_sunzilog_port *up = (struct uart_sunzilog_port *) port;
|
||||
struct uart_sunzilog_port *up =
|
||||
container_of(port, struct uart_sunzilog_port, port);
|
||||
struct zilog_channel __iomem *channel
|
||||
= ZILOG_CHANNEL_FROM_PORT(&up->port);
|
||||
|
||||
|
@ -1032,7 +1039,8 @@ static int sunzilog_get_poll_char(struct uart_port *port)
|
|||
static void sunzilog_put_poll_char(struct uart_port *port,
|
||||
unsigned char ch)
|
||||
{
|
||||
struct uart_sunzilog_port *up = (struct uart_sunzilog_port *)port;
|
||||
struct uart_sunzilog_port *up =
|
||||
container_of(port, struct uart_sunzilog_port, port);
|
||||
|
||||
sunzilog_putchar(&up->port, ch);
|
||||
}
|
||||
|
|
|
@ -273,6 +273,8 @@ static void timbuart_shutdown(struct uart_port *port)
|
|||
dev_dbg(port->dev, "%s\n", __func__);
|
||||
free_irq(port->irq, uart);
|
||||
iowrite32(0, port->membase + TIMBUART_IER);
|
||||
|
||||
timbuart_flush_buffer(port);
|
||||
}
|
||||
|
||||
static int get_bindex(int baud)
|
||||
|
|
|
@ -132,6 +132,15 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
|
|||
/* Goes in read_status_mask for break detection as the HW doesn't do it*/
|
||||
#define CDNS_UART_IXR_BRK 0x80000000
|
||||
|
||||
/*
|
||||
* Modem Control register:
|
||||
* The read/write Modem Control register controls the interface with the modem
|
||||
* or data set, or a peripheral device emulating a modem.
|
||||
*/
|
||||
#define CDNS_UART_MODEMCR_FCM 0x00000020 /* Automatic flow control mode */
|
||||
#define CDNS_UART_MODEMCR_RTS 0x00000002 /* Request to send output control */
|
||||
#define CDNS_UART_MODEMCR_DTR 0x00000001 /* Data Terminal Ready */
|
||||
|
||||
/*
|
||||
* Channel Status Register:
|
||||
* The channel status register (CSR) is provided to enable the control logic
|
||||
|
@ -915,7 +924,18 @@ static unsigned int cdns_uart_get_mctrl(struct uart_port *port)
|
|||
|
||||
static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
/* N/A */
|
||||
u32 val;
|
||||
|
||||
val = cdns_uart_readl(CDNS_UART_MODEMCR_OFFSET);
|
||||
|
||||
val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR);
|
||||
|
||||
if (mctrl & TIOCM_RTS)
|
||||
val |= CDNS_UART_MODEMCR_RTS;
|
||||
if (mctrl & TIOCM_DTR)
|
||||
val |= CDNS_UART_MODEMCR_DTR;
|
||||
|
||||
cdns_uart_writel(val, CDNS_UART_MODEMCR_OFFSET);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
|
|
|
@ -202,14 +202,16 @@ static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b)
|
|||
/**
|
||||
* tty_buffer_flush - flush full tty buffers
|
||||
* @tty: tty to flush
|
||||
* @ld: optional ldisc ptr (must be referenced)
|
||||
*
|
||||
* flush all the buffers containing receive data.
|
||||
* flush all the buffers containing receive data. If ld != NULL,
|
||||
* flush the ldisc input buffer.
|
||||
*
|
||||
* Locking: takes buffer lock to ensure single-threaded flip buffer
|
||||
* 'consumer'
|
||||
*/
|
||||
|
||||
void tty_buffer_flush(struct tty_struct *tty)
|
||||
void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld)
|
||||
{
|
||||
struct tty_port *port = tty->port;
|
||||
struct tty_bufhead *buf = &port->buf;
|
||||
|
@ -223,6 +225,10 @@ void tty_buffer_flush(struct tty_struct *tty)
|
|||
buf->head = next;
|
||||
}
|
||||
buf->head->read = buf->head->commit;
|
||||
|
||||
if (ld && ld->ops->flush_buffer)
|
||||
ld->ops->flush_buffer(tty);
|
||||
|
||||
atomic_dec(&buf->priority);
|
||||
mutex_unlock(&buf->lock);
|
||||
}
|
||||
|
|
|
@ -153,8 +153,6 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
|
|||
static int __tty_fasync(int fd, struct file *filp, int on);
|
||||
static int tty_fasync(int fd, struct file *filp, int on);
|
||||
static void release_tty(struct tty_struct *tty, int idx);
|
||||
static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
|
||||
static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
|
||||
|
||||
/**
|
||||
* free_tty_struct - free a disused tty
|
||||
|
@ -169,8 +167,7 @@ void free_tty_struct(struct tty_struct *tty)
|
|||
{
|
||||
if (!tty)
|
||||
return;
|
||||
if (tty->dev)
|
||||
put_device(tty->dev);
|
||||
put_device(tty->dev);
|
||||
kfree(tty->write_buf);
|
||||
tty->magic = 0xDEADDEAD;
|
||||
kfree(tty);
|
||||
|
@ -277,6 +274,7 @@ int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Caller must hold tty_lock */
|
||||
static int check_tty_count(struct tty_struct *tty, const char *routine)
|
||||
{
|
||||
#ifdef CHECK_TTY_COUNT
|
||||
|
@ -492,6 +490,78 @@ static const struct file_operations hung_up_tty_fops = {
|
|||
static DEFINE_SPINLOCK(redirect_lock);
|
||||
static struct file *redirect;
|
||||
|
||||
|
||||
void proc_clear_tty(struct task_struct *p)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct tty_struct *tty;
|
||||
spin_lock_irqsave(&p->sighand->siglock, flags);
|
||||
tty = p->signal->tty;
|
||||
p->signal->tty = NULL;
|
||||
spin_unlock_irqrestore(&p->sighand->siglock, flags);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
/**
|
||||
* proc_set_tty - set the controlling terminal
|
||||
*
|
||||
* Only callable by the session leader and only if it does not already have
|
||||
* a controlling terminal.
|
||||
*
|
||||
* Caller must hold: tty_lock()
|
||||
* a readlock on tasklist_lock
|
||||
* sighand lock
|
||||
*/
|
||||
static void __proc_set_tty(struct tty_struct *tty)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
/*
|
||||
* The session and fg pgrp references will be non-NULL if
|
||||
* tiocsctty() is stealing the controlling tty
|
||||
*/
|
||||
put_pid(tty->session);
|
||||
put_pid(tty->pgrp);
|
||||
tty->pgrp = get_pid(task_pgrp(current));
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
tty->session = get_pid(task_session(current));
|
||||
if (current->signal->tty) {
|
||||
printk(KERN_DEBUG "tty not NULL!!\n");
|
||||
tty_kref_put(current->signal->tty);
|
||||
}
|
||||
put_pid(current->signal->tty_old_pgrp);
|
||||
current->signal->tty = tty_kref_get(tty);
|
||||
current->signal->tty_old_pgrp = NULL;
|
||||
}
|
||||
|
||||
static void proc_set_tty(struct tty_struct *tty)
|
||||
{
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
__proc_set_tty(tty);
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
}
|
||||
|
||||
struct tty_struct *get_current_tty(void)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
||||
tty = tty_kref_get(current->signal->tty);
|
||||
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
||||
return tty;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(get_current_tty);
|
||||
|
||||
static void session_clear_tty(struct pid *session)
|
||||
{
|
||||
struct task_struct *p;
|
||||
do_each_pid_task(session, PIDTYPE_SID, p) {
|
||||
proc_clear_tty(p);
|
||||
} while_each_pid_task(session, PIDTYPE_SID, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_wakeup - request more data
|
||||
* @tty: terminal
|
||||
|
@ -620,9 +690,6 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
|
|||
return;
|
||||
}
|
||||
|
||||
/* some functions below drop BTM, so we need this bit */
|
||||
set_bit(TTY_HUPPING, &tty->flags);
|
||||
|
||||
/* inuse_filps is protected by the single tty lock,
|
||||
this really needs to change if we want to flush the
|
||||
workqueue with the lock held */
|
||||
|
@ -647,10 +714,6 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
|
|||
while (refs--)
|
||||
tty_kref_put(tty);
|
||||
|
||||
/*
|
||||
* it drops BTM and thus races with reopen
|
||||
* we protect the race by TTY_HUPPING
|
||||
*/
|
||||
tty_ldisc_hangup(tty);
|
||||
|
||||
spin_lock_irq(&tty->ctrl_lock);
|
||||
|
@ -682,8 +745,6 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
|
|||
* can't yet guarantee all that.
|
||||
*/
|
||||
set_bit(TTY_HUPPED, &tty->flags);
|
||||
clear_bit(TTY_HUPPING, &tty->flags);
|
||||
|
||||
tty_unlock(tty);
|
||||
|
||||
if (f)
|
||||
|
@ -792,14 +853,6 @@ int tty_hung_up_p(struct file *filp)
|
|||
|
||||
EXPORT_SYMBOL(tty_hung_up_p);
|
||||
|
||||
static void session_clear_tty(struct pid *session)
|
||||
{
|
||||
struct task_struct *p;
|
||||
do_each_pid_task(session, PIDTYPE_SID, p) {
|
||||
proc_clear_tty(p);
|
||||
} while_each_pid_task(session, PIDTYPE_SID, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* disassociate_ctty - disconnect controlling tty
|
||||
* @on_exit: true if exiting so need to "hang up" the session
|
||||
|
@ -927,7 +980,7 @@ void __stop_tty(struct tty_struct *tty)
|
|||
return;
|
||||
tty->stopped = 1;
|
||||
if (tty->ops->stop)
|
||||
(tty->ops->stop)(tty);
|
||||
tty->ops->stop(tty);
|
||||
}
|
||||
|
||||
void stop_tty(struct tty_struct *tty)
|
||||
|
@ -958,7 +1011,7 @@ void __start_tty(struct tty_struct *tty)
|
|||
return;
|
||||
tty->stopped = 0;
|
||||
if (tty->ops->start)
|
||||
(tty->ops->start)(tty);
|
||||
tty->ops->start(tty);
|
||||
tty_wakeup(tty);
|
||||
}
|
||||
|
||||
|
@ -1012,7 +1065,7 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
|
|||
situation */
|
||||
ld = tty_ldisc_ref_wait(tty);
|
||||
if (ld->ops->read)
|
||||
i = (ld->ops->read)(tty, file, buf, count);
|
||||
i = ld->ops->read(tty, file, buf, count);
|
||||
else
|
||||
i = -EIO;
|
||||
tty_ldisc_deref(ld);
|
||||
|
@ -1024,14 +1077,12 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
|
|||
}
|
||||
|
||||
static void tty_write_unlock(struct tty_struct *tty)
|
||||
__releases(&tty->atomic_write_lock)
|
||||
{
|
||||
mutex_unlock(&tty->atomic_write_lock);
|
||||
wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
|
||||
}
|
||||
|
||||
static int tty_write_lock(struct tty_struct *tty, int ndelay)
|
||||
__acquires(&tty->atomic_write_lock)
|
||||
{
|
||||
if (!mutex_trylock(&tty->atomic_write_lock)) {
|
||||
if (ndelay)
|
||||
|
@ -1146,7 +1197,7 @@ void tty_write_message(struct tty_struct *tty, char *msg)
|
|||
if (tty) {
|
||||
mutex_lock(&tty->atomic_write_lock);
|
||||
tty_lock(tty);
|
||||
if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
|
||||
if (tty->ops->write && tty->count > 0) {
|
||||
tty_unlock(tty);
|
||||
tty->ops->write(tty, msg, strlen(msg));
|
||||
} else
|
||||
|
@ -1293,19 +1344,24 @@ static ssize_t tty_line_name(struct tty_driver *driver, int index, char *p)
|
|||
* @driver: the driver for the tty
|
||||
* @idx: the minor number
|
||||
*
|
||||
* Return the tty, if found or ERR_PTR() otherwise.
|
||||
* Return the tty, if found. If not found, return NULL or ERR_PTR() if the
|
||||
* driver lookup() method returns an error.
|
||||
*
|
||||
* Locking: tty_mutex must be held. If tty is found, the mutex must
|
||||
* be held until the 'fast-open' is also done. Will change once we
|
||||
* have refcounting in the driver and per driver locking
|
||||
* Locking: tty_mutex must be held. If the tty is found, bump the tty kref.
|
||||
*/
|
||||
static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
|
||||
struct inode *inode, int idx)
|
||||
{
|
||||
if (driver->ops->lookup)
|
||||
return driver->ops->lookup(driver, inode, idx);
|
||||
struct tty_struct *tty;
|
||||
|
||||
return driver->ttys[idx];
|
||||
if (driver->ops->lookup)
|
||||
tty = driver->ops->lookup(driver, inode, idx);
|
||||
else
|
||||
tty = driver->ttys[idx];
|
||||
|
||||
if (!IS_ERR(tty))
|
||||
tty_kref_get(tty);
|
||||
return tty;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1393,29 +1449,21 @@ void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct *tty)
|
|||
* @tty - the tty to open
|
||||
*
|
||||
* Return 0 on success, -errno on error.
|
||||
* Re-opens on master ptys are not allowed and return -EIO.
|
||||
*
|
||||
* Locking: tty_mutex must be held from the time the tty was found
|
||||
* till this open completes.
|
||||
* Locking: Caller must hold tty_lock
|
||||
*/
|
||||
static int tty_reopen(struct tty_struct *tty)
|
||||
{
|
||||
struct tty_driver *driver = tty->driver;
|
||||
|
||||
if (test_bit(TTY_CLOSING, &tty->flags) ||
|
||||
test_bit(TTY_HUPPING, &tty->flags))
|
||||
if (!tty->count)
|
||||
return -EIO;
|
||||
|
||||
if (driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||
driver->subtype == PTY_TYPE_MASTER) {
|
||||
/*
|
||||
* special case for PTY masters: only one open permitted,
|
||||
* and the slave side open count is incremented as well.
|
||||
*/
|
||||
if (tty->count)
|
||||
return -EIO;
|
||||
driver->subtype == PTY_TYPE_MASTER)
|
||||
return -EIO;
|
||||
|
||||
tty->link->count++;
|
||||
}
|
||||
tty->count++;
|
||||
|
||||
WARN_ON(!tty->ldisc);
|
||||
|
@ -1535,15 +1583,19 @@ void tty_free_termios(struct tty_struct *tty)
|
|||
EXPORT_SYMBOL(tty_free_termios);
|
||||
|
||||
/**
|
||||
* tty_flush_works - flush all works of a tty
|
||||
* @tty: tty device to flush works for
|
||||
* tty_flush_works - flush all works of a tty/pty pair
|
||||
* @tty: tty device to flush works for (or either end of a pty pair)
|
||||
*
|
||||
* Sync flush all works belonging to @tty.
|
||||
* Sync flush all works belonging to @tty (and the 'other' tty).
|
||||
*/
|
||||
static void tty_flush_works(struct tty_struct *tty)
|
||||
{
|
||||
flush_work(&tty->SAK_work);
|
||||
flush_work(&tty->hangup_work);
|
||||
if (tty->link) {
|
||||
flush_work(&tty->link->SAK_work);
|
||||
flush_work(&tty->link->hangup_work);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1635,8 +1687,7 @@ static void release_tty(struct tty_struct *tty, int idx)
|
|||
tty->link->port->itty = NULL;
|
||||
cancel_work_sync(&tty->port->buf.work);
|
||||
|
||||
if (tty->link)
|
||||
tty_kref_put(tty->link);
|
||||
tty_kref_put(tty->link);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
|
@ -1649,8 +1700,7 @@ static void release_tty(struct tty_struct *tty, int idx)
|
|||
* Performs some paranoid checking before true release of the @tty.
|
||||
* This is a no-op unless TTY_PARANOIA_CHECK is defined.
|
||||
*/
|
||||
static int tty_release_checks(struct tty_struct *tty, struct tty_struct *o_tty,
|
||||
int idx)
|
||||
static int tty_release_checks(struct tty_struct *tty, int idx)
|
||||
{
|
||||
#ifdef TTY_PARANOIA_CHECK
|
||||
if (idx < 0 || idx >= tty->driver->num) {
|
||||
|
@ -1669,6 +1719,8 @@ static int tty_release_checks(struct tty_struct *tty, struct tty_struct *o_tty,
|
|||
return -1;
|
||||
}
|
||||
if (tty->driver->other) {
|
||||
struct tty_struct *o_tty = tty->link;
|
||||
|
||||
if (o_tty != tty->driver->other->ttys[idx]) {
|
||||
printk(KERN_DEBUG "%s: other->table[%d] not o_tty for (%s)\n",
|
||||
__func__, idx, tty->name);
|
||||
|
@ -1705,8 +1757,8 @@ static int tty_release_checks(struct tty_struct *tty, struct tty_struct *o_tty,
|
|||
int tty_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct tty_struct *tty = file_tty(filp);
|
||||
struct tty_struct *o_tty;
|
||||
int pty_master, tty_closing, o_tty_closing, do_sleep;
|
||||
struct tty_struct *o_tty = NULL;
|
||||
int do_sleep, final;
|
||||
int idx;
|
||||
char buf[64];
|
||||
long timeout = 0;
|
||||
|
@ -1721,12 +1773,11 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
__tty_fasync(-1, filp, 0);
|
||||
|
||||
idx = tty->index;
|
||||
pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||
tty->driver->subtype == PTY_TYPE_MASTER);
|
||||
/* Review: parallel close */
|
||||
o_tty = tty->link;
|
||||
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||
tty->driver->subtype == PTY_TYPE_MASTER)
|
||||
o_tty = tty->link;
|
||||
|
||||
if (tty_release_checks(tty, o_tty, idx)) {
|
||||
if (tty_release_checks(tty, idx)) {
|
||||
tty_unlock(tty);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1739,7 +1790,9 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
if (tty->ops->close)
|
||||
tty->ops->close(tty, filp);
|
||||
|
||||
tty_unlock(tty);
|
||||
/* If tty is pty master, lock the slave pty (stable lock order) */
|
||||
tty_lock_slave(o_tty);
|
||||
|
||||
/*
|
||||
* Sanity check: if tty->count is going to zero, there shouldn't be
|
||||
* any waiters on tty->read_wait or tty->write_wait. We test the
|
||||
|
@ -1750,25 +1803,13 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
* The test for the o_tty closing is necessary, since the master and
|
||||
* slave sides may close in any order. If the slave side closes out
|
||||
* first, its count will be one, since the master side holds an open.
|
||||
* Thus this test wouldn't be triggered at the time the slave closes,
|
||||
* Thus this test wouldn't be triggered at the time the slave closed,
|
||||
* so we do it now.
|
||||
*
|
||||
* Note that it's possible for the tty to be opened again while we're
|
||||
* flushing out waiters. By recalculating the closing flags before
|
||||
* each iteration we avoid any problems.
|
||||
*/
|
||||
while (1) {
|
||||
/* Guard against races with tty->count changes elsewhere and
|
||||
opens on /dev/tty */
|
||||
|
||||
mutex_lock(&tty_mutex);
|
||||
tty_lock_pair(tty, o_tty);
|
||||
tty_closing = tty->count <= 1;
|
||||
o_tty_closing = o_tty &&
|
||||
(o_tty->count <= (pty_master ? 1 : 0));
|
||||
do_sleep = 0;
|
||||
|
||||
if (tty_closing) {
|
||||
if (tty->count <= 1) {
|
||||
if (waitqueue_active(&tty->read_wait)) {
|
||||
wake_up_poll(&tty->read_wait, POLLIN);
|
||||
do_sleep++;
|
||||
|
@ -1778,7 +1819,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
do_sleep++;
|
||||
}
|
||||
}
|
||||
if (o_tty_closing) {
|
||||
if (o_tty && o_tty->count <= 1) {
|
||||
if (waitqueue_active(&o_tty->read_wait)) {
|
||||
wake_up_poll(&o_tty->read_wait, POLLIN);
|
||||
do_sleep++;
|
||||
|
@ -1796,8 +1837,6 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",
|
||||
__func__, tty_name(tty, buf));
|
||||
}
|
||||
tty_unlock_pair(tty, o_tty);
|
||||
mutex_unlock(&tty_mutex);
|
||||
schedule_timeout_killable(timeout);
|
||||
if (timeout < 120 * HZ)
|
||||
timeout = 2 * timeout + 1;
|
||||
|
@ -1805,15 +1844,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
timeout = MAX_SCHEDULE_TIMEOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* The closing flags are now consistent with the open counts on
|
||||
* both sides, and we've completed the last operation that could
|
||||
* block, so it's safe to proceed with closing.
|
||||
*
|
||||
* We must *not* drop the tty_mutex until we ensure that a further
|
||||
* entry into tty_open can not pick up this tty.
|
||||
*/
|
||||
if (pty_master) {
|
||||
if (o_tty) {
|
||||
if (--o_tty->count < 0) {
|
||||
printk(KERN_WARNING "%s: bad pty slave count (%d) for %s\n",
|
||||
__func__, o_tty->count, tty_name(o_tty, buf));
|
||||
|
@ -1840,21 +1871,11 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
/*
|
||||
* Perform some housekeeping before deciding whether to return.
|
||||
*
|
||||
* Set the TTY_CLOSING flag if this was the last open. In the
|
||||
* case of a pty we may have to wait around for the other side
|
||||
* to close, and TTY_CLOSING makes sure we can't be reopened.
|
||||
*/
|
||||
if (tty_closing)
|
||||
set_bit(TTY_CLOSING, &tty->flags);
|
||||
if (o_tty_closing)
|
||||
set_bit(TTY_CLOSING, &o_tty->flags);
|
||||
|
||||
/*
|
||||
* If _either_ side is closing, make sure there aren't any
|
||||
* processes that still think tty or o_tty is their controlling
|
||||
* tty.
|
||||
*/
|
||||
if (tty_closing || o_tty_closing) {
|
||||
if (!tty->count) {
|
||||
read_lock(&tasklist_lock);
|
||||
session_clear_tty(tty->session);
|
||||
if (o_tty)
|
||||
|
@ -1862,13 +1883,16 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
read_unlock(&tasklist_lock);
|
||||
}
|
||||
|
||||
mutex_unlock(&tty_mutex);
|
||||
tty_unlock_pair(tty, o_tty);
|
||||
/* At this point the TTY_CLOSING flag should ensure a dead tty
|
||||
/* check whether both sides are closing ... */
|
||||
final = !tty->count && !(o_tty && o_tty->count);
|
||||
|
||||
tty_unlock_slave(o_tty);
|
||||
tty_unlock(tty);
|
||||
|
||||
/* At this point, the tty->count == 0 should ensure a dead tty
|
||||
cannot be re-opened by a racing opener */
|
||||
|
||||
/* check whether both sides are closing ... */
|
||||
if (!tty_closing || (o_tty && !o_tty_closing))
|
||||
if (!final)
|
||||
return 0;
|
||||
|
||||
#ifdef TTY_DEBUG_HANGUP
|
||||
|
@ -1877,12 +1901,10 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
/*
|
||||
* Ask the line discipline code to release its structures
|
||||
*/
|
||||
tty_ldisc_release(tty, o_tty);
|
||||
tty_ldisc_release(tty);
|
||||
|
||||
/* Wait for pending work before tty destruction commmences */
|
||||
tty_flush_works(tty);
|
||||
if (o_tty)
|
||||
tty_flush_works(o_tty);
|
||||
|
||||
#ifdef TTY_DEBUG_HANGUP
|
||||
printk(KERN_DEBUG "%s: %s: freeing structure...\n", __func__, tty_name(tty, buf));
|
||||
|
@ -1901,20 +1923,20 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
}
|
||||
|
||||
/**
|
||||
* tty_open_current_tty - get tty of current task for open
|
||||
* tty_open_current_tty - get locked tty of current task
|
||||
* @device: device number
|
||||
* @filp: file pointer to tty
|
||||
* @return: tty of the current task iff @device is /dev/tty
|
||||
* @return: locked tty of the current task iff @device is /dev/tty
|
||||
*
|
||||
* Performs a re-open of the current task's controlling tty.
|
||||
*
|
||||
* We cannot return driver and index like for the other nodes because
|
||||
* devpts will not work then. It expects inodes to be from devpts FS.
|
||||
*
|
||||
* We need to move to returning a refcounted object from all the lookup
|
||||
* paths including this one.
|
||||
*/
|
||||
static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
int retval;
|
||||
|
||||
if (device != MKDEV(TTYAUX_MAJOR, 0))
|
||||
return NULL;
|
||||
|
@ -1925,9 +1947,14 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
|
|||
|
||||
filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
|
||||
/* noctty = 1; */
|
||||
tty_kref_put(tty);
|
||||
/* FIXME: we put a reference and return a TTY! */
|
||||
/* This is only safe because the caller holds tty_mutex */
|
||||
tty_lock(tty);
|
||||
tty_kref_put(tty); /* safe to drop the kref now */
|
||||
|
||||
retval = tty_reopen(tty);
|
||||
if (retval < 0) {
|
||||
tty_unlock(tty);
|
||||
tty = ERR_PTR(retval);
|
||||
}
|
||||
return tty;
|
||||
}
|
||||
|
||||
|
@ -2025,13 +2052,9 @@ retry_open:
|
|||
index = -1;
|
||||
retval = 0;
|
||||
|
||||
mutex_lock(&tty_mutex);
|
||||
/* This is protected by the tty_mutex */
|
||||
tty = tty_open_current_tty(device, filp);
|
||||
if (IS_ERR(tty)) {
|
||||
retval = PTR_ERR(tty);
|
||||
goto err_unlock;
|
||||
} else if (!tty) {
|
||||
if (!tty) {
|
||||
mutex_lock(&tty_mutex);
|
||||
driver = tty_lookup_driver(device, filp, &noctty, &index);
|
||||
if (IS_ERR(driver)) {
|
||||
retval = PTR_ERR(driver);
|
||||
|
@ -2044,21 +2067,25 @@ retry_open:
|
|||
retval = PTR_ERR(tty);
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
if (tty) {
|
||||
mutex_unlock(&tty_mutex);
|
||||
tty_lock(tty);
|
||||
/* safe to drop the kref from tty_driver_lookup_tty() */
|
||||
tty_kref_put(tty);
|
||||
retval = tty_reopen(tty);
|
||||
if (retval < 0) {
|
||||
tty_unlock(tty);
|
||||
tty = ERR_PTR(retval);
|
||||
}
|
||||
} else { /* Returns with the tty_lock held for now */
|
||||
tty = tty_init_dev(driver, index);
|
||||
mutex_unlock(&tty_mutex);
|
||||
}
|
||||
|
||||
tty_driver_kref_put(driver);
|
||||
}
|
||||
|
||||
if (tty) {
|
||||
tty_lock(tty);
|
||||
retval = tty_reopen(tty);
|
||||
if (retval < 0) {
|
||||
tty_unlock(tty);
|
||||
tty = ERR_PTR(retval);
|
||||
}
|
||||
} else /* Returns with the tty_lock held for now */
|
||||
tty = tty_init_dev(driver, index);
|
||||
|
||||
mutex_unlock(&tty_mutex);
|
||||
if (driver)
|
||||
tty_driver_kref_put(driver);
|
||||
if (IS_ERR(tty)) {
|
||||
retval = PTR_ERR(tty);
|
||||
goto err_file;
|
||||
|
@ -2100,25 +2127,23 @@ retry_open:
|
|||
/*
|
||||
* Need to reset f_op in case a hangup happened.
|
||||
*/
|
||||
if (filp->f_op == &hung_up_tty_fops)
|
||||
if (tty_hung_up_p(filp))
|
||||
filp->f_op = &tty_fops;
|
||||
goto retry_open;
|
||||
}
|
||||
clear_bit(TTY_HUPPED, &tty->flags);
|
||||
tty_unlock(tty);
|
||||
|
||||
|
||||
mutex_lock(&tty_mutex);
|
||||
tty_lock(tty);
|
||||
read_lock(&tasklist_lock);
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
if (!noctty &&
|
||||
current->signal->leader &&
|
||||
!current->signal->tty &&
|
||||
tty->session == NULL)
|
||||
__proc_set_tty(current, tty);
|
||||
__proc_set_tty(tty);
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
read_unlock(&tasklist_lock);
|
||||
tty_unlock(tty);
|
||||
mutex_unlock(&tty_mutex);
|
||||
return 0;
|
||||
err_unlock:
|
||||
mutex_unlock(&tty_mutex);
|
||||
|
@ -2155,7 +2180,7 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait)
|
|||
|
||||
ld = tty_ldisc_ref_wait(tty);
|
||||
if (ld->ops->poll)
|
||||
ret = (ld->ops->poll)(tty, filp, wait);
|
||||
ret = ld->ops->poll(tty, filp, wait);
|
||||
tty_ldisc_deref(ld);
|
||||
return ret;
|
||||
}
|
||||
|
@ -2283,18 +2308,14 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
|
|||
int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
|
||||
{
|
||||
struct pid *pgrp;
|
||||
unsigned long flags;
|
||||
|
||||
/* Lock the tty */
|
||||
mutex_lock(&tty->winsize_mutex);
|
||||
if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
|
||||
goto done;
|
||||
/* Get the PID values and reference them so we can
|
||||
avoid holding the tty ctrl lock while sending signals */
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
pgrp = get_pid(tty->pgrp);
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
|
||||
/* Signal the foreground process group */
|
||||
pgrp = tty_get_pgrp(tty);
|
||||
if (pgrp)
|
||||
kill_pgrp(pgrp, SIGWINCH, 1);
|
||||
put_pid(pgrp);
|
||||
|
@ -2403,7 +2424,7 @@ static int fionbio(struct file *file, int __user *p)
|
|||
* leader to set this tty as the controlling tty for the session.
|
||||
*
|
||||
* Locking:
|
||||
* Takes tty_mutex() to protect tty instance
|
||||
* Takes tty_lock() to serialize proc_set_tty() for this tty
|
||||
* Takes tasklist_lock internally to walk sessions
|
||||
* Takes ->siglock() when updating signal->tty
|
||||
*/
|
||||
|
@ -2411,10 +2432,13 @@ static int fionbio(struct file *file, int __user *p)
|
|||
static int tiocsctty(struct tty_struct *tty, int arg)
|
||||
{
|
||||
int ret = 0;
|
||||
if (current->signal->leader && (task_session(current) == tty->session))
|
||||
return ret;
|
||||
|
||||
mutex_lock(&tty_mutex);
|
||||
tty_lock(tty);
|
||||
read_lock(&tasklist_lock);
|
||||
|
||||
if (current->signal->leader && (task_session(current) == tty->session))
|
||||
goto unlock;
|
||||
|
||||
/*
|
||||
* The process must be a session leader and
|
||||
* not have a controlling tty already.
|
||||
|
@ -2433,17 +2457,16 @@ static int tiocsctty(struct tty_struct *tty, int arg)
|
|||
/*
|
||||
* Steal it away
|
||||
*/
|
||||
read_lock(&tasklist_lock);
|
||||
session_clear_tty(tty->session);
|
||||
read_unlock(&tasklist_lock);
|
||||
} else {
|
||||
ret = -EPERM;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
proc_set_tty(current, tty);
|
||||
proc_set_tty(tty);
|
||||
unlock:
|
||||
mutex_unlock(&tty_mutex);
|
||||
read_unlock(&tasklist_lock);
|
||||
tty_unlock(tty);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2468,6 +2491,27 @@ struct pid *tty_get_pgrp(struct tty_struct *tty)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(tty_get_pgrp);
|
||||
|
||||
/*
|
||||
* This checks not only the pgrp, but falls back on the pid if no
|
||||
* satisfactory pgrp is found. I dunno - gdb doesn't work correctly
|
||||
* without this...
|
||||
*
|
||||
* The caller must hold rcu lock or the tasklist lock.
|
||||
*/
|
||||
static struct pid *session_of_pgrp(struct pid *pgrp)
|
||||
{
|
||||
struct task_struct *p;
|
||||
struct pid *sid = NULL;
|
||||
|
||||
p = pid_task(pgrp, PIDTYPE_PGID);
|
||||
if (p == NULL)
|
||||
p = pid_task(pgrp, PIDTYPE_PID);
|
||||
if (p != NULL)
|
||||
sid = task_session(p);
|
||||
|
||||
return sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* tiocgpgrp - get process group
|
||||
* @tty: tty passed by user
|
||||
|
@ -2714,23 +2758,35 @@ static int tty_tiocgicount(struct tty_struct *tty, void __user *arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
|
||||
static void tty_warn_deprecated_flags(struct serial_struct __user *ss)
|
||||
{
|
||||
static DEFINE_RATELIMIT_STATE(depr_flags,
|
||||
DEFAULT_RATELIMIT_INTERVAL,
|
||||
DEFAULT_RATELIMIT_BURST);
|
||||
char comm[TASK_COMM_LEN];
|
||||
int flags;
|
||||
|
||||
if (get_user(flags, &ss->flags))
|
||||
return;
|
||||
|
||||
flags &= ASYNC_DEPRECATED;
|
||||
|
||||
if (flags && __ratelimit(&depr_flags))
|
||||
pr_warning("%s: '%s' is using deprecated serial flags (with no effect): %.8x\n",
|
||||
__func__, get_task_comm(comm, current), flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* if pty, return the slave side (real_tty)
|
||||
* otherwise, return self
|
||||
*/
|
||||
static struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
|
||||
{
|
||||
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||
tty->driver->subtype == PTY_TYPE_MASTER)
|
||||
tty = tty->link;
|
||||
return tty;
|
||||
}
|
||||
EXPORT_SYMBOL(tty_pair_get_tty);
|
||||
|
||||
struct tty_struct *tty_pair_get_pty(struct tty_struct *tty)
|
||||
{
|
||||
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||
tty->driver->subtype == PTY_TYPE_MASTER)
|
||||
return tty;
|
||||
return tty->link;
|
||||
}
|
||||
EXPORT_SYMBOL(tty_pair_get_pty);
|
||||
|
||||
/*
|
||||
* Split this up, as gcc can choke on it otherwise..
|
||||
|
@ -2859,13 +2915,16 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
case TCIFLUSH:
|
||||
case TCIOFLUSH:
|
||||
/* flush tty buffer and allow ldisc to process ioctl */
|
||||
tty_buffer_flush(tty);
|
||||
tty_buffer_flush(tty, NULL);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TIOCSSERIAL:
|
||||
tty_warn_deprecated_flags(p);
|
||||
break;
|
||||
}
|
||||
if (tty->ops->ioctl) {
|
||||
retval = (tty->ops->ioctl)(tty, cmd, arg);
|
||||
retval = tty->ops->ioctl(tty, cmd, arg);
|
||||
if (retval != -ENOIOCTLCMD)
|
||||
return retval;
|
||||
}
|
||||
|
@ -2892,7 +2951,7 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
|
|||
return -EINVAL;
|
||||
|
||||
if (tty->ops->compat_ioctl) {
|
||||
retval = (tty->ops->compat_ioctl)(tty, cmd, arg);
|
||||
retval = tty->ops->compat_ioctl(tty, cmd, arg);
|
||||
if (retval != -ENOIOCTLCMD)
|
||||
return retval;
|
||||
}
|
||||
|
@ -3443,59 +3502,6 @@ dev_t tty_devnum(struct tty_struct *tty)
|
|||
}
|
||||
EXPORT_SYMBOL(tty_devnum);
|
||||
|
||||
void proc_clear_tty(struct task_struct *p)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct tty_struct *tty;
|
||||
spin_lock_irqsave(&p->sighand->siglock, flags);
|
||||
tty = p->signal->tty;
|
||||
p->signal->tty = NULL;
|
||||
spin_unlock_irqrestore(&p->sighand->siglock, flags);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
/* Called under the sighand lock */
|
||||
|
||||
static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
|
||||
{
|
||||
if (tty) {
|
||||
unsigned long flags;
|
||||
/* We should not have a session or pgrp to put here but.... */
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
put_pid(tty->session);
|
||||
put_pid(tty->pgrp);
|
||||
tty->pgrp = get_pid(task_pgrp(tsk));
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
tty->session = get_pid(task_session(tsk));
|
||||
if (tsk->signal->tty) {
|
||||
printk(KERN_DEBUG "tty not NULL!!\n");
|
||||
tty_kref_put(tsk->signal->tty);
|
||||
}
|
||||
}
|
||||
put_pid(tsk->signal->tty_old_pgrp);
|
||||
tsk->signal->tty = tty_kref_get(tty);
|
||||
tsk->signal->tty_old_pgrp = NULL;
|
||||
}
|
||||
|
||||
static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
|
||||
{
|
||||
spin_lock_irq(&tsk->sighand->siglock);
|
||||
__proc_set_tty(tsk, tty);
|
||||
spin_unlock_irq(&tsk->sighand->siglock);
|
||||
}
|
||||
|
||||
struct tty_struct *get_current_tty(void)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
||||
tty = tty_kref_get(current->signal->tty);
|
||||
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
||||
return tty;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(get_current_tty);
|
||||
|
||||
void tty_default_fops(struct file_operations *fops)
|
||||
{
|
||||
*fops = tty_fops;
|
||||
|
|
|
@ -524,9 +524,8 @@ EXPORT_SYMBOL(tty_termios_hw_change);
|
|||
* @tty: tty to update
|
||||
* @new_termios: desired new value
|
||||
*
|
||||
* Perform updates to the termios values set on this terminal. There
|
||||
* is a bit of layering violation here with n_tty in terms of the
|
||||
* internal knowledge of this function.
|
||||
* Perform updates to the termios values set on this terminal.
|
||||
* A master pty's termios should never be set.
|
||||
*
|
||||
* Locking: termios_rwsem
|
||||
*/
|
||||
|
@ -535,8 +534,9 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
|
|||
{
|
||||
struct ktermios old_termios;
|
||||
struct tty_ldisc *ld;
|
||||
unsigned long flags;
|
||||
|
||||
WARN_ON(tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||
tty->driver->subtype == PTY_TYPE_MASTER);
|
||||
/*
|
||||
* Perform the actual termios internal changes under lock.
|
||||
*/
|
||||
|
@ -549,41 +549,15 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
|
|||
tty->termios = *new_termios;
|
||||
unset_locked_termios(&tty->termios, &old_termios, &tty->termios_locked);
|
||||
|
||||
/* See if packet mode change of state. */
|
||||
if (tty->link && tty->link->packet) {
|
||||
int extproc = (old_termios.c_lflag & EXTPROC) |
|
||||
(tty->termios.c_lflag & EXTPROC);
|
||||
int old_flow = ((old_termios.c_iflag & IXON) &&
|
||||
(old_termios.c_cc[VSTOP] == '\023') &&
|
||||
(old_termios.c_cc[VSTART] == '\021'));
|
||||
int new_flow = (I_IXON(tty) &&
|
||||
STOP_CHAR(tty) == '\023' &&
|
||||
START_CHAR(tty) == '\021');
|
||||
if ((old_flow != new_flow) || extproc) {
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
if (old_flow != new_flow) {
|
||||
tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
|
||||
if (new_flow)
|
||||
tty->ctrl_status |= TIOCPKT_DOSTOP;
|
||||
else
|
||||
tty->ctrl_status |= TIOCPKT_NOSTOP;
|
||||
}
|
||||
if (extproc)
|
||||
tty->ctrl_status |= TIOCPKT_IOCTL;
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
wake_up_interruptible(&tty->link->read_wait);
|
||||
}
|
||||
}
|
||||
|
||||
if (tty->ops->set_termios)
|
||||
(*tty->ops->set_termios)(tty, &old_termios);
|
||||
tty->ops->set_termios(tty, &old_termios);
|
||||
else
|
||||
tty_termios_copy_hw(&tty->termios, &old_termios);
|
||||
|
||||
ld = tty_ldisc_ref(tty);
|
||||
if (ld != NULL) {
|
||||
if (ld->ops->set_termios)
|
||||
(ld->ops->set_termios)(tty, &old_termios);
|
||||
ld->ops->set_termios(tty, &old_termios);
|
||||
tty_ldisc_deref(ld);
|
||||
}
|
||||
up_write(&tty->termios_rwsem);
|
||||
|
|
|
@ -308,23 +308,41 @@ EXPORT_SYMBOL_GPL(tty_ldisc_deref);
|
|||
|
||||
|
||||
static inline int __lockfunc
|
||||
tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
|
||||
__tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
|
||||
{
|
||||
return ldsem_down_write(&tty->ldisc_sem, timeout);
|
||||
}
|
||||
|
||||
static inline int __lockfunc
|
||||
tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout)
|
||||
__tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout)
|
||||
{
|
||||
return ldsem_down_write_nested(&tty->ldisc_sem,
|
||||
LDISC_SEM_OTHER, timeout);
|
||||
}
|
||||
|
||||
static inline void tty_ldisc_unlock(struct tty_struct *tty)
|
||||
static inline void __tty_ldisc_unlock(struct tty_struct *tty)
|
||||
{
|
||||
return ldsem_up_write(&tty->ldisc_sem);
|
||||
}
|
||||
|
||||
static int __lockfunc
|
||||
tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = __tty_ldisc_lock(tty, timeout);
|
||||
if (!ret)
|
||||
return -EBUSY;
|
||||
set_bit(TTY_LDISC_HALTED, &tty->flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tty_ldisc_unlock(struct tty_struct *tty)
|
||||
{
|
||||
clear_bit(TTY_LDISC_HALTED, &tty->flags);
|
||||
__tty_ldisc_unlock(tty);
|
||||
}
|
||||
|
||||
static int __lockfunc
|
||||
tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2,
|
||||
unsigned long timeout)
|
||||
|
@ -332,24 +350,24 @@ tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2,
|
|||
int ret;
|
||||
|
||||
if (tty < tty2) {
|
||||
ret = tty_ldisc_lock(tty, timeout);
|
||||
ret = __tty_ldisc_lock(tty, timeout);
|
||||
if (ret) {
|
||||
ret = tty_ldisc_lock_nested(tty2, timeout);
|
||||
ret = __tty_ldisc_lock_nested(tty2, timeout);
|
||||
if (!ret)
|
||||
tty_ldisc_unlock(tty);
|
||||
__tty_ldisc_unlock(tty);
|
||||
}
|
||||
} else {
|
||||
/* if this is possible, it has lots of implications */
|
||||
WARN_ON_ONCE(tty == tty2);
|
||||
if (tty2 && tty != tty2) {
|
||||
ret = tty_ldisc_lock(tty2, timeout);
|
||||
ret = __tty_ldisc_lock(tty2, timeout);
|
||||
if (ret) {
|
||||
ret = tty_ldisc_lock_nested(tty, timeout);
|
||||
ret = __tty_ldisc_lock_nested(tty, timeout);
|
||||
if (!ret)
|
||||
tty_ldisc_unlock(tty2);
|
||||
__tty_ldisc_unlock(tty2);
|
||||
}
|
||||
} else
|
||||
ret = tty_ldisc_lock(tty, timeout);
|
||||
ret = __tty_ldisc_lock(tty, timeout);
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
|
@ -370,38 +388,26 @@ tty_ldisc_lock_pair(struct tty_struct *tty, struct tty_struct *tty2)
|
|||
static void __lockfunc tty_ldisc_unlock_pair(struct tty_struct *tty,
|
||||
struct tty_struct *tty2)
|
||||
{
|
||||
tty_ldisc_unlock(tty);
|
||||
__tty_ldisc_unlock(tty);
|
||||
if (tty2)
|
||||
tty_ldisc_unlock(tty2);
|
||||
}
|
||||
|
||||
static void __lockfunc tty_ldisc_enable_pair(struct tty_struct *tty,
|
||||
struct tty_struct *tty2)
|
||||
{
|
||||
clear_bit(TTY_LDISC_HALTED, &tty->flags);
|
||||
if (tty2)
|
||||
clear_bit(TTY_LDISC_HALTED, &tty2->flags);
|
||||
|
||||
tty_ldisc_unlock_pair(tty, tty2);
|
||||
__tty_ldisc_unlock(tty2);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_flush - flush line discipline queue
|
||||
* @tty: tty
|
||||
*
|
||||
* Flush the line discipline queue (if any) for this tty. If there
|
||||
* is no line discipline active this is a no-op.
|
||||
* Flush the line discipline queue (if any) and the tty flip buffers
|
||||
* for this tty.
|
||||
*/
|
||||
|
||||
void tty_ldisc_flush(struct tty_struct *tty)
|
||||
{
|
||||
struct tty_ldisc *ld = tty_ldisc_ref(tty);
|
||||
if (ld) {
|
||||
if (ld->ops->flush_buffer)
|
||||
ld->ops->flush_buffer(tty);
|
||||
|
||||
tty_buffer_flush(tty, ld);
|
||||
if (ld)
|
||||
tty_ldisc_deref(ld);
|
||||
}
|
||||
tty_buffer_flush(tty);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_ldisc_flush);
|
||||
|
||||
|
@ -517,15 +523,16 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|||
{
|
||||
int retval;
|
||||
struct tty_ldisc *old_ldisc, *new_ldisc;
|
||||
struct tty_struct *o_tty = tty->link;
|
||||
|
||||
new_ldisc = tty_ldisc_get(tty, ldisc);
|
||||
if (IS_ERR(new_ldisc))
|
||||
return PTR_ERR(new_ldisc);
|
||||
|
||||
retval = tty_ldisc_lock_pair_timeout(tty, o_tty, 5 * HZ);
|
||||
tty_lock(tty);
|
||||
retval = tty_ldisc_lock(tty, 5 * HZ);
|
||||
if (retval) {
|
||||
tty_ldisc_put(new_ldisc);
|
||||
tty_unlock(tty);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -534,19 +541,18 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|||
*/
|
||||
|
||||
if (tty->ldisc->ops->num == ldisc) {
|
||||
tty_ldisc_enable_pair(tty, o_tty);
|
||||
tty_ldisc_unlock(tty);
|
||||
tty_ldisc_put(new_ldisc);
|
||||
tty_unlock(tty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
old_ldisc = tty->ldisc;
|
||||
tty_lock(tty);
|
||||
|
||||
if (test_bit(TTY_HUPPING, &tty->flags) ||
|
||||
test_bit(TTY_HUPPED, &tty->flags)) {
|
||||
if (test_bit(TTY_HUPPED, &tty->flags)) {
|
||||
/* We were raced by the hangup method. It will have stomped
|
||||
the ldisc data and closed the ldisc down */
|
||||
tty_ldisc_enable_pair(tty, o_tty);
|
||||
tty_ldisc_unlock(tty);
|
||||
tty_ldisc_put(new_ldisc);
|
||||
tty_unlock(tty);
|
||||
return -EIO;
|
||||
|
@ -566,8 +572,11 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|||
tty_ldisc_restore(tty, old_ldisc);
|
||||
}
|
||||
|
||||
if (tty->ldisc->ops->num != old_ldisc->ops->num && tty->ops->set_ldisc)
|
||||
if (tty->ldisc->ops->num != old_ldisc->ops->num && tty->ops->set_ldisc) {
|
||||
down_read(&tty->termios_rwsem);
|
||||
tty->ops->set_ldisc(tty);
|
||||
up_read(&tty->termios_rwsem);
|
||||
}
|
||||
|
||||
/* At this point we hold a reference to the new ldisc and a
|
||||
reference to the old ldisc, or we hold two references to
|
||||
|
@ -580,13 +589,11 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|||
/*
|
||||
* Allow ldisc referencing to occur again
|
||||
*/
|
||||
tty_ldisc_enable_pair(tty, o_tty);
|
||||
tty_ldisc_unlock(tty);
|
||||
|
||||
/* Restart the work queue in case no characters kick it off. Safe if
|
||||
already running */
|
||||
schedule_work(&tty->port->buf.work);
|
||||
if (o_tty)
|
||||
schedule_work(&o_tty->port->buf.work);
|
||||
|
||||
tty_unlock(tty);
|
||||
return retval;
|
||||
|
@ -675,16 +682,13 @@ void tty_ldisc_hangup(struct tty_struct *tty)
|
|||
wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
|
||||
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
|
||||
|
||||
tty_unlock(tty);
|
||||
|
||||
/*
|
||||
* Shutdown the current line discipline, and reset it to
|
||||
* N_TTY if need be.
|
||||
*
|
||||
* Avoid racing set_ldisc or tty_ldisc_release
|
||||
*/
|
||||
tty_ldisc_lock_pair(tty, tty->link);
|
||||
tty_lock(tty);
|
||||
tty_ldisc_lock(tty, MAX_SCHEDULE_TIMEOUT);
|
||||
|
||||
if (tty->ldisc) {
|
||||
|
||||
|
@ -706,7 +710,7 @@ void tty_ldisc_hangup(struct tty_struct *tty)
|
|||
WARN_ON(tty_ldisc_open(tty, tty->ldisc));
|
||||
}
|
||||
}
|
||||
tty_ldisc_enable_pair(tty, tty->link);
|
||||
tty_ldisc_unlock(tty);
|
||||
if (reset)
|
||||
tty_reset_termios(tty);
|
||||
|
||||
|
@ -758,16 +762,17 @@ static void tty_ldisc_kill(struct tty_struct *tty)
|
|||
|
||||
/**
|
||||
* tty_ldisc_release - release line discipline
|
||||
* @tty: tty being shut down
|
||||
* @o_tty: pair tty for pty/tty pairs
|
||||
* @tty: tty being shut down (or one end of pty pair)
|
||||
*
|
||||
* Called during the final close of a tty/pty pair in order to shut down
|
||||
* the line discpline layer. On exit the ldisc assigned is N_TTY and the
|
||||
* ldisc has not been opened.
|
||||
* Called during the final close of a tty or a pty pair in order to shut
|
||||
* down the line discpline layer. On exit, each ldisc assigned is N_TTY and
|
||||
* each ldisc has not been opened.
|
||||
*/
|
||||
|
||||
void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
|
||||
void tty_ldisc_release(struct tty_struct *tty)
|
||||
{
|
||||
struct tty_struct *o_tty = tty->link;
|
||||
|
||||
/*
|
||||
* Shutdown this line discipline. As this is the final close,
|
||||
* it does not race with the set_ldisc code path.
|
||||
|
@ -776,13 +781,9 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
|
|||
tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc);
|
||||
|
||||
tty_ldisc_lock_pair(tty, o_tty);
|
||||
tty_lock_pair(tty, o_tty);
|
||||
|
||||
tty_ldisc_kill(tty);
|
||||
if (o_tty)
|
||||
tty_ldisc_kill(o_tty);
|
||||
|
||||
tty_unlock_pair(tty, o_tty);
|
||||
tty_ldisc_unlock_pair(tty, o_tty);
|
||||
|
||||
/* And the memory resources remaining (buffers, termios) will be
|
||||
|
|
|
@ -4,19 +4,23 @@
|
|||
#include <linux/semaphore.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
/*
|
||||
* Nested tty locks are necessary for releasing pty pairs.
|
||||
* The stable lock order is master pty first, then slave pty.
|
||||
*/
|
||||
|
||||
/* Legacy tty mutex glue */
|
||||
|
||||
enum {
|
||||
TTY_MUTEX_NORMAL,
|
||||
TTY_MUTEX_NESTED,
|
||||
TTY_MUTEX_SLAVE,
|
||||
};
|
||||
|
||||
/*
|
||||
* Getting the big tty mutex.
|
||||
*/
|
||||
|
||||
static void __lockfunc tty_lock_nested(struct tty_struct *tty,
|
||||
unsigned int subclass)
|
||||
void __lockfunc tty_lock(struct tty_struct *tty)
|
||||
{
|
||||
if (tty->magic != TTY_MAGIC) {
|
||||
pr_err("L Bad %p\n", tty);
|
||||
|
@ -24,12 +28,7 @@ static void __lockfunc tty_lock_nested(struct tty_struct *tty,
|
|||
return;
|
||||
}
|
||||
tty_kref_get(tty);
|
||||
mutex_lock_nested(&tty->legacy_mutex, subclass);
|
||||
}
|
||||
|
||||
void __lockfunc tty_lock(struct tty_struct *tty)
|
||||
{
|
||||
return tty_lock_nested(tty, TTY_MUTEX_NORMAL);
|
||||
mutex_lock(&tty->legacy_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_lock);
|
||||
|
||||
|
@ -45,29 +44,23 @@ void __lockfunc tty_unlock(struct tty_struct *tty)
|
|||
}
|
||||
EXPORT_SYMBOL(tty_unlock);
|
||||
|
||||
/*
|
||||
* Getting the big tty mutex for a pair of ttys with lock ordering
|
||||
* On a non pty/tty pair tty2 can be NULL which is just fine.
|
||||
*/
|
||||
void __lockfunc tty_lock_pair(struct tty_struct *tty,
|
||||
struct tty_struct *tty2)
|
||||
void __lockfunc tty_lock_slave(struct tty_struct *tty)
|
||||
{
|
||||
if (tty < tty2) {
|
||||
if (tty && tty != tty->link) {
|
||||
WARN_ON(!mutex_is_locked(&tty->link->legacy_mutex) ||
|
||||
!tty->driver->type == TTY_DRIVER_TYPE_PTY ||
|
||||
!tty->driver->type == PTY_TYPE_SLAVE);
|
||||
tty_lock(tty);
|
||||
tty_lock_nested(tty2, TTY_MUTEX_NESTED);
|
||||
} else {
|
||||
if (tty2 && tty2 != tty)
|
||||
tty_lock(tty2);
|
||||
tty_lock_nested(tty, TTY_MUTEX_NESTED);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(tty_lock_pair);
|
||||
|
||||
void __lockfunc tty_unlock_pair(struct tty_struct *tty,
|
||||
struct tty_struct *tty2)
|
||||
void __lockfunc tty_unlock_slave(struct tty_struct *tty)
|
||||
{
|
||||
tty_unlock(tty);
|
||||
if (tty2 && tty2 != tty)
|
||||
tty_unlock(tty2);
|
||||
if (tty && tty != tty->link)
|
||||
tty_unlock(tty);
|
||||
}
|
||||
|
||||
void tty_set_lock_subclass(struct tty_struct *tty)
|
||||
{
|
||||
lockdep_set_subclass(&tty->legacy_mutex, TTY_MUTEX_SLAVE);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_unlock_pair);
|
||||
|
|
|
@ -193,8 +193,7 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
|
|||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
if (port->tty)
|
||||
tty_kref_put(port->tty);
|
||||
tty_kref_put(port->tty);
|
||||
port->tty = tty_kref_get(tty);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
@ -473,12 +472,10 @@ int tty_port_close_start(struct tty_port *port,
|
|||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
if (tty_hung_up_p(filp)) {
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
if (tty_hung_up_p(filp))
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
if (tty->count == 1 && port->count != 1) {
|
||||
printk(KERN_WARNING
|
||||
"tty_port_close_start: tty->count = 1 port count = %d.\n",
|
||||
|
@ -522,6 +519,7 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
|
|||
{
|
||||
unsigned long flags;
|
||||
|
||||
tty_ldisc_flush(tty);
|
||||
tty->closing = 0;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
|
|
@ -924,7 +924,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
|
|||
|
||||
if (kbd->kbdmode != VC_UNICODE) {
|
||||
if (!up_flag)
|
||||
pr_warning("keyboard mode must be unicode for braille patterns\n");
|
||||
pr_warn("keyboard mode must be unicode for braille patterns\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1253,8 +1253,8 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
|
|||
if (raw_mode && !hw_raw)
|
||||
if (emulate_raw(vc, keycode, !down << 7))
|
||||
if (keycode < BTN_MISC && printk_ratelimit())
|
||||
pr_warning("can't emulate rawmode for keycode %d\n",
|
||||
keycode);
|
||||
pr_warn("can't emulate rawmode for keycode %d\n",
|
||||
keycode);
|
||||
|
||||
#ifdef CONFIG_SPARC
|
||||
if (keycode == KEY_A && sparc_l1_a_state) {
|
||||
|
|
|
@ -156,6 +156,8 @@ static void console_callback(struct work_struct *ignored);
|
|||
static void blank_screen_t(unsigned long dummy);
|
||||
static void set_palette(struct vc_data *vc);
|
||||
|
||||
#define vt_get_kmsg_redirect() vt_kmsg_redirect(-1)
|
||||
|
||||
static int printable; /* Is console ready for printing? */
|
||||
int default_utf8 = true;
|
||||
module_param(default_utf8, int, S_IRUGO | S_IWUSR);
|
||||
|
@ -1367,9 +1369,11 @@ static void csi_m(struct vc_data *vc)
|
|||
rgb_from_256(vc->vc_par[i]));
|
||||
} else if (vc->vc_par[i] == 2 && /* 24 bit */
|
||||
i <= vc->vc_npar + 3) {/* extremely rare */
|
||||
struct rgb c = {r:vc->vc_par[i+1],
|
||||
g:vc->vc_par[i+2],
|
||||
b:vc->vc_par[i+3]};
|
||||
struct rgb c = {
|
||||
.r = vc->vc_par[i + 1],
|
||||
.g = vc->vc_par[i + 2],
|
||||
.b = vc->vc_par[i + 3],
|
||||
};
|
||||
rgb_foreground(vc, c);
|
||||
i += 3;
|
||||
}
|
||||
|
@ -1388,9 +1392,11 @@ static void csi_m(struct vc_data *vc)
|
|||
rgb_from_256(vc->vc_par[i]));
|
||||
} else if (vc->vc_par[i] == 2 && /* 24 bit */
|
||||
i <= vc->vc_npar + 3) {
|
||||
struct rgb c = {r:vc->vc_par[i+1],
|
||||
g:vc->vc_par[i+2],
|
||||
b:vc->vc_par[i+3]};
|
||||
struct rgb c = {
|
||||
.r = vc->vc_par[i + 1],
|
||||
.g = vc->vc_par[i + 2],
|
||||
.b = vc->vc_par[i + 3],
|
||||
};
|
||||
rgb_background(vc, c);
|
||||
i += 3;
|
||||
}
|
||||
|
@ -3849,8 +3855,8 @@ void do_unblank_screen(int leaving_gfx)
|
|||
return;
|
||||
if (!vc_cons_allocated(fg_console)) {
|
||||
/* impossible */
|
||||
pr_warning("unblank_screen: tty %d not allocated ??\n",
|
||||
fg_console+1);
|
||||
pr_warn("unblank_screen: tty %d not allocated ??\n",
|
||||
fg_console + 1);
|
||||
return;
|
||||
}
|
||||
vc = vc_cons[fg_console].d;
|
||||
|
|
|
@ -416,9 +416,6 @@ extern int __kernel_text_address(unsigned long addr);
|
|||
extern int kernel_text_address(unsigned long addr);
|
||||
extern int func_ptr_is_kernel_text(void *ptr);
|
||||
|
||||
struct pid;
|
||||
extern struct pid *session_of_pgrp(struct pid *pgrp);
|
||||
|
||||
unsigned long int_sqrt(unsigned long);
|
||||
|
||||
extern void bust_spinlocks(int yes);
|
||||
|
|
|
@ -97,13 +97,10 @@ struct uart_8250_port {
|
|||
unsigned char msr_saved_flags;
|
||||
|
||||
struct uart_8250_dma *dma;
|
||||
struct serial_rs485 rs485;
|
||||
|
||||
/* 8250 specific callbacks */
|
||||
int (*dl_read)(struct uart_8250_port *);
|
||||
void (*dl_write)(struct uart_8250_port *, int);
|
||||
int (*rs485_config)(struct uart_8250_port *,
|
||||
struct serial_rs485 *rs485);
|
||||
};
|
||||
|
||||
static inline struct uart_8250_port *up_to_u8250p(struct uart_port *up)
|
||||
|
|
|
@ -116,6 +116,4 @@
|
|||
UART_FIFO_PARERR_MASK | \
|
||||
UART_FIFO_BRKDET_MASK)
|
||||
|
||||
#define UART_REG_SIZE 24
|
||||
|
||||
#endif /* _LINUX_SERIAL_BCM63XX_H */
|
||||
|
|
|
@ -63,7 +63,7 @@ struct uart_ops {
|
|||
void (*flush_buffer)(struct uart_port *);
|
||||
void (*set_termios)(struct uart_port *, struct ktermios *new,
|
||||
struct ktermios *old);
|
||||
void (*set_ldisc)(struct uart_port *, int new);
|
||||
void (*set_ldisc)(struct uart_port *, struct ktermios *);
|
||||
void (*pm)(struct uart_port *, unsigned int state,
|
||||
unsigned int oldstate);
|
||||
|
||||
|
@ -131,6 +131,8 @@ struct uart_port {
|
|||
void (*pm)(struct uart_port *, unsigned int state,
|
||||
unsigned int old);
|
||||
void (*handle_break)(struct uart_port *);
|
||||
int (*rs485_config)(struct uart_port *,
|
||||
struct serial_rs485 *rs485);
|
||||
unsigned int irq; /* irq number */
|
||||
unsigned long irqflags; /* irq flags */
|
||||
unsigned int uartclk; /* base uart clock */
|
||||
|
@ -140,12 +142,13 @@ struct uart_port {
|
|||
unsigned char iotype; /* io access style */
|
||||
unsigned char unused1;
|
||||
|
||||
#define UPIO_PORT (0)
|
||||
#define UPIO_HUB6 (1)
|
||||
#define UPIO_MEM (2)
|
||||
#define UPIO_MEM32 (3)
|
||||
#define UPIO_AU (4) /* Au1x00 and RT288x type IO */
|
||||
#define UPIO_TSI (5) /* Tsi108/109 type IO */
|
||||
#define UPIO_PORT (0) /* 8b I/O port access */
|
||||
#define UPIO_HUB6 (1) /* Hub6 ISA card */
|
||||
#define UPIO_MEM (2) /* 8b MMIO access */
|
||||
#define UPIO_MEM32 (3) /* 32b little endian */
|
||||
#define UPIO_MEM32BE (4) /* 32b big endian */
|
||||
#define UPIO_AU (5) /* Au1x00 and RT288x type IO */
|
||||
#define UPIO_TSI (6) /* Tsi108/109 type IO */
|
||||
|
||||
unsigned int read_status_mask; /* driver specific */
|
||||
unsigned int ignore_status_mask; /* driver specific */
|
||||
|
@ -160,21 +163,33 @@ struct uart_port {
|
|||
/* flags must be updated while holding port mutex */
|
||||
upf_t flags;
|
||||
|
||||
#define UPF_FOURPORT ((__force upf_t) (1 << 1))
|
||||
#define UPF_SAK ((__force upf_t) (1 << 2))
|
||||
#define UPF_SPD_MASK ((__force upf_t) (0x1030))
|
||||
#define UPF_SPD_HI ((__force upf_t) (0x0010))
|
||||
#define UPF_SPD_VHI ((__force upf_t) (0x0020))
|
||||
#define UPF_SPD_CUST ((__force upf_t) (0x0030))
|
||||
#define UPF_SPD_SHI ((__force upf_t) (0x1000))
|
||||
#define UPF_SPD_WARP ((__force upf_t) (0x1010))
|
||||
#define UPF_SKIP_TEST ((__force upf_t) (1 << 6))
|
||||
#define UPF_AUTO_IRQ ((__force upf_t) (1 << 7))
|
||||
#define UPF_HARDPPS_CD ((__force upf_t) (1 << 11))
|
||||
#define UPF_LOW_LATENCY ((__force upf_t) (1 << 13))
|
||||
#define UPF_BUGGY_UART ((__force upf_t) (1 << 14))
|
||||
/*
|
||||
* These flags must be equivalent to the flags defined in
|
||||
* include/uapi/linux/tty_flags.h which are the userspace definitions
|
||||
* assigned from the serial_struct flags in uart_set_info()
|
||||
* [for bit definitions in the UPF_CHANGE_MASK]
|
||||
*
|
||||
* Bits [0..UPF_LAST_USER] are userspace defined/visible/changeable
|
||||
* except bit 15 (UPF_NO_TXEN_TEST) which is masked off.
|
||||
* The remaining bits are serial-core specific and not modifiable by
|
||||
* userspace.
|
||||
*/
|
||||
#define UPF_FOURPORT ((__force upf_t) ASYNC_FOURPORT /* 1 */ )
|
||||
#define UPF_SAK ((__force upf_t) ASYNC_SAK /* 2 */ )
|
||||
#define UPF_SPD_HI ((__force upf_t) ASYNC_SPD_HI /* 4 */ )
|
||||
#define UPF_SPD_VHI ((__force upf_t) ASYNC_SPD_VHI /* 5 */ )
|
||||
#define UPF_SPD_CUST ((__force upf_t) ASYNC_SPD_CUST /* 0x0030 */ )
|
||||
#define UPF_SPD_WARP ((__force upf_t) ASYNC_SPD_WARP /* 0x1010 */ )
|
||||
#define UPF_SPD_MASK ((__force upf_t) ASYNC_SPD_MASK /* 0x1030 */ )
|
||||
#define UPF_SKIP_TEST ((__force upf_t) ASYNC_SKIP_TEST /* 6 */ )
|
||||
#define UPF_AUTO_IRQ ((__force upf_t) ASYNC_AUTO_IRQ /* 7 */ )
|
||||
#define UPF_HARDPPS_CD ((__force upf_t) ASYNC_HARDPPS_CD /* 11 */ )
|
||||
#define UPF_SPD_SHI ((__force upf_t) ASYNC_SPD_SHI /* 12 */ )
|
||||
#define UPF_LOW_LATENCY ((__force upf_t) ASYNC_LOW_LATENCY /* 13 */ )
|
||||
#define UPF_BUGGY_UART ((__force upf_t) ASYNC_BUGGY_UART /* 14 */ )
|
||||
#define UPF_NO_TXEN_TEST ((__force upf_t) (1 << 15))
|
||||
#define UPF_MAGIC_MULTIPLIER ((__force upf_t) (1 << 16))
|
||||
#define UPF_MAGIC_MULTIPLIER ((__force upf_t) ASYNC_MAGIC_MULTIPLIER /* 16 */ )
|
||||
|
||||
/* Port has hardware-assisted h/w flow control (iow, auto-RTS *not* auto-CTS) */
|
||||
#define UPF_HARD_FLOW ((__force upf_t) (1 << 21))
|
||||
/* Port has hardware-assisted s/w flow control */
|
||||
|
@ -190,9 +205,14 @@ struct uart_port {
|
|||
#define UPF_DEAD ((__force upf_t) (1 << 30))
|
||||
#define UPF_IOREMAP ((__force upf_t) (1 << 31))
|
||||
|
||||
#define UPF_CHANGE_MASK ((__force upf_t) (0x17fff))
|
||||
#define __UPF_CHANGE_MASK 0x17fff
|
||||
#define UPF_CHANGE_MASK ((__force upf_t) __UPF_CHANGE_MASK)
|
||||
#define UPF_USR_MASK ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY))
|
||||
|
||||
#if __UPF_CHANGE_MASK > ASYNC_FLAGS
|
||||
#error Change mask not equivalent to userspace-visible bit defines
|
||||
#endif
|
||||
|
||||
/* status must be updated while holding port lock */
|
||||
upstat_t status;
|
||||
|
||||
|
@ -214,6 +234,7 @@ struct uart_port {
|
|||
unsigned char unused[2];
|
||||
struct attribute_group *attr_group; /* port specific attributes */
|
||||
const struct attribute_group **tty_groups; /* all attributes (serial core use only) */
|
||||
struct serial_rs485 rs485;
|
||||
void *private_data; /* generic platform data pointer */
|
||||
};
|
||||
|
||||
|
@ -367,7 +388,7 @@ static inline int uart_tx_stopped(struct uart_port *port)
|
|||
|
||||
static inline bool uart_cts_enabled(struct uart_port *uport)
|
||||
{
|
||||
return uport->status & UPSTAT_CTS_ENABLE;
|
||||
return !!(uport->status & UPSTAT_CTS_ENABLE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -284,7 +284,7 @@ struct tty_struct {
|
|||
|
||||
#define N_TTY_BUF_SIZE 4096
|
||||
|
||||
unsigned char closing:1;
|
||||
int closing;
|
||||
unsigned char *write_buf;
|
||||
int write_cnt;
|
||||
/* If the tty has a pending do_SAK, queue it here - akpm */
|
||||
|
@ -316,12 +316,10 @@ struct tty_file_private {
|
|||
#define TTY_EXCLUSIVE 3 /* Exclusive open mode */
|
||||
#define TTY_DEBUG 4 /* Debugging */
|
||||
#define TTY_DO_WRITE_WAKEUP 5 /* Call write_wakeup after queuing new */
|
||||
#define TTY_CLOSING 7 /* ->close() in progress */
|
||||
#define TTY_LDISC_OPEN 11 /* Line discipline is open */
|
||||
#define TTY_PTY_LOCK 16 /* pty private */
|
||||
#define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */
|
||||
#define TTY_HUPPED 18 /* Post driver->hangup() */
|
||||
#define TTY_HUPPING 21 /* ->hangup() in progress */
|
||||
#define TTY_LDISC_HALTED 22 /* Line discipline is halted */
|
||||
|
||||
#define TTY_WRITE_FLUSH(tty) tty_write_flush((tty))
|
||||
|
@ -437,14 +435,13 @@ extern int is_ignored(int sig);
|
|||
extern int tty_signal(int sig, struct tty_struct *tty);
|
||||
extern void tty_hangup(struct tty_struct *tty);
|
||||
extern void tty_vhangup(struct tty_struct *tty);
|
||||
extern void tty_unhangup(struct file *filp);
|
||||
extern int tty_hung_up_p(struct file *filp);
|
||||
extern void do_SAK(struct tty_struct *tty);
|
||||
extern void __do_SAK(struct tty_struct *tty);
|
||||
extern void no_tty(void);
|
||||
extern void tty_flush_to_ldisc(struct tty_struct *tty);
|
||||
extern void tty_buffer_free_all(struct tty_port *port);
|
||||
extern void tty_buffer_flush(struct tty_struct *tty);
|
||||
extern void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld);
|
||||
extern void tty_buffer_init(struct tty_port *port);
|
||||
extern speed_t tty_termios_baud_rate(struct ktermios *termios);
|
||||
extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
|
||||
|
@ -498,9 +495,6 @@ extern int tty_init_termios(struct tty_struct *tty);
|
|||
extern int tty_standard_install(struct tty_driver *driver,
|
||||
struct tty_struct *tty);
|
||||
|
||||
extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty);
|
||||
extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty);
|
||||
|
||||
extern struct mutex tty_mutex;
|
||||
extern spinlock_t tty_files_lock;
|
||||
|
||||
|
@ -562,7 +556,7 @@ extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
|
|||
extern int tty_unregister_ldisc(int disc);
|
||||
extern int tty_set_ldisc(struct tty_struct *tty, int ldisc);
|
||||
extern int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty);
|
||||
extern void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty);
|
||||
extern void tty_ldisc_release(struct tty_struct *tty);
|
||||
extern void tty_ldisc_init(struct tty_struct *tty);
|
||||
extern void tty_ldisc_deinit(struct tty_struct *tty);
|
||||
extern void tty_ldisc_begin(void);
|
||||
|
@ -623,14 +617,6 @@ extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
|
|||
extern long n_tty_compat_ioctl_helper(struct tty_struct *tty, struct file *file,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
|
||||
/* serial.c */
|
||||
|
||||
extern void serial_console_init(void);
|
||||
|
||||
/* pcxx.c */
|
||||
|
||||
extern int pcxe_open(struct tty_struct *tty, struct file *filp);
|
||||
|
||||
/* vt.c */
|
||||
|
||||
extern int vt_ioctl(struct tty_struct *tty,
|
||||
|
@ -643,11 +629,9 @@ extern long vt_compat_ioctl(struct tty_struct *tty,
|
|||
/* functions for preparation of BKL removal */
|
||||
extern void __lockfunc tty_lock(struct tty_struct *tty);
|
||||
extern void __lockfunc tty_unlock(struct tty_struct *tty);
|
||||
extern void __lockfunc tty_lock_pair(struct tty_struct *tty,
|
||||
struct tty_struct *tty2);
|
||||
extern void __lockfunc tty_unlock_pair(struct tty_struct *tty,
|
||||
struct tty_struct *tty2);
|
||||
|
||||
extern void __lockfunc tty_lock_slave(struct tty_struct *tty);
|
||||
extern void __lockfunc tty_unlock_slave(struct tty_struct *tty);
|
||||
extern void tty_set_lock_subclass(struct tty_struct *tty);
|
||||
/*
|
||||
* this shall be called only from where BTM is held (like close)
|
||||
*
|
||||
|
|
|
@ -54,7 +54,8 @@
|
|||
#define PORT_ALTR_16550_F32 26 /* Altera 16550 UART with 32 FIFOs */
|
||||
#define PORT_ALTR_16550_F64 27 /* Altera 16550 UART with 64 FIFOs */
|
||||
#define PORT_ALTR_16550_F128 28 /* Altera 16550 UART with 128 FIFOs */
|
||||
#define PORT_MAX_8250 28 /* max port ID */
|
||||
#define PORT_RT2880 29 /* Ralink RT2880 internal UART */
|
||||
#define PORT_MAX_8250 29 /* max port ID */
|
||||
|
||||
/*
|
||||
* ARM specific type numbers. These are not currently guaranteed
|
||||
|
|
|
@ -359,6 +359,7 @@
|
|||
#define UART_OMAP_SYSC 0x15 /* System configuration register */
|
||||
#define UART_OMAP_SYSS 0x16 /* System status register */
|
||||
#define UART_OMAP_WER 0x17 /* Wake-up enable register */
|
||||
#define UART_OMAP_TX_LVL 0x1a /* TX FIFO level register */
|
||||
|
||||
/*
|
||||
* These are the definitions for the MDR1 register
|
||||
|
|
|
@ -6,27 +6,31 @@
|
|||
* shared by the tty_port flags structures.
|
||||
*
|
||||
* Define ASYNCB_* for convenient use with {test,set,clear}_bit.
|
||||
*
|
||||
* Bits [0..ASYNCB_LAST_USER] are userspace defined/visible/changeable
|
||||
* [x] in the bit comments indicates the flag is defunct and no longer used.
|
||||
*/
|
||||
#define ASYNCB_HUP_NOTIFY 0 /* Notify getty on hangups and closes
|
||||
* on the callout port */
|
||||
#define ASYNCB_FOURPORT 1 /* Set OU1, OUT2 per AST Fourport settings */
|
||||
#define ASYNCB_SAK 2 /* Secure Attention Key (Orange book) */
|
||||
#define ASYNCB_SPLIT_TERMIOS 3 /* Separate termios for dialin/callout */
|
||||
#define ASYNCB_SPLIT_TERMIOS 3 /* [x] Separate termios for dialin/callout */
|
||||
#define ASYNCB_SPD_HI 4 /* Use 56000 instead of 38400 bps */
|
||||
#define ASYNCB_SPD_VHI 5 /* Use 115200 instead of 38400 bps */
|
||||
#define ASYNCB_SKIP_TEST 6 /* Skip UART test during autoconfiguration */
|
||||
#define ASYNCB_AUTO_IRQ 7 /* Do automatic IRQ during
|
||||
* autoconfiguration */
|
||||
#define ASYNCB_SESSION_LOCKOUT 8 /* Lock out cua opens based on session */
|
||||
#define ASYNCB_PGRP_LOCKOUT 9 /* Lock out cua opens based on pgrp */
|
||||
#define ASYNCB_CALLOUT_NOHUP 10 /* Don't do hangups for cua device */
|
||||
#define ASYNCB_SESSION_LOCKOUT 8 /* [x] Lock out cua opens based on session */
|
||||
#define ASYNCB_PGRP_LOCKOUT 9 /* [x] Lock out cua opens based on pgrp */
|
||||
#define ASYNCB_CALLOUT_NOHUP 10 /* [x] Don't do hangups for cua device */
|
||||
#define ASYNCB_HARDPPS_CD 11 /* Call hardpps when CD goes high */
|
||||
#define ASYNCB_SPD_SHI 12 /* Use 230400 instead of 38400 bps */
|
||||
#define ASYNCB_LOW_LATENCY 13 /* Request low latency behaviour */
|
||||
#define ASYNCB_BUGGY_UART 14 /* This is a buggy UART, skip some safety
|
||||
* checks. Note: can be dangerous! */
|
||||
#define ASYNCB_AUTOPROBE 15 /* Port was autoprobed by PCI or PNP code */
|
||||
#define ASYNCB_LAST_USER 15
|
||||
#define ASYNCB_AUTOPROBE 15 /* [x] Port was autoprobed by PCI/PNP code */
|
||||
#define ASYNCB_MAGIC_MULTIPLIER 16 /* Use special CLK or divisor */
|
||||
#define ASYNCB_LAST_USER 16
|
||||
|
||||
/* Internal flags used only by kernel */
|
||||
#define ASYNCB_INITIALIZED 31 /* Serial port was initialized */
|
||||
|
@ -57,8 +61,11 @@
|
|||
#define ASYNC_LOW_LATENCY (1U << ASYNCB_LOW_LATENCY)
|
||||
#define ASYNC_BUGGY_UART (1U << ASYNCB_BUGGY_UART)
|
||||
#define ASYNC_AUTOPROBE (1U << ASYNCB_AUTOPROBE)
|
||||
#define ASYNC_MAGIC_MULTIPLIER (1U << ASYNCB_MAGIC_MULTIPLIER)
|
||||
|
||||
#define ASYNC_FLAGS ((1U << (ASYNCB_LAST_USER + 1)) - 1)
|
||||
#define ASYNC_DEPRECATED (ASYNC_SESSION_LOCKOUT | ASYNC_PGRP_LOCKOUT | \
|
||||
ASYNC_CALLOUT_NOHUP | ASYNC_AUTOPROBE)
|
||||
#define ASYNC_USR_MASK (ASYNC_SPD_MASK|ASYNC_CALLOUT_NOHUP| \
|
||||
ASYNC_LOW_LATENCY)
|
||||
#define ASYNC_SPD_CUST (ASYNC_SPD_HI|ASYNC_SPD_VHI)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue