mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 09:16:33 +00:00
TTY/Serial driver updates for 6.3-rc1
Here is the big set of serial and tty driver updates for 6.3-rc1. Once again, Jiri and Ilpo have done a number of core vt and tty/serial layer cleanups that were much needed and appreciated. Other than that, it's just a bunch of little tty/serial driver updates: - qcom-geni-serial driver updates - liteuart driver updates - hvcs driver cleanups - n_gsm updates and additions for new features - more 8250 device support added - fpga/dfl update and additions - imx serial driver updates - fsl_lpuart updates - other tiny fixes and updates for serial drivers All of these have been in linux-next for a while with no reported problems. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCY/itAw8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ykJbQCfWv/J4ZElO108iHBU5mJCDagUDBgAnAtLLN6A SEAnnokGCDtA/BNIXeES =luRi -----END PGP SIGNATURE----- Merge tag 'tty-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty / serial driver updates from Greg KH: "Here is the big set of serial and tty driver updates for 6.3-rc1. Once again, Jiri and Ilpo have done a number of core vt and tty/serial layer cleanups that were much needed and appreciated. Other than that, it's just a bunch of little tty/serial driver updates: - qcom-geni-serial driver updates - liteuart driver updates - hvcs driver cleanups - n_gsm updates and additions for new features - more 8250 device support added - fpga/dfl update and additions - imx serial driver updates - fsl_lpuart updates - other tiny fixes and updates for serial drivers All of these have been in linux-next for a while with no reported problems" * tag 'tty-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (143 commits) tty: n_gsm: add keep alive support serial: imx: remove a redundant check dt-bindings: serial: snps-dw-apb-uart: add dma & dma-names properties soc: qcom: geni-se: Move qcom-geni-se.h to linux/soc/qcom/geni-se.h tty: n_gsm: add TIOCMIWAIT support tty: n_gsm: add RING/CD control support tty: n_gsm: mark unusable ioctl structure fields accordingly serial: imx: get rid of registers shadowing serial: imx: refine local variables in rxint() serial: imx: stop using USR2 in FIFO reading loop serial: imx: remove redundant USR2 read from FIFO reading loop serial: imx: do not break from FIFO reading loop prematurely serial: imx: do not sysrq broken chars serial: imx: work-around for hardware RX flood serial: imx: factor-out common code to imx_uart_soft_reset() serial: 8250_pci1xxxx: Add power management functions to quad-uart driver serial: 8250_pci1xxxx: Add RS485 support to quad-uart driver serial: 8250_pci1xxxx: Add driver for quad-uart support serial: 8250_pci: Add serial8250_pci_setup_port definition in 8250_pcilib.c tty: pcn_uart: fix memory leak with using debugfs_lookup() ...
This commit is contained in:
commit
17cd4d6f05
@ -1172,10 +1172,10 @@
|
||||
specified, the serial port must already be setup and
|
||||
configured.
|
||||
|
||||
uart[8250],io,<addr>[,options]
|
||||
uart[8250],mmio,<addr>[,options]
|
||||
uart[8250],mmio32,<addr>[,options]
|
||||
uart[8250],mmio32be,<addr>[,options]
|
||||
uart[8250],io,<addr>[,options[,uartclk]]
|
||||
uart[8250],mmio,<addr>[,options[,uartclk]]
|
||||
uart[8250],mmio32,<addr>[,options[,uartclk]]
|
||||
uart[8250],mmio32be,<addr>[,options[,uartclk]]
|
||||
uart[8250],0x<addr>[,options]
|
||||
Start an early, polled-mode console on the 8250/16550
|
||||
UART at the specified I/O port or MMIO address.
|
||||
@ -1184,7 +1184,9 @@
|
||||
If none of [io|mmio|mmio32|mmio32be], <addr> is assumed
|
||||
to be equivalent to 'mmio'. 'options' are specified
|
||||
in the same format described for "console=ttyS<n>"; if
|
||||
unspecified, the h/w is not initialized.
|
||||
unspecified, the h/w is not initialized. 'uartclk' is
|
||||
the uart clock frequency; if unspecified, it is set
|
||||
to 'BASE_BAUD' * 16.
|
||||
|
||||
pl011,<addr>
|
||||
pl011,mmio32,<addr>
|
||||
|
@ -62,7 +62,6 @@ properties:
|
||||
- const: mrvl,pxa-uart
|
||||
- const: nuvoton,wpcm450-uart
|
||||
- const: nuvoton,npcm750-uart
|
||||
- const: nuvoton,npcm845-uart
|
||||
- const: nvidia,tegra20-uart
|
||||
- const: nxp,lpc3220-uart
|
||||
- items:
|
||||
@ -92,6 +91,10 @@ properties:
|
||||
- enum:
|
||||
- ns16550 # Deprecated, unless the FIFO really is broken
|
||||
- ns16550a
|
||||
- items:
|
||||
- enum:
|
||||
- nuvoton,npcm845-uart
|
||||
- const: nuvoton,npcm750-uart
|
||||
- items:
|
||||
- enum:
|
||||
- ralink,mt7620a-uart
|
||||
@ -200,12 +203,13 @@ properties:
|
||||
deprecated: true
|
||||
|
||||
aspeed,lpc-io-reg:
|
||||
$ref: '/schemas/types.yaml#/definitions/uint32'
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
maxItems: 1
|
||||
description: |
|
||||
The VUART LPC address. Only applicable to aspeed,ast2500-vuart.
|
||||
|
||||
aspeed,lpc-interrupts:
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32-array"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
description: |
|
||||
|
@ -70,11 +70,6 @@ properties:
|
||||
dsr-gpios: true
|
||||
rng-gpios: true
|
||||
dcd-gpios: true
|
||||
rs485-rts-delay: true
|
||||
rs485-rts-active-low: true
|
||||
rs485-rx-during-tx: true
|
||||
rs485-rts-active-high: true
|
||||
linux,rs485-enabled-at-boot-time: true
|
||||
rts-gpio: true
|
||||
power-domains: true
|
||||
clock-frequency: true
|
||||
@ -109,12 +104,12 @@ else:
|
||||
|
||||
examples:
|
||||
- |
|
||||
serial@49042000 {
|
||||
compatible = "ti,omap3-uart";
|
||||
reg = <0x49042000 0x400>;
|
||||
interrupts = <80>;
|
||||
dmas = <&sdma 81 &sdma 82>;
|
||||
dma-names = "tx", "rx";
|
||||
ti,hwmods = "uart4";
|
||||
clock-frequency = <48000000>;
|
||||
};
|
||||
serial@49042000 {
|
||||
compatible = "ti,omap3-uart";
|
||||
reg = <0x49042000 0x400>;
|
||||
interrupts = <80>;
|
||||
dmas = <&sdma 81 &sdma 82>;
|
||||
dma-names = "tx", "rx";
|
||||
ti,hwmods = "uart4";
|
||||
clock-frequency = <48000000>;
|
||||
};
|
||||
|
@ -19,6 +19,9 @@ description: |
|
||||
is active since power-on and does not need any clock gating and is usable
|
||||
as very early serial console.
|
||||
|
||||
allOf:
|
||||
- $ref: serial.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
@ -69,14 +72,14 @@ required:
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
serial@84c0 {
|
||||
compatible = "amlogic,meson-gx-uart";
|
||||
reg = <0x84c0 0x14>;
|
||||
interrupts = <26>;
|
||||
clocks = <&xtal>, <&pclk>, <&xtal>;
|
||||
clock-names = "xtal", "pclk", "baud";
|
||||
compatible = "amlogic,meson-gx-uart";
|
||||
reg = <0x84c0 0x14>;
|
||||
interrupts = <26>;
|
||||
clocks = <&xtal>, <&pclk>, <&xtal>;
|
||||
clock-names = "xtal", "pclk", "baud";
|
||||
};
|
||||
|
@ -9,9 +9,6 @@ title: Cadence UART Controller
|
||||
maintainers:
|
||||
- Michal Simek <michal.simek@xilinx.com>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/serial.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
@ -46,6 +43,9 @@ properties:
|
||||
port does not use this pin.
|
||||
type: boolean
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@ -53,14 +53,25 @@ required:
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
allOf:
|
||||
- $ref: serial.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: cdns,uart-r1p8
|
||||
then:
|
||||
properties:
|
||||
power-domains: false
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
uart0: serial@e0000000 {
|
||||
compatible = "xlnx,xuartps", "cdns,uart-r1p8";
|
||||
clocks = <&clkc 23>, <&clkc 40>;
|
||||
clock-names = "uart_clk", "pclk";
|
||||
reg = <0xE0000000 0x1000>;
|
||||
interrupts = <0 27 4>;
|
||||
compatible = "xlnx,xuartps", "cdns,uart-r1p8";
|
||||
clocks = <&clkc 23>, <&clkc 40>;
|
||||
clock-names = "uart_clk", "pclk";
|
||||
reg = <0xe0000000 0x1000>;
|
||||
interrupts = <0 27 4>;
|
||||
};
|
||||
|
@ -16,7 +16,7 @@ maintainers:
|
||||
- Chester Lin <clin@suse.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "serial.yaml"
|
||||
- $ref: serial.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -10,8 +10,8 @@ maintainers:
|
||||
- Fabio Estevam <festevam@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "serial.yaml"
|
||||
- $ref: "rs485.yaml"
|
||||
- $ref: serial.yaml#
|
||||
- $ref: rs485.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@ -83,13 +83,6 @@ properties:
|
||||
are sensible for most use cases. If you need low latency processing on
|
||||
slow connections this needs to be configured appropriately.
|
||||
|
||||
uart-has-rtscts: true
|
||||
|
||||
rs485-rts-delay: true
|
||||
rs485-rts-active-low: true
|
||||
rs485-rx-during-tx: true
|
||||
linux,rs485-enabled-at-boot-time: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -10,7 +10,8 @@ maintainers:
|
||||
- Fugang Duan <fugang.duan@nxp.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "rs485.yaml"
|
||||
- $ref: rs485.yaml#
|
||||
- $ref: serial.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@ -64,9 +65,6 @@ properties:
|
||||
- const: rx
|
||||
- const: tx
|
||||
|
||||
rs485-rts-active-low: true
|
||||
linux,rs485-enabled-at-boot-time: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Fabio Estevam <festevam@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "serial.yaml"
|
||||
- $ref: serial.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -10,6 +10,7 @@ maintainers:
|
||||
- Rob Herring <robh@kernel.org>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/arm/primecell.yaml#
|
||||
- $ref: serial.yaml#
|
||||
|
||||
# Need a custom select here or 'arm,primecell' will match on lots of nodes
|
||||
|
@ -1,25 +0,0 @@
|
||||
* MSM Serial UART
|
||||
|
||||
The MSM serial UART hardware is designed for low-speed use cases where a
|
||||
dma-engine isn't needed. From a software perspective it's mostly compatible
|
||||
with the MSM serial UARTDM except that it only supports reading and writing one
|
||||
character at a time.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should contain "qcom,msm-uart"
|
||||
- reg: Should contain UART register location and length.
|
||||
- interrupts: Should contain UART interrupt.
|
||||
- clocks: Should contain the core clock.
|
||||
- clock-names: Should be "core".
|
||||
|
||||
Example:
|
||||
|
||||
A uart device at 0xa9c00000 with interrupt 11.
|
||||
|
||||
serial@a9c00000 {
|
||||
compatible = "qcom,msm-uart";
|
||||
reg = <0xa9c00000 0x1000>;
|
||||
interrupts = <11>;
|
||||
clocks = <&uart_cxc>;
|
||||
clock-names = "core";
|
||||
};
|
56
Documentation/devicetree/bindings/serial/qcom,msm-uart.yaml
Normal file
56
Documentation/devicetree/bindings/serial/qcom,msm-uart.yaml
Normal file
@ -0,0 +1,56 @@
|
||||
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/serial/qcom,msm-uart.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm MSM SoC Serial UART
|
||||
|
||||
maintainers:
|
||||
- Bjorn Andersson <andersson@kernel.org>
|
||||
- Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
|
||||
|
||||
description:
|
||||
The MSM serial UART hardware is designed for low-speed use cases where a
|
||||
dma-engine isn't needed. From a software perspective it's mostly compatible
|
||||
with the MSM serial UARTDM except that it only supports reading and writing
|
||||
one character at a time.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,msm-uart
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: core
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clock-names
|
||||
- clocks
|
||||
- interrupts
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/serial/serial.yaml#
|
||||
|
||||
examples:
|
||||
- |
|
||||
serial@a9c00000 {
|
||||
compatible = "qcom,msm-uart";
|
||||
reg = <0xa9c00000 0x1000>;
|
||||
interrupts = <11>;
|
||||
clocks = <&uart_cxc>;
|
||||
clock-names = "core";
|
||||
};
|
@ -66,9 +66,9 @@ examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
uart0: serial@e1020000 {
|
||||
compatible = "renesas,em-uart";
|
||||
reg = <0xe1020000 0x38>;
|
||||
interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&usia_u0_sclk>;
|
||||
clock-names = "sclk";
|
||||
compatible = "renesas,em-uart";
|
||||
reg = <0xe1020000 0x38>;
|
||||
interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&usia_u0_sclk>;
|
||||
clock-names = "sclk";
|
||||
};
|
||||
|
@ -131,20 +131,20 @@ examples:
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/power/r8a7795-sysc.h>
|
||||
aliases {
|
||||
serial1 = &hscif1;
|
||||
serial1 = &hscif1;
|
||||
};
|
||||
|
||||
hscif1: serial@e6550000 {
|
||||
compatible = "renesas,hscif-r8a7795", "renesas,rcar-gen3-hscif",
|
||||
"renesas,hscif";
|
||||
reg = <0xe6550000 96>;
|
||||
interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 519>, <&cpg CPG_CORE R8A7795_CLK_S3D1>,
|
||||
<&scif_clk>;
|
||||
clock-names = "fck", "brg_int", "scif_clk";
|
||||
dmas = <&dmac1 0x33>, <&dmac1 0x32>, <&dmac2 0x33>, <&dmac2 0x32>;
|
||||
dma-names = "tx", "rx", "tx", "rx";
|
||||
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 519>;
|
||||
uart-has-rtscts;
|
||||
compatible = "renesas,hscif-r8a7795", "renesas,rcar-gen3-hscif",
|
||||
"renesas,hscif";
|
||||
reg = <0xe6550000 96>;
|
||||
interrupts = <GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 519>, <&cpg CPG_CORE R8A7795_CLK_S3D1>,
|
||||
<&scif_clk>;
|
||||
clock-names = "fck", "brg_int", "scif_clk";
|
||||
dmas = <&dmac1 0x33>, <&dmac1 0x32>, <&dmac2 0x33>, <&dmac2 0x32>;
|
||||
dma-names = "tx", "rx", "tx", "rx";
|
||||
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 519>;
|
||||
uart-has-rtscts;
|
||||
};
|
||||
|
@ -91,19 +91,19 @@ examples:
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
aliases {
|
||||
serial0 = &sci0;
|
||||
serial0 = &sci0;
|
||||
};
|
||||
|
||||
sci0: serial@1004d000 {
|
||||
compatible = "renesas,r9a07g044-sci", "renesas,sci";
|
||||
reg = <0x1004d000 0x400>;
|
||||
interrupts = <GIC_SPI 405 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "eri", "rxi", "txi", "tei";
|
||||
clocks = <&cpg CPG_MOD R9A07G044_SCI0_CLKP>;
|
||||
clock-names = "fck";
|
||||
power-domains = <&cpg>;
|
||||
resets = <&cpg R9A07G044_SCI0_RST>;
|
||||
compatible = "renesas,r9a07g044-sci", "renesas,sci";
|
||||
reg = <0x1004d000 0x400>;
|
||||
interrupts = <GIC_SPI 405 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "eri", "rxi", "txi", "tei";
|
||||
clocks = <&cpg CPG_MOD R9A07G044_SCI0_CLKP>;
|
||||
clock-names = "fck";
|
||||
power-domains = <&cpg>;
|
||||
resets = <&cpg R9A07G044_SCI0_RST>;
|
||||
};
|
||||
|
@ -180,19 +180,19 @@ examples:
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/power/r8a7791-sysc.h>
|
||||
aliases {
|
||||
serial0 = &scif0;
|
||||
serial0 = &scif0;
|
||||
};
|
||||
|
||||
scif0: serial@e6e60000 {
|
||||
compatible = "renesas,scif-r8a7791", "renesas,rcar-gen2-scif",
|
||||
"renesas,scif";
|
||||
reg = <0xe6e60000 64>;
|
||||
interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 721>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
|
||||
<&scif_clk>;
|
||||
clock-names = "fck", "brg_int", "scif_clk";
|
||||
dmas = <&dmac0 0x29>, <&dmac0 0x2a>, <&dmac1 0x29>, <&dmac1 0x2a>;
|
||||
dma-names = "tx", "rx", "tx", "rx";
|
||||
power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 721>;
|
||||
compatible = "renesas,scif-r8a7791", "renesas,rcar-gen2-scif",
|
||||
"renesas,scif";
|
||||
reg = <0xe6e60000 64>;
|
||||
interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 721>, <&cpg CPG_CORE R8A7791_CLK_ZS>,
|
||||
<&scif_clk>;
|
||||
clock-names = "fck", "brg_int", "scif_clk";
|
||||
dmas = <&dmac0 0x29>, <&dmac0 0x2a>, <&dmac1 0x29>, <&dmac1 0x2a>;
|
||||
dma-names = "tx", "rx", "tx", "rx";
|
||||
power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 721>;
|
||||
};
|
||||
|
@ -95,18 +95,18 @@ examples:
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/power/r8a7790-sysc.h>
|
||||
aliases {
|
||||
serial0 = &scifa0;
|
||||
serial0 = &scifa0;
|
||||
};
|
||||
|
||||
scifa0: serial@e6c40000 {
|
||||
compatible = "renesas,scifa-r8a7790", "renesas,rcar-gen2-scifa",
|
||||
"renesas,scifa";
|
||||
reg = <0xe6c40000 64>;
|
||||
interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 204>;
|
||||
clock-names = "fck";
|
||||
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 204>;
|
||||
dmas = <&dmac0 0x21>, <&dmac0 0x22>, <&dmac1 0x21>, <&dmac1 0x22>;
|
||||
dma-names = "tx", "rx", "tx", "rx";
|
||||
compatible = "renesas,scifa-r8a7790", "renesas,rcar-gen2-scifa",
|
||||
"renesas,scifa";
|
||||
reg = <0xe6c40000 64>;
|
||||
interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 204>;
|
||||
clock-names = "fck";
|
||||
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 204>;
|
||||
dmas = <&dmac0 0x21>, <&dmac0 0x22>, <&dmac1 0x21>, <&dmac1 0x22>;
|
||||
dma-names = "tx", "rx", "tx", "rx";
|
||||
};
|
||||
|
@ -94,10 +94,10 @@ examples:
|
||||
#include <dt-bindings/clock/r8a7740-clock.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
scifb: serial@e6c30000 {
|
||||
compatible = "renesas,scifb-r8a7740", "renesas,scifb";
|
||||
reg = <0xe6c30000 0x100>;
|
||||
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&mstp2_clks R8A7740_CLK_SCIFB>;
|
||||
clock-names = "fck";
|
||||
power-domains = <&pd_a3sp>;
|
||||
compatible = "renesas,scifb-r8a7740", "renesas,scifb";
|
||||
reg = <0xe6c30000 0x100>;
|
||||
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&mstp2_clks R8A7740_CLK_SCIFB>;
|
||||
clock-names = "fck";
|
||||
power-domains = <&pd_a3sp>;
|
||||
};
|
||||
|
@ -51,6 +51,12 @@ properties:
|
||||
description: GPIO pin to enable RS485 bus termination.
|
||||
maxItems: 1
|
||||
|
||||
rs485-rx-during-tx-gpios:
|
||||
description: Output GPIO pin that sets the state of rs485-rx-during-tx. This
|
||||
signal can be used to control the RX part of an RS485 transceiver. Thereby
|
||||
the active state enables RX during TX.
|
||||
maxItems: 1
|
||||
|
||||
additionalProperties: true
|
||||
|
||||
...
|
||||
|
@ -141,13 +141,13 @@ additionalProperties: true
|
||||
examples:
|
||||
- |
|
||||
serial@1234 {
|
||||
compatible = "ns16550a";
|
||||
reg = <0x1234 0x20>;
|
||||
interrupts = <1>;
|
||||
compatible = "ns16550a";
|
||||
reg = <0x1234 0x20>;
|
||||
interrupts = <1>;
|
||||
|
||||
bluetooth {
|
||||
compatible = "brcm,bcm4330-bt";
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <10>;
|
||||
};
|
||||
bluetooth {
|
||||
compatible = "brcm,bcm4330-bt";
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <10>;
|
||||
};
|
||||
};
|
||||
|
@ -53,13 +53,13 @@ unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/sifive-fu540-prci.h>
|
||||
serial@10010000 {
|
||||
#include <dt-bindings/clock/sifive-fu540-prci.h>
|
||||
serial@10010000 {
|
||||
compatible = "sifive,fu540-c000-uart", "sifive,uart0";
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <80>;
|
||||
reg = <0x10010000 0x1000>;
|
||||
clocks = <&prci FU540_PRCI_CLK_TLCLK>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
@ -67,6 +67,14 @@ properties:
|
||||
- const: baudclk
|
||||
- const: apb_pclk
|
||||
|
||||
dmas:
|
||||
minItems: 2
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: rx
|
||||
- const: tx
|
||||
|
||||
snps,uart-16550-compatible:
|
||||
description: reflects the value of UART_16550_COMPATIBLE configuration
|
||||
parameter. Define this if your UART does not implement the busy functionality.
|
||||
|
@ -35,8 +35,6 @@ properties:
|
||||
description: enable hardware flow control (deprecated)
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
|
||||
uart-has-rtscts: true
|
||||
|
||||
rx-tx-swap: true
|
||||
|
||||
dmas:
|
||||
@ -60,11 +58,6 @@ properties:
|
||||
|
||||
wakeup-source: true
|
||||
|
||||
rs485-rts-delay: true
|
||||
rs485-rts-active-low: true
|
||||
linux,rs485-enabled-at-boot-time: true
|
||||
rs485-rx-during-tx: true
|
||||
|
||||
rx-threshold:
|
||||
description:
|
||||
If value is set to 1, RX FIFO threshold is disabled.
|
||||
|
@ -63,7 +63,7 @@ required:
|
||||
- xlnx,use-parity
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/serial.yaml#
|
||||
- $ref: serial.yaml#
|
||||
- if:
|
||||
properties:
|
||||
xlnx,use-parity:
|
||||
@ -76,7 +76,7 @@ unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
serial@800c0000 {
|
||||
serial@800c0000 {
|
||||
compatible = "xlnx,xps-uartlite-1.00.a";
|
||||
reg = <0x800c0000 0x10000>;
|
||||
interrupts = <0x0 0x6e 0x1>;
|
||||
@ -84,5 +84,5 @@ examples:
|
||||
current-speed = <115200>;
|
||||
xlnx,data-bits = <8>;
|
||||
xlnx,use-parity = <0>;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
@ -25,6 +25,8 @@ Config Initiator
|
||||
#. Switch the serial line to using the n_gsm line discipline by using
|
||||
``TIOCSETD`` ioctl.
|
||||
|
||||
#. Configure the mux using ``GSMIOC_GETCONF_EXT``/``GSMIOC_SETCONF_EXT`` ioctl if needed.
|
||||
|
||||
#. Configure the mux using ``GSMIOC_GETCONF``/``GSMIOC_SETCONF`` ioctl.
|
||||
|
||||
#. Obtain base gsmtty number for the used serial port.
|
||||
@ -42,6 +44,7 @@ Config Initiator
|
||||
|
||||
int ldisc = N_GSM0710;
|
||||
struct gsm_config c;
|
||||
struct gsm_config_ext ce;
|
||||
struct termios configuration;
|
||||
uint32_t first;
|
||||
|
||||
@ -62,6 +65,12 @@ Config Initiator
|
||||
/* use n_gsm line discipline */
|
||||
ioctl(fd, TIOCSETD, &ldisc);
|
||||
|
||||
/* get n_gsm extended configuration */
|
||||
ioctl(fd, GSMIOC_GETCONF_EXT, &ce);
|
||||
/* use keep-alive once every 5s for modem connection supervision */
|
||||
ce.keep_alive = 500;
|
||||
/* set the new extended configuration */
|
||||
ioctl(fd, GSMIOC_SETCONF_EXT, &ce);
|
||||
/* get n_gsm configuration */
|
||||
ioctl(fd, GSMIOC_GETCONF, &c);
|
||||
/* we are initiator and need encoding 0 (basic) */
|
||||
@ -106,6 +115,9 @@ Config Requester
|
||||
#. Switch the serial line to using the *n_gsm* line discipline by using
|
||||
``TIOCSETD`` ioctl.
|
||||
|
||||
#. Configure the mux using ``GSMIOC_GETCONF_EXT``/``GSMIOC_SETCONF_EXT``
|
||||
ioctl if needed.
|
||||
|
||||
#. Configure the mux using ``GSMIOC_GETCONF``/``GSMIOC_SETCONF`` ioctl.
|
||||
|
||||
#. Obtain base gsmtty number for the used serial port::
|
||||
@ -119,6 +131,7 @@ Config Requester
|
||||
|
||||
int ldisc = N_GSM0710;
|
||||
struct gsm_config c;
|
||||
struct gsm_config_ext ce;
|
||||
struct termios configuration;
|
||||
uint32_t first;
|
||||
|
||||
@ -132,6 +145,12 @@ Config Requester
|
||||
/* use n_gsm line discipline */
|
||||
ioctl(fd, TIOCSETD, &ldisc);
|
||||
|
||||
/* get n_gsm extended configuration */
|
||||
ioctl(fd, GSMIOC_GETCONF_EXT, &ce);
|
||||
/* use keep-alive once every 5s for peer connection supervision */
|
||||
ce.keep_alive = 500;
|
||||
/* set the new extended configuration */
|
||||
ioctl(fd, GSMIOC_SETCONF_EXT, &ce);
|
||||
/* get n_gsm configuration */
|
||||
ioctl(fd, GSMIOC_GETCONF, &c);
|
||||
/* we are requester and need encoding 0 (basic) */
|
||||
|
@ -75,6 +75,125 @@ convenient for software to locate each feature by walking through this list,
|
||||
and can be implemented in register regions of any FPGA device.
|
||||
|
||||
|
||||
Device Feature Header - Version 0
|
||||
=================================
|
||||
Version 0 (DFHv0) is the original version of the Device Feature Header.
|
||||
All multi-byte quantities in DFHv0 are little-endian.
|
||||
The format of DFHv0 is shown below::
|
||||
|
||||
+-----------------------------------------------------------------------+
|
||||
|63 Type 60|59 DFH VER 52|51 Rsvd 41|40 EOL|39 Next 16|15 REV 12|11 ID 0| 0x00
|
||||
+-----------------------------------------------------------------------+
|
||||
|63 GUID_L 0| 0x08
|
||||
+-----------------------------------------------------------------------+
|
||||
|63 GUID_H 0| 0x10
|
||||
+-----------------------------------------------------------------------+
|
||||
|
||||
- Offset 0x00
|
||||
|
||||
* Type - The type of DFH (e.g. FME, AFU, or private feature).
|
||||
* DFH VER - The version of the DFH.
|
||||
* Rsvd - Currently unused.
|
||||
* EOL - Set if the DFH is the end of the Device Feature List (DFL).
|
||||
* Next - The offset in bytes of the next DFH in the DFL from the DFH start,
|
||||
and the start of a DFH must be aligned to an 8 byte boundary.
|
||||
If EOL is set, Next is the size of MMIO of the last feature in the list.
|
||||
* REV - The revision of the feature associated with this header.
|
||||
* ID - The feature ID if Type is private feature.
|
||||
|
||||
- Offset 0x08
|
||||
|
||||
* GUID_L - Least significant 64 bits of a 128-bit Globally Unique Identifier
|
||||
(present only if Type is FME or AFU).
|
||||
|
||||
- Offset 0x10
|
||||
|
||||
* GUID_H - Most significant 64 bits of a 128-bit Globally Unique Identifier
|
||||
(present only if Type is FME or AFU).
|
||||
|
||||
|
||||
Device Feature Header - Version 1
|
||||
=================================
|
||||
Version 1 (DFHv1) of the Device Feature Header adds the following functionality:
|
||||
|
||||
* Provides a standardized mechanism for features to describe
|
||||
parameters/capabilities to software.
|
||||
* Standardize the use of a GUID for all DFHv1 types.
|
||||
* Decouples the DFH location from the register space of the feature itself.
|
||||
|
||||
All multi-byte quantities in DFHv1 are little-endian.
|
||||
The format of Version 1 of the Device Feature Header (DFH) is shown below::
|
||||
|
||||
+-----------------------------------------------------------------------+
|
||||
|63 Type 60|59 DFH VER 52|51 Rsvd 41|40 EOL|39 Next 16|15 REV 12|11 ID 0| 0x00
|
||||
+-----------------------------------------------------------------------+
|
||||
|63 GUID_L 0| 0x08
|
||||
+-----------------------------------------------------------------------+
|
||||
|63 GUID_H 0| 0x10
|
||||
+-----------------------------------------------------------------------+
|
||||
|63 Reg Address/Offset 1| Rel 0| 0x18
|
||||
+-----------------------------------------------------------------------+
|
||||
|63 Reg Size 32|Params 31|30 Group 16|15 Instance 0| 0x20
|
||||
+-----------------------------------------------------------------------+
|
||||
|63 Next 35|34RSV33|EOP32|31 Param Version 16|15 Param ID 0| 0x28
|
||||
+-----------------------------------------------------------------------+
|
||||
|63 Parameter Data 0| 0x30
|
||||
+-----------------------------------------------------------------------+
|
||||
|
||||
...
|
||||
|
||||
+-----------------------------------------------------------------------+
|
||||
|63 Next 35|34RSV33|EOP32|31 Param Version 16|15 Param ID 0|
|
||||
+-----------------------------------------------------------------------+
|
||||
|63 Parameter Data 0|
|
||||
+-----------------------------------------------------------------------+
|
||||
|
||||
- Offset 0x00
|
||||
|
||||
* Type - The type of DFH (e.g. FME, AFU, or private feature).
|
||||
* DFH VER - The version of the DFH.
|
||||
* Rsvd - Currently unused.
|
||||
* EOL - Set if the DFH is the end of the Device Feature List (DFL).
|
||||
* Next - The offset in bytes of the next DFH in the DFL from the DFH start,
|
||||
and the start of a DFH must be aligned to an 8 byte boundary.
|
||||
If EOL is set, Next is the size of MMIO of the last feature in the list.
|
||||
* REV - The revision of the feature associated with this header.
|
||||
* ID - The feature ID if Type is private feature.
|
||||
|
||||
- Offset 0x08
|
||||
|
||||
* GUID_L - Least significant 64 bits of a 128-bit Globally Unique Identifier.
|
||||
|
||||
- Offset 0x10
|
||||
|
||||
* GUID_H - Most significant 64 bits of a 128-bit Globally Unique Identifier.
|
||||
|
||||
- Offset 0x18
|
||||
|
||||
* Reg Address/Offset - If Rel bit is set, then the value is the high 63 bits
|
||||
of a 16-bit aligned absolute address of the feature's registers. Otherwise
|
||||
the value is the offset from the start of the DFH of the feature's registers.
|
||||
|
||||
- Offset 0x20
|
||||
|
||||
* Reg Size - Size of feature's register set in bytes.
|
||||
* Params - Set if DFH has a list of parameter blocks.
|
||||
* Group - Id of group if feature is part of a group.
|
||||
* Instance - Id of feature instance within a group.
|
||||
|
||||
- Offset 0x28 if feature has parameters
|
||||
|
||||
* Next - Offset to the next parameter block in 8 byte words. If EOP set,
|
||||
size in 8 byte words of last parameter.
|
||||
* Param Version - Version of Param ID.
|
||||
* Param ID - ID of parameter.
|
||||
|
||||
- Offset 0x30
|
||||
|
||||
* Parameter Data - Parameter data whose size and format is defined by
|
||||
version and ID of the parameter.
|
||||
|
||||
|
||||
FIU - FME (FPGA Management Engine)
|
||||
==================================
|
||||
The FPGA Management Engine performs reconfiguration and other infrastructure
|
||||
|
@ -13703,6 +13703,13 @@ L: linux-i2c@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/i2c/busses/i2c-mchp-pci1xxxx.c
|
||||
|
||||
MICROCHIP PCIe UART DRIVER
|
||||
M: Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>
|
||||
M: Tharun Kumar P <tharunkumar.pasumarthi@microchip.com>
|
||||
L: linux-serial@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/tty/serial/8250/8250_pci1xxxx.c
|
||||
|
||||
MICROCHIP PWM DRIVER
|
||||
M: Claudiu Beznea <claudiu.beznea@microchip.com>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
|
30
arch/arm/include/asm/semihost.h
Normal file
30
arch/arm/include/asm/semihost.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2012 ARM Ltd.
|
||||
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
||||
*
|
||||
* Adapted for ARM and earlycon:
|
||||
* Copyright (C) 2014 Linaro Ltd.
|
||||
* Author: Rob Herring <robh@kernel.org>
|
||||
*/
|
||||
|
||||
#ifndef _ARM_SEMIHOST_H_
|
||||
#define _ARM_SEMIHOST_H_
|
||||
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
#define SEMIHOST_SWI "0xab"
|
||||
#else
|
||||
#define SEMIHOST_SWI "0x123456"
|
||||
#endif
|
||||
|
||||
struct uart_port;
|
||||
|
||||
static inline void smh_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
asm volatile("mov r1, %0\n"
|
||||
"mov r0, #3\n"
|
||||
"svc " SEMIHOST_SWI "\n"
|
||||
: : "r" (&c) : "r0", "r1", "memory");
|
||||
}
|
||||
|
||||
#endif /* _ARM_SEMIHOST_H_ */
|
24
arch/arm64/include/asm/semihost.h
Normal file
24
arch/arm64/include/asm/semihost.h
Normal file
@ -0,0 +1,24 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2012 ARM Ltd.
|
||||
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
||||
*
|
||||
* Adapted for ARM and earlycon:
|
||||
* Copyright (C) 2014 Linaro Ltd.
|
||||
* Author: Rob Herring <robh@kernel.org>
|
||||
*/
|
||||
|
||||
#ifndef _ARM64_SEMIHOST_H_
|
||||
#define _ARM64_SEMIHOST_H_
|
||||
|
||||
struct uart_port;
|
||||
|
||||
static inline void smh_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
asm volatile("mov x1, %0\n"
|
||||
"mov x0, #3\n"
|
||||
"hlt 0xf000\n"
|
||||
: : "r" (&c) : "x0", "x1", "memory");
|
||||
}
|
||||
|
||||
#endif /* _ARM64_SEMIHOST_H_ */
|
26
arch/riscv/include/asm/semihost.h
Normal file
26
arch/riscv/include/asm/semihost.h
Normal file
@ -0,0 +1,26 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2022 tinylab.org
|
||||
* Author: Bin Meng <bmeng@tinylab.org>
|
||||
*/
|
||||
|
||||
#ifndef _RISCV_SEMIHOST_H_
|
||||
#define _RISCV_SEMIHOST_H_
|
||||
|
||||
struct uart_port;
|
||||
|
||||
static inline void smh_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
asm volatile("addi a1, %0, 0\n"
|
||||
"addi a0, zero, 3\n"
|
||||
".balign 16\n"
|
||||
".option push\n"
|
||||
".option norvc\n"
|
||||
"slli zero, zero, 0x1f\n"
|
||||
"ebreak\n"
|
||||
"srai zero, zero, 0x7\n"
|
||||
".option pop\n"
|
||||
: : "r" (&c) : "a0", "a1", "memory");
|
||||
}
|
||||
|
||||
#endif /* _RISCV_SEMIHOST_H_ */
|
@ -377,8 +377,8 @@ static void async_mode(MGSLPC_INFO *info);
|
||||
|
||||
static void tx_timeout(struct timer_list *t);
|
||||
|
||||
static int carrier_raised(struct tty_port *port);
|
||||
static void dtr_rts(struct tty_port *port, int onoff);
|
||||
static bool carrier_raised(struct tty_port *port);
|
||||
static void dtr_rts(struct tty_port *port, bool active);
|
||||
|
||||
#if SYNCLINK_GENERIC_HDLC
|
||||
#define dev_to_port(D) (dev_to_hdlc(D)->priv)
|
||||
@ -1309,7 +1309,7 @@ static int startup(MGSLPC_INFO * info, struct tty_struct *tty)
|
||||
if (tty)
|
||||
clear_bit(TTY_IO_ERROR, &tty->flags);
|
||||
|
||||
tty_port_set_initialized(&info->port, 1);
|
||||
tty_port_set_initialized(&info->port, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1359,7 +1359,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
|
||||
if (tty)
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
|
||||
tty_port_set_initialized(&info->port, 0);
|
||||
tty_port_set_initialized(&info->port, false);
|
||||
}
|
||||
|
||||
static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty)
|
||||
@ -2430,7 +2430,7 @@ static void mgslpc_hangup(struct tty_struct *tty)
|
||||
tty_port_hangup(&info->port);
|
||||
}
|
||||
|
||||
static int carrier_raised(struct tty_port *port)
|
||||
static bool carrier_raised(struct tty_port *port)
|
||||
{
|
||||
MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
|
||||
unsigned long flags;
|
||||
@ -2439,18 +2439,16 @@ static int carrier_raised(struct tty_port *port)
|
||||
get_signals(info);
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
|
||||
if (info->serial_signals & SerialSignal_DCD)
|
||||
return 1;
|
||||
return 0;
|
||||
return info->serial_signals & SerialSignal_DCD;
|
||||
}
|
||||
|
||||
static void dtr_rts(struct tty_port *port, int onoff)
|
||||
static void dtr_rts(struct tty_port *port, bool active)
|
||||
{
|
||||
MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
if (onoff)
|
||||
if (active)
|
||||
info->serial_signals |= SerialSignal_RTS | SerialSignal_DTR;
|
||||
else
|
||||
info->serial_signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/dfl.h>
|
||||
#include <linux/fpga-dfl.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "dfl.h"
|
||||
@ -342,6 +343,8 @@ static void release_dfl_dev(struct device *dev)
|
||||
if (ddev->mmio_res.parent)
|
||||
release_resource(&ddev->mmio_res);
|
||||
|
||||
kfree(ddev->params);
|
||||
|
||||
ida_free(&dfl_device_ida, ddev->id);
|
||||
kfree(ddev->irqs);
|
||||
kfree(ddev);
|
||||
@ -380,7 +383,16 @@ dfl_dev_add(struct dfl_feature_platform_data *pdata,
|
||||
ddev->type = feature_dev_id_type(pdev);
|
||||
ddev->feature_id = feature->id;
|
||||
ddev->revision = feature->revision;
|
||||
ddev->dfh_version = feature->dfh_version;
|
||||
ddev->cdev = pdata->dfl_cdev;
|
||||
if (feature->param_size) {
|
||||
ddev->params = kmemdup(feature->params, feature->param_size, GFP_KERNEL);
|
||||
if (!ddev->params) {
|
||||
ret = -ENOMEM;
|
||||
goto put_dev;
|
||||
}
|
||||
ddev->param_size = feature->param_size;
|
||||
}
|
||||
|
||||
/* add mmio resource */
|
||||
parent_res = &pdev->resource[feature->resource_index];
|
||||
@ -708,20 +720,27 @@ struct build_feature_devs_info {
|
||||
* struct dfl_feature_info - sub feature info collected during feature dev build
|
||||
*
|
||||
* @fid: id of this sub feature.
|
||||
* @revision: revision of this sub feature
|
||||
* @dfh_version: version of Device Feature Header (DFH)
|
||||
* @mmio_res: mmio resource of this sub feature.
|
||||
* @ioaddr: mapped base address of mmio resource.
|
||||
* @node: node in sub_features linked list.
|
||||
* @irq_base: start of irq index in this sub feature.
|
||||
* @nr_irqs: number of irqs of this sub feature.
|
||||
* @param_size: size DFH parameters.
|
||||
* @params: DFH parameter data.
|
||||
*/
|
||||
struct dfl_feature_info {
|
||||
u16 fid;
|
||||
u8 revision;
|
||||
u8 dfh_version;
|
||||
struct resource mmio_res;
|
||||
void __iomem *ioaddr;
|
||||
struct list_head node;
|
||||
unsigned int irq_base;
|
||||
unsigned int nr_irqs;
|
||||
unsigned int param_size;
|
||||
u64 params[];
|
||||
};
|
||||
|
||||
static void dfl_fpga_cdev_add_port_dev(struct dfl_fpga_cdev *cdev,
|
||||
@ -797,7 +816,17 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
|
||||
feature->dev = fdev;
|
||||
feature->id = finfo->fid;
|
||||
feature->revision = finfo->revision;
|
||||
feature->dfh_version = finfo->dfh_version;
|
||||
|
||||
if (finfo->param_size) {
|
||||
feature->params = devm_kmemdup(binfo->dev,
|
||||
finfo->params, finfo->param_size,
|
||||
GFP_KERNEL);
|
||||
if (!feature->params)
|
||||
return -ENOMEM;
|
||||
|
||||
feature->param_size = finfo->param_size;
|
||||
}
|
||||
/*
|
||||
* the FIU header feature has some fundamental functions (sriov
|
||||
* set, port enable/disable) needed for the dfl bus device and
|
||||
@ -934,56 +963,115 @@ static u16 feature_id(u64 value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 *find_param(u64 *params, resource_size_t max, int param_id)
|
||||
{
|
||||
u64 *end = params + max / sizeof(u64);
|
||||
u64 v, next;
|
||||
|
||||
while (params < end) {
|
||||
v = *params;
|
||||
if (param_id == FIELD_GET(DFHv1_PARAM_HDR_ID, v))
|
||||
return params;
|
||||
|
||||
if (FIELD_GET(DFHv1_PARAM_HDR_NEXT_EOP, v))
|
||||
break;
|
||||
|
||||
next = FIELD_GET(DFHv1_PARAM_HDR_NEXT_OFFSET, v);
|
||||
params += next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* dfh_find_param() - find parameter block for the given parameter id
|
||||
* @dfl_dev: dfl device
|
||||
* @param_id: id of dfl parameter
|
||||
* @psize: destination to store size of parameter data in bytes
|
||||
*
|
||||
* Return: pointer to start of parameter data, PTR_ERR otherwise.
|
||||
*/
|
||||
void *dfh_find_param(struct dfl_device *dfl_dev, int param_id, size_t *psize)
|
||||
{
|
||||
u64 *phdr = find_param(dfl_dev->params, dfl_dev->param_size, param_id);
|
||||
|
||||
if (!phdr)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
if (psize)
|
||||
*psize = (FIELD_GET(DFHv1_PARAM_HDR_NEXT_OFFSET, *phdr) - 1) * sizeof(u64);
|
||||
|
||||
return phdr + 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dfh_find_param);
|
||||
|
||||
static int parse_feature_irqs(struct build_feature_devs_info *binfo,
|
||||
resource_size_t ofst, u16 fid,
|
||||
unsigned int *irq_base, unsigned int *nr_irqs)
|
||||
resource_size_t ofst, struct dfl_feature_info *finfo)
|
||||
{
|
||||
void __iomem *base = binfo->ioaddr + ofst;
|
||||
unsigned int i, ibase, inr = 0;
|
||||
void *params = finfo->params;
|
||||
enum dfl_id_type type;
|
||||
u16 fid = finfo->fid;
|
||||
int virq;
|
||||
u64 *p;
|
||||
u64 v;
|
||||
|
||||
type = feature_dev_id_type(binfo->feature_dev);
|
||||
switch (finfo->dfh_version) {
|
||||
case 0:
|
||||
/*
|
||||
* DFHv0 only provides MMIO resource information for each feature
|
||||
* in the DFL header. There is no generic interrupt information.
|
||||
* Instead, features with interrupt functionality provide
|
||||
* the information in feature specific registers.
|
||||
*/
|
||||
type = feature_dev_id_type(binfo->feature_dev);
|
||||
if (type == PORT_ID) {
|
||||
switch (fid) {
|
||||
case PORT_FEATURE_ID_UINT:
|
||||
v = readq(base + PORT_UINT_CAP);
|
||||
ibase = FIELD_GET(PORT_UINT_CAP_FST_VECT, v);
|
||||
inr = FIELD_GET(PORT_UINT_CAP_INT_NUM, v);
|
||||
break;
|
||||
case PORT_FEATURE_ID_ERROR:
|
||||
v = readq(base + PORT_ERROR_CAP);
|
||||
ibase = FIELD_GET(PORT_ERROR_CAP_INT_VECT, v);
|
||||
inr = FIELD_GET(PORT_ERROR_CAP_SUPP_INT, v);
|
||||
break;
|
||||
}
|
||||
} else if (type == FME_ID) {
|
||||
switch (fid) {
|
||||
case FME_FEATURE_ID_GLOBAL_ERR:
|
||||
v = readq(base + FME_ERROR_CAP);
|
||||
ibase = FIELD_GET(FME_ERROR_CAP_INT_VECT, v);
|
||||
inr = FIELD_GET(FME_ERROR_CAP_SUPP_INT, v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
* Ideally DFL framework should only read info from DFL header, but
|
||||
* current version DFL only provides mmio resources information for
|
||||
* each feature in DFL Header, no field for interrupt resources.
|
||||
* Interrupt resource information is provided by specific mmio
|
||||
* registers of each private feature which supports interrupt. So in
|
||||
* order to parse and assign irq resources, DFL framework has to look
|
||||
* into specific capability registers of these private features.
|
||||
*
|
||||
* Once future DFL version supports generic interrupt resource
|
||||
* information in common DFL headers, the generic interrupt parsing
|
||||
* code will be added. But in order to be compatible to old version
|
||||
* DFL, the driver may still fall back to these quirks.
|
||||
*/
|
||||
if (type == PORT_ID) {
|
||||
switch (fid) {
|
||||
case PORT_FEATURE_ID_UINT:
|
||||
v = readq(base + PORT_UINT_CAP);
|
||||
ibase = FIELD_GET(PORT_UINT_CAP_FST_VECT, v);
|
||||
inr = FIELD_GET(PORT_UINT_CAP_INT_NUM, v);
|
||||
case 1:
|
||||
/*
|
||||
* DFHv1 provides interrupt resource information in DFHv1
|
||||
* parameter blocks.
|
||||
*/
|
||||
p = find_param(params, finfo->param_size, DFHv1_PARAM_ID_MSI_X);
|
||||
if (!p)
|
||||
break;
|
||||
case PORT_FEATURE_ID_ERROR:
|
||||
v = readq(base + PORT_ERROR_CAP);
|
||||
ibase = FIELD_GET(PORT_ERROR_CAP_INT_VECT, v);
|
||||
inr = FIELD_GET(PORT_ERROR_CAP_SUPP_INT, v);
|
||||
break;
|
||||
}
|
||||
} else if (type == FME_ID) {
|
||||
if (fid == FME_FEATURE_ID_GLOBAL_ERR) {
|
||||
v = readq(base + FME_ERROR_CAP);
|
||||
ibase = FIELD_GET(FME_ERROR_CAP_INT_VECT, v);
|
||||
inr = FIELD_GET(FME_ERROR_CAP_SUPP_INT, v);
|
||||
}
|
||||
|
||||
p++;
|
||||
ibase = FIELD_GET(DFHv1_PARAM_MSI_X_STARTV, *p);
|
||||
inr = FIELD_GET(DFHv1_PARAM_MSI_X_NUMV, *p);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_warn(binfo->dev, "unexpected DFH version %d\n", finfo->dfh_version);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!inr) {
|
||||
*irq_base = 0;
|
||||
*nr_irqs = 0;
|
||||
finfo->irq_base = 0;
|
||||
finfo->nr_irqs = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1006,12 +1094,37 @@ static int parse_feature_irqs(struct build_feature_devs_info *binfo,
|
||||
}
|
||||
}
|
||||
|
||||
*irq_base = ibase;
|
||||
*nr_irqs = inr;
|
||||
finfo->irq_base = ibase;
|
||||
finfo->nr_irqs = inr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dfh_get_param_size(void __iomem *dfh_base, resource_size_t max)
|
||||
{
|
||||
int size = 0;
|
||||
u64 v, next;
|
||||
|
||||
if (!FIELD_GET(DFHv1_CSR_SIZE_GRP_HAS_PARAMS,
|
||||
readq(dfh_base + DFHv1_CSR_SIZE_GRP)))
|
||||
return 0;
|
||||
|
||||
while (size + DFHv1_PARAM_HDR < max) {
|
||||
v = readq(dfh_base + DFHv1_PARAM_HDR + size);
|
||||
|
||||
next = FIELD_GET(DFHv1_PARAM_HDR_NEXT_OFFSET, v);
|
||||
if (!next)
|
||||
return -EINVAL;
|
||||
|
||||
size += next * sizeof(u64);
|
||||
|
||||
if (FIELD_GET(DFHv1_PARAM_HDR_NEXT_EOP, v))
|
||||
return size;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* when create sub feature instances, for private features, it doesn't need
|
||||
* to provide resource size and feature id as they could be read from DFH
|
||||
@ -1023,39 +1136,69 @@ static int
|
||||
create_feature_instance(struct build_feature_devs_info *binfo,
|
||||
resource_size_t ofst, resource_size_t size, u16 fid)
|
||||
{
|
||||
unsigned int irq_base, nr_irqs;
|
||||
struct dfl_feature_info *finfo;
|
||||
resource_size_t start, end;
|
||||
int dfh_psize = 0;
|
||||
u8 revision = 0;
|
||||
u64 v, addr_off;
|
||||
u8 dfh_ver = 0;
|
||||
int ret;
|
||||
u64 v;
|
||||
|
||||
if (fid != FEATURE_ID_AFU) {
|
||||
v = readq(binfo->ioaddr + ofst);
|
||||
revision = FIELD_GET(DFH_REVISION, v);
|
||||
|
||||
dfh_ver = FIELD_GET(DFH_VERSION, v);
|
||||
/* read feature size and id if inputs are invalid */
|
||||
size = size ? size : feature_size(v);
|
||||
fid = fid ? fid : feature_id(v);
|
||||
if (dfh_ver == 1) {
|
||||
dfh_psize = dfh_get_param_size(binfo->ioaddr + ofst, size);
|
||||
if (dfh_psize < 0) {
|
||||
dev_err(binfo->dev,
|
||||
"failed to read size of DFHv1 parameters %d\n",
|
||||
dfh_psize);
|
||||
return dfh_psize;
|
||||
}
|
||||
dev_dbg(binfo->dev, "dfhv1_psize %d\n", dfh_psize);
|
||||
}
|
||||
}
|
||||
|
||||
if (binfo->len - ofst < size)
|
||||
return -EINVAL;
|
||||
|
||||
ret = parse_feature_irqs(binfo, ofst, fid, &irq_base, &nr_irqs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
finfo = kzalloc(sizeof(*finfo), GFP_KERNEL);
|
||||
finfo = kzalloc(struct_size(finfo, params, dfh_psize / sizeof(u64)), GFP_KERNEL);
|
||||
if (!finfo)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy_fromio(finfo->params, binfo->ioaddr + ofst + DFHv1_PARAM_HDR, dfh_psize);
|
||||
finfo->param_size = dfh_psize;
|
||||
|
||||
finfo->fid = fid;
|
||||
finfo->revision = revision;
|
||||
finfo->mmio_res.start = binfo->start + ofst;
|
||||
finfo->mmio_res.end = finfo->mmio_res.start + size - 1;
|
||||
finfo->dfh_version = dfh_ver;
|
||||
if (dfh_ver == 1) {
|
||||
v = readq(binfo->ioaddr + ofst + DFHv1_CSR_ADDR);
|
||||
addr_off = FIELD_GET(DFHv1_CSR_ADDR_MASK, v);
|
||||
if (FIELD_GET(DFHv1_CSR_ADDR_REL, v))
|
||||
start = addr_off << 1;
|
||||
else
|
||||
start = binfo->start + ofst + addr_off;
|
||||
|
||||
v = readq(binfo->ioaddr + ofst + DFHv1_CSR_SIZE_GRP);
|
||||
end = start + FIELD_GET(DFHv1_CSR_SIZE_GRP_SIZE, v) - 1;
|
||||
} else {
|
||||
start = binfo->start + ofst;
|
||||
end = start + size - 1;
|
||||
}
|
||||
finfo->mmio_res.flags = IORESOURCE_MEM;
|
||||
finfo->irq_base = irq_base;
|
||||
finfo->nr_irqs = nr_irqs;
|
||||
finfo->mmio_res.start = start;
|
||||
finfo->mmio_res.end = end;
|
||||
|
||||
ret = parse_feature_irqs(binfo, ofst, finfo);
|
||||
if (ret) {
|
||||
kfree(finfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
list_add_tail(&finfo->node, &binfo->sub_features);
|
||||
binfo->feature_num++;
|
||||
|
@ -74,11 +74,47 @@
|
||||
#define DFH_REVISION GENMASK_ULL(15, 12) /* Feature revision */
|
||||
#define DFH_NEXT_HDR_OFST GENMASK_ULL(39, 16) /* Offset to next DFH */
|
||||
#define DFH_EOL BIT_ULL(40) /* End of list */
|
||||
#define DFH_VERSION GENMASK_ULL(59, 52) /* DFH version */
|
||||
#define DFH_TYPE GENMASK_ULL(63, 60) /* Feature type */
|
||||
#define DFH_TYPE_AFU 1
|
||||
#define DFH_TYPE_PRIVATE 3
|
||||
#define DFH_TYPE_FIU 4
|
||||
|
||||
/*
|
||||
* DFHv1 Register Offset definitons
|
||||
* In DHFv1, DFH + GUID + CSR_START + CSR_SIZE_GROUP + PARAM_HDR + PARAM_DATA
|
||||
* as common header registers
|
||||
*/
|
||||
#define DFHv1_CSR_ADDR 0x18 /* CSR Register start address */
|
||||
#define DFHv1_CSR_SIZE_GRP 0x20 /* Size of Reg Block and Group/tag */
|
||||
#define DFHv1_PARAM_HDR 0x28 /* Optional First Param header */
|
||||
|
||||
/*
|
||||
* CSR Rel Bit, 1'b0 = relative (offset from feature DFH start),
|
||||
* 1'b1 = absolute (ARM or other non-PCIe use)
|
||||
*/
|
||||
#define DFHv1_CSR_ADDR_REL BIT_ULL(0)
|
||||
|
||||
/* CSR Header Register Bit Definitions */
|
||||
#define DFHv1_CSR_ADDR_MASK GENMASK_ULL(63, 1) /* 63:1 of CSR address */
|
||||
|
||||
/* CSR SIZE Goup Register Bit Definitions */
|
||||
#define DFHv1_CSR_SIZE_GRP_INSTANCE_ID GENMASK_ULL(15, 0) /* Enumeration instantiated IP */
|
||||
#define DFHv1_CSR_SIZE_GRP_GROUPING_ID GENMASK_ULL(30, 16) /* Group Features/interfaces */
|
||||
#define DFHv1_CSR_SIZE_GRP_HAS_PARAMS BIT_ULL(31) /* Presence of Parameters */
|
||||
#define DFHv1_CSR_SIZE_GRP_SIZE GENMASK_ULL(63, 32) /* Size of CSR Block in bytes */
|
||||
|
||||
/* PARAM Header Register Bit Definitions */
|
||||
#define DFHv1_PARAM_HDR_ID GENMASK_ULL(15, 0) /* Id of this Param */
|
||||
#define DFHv1_PARAM_HDR_VER GENMASK_ULL(31, 16) /* Version Param */
|
||||
#define DFHv1_PARAM_HDR_NEXT_OFFSET GENMASK_ULL(63, 35) /* Offset of next Param */
|
||||
#define DFHv1_PARAM_HDR_NEXT_EOP BIT_ULL(32)
|
||||
#define DFHv1_PARAM_DATA 0x08 /* Offset of Param data from Param header */
|
||||
|
||||
#define DFHv1_PARAM_ID_MSI_X 0x1
|
||||
#define DFHv1_PARAM_MSI_X_NUMV GENMASK_ULL(63, 32)
|
||||
#define DFHv1_PARAM_MSI_X_STARTV GENMASK_ULL(31, 0)
|
||||
|
||||
/* Next AFU Register Bitfield */
|
||||
#define NEXT_AFU_NEXT_DFH_OFST GENMASK_ULL(23, 0) /* Offset to next AFU */
|
||||
|
||||
@ -231,6 +267,7 @@ struct dfl_feature_irq_ctx {
|
||||
*
|
||||
* @dev: ptr to pdev of the feature device which has the sub feature.
|
||||
* @id: sub feature id.
|
||||
* @revision: revisition of the instance of a feature.
|
||||
* @resource_index: each sub feature has one mmio resource for its registers.
|
||||
* this index is used to find its mmio resource from the
|
||||
* feature dev (platform device)'s resources.
|
||||
@ -240,6 +277,9 @@ struct dfl_feature_irq_ctx {
|
||||
* @ops: ops of this sub feature.
|
||||
* @ddev: ptr to the dfl device of this sub feature.
|
||||
* @priv: priv data of this feature.
|
||||
* @dfh_version: version of the DFH
|
||||
* @param_size: size of dfh parameters
|
||||
* @params: point to memory copy of dfh parameters
|
||||
*/
|
||||
struct dfl_feature {
|
||||
struct platform_device *dev;
|
||||
@ -252,6 +292,9 @@ struct dfl_feature {
|
||||
const struct dfl_feature_ops *ops;
|
||||
struct dfl_device *ddev;
|
||||
void *priv;
|
||||
u8 dfh_version;
|
||||
unsigned int param_size;
|
||||
void *params;
|
||||
};
|
||||
|
||||
#define FEATURE_DEV_ID_UNUSED (-1)
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/qcom-geni-se.h>
|
||||
#include <linux/soc/qcom/geni-se.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define SE_I2C_TX_TRANS_LEN 0x26c
|
||||
|
@ -647,7 +647,7 @@ static void ipoctal_hangup(struct tty_struct *tty)
|
||||
tty_port_hangup(&channel->tty_port);
|
||||
|
||||
ipoctal_reset_channel(channel);
|
||||
tty_port_set_initialized(&channel->tty_port, 0);
|
||||
tty_port_set_initialized(&channel->tty_port, false);
|
||||
wake_up_interruptible(&channel->tty_port.open_wait);
|
||||
}
|
||||
|
||||
@ -659,7 +659,7 @@ static void ipoctal_shutdown(struct tty_struct *tty)
|
||||
return;
|
||||
|
||||
ipoctal_reset_channel(channel);
|
||||
tty_port_set_initialized(&channel->tty_port, 0);
|
||||
tty_port_set_initialized(&channel->tty_port, false);
|
||||
}
|
||||
|
||||
static void ipoctal_cleanup(struct tty_struct *tty)
|
||||
|
@ -526,7 +526,7 @@ static void sdio_uart_irq(struct sdio_func *func)
|
||||
port->in_sdio_uart_irq = NULL;
|
||||
}
|
||||
|
||||
static int uart_carrier_raised(struct tty_port *tport)
|
||||
static bool uart_carrier_raised(struct tty_port *tport)
|
||||
{
|
||||
struct sdio_uart_port *port =
|
||||
container_of(tport, struct sdio_uart_port, port);
|
||||
@ -535,28 +535,27 @@ static int uart_carrier_raised(struct tty_port *tport)
|
||||
return 1;
|
||||
ret = sdio_uart_get_mctrl(port);
|
||||
sdio_uart_release_func(port);
|
||||
if (ret & TIOCM_CAR)
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
return ret & TIOCM_CAR;
|
||||
}
|
||||
|
||||
/**
|
||||
* uart_dtr_rts - port helper to set uart signals
|
||||
* @tport: tty port to be updated
|
||||
* @onoff: set to turn on DTR/RTS
|
||||
* @active: set to turn on DTR/RTS
|
||||
*
|
||||
* Called by the tty port helpers when the modem signals need to be
|
||||
* adjusted during an open, close and hangup.
|
||||
*/
|
||||
|
||||
static void uart_dtr_rts(struct tty_port *tport, int onoff)
|
||||
static void uart_dtr_rts(struct tty_port *tport, bool active)
|
||||
{
|
||||
struct sdio_uart_port *port =
|
||||
container_of(tport, struct sdio_uart_port, port);
|
||||
int ret = sdio_uart_claim_func(port);
|
||||
if (ret)
|
||||
return;
|
||||
if (onoff == 0)
|
||||
if (!active)
|
||||
sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
|
||||
else
|
||||
sdio_uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include <linux/pps_kernel.h>
|
||||
#include <linux/bug.h>
|
||||
|
||||
static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status)
|
||||
static void pps_tty_dcd_change(struct tty_struct *tty, bool active)
|
||||
{
|
||||
struct pps_device *pps;
|
||||
struct pps_event_time ts;
|
||||
@ -29,11 +29,11 @@ static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status)
|
||||
return;
|
||||
|
||||
/* Now do the PPS event report */
|
||||
pps_event(pps, &ts, status ? PPS_CAPTUREASSERT :
|
||||
pps_event(pps, &ts, active ? PPS_CAPTUREASSERT :
|
||||
PPS_CAPTURECLEAR, NULL);
|
||||
|
||||
dev_dbg(pps->dev, "PPS %s at %lu\n",
|
||||
status ? "assert" : "clear", jiffies);
|
||||
active ? "assert" : "clear", jiffies);
|
||||
}
|
||||
|
||||
static int (*alias_n_tty_open)(struct tty_struct *tty);
|
||||
|
@ -629,7 +629,7 @@ static int raw3215_startup(struct raw3215_info *raw)
|
||||
if (tty_port_initialized(&raw->port))
|
||||
return 0;
|
||||
raw->line_pos = 0;
|
||||
tty_port_set_initialized(&raw->port, 1);
|
||||
tty_port_set_initialized(&raw->port, true);
|
||||
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
|
||||
raw3215_try_io(raw);
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
|
||||
@ -659,7 +659,7 @@ static void raw3215_shutdown(struct raw3215_info *raw)
|
||||
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
|
||||
remove_wait_queue(&raw->empty_wait, &wait);
|
||||
set_current_state(TASK_RUNNING);
|
||||
tty_port_set_initialized(&raw->port, 1);
|
||||
tty_port_set_initialized(&raw->port, true);
|
||||
}
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/qcom-geni-se.h>
|
||||
#include <linux/soc/qcom/geni-se.h>
|
||||
|
||||
/**
|
||||
* DOC: Overview
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/qcom-geni-se.h>
|
||||
#include <linux/soc/qcom/geni-se.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
|
@ -701,7 +701,7 @@ static int gb_tty_ioctl(struct tty_struct *tty, unsigned int cmd,
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
static void gb_tty_dtr_rts(struct tty_port *port, int on)
|
||||
static void gb_tty_dtr_rts(struct tty_port *port, bool active)
|
||||
{
|
||||
struct gb_tty *gb_tty;
|
||||
u8 newctrl;
|
||||
@ -709,7 +709,7 @@ static void gb_tty_dtr_rts(struct tty_port *port, int on)
|
||||
gb_tty = container_of(port, struct gb_tty, port);
|
||||
newctrl = gb_tty->ctrlout;
|
||||
|
||||
if (on)
|
||||
if (active)
|
||||
newctrl |= (GB_UART_CTRL_DTR | GB_UART_CTRL_RTS);
|
||||
else
|
||||
newctrl &= ~(GB_UART_CTRL_DTR | GB_UART_CTRL_RTS);
|
||||
|
@ -502,7 +502,7 @@ static int startup(struct tty_struct *tty, struct serial_state *info)
|
||||
*/
|
||||
change_speed(tty, info, NULL);
|
||||
|
||||
tty_port_set_initialized(port, 1);
|
||||
tty_port_set_initialized(port, true);
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
|
||||
@ -556,7 +556,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info)
|
||||
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
|
||||
tty_port_set_initialized(&info->tport, 0);
|
||||
tty_port_set_initialized(&info->tport, false);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
@ -1329,7 +1329,7 @@ static void rs_hangup(struct tty_struct *tty)
|
||||
rs_flush_buffer(tty);
|
||||
shutdown(tty, info);
|
||||
info->tport.count = 0;
|
||||
tty_port_set_active(&info->tport, 0);
|
||||
tty_port_set_active(&info->tport, false);
|
||||
info->tport.tty = NULL;
|
||||
wake_up_interruptible(&info->tport.open_wait);
|
||||
}
|
||||
@ -1454,18 +1454,18 @@ static const struct tty_operations serial_ops = {
|
||||
.proc_show = rs_proc_show,
|
||||
};
|
||||
|
||||
static int amiga_carrier_raised(struct tty_port *port)
|
||||
static bool amiga_carrier_raised(struct tty_port *port)
|
||||
{
|
||||
return !(ciab.pra & SER_DCD);
|
||||
}
|
||||
|
||||
static void amiga_dtr_rts(struct tty_port *port, int raise)
|
||||
static void amiga_dtr_rts(struct tty_port *port, bool active)
|
||||
{
|
||||
struct serial_state *info = container_of(port, struct serial_state,
|
||||
tport);
|
||||
unsigned long flags;
|
||||
|
||||
if (raise)
|
||||
if (active)
|
||||
info->MCR |= SER_DTR|SER_RTS;
|
||||
else
|
||||
info->MCR &= ~(SER_DTR|SER_RTS);
|
||||
|
@ -376,7 +376,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
|
||||
/* We are ready... raise DTR/RTS */
|
||||
if (C_BAUD(tty))
|
||||
if (hp->ops->dtr_rts)
|
||||
hp->ops->dtr_rts(hp, 1);
|
||||
hp->ops->dtr_rts(hp, true);
|
||||
tty_port_set_initialized(&hp->port, true);
|
||||
}
|
||||
|
||||
@ -406,7 +406,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
|
||||
|
||||
if (C_HUPCL(tty))
|
||||
if (hp->ops->dtr_rts)
|
||||
hp->ops->dtr_rts(hp, 0);
|
||||
hp->ops->dtr_rts(hp, false);
|
||||
|
||||
if (hp->ops->notifier_del)
|
||||
hp->ops->notifier_del(hp, hp->data);
|
||||
|
@ -66,7 +66,7 @@ struct hv_ops {
|
||||
int (*tiocmset)(struct hvc_struct *hp, unsigned int set, unsigned int clear);
|
||||
|
||||
/* Callbacks to handle tty ports */
|
||||
void (*dtr_rts)(struct hvc_struct *hp, int raise);
|
||||
void (*dtr_rts)(struct hvc_struct *hp, bool active);
|
||||
};
|
||||
|
||||
/* Register a vterm and a slot index for use as a console (console_init) */
|
||||
|
@ -658,13 +658,13 @@ static void hvc_iucv_notifier_hangup(struct hvc_struct *hp, int id)
|
||||
/**
|
||||
* hvc_iucv_dtr_rts() - HVC notifier for handling DTR/RTS
|
||||
* @hp: Pointer the HVC device (struct hvc_struct)
|
||||
* @raise: Non-zero to raise or zero to lower DTR/RTS lines
|
||||
* @active: True to raise or false to lower DTR/RTS lines
|
||||
*
|
||||
* This routine notifies the HVC back-end to raise or lower DTR/RTS
|
||||
* lines. Raising DTR/RTS is ignored. Lowering DTR/RTS indicates to
|
||||
* drop the IUCV connection (similar to hang up the modem).
|
||||
*/
|
||||
static void hvc_iucv_dtr_rts(struct hvc_struct *hp, int raise)
|
||||
static void hvc_iucv_dtr_rts(struct hvc_struct *hp, bool active)
|
||||
{
|
||||
struct hvc_iucv_private *priv;
|
||||
struct iucv_path *path;
|
||||
@ -672,7 +672,7 @@ static void hvc_iucv_dtr_rts(struct hvc_struct *hp, int raise)
|
||||
/* Raising the DTR/RTS is ignored as IUCV connections can be
|
||||
* established at any times.
|
||||
*/
|
||||
if (raise)
|
||||
if (active)
|
||||
return;
|
||||
|
||||
priv = hvc_iucv_get_private(hp->vtermno);
|
||||
|
@ -52,6 +52,7 @@
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kref.h>
|
||||
@ -285,6 +286,7 @@ struct hvcs_struct {
|
||||
char p_location_code[HVCS_CLC_LENGTH + 1]; /* CLC + Null Term */
|
||||
struct list_head next; /* list management */
|
||||
struct vio_dev *vdev;
|
||||
struct completion *destroyed;
|
||||
};
|
||||
|
||||
static LIST_HEAD(hvcs_structs);
|
||||
@ -432,7 +434,7 @@ static ssize_t hvcs_index_show(struct device *dev, struct device_attribute *attr
|
||||
|
||||
static DEVICE_ATTR(index, S_IRUGO, hvcs_index_show, NULL);
|
||||
|
||||
static struct attribute *hvcs_attrs[] = {
|
||||
static struct attribute *hvcs_dev_attrs[] = {
|
||||
&dev_attr_partner_vtys.attr,
|
||||
&dev_attr_partner_clcs.attr,
|
||||
&dev_attr_current_vty.attr,
|
||||
@ -441,9 +443,7 @@ static struct attribute *hvcs_attrs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group hvcs_attr_group = {
|
||||
.attrs = hvcs_attrs,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(hvcs_dev);
|
||||
|
||||
static ssize_t rescan_show(struct device_driver *ddp, char *buf)
|
||||
{
|
||||
@ -468,6 +468,13 @@ static ssize_t rescan_store(struct device_driver *ddp, const char * buf,
|
||||
|
||||
static DRIVER_ATTR_RW(rescan);
|
||||
|
||||
static struct attribute *hvcs_attrs[] = {
|
||||
&driver_attr_rescan.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
ATTRIBUTE_GROUPS(hvcs);
|
||||
|
||||
static void hvcs_kick(void)
|
||||
{
|
||||
hvcs_kicked = 1;
|
||||
@ -658,11 +665,13 @@ static void hvcs_destruct_port(struct tty_port *p)
|
||||
{
|
||||
struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port);
|
||||
struct vio_dev *vdev;
|
||||
struct completion *comp;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock(&hvcs_structs_lock);
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
|
||||
comp = hvcsd->destroyed;
|
||||
/* the list_del poisons the pointers */
|
||||
list_del(&(hvcsd->next));
|
||||
|
||||
@ -682,15 +691,16 @@ static void hvcs_destruct_port(struct tty_port *p)
|
||||
|
||||
hvcsd->p_unit_address = 0;
|
||||
hvcsd->p_partition_ID = 0;
|
||||
hvcsd->destroyed = NULL;
|
||||
hvcs_return_index(hvcsd->index);
|
||||
memset(&hvcsd->p_location_code[0], 0x00, HVCS_CLC_LENGTH + 1);
|
||||
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
spin_unlock(&hvcs_structs_lock);
|
||||
|
||||
sysfs_remove_group(&vdev->dev.kobj, &hvcs_attr_group);
|
||||
|
||||
kfree(hvcsd);
|
||||
if (comp)
|
||||
complete(comp);
|
||||
}
|
||||
|
||||
static const struct tty_port_operations hvcs_port_ops = {
|
||||
@ -721,7 +731,6 @@ static int hvcs_probe(
|
||||
{
|
||||
struct hvcs_struct *hvcsd;
|
||||
int index, rc;
|
||||
int retval;
|
||||
|
||||
if (!dev || !id) {
|
||||
printk(KERN_ERR "HVCS: probed with invalid parameter.\n");
|
||||
@ -778,13 +787,6 @@ static int hvcs_probe(
|
||||
list_add_tail(&(hvcsd->next), &hvcs_structs);
|
||||
spin_unlock(&hvcs_structs_lock);
|
||||
|
||||
retval = sysfs_create_group(&dev->dev.kobj, &hvcs_attr_group);
|
||||
if (retval) {
|
||||
printk(KERN_ERR "HVCS: Can't create sysfs attrs for vty-server@%X\n",
|
||||
hvcsd->vdev->unit_address);
|
||||
return retval;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "HVCS: vty-server@%X added to the vio bus.\n", dev->unit_address);
|
||||
|
||||
/*
|
||||
@ -797,6 +799,7 @@ static int hvcs_probe(
|
||||
static void hvcs_remove(struct vio_dev *dev)
|
||||
{
|
||||
struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev);
|
||||
DECLARE_COMPLETION_ONSTACK(comp);
|
||||
unsigned long flags;
|
||||
struct tty_struct *tty;
|
||||
|
||||
@ -804,24 +807,22 @@ static void hvcs_remove(struct vio_dev *dev)
|
||||
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
|
||||
tty = hvcsd->port.tty;
|
||||
hvcsd->destroyed = ∁
|
||||
tty = tty_port_tty_get(&hvcsd->port);
|
||||
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
|
||||
/*
|
||||
* Let the last holder of this object cause it to be removed, which
|
||||
* would probably be tty_hangup below.
|
||||
*/
|
||||
tty_port_put(&hvcsd->port);
|
||||
|
||||
/*
|
||||
* The hangup is a scheduled function which will auto chain call
|
||||
* hvcs_hangup. The tty should always be valid at this time unless a
|
||||
* The tty should always be valid at this time unless a
|
||||
* simultaneous tty close already cleaned up the hvcs_struct.
|
||||
*/
|
||||
if (tty)
|
||||
tty_hangup(tty);
|
||||
if (tty) {
|
||||
tty_vhangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
tty_port_put(&hvcsd->port);
|
||||
wait_for_completion(&comp);
|
||||
printk(KERN_INFO "HVCS: vty-server@%X removed from the"
|
||||
" vio bus.\n", dev->unit_address);
|
||||
};
|
||||
@ -831,6 +832,10 @@ static struct vio_driver hvcs_vio_driver = {
|
||||
.probe = hvcs_probe,
|
||||
.remove = hvcs_remove,
|
||||
.name = hvcs_driver_name,
|
||||
.driver = {
|
||||
.groups = hvcs_groups,
|
||||
.dev_groups = hvcs_dev_groups,
|
||||
},
|
||||
};
|
||||
|
||||
/* Only called from hvcs_get_pi please */
|
||||
@ -1171,7 +1176,10 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
|
||||
hvcsd = tty->driver_data;
|
||||
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
if (--hvcsd->port.count == 0) {
|
||||
if (hvcsd->port.count == 0) {
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
return;
|
||||
} else if (--hvcsd->port.count == 0) {
|
||||
|
||||
vio_disable_interrupts(hvcsd->vdev);
|
||||
|
||||
@ -1215,12 +1223,9 @@ static void hvcs_hangup(struct tty_struct * tty)
|
||||
{
|
||||
struct hvcs_struct *hvcsd = tty->driver_data;
|
||||
unsigned long flags;
|
||||
int temp_open_count;
|
||||
int irq;
|
||||
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
/* Preserve this so that we know how many kref refs to put */
|
||||
temp_open_count = hvcsd->port.count;
|
||||
|
||||
/*
|
||||
* Don't kref put inside the spinlock because the destruction
|
||||
@ -1230,11 +1235,7 @@ static void hvcs_hangup(struct tty_struct * tty)
|
||||
vio_disable_interrupts(hvcsd->vdev);
|
||||
|
||||
hvcsd->todo_mask = 0;
|
||||
|
||||
/* I don't think the tty needs the hvcs_struct pointer after a hangup */
|
||||
tty->driver_data = NULL;
|
||||
hvcsd->port.tty = NULL;
|
||||
|
||||
hvcsd->port.count = 0;
|
||||
|
||||
/* This will drop any buffered data on the floor which is OK in a hangup
|
||||
@ -1247,21 +1248,6 @@ static void hvcs_hangup(struct tty_struct * tty)
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
|
||||
free_irq(irq, hvcsd);
|
||||
|
||||
/*
|
||||
* We need to kref_put() for every open_count we have since the
|
||||
* tty_hangup() function doesn't invoke a close per open connection on a
|
||||
* non-console device.
|
||||
*/
|
||||
while(temp_open_count) {
|
||||
--temp_open_count;
|
||||
/*
|
||||
* The final put will trigger destruction of the hvcs_struct.
|
||||
* NOTE: If this hangup was signaled from user space then the
|
||||
* final put will never happen.
|
||||
*/
|
||||
tty_port_put(&hvcsd->port);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1525,13 +1511,6 @@ static int __init hvcs_module_init(void)
|
||||
|
||||
pr_info("HVCS: Driver registered.\n");
|
||||
|
||||
/* This needs to be done AFTER the vio_register_driver() call or else
|
||||
* the kobjects won't be initialized properly.
|
||||
*/
|
||||
rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan);
|
||||
if (rc)
|
||||
pr_warn("HVCS: Failed to create rescan file (err %d)\n", rc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1556,8 +1535,6 @@ static void __exit hvcs_module_exit(void)
|
||||
hvcs_pi_buff = NULL;
|
||||
spin_unlock(&hvcs_pi_lock);
|
||||
|
||||
driver_remove_file(&hvcs_vio_driver.driver, &driver_attr_rescan);
|
||||
|
||||
tty_unregister_driver(hvcs_tty_driver);
|
||||
|
||||
hvcs_free_index_list();
|
||||
|
@ -501,16 +501,16 @@ static int moxa_tiocmset(struct tty_struct *tty,
|
||||
static void moxa_poll(struct timer_list *);
|
||||
static void moxa_set_tty_param(struct tty_struct *, const struct ktermios *);
|
||||
static void moxa_shutdown(struct tty_port *);
|
||||
static int moxa_carrier_raised(struct tty_port *);
|
||||
static void moxa_dtr_rts(struct tty_port *, int);
|
||||
static bool moxa_carrier_raised(struct tty_port *);
|
||||
static void moxa_dtr_rts(struct tty_port *, bool);
|
||||
/*
|
||||
* moxa board interface functions:
|
||||
*/
|
||||
static void MoxaPortEnable(struct moxa_port *);
|
||||
static void MoxaPortDisable(struct moxa_port *);
|
||||
static int MoxaPortSetTermio(struct moxa_port *, struct ktermios *, speed_t);
|
||||
static int MoxaPortGetLineOut(struct moxa_port *, int *, int *);
|
||||
static void MoxaPortLineCtrl(struct moxa_port *, int, int);
|
||||
static int MoxaPortGetLineOut(struct moxa_port *, bool *, bool *);
|
||||
static void MoxaPortLineCtrl(struct moxa_port *, bool, bool);
|
||||
static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
|
||||
static int MoxaPortLineStatus(struct moxa_port *);
|
||||
static void MoxaPortFlushData(struct moxa_port *, int);
|
||||
@ -1432,7 +1432,7 @@ static void moxa_shutdown(struct tty_port *port)
|
||||
MoxaPortFlushData(ch, 2);
|
||||
}
|
||||
|
||||
static int moxa_carrier_raised(struct tty_port *port)
|
||||
static bool moxa_carrier_raised(struct tty_port *port)
|
||||
{
|
||||
struct moxa_port *ch = container_of(port, struct moxa_port, port);
|
||||
int dcd;
|
||||
@ -1443,10 +1443,10 @@ static int moxa_carrier_raised(struct tty_port *port)
|
||||
return dcd;
|
||||
}
|
||||
|
||||
static void moxa_dtr_rts(struct tty_port *port, int onoff)
|
||||
static void moxa_dtr_rts(struct tty_port *port, bool active)
|
||||
{
|
||||
struct moxa_port *ch = container_of(port, struct moxa_port, port);
|
||||
MoxaPortLineCtrl(ch, onoff, onoff);
|
||||
MoxaPortLineCtrl(ch, active, active);
|
||||
}
|
||||
|
||||
|
||||
@ -1481,10 +1481,10 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
|
||||
if (!tty_port_initialized(&ch->port)) {
|
||||
ch->statusflags = 0;
|
||||
moxa_set_tty_param(tty, &tty->termios);
|
||||
MoxaPortLineCtrl(ch, 1, 1);
|
||||
MoxaPortLineCtrl(ch, true, true);
|
||||
MoxaPortEnable(ch);
|
||||
MoxaSetFifo(ch, ch->type == PORT_16550A);
|
||||
tty_port_set_initialized(&ch->port, 1);
|
||||
tty_port_set_initialized(&ch->port, true);
|
||||
}
|
||||
mutex_unlock(&ch->port.mutex);
|
||||
mutex_unlock(&moxa_openlock);
|
||||
@ -1557,19 +1557,21 @@ static unsigned int moxa_chars_in_buffer(struct tty_struct *tty)
|
||||
static int moxa_tiocmget(struct tty_struct *tty)
|
||||
{
|
||||
struct moxa_port *ch = tty->driver_data;
|
||||
int flag = 0, dtr, rts;
|
||||
bool dtr_active, rts_active;
|
||||
int flag = 0;
|
||||
int status;
|
||||
|
||||
MoxaPortGetLineOut(ch, &dtr, &rts);
|
||||
if (dtr)
|
||||
MoxaPortGetLineOut(ch, &dtr_active, &rts_active);
|
||||
if (dtr_active)
|
||||
flag |= TIOCM_DTR;
|
||||
if (rts)
|
||||
if (rts_active)
|
||||
flag |= TIOCM_RTS;
|
||||
dtr = MoxaPortLineStatus(ch);
|
||||
if (dtr & 1)
|
||||
status = MoxaPortLineStatus(ch);
|
||||
if (status & 1)
|
||||
flag |= TIOCM_CTS;
|
||||
if (dtr & 2)
|
||||
if (status & 2)
|
||||
flag |= TIOCM_DSR;
|
||||
if (dtr & 4)
|
||||
if (status & 4)
|
||||
flag |= TIOCM_CD;
|
||||
return flag;
|
||||
}
|
||||
@ -1577,8 +1579,8 @@ static int moxa_tiocmget(struct tty_struct *tty)
|
||||
static int moxa_tiocmset(struct tty_struct *tty,
|
||||
unsigned int set, unsigned int clear)
|
||||
{
|
||||
bool dtr_active, rts_active;
|
||||
struct moxa_port *ch;
|
||||
int dtr, rts;
|
||||
|
||||
mutex_lock(&moxa_openlock);
|
||||
ch = tty->driver_data;
|
||||
@ -1587,16 +1589,16 @@ static int moxa_tiocmset(struct tty_struct *tty,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
MoxaPortGetLineOut(ch, &dtr, &rts);
|
||||
MoxaPortGetLineOut(ch, &dtr_active, &rts_active);
|
||||
if (set & TIOCM_RTS)
|
||||
rts = 1;
|
||||
rts_active = true;
|
||||
if (set & TIOCM_DTR)
|
||||
dtr = 1;
|
||||
dtr_active = true;
|
||||
if (clear & TIOCM_RTS)
|
||||
rts = 0;
|
||||
rts_active = false;
|
||||
if (clear & TIOCM_DTR)
|
||||
dtr = 0;
|
||||
MoxaPortLineCtrl(ch, dtr, rts);
|
||||
dtr_active = false;
|
||||
MoxaPortLineCtrl(ch, dtr_active, rts_active);
|
||||
mutex_unlock(&moxa_openlock);
|
||||
return 0;
|
||||
}
|
||||
@ -1664,8 +1666,8 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
|
||||
u16 __iomem *ip)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(&p->port);
|
||||
bool inited = tty_port_initialized(&p->port);
|
||||
void __iomem *ofsAddr;
|
||||
unsigned int inited = tty_port_initialized(&p->port);
|
||||
u16 intr;
|
||||
|
||||
if (tty) {
|
||||
@ -1877,12 +1879,12 @@ static void MoxaPortFlushData(struct moxa_port *port, int mode)
|
||||
*
|
||||
* Function 13: Get the DTR/RTS state of this port.
|
||||
* Syntax:
|
||||
* int MoxaPortGetLineOut(int port, int *dtrState, int *rtsState);
|
||||
* int MoxaPortGetLineOut(int port, bool *dtrState, bool *rtsState);
|
||||
* int port : port number (0 - 127)
|
||||
* int * dtrState : pointer to INT to receive the current DTR
|
||||
* bool * dtr_active : pointer to bool to receive the current DTR
|
||||
* state. (if NULL, this function will not
|
||||
* write to this address)
|
||||
* int * rtsState : pointer to INT to receive the current RTS
|
||||
* bool * rts_active : pointer to bool to receive the current RTS
|
||||
* state. (if NULL, this function will not
|
||||
* write to this address)
|
||||
*
|
||||
@ -1892,10 +1894,10 @@ static void MoxaPortFlushData(struct moxa_port *port, int mode)
|
||||
*
|
||||
* Function 14: Setting the DTR/RTS output state of this port.
|
||||
* Syntax:
|
||||
* void MoxaPortLineCtrl(int port, int dtrState, int rtsState);
|
||||
* void MoxaPortLineCtrl(int port, bool dtrState, bool rtsState);
|
||||
* int port : port number (0 - 127)
|
||||
* int dtrState : DTR output state (0: off, 1: on)
|
||||
* int rtsState : RTS output state (0: off, 1: on)
|
||||
* bool dtr_active : DTR output state
|
||||
* bool rts_active : RTS output state
|
||||
*
|
||||
*
|
||||
* Function 15: Setting the flow control of this port.
|
||||
@ -2103,24 +2105,24 @@ static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio,
|
||||
return baud;
|
||||
}
|
||||
|
||||
static int MoxaPortGetLineOut(struct moxa_port *port, int *dtrState,
|
||||
int *rtsState)
|
||||
static int MoxaPortGetLineOut(struct moxa_port *port, bool *dtr_active,
|
||||
bool *rts_active)
|
||||
{
|
||||
if (dtrState)
|
||||
*dtrState = !!(port->lineCtrl & DTR_ON);
|
||||
if (rtsState)
|
||||
*rtsState = !!(port->lineCtrl & RTS_ON);
|
||||
if (dtr_active)
|
||||
*dtr_active = port->lineCtrl & DTR_ON;
|
||||
if (rts_active)
|
||||
*rts_active = port->lineCtrl & RTS_ON;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void MoxaPortLineCtrl(struct moxa_port *port, int dtr, int rts)
|
||||
static void MoxaPortLineCtrl(struct moxa_port *port, bool dtr_active, bool rts_active)
|
||||
{
|
||||
u8 mode = 0;
|
||||
|
||||
if (dtr)
|
||||
if (dtr_active)
|
||||
mode |= DTR_ON;
|
||||
if (rts)
|
||||
if (rts_active)
|
||||
mode |= RTS_ON;
|
||||
port->lineCtrl = mode;
|
||||
moxafunc(port->tableAddr, FC_LineControl, mode);
|
||||
|
@ -458,13 +458,14 @@ static void __mxser_stop_tx(struct mxser_port *info)
|
||||
outb(info->IER, info->ioaddr + UART_IER);
|
||||
}
|
||||
|
||||
static int mxser_carrier_raised(struct tty_port *port)
|
||||
static bool mxser_carrier_raised(struct tty_port *port)
|
||||
{
|
||||
struct mxser_port *mp = container_of(port, struct mxser_port, port);
|
||||
return (inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD)?1:0;
|
||||
|
||||
return inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD;
|
||||
}
|
||||
|
||||
static void mxser_dtr_rts(struct tty_port *port, int on)
|
||||
static void mxser_dtr_rts(struct tty_port *port, bool active)
|
||||
{
|
||||
struct mxser_port *mp = container_of(port, struct mxser_port, port);
|
||||
unsigned long flags;
|
||||
@ -472,7 +473,7 @@ static void mxser_dtr_rts(struct tty_port *port, int on)
|
||||
|
||||
spin_lock_irqsave(&mp->slock, flags);
|
||||
mcr = inb(mp->ioaddr + UART_MCR);
|
||||
if (on)
|
||||
if (active)
|
||||
mcr |= UART_MCR_DTR | UART_MCR_RTS;
|
||||
else
|
||||
mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
|
||||
@ -1063,7 +1064,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
|
||||
} else {
|
||||
retval = mxser_activate(port, tty);
|
||||
if (retval == 0)
|
||||
tty_port_set_initialized(port, 1);
|
||||
tty_port_set_initialized(port, true);
|
||||
}
|
||||
mutex_unlock(&port->mutex);
|
||||
return retval;
|
||||
|
@ -318,6 +318,11 @@ struct gsm_mux {
|
||||
struct gsm_control *pending_cmd;/* Our current pending command */
|
||||
spinlock_t control_lock; /* Protects the pending command */
|
||||
|
||||
/* Keep-alive */
|
||||
struct timer_list ka_timer; /* Keep-alive response timer */
|
||||
u8 ka_num; /* Keep-alive match pattern */
|
||||
signed int ka_retries; /* Keep-alive retry counter, -1 if not yet initialized */
|
||||
|
||||
/* Configuration */
|
||||
int adaption; /* 1 or 2 supported */
|
||||
u8 ftype; /* UI or UIH */
|
||||
@ -325,6 +330,7 @@ struct gsm_mux {
|
||||
unsigned int t3; /* Power wake-up timer in seconds. */
|
||||
int n2; /* Retry count */
|
||||
u8 k; /* Window size */
|
||||
u32 keep_alive; /* Control channel keep-alive in 10ms */
|
||||
|
||||
/* Statistics (not currently exposed) */
|
||||
unsigned long bad_fcs;
|
||||
@ -540,6 +546,11 @@ static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
|
||||
modembits |= MDM_IC;
|
||||
if (dlci->modem_tx & TIOCM_CD || dlci->gsm->initiator)
|
||||
modembits |= MDM_DV;
|
||||
/* special mappings for passive side to operate as UE */
|
||||
if (dlci->modem_tx & TIOCM_OUT1)
|
||||
modembits |= MDM_IC;
|
||||
if (dlci->modem_tx & TIOCM_OUT2)
|
||||
modembits |= MDM_DV;
|
||||
return modembits;
|
||||
}
|
||||
|
||||
@ -1531,6 +1542,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
|
||||
if (brk & 0x01)
|
||||
tty_insert_flip_char(&dlci->port, 0, TTY_BREAK);
|
||||
dlci->modem_rx = mlines;
|
||||
wake_up_interruptible(&dlci->gsm->event);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1897,11 +1909,13 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
|
||||
const u8 *data, int clen)
|
||||
{
|
||||
struct gsm_control *ctrl;
|
||||
struct gsm_dlci *dlci;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gsm->control_lock, flags);
|
||||
|
||||
ctrl = gsm->pending_cmd;
|
||||
dlci = gsm->dlci[0];
|
||||
command |= 1;
|
||||
/* Does the reply match our command */
|
||||
if (ctrl != NULL && (command == ctrl->cmd || command == CMD_NSC)) {
|
||||
@ -1916,6 +1930,53 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
|
||||
/* Or did we receive the PN response to our PN command */
|
||||
} else if (command == CMD_PN) {
|
||||
gsm_control_negotiation(gsm, 0, data, clen);
|
||||
/* Or did we receive the TEST response to our TEST command */
|
||||
} else if (command == CMD_TEST && clen == 1 && *data == gsm->ka_num) {
|
||||
gsm->ka_retries = -1; /* trigger new keep-alive message */
|
||||
if (dlci && !dlci->dead)
|
||||
mod_timer(&gsm->ka_timer, jiffies + gsm->keep_alive * HZ / 100);
|
||||
}
|
||||
spin_unlock_irqrestore(&gsm->control_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsm_control_keep_alive - check timeout or start keep-alive
|
||||
* @t: timer contained in our gsm object
|
||||
*
|
||||
* Called off the keep-alive timer expiry signaling that our link
|
||||
* partner is not responding anymore. Link will be closed.
|
||||
* This is also called to startup our timer.
|
||||
*/
|
||||
|
||||
static void gsm_control_keep_alive(struct timer_list *t)
|
||||
{
|
||||
struct gsm_mux *gsm = from_timer(gsm, t, ka_timer);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gsm->control_lock, flags);
|
||||
if (gsm->ka_num && gsm->ka_retries == 0) {
|
||||
/* Keep-alive expired -> close the link */
|
||||
if (debug & DBG_ERRORS)
|
||||
pr_debug("%s keep-alive timed out\n", __func__);
|
||||
spin_unlock_irqrestore(&gsm->control_lock, flags);
|
||||
if (gsm->dlci[0])
|
||||
gsm_dlci_begin_close(gsm->dlci[0]);
|
||||
return;
|
||||
} else if (gsm->keep_alive && gsm->dlci[0] && !gsm->dlci[0]->dead) {
|
||||
if (gsm->ka_retries > 0) {
|
||||
/* T2 expired for keep-alive -> resend */
|
||||
gsm->ka_retries--;
|
||||
} else {
|
||||
/* Start keep-alive timer */
|
||||
gsm->ka_num++;
|
||||
if (!gsm->ka_num)
|
||||
gsm->ka_num++;
|
||||
gsm->ka_retries = (signed int)gsm->n2;
|
||||
}
|
||||
gsm_control_command(gsm, CMD_TEST, &gsm->ka_num,
|
||||
sizeof(gsm->ka_num));
|
||||
mod_timer(&gsm->ka_timer,
|
||||
jiffies + gsm->t2 * HZ / 100);
|
||||
}
|
||||
spin_unlock_irqrestore(&gsm->control_lock, flags);
|
||||
}
|
||||
@ -2059,14 +2120,16 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
|
||||
tty_port_tty_hangup(&dlci->port, false);
|
||||
gsm_dlci_clear_queues(dlci->gsm, dlci);
|
||||
/* Ensure that gsmtty_open() can return. */
|
||||
tty_port_set_initialized(&dlci->port, 0);
|
||||
tty_port_set_initialized(&dlci->port, false);
|
||||
wake_up_interruptible(&dlci->port.open_wait);
|
||||
} else
|
||||
} else {
|
||||
del_timer(&dlci->gsm->ka_timer);
|
||||
dlci->gsm->dead = true;
|
||||
}
|
||||
/* A DLCI 0 close is a MUX termination so we need to kick that
|
||||
back to userspace somehow */
|
||||
gsm_dlci_data_kick(dlci);
|
||||
wake_up(&dlci->gsm->event);
|
||||
wake_up_all(&dlci->gsm->event);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2078,6 +2141,8 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
|
||||
|
||||
static void gsm_dlci_open(struct gsm_dlci *dlci)
|
||||
{
|
||||
struct gsm_mux *gsm = dlci->gsm;
|
||||
|
||||
/* Note that SABM UA .. SABM UA first UA lost can mean that we go
|
||||
open -> open */
|
||||
del_timer(&dlci->t1);
|
||||
@ -2087,8 +2152,15 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
|
||||
if (debug & DBG_ERRORS)
|
||||
pr_debug("DLCI %d goes open.\n", dlci->addr);
|
||||
/* Send current modem state */
|
||||
if (dlci->addr)
|
||||
if (dlci->addr) {
|
||||
gsm_modem_update(dlci, 0);
|
||||
} else {
|
||||
/* Start keep-alive control */
|
||||
gsm->ka_num = 0;
|
||||
gsm->ka_retries = -1;
|
||||
mod_timer(&gsm->ka_timer,
|
||||
jiffies + gsm->keep_alive * HZ / 100);
|
||||
}
|
||||
gsm_dlci_data_kick(dlci);
|
||||
wake_up(&dlci->gsm->event);
|
||||
}
|
||||
@ -2267,6 +2339,7 @@ static void gsm_dlci_begin_close(struct gsm_dlci *dlci)
|
||||
dlci->state = DLCI_CLOSING;
|
||||
gsm_command(dlci->gsm, dlci->addr, DISC|PF);
|
||||
mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
|
||||
wake_up_interruptible(&gsm->event);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2840,6 +2913,7 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc)
|
||||
/* Finish outstanding timers, making sure they are done */
|
||||
del_timer_sync(&gsm->kick_timer);
|
||||
del_timer_sync(&gsm->t2_timer);
|
||||
del_timer_sync(&gsm->ka_timer);
|
||||
|
||||
/* Finish writing to ldisc */
|
||||
flush_work(&gsm->tx_work);
|
||||
@ -2987,6 +3061,7 @@ static struct gsm_mux *gsm_alloc_mux(void)
|
||||
INIT_LIST_HEAD(&gsm->tx_data_list);
|
||||
timer_setup(&gsm->kick_timer, gsm_kick_timer, 0);
|
||||
timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0);
|
||||
timer_setup(&gsm->ka_timer, gsm_control_keep_alive, 0);
|
||||
INIT_WORK(&gsm->tx_work, gsmld_write_task);
|
||||
init_waitqueue_head(&gsm->event);
|
||||
spin_lock_init(&gsm->control_lock);
|
||||
@ -3003,6 +3078,7 @@ static struct gsm_mux *gsm_alloc_mux(void)
|
||||
gsm->mru = 64; /* Default to encoding 1 so these should be 64 */
|
||||
gsm->mtu = 64;
|
||||
gsm->dead = true; /* Avoid early tty opens */
|
||||
gsm->keep_alive = 0; /* Disabled */
|
||||
|
||||
/* Store the instance to the mux array or abort if no space is
|
||||
* available.
|
||||
@ -3138,6 +3214,29 @@ static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gsm_copy_config_ext_values(struct gsm_mux *gsm,
|
||||
struct gsm_config_ext *ce)
|
||||
{
|
||||
memset(ce, 0, sizeof(*ce));
|
||||
ce->keep_alive = gsm->keep_alive;
|
||||
}
|
||||
|
||||
static int gsm_config_ext(struct gsm_mux *gsm, struct gsm_config_ext *ce)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/*
|
||||
* Check that userspace doesn't put stuff in here to prevent breakages
|
||||
* in the future.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(ce->reserved); i++)
|
||||
if (ce->reserved[i])
|
||||
return -EINVAL;
|
||||
|
||||
gsm->keep_alive = ce->keep_alive;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsmld_output - write to link
|
||||
* @gsm: our mux
|
||||
@ -3456,6 +3555,7 @@ static int gsmld_ioctl(struct tty_struct *tty, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct gsm_config c;
|
||||
struct gsm_config_ext ce;
|
||||
struct gsm_mux *gsm = tty->disc_data;
|
||||
unsigned int base;
|
||||
|
||||
@ -3472,6 +3572,15 @@ static int gsmld_ioctl(struct tty_struct *tty, unsigned int cmd,
|
||||
case GSMIOC_GETFIRST:
|
||||
base = mux_num_to_base(gsm);
|
||||
return put_user(base + 1, (__u32 __user *)arg);
|
||||
case GSMIOC_GETCONF_EXT:
|
||||
gsm_copy_config_ext_values(gsm, &ce);
|
||||
if (copy_to_user((void __user *)arg, &ce, sizeof(ce)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
case GSMIOC_SETCONF_EXT:
|
||||
if (copy_from_user(&ce, (void __user *)arg, sizeof(ce)))
|
||||
return -EFAULT;
|
||||
return gsm_config_ext(gsm, &ce);
|
||||
default:
|
||||
return n_tty_ioctl_helper(tty, cmd, arg);
|
||||
}
|
||||
@ -3770,16 +3879,43 @@ static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk)
|
||||
return -EPROTONOSUPPORT;
|
||||
}
|
||||
|
||||
static int gsm_carrier_raised(struct tty_port *port)
|
||||
/**
|
||||
* gsm_wait_modem_change - wait for modem status line change
|
||||
* @dlci: channel
|
||||
* @mask: modem status line bits
|
||||
*
|
||||
* The function returns if:
|
||||
* - any given modem status line bit changed
|
||||
* - the wait event function got interrupted (e.g. by a signal)
|
||||
* - the underlying DLCI was closed
|
||||
* - the underlying ldisc device was removed
|
||||
*/
|
||||
static int gsm_wait_modem_change(struct gsm_dlci *dlci, u32 mask)
|
||||
{
|
||||
struct gsm_mux *gsm = dlci->gsm;
|
||||
u32 old = dlci->modem_rx;
|
||||
int ret;
|
||||
|
||||
ret = wait_event_interruptible(gsm->event, gsm->dead ||
|
||||
dlci->state != DLCI_OPEN ||
|
||||
(old ^ dlci->modem_rx) & mask);
|
||||
if (gsm->dead)
|
||||
return -ENODEV;
|
||||
if (dlci->state != DLCI_OPEN)
|
||||
return -EL2NSYNC;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool gsm_carrier_raised(struct tty_port *port)
|
||||
{
|
||||
struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
|
||||
struct gsm_mux *gsm = dlci->gsm;
|
||||
|
||||
/* Not yet open so no carrier info */
|
||||
if (dlci->state != DLCI_OPEN)
|
||||
return 0;
|
||||
return false;
|
||||
if (debug & DBG_CD_ON)
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Basic mode with control channel in ADM mode may not respond
|
||||
@ -3787,16 +3923,16 @@ static int gsm_carrier_raised(struct tty_port *port)
|
||||
*/
|
||||
if (gsm->encoding == GSM_BASIC_OPT &&
|
||||
gsm->dlci[0]->mode == DLCI_MODE_ADM && !dlci->modem_rx)
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
return dlci->modem_rx & TIOCM_CD;
|
||||
}
|
||||
|
||||
static void gsm_dtr_rts(struct tty_port *port, int onoff)
|
||||
static void gsm_dtr_rts(struct tty_port *port, bool active)
|
||||
{
|
||||
struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
|
||||
unsigned int modem_tx = dlci->modem_tx;
|
||||
if (onoff)
|
||||
if (active)
|
||||
modem_tx |= TIOCM_DTR | TIOCM_RTS;
|
||||
else
|
||||
modem_tx &= ~(TIOCM_DTR | TIOCM_RTS);
|
||||
@ -3880,7 +4016,7 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)
|
||||
dlci->modem_rx = 0;
|
||||
/* We could in theory open and close before we wait - eg if we get
|
||||
a DM straight back. This is ok as that will have caused a hangup */
|
||||
tty_port_set_initialized(port, 1);
|
||||
tty_port_set_initialized(port, true);
|
||||
/* Start sending off SABM messages */
|
||||
if (gsm->initiator)
|
||||
gsm_dlci_begin_open(dlci);
|
||||
@ -4029,6 +4165,8 @@ static int gsmtty_ioctl(struct tty_struct *tty,
|
||||
gsm_destroy_network(dlci);
|
||||
mutex_unlock(&dlci->mutex);
|
||||
return 0;
|
||||
case TIOCMIWAIT:
|
||||
return gsm_wait_modem_change(dlci, (u32)arg);
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
167
drivers/tty/serial/8250/8250_dfl.c
Normal file
167
drivers/tty/serial/8250/8250_dfl.c
Normal file
@ -0,0 +1,167 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Driver for FPGA UART
|
||||
*
|
||||
* Copyright (C) 2022 Intel Corporation.
|
||||
*
|
||||
* Authors:
|
||||
* Ananda Ravuri <ananda.ravuri@intel.com>
|
||||
* Matthew Gerlach <matthew.gerlach@linux.intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dfl.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_8250.h>
|
||||
|
||||
#define DFHv1_PARAM_ID_CLK_FRQ 0x2
|
||||
#define DFHv1_PARAM_ID_FIFO_LEN 0x3
|
||||
|
||||
#define DFHv1_PARAM_ID_REG_LAYOUT 0x4
|
||||
#define DFHv1_PARAM_REG_LAYOUT_WIDTH GENMASK_ULL(63, 32)
|
||||
#define DFHv1_PARAM_REG_LAYOUT_SHIFT GENMASK_ULL(31, 0)
|
||||
|
||||
struct dfl_uart {
|
||||
int line;
|
||||
};
|
||||
|
||||
static int dfh_get_u64_param_val(struct dfl_device *dfl_dev, int param_id, u64 *pval)
|
||||
{
|
||||
size_t psize;
|
||||
u64 *p;
|
||||
|
||||
p = dfh_find_param(dfl_dev, param_id, &psize);
|
||||
if (IS_ERR(p))
|
||||
return PTR_ERR(p);
|
||||
|
||||
if (psize != sizeof(*pval))
|
||||
return -EINVAL;
|
||||
|
||||
*pval = *p;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dfl_uart_get_params(struct dfl_device *dfl_dev, struct uart_8250_port *uart)
|
||||
{
|
||||
struct device *dev = &dfl_dev->dev;
|
||||
u64 fifo_len, clk_freq, reg_layout;
|
||||
u32 reg_width;
|
||||
int ret;
|
||||
|
||||
ret = dfh_get_u64_param_val(dfl_dev, DFHv1_PARAM_ID_CLK_FRQ, &clk_freq);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "missing CLK_FRQ param\n");
|
||||
|
||||
uart->port.uartclk = clk_freq;
|
||||
|
||||
ret = dfh_get_u64_param_val(dfl_dev, DFHv1_PARAM_ID_FIFO_LEN, &fifo_len);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "missing FIFO_LEN param\n");
|
||||
|
||||
switch (fifo_len) {
|
||||
case 32:
|
||||
uart->port.type = PORT_ALTR_16550_F32;
|
||||
break;
|
||||
|
||||
case 64:
|
||||
uart->port.type = PORT_ALTR_16550_F64;
|
||||
break;
|
||||
|
||||
case 128:
|
||||
uart->port.type = PORT_ALTR_16550_F128;
|
||||
break;
|
||||
|
||||
default:
|
||||
return dev_err_probe(dev, -EINVAL, "unsupported FIFO_LEN %llu\n", fifo_len);
|
||||
}
|
||||
|
||||
ret = dfh_get_u64_param_val(dfl_dev, DFHv1_PARAM_ID_REG_LAYOUT, ®_layout);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "missing REG_LAYOUT param\n");
|
||||
|
||||
uart->port.regshift = FIELD_GET(DFHv1_PARAM_REG_LAYOUT_SHIFT, reg_layout);
|
||||
reg_width = FIELD_GET(DFHv1_PARAM_REG_LAYOUT_WIDTH, reg_layout);
|
||||
switch (reg_width) {
|
||||
case 4:
|
||||
uart->port.iotype = UPIO_MEM32;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
uart->port.iotype = UPIO_MEM16;
|
||||
break;
|
||||
|
||||
default:
|
||||
return dev_err_probe(dev, -EINVAL, "unsupported reg-width %u\n", reg_width);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dfl_uart_probe(struct dfl_device *dfl_dev)
|
||||
{
|
||||
struct device *dev = &dfl_dev->dev;
|
||||
struct uart_8250_port uart = { };
|
||||
struct dfl_uart *dfluart;
|
||||
int ret;
|
||||
|
||||
uart.port.flags = UPF_IOREMAP;
|
||||
uart.port.mapbase = dfl_dev->mmio_res.start;
|
||||
uart.port.mapsize = resource_size(&dfl_dev->mmio_res);
|
||||
|
||||
ret = dfl_uart_get_params(dfl_dev, &uart);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "failed uart feature walk\n");
|
||||
|
||||
if (dfl_dev->num_irqs == 1)
|
||||
uart.port.irq = dfl_dev->irqs[0];
|
||||
|
||||
dfluart = devm_kzalloc(dev, sizeof(*dfluart), GFP_KERNEL);
|
||||
if (!dfluart)
|
||||
return -ENOMEM;
|
||||
|
||||
dfluart->line = serial8250_register_8250_port(&uart);
|
||||
if (dfluart->line < 0)
|
||||
return dev_err_probe(dev, dfluart->line, "unable to register 8250 port.\n");
|
||||
|
||||
dev_set_drvdata(dev, dfluart);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dfl_uart_remove(struct dfl_device *dfl_dev)
|
||||
{
|
||||
struct dfl_uart *dfluart = dev_get_drvdata(&dfl_dev->dev);
|
||||
|
||||
serial8250_unregister_port(dfluart->line);
|
||||
}
|
||||
|
||||
#define FME_FEATURE_ID_UART 0x24
|
||||
|
||||
static const struct dfl_device_id dfl_uart_ids[] = {
|
||||
{ FME_ID, FME_FEATURE_ID_UART },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(dfl, dfl_uart_ids);
|
||||
|
||||
static struct dfl_driver dfl_uart_driver = {
|
||||
.drv = {
|
||||
.name = "dfl-uart",
|
||||
},
|
||||
.id_table = dfl_uart_ids,
|
||||
.probe = dfl_uart_probe,
|
||||
.remove = dfl_uart_remove,
|
||||
};
|
||||
module_dfl_driver(dfl_uart_driver);
|
||||
|
||||
MODULE_DESCRIPTION("DFL Intel UART driver");
|
||||
MODULE_AUTHOR("Intel Corporation");
|
||||
MODULE_LICENSE("GPL");
|
@ -136,11 +136,11 @@ static void __init init_port(struct earlycon_device *device)
|
||||
unsigned char c;
|
||||
unsigned int ier;
|
||||
|
||||
serial8250_early_out(port, UART_LCR, 0x3); /* 8n1 */
|
||||
serial8250_early_out(port, UART_LCR, UART_LCR_WLEN8); /* 8n1 */
|
||||
ier = serial8250_early_in(port, UART_IER);
|
||||
serial8250_early_out(port, UART_IER, ier & UART_IER_UUE); /* no interrupt */
|
||||
serial8250_early_out(port, UART_FCR, 0); /* no fifo */
|
||||
serial8250_early_out(port, UART_MCR, 0x3); /* DTR + RTS */
|
||||
serial8250_early_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
|
||||
|
||||
if (port->uartclk) {
|
||||
divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud);
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "8250.h"
|
||||
#include "8250_pcilib.h"
|
||||
|
||||
/*
|
||||
* init function returns:
|
||||
@ -89,28 +90,7 @@ static int
|
||||
setup_port(struct serial_private *priv, struct uart_8250_port *port,
|
||||
u8 bar, unsigned int offset, int regshift)
|
||||
{
|
||||
struct pci_dev *dev = priv->dev;
|
||||
|
||||
if (bar >= PCI_STD_NUM_BARS)
|
||||
return -EINVAL;
|
||||
|
||||
if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
|
||||
if (!pcim_iomap(dev, bar, 0) && !pcim_iomap_table(dev))
|
||||
return -ENOMEM;
|
||||
|
||||
port->port.iotype = UPIO_MEM;
|
||||
port->port.iobase = 0;
|
||||
port->port.mapbase = pci_resource_start(dev, bar) + offset;
|
||||
port->port.membase = pcim_iomap_table(dev)[bar] + offset;
|
||||
port->port.regshift = regshift;
|
||||
} else {
|
||||
port->port.iotype = UPIO_PORT;
|
||||
port->port.iobase = pci_resource_start(dev, bar) + offset;
|
||||
port->port.mapbase = 0;
|
||||
port->port.membase = NULL;
|
||||
port->port.regshift = 0;
|
||||
}
|
||||
return 0;
|
||||
return serial8250_pci_setup_port(priv->dev, port, bar, offset, regshift);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -5757,3 +5737,4 @@ module_pci_driver(serial_pci_driver);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module");
|
||||
MODULE_DEVICE_TABLE(pci, serial_pci_tbl);
|
||||
MODULE_IMPORT_NS(SERIAL_8250_PCI);
|
||||
|
494
drivers/tty/serial/8250/8250_pci1xxxx.c
Normal file
494
drivers/tty/serial/8250/8250_pci1xxxx.c
Normal file
@ -0,0 +1,494 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Probe module for 8250/16550-type MCHP PCI serial ports.
|
||||
*
|
||||
* Based on drivers/tty/serial/8250/8250_pci.c,
|
||||
*
|
||||
* Copyright (C) 2022 Microchip Technology Inc., All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/units.h>
|
||||
#include <linux/tty.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include "8250.h"
|
||||
#include "8250_pcilib.h"
|
||||
|
||||
#define PCI_DEVICE_ID_EFAR_PCI12000 0xa002
|
||||
#define PCI_DEVICE_ID_EFAR_PCI11010 0xa012
|
||||
#define PCI_DEVICE_ID_EFAR_PCI11101 0xa022
|
||||
#define PCI_DEVICE_ID_EFAR_PCI11400 0xa032
|
||||
#define PCI_DEVICE_ID_EFAR_PCI11414 0xa042
|
||||
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_4p 0x0001
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p012 0x0002
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p013 0x0003
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p023 0x0004
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p123 0x0005
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p01 0x0006
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p02 0x0007
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p03 0x0008
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p12 0x0009
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p13 0x000a
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p23 0x000b
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p0 0x000c
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p1 0x000d
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p2 0x000e
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p3 0x000f
|
||||
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI12000 PCI_DEVICE_ID_EFAR_PCI12000
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI11010 PCI_DEVICE_ID_EFAR_PCI11010
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI11101 PCI_DEVICE_ID_EFAR_PCI11101
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI11400 PCI_DEVICE_ID_EFAR_PCI11400
|
||||
#define PCI_SUBDEVICE_ID_EFAR_PCI11414 PCI_DEVICE_ID_EFAR_PCI11414
|
||||
|
||||
#define UART_ACTV_REG 0x11
|
||||
#define UART_BLOCK_SET_ACTIVE BIT(0)
|
||||
|
||||
#define UART_PCI_CTRL_REG 0x80
|
||||
#define UART_PCI_CTRL_SET_MULTIPLE_MSI BIT(4)
|
||||
#define UART_PCI_CTRL_D3_CLK_ENABLE BIT(0)
|
||||
|
||||
#define ADCL_CFG_REG 0x40
|
||||
#define ADCL_CFG_POL_SEL BIT(2)
|
||||
#define ADCL_CFG_PIN_SEL BIT(1)
|
||||
#define ADCL_CFG_EN BIT(0)
|
||||
|
||||
#define UART_BIT_SAMPLE_CNT 16
|
||||
#define BAUD_CLOCK_DIV_INT_MSK GENMASK(31, 8)
|
||||
#define ADCL_CFG_RTS_DELAY_MASK GENMASK(11, 8)
|
||||
#define UART_CLOCK_DEFAULT (62500 * HZ_PER_KHZ)
|
||||
|
||||
#define UART_WAKE_REG 0x8C
|
||||
#define UART_WAKE_MASK_REG 0x90
|
||||
#define UART_WAKE_N_PIN BIT(2)
|
||||
#define UART_WAKE_NCTS BIT(1)
|
||||
#define UART_WAKE_INT BIT(0)
|
||||
#define UART_WAKE_SRCS \
|
||||
(UART_WAKE_N_PIN | UART_WAKE_NCTS | UART_WAKE_INT)
|
||||
|
||||
#define UART_BAUD_CLK_DIVISOR_REG 0x54
|
||||
|
||||
#define UART_RESET_REG 0x94
|
||||
#define UART_RESET_D3_RESET_DISABLE BIT(16)
|
||||
|
||||
#define MAX_PORTS 4
|
||||
#define PORT_OFFSET 0x100
|
||||
|
||||
static const int logical_to_physical_port_idx[][MAX_PORTS] = {
|
||||
{0, 1, 2, 3}, /* PCI12000, PCI11010, PCI11101, PCI11400, PCI11414 */
|
||||
{0, 1, 2, 3}, /* PCI4p */
|
||||
{0, 1, 2, -1}, /* PCI3p012 */
|
||||
{0, 1, 3, -1}, /* PCI3p013 */
|
||||
{0, 2, 3, -1}, /* PCI3p023 */
|
||||
{1, 2, 3, -1}, /* PCI3p123 */
|
||||
{0, 1, -1, -1}, /* PCI2p01 */
|
||||
{0, 2, -1, -1}, /* PCI2p02 */
|
||||
{0, 3, -1, -1}, /* PCI2p03 */
|
||||
{1, 2, -1, -1}, /* PCI2p12 */
|
||||
{1, 3, -1, -1}, /* PCI2p13 */
|
||||
{2, 3, -1, -1}, /* PCI2p23 */
|
||||
{0, -1, -1, -1}, /* PCI1p0 */
|
||||
{1, -1, -1, -1}, /* PCI1p1 */
|
||||
{2, -1, -1, -1}, /* PCI1p2 */
|
||||
{3, -1, -1, -1}, /* PCI1p3 */
|
||||
};
|
||||
|
||||
struct pci1xxxx_8250 {
|
||||
unsigned int nr;
|
||||
void __iomem *membase;
|
||||
int line[];
|
||||
};
|
||||
|
||||
static int pci1xxxx_get_num_ports(struct pci_dev *dev)
|
||||
{
|
||||
switch (dev->subsystem_device) {
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p0:
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p1:
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p2:
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p3:
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI12000:
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI11010:
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI11101:
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI11400:
|
||||
default:
|
||||
return 1;
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p01:
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p02:
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p03:
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p12:
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p13:
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_2p23:
|
||||
return 2;
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p012:
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p123:
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p013:
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_3p023:
|
||||
return 3;
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_4p:
|
||||
case PCI_SUBDEVICE_ID_EFAR_PCI11414:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int pci1xxxx_get_divisor(struct uart_port *port,
|
||||
unsigned int baud, unsigned int *frac)
|
||||
{
|
||||
unsigned int quot;
|
||||
|
||||
/*
|
||||
* Calculate baud rate sampling period in nanoseconds.
|
||||
* Fractional part x denotes x/255 parts of a nanosecond.
|
||||
*/
|
||||
quot = NSEC_PER_SEC / (baud * UART_BIT_SAMPLE_CNT);
|
||||
*frac = (NSEC_PER_SEC - quot * baud * UART_BIT_SAMPLE_CNT) *
|
||||
255 / UART_BIT_SAMPLE_CNT / baud;
|
||||
|
||||
return quot;
|
||||
}
|
||||
|
||||
static void pci1xxxx_set_divisor(struct uart_port *port, unsigned int baud,
|
||||
unsigned int quot, unsigned int frac)
|
||||
{
|
||||
writel(FIELD_PREP(BAUD_CLOCK_DIV_INT_MSK, quot) | frac,
|
||||
port->membase + UART_BAUD_CLK_DIVISOR_REG);
|
||||
}
|
||||
|
||||
static int pci1xxxx_rs485_config(struct uart_port *port,
|
||||
struct ktermios *termios,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
u32 delay_in_baud_periods;
|
||||
u32 baud_period_in_ns;
|
||||
u32 mode_cfg = 0;
|
||||
u32 clock_div;
|
||||
|
||||
/*
|
||||
* pci1xxxx's uart hardware supports only RTS delay after
|
||||
* Tx and in units of bit times to a maximum of 15
|
||||
*/
|
||||
if (rs485->flags & SER_RS485_ENABLED) {
|
||||
mode_cfg = ADCL_CFG_EN | ADCL_CFG_PIN_SEL;
|
||||
|
||||
if (!(rs485->flags & SER_RS485_RTS_ON_SEND))
|
||||
mode_cfg |= ADCL_CFG_POL_SEL;
|
||||
|
||||
if (rs485->delay_rts_after_send) {
|
||||
clock_div = readl(port->membase + UART_BAUD_CLK_DIVISOR_REG);
|
||||
baud_period_in_ns =
|
||||
FIELD_GET(BAUD_CLOCK_DIV_INT_MSK, clock_div) *
|
||||
UART_BIT_SAMPLE_CNT;
|
||||
delay_in_baud_periods =
|
||||
rs485->delay_rts_after_send * NSEC_PER_MSEC /
|
||||
baud_period_in_ns;
|
||||
delay_in_baud_periods =
|
||||
min_t(u32, delay_in_baud_periods,
|
||||
FIELD_MAX(ADCL_CFG_RTS_DELAY_MASK));
|
||||
mode_cfg |= FIELD_PREP(ADCL_CFG_RTS_DELAY_MASK,
|
||||
delay_in_baud_periods);
|
||||
rs485->delay_rts_after_send =
|
||||
baud_period_in_ns * delay_in_baud_periods /
|
||||
NSEC_PER_MSEC;
|
||||
}
|
||||
}
|
||||
writel(mode_cfg, port->membase + ADCL_CFG_REG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct serial_rs485 pci1xxxx_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
|
||||
SER_RS485_RTS_AFTER_SEND,
|
||||
.delay_rts_after_send = 1,
|
||||
/* Delay RTS before send is not supported */
|
||||
};
|
||||
|
||||
static bool pci1xxxx_port_suspend(int line)
|
||||
{
|
||||
struct uart_8250_port *up = serial8250_get_port(line);
|
||||
struct uart_port *port = &up->port;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned long flags;
|
||||
bool ret = false;
|
||||
u8 wakeup_mask;
|
||||
|
||||
mutex_lock(&tport->mutex);
|
||||
if (port->suspended == 0 && port->dev) {
|
||||
wakeup_mask = readb(up->port.membase + UART_WAKE_MASK_REG);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
port->mctrl &= ~TIOCM_OUT2;
|
||||
port->ops->set_mctrl(port, port->mctrl);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
ret = (wakeup_mask & UART_WAKE_SRCS) != UART_WAKE_SRCS;
|
||||
}
|
||||
|
||||
writeb(UART_WAKE_SRCS, port->membase + UART_WAKE_REG);
|
||||
mutex_unlock(&tport->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pci1xxxx_port_resume(int line)
|
||||
{
|
||||
struct uart_8250_port *up = serial8250_get_port(line);
|
||||
struct uart_port *port = &up->port;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&tport->mutex);
|
||||
writeb(UART_BLOCK_SET_ACTIVE, port->membase + UART_ACTV_REG);
|
||||
writeb(UART_WAKE_SRCS, port->membase + UART_WAKE_REG);
|
||||
|
||||
if (port->suspended == 0) {
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
port->mctrl |= TIOCM_OUT2;
|
||||
port->ops->set_mctrl(port, port->mctrl);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
mutex_unlock(&tport->mutex);
|
||||
}
|
||||
|
||||
static int pci1xxxx_suspend(struct device *dev)
|
||||
{
|
||||
struct pci1xxxx_8250 *priv = dev_get_drvdata(dev);
|
||||
struct pci_dev *pcidev = to_pci_dev(dev);
|
||||
bool wakeup = false;
|
||||
unsigned int data;
|
||||
void __iomem *p;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->nr; i++) {
|
||||
if (priv->line[i] >= 0) {
|
||||
serial8250_suspend_port(priv->line[i]);
|
||||
wakeup |= pci1xxxx_port_suspend(priv->line[i]);
|
||||
}
|
||||
}
|
||||
|
||||
p = pci_ioremap_bar(pcidev, 0);
|
||||
if (!p) {
|
||||
dev_err(dev, "remapping of bar 0 memory failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
data = readl(p + UART_RESET_REG);
|
||||
writel(data | UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG);
|
||||
|
||||
if (wakeup)
|
||||
writeb(UART_PCI_CTRL_D3_CLK_ENABLE, p + UART_PCI_CTRL_REG);
|
||||
|
||||
iounmap(p);
|
||||
device_set_wakeup_enable(dev, true);
|
||||
pci_wake_from_d3(pcidev, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci1xxxx_resume(struct device *dev)
|
||||
{
|
||||
struct pci1xxxx_8250 *priv = dev_get_drvdata(dev);
|
||||
struct pci_dev *pcidev = to_pci_dev(dev);
|
||||
unsigned int data;
|
||||
void __iomem *p;
|
||||
int i;
|
||||
|
||||
p = pci_ioremap_bar(pcidev, 0);
|
||||
if (!p) {
|
||||
dev_err(dev, "remapping of bar 0 memory failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
data = readl(p + UART_RESET_REG);
|
||||
writel(data & ~UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG);
|
||||
iounmap(p);
|
||||
|
||||
for (i = 0; i < priv->nr; i++) {
|
||||
if (priv->line[i] >= 0) {
|
||||
pci1xxxx_port_resume(priv->line[i]);
|
||||
serial8250_resume_port(priv->line[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci1xxxx_setup(struct pci_dev *pdev,
|
||||
struct uart_8250_port *port, int port_idx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
port->port.flags |= UPF_FIXED_TYPE | UPF_SKIP_TEST;
|
||||
port->port.type = PORT_MCHP16550A;
|
||||
port->port.set_termios = serial8250_do_set_termios;
|
||||
port->port.get_divisor = pci1xxxx_get_divisor;
|
||||
port->port.set_divisor = pci1xxxx_set_divisor;
|
||||
port->port.rs485_config = pci1xxxx_rs485_config;
|
||||
port->port.rs485_supported = pci1xxxx_rs485_supported;
|
||||
|
||||
ret = serial8250_pci_setup_port(pdev, port, 0, PORT_OFFSET * port_idx, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
writeb(UART_BLOCK_SET_ACTIVE, port->port.membase + UART_ACTV_REG);
|
||||
writeb(UART_WAKE_SRCS, port->port.membase + UART_WAKE_REG);
|
||||
writeb(UART_WAKE_N_PIN, port->port.membase + UART_WAKE_MASK_REG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int pci1xxxx_get_max_port(int subsys_dev)
|
||||
{
|
||||
unsigned int i = MAX_PORTS;
|
||||
|
||||
if (subsys_dev < ARRAY_SIZE(logical_to_physical_port_idx))
|
||||
while (i--) {
|
||||
if (logical_to_physical_port_idx[subsys_dev][i] != -1)
|
||||
return logical_to_physical_port_idx[subsys_dev][i] + 1;
|
||||
}
|
||||
|
||||
if (subsys_dev == PCI_SUBDEVICE_ID_EFAR_PCI11414)
|
||||
return 4;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int pci1xxxx_logical_to_physical_port_translate(int subsys_dev, int port)
|
||||
{
|
||||
if (subsys_dev < ARRAY_SIZE(logical_to_physical_port_idx))
|
||||
return logical_to_physical_port_idx[subsys_dev][port];
|
||||
|
||||
return logical_to_physical_port_idx[0][port];
|
||||
}
|
||||
|
||||
static int pci1xxxx_serial_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pci1xxxx_8250 *priv;
|
||||
struct uart_8250_port uart;
|
||||
unsigned int max_vec_reqd;
|
||||
unsigned int nr_ports, i;
|
||||
int num_vectors;
|
||||
int subsys_dev;
|
||||
int port_idx;
|
||||
int rc;
|
||||
|
||||
rc = pcim_enable_device(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
nr_ports = pci1xxxx_get_num_ports(pdev);
|
||||
|
||||
priv = devm_kzalloc(dev, struct_size(priv, line, nr_ports), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->membase = pci_ioremap_bar(pdev, 0);
|
||||
if (!priv->membase)
|
||||
return -ENOMEM;
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
priv->nr = nr_ports;
|
||||
|
||||
subsys_dev = pdev->subsystem_device;
|
||||
max_vec_reqd = pci1xxxx_get_max_port(subsys_dev);
|
||||
|
||||
num_vectors = pci_alloc_irq_vectors(pdev, 1, max_vec_reqd, PCI_IRQ_ALL_TYPES);
|
||||
if (num_vectors < 0) {
|
||||
pci_iounmap(pdev, priv->membase);
|
||||
return num_vectors;
|
||||
}
|
||||
|
||||
memset(&uart, 0, sizeof(uart));
|
||||
uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT;
|
||||
uart.port.uartclk = UART_CLOCK_DEFAULT;
|
||||
uart.port.dev = dev;
|
||||
|
||||
if (num_vectors == max_vec_reqd)
|
||||
writeb(UART_PCI_CTRL_SET_MULTIPLE_MSI, priv->membase + UART_PCI_CTRL_REG);
|
||||
|
||||
for (i = 0; i < nr_ports; i++) {
|
||||
priv->line[i] = -ENODEV;
|
||||
|
||||
port_idx = pci1xxxx_logical_to_physical_port_translate(subsys_dev, i);
|
||||
|
||||
if (num_vectors == max_vec_reqd)
|
||||
uart.port.irq = pci_irq_vector(pdev, port_idx);
|
||||
else
|
||||
uart.port.irq = pci_irq_vector(pdev, 0);
|
||||
|
||||
rc = pci1xxxx_setup(pdev, &uart, port_idx);
|
||||
if (rc) {
|
||||
dev_warn(dev, "Failed to setup port %u\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
priv->line[i] = serial8250_register_8250_port(&uart);
|
||||
if (priv->line[i] < 0) {
|
||||
dev_warn(dev,
|
||||
"Couldn't register serial port %lx, irq %d, type %d, error %d\n",
|
||||
uart.port.iobase, uart.port.irq, uart.port.iotype,
|
||||
priv->line[i]);
|
||||
}
|
||||
}
|
||||
|
||||
pci_set_drvdata(pdev, priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pci1xxxx_serial_remove(struct pci_dev *dev)
|
||||
{
|
||||
struct pci1xxxx_8250 *priv = pci_get_drvdata(dev);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < priv->nr; i++) {
|
||||
if (priv->line[i] >= 0)
|
||||
serial8250_unregister_port(priv->line[i]);
|
||||
}
|
||||
|
||||
pci_free_irq_vectors(dev);
|
||||
pci_iounmap(dev, priv->membase);
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(pci1xxxx_pm_ops, pci1xxxx_suspend, pci1xxxx_resume);
|
||||
|
||||
static const struct pci_device_id pci1xxxx_pci_tbl[] = {
|
||||
{ PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11010) },
|
||||
{ PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11101) },
|
||||
{ PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11400) },
|
||||
{ PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI11414) },
|
||||
{ PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_PCI12000) },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pci1xxxx_pci_tbl);
|
||||
|
||||
static struct pci_driver pci1xxxx_pci_driver = {
|
||||
.name = "pci1xxxx serial",
|
||||
.probe = pci1xxxx_serial_probe,
|
||||
.remove = pci1xxxx_serial_remove,
|
||||
.driver = {
|
||||
.pm = pm_sleep_ptr(&pci1xxxx_pm_ops),
|
||||
},
|
||||
.id_table = pci1xxxx_pci_tbl,
|
||||
};
|
||||
module_pci_driver(pci1xxxx_pci_driver);
|
||||
|
||||
static_assert((ARRAY_SIZE(logical_to_physical_port_idx) == PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p3 + 1));
|
||||
|
||||
MODULE_IMPORT_NS(SERIAL_8250_PCI);
|
||||
MODULE_DESCRIPTION("Microchip Technology Inc. PCIe to UART module");
|
||||
MODULE_AUTHOR("Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>");
|
||||
MODULE_AUTHOR("Tharun Kumar P <tharunkumar.pasumarthi@microchip.com>");
|
||||
MODULE_LICENSE("GPL");
|
40
drivers/tty/serial/8250/8250_pcilib.c
Normal file
40
drivers/tty/serial/8250/8250_pcilib.c
Normal file
@ -0,0 +1,40 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* 8250 PCI library.
|
||||
*
|
||||
* Copyright (C) 2001 Russell King, All Rights Reserved.
|
||||
*/
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "8250.h"
|
||||
#include "8250_pcilib.h"
|
||||
|
||||
int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port,
|
||||
u8 bar, unsigned int offset, int regshift)
|
||||
{
|
||||
if (bar >= PCI_STD_NUM_BARS)
|
||||
return -EINVAL;
|
||||
|
||||
if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
|
||||
if (!pcim_iomap(dev, bar, 0) && !pcim_iomap_table(dev))
|
||||
return -ENOMEM;
|
||||
|
||||
port->port.iotype = UPIO_MEM;
|
||||
port->port.iobase = 0;
|
||||
port->port.mapbase = pci_resource_start(dev, bar) + offset;
|
||||
port->port.membase = pcim_iomap_table(dev)[bar] + offset;
|
||||
port->port.regshift = regshift;
|
||||
} else {
|
||||
port->port.iotype = UPIO_PORT;
|
||||
port->port.iobase = pci_resource_start(dev, bar) + offset;
|
||||
port->port.mapbase = 0;
|
||||
port->port.membase = NULL;
|
||||
port->port.regshift = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(serial8250_pci_setup_port, SERIAL_8250_PCI);
|
||||
MODULE_LICENSE("GPL");
|
15
drivers/tty/serial/8250/8250_pcilib.h
Normal file
15
drivers/tty/serial/8250/8250_pcilib.h
Normal file
@ -0,0 +1,15 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* 8250 PCI library header file.
|
||||
*
|
||||
* Copyright (C) 2001 Russell King, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct pci_dev;
|
||||
|
||||
struct uart_8250_port;
|
||||
|
||||
int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port, u8 bar,
|
||||
unsigned int offset, int regshift);
|
@ -313,6 +313,14 @@ static const struct serial8250_config uart_config[] = {
|
||||
.rxtrig_bytes = {1, 4, 8, 14},
|
||||
.flags = UART_CAP_FIFO,
|
||||
},
|
||||
[PORT_MCHP16550A] = {
|
||||
.name = "MCHP16550A",
|
||||
.fifo_size = 256,
|
||||
.tx_loadsz = 256,
|
||||
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01,
|
||||
.rxtrig_bytes = {2, 66, 130, 194},
|
||||
.flags = UART_CAP_FIFO,
|
||||
},
|
||||
};
|
||||
|
||||
/* Uart divisor latch read */
|
||||
@ -1050,11 +1058,12 @@ static void autoconfig_16550a(struct uart_8250_port *up)
|
||||
serial_out(up, UART_LCR, 0);
|
||||
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
|
||||
UART_FCR7_64BYTE);
|
||||
status1 = serial_in(up, UART_IIR) >> 5;
|
||||
status1 = serial_in(up, UART_IIR) & (UART_IIR_64BYTE_FIFO |
|
||||
UART_IIR_FIFO_ENABLED);
|
||||
serial_out(up, UART_FCR, 0);
|
||||
serial_out(up, UART_LCR, 0);
|
||||
|
||||
if (status1 == 7)
|
||||
if (status1 == (UART_IIR_64BYTE_FIFO | UART_IIR_FIFO_ENABLED))
|
||||
up->port.type = PORT_16550A_FSL64;
|
||||
else
|
||||
DEBUG_AUTOCONF("Motorola 8xxx DUART ");
|
||||
@ -1122,17 +1131,20 @@ static void autoconfig_16550a(struct uart_8250_port *up)
|
||||
*/
|
||||
serial_out(up, UART_LCR, 0);
|
||||
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
|
||||
status1 = serial_in(up, UART_IIR) >> 5;
|
||||
status1 = serial_in(up, UART_IIR) & (UART_IIR_64BYTE_FIFO | UART_IIR_FIFO_ENABLED);
|
||||
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
|
||||
|
||||
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
|
||||
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
|
||||
status2 = serial_in(up, UART_IIR) >> 5;
|
||||
status2 = serial_in(up, UART_IIR) & (UART_IIR_64BYTE_FIFO | UART_IIR_FIFO_ENABLED);
|
||||
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
|
||||
|
||||
serial_out(up, UART_LCR, 0);
|
||||
|
||||
DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2);
|
||||
|
||||
if (status1 == 6 && status2 == 7) {
|
||||
if (status1 == UART_IIR_FIFO_ENABLED_16550A &&
|
||||
status2 == (UART_IIR_64BYTE_FIFO | UART_IIR_FIFO_ENABLED_16550A)) {
|
||||
up->port.type = PORT_16750;
|
||||
up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP;
|
||||
return;
|
||||
@ -1236,14 +1248,14 @@ static void autoconfig(struct uart_8250_port *up)
|
||||
* Mask out IER[7:4] bits for test as some UARTs (e.g. TL
|
||||
* 16C754B) allow only to modify them if an EFR bit is set.
|
||||
*/
|
||||
scratch2 = serial_in(up, UART_IER) & 0x0f;
|
||||
serial_out(up, UART_IER, 0x0F);
|
||||
scratch2 = serial_in(up, UART_IER) & UART_IER_ALL_INTR;
|
||||
serial_out(up, UART_IER, UART_IER_ALL_INTR);
|
||||
#ifdef __i386__
|
||||
outb(0, 0x080);
|
||||
#endif
|
||||
scratch3 = serial_in(up, UART_IER) & 0x0f;
|
||||
scratch3 = serial_in(up, UART_IER) & UART_IER_ALL_INTR;
|
||||
serial_out(up, UART_IER, scratch);
|
||||
if (scratch2 != 0 || scratch3 != 0x0F) {
|
||||
if (scratch2 != 0 || scratch3 != UART_IER_ALL_INTR) {
|
||||
/*
|
||||
* We failed; there's nothing here
|
||||
*/
|
||||
@ -1267,10 +1279,10 @@ static void autoconfig(struct uart_8250_port *up)
|
||||
* that conflicts with COM 1-4 --- we hope!
|
||||
*/
|
||||
if (!(port->flags & UPF_SKIP_TEST)) {
|
||||
serial8250_out_MCR(up, UART_MCR_LOOP | 0x0A);
|
||||
status1 = serial_in(up, UART_MSR) & 0xF0;
|
||||
serial8250_out_MCR(up, UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_RTS);
|
||||
status1 = serial_in(up, UART_MSR) & UART_MSR_STATUS_BITS;
|
||||
serial8250_out_MCR(up, save_mcr);
|
||||
if (status1 != 0x90) {
|
||||
if (status1 != (UART_MSR_DCD | UART_MSR_CTS)) {
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
DEBUG_AUTOCONF("LOOP test failed (%02x) ",
|
||||
status1);
|
||||
@ -1293,22 +1305,19 @@ static void autoconfig(struct uart_8250_port *up)
|
||||
|
||||
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
|
||||
|
||||
/* Assign this as it is to truncate any bits above 7. */
|
||||
scratch = serial_in(up, UART_IIR);
|
||||
|
||||
switch (scratch >> 6) {
|
||||
case 0:
|
||||
switch (serial_in(up, UART_IIR) & UART_IIR_FIFO_ENABLED) {
|
||||
case UART_IIR_FIFO_ENABLED_8250:
|
||||
autoconfig_8250(up);
|
||||
break;
|
||||
case 1:
|
||||
port->type = PORT_UNKNOWN;
|
||||
break;
|
||||
case 2:
|
||||
case UART_IIR_FIFO_ENABLED_16550:
|
||||
port->type = PORT_16550;
|
||||
break;
|
||||
case 3:
|
||||
case UART_IIR_FIFO_ENABLED_16550A:
|
||||
autoconfig_16550a(up);
|
||||
break;
|
||||
default:
|
||||
port->type = PORT_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_RSA
|
||||
@ -1394,7 +1403,7 @@ static void autoconfig_irq(struct uart_8250_port *up)
|
||||
serial8250_out_MCR(up,
|
||||
UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
|
||||
}
|
||||
serial_out(up, UART_IER, 0x0f); /* enable all intrs */
|
||||
serial_out(up, UART_IER, UART_IER_ALL_INTR);
|
||||
serial_in(up, UART_LSR);
|
||||
serial_in(up, UART_RX);
|
||||
serial_in(up, UART_IIR);
|
||||
@ -1511,8 +1520,6 @@ static inline void __stop_tx(struct uart_8250_port *p)
|
||||
u16 lsr = serial_lsr_in(p);
|
||||
u64 stop_delay = 0;
|
||||
|
||||
p->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
|
||||
|
||||
if (!(lsr & UART_LSR_THRE))
|
||||
return;
|
||||
/*
|
||||
|
@ -129,9 +129,13 @@ config SERIAL_8250_DMA
|
||||
This builds DMA support that can be used with 8250/16650
|
||||
compatible UART controllers that support DMA signaling.
|
||||
|
||||
config SERIAL_8250_PCILIB
|
||||
bool
|
||||
|
||||
config SERIAL_8250_PCI
|
||||
tristate "8250/16550 PCI device support"
|
||||
depends on SERIAL_8250 && PCI
|
||||
select SERIAL_8250_PCILIB
|
||||
default SERIAL_8250
|
||||
help
|
||||
This builds standard PCI serial support. You may be able to
|
||||
@ -291,6 +295,17 @@ config SERIAL_8250_HUB6
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called 8250_hub6.
|
||||
|
||||
config SERIAL_8250_PCI1XXXX
|
||||
tristate "Microchip 8250 based serial port"
|
||||
depends on SERIAL_8250 && PCI
|
||||
select SERIAL_8250_PCILIB
|
||||
default SERIAL_8250
|
||||
help
|
||||
Select this option if you have a setup with Microchip PCIe
|
||||
Switch with serial port enabled and wish to enable 8250
|
||||
serial driver for the serial interface. This driver support
|
||||
will ensure to support baud rates upto 1.5Mpbs.
|
||||
|
||||
#
|
||||
# Misc. options/drivers.
|
||||
#
|
||||
@ -370,6 +385,18 @@ config SERIAL_8250_FSL
|
||||
erratum for Freescale 16550 UARTs in the 8250 driver. It also
|
||||
enables support for ACPI enumeration.
|
||||
|
||||
config SERIAL_8250_DFL
|
||||
tristate "DFL bus driver for Altera 16550 UART"
|
||||
depends on SERIAL_8250 && FPGA_DFL
|
||||
help
|
||||
This option enables support for a Device Feature List (DFL) bus
|
||||
driver for the Altera 16550 UART. One or more Altera 16550 UARTs
|
||||
can be instantiated in a FPGA and then be discovered during
|
||||
enumeration of the DFL bus.
|
||||
|
||||
To compile this driver as a module, chose M here: the
|
||||
module will be called 8250_dfl.
|
||||
|
||||
config SERIAL_8250_DW
|
||||
tristate "Support for Synopsys DesignWare 8250 quirks"
|
||||
depends on SERIAL_8250
|
||||
|
@ -12,6 +12,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o
|
||||
8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o
|
||||
8250_base-$(CONFIG_SERIAL_8250_DWLIB) += 8250_dwlib.o
|
||||
8250_base-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o
|
||||
8250_base-$(CONFIG_SERIAL_8250_PCILIB) += 8250_pcilib.o
|
||||
obj-$(CONFIG_SERIAL_8250_PARISC) += 8250_parisc.o
|
||||
obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
|
||||
obj-$(CONFIG_SERIAL_8250_EXAR) += 8250_exar.o
|
||||
@ -26,8 +27,10 @@ obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
|
||||
obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
|
||||
obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o
|
||||
obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
|
||||
obj-$(CONFIG_SERIAL_8250_PCI1XXXX) += 8250_pci1xxxx.o
|
||||
obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
|
||||
obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o
|
||||
obj-$(CONFIG_SERIAL_8250_DFL) += 8250_dfl.o
|
||||
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
|
||||
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
|
||||
obj-$(CONFIG_SERIAL_8250_IOC3) += 8250_ioc3.o
|
||||
|
@ -73,17 +73,17 @@ config SERIAL_AMBA_PL011_CONSOLE
|
||||
your boot loader (lilo or loadlin) about how to pass options to the
|
||||
kernel at boot time.)
|
||||
|
||||
config SERIAL_EARLYCON_ARM_SEMIHOST
|
||||
bool "Early console using ARM semihosting"
|
||||
depends on ARM64 || ARM
|
||||
config SERIAL_EARLYCON_SEMIHOST
|
||||
bool "Early console using Arm compatible semihosting"
|
||||
depends on ARM64 || ARM || RISCV
|
||||
select SERIAL_CORE
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON
|
||||
help
|
||||
Support for early debug console using ARM semihosting. This enables
|
||||
the console before standard serial driver is probed. This is enabled
|
||||
with "earlycon=smh" on the kernel command line. The console is
|
||||
enabled when early_param is processed.
|
||||
Support for early debug console using Arm compatible semihosting.
|
||||
This enables the console before standard serial driver is probed.
|
||||
This is enabled with "earlycon=smh" on the kernel command line.
|
||||
The console is enabled when early_param is processed.
|
||||
|
||||
config SERIAL_EARLYCON_RISCV_SBI
|
||||
bool "Early console using RISC-V SBI"
|
||||
@ -1507,7 +1507,7 @@ config SERIAL_MILBEAUT_USIO_CONSOLE
|
||||
config SERIAL_LITEUART
|
||||
tristate "LiteUART serial port support"
|
||||
depends on HAS_IOMEM
|
||||
depends on OF || COMPILE_TEST
|
||||
depends on OF
|
||||
depends on LITEX || COMPILE_TEST
|
||||
select SERIAL_CORE
|
||||
help
|
||||
|
@ -6,7 +6,7 @@
|
||||
obj-$(CONFIG_SERIAL_CORE) += serial_core.o
|
||||
|
||||
obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o
|
||||
obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o
|
||||
obj-$(CONFIG_SERIAL_EARLYCON_SEMIHOST) += earlycon-semihost.o
|
||||
obj-$(CONFIG_SERIAL_EARLYCON_RISCV_SBI) += earlycon-riscv-sbi.o
|
||||
|
||||
# These Sparc drivers have to appear before others such as 8250
|
||||
|
@ -11,30 +11,7 @@
|
||||
#include <linux/console.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/serial_core.h>
|
||||
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
#define SEMIHOST_SWI "0xab"
|
||||
#else
|
||||
#define SEMIHOST_SWI "0x123456"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Semihosting-based debug console
|
||||
*/
|
||||
static void smh_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
#ifdef CONFIG_ARM64
|
||||
asm volatile("mov x1, %0\n"
|
||||
"mov x0, #3\n"
|
||||
"hlt 0xf000\n"
|
||||
: : "r" (&c) : "x0", "x1", "memory");
|
||||
#else
|
||||
asm volatile("mov r1, %0\n"
|
||||
"mov r0, #3\n"
|
||||
"svc " SEMIHOST_SWI "\n"
|
||||
: : "r" (&c) : "r0", "r1", "memory");
|
||||
#endif
|
||||
}
|
||||
#include <asm/semihost.h>
|
||||
|
||||
static void smh_write(struct console *con, const char *s, unsigned n)
|
||||
{
|
@ -120,7 +120,13 @@ static int __init parse_options(struct earlycon_device *device, char *options)
|
||||
}
|
||||
|
||||
if (options) {
|
||||
char *uartclk;
|
||||
|
||||
device->baud = simple_strtoul(options, NULL, 0);
|
||||
uartclk = strchr(options, ',');
|
||||
if (uartclk && kstrtouint(uartclk + 1, 0, &port->uartclk) < 0)
|
||||
pr_warn("[%s] unsupported earlycon uart clkrate option\n",
|
||||
options);
|
||||
length = min(strcspn(options, " ") + 1,
|
||||
(size_t)(sizeof(device->options)));
|
||||
strscpy(device->options, options, length);
|
||||
@ -139,7 +145,8 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
|
||||
buf = NULL;
|
||||
|
||||
spin_lock_init(&port->lock);
|
||||
port->uartclk = BASE_BAUD * 16;
|
||||
if (!port->uartclk)
|
||||
port->uartclk = BASE_BAUD * 16;
|
||||
if (port->mapbase)
|
||||
port->membase = earlycon_map(port->mapbase, 64);
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
* Copyright 2012-2014 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/delay.h>
|
||||
@ -181,7 +183,7 @@
|
||||
#define UARTCTRL_SBK 0x00010000
|
||||
#define UARTCTRL_MA1IE 0x00008000
|
||||
#define UARTCTRL_MA2IE 0x00004000
|
||||
#define UARTCTRL_IDLECFG 0x00000100
|
||||
#define UARTCTRL_IDLECFG GENMASK(10, 8)
|
||||
#define UARTCTRL_LOOPS 0x00000080
|
||||
#define UARTCTRL_DOZEEN 0x00000040
|
||||
#define UARTCTRL_RSRC 0x00000020
|
||||
@ -199,6 +201,7 @@
|
||||
#define UARTDATA_MASK 0x3ff
|
||||
|
||||
#define UARTMODIR_IREN 0x00020000
|
||||
#define UARTMODIR_RTSWATER GENMASK(10, 8)
|
||||
#define UARTMODIR_TXCTSSRC 0x00000020
|
||||
#define UARTMODIR_TXCTSC 0x00000010
|
||||
#define UARTMODIR_RXRTSE 0x00000008
|
||||
@ -212,6 +215,7 @@
|
||||
#define UARTFIFO_RXUF 0x00010000
|
||||
#define UARTFIFO_TXFLUSH 0x00008000
|
||||
#define UARTFIFO_RXFLUSH 0x00004000
|
||||
#define UARTFIFO_RXIDEN GENMASK(12, 10)
|
||||
#define UARTFIFO_TXOFE 0x00000200
|
||||
#define UARTFIFO_RXUFE 0x00000100
|
||||
#define UARTFIFO_TXFE 0x00000080
|
||||
@ -238,7 +242,7 @@
|
||||
|
||||
#define DRIVER_NAME "fsl-lpuart"
|
||||
#define DEV_NAME "ttyLP"
|
||||
#define UART_NR 6
|
||||
#define UART_NR 8
|
||||
|
||||
/* IMX lpuart has four extra unused regs located at the beginning */
|
||||
#define IMX_REG_OFF 0x10
|
||||
@ -248,6 +252,7 @@ enum lpuart_type {
|
||||
LS1021A_LPUART,
|
||||
LS1028A_LPUART,
|
||||
IMX7ULP_LPUART,
|
||||
IMX8ULP_LPUART,
|
||||
IMX8QXP_LPUART,
|
||||
IMXRT1050_LPUART,
|
||||
};
|
||||
@ -260,6 +265,7 @@ struct lpuart_port {
|
||||
unsigned int txfifo_size;
|
||||
unsigned int rxfifo_size;
|
||||
|
||||
u8 rx_watermark;
|
||||
bool lpuart_dma_tx_use;
|
||||
bool lpuart_dma_rx_use;
|
||||
struct dma_chan *dma_tx_chan;
|
||||
@ -286,38 +292,52 @@ struct lpuart_soc_data {
|
||||
enum lpuart_type devtype;
|
||||
char iotype;
|
||||
u8 reg_off;
|
||||
u8 rx_watermark;
|
||||
};
|
||||
|
||||
static const struct lpuart_soc_data vf_data = {
|
||||
.devtype = VF610_LPUART,
|
||||
.iotype = UPIO_MEM,
|
||||
.rx_watermark = 1,
|
||||
};
|
||||
|
||||
static const struct lpuart_soc_data ls1021a_data = {
|
||||
.devtype = LS1021A_LPUART,
|
||||
.iotype = UPIO_MEM32BE,
|
||||
.rx_watermark = 1,
|
||||
};
|
||||
|
||||
static const struct lpuart_soc_data ls1028a_data = {
|
||||
.devtype = LS1028A_LPUART,
|
||||
.iotype = UPIO_MEM32,
|
||||
.rx_watermark = 1,
|
||||
};
|
||||
|
||||
static struct lpuart_soc_data imx7ulp_data = {
|
||||
.devtype = IMX7ULP_LPUART,
|
||||
.iotype = UPIO_MEM32,
|
||||
.reg_off = IMX_REG_OFF,
|
||||
.rx_watermark = 1,
|
||||
};
|
||||
|
||||
static struct lpuart_soc_data imx8ulp_data = {
|
||||
.devtype = IMX8ULP_LPUART,
|
||||
.iotype = UPIO_MEM32,
|
||||
.reg_off = IMX_REG_OFF,
|
||||
.rx_watermark = 3,
|
||||
};
|
||||
|
||||
static struct lpuart_soc_data imx8qxp_data = {
|
||||
.devtype = IMX8QXP_LPUART,
|
||||
.iotype = UPIO_MEM32,
|
||||
.reg_off = IMX_REG_OFF,
|
||||
.rx_watermark = 31,
|
||||
};
|
||||
static struct lpuart_soc_data imxrt1050_data = {
|
||||
.devtype = IMXRT1050_LPUART,
|
||||
.iotype = UPIO_MEM32,
|
||||
.reg_off = IMX_REG_OFF,
|
||||
.rx_watermark = 1,
|
||||
};
|
||||
|
||||
static const struct of_device_id lpuart_dt_ids[] = {
|
||||
@ -325,6 +345,7 @@ static const struct of_device_id lpuart_dt_ids[] = {
|
||||
{ .compatible = "fsl,ls1021a-lpuart", .data = &ls1021a_data, },
|
||||
{ .compatible = "fsl,ls1028a-lpuart", .data = &ls1028a_data, },
|
||||
{ .compatible = "fsl,imx7ulp-lpuart", .data = &imx7ulp_data, },
|
||||
{ .compatible = "fsl,imx8ulp-lpuart", .data = &imx8ulp_data, },
|
||||
{ .compatible = "fsl,imx8qxp-lpuart", .data = &imx8qxp_data, },
|
||||
{ .compatible = "fsl,imxrt1050-lpuart", .data = &imxrt1050_data},
|
||||
{ /* sentinel */ }
|
||||
@ -345,6 +366,11 @@ static inline bool is_imx7ulp_lpuart(struct lpuart_port *sport)
|
||||
return sport->devtype == IMX7ULP_LPUART;
|
||||
}
|
||||
|
||||
static inline bool is_imx8ulp_lpuart(struct lpuart_port *sport)
|
||||
{
|
||||
return sport->devtype == IMX8ULP_LPUART;
|
||||
}
|
||||
|
||||
static inline bool is_imx8qxp_lpuart(struct lpuart_port *sport)
|
||||
{
|
||||
return sport->devtype == IMX8QXP_LPUART;
|
||||
@ -1387,9 +1413,9 @@ static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termio
|
||||
* Note: UART is assumed to be active high.
|
||||
*/
|
||||
if (rs485->flags & SER_RS485_RTS_ON_SEND)
|
||||
modem &= ~UARTMODEM_TXRTSPOL;
|
||||
else if (rs485->flags & SER_RS485_RTS_AFTER_SEND)
|
||||
modem |= UARTMODEM_TXRTSPOL;
|
||||
else if (rs485->flags & SER_RS485_RTS_AFTER_SEND)
|
||||
modem &= ~UARTMODEM_TXRTSPOL;
|
||||
}
|
||||
|
||||
lpuart32_write(&sport->port, modem, UARTMODIR);
|
||||
@ -1462,12 +1488,32 @@ static void lpuart_break_ctl(struct uart_port *port, int break_state)
|
||||
|
||||
static void lpuart32_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
unsigned long temp;
|
||||
unsigned long temp, modem;
|
||||
struct tty_struct *tty;
|
||||
unsigned int cflag = 0;
|
||||
|
||||
tty = tty_port_tty_get(&port->state->port);
|
||||
if (tty) {
|
||||
cflag = tty->termios.c_cflag;
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
temp = lpuart32_read(port, UARTCTRL) & ~UARTCTRL_SBK;
|
||||
modem = lpuart32_read(port, UARTMODIR);
|
||||
|
||||
if (break_state != 0)
|
||||
if (break_state != 0) {
|
||||
temp |= UARTCTRL_SBK;
|
||||
/*
|
||||
* LPUART CTS has higher priority than SBK, need to disable CTS before
|
||||
* asserting SBK to avoid any interference if flow control is enabled.
|
||||
*/
|
||||
if (cflag & CRTSCTS && modem & UARTMODIR_TXCTSE)
|
||||
lpuart32_write(port, modem & ~UARTMODIR_TXCTSE, UARTMODIR);
|
||||
} else {
|
||||
/* Re-enable the CTS when break off. */
|
||||
if (cflag & CRTSCTS && !(modem & UARTMODIR_TXCTSE))
|
||||
lpuart32_write(port, modem | UARTMODIR_TXCTSE, UARTMODIR);
|
||||
}
|
||||
|
||||
lpuart32_write(port, temp, UARTCTRL);
|
||||
}
|
||||
@ -1497,8 +1543,10 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
|
||||
writeb(UARTSFIFO_RXUF, sport->port.membase + UARTSFIFO);
|
||||
}
|
||||
|
||||
if (uart_console(&sport->port))
|
||||
sport->rx_watermark = 1;
|
||||
writeb(0, sport->port.membase + UARTTWFIFO);
|
||||
writeb(1, sport->port.membase + UARTRWFIFO);
|
||||
writeb(sport->rx_watermark, sport->port.membase + UARTRWFIFO);
|
||||
|
||||
/* Restore cr2 */
|
||||
writeb(cr2_saved, sport->port.membase + UARTCR2);
|
||||
@ -1523,19 +1571,30 @@ static void lpuart32_setup_watermark(struct lpuart_port *sport)
|
||||
ctrl = lpuart32_read(&sport->port, UARTCTRL);
|
||||
ctrl_saved = ctrl;
|
||||
ctrl &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_TE |
|
||||
UARTCTRL_RIE | UARTCTRL_RE);
|
||||
UARTCTRL_RIE | UARTCTRL_RE | UARTCTRL_ILIE);
|
||||
lpuart32_write(&sport->port, ctrl, UARTCTRL);
|
||||
|
||||
/* enable FIFO mode */
|
||||
val = lpuart32_read(&sport->port, UARTFIFO);
|
||||
val |= UARTFIFO_TXFE | UARTFIFO_RXFE;
|
||||
val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
|
||||
val |= FIELD_PREP(UARTFIFO_RXIDEN, 0x3);
|
||||
lpuart32_write(&sport->port, val, UARTFIFO);
|
||||
|
||||
/* set the watermark */
|
||||
val = (0x1 << UARTWATER_RXWATER_OFF) | (0x0 << UARTWATER_TXWATER_OFF);
|
||||
if (uart_console(&sport->port))
|
||||
sport->rx_watermark = 1;
|
||||
val = (sport->rx_watermark << UARTWATER_RXWATER_OFF) |
|
||||
(0x0 << UARTWATER_TXWATER_OFF);
|
||||
lpuart32_write(&sport->port, val, UARTWATER);
|
||||
|
||||
/* set RTS watermark */
|
||||
if (!uart_console(&sport->port)) {
|
||||
val = lpuart32_read(&sport->port, UARTMODIR);
|
||||
val |= FIELD_PREP(UARTMODIR_RTSWATER, sport->rxfifo_size >> 1);
|
||||
lpuart32_write(&sport->port, val, UARTMODIR);
|
||||
}
|
||||
|
||||
/* Restore cr2 */
|
||||
lpuart32_write(&sport->port, ctrl_saved, UARTCTRL);
|
||||
}
|
||||
@ -1547,7 +1606,8 @@ static void lpuart32_setup_watermark_enable(struct lpuart_port *sport)
|
||||
lpuart32_setup_watermark(sport);
|
||||
|
||||
temp = lpuart32_read(&sport->port, UARTCTRL);
|
||||
temp |= UARTCTRL_RE | UARTCTRL_TE | UARTCTRL_ILIE;
|
||||
temp |= UARTCTRL_RE | UARTCTRL_TE;
|
||||
temp |= FIELD_PREP(UARTCTRL_IDLECFG, 0x7);
|
||||
lpuart32_write(&sport->port, temp, UARTCTRL);
|
||||
}
|
||||
|
||||
@ -1679,19 +1739,23 @@ static int lpuart_startup(struct uart_port *port)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lpuart32_hw_disable(struct lpuart_port *sport)
|
||||
{
|
||||
unsigned long temp;
|
||||
|
||||
temp = lpuart32_read(&sport->port, UARTCTRL);
|
||||
temp &= ~(UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE |
|
||||
UARTCTRL_TIE | UARTCTRL_TE);
|
||||
lpuart32_write(&sport->port, temp, UARTCTRL);
|
||||
}
|
||||
|
||||
static void lpuart32_configure(struct lpuart_port *sport)
|
||||
{
|
||||
unsigned long temp;
|
||||
|
||||
if (sport->lpuart_dma_rx_use) {
|
||||
/* RXWATER must be 0 */
|
||||
temp = lpuart32_read(&sport->port, UARTWATER);
|
||||
temp &= ~(UARTWATER_WATER_MASK << UARTWATER_RXWATER_OFF);
|
||||
lpuart32_write(&sport->port, temp, UARTWATER);
|
||||
}
|
||||
temp = lpuart32_read(&sport->port, UARTCTRL);
|
||||
if (!sport->lpuart_dma_rx_use)
|
||||
temp |= UARTCTRL_RIE;
|
||||
temp |= UARTCTRL_RIE | UARTCTRL_ILIE;
|
||||
if (!sport->lpuart_dma_tx_use)
|
||||
temp |= UARTCTRL_TIE;
|
||||
lpuart32_write(&sport->port, temp, UARTCTRL);
|
||||
@ -1703,11 +1767,12 @@ static void lpuart32_hw_setup(struct lpuart_port *sport)
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
lpuart32_setup_watermark_enable(sport);
|
||||
lpuart32_hw_disable(sport);
|
||||
|
||||
lpuart_rx_dma_startup(sport);
|
||||
lpuart_tx_dma_startup(sport);
|
||||
|
||||
lpuart32_setup_watermark_enable(sport);
|
||||
lpuart32_configure(sport);
|
||||
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
@ -1796,10 +1861,19 @@ static void lpuart32_shutdown(struct uart_port *port)
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* disable Rx/Tx and interrupts */
|
||||
/* clear status */
|
||||
temp = lpuart32_read(&sport->port, UARTSTAT);
|
||||
lpuart32_write(&sport->port, temp, UARTSTAT);
|
||||
|
||||
/* disable Rx/Tx DMA */
|
||||
temp = lpuart32_read(port, UARTBAUD);
|
||||
temp &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE);
|
||||
lpuart32_write(port, temp, UARTBAUD);
|
||||
|
||||
/* disable Rx/Tx and interrupts and break condition */
|
||||
temp = lpuart32_read(port, UARTCTRL);
|
||||
temp &= ~(UARTCTRL_TE | UARTCTRL_RE |
|
||||
UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE);
|
||||
temp &= ~(UARTCTRL_TE | UARTCTRL_RE | UARTCTRL_ILIE |
|
||||
UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE | UARTCTRL_SBK);
|
||||
lpuart32_write(port, temp, UARTCTRL);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
@ -2631,7 +2705,7 @@ static int lpuart_global_reset(struct lpuart_port *sport)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (is_imx7ulp_lpuart(sport) || is_imx8qxp_lpuart(sport)) {
|
||||
if (is_imx7ulp_lpuart(sport) || is_imx8ulp_lpuart(sport) || is_imx8qxp_lpuart(sport)) {
|
||||
/*
|
||||
* If the transmitter is used by earlycon, wait for transmit engine to
|
||||
* complete and then reset.
|
||||
@ -2688,6 +2762,7 @@ static int lpuart_probe(struct platform_device *pdev)
|
||||
sport->port.dev = &pdev->dev;
|
||||
sport->port.type = PORT_LPUART;
|
||||
sport->devtype = sdata->devtype;
|
||||
sport->rx_watermark = sdata->rx_watermark;
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -210,12 +210,8 @@ struct imx_port {
|
||||
|
||||
struct mctrl_gpios *gpios;
|
||||
|
||||
/* shadow registers */
|
||||
unsigned int ucr1;
|
||||
unsigned int ucr2;
|
||||
unsigned int ucr3;
|
||||
unsigned int ucr4;
|
||||
unsigned int ufcr;
|
||||
/* counter to stop 0xff flood */
|
||||
int idle_counter;
|
||||
|
||||
/* DMA fields */
|
||||
unsigned int dma_is_enabled:1;
|
||||
@ -273,59 +269,14 @@ static const struct of_device_id imx_uart_dt_ids[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx_uart_dt_ids);
|
||||
|
||||
static void imx_uart_writel(struct imx_port *sport, u32 val, u32 offset)
|
||||
static inline void imx_uart_writel(struct imx_port *sport, u32 val, u32 offset)
|
||||
{
|
||||
switch (offset) {
|
||||
case UCR1:
|
||||
sport->ucr1 = val;
|
||||
break;
|
||||
case UCR2:
|
||||
sport->ucr2 = val;
|
||||
break;
|
||||
case UCR3:
|
||||
sport->ucr3 = val;
|
||||
break;
|
||||
case UCR4:
|
||||
sport->ucr4 = val;
|
||||
break;
|
||||
case UFCR:
|
||||
sport->ufcr = val;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
writel(val, sport->port.membase + offset);
|
||||
}
|
||||
|
||||
static u32 imx_uart_readl(struct imx_port *sport, u32 offset)
|
||||
static inline u32 imx_uart_readl(struct imx_port *sport, u32 offset)
|
||||
{
|
||||
switch (offset) {
|
||||
case UCR1:
|
||||
return sport->ucr1;
|
||||
break;
|
||||
case UCR2:
|
||||
/*
|
||||
* UCR2_SRST is the only bit in the cached registers that might
|
||||
* differ from the value that was last written. As it only
|
||||
* automatically becomes one after being cleared, reread
|
||||
* conditionally.
|
||||
*/
|
||||
if (!(sport->ucr2 & UCR2_SRST))
|
||||
sport->ucr2 = readl(sport->port.membase + offset);
|
||||
return sport->ucr2;
|
||||
break;
|
||||
case UCR3:
|
||||
return sport->ucr3;
|
||||
break;
|
||||
case UCR4:
|
||||
return sport->ucr4;
|
||||
break;
|
||||
case UFCR:
|
||||
return sport->ufcr;
|
||||
break;
|
||||
default:
|
||||
return readl(sport->port.membase + offset);
|
||||
}
|
||||
return readl(sport->port.membase + offset);
|
||||
}
|
||||
|
||||
static inline unsigned imx_uart_uts_reg(struct imx_port *sport)
|
||||
@ -397,6 +348,41 @@ static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec)
|
||||
hrtimer_start(hrt, ms_to_ktime(msec), HRTIMER_MODE_REL);
|
||||
}
|
||||
|
||||
/* called with port.lock taken and irqs off */
|
||||
static void imx_uart_soft_reset(struct imx_port *sport)
|
||||
{
|
||||
int i = 10;
|
||||
u32 ucr2, ubir, ubmr, uts;
|
||||
|
||||
/*
|
||||
* According to the Reference Manual description of the UART SRST bit:
|
||||
*
|
||||
* "Reset the transmit and receive state machines,
|
||||
* all FIFOs and register USR1, USR2, UBIR, UBMR, UBRC, URXD, UTXD
|
||||
* and UTS[6-3]".
|
||||
*
|
||||
* We don't need to restore the old values from USR1, USR2, URXD and
|
||||
* UTXD. UBRC is read only, so only save/restore the other three
|
||||
* registers.
|
||||
*/
|
||||
ubir = imx_uart_readl(sport, UBIR);
|
||||
ubmr = imx_uart_readl(sport, UBMR);
|
||||
uts = imx_uart_readl(sport, IMX21_UTS);
|
||||
|
||||
ucr2 = imx_uart_readl(sport, UCR2);
|
||||
imx_uart_writel(sport, ucr2 & ~UCR2_SRST, UCR2);
|
||||
|
||||
while (!(imx_uart_readl(sport, UCR2) & UCR2_SRST) && (--i > 0))
|
||||
udelay(1);
|
||||
|
||||
/* Restore the registers */
|
||||
imx_uart_writel(sport, ubir, UBIR);
|
||||
imx_uart_writel(sport, ubmr, UBMR);
|
||||
imx_uart_writel(sport, uts, IMX21_UTS);
|
||||
|
||||
sport->idle_counter = 0;
|
||||
}
|
||||
|
||||
/* called with port.lock taken and irqs off */
|
||||
static void imx_uart_start_rx(struct uart_port *port)
|
||||
{
|
||||
@ -476,7 +462,8 @@ static void imx_uart_stop_tx(struct uart_port *port)
|
||||
imx_uart_rts_inactive(sport, &ucr2);
|
||||
imx_uart_writel(sport, ucr2, UCR2);
|
||||
|
||||
imx_uart_start_rx(port);
|
||||
if (!port->rs485_rx_during_tx_gpio)
|
||||
imx_uart_start_rx(port);
|
||||
|
||||
sport->tx_state = OFF;
|
||||
}
|
||||
@ -705,7 +692,8 @@ static void imx_uart_start_tx(struct uart_port *port)
|
||||
imx_uart_rts_inactive(sport, &ucr2);
|
||||
imx_uart_writel(sport, ucr2, UCR2);
|
||||
|
||||
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX) &&
|
||||
!port->rs485_rx_during_tx_gpio)
|
||||
imx_uart_stop_rx(port);
|
||||
|
||||
sport->tx_state = WAIT_AFTER_RTS;
|
||||
@ -771,7 +759,7 @@ static irqreturn_t __imx_uart_rtsint(int irq, void *dev_id)
|
||||
|
||||
imx_uart_writel(sport, USR1_RTSD, USR1);
|
||||
usr1 = imx_uart_readl(sport, USR1) & USR1_RTSS;
|
||||
uart_handle_cts_change(&sport->port, !!usr1);
|
||||
uart_handle_cts_change(&sport->port, usr1);
|
||||
wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
@ -801,33 +789,73 @@ static irqreturn_t imx_uart_txint(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* Check if hardware Rx flood is in progress, and issue soft reset to stop it.
|
||||
* This is to be called from Rx ISRs only when some bytes were actually
|
||||
* received.
|
||||
*
|
||||
* A way to reproduce the flood (checked on iMX6SX) is: open iMX UART at 9600
|
||||
* 8N1, and from external source send 0xf0 char at 115200 8N1. In about 90% of
|
||||
* cases this starts a flood of "receiving" of 0xff characters by the iMX6 UART
|
||||
* that is terminated by any activity on RxD line, or could be stopped by
|
||||
* issuing soft reset to the UART (just stop/start of RX does not help). Note
|
||||
* that what we do here is sending isolated start bit about 2.4 times shorter
|
||||
* than it is to be on UART configured baud rate.
|
||||
*/
|
||||
static void imx_uart_check_flood(struct imx_port *sport, u32 usr2)
|
||||
{
|
||||
/* To detect hardware 0xff flood we monitor RxD line between RX
|
||||
* interrupts to isolate "receiving" of char(s) with no activity
|
||||
* on RxD line, that'd never happen on actual data transfers.
|
||||
*
|
||||
* We use USR2_WAKE bit to check for activity on RxD line, but we have a
|
||||
* race here if we clear USR2_WAKE when receiving of a char is in
|
||||
* progress, so we might get RX interrupt later with USR2_WAKE bit
|
||||
* cleared. Note though that as we don't try to clear USR2_WAKE when we
|
||||
* detected no activity, this race may hide actual activity only once.
|
||||
*
|
||||
* Yet another case where receive interrupt may occur without RxD
|
||||
* activity is expiration of aging timer, so we consider this as well.
|
||||
*
|
||||
* We use 'idle_counter' to ensure that we got at least so many RX
|
||||
* interrupts without any detected activity on RxD line. 2 cases
|
||||
* described plus 1 to be on the safe side gives us a margin of 3,
|
||||
* below. In practice I was not able to produce a false positive to
|
||||
* induce soft reset at regular data transfers even using 1 as the
|
||||
* margin, so 3 is actually very strong.
|
||||
*
|
||||
* We count interrupts, not chars in 'idle-counter' for simplicity.
|
||||
*/
|
||||
|
||||
if (usr2 & USR2_WAKE) {
|
||||
imx_uart_writel(sport, USR2_WAKE, USR2);
|
||||
sport->idle_counter = 0;
|
||||
} else if (++sport->idle_counter > 3) {
|
||||
dev_warn(sport->port.dev, "RX flood detected: soft reset.");
|
||||
imx_uart_soft_reset(sport); /* also clears 'sport->idle_counter' */
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t __imx_uart_rxint(int irq, void *dev_id)
|
||||
{
|
||||
struct imx_port *sport = dev_id;
|
||||
unsigned int rx, flg, ignored = 0;
|
||||
struct tty_port *port = &sport->port.state->port;
|
||||
u32 usr2, rx;
|
||||
|
||||
while (imx_uart_readl(sport, USR2) & USR2_RDR) {
|
||||
u32 usr2;
|
||||
/* If we received something, check for 0xff flood */
|
||||
usr2 = imx_uart_readl(sport, USR2);
|
||||
if (usr2 & USR2_RDR)
|
||||
imx_uart_check_flood(sport, usr2);
|
||||
|
||||
flg = TTY_NORMAL;
|
||||
while ((rx = imx_uart_readl(sport, URXD0)) & URXD_CHARRDY) {
|
||||
unsigned int flg = TTY_NORMAL;
|
||||
sport->port.icount.rx++;
|
||||
|
||||
rx = imx_uart_readl(sport, URXD0);
|
||||
|
||||
usr2 = imx_uart_readl(sport, USR2);
|
||||
if (usr2 & USR2_BRCD) {
|
||||
imx_uart_writel(sport, USR2_BRCD, USR2);
|
||||
if (uart_handle_break(&sport->port))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
|
||||
continue;
|
||||
|
||||
if (unlikely(rx & URXD_ERR)) {
|
||||
if (rx & URXD_BRK)
|
||||
if (rx & URXD_BRK) {
|
||||
sport->port.icount.brk++;
|
||||
if (uart_handle_break(&sport->port))
|
||||
continue;
|
||||
}
|
||||
else if (rx & URXD_PRERR)
|
||||
sport->port.icount.parity++;
|
||||
else if (rx & URXD_FRMERR)
|
||||
@ -835,11 +863,8 @@ static irqreturn_t __imx_uart_rxint(int irq, void *dev_id)
|
||||
if (rx & URXD_OVRRUN)
|
||||
sport->port.icount.overrun++;
|
||||
|
||||
if (rx & sport->port.ignore_status_mask) {
|
||||
if (++ignored > 100)
|
||||
goto out;
|
||||
if (rx & sport->port.ignore_status_mask)
|
||||
continue;
|
||||
}
|
||||
|
||||
rx &= (sport->port.read_status_mask | 0xFF);
|
||||
|
||||
@ -853,16 +878,17 @@ static irqreturn_t __imx_uart_rxint(int irq, void *dev_id)
|
||||
flg = TTY_OVERRUN;
|
||||
|
||||
sport->port.sysrq = 0;
|
||||
} else if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sport->port.ignore_status_mask & URXD_DUMMY_READ)
|
||||
goto out;
|
||||
continue;
|
||||
|
||||
if (tty_insert_flip_char(port, rx, flg) == 0)
|
||||
sport->port.icount.buf_overrun++;
|
||||
}
|
||||
|
||||
out:
|
||||
tty_flip_buffer_push(port);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
@ -1147,55 +1173,62 @@ static void imx_uart_dma_rx_callback(void *data)
|
||||
status = dmaengine_tx_status(chan, sport->rx_cookie, &state);
|
||||
|
||||
if (status == DMA_ERROR) {
|
||||
spin_lock(&sport->port.lock);
|
||||
imx_uart_clear_rx_errors(sport);
|
||||
spin_unlock(&sport->port.lock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) {
|
||||
/*
|
||||
* The state-residue variable represents the empty space
|
||||
* relative to the entire buffer. Taking this in consideration
|
||||
* the head is always calculated base on the buffer total
|
||||
* length - DMA transaction residue. The UART script from the
|
||||
* SDMA firmware will jump to the next buffer descriptor,
|
||||
* once a DMA transaction if finalized (IMX53 RM - A.4.1.2.4).
|
||||
* Taking this in consideration the tail is always at the
|
||||
* beginning of the buffer descriptor that contains the head.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The state-residue variable represents the empty space
|
||||
* relative to the entire buffer. Taking this in consideration
|
||||
* the head is always calculated base on the buffer total
|
||||
* length - DMA transaction residue. The UART script from the
|
||||
* SDMA firmware will jump to the next buffer descriptor,
|
||||
* once a DMA transaction if finalized (IMX53 RM - A.4.1.2.4).
|
||||
* Taking this in consideration the tail is always at the
|
||||
* beginning of the buffer descriptor that contains the head.
|
||||
*/
|
||||
/* Calculate the head */
|
||||
rx_ring->head = sg_dma_len(sgl) - state.residue;
|
||||
|
||||
/* Calculate the head */
|
||||
rx_ring->head = sg_dma_len(sgl) - state.residue;
|
||||
/* Calculate the tail. */
|
||||
bd_size = sg_dma_len(sgl) / sport->rx_periods;
|
||||
rx_ring->tail = ((rx_ring->head-1) / bd_size) * bd_size;
|
||||
|
||||
/* Calculate the tail. */
|
||||
bd_size = sg_dma_len(sgl) / sport->rx_periods;
|
||||
rx_ring->tail = ((rx_ring->head-1) / bd_size) * bd_size;
|
||||
if (rx_ring->head <= sg_dma_len(sgl) &&
|
||||
rx_ring->head > rx_ring->tail) {
|
||||
|
||||
if (rx_ring->head <= sg_dma_len(sgl) &&
|
||||
rx_ring->head > rx_ring->tail) {
|
||||
/* Move data from tail to head */
|
||||
r_bytes = rx_ring->head - rx_ring->tail;
|
||||
|
||||
/* Move data from tail to head */
|
||||
r_bytes = rx_ring->head - rx_ring->tail;
|
||||
/* If we received something, check for 0xff flood */
|
||||
spin_lock(&sport->port.lock);
|
||||
imx_uart_check_flood(sport, imx_uart_readl(sport, USR2));
|
||||
spin_unlock(&sport->port.lock);
|
||||
|
||||
if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) {
|
||||
|
||||
/* CPU claims ownership of RX DMA buffer */
|
||||
dma_sync_sg_for_cpu(sport->port.dev, sgl, 1,
|
||||
DMA_FROM_DEVICE);
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
w_bytes = tty_insert_flip_string(port,
|
||||
sport->rx_buf + rx_ring->tail, r_bytes);
|
||||
sport->rx_buf + rx_ring->tail, r_bytes);
|
||||
|
||||
/* UART retrieves ownership of RX DMA buffer */
|
||||
dma_sync_sg_for_device(sport->port.dev, sgl, 1,
|
||||
DMA_FROM_DEVICE);
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
if (w_bytes != r_bytes)
|
||||
sport->port.icount.buf_overrun++;
|
||||
|
||||
sport->port.icount.rx += w_bytes;
|
||||
} else {
|
||||
WARN_ON(rx_ring->head > sg_dma_len(sgl));
|
||||
WARN_ON(rx_ring->head <= rx_ring->tail);
|
||||
}
|
||||
} else {
|
||||
WARN_ON(rx_ring->head > sg_dma_len(sgl));
|
||||
WARN_ON(rx_ring->head <= rx_ring->tail);
|
||||
}
|
||||
|
||||
if (w_bytes) {
|
||||
@ -1271,6 +1304,8 @@ static void imx_uart_clear_rx_errors(struct imx_port *sport)
|
||||
imx_uart_writel(sport, USR2_ORE, USR2);
|
||||
}
|
||||
|
||||
sport->idle_counter = 0;
|
||||
|
||||
}
|
||||
|
||||
#define TXTL_DEFAULT 2 /* reset default */
|
||||
@ -1398,7 +1433,7 @@ static void imx_uart_disable_dma(struct imx_port *sport)
|
||||
static int imx_uart_startup(struct uart_port *port)
|
||||
{
|
||||
struct imx_port *sport = (struct imx_port *)port;
|
||||
int retval, i;
|
||||
int retval;
|
||||
unsigned long flags;
|
||||
int dma_is_inited = 0;
|
||||
u32 ucr1, ucr2, ucr3, ucr4, uts;
|
||||
@ -1430,15 +1465,9 @@ static int imx_uart_startup(struct uart_port *port)
|
||||
dma_is_inited = 1;
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
/* Reset fifo's and state machines */
|
||||
i = 100;
|
||||
|
||||
ucr2 = imx_uart_readl(sport, UCR2);
|
||||
ucr2 &= ~UCR2_SRST;
|
||||
imx_uart_writel(sport, ucr2, UCR2);
|
||||
|
||||
while (!(imx_uart_readl(sport, UCR2) & UCR2_SRST) && (--i > 0))
|
||||
udelay(1);
|
||||
imx_uart_soft_reset(sport);
|
||||
|
||||
/*
|
||||
* Finally, clear and enable interrupts
|
||||
@ -1564,7 +1593,8 @@ static void imx_uart_shutdown(struct uart_port *port)
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
ucr1 = imx_uart_readl(sport, UCR1);
|
||||
ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_RXDMAEN | UCR1_ATDMAEN);
|
||||
ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_RXDMAEN |
|
||||
UCR1_ATDMAEN | UCR1_SNDBRK);
|
||||
/* See SER_RS485_ENABLED/UTS_LOOP comment in imx_uart_probe() */
|
||||
if (port->rs485.flags & SER_RS485_ENABLED &&
|
||||
port->rs485.flags & SER_RS485_RTS_ON_SEND &&
|
||||
@ -1593,8 +1623,6 @@ static void imx_uart_flush_buffer(struct uart_port *port)
|
||||
{
|
||||
struct imx_port *sport = (struct imx_port *)port;
|
||||
struct scatterlist *sgl = &sport->tx_sgl[0];
|
||||
u32 ucr2;
|
||||
int i = 100, ubir, ubmr, uts;
|
||||
|
||||
if (!sport->dma_chan_tx)
|
||||
return;
|
||||
@ -1612,32 +1640,8 @@ static void imx_uart_flush_buffer(struct uart_port *port)
|
||||
sport->dma_is_txing = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* According to the Reference Manual description of the UART SRST bit:
|
||||
*
|
||||
* "Reset the transmit and receive state machines,
|
||||
* all FIFOs and register USR1, USR2, UBIR, UBMR, UBRC, URXD, UTXD
|
||||
* and UTS[6-3]".
|
||||
*
|
||||
* We don't need to restore the old values from USR1, USR2, URXD and
|
||||
* UTXD. UBRC is read only, so only save/restore the other three
|
||||
* registers.
|
||||
*/
|
||||
ubir = imx_uart_readl(sport, UBIR);
|
||||
ubmr = imx_uart_readl(sport, UBMR);
|
||||
uts = imx_uart_readl(sport, IMX21_UTS);
|
||||
imx_uart_soft_reset(sport);
|
||||
|
||||
ucr2 = imx_uart_readl(sport, UCR2);
|
||||
ucr2 &= ~UCR2_SRST;
|
||||
imx_uart_writel(sport, ucr2, UCR2);
|
||||
|
||||
while (!(imx_uart_readl(sport, UCR2) & UCR2_SRST) && (--i > 0))
|
||||
udelay(1);
|
||||
|
||||
/* Restore the registers */
|
||||
imx_uart_writel(sport, ubir, UBIR);
|
||||
imx_uart_writel(sport, ubmr, UBMR);
|
||||
imx_uart_writel(sport, uts, IMX21_UTS);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1955,6 +1959,10 @@ static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termio
|
||||
rs485conf->flags & SER_RS485_RX_DURING_TX)
|
||||
imx_uart_start_rx(port);
|
||||
|
||||
if (port->rs485_rx_during_tx_gpio)
|
||||
gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio,
|
||||
!!(rs485conf->flags & SER_RS485_RX_DURING_TX));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2340,13 +2348,6 @@ static int imx_uart_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* initialize shadow register values */
|
||||
sport->ucr1 = readl(sport->port.membase + UCR1);
|
||||
sport->ucr2 = readl(sport->port.membase + UCR2);
|
||||
sport->ucr3 = readl(sport->port.membase + UCR3);
|
||||
sport->ucr4 = readl(sport->port.membase + UCR4);
|
||||
sport->ufcr = readl(sport->port.membase + UFCR);
|
||||
|
||||
ret = uart_get_rs485_mode(&sport->port);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(sport->clk_ipg);
|
||||
@ -2374,6 +2375,11 @@ static int imx_uart_probe(struct platform_device *pdev)
|
||||
ucr1 &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | UCR1_RTSDEN);
|
||||
imx_uart_writel(sport, ucr1, UCR1);
|
||||
|
||||
/* Disable Ageing Timer interrupt */
|
||||
ucr2 = imx_uart_readl(sport, UCR2);
|
||||
ucr2 &= ~UCR2_ATEN;
|
||||
imx_uart_writel(sport, ucr2, UCR2);
|
||||
|
||||
/*
|
||||
* In case RS485 is enabled without GPIO RTS control, the UART IP
|
||||
* is used to control CTS signal. Keep both the UART and Receiver
|
||||
|
@ -5,7 +5,9 @@
|
||||
* Copyright (C) 2019-2020 Antmicro <www.antmicro.com>
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/litex.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
@ -38,13 +40,13 @@
|
||||
#define OFF_EV_ENABLE 0x14
|
||||
|
||||
/* events */
|
||||
#define EV_TX 0x1
|
||||
#define EV_RX 0x2
|
||||
#define EV_TX BIT(0)
|
||||
#define EV_RX BIT(1)
|
||||
|
||||
struct liteuart_port {
|
||||
struct uart_port port;
|
||||
struct timer_list timer;
|
||||
u32 id;
|
||||
u8 irq_reg;
|
||||
};
|
||||
|
||||
#define to_liteuart_port(port) container_of(port, struct liteuart_port, port)
|
||||
@ -57,7 +59,7 @@ static struct console liteuart_console;
|
||||
|
||||
static struct uart_driver liteuart_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = "liteuart",
|
||||
.driver_name = KBUILD_MODNAME,
|
||||
.dev_name = "ttyLXU",
|
||||
.major = 0,
|
||||
.minor = 0,
|
||||
@ -67,38 +69,95 @@ static struct uart_driver liteuart_driver = {
|
||||
#endif
|
||||
};
|
||||
|
||||
static void liteuart_timer(struct timer_list *t)
|
||||
static void liteuart_update_irq_reg(struct uart_port *port, bool set, u8 mask)
|
||||
{
|
||||
struct liteuart_port *uart = from_timer(uart, t, timer);
|
||||
struct uart_port *port = &uart->port;
|
||||
unsigned char __iomem *membase = port->membase;
|
||||
unsigned int flg = TTY_NORMAL;
|
||||
int ch;
|
||||
unsigned long status;
|
||||
struct liteuart_port *uart = to_liteuart_port(port);
|
||||
|
||||
while ((status = !litex_read8(membase + OFF_RXEMPTY)) == 1) {
|
||||
if (set)
|
||||
uart->irq_reg |= mask;
|
||||
else
|
||||
uart->irq_reg &= ~mask;
|
||||
|
||||
if (port->irq)
|
||||
litex_write8(port->membase + OFF_EV_ENABLE, uart->irq_reg);
|
||||
}
|
||||
|
||||
static void liteuart_stop_tx(struct uart_port *port)
|
||||
{
|
||||
liteuart_update_irq_reg(port, false, EV_TX);
|
||||
}
|
||||
|
||||
static void liteuart_start_tx(struct uart_port *port)
|
||||
{
|
||||
liteuart_update_irq_reg(port, true, EV_TX);
|
||||
}
|
||||
|
||||
static void liteuart_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct liteuart_port *uart = to_liteuart_port(port);
|
||||
|
||||
/* just delete timer */
|
||||
del_timer(&uart->timer);
|
||||
}
|
||||
|
||||
static void liteuart_rx_chars(struct uart_port *port)
|
||||
{
|
||||
unsigned char __iomem *membase = port->membase;
|
||||
u8 ch;
|
||||
|
||||
while (!litex_read8(membase + OFF_RXEMPTY)) {
|
||||
ch = litex_read8(membase + OFF_RXTX);
|
||||
port->icount.rx++;
|
||||
|
||||
/* necessary for RXEMPTY to refresh its value */
|
||||
litex_write8(membase + OFF_EV_PENDING, EV_TX | EV_RX);
|
||||
litex_write8(membase + OFF_EV_PENDING, EV_RX);
|
||||
|
||||
/* no overflow bits in status */
|
||||
if (!(uart_handle_sysrq_char(port, ch)))
|
||||
uart_insert_char(port, status, 0, ch, flg);
|
||||
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
uart_insert_char(port, 1, 0, ch, TTY_NORMAL);
|
||||
}
|
||||
|
||||
mod_timer(&uart->timer, jiffies + uart_poll_timeout(port));
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
}
|
||||
|
||||
static void liteuart_putchar(struct uart_port *port, unsigned char ch)
|
||||
static void liteuart_tx_chars(struct uart_port *port)
|
||||
{
|
||||
while (litex_read8(port->membase + OFF_TXFULL))
|
||||
cpu_relax();
|
||||
u8 ch;
|
||||
|
||||
litex_write8(port->membase + OFF_RXTX, ch);
|
||||
uart_port_tx(port, ch,
|
||||
!litex_read8(port->membase + OFF_TXFULL),
|
||||
litex_write8(port->membase + OFF_RXTX, ch));
|
||||
}
|
||||
|
||||
static irqreturn_t liteuart_interrupt(int irq, void *data)
|
||||
{
|
||||
struct liteuart_port *uart = data;
|
||||
struct uart_port *port = &uart->port;
|
||||
unsigned long flags;
|
||||
u8 isr;
|
||||
|
||||
/*
|
||||
* if polling, the context would be "in_serving_softirq", so use
|
||||
* irq[save|restore] spin_lock variants to cover all possibilities
|
||||
*/
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
isr = litex_read8(port->membase + OFF_EV_PENDING) & uart->irq_reg;
|
||||
if (isr & EV_RX)
|
||||
liteuart_rx_chars(port);
|
||||
if (isr & EV_TX)
|
||||
liteuart_tx_chars(port);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
return IRQ_RETVAL(isr);
|
||||
}
|
||||
|
||||
static void liteuart_timer(struct timer_list *t)
|
||||
{
|
||||
struct liteuart_port *uart = from_timer(uart, t, timer);
|
||||
struct uart_port *port = &uart->port;
|
||||
|
||||
liteuart_interrupt(0, port);
|
||||
mod_timer(&uart->timer, jiffies + uart_poll_timeout(port));
|
||||
}
|
||||
|
||||
static unsigned int liteuart_tx_empty(struct uart_port *port)
|
||||
@ -120,60 +179,49 @@ static unsigned int liteuart_get_mctrl(struct uart_port *port)
|
||||
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
|
||||
}
|
||||
|
||||
static void liteuart_stop_tx(struct uart_port *port)
|
||||
{
|
||||
}
|
||||
|
||||
static void liteuart_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned char ch;
|
||||
|
||||
if (unlikely(port->x_char)) {
|
||||
litex_write8(port->membase + OFF_RXTX, port->x_char);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
} else if (!uart_circ_empty(xmit)) {
|
||||
while (xmit->head != xmit->tail) {
|
||||
ch = xmit->buf[xmit->tail];
|
||||
uart_xmit_advance(port, 1);
|
||||
liteuart_putchar(port, ch);
|
||||
}
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
}
|
||||
|
||||
static void liteuart_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct liteuart_port *uart = to_liteuart_port(port);
|
||||
|
||||
/* just delete timer */
|
||||
del_timer(&uart->timer);
|
||||
}
|
||||
|
||||
static void liteuart_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
/* LiteUART doesn't support sending break signal */
|
||||
}
|
||||
|
||||
static int liteuart_startup(struct uart_port *port)
|
||||
{
|
||||
struct liteuart_port *uart = to_liteuart_port(port);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
/* disable events */
|
||||
litex_write8(port->membase + OFF_EV_ENABLE, 0);
|
||||
if (port->irq) {
|
||||
ret = request_irq(port->irq, liteuart_interrupt, 0,
|
||||
KBUILD_MODNAME, uart);
|
||||
if (ret) {
|
||||
dev_warn(port->dev,
|
||||
"line %d irq %d failed: switch to polling\n",
|
||||
port->line, port->irq);
|
||||
port->irq = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* prepare timer for polling */
|
||||
timer_setup(&uart->timer, liteuart_timer, 0);
|
||||
mod_timer(&uart->timer, jiffies + uart_poll_timeout(port));
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
/* only enabling rx irqs during startup */
|
||||
liteuart_update_irq_reg(port, true, EV_RX);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
if (!port->irq) {
|
||||
timer_setup(&uart->timer, liteuart_timer, 0);
|
||||
mod_timer(&uart->timer, jiffies + uart_poll_timeout(port));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void liteuart_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct liteuart_port *uart = to_liteuart_port(port);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
liteuart_update_irq_reg(port, false, EV_RX | EV_TX);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
if (port->irq)
|
||||
free_irq(port->irq, port);
|
||||
else
|
||||
del_timer_sync(&uart->timer);
|
||||
}
|
||||
|
||||
static void liteuart_set_termios(struct uart_port *port, struct ktermios *new,
|
||||
@ -196,15 +244,6 @@ static const char *liteuart_type(struct uart_port *port)
|
||||
return "liteuart";
|
||||
}
|
||||
|
||||
static void liteuart_release_port(struct uart_port *port)
|
||||
{
|
||||
}
|
||||
|
||||
static int liteuart_request_port(struct uart_port *port)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void liteuart_config_port(struct uart_port *port, int flags)
|
||||
{
|
||||
/*
|
||||
@ -231,13 +270,10 @@ static const struct uart_ops liteuart_ops = {
|
||||
.stop_tx = liteuart_stop_tx,
|
||||
.start_tx = liteuart_start_tx,
|
||||
.stop_rx = liteuart_stop_rx,
|
||||
.break_ctl = liteuart_break_ctl,
|
||||
.startup = liteuart_startup,
|
||||
.shutdown = liteuart_shutdown,
|
||||
.set_termios = liteuart_set_termios,
|
||||
.type = liteuart_type,
|
||||
.release_port = liteuart_release_port,
|
||||
.request_port = liteuart_request_port,
|
||||
.config_port = liteuart_config_port,
|
||||
.verify_port = liteuart_verify_port,
|
||||
};
|
||||
@ -249,6 +285,23 @@ static int liteuart_probe(struct platform_device *pdev)
|
||||
struct xa_limit limit;
|
||||
int dev_id, ret;
|
||||
|
||||
uart = devm_kzalloc(&pdev->dev, sizeof(struct liteuart_port), GFP_KERNEL);
|
||||
if (!uart)
|
||||
return -ENOMEM;
|
||||
|
||||
port = &uart->port;
|
||||
|
||||
/* get membase */
|
||||
port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
|
||||
if (IS_ERR(port->membase))
|
||||
return PTR_ERR(port->membase);
|
||||
|
||||
ret = platform_get_irq_optional(pdev, 0);
|
||||
if (ret < 0 && ret != -ENXIO)
|
||||
return ret;
|
||||
if (ret > 0)
|
||||
port->irq = ret;
|
||||
|
||||
/* look for aliases; auto-enumerate for free index if not found */
|
||||
dev_id = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
if (dev_id < 0)
|
||||
@ -256,32 +309,16 @@ static int liteuart_probe(struct platform_device *pdev)
|
||||
else
|
||||
limit = XA_LIMIT(dev_id, dev_id);
|
||||
|
||||
uart = devm_kzalloc(&pdev->dev, sizeof(struct liteuart_port), GFP_KERNEL);
|
||||
if (!uart)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = xa_alloc(&liteuart_array, &dev_id, uart, limit, GFP_KERNEL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
uart->id = dev_id;
|
||||
port = &uart->port;
|
||||
|
||||
/* get membase */
|
||||
port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
|
||||
if (IS_ERR(port->membase)) {
|
||||
ret = PTR_ERR(port->membase);
|
||||
goto err_erase_id;
|
||||
}
|
||||
|
||||
/* values not from device tree */
|
||||
port->dev = &pdev->dev;
|
||||
port->iotype = UPIO_MEM;
|
||||
port->flags = UPF_BOOT_AUTOCONF;
|
||||
port->ops = &liteuart_ops;
|
||||
port->regshift = 2;
|
||||
port->fifosize = 16;
|
||||
port->iobase = 1;
|
||||
port->type = PORT_UNKNOWN;
|
||||
port->line = dev_id;
|
||||
spin_lock_init(&port->lock);
|
||||
@ -295,7 +332,7 @@ static int liteuart_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
err_erase_id:
|
||||
xa_erase(&liteuart_array, uart->id);
|
||||
xa_erase(&liteuart_array, dev_id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -303,10 +340,10 @@ static int liteuart_probe(struct platform_device *pdev)
|
||||
static int liteuart_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_port *port = platform_get_drvdata(pdev);
|
||||
struct liteuart_port *uart = to_liteuart_port(port);
|
||||
unsigned int line = port->line;
|
||||
|
||||
uart_remove_one_port(&liteuart_driver, port);
|
||||
xa_erase(&liteuart_array, uart->id);
|
||||
xa_erase(&liteuart_array, line);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -321,13 +358,21 @@ static struct platform_driver liteuart_platform_driver = {
|
||||
.probe = liteuart_probe,
|
||||
.remove = liteuart_remove,
|
||||
.driver = {
|
||||
.name = "liteuart",
|
||||
.name = KBUILD_MODNAME,
|
||||
.of_match_table = liteuart_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_LITEUART_CONSOLE
|
||||
|
||||
static void liteuart_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
while (litex_read8(port->membase + OFF_TXFULL))
|
||||
cpu_relax();
|
||||
|
||||
litex_write8(port->membase + OFF_RXTX, ch);
|
||||
}
|
||||
|
||||
static void liteuart_console_write(struct console *co, const char *s,
|
||||
unsigned int count)
|
||||
{
|
||||
@ -367,7 +412,7 @@ static int liteuart_console_setup(struct console *co, char *options)
|
||||
}
|
||||
|
||||
static struct console liteuart_console = {
|
||||
.name = "liteuart",
|
||||
.name = KBUILD_MODNAME,
|
||||
.write = liteuart_console_write,
|
||||
.device = uart_console_device,
|
||||
.setup = liteuart_console_setup,
|
||||
@ -415,12 +460,10 @@ static int __init liteuart_init(void)
|
||||
return res;
|
||||
|
||||
res = platform_driver_register(&liteuart_platform_driver);
|
||||
if (res) {
|
||||
if (res)
|
||||
uart_unregister_driver(&liteuart_driver);
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void __exit liteuart_exit(void)
|
||||
|
@ -247,7 +247,7 @@ static int max3100_handlerx(struct max3100_port *s, u16 rx)
|
||||
cts = (rx & MAX3100_CTS) > 0;
|
||||
if (s->cts != cts) {
|
||||
s->cts = cts;
|
||||
uart_handle_cts_change(&s->port, cts ? TIOCM_CTS : 0);
|
||||
uart_handle_cts_change(&s->port, cts);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -819,8 +819,7 @@ static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno)
|
||||
|
||||
if (ists & MAX310X_IRQ_CTS_BIT) {
|
||||
lsr = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG);
|
||||
uart_handle_cts_change(port,
|
||||
!!(lsr & MAX310X_LSR_CTS_BIT));
|
||||
uart_handle_cts_change(port, lsr & MAX310X_LSR_CTS_BIT);
|
||||
}
|
||||
if (rxlen)
|
||||
max310x_handle_rx(port, rxlen);
|
||||
|
@ -1120,6 +1120,7 @@ msm_find_best_baud(struct uart_port *port, unsigned int baud,
|
||||
|
||||
static int msm_set_baud_rate(struct uart_port *port, unsigned int baud,
|
||||
unsigned long *saved_flags)
|
||||
__must_hold(&port->lock)
|
||||
{
|
||||
unsigned int rxstale, watermark, mask;
|
||||
struct msm_port *msm_port = to_msm_port(port);
|
||||
|
@ -1775,7 +1775,7 @@ static void pch_uart_exit_port(struct eg20t_port *priv)
|
||||
char name[32];
|
||||
|
||||
snprintf(name, sizeof(name), "uart%d_regs", priv->port.line);
|
||||
debugfs_remove(debugfs_lookup(name, NULL));
|
||||
debugfs_lookup_and_remove(name, NULL);
|
||||
uart_remove_one_port(&pch_uart_driver, &priv->port);
|
||||
free_page((unsigned long)priv->rxbuf.buf);
|
||||
}
|
||||
|
@ -889,6 +889,8 @@ static int pic32_uart_probe(struct platform_device *pdev)
|
||||
sport->irq_rx = irq_of_parse_and_map(np, 1);
|
||||
sport->irq_tx = irq_of_parse_and_map(np, 2);
|
||||
sport->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(sport->clk))
|
||||
return PTR_ERR(sport->clk);
|
||||
sport->dev = &pdev->dev;
|
||||
|
||||
/* Hardware flow control: gpios
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1423,25 +1423,6 @@ static int sc16is7xx_probe(struct device *dev,
|
||||
}
|
||||
sched_set_fifo(s->kworker_task);
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
if (devtype->nr_gpio) {
|
||||
/* Setup GPIO cotroller */
|
||||
s->gpio.owner = THIS_MODULE;
|
||||
s->gpio.parent = dev;
|
||||
s->gpio.label = dev_name(dev);
|
||||
s->gpio.direction_input = sc16is7xx_gpio_direction_input;
|
||||
s->gpio.get = sc16is7xx_gpio_get;
|
||||
s->gpio.direction_output = sc16is7xx_gpio_direction_output;
|
||||
s->gpio.set = sc16is7xx_gpio_set;
|
||||
s->gpio.base = -1;
|
||||
s->gpio.ngpio = devtype->nr_gpio;
|
||||
s->gpio.can_sleep = 1;
|
||||
ret = gpiochip_add_data(&s->gpio, s);
|
||||
if (ret)
|
||||
goto out_thread;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* reset device, purging any pending irq / data */
|
||||
regmap_write(s->regmap, SC16IS7XX_IOCONTROL_REG << SC16IS7XX_REG_SHIFT,
|
||||
SC16IS7XX_IOCONTROL_SRESET_BIT);
|
||||
@ -1518,6 +1499,25 @@ static int sc16is7xx_probe(struct device *dev,
|
||||
s->p[u].irda_mode = true;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
if (devtype->nr_gpio) {
|
||||
/* Setup GPIO cotroller */
|
||||
s->gpio.owner = THIS_MODULE;
|
||||
s->gpio.parent = dev;
|
||||
s->gpio.label = dev_name(dev);
|
||||
s->gpio.direction_input = sc16is7xx_gpio_direction_input;
|
||||
s->gpio.get = sc16is7xx_gpio_get;
|
||||
s->gpio.direction_output = sc16is7xx_gpio_direction_output;
|
||||
s->gpio.set = sc16is7xx_gpio_set;
|
||||
s->gpio.base = -1;
|
||||
s->gpio.ngpio = devtype->nr_gpio;
|
||||
s->gpio.can_sleep = 1;
|
||||
ret = gpiochip_add_data(&s->gpio, s);
|
||||
if (ret)
|
||||
goto out_thread;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Setup interrupt. We first try to acquire the IRQ line as level IRQ.
|
||||
* If that succeeds, we can allow sharing the interrupt as well.
|
||||
@ -1537,18 +1537,19 @@ static int sc16is7xx_probe(struct device *dev,
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
out_ports:
|
||||
for (i--; i >= 0; i--) {
|
||||
uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
|
||||
clear_bit(s->p[i].port.line, &sc16is7xx_lines);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
if (devtype->nr_gpio)
|
||||
gpiochip_remove(&s->gpio);
|
||||
|
||||
out_thread:
|
||||
#endif
|
||||
|
||||
out_ports:
|
||||
for (i--; i >= 0; i--) {
|
||||
uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
|
||||
clear_bit(s->p[i].port.line, &sc16is7xx_lines);
|
||||
}
|
||||
|
||||
kthread_stop(s->kworker_task);
|
||||
|
||||
out_clk:
|
||||
|
@ -913,23 +913,13 @@ static int sccnxp_probe(struct platform_device *pdev)
|
||||
} else if (PTR_ERR(s->regulator) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
clk = devm_clk_get(&pdev->dev, NULL);
|
||||
clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
goto err_out;
|
||||
uartclk = 0;
|
||||
} else {
|
||||
ret = clk_prepare_enable(clk);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
ret = devm_add_action_or_reset(&pdev->dev,
|
||||
(void(*)(void *))clk_disable_unprepare,
|
||||
clk);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
uartclk = clk_get_rate(clk);
|
||||
}
|
||||
|
||||
|
@ -1046,6 +1046,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)
|
||||
if (tup->cdata->fifo_mode_enable_status) {
|
||||
ret = tegra_uart_wait_fifo_mode_enabled(tup);
|
||||
if (ret < 0) {
|
||||
clk_disable_unprepare(tup->uart_clk);
|
||||
dev_err(tup->uport.dev,
|
||||
"Failed to enable FIFO mode: %d\n", ret);
|
||||
return ret;
|
||||
@ -1067,6 +1068,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)
|
||||
*/
|
||||
ret = tegra_set_baudrate(tup, TEGRA_UART_DEFAULT_BAUD);
|
||||
if (ret < 0) {
|
||||
clk_disable_unprepare(tup->uart_clk);
|
||||
dev_err(tup->uport.dev, "Failed to set baud rate\n");
|
||||
return ret;
|
||||
}
|
||||
@ -1226,10 +1228,13 @@ static int tegra_uart_startup(struct uart_port *u)
|
||||
dev_name(u->dev), tup);
|
||||
if (ret < 0) {
|
||||
dev_err(u->dev, "Failed to register ISR for IRQ %d\n", u->irq);
|
||||
goto fail_hw_init;
|
||||
goto fail_request_irq;
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail_request_irq:
|
||||
/* tup->uart_clk is already enabled in tegra_uart_hw_init */
|
||||
clk_disable_unprepare(tup->uart_clk);
|
||||
fail_hw_init:
|
||||
if (!tup->use_rx_pio)
|
||||
tegra_uart_dma_channel_free(tup, true);
|
||||
|
@ -169,9 +169,9 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
|
||||
#define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0)
|
||||
#define uart_clear_mctrl(port, clear) uart_update_mctrl(port, 0, clear)
|
||||
|
||||
static void uart_port_dtr_rts(struct uart_port *uport, int raise)
|
||||
static void uart_port_dtr_rts(struct uart_port *uport, bool active)
|
||||
{
|
||||
if (raise)
|
||||
if (active)
|
||||
uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
|
||||
else
|
||||
uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
|
||||
@ -182,7 +182,7 @@ static void uart_port_dtr_rts(struct uart_port *uport, int raise)
|
||||
* will be serialised by the per-port mutex.
|
||||
*/
|
||||
static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
|
||||
int init_hw)
|
||||
bool init_hw)
|
||||
{
|
||||
struct uart_port *uport = uart_port_check(state);
|
||||
unsigned long flags;
|
||||
@ -239,7 +239,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
|
||||
* port is open and ready to respond.
|
||||
*/
|
||||
if (init_hw && C_BAUD(tty))
|
||||
uart_port_dtr_rts(uport, 1);
|
||||
uart_port_dtr_rts(uport, true);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -254,7 +254,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
|
||||
}
|
||||
|
||||
static int uart_startup(struct tty_struct *tty, struct uart_state *state,
|
||||
int init_hw)
|
||||
bool init_hw)
|
||||
{
|
||||
struct tty_port *port = &state->port;
|
||||
int retval;
|
||||
@ -290,7 +290,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
|
||||
if (tty_port_initialized(port)) {
|
||||
tty_port_set_initialized(port, 0);
|
||||
tty_port_set_initialized(port, false);
|
||||
|
||||
/*
|
||||
* Turn off DTR and RTS early.
|
||||
@ -302,7 +302,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
|
||||
}
|
||||
|
||||
if (!tty || C_HUPCL(tty))
|
||||
uart_port_dtr_rts(uport, 0);
|
||||
uart_port_dtr_rts(uport, false);
|
||||
|
||||
uart_port_shutdown(port);
|
||||
}
|
||||
@ -312,7 +312,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
|
||||
* a DCD drop (hangup) at just the right time. Clear suspended bit so
|
||||
* we don't try to resume a port that has been shutdown.
|
||||
*/
|
||||
tty_port_set_suspended(port, 0);
|
||||
tty_port_set_suspended(port, false);
|
||||
|
||||
/*
|
||||
* Do not free() the transmit buffer page under the port lock since
|
||||
@ -997,7 +997,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
|
||||
uart_change_speed(tty, state, NULL);
|
||||
}
|
||||
} else {
|
||||
retval = uart_startup(tty, state, 1);
|
||||
retval = uart_startup(tty, state, true);
|
||||
if (retval == 0)
|
||||
tty_port_set_initialized(port, true);
|
||||
if (retval > 0)
|
||||
@ -1165,7 +1165,7 @@ static int uart_do_autoconfig(struct tty_struct *tty, struct uart_state *state)
|
||||
*/
|
||||
uport->ops->config_port(uport, flags);
|
||||
|
||||
ret = uart_startup(tty, state, 1);
|
||||
ret = uart_startup(tty, state, true);
|
||||
if (ret == 0)
|
||||
tty_port_set_initialized(port, true);
|
||||
if (ret > 0)
|
||||
@ -1725,7 +1725,7 @@ static void uart_tty_port_shutdown(struct tty_port *port)
|
||||
* a DCD drop (hangup) at just the right time. Clear suspended bit so
|
||||
* we don't try to resume a port that has been shutdown.
|
||||
*/
|
||||
tty_port_set_suspended(port, 0);
|
||||
tty_port_set_suspended(port, false);
|
||||
|
||||
/*
|
||||
* Free the transmit buffer.
|
||||
@ -1827,7 +1827,7 @@ static void uart_hangup(struct tty_struct *tty)
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
port->count = 0;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
tty_port_set_active(port, 0);
|
||||
tty_port_set_active(port, false);
|
||||
tty_port_tty_set(port, NULL);
|
||||
if (uport && !uart_console(uport))
|
||||
uart_change_pm(state, UART_PM_STATE_OFF);
|
||||
@ -1861,7 +1861,7 @@ static void uart_port_shutdown(struct tty_port *port)
|
||||
}
|
||||
}
|
||||
|
||||
static int uart_carrier_raised(struct tty_port *port)
|
||||
static bool uart_carrier_raised(struct tty_port *port)
|
||||
{
|
||||
struct uart_state *state = container_of(port, struct uart_state, port);
|
||||
struct uart_port *uport;
|
||||
@ -1875,18 +1875,17 @@ static int uart_carrier_raised(struct tty_port *port)
|
||||
* continue and not sleep
|
||||
*/
|
||||
if (WARN_ON(!uport))
|
||||
return 1;
|
||||
return true;
|
||||
spin_lock_irq(&uport->lock);
|
||||
uart_enable_ms(uport);
|
||||
mctrl = uport->ops->get_mctrl(uport);
|
||||
spin_unlock_irq(&uport->lock);
|
||||
uart_port_deref(uport);
|
||||
if (mctrl & TIOCM_CAR)
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
return mctrl & TIOCM_CAR;
|
||||
}
|
||||
|
||||
static void uart_dtr_rts(struct tty_port *port, int raise)
|
||||
static void uart_dtr_rts(struct tty_port *port, bool active)
|
||||
{
|
||||
struct uart_state *state = container_of(port, struct uart_state, port);
|
||||
struct uart_port *uport;
|
||||
@ -1894,7 +1893,7 @@ static void uart_dtr_rts(struct tty_port *port, int raise)
|
||||
uport = uart_port_ref(state);
|
||||
if (!uport)
|
||||
return;
|
||||
uart_port_dtr_rts(uport, raise);
|
||||
uart_port_dtr_rts(uport, active);
|
||||
uart_port_deref(uport);
|
||||
}
|
||||
|
||||
@ -1943,9 +1942,9 @@ static int uart_port_activate(struct tty_port *port, struct tty_struct *tty)
|
||||
/*
|
||||
* Start up the serial port.
|
||||
*/
|
||||
ret = uart_startup(tty, state, 0);
|
||||
ret = uart_startup(tty, state, false);
|
||||
if (ret > 0)
|
||||
tty_port_set_active(port, 1);
|
||||
tty_port_set_active(port, true);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -2349,8 +2348,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
int tries;
|
||||
unsigned int mctrl;
|
||||
|
||||
tty_port_set_suspended(port, 1);
|
||||
tty_port_set_initialized(port, 0);
|
||||
tty_port_set_suspended(port, true);
|
||||
tty_port_set_initialized(port, false);
|
||||
|
||||
spin_lock_irq(&uport->lock);
|
||||
ops->stop_tx(uport);
|
||||
@ -2461,7 +2460,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
uart_rs485_config(uport);
|
||||
ops->start_tx(uport);
|
||||
spin_unlock_irq(&uport->lock);
|
||||
tty_port_set_initialized(port, 1);
|
||||
tty_port_set_initialized(port, true);
|
||||
} else {
|
||||
/*
|
||||
* Failed to resume - maybe hardware went away?
|
||||
@ -2472,7 +2471,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
}
|
||||
}
|
||||
|
||||
tty_port_set_suspended(port, 0);
|
||||
tty_port_set_suspended(port, false);
|
||||
}
|
||||
|
||||
mutex_unlock(&port->mutex);
|
||||
@ -3258,11 +3257,11 @@ EXPORT_SYMBOL(uart_match_port);
|
||||
/**
|
||||
* uart_handle_dcd_change - handle a change of carrier detect state
|
||||
* @uport: uart_port structure for the open port
|
||||
* @status: new carrier detect status, nonzero if active
|
||||
* @active: new carrier detect status
|
||||
*
|
||||
* Caller must hold uport->lock.
|
||||
*/
|
||||
void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
|
||||
void uart_handle_dcd_change(struct uart_port *uport, bool active)
|
||||
{
|
||||
struct tty_port *port = &uport->state->port;
|
||||
struct tty_struct *tty = port->tty;
|
||||
@ -3274,7 +3273,7 @@ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
|
||||
ld = tty_ldisc_ref(tty);
|
||||
if (ld) {
|
||||
if (ld->ops->dcd_change)
|
||||
ld->ops->dcd_change(tty, status);
|
||||
ld->ops->dcd_change(tty, active);
|
||||
tty_ldisc_deref(ld);
|
||||
}
|
||||
}
|
||||
@ -3282,7 +3281,7 @@ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
|
||||
uport->icount.dcd++;
|
||||
|
||||
if (uart_dcd_enabled(uport)) {
|
||||
if (status)
|
||||
if (active)
|
||||
wake_up_interruptible(&port->open_wait);
|
||||
else if (tty)
|
||||
tty_hangup(tty);
|
||||
@ -3293,11 +3292,11 @@ EXPORT_SYMBOL_GPL(uart_handle_dcd_change);
|
||||
/**
|
||||
* uart_handle_cts_change - handle a change of clear-to-send state
|
||||
* @uport: uart_port structure for the open port
|
||||
* @status: new clear to send status, nonzero if active
|
||||
* @active: new clear-to-send status
|
||||
*
|
||||
* Caller must hold uport->lock.
|
||||
*/
|
||||
void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
|
||||
void uart_handle_cts_change(struct uart_port *uport, bool active)
|
||||
{
|
||||
lockdep_assert_held_once(&uport->lock);
|
||||
|
||||
@ -3305,13 +3304,13 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
|
||||
|
||||
if (uart_softcts_mode(uport)) {
|
||||
if (uport->hw_stopped) {
|
||||
if (status) {
|
||||
if (active) {
|
||||
uport->hw_stopped = 0;
|
||||
uport->ops->start_tx(uport);
|
||||
uart_write_wakeup(uport);
|
||||
}
|
||||
} else {
|
||||
if (!status) {
|
||||
if (!active) {
|
||||
uport->hw_stopped = 1;
|
||||
uport->ops->stop_tx(uport);
|
||||
}
|
||||
@ -3415,6 +3414,7 @@ int uart_get_rs485_mode(struct uart_port *port)
|
||||
struct device *dev = port->dev;
|
||||
u32 rs485_delay[2];
|
||||
int ret;
|
||||
int rx_during_tx_gpio_flag;
|
||||
|
||||
ret = device_property_read_u32_array(dev, "rs485-rts-delay",
|
||||
rs485_delay, 2);
|
||||
@ -3463,6 +3463,17 @@ int uart_get_rs485_mode(struct uart_port *port)
|
||||
if (port->rs485_term_gpio)
|
||||
port->rs485_supported.flags |= SER_RS485_TERMINATE_BUS;
|
||||
|
||||
rx_during_tx_gpio_flag = (rs485conf->flags & SER_RS485_RX_DURING_TX) ?
|
||||
GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
|
||||
port->rs485_rx_during_tx_gpio = devm_gpiod_get_optional(dev,
|
||||
"rs485-rx-during-tx",
|
||||
rx_during_tx_gpio_flag);
|
||||
if (IS_ERR(port->rs485_rx_during_tx_gpio)) {
|
||||
ret = PTR_ERR(port->rs485_rx_during_tx_gpio);
|
||||
port->rs485_rx_during_tx_gpio = NULL;
|
||||
return dev_err_probe(dev, ret, "Cannot get rs485-rx-during-tx-gpios\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uart_get_rs485_mode);
|
||||
|
@ -226,7 +226,11 @@ static int stm32_usart_config_rs485(struct uart_port *port, struct ktermios *ter
|
||||
|
||||
stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
|
||||
|
||||
rs485conf->flags |= SER_RS485_RX_DURING_TX;
|
||||
if (port->rs485_rx_during_tx_gpio)
|
||||
gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio,
|
||||
!!(rs485conf->flags & SER_RS485_RX_DURING_TX));
|
||||
else
|
||||
rs485conf->flags |= SER_RS485_RX_DURING_TX;
|
||||
|
||||
if (rs485conf->flags & SER_RS485_ENABLED) {
|
||||
cr1 = readl_relaxed(port->membase + ofs->cr1);
|
||||
|
@ -87,10 +87,10 @@ static int receive_chars_getchar(struct uart_port *port)
|
||||
|
||||
if (c == CON_HUP) {
|
||||
hung_up = 1;
|
||||
uart_handle_dcd_change(port, 0);
|
||||
uart_handle_dcd_change(port, false);
|
||||
} else if (hung_up) {
|
||||
hung_up = 0;
|
||||
uart_handle_dcd_change(port, 1);
|
||||
uart_handle_dcd_change(port, true);
|
||||
}
|
||||
|
||||
if (port->state == NULL) {
|
||||
@ -133,7 +133,7 @@ static int receive_chars_read(struct uart_port *port)
|
||||
bytes_read = 1;
|
||||
} else if (stat == CON_HUP) {
|
||||
hung_up = 1;
|
||||
uart_handle_dcd_change(port, 0);
|
||||
uart_handle_dcd_change(port, false);
|
||||
continue;
|
||||
} else {
|
||||
/* HV_EWOULDBLOCK, etc. */
|
||||
@ -143,7 +143,7 @@ static int receive_chars_read(struct uart_port *port)
|
||||
|
||||
if (hung_up) {
|
||||
hung_up = 0;
|
||||
uart_handle_dcd_change(port, 1);
|
||||
uart_handle_dcd_change(port, true);
|
||||
}
|
||||
|
||||
if (port->sysrq != 0 && *con_read_page) {
|
||||
|
@ -1468,6 +1468,8 @@ static int ucc_uart_remove(struct platform_device *ofdev)
|
||||
|
||||
uart_remove_one_port(&ucc_uart_driver, &qe_port->port);
|
||||
|
||||
of_node_put(qe_port->np);
|
||||
|
||||
kfree(qe_port);
|
||||
|
||||
return 0;
|
||||
|
@ -694,7 +694,7 @@ static void hangup(struct tty_struct *tty)
|
||||
info->port.count = 0;
|
||||
info->port.tty = NULL;
|
||||
spin_unlock_irqrestore(&info->port.lock, flags);
|
||||
tty_port_set_active(&info->port, 0);
|
||||
tty_port_set_active(&info->port, false);
|
||||
mutex_unlock(&info->port.mutex);
|
||||
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
@ -2354,7 +2354,7 @@ static int startup(struct slgt_info *info)
|
||||
if (info->port.tty)
|
||||
clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
|
||||
|
||||
tty_port_set_initialized(&info->port, 1);
|
||||
tty_port_set_initialized(&info->port, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2401,7 +2401,7 @@ static void shutdown(struct slgt_info *info)
|
||||
if (info->port.tty)
|
||||
set_bit(TTY_IO_ERROR, &info->port.tty->flags);
|
||||
|
||||
tty_port_set_initialized(&info->port, 0);
|
||||
tty_port_set_initialized(&info->port, false);
|
||||
}
|
||||
|
||||
static void program_hw(struct slgt_info *info)
|
||||
@ -3126,7 +3126,7 @@ static int tiocmset(struct tty_struct *tty,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int carrier_raised(struct tty_port *port)
|
||||
static bool carrier_raised(struct tty_port *port)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct slgt_info *info = container_of(port, struct slgt_info, port);
|
||||
@ -3134,16 +3134,17 @@ static int carrier_raised(struct tty_port *port)
|
||||
spin_lock_irqsave(&info->lock,flags);
|
||||
get_gtsignals(info);
|
||||
spin_unlock_irqrestore(&info->lock,flags);
|
||||
return (info->signals & SerialSignal_DCD) ? 1 : 0;
|
||||
|
||||
return info->signals & SerialSignal_DCD;
|
||||
}
|
||||
|
||||
static void dtr_rts(struct tty_port *port, int on)
|
||||
static void dtr_rts(struct tty_port *port, bool active)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct slgt_info *info = container_of(port, struct slgt_info, port);
|
||||
|
||||
spin_lock_irqsave(&info->lock,flags);
|
||||
if (on)
|
||||
if (active)
|
||||
info->signals |= SerialSignal_RTS | SerialSignal_DTR;
|
||||
else
|
||||
info->signals &= ~(SerialSignal_RTS | SerialSignal_DTR);
|
||||
@ -3162,14 +3163,14 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
|
||||
int retval;
|
||||
bool do_clocal = false;
|
||||
unsigned long flags;
|
||||
int cd;
|
||||
bool cd;
|
||||
struct tty_port *port = &info->port;
|
||||
|
||||
DBGINFO(("%s block_til_ready\n", tty->driver->name));
|
||||
|
||||
if (filp->f_flags & O_NONBLOCK || tty_io_error(tty)) {
|
||||
/* nonblock mode is set or port is not enabled */
|
||||
tty_port_set_active(port, 1);
|
||||
tty_port_set_active(port, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3226,7 +3227,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
|
||||
port->blocked_open--;
|
||||
|
||||
if (!retval)
|
||||
tty_port_set_active(port, 1);
|
||||
tty_port_set_active(port, true);
|
||||
|
||||
DBGINFO(("%s block_til_ready ready, rc=%d\n", tty->driver->name, retval));
|
||||
return retval;
|
||||
|
@ -1224,14 +1224,16 @@ static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
|
||||
if (driver->ops->lookup)
|
||||
if (driver->ops->lookup) {
|
||||
if (!file)
|
||||
tty = ERR_PTR(-EIO);
|
||||
else
|
||||
tty = driver->ops->lookup(driver, file, idx);
|
||||
else
|
||||
} else {
|
||||
if (idx >= driver->num)
|
||||
return ERR_PTR(-EINVAL);
|
||||
tty = driver->ttys[idx];
|
||||
|
||||
}
|
||||
if (!IS_ERR(tty))
|
||||
tty_kref_get(tty);
|
||||
return tty;
|
||||
|
@ -270,13 +270,13 @@ EXPORT_SYMBOL(tty_termios_copy_hw);
|
||||
* between the two termios structures, or a speed change is needed.
|
||||
*/
|
||||
|
||||
int tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b)
|
||||
bool tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b)
|
||||
{
|
||||
if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
|
||||
return 1;
|
||||
return true;
|
||||
if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
|
||||
return 1;
|
||||
return 0;
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL(tty_termios_hw_change);
|
||||
|
||||
|
@ -367,7 +367,7 @@ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
|
||||
goto out;
|
||||
|
||||
if (tty_port_initialized(port)) {
|
||||
tty_port_set_initialized(port, 0);
|
||||
tty_port_set_initialized(port, false);
|
||||
/*
|
||||
* Drop DTR/RTS if HUPCL is set. This causes any attached
|
||||
* modem to hang up the line.
|
||||
@ -403,7 +403,7 @@ void tty_port_hangup(struct tty_port *port)
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
port->tty = NULL;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
tty_port_set_active(port, 0);
|
||||
tty_port_set_active(port, false);
|
||||
tty_port_shutdown(port, tty);
|
||||
tty_kref_put(tty);
|
||||
wake_up_interruptible(&port->open_wait);
|
||||
@ -444,10 +444,10 @@ EXPORT_SYMBOL_GPL(tty_port_tty_wakeup);
|
||||
* to hide some internal details. This will eventually become entirely
|
||||
* internal to the tty port.
|
||||
*/
|
||||
int tty_port_carrier_raised(struct tty_port *port)
|
||||
bool tty_port_carrier_raised(struct tty_port *port)
|
||||
{
|
||||
if (port->ops->carrier_raised == NULL)
|
||||
return 1;
|
||||
return true;
|
||||
return port->ops->carrier_raised(port);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_carrier_raised);
|
||||
@ -463,7 +463,7 @@ EXPORT_SYMBOL(tty_port_carrier_raised);
|
||||
void tty_port_raise_dtr_rts(struct tty_port *port)
|
||||
{
|
||||
if (port->ops->dtr_rts)
|
||||
port->ops->dtr_rts(port, 1);
|
||||
port->ops->dtr_rts(port, true);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_raise_dtr_rts);
|
||||
|
||||
@ -478,7 +478,7 @@ EXPORT_SYMBOL(tty_port_raise_dtr_rts);
|
||||
void tty_port_lower_dtr_rts(struct tty_port *port)
|
||||
{
|
||||
if (port->ops->dtr_rts)
|
||||
port->ops->dtr_rts(port, 0);
|
||||
port->ops->dtr_rts(port, false);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_lower_dtr_rts);
|
||||
|
||||
@ -518,14 +518,14 @@ int tty_port_block_til_ready(struct tty_port *port,
|
||||
* the port has just hung up or is in another error state.
|
||||
*/
|
||||
if (tty_io_error(tty)) {
|
||||
tty_port_set_active(port, 1);
|
||||
tty_port_set_active(port, true);
|
||||
return 0;
|
||||
}
|
||||
if (filp == NULL || (filp->f_flags & O_NONBLOCK)) {
|
||||
/* Indicate we are open */
|
||||
if (C_BAUD(tty))
|
||||
tty_port_raise_dtr_rts(port);
|
||||
tty_port_set_active(port, 1);
|
||||
tty_port_set_active(port, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -588,7 +588,7 @@ int tty_port_block_til_ready(struct tty_port *port,
|
||||
port->blocked_open--;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
if (retval == 0)
|
||||
tty_port_set_active(port, 1);
|
||||
tty_port_set_active(port, true);
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_block_til_ready);
|
||||
@ -695,7 +695,7 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
|
||||
wake_up_interruptible(&port->open_wait);
|
||||
}
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
tty_port_set_active(port, 0);
|
||||
tty_port_set_active(port, false);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_close_end);
|
||||
|
||||
@ -788,7 +788,7 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty,
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
tty_port_set_initialized(port, 1);
|
||||
tty_port_set_initialized(port, true);
|
||||
}
|
||||
mutex_unlock(&port->mutex);
|
||||
return tty_port_block_til_ready(port, tty, filp);
|
||||
|
@ -316,73 +316,55 @@ void schedule_console_callback(void)
|
||||
* Code to manage unicode-based screen buffers
|
||||
*/
|
||||
|
||||
#ifdef NO_VC_UNI_SCREEN
|
||||
/* this disables and optimizes related code away at compile time */
|
||||
#define get_vc_uniscr(vc) NULL
|
||||
#else
|
||||
#define get_vc_uniscr(vc) vc->vc_uni_screen
|
||||
#endif
|
||||
|
||||
#define VC_UNI_SCREEN_DEBUG 0
|
||||
|
||||
typedef uint32_t char32_t;
|
||||
|
||||
/*
|
||||
* Our screen buffer is preceded by an array of line pointers so that
|
||||
* scrolling only implies some pointer shuffling.
|
||||
*/
|
||||
struct uni_screen {
|
||||
char32_t *lines[0];
|
||||
};
|
||||
|
||||
static struct uni_screen *vc_uniscr_alloc(unsigned int cols, unsigned int rows)
|
||||
static u32 **vc_uniscr_alloc(unsigned int cols, unsigned int rows)
|
||||
{
|
||||
struct uni_screen *uniscr;
|
||||
u32 **uni_lines;
|
||||
void *p;
|
||||
unsigned int memsize, i;
|
||||
unsigned int memsize, i, col_size = cols * sizeof(**uni_lines);
|
||||
|
||||
/* allocate everything in one go */
|
||||
memsize = cols * rows * sizeof(char32_t);
|
||||
memsize += rows * sizeof(char32_t *);
|
||||
p = vzalloc(memsize);
|
||||
if (!p)
|
||||
memsize = col_size * rows;
|
||||
memsize += rows * sizeof(*uni_lines);
|
||||
uni_lines = vzalloc(memsize);
|
||||
if (!uni_lines)
|
||||
return NULL;
|
||||
|
||||
/* initial line pointers */
|
||||
uniscr = p;
|
||||
p = uniscr->lines + rows;
|
||||
p = uni_lines + rows;
|
||||
for (i = 0; i < rows; i++) {
|
||||
uniscr->lines[i] = p;
|
||||
p += cols * sizeof(char32_t);
|
||||
uni_lines[i] = p;
|
||||
p += col_size;
|
||||
}
|
||||
return uniscr;
|
||||
|
||||
return uni_lines;
|
||||
}
|
||||
|
||||
static void vc_uniscr_free(struct uni_screen *uniscr)
|
||||
static void vc_uniscr_free(u32 **uni_lines)
|
||||
{
|
||||
vfree(uniscr);
|
||||
vfree(uni_lines);
|
||||
}
|
||||
|
||||
static void vc_uniscr_set(struct vc_data *vc, struct uni_screen *new_uniscr)
|
||||
static void vc_uniscr_set(struct vc_data *vc, u32 **new_uni_lines)
|
||||
{
|
||||
vc_uniscr_free(vc->vc_uni_screen);
|
||||
vc->vc_uni_screen = new_uniscr;
|
||||
vc_uniscr_free(vc->vc_uni_lines);
|
||||
vc->vc_uni_lines = new_uni_lines;
|
||||
}
|
||||
|
||||
static void vc_uniscr_putc(struct vc_data *vc, char32_t uc)
|
||||
static void vc_uniscr_putc(struct vc_data *vc, u32 uc)
|
||||
{
|
||||
struct uni_screen *uniscr = get_vc_uniscr(vc);
|
||||
|
||||
if (uniscr)
|
||||
uniscr->lines[vc->state.y][vc->state.x] = uc;
|
||||
if (vc->vc_uni_lines)
|
||||
vc->vc_uni_lines[vc->state.y][vc->state.x] = uc;
|
||||
}
|
||||
|
||||
static void vc_uniscr_insert(struct vc_data *vc, unsigned int nr)
|
||||
{
|
||||
struct uni_screen *uniscr = get_vc_uniscr(vc);
|
||||
|
||||
if (uniscr) {
|
||||
char32_t *ln = uniscr->lines[vc->state.y];
|
||||
if (vc->vc_uni_lines) {
|
||||
u32 *ln = vc->vc_uni_lines[vc->state.y];
|
||||
unsigned int x = vc->state.x, cols = vc->vc_cols;
|
||||
|
||||
memmove(&ln[x + nr], &ln[x], (cols - x - nr) * sizeof(*ln));
|
||||
@ -392,10 +374,8 @@ static void vc_uniscr_insert(struct vc_data *vc, unsigned int nr)
|
||||
|
||||
static void vc_uniscr_delete(struct vc_data *vc, unsigned int nr)
|
||||
{
|
||||
struct uni_screen *uniscr = get_vc_uniscr(vc);
|
||||
|
||||
if (uniscr) {
|
||||
char32_t *ln = uniscr->lines[vc->state.y];
|
||||
if (vc->vc_uni_lines) {
|
||||
u32 *ln = vc->vc_uni_lines[vc->state.y];
|
||||
unsigned int x = vc->state.x, cols = vc->vc_cols;
|
||||
|
||||
memcpy(&ln[x], &ln[x + nr], (cols - x - nr) * sizeof(*ln));
|
||||
@ -406,86 +386,84 @@ static void vc_uniscr_delete(struct vc_data *vc, unsigned int nr)
|
||||
static void vc_uniscr_clear_line(struct vc_data *vc, unsigned int x,
|
||||
unsigned int nr)
|
||||
{
|
||||
struct uni_screen *uniscr = get_vc_uniscr(vc);
|
||||
|
||||
if (uniscr) {
|
||||
char32_t *ln = uniscr->lines[vc->state.y];
|
||||
|
||||
memset32(&ln[x], ' ', nr);
|
||||
}
|
||||
if (vc->vc_uni_lines)
|
||||
memset32(&vc->vc_uni_lines[vc->state.y][x], ' ', nr);
|
||||
}
|
||||
|
||||
static void vc_uniscr_clear_lines(struct vc_data *vc, unsigned int y,
|
||||
unsigned int nr)
|
||||
{
|
||||
struct uni_screen *uniscr = get_vc_uniscr(vc);
|
||||
|
||||
if (uniscr) {
|
||||
unsigned int cols = vc->vc_cols;
|
||||
|
||||
if (vc->vc_uni_lines)
|
||||
while (nr--)
|
||||
memset32(uniscr->lines[y++], ' ', cols);
|
||||
}
|
||||
memset32(vc->vc_uni_lines[y++], ' ', vc->vc_cols);
|
||||
}
|
||||
|
||||
static void vc_uniscr_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
|
||||
enum con_scroll dir, unsigned int nr)
|
||||
/* juggling array rotation algorithm (complexity O(N), size complexity O(1)) */
|
||||
static void juggle_array(u32 **array, unsigned int size, unsigned int nr)
|
||||
{
|
||||
struct uni_screen *uniscr = get_vc_uniscr(vc);
|
||||
unsigned int gcd_idx;
|
||||
|
||||
if (uniscr) {
|
||||
unsigned int i, j, k, sz, d, clear;
|
||||
for (gcd_idx = 0; gcd_idx < gcd(nr, size); gcd_idx++) {
|
||||
u32 *gcd_idx_val = array[gcd_idx];
|
||||
unsigned int dst_idx = gcd_idx;
|
||||
|
||||
sz = b - t;
|
||||
clear = b - nr;
|
||||
d = nr;
|
||||
if (dir == SM_DOWN) {
|
||||
clear = t;
|
||||
d = sz - nr;
|
||||
while (1) {
|
||||
unsigned int src_idx = (dst_idx + nr) % size;
|
||||
if (src_idx == gcd_idx)
|
||||
break;
|
||||
|
||||
array[dst_idx] = array[src_idx];
|
||||
dst_idx = src_idx;
|
||||
}
|
||||
for (i = 0; i < gcd(d, sz); i++) {
|
||||
char32_t *tmp = uniscr->lines[t + i];
|
||||
j = i;
|
||||
while (1) {
|
||||
k = j + d;
|
||||
if (k >= sz)
|
||||
k -= sz;
|
||||
if (k == i)
|
||||
break;
|
||||
uniscr->lines[t + j] = uniscr->lines[t + k];
|
||||
j = k;
|
||||
}
|
||||
uniscr->lines[t + j] = tmp;
|
||||
}
|
||||
vc_uniscr_clear_lines(vc, clear, nr);
|
||||
|
||||
array[dst_idx] = gcd_idx_val;
|
||||
}
|
||||
}
|
||||
|
||||
static void vc_uniscr_copy_area(struct uni_screen *dst,
|
||||
static void vc_uniscr_scroll(struct vc_data *vc, unsigned int top,
|
||||
unsigned int bottom, enum con_scroll dir,
|
||||
unsigned int nr)
|
||||
{
|
||||
u32 **uni_lines = vc->vc_uni_lines;
|
||||
unsigned int size = bottom - top;
|
||||
|
||||
if (!uni_lines)
|
||||
return;
|
||||
|
||||
if (dir == SM_DOWN) {
|
||||
juggle_array(&uni_lines[top], size, size - nr);
|
||||
vc_uniscr_clear_lines(vc, top, nr);
|
||||
} else {
|
||||
juggle_array(&uni_lines[top], size, nr);
|
||||
vc_uniscr_clear_lines(vc, bottom - nr, nr);
|
||||
}
|
||||
}
|
||||
|
||||
static void vc_uniscr_copy_area(u32 **dst_lines,
|
||||
unsigned int dst_cols,
|
||||
unsigned int dst_rows,
|
||||
struct uni_screen *src,
|
||||
u32 **src_lines,
|
||||
unsigned int src_cols,
|
||||
unsigned int src_top_row,
|
||||
unsigned int src_bot_row)
|
||||
{
|
||||
unsigned int dst_row = 0;
|
||||
|
||||
if (!dst)
|
||||
if (!dst_lines)
|
||||
return;
|
||||
|
||||
while (src_top_row < src_bot_row) {
|
||||
char32_t *src_line = src->lines[src_top_row];
|
||||
char32_t *dst_line = dst->lines[dst_row];
|
||||
u32 *src_line = src_lines[src_top_row];
|
||||
u32 *dst_line = dst_lines[dst_row];
|
||||
|
||||
memcpy(dst_line, src_line, src_cols * sizeof(char32_t));
|
||||
memcpy(dst_line, src_line, src_cols * sizeof(*src_line));
|
||||
if (dst_cols - src_cols)
|
||||
memset32(dst_line + src_cols, ' ', dst_cols - src_cols);
|
||||
src_top_row++;
|
||||
dst_row++;
|
||||
}
|
||||
while (dst_row < dst_rows) {
|
||||
char32_t *dst_line = dst->lines[dst_row];
|
||||
u32 *dst_line = dst_lines[dst_row];
|
||||
|
||||
memset32(dst_line, ' ', dst_cols);
|
||||
dst_row++;
|
||||
@ -500,23 +478,20 @@ static void vc_uniscr_copy_area(struct uni_screen *dst,
|
||||
*/
|
||||
int vc_uniscr_check(struct vc_data *vc)
|
||||
{
|
||||
struct uni_screen *uniscr;
|
||||
u32 **uni_lines;
|
||||
unsigned short *p;
|
||||
int x, y, mask;
|
||||
|
||||
if (__is_defined(NO_VC_UNI_SCREEN))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
if (!vc->vc_utf)
|
||||
return -ENODATA;
|
||||
|
||||
if (vc->vc_uni_screen)
|
||||
if (vc->vc_uni_lines)
|
||||
return 0;
|
||||
|
||||
uniscr = vc_uniscr_alloc(vc->vc_cols, vc->vc_rows);
|
||||
if (!uniscr)
|
||||
uni_lines = vc_uniscr_alloc(vc->vc_cols, vc->vc_rows);
|
||||
if (!uni_lines)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
@ -528,14 +503,15 @@ int vc_uniscr_check(struct vc_data *vc)
|
||||
p = (unsigned short *)vc->vc_origin;
|
||||
mask = vc->vc_hi_font_mask | 0xff;
|
||||
for (y = 0; y < vc->vc_rows; y++) {
|
||||
char32_t *line = uniscr->lines[y];
|
||||
u32 *line = uni_lines[y];
|
||||
for (x = 0; x < vc->vc_cols; x++) {
|
||||
u16 glyph = scr_readw(p++) & mask;
|
||||
line[x] = inverse_translate(vc, glyph, true);
|
||||
}
|
||||
}
|
||||
|
||||
vc->vc_uni_screen = uniscr;
|
||||
vc->vc_uni_lines = uni_lines;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -547,11 +523,12 @@ int vc_uniscr_check(struct vc_data *vc)
|
||||
void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed,
|
||||
unsigned int row, unsigned int col, unsigned int nr)
|
||||
{
|
||||
struct uni_screen *uniscr = get_vc_uniscr(vc);
|
||||
u32 **uni_lines = vc->vc_uni_lines;
|
||||
int offset = row * vc->vc_size_row + col * 2;
|
||||
unsigned long pos;
|
||||
|
||||
BUG_ON(!uniscr);
|
||||
if (WARN_ON_ONCE(!uni_lines))
|
||||
return;
|
||||
|
||||
pos = (unsigned long)screenpos(vc, offset, viewed);
|
||||
if (pos >= vc->vc_origin && pos < vc->vc_scr_end) {
|
||||
@ -562,7 +539,7 @@ void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed,
|
||||
*/
|
||||
row = (pos - vc->vc_origin) / vc->vc_size_row;
|
||||
col = ((pos - vc->vc_origin) % vc->vc_size_row) / 2;
|
||||
memcpy(dest, &uniscr->lines[row][col], nr * sizeof(char32_t));
|
||||
memcpy(dest, &uni_lines[row][col], nr * sizeof(u32));
|
||||
} else {
|
||||
/*
|
||||
* Scrollback is active. For now let's simply backtranslate
|
||||
@ -572,7 +549,7 @@ void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed,
|
||||
*/
|
||||
u16 *p = (u16 *)pos;
|
||||
int mask = vc->vc_hi_font_mask | 0xff;
|
||||
char32_t *uni_buf = dest;
|
||||
u32 *uni_buf = dest;
|
||||
while (nr--) {
|
||||
u16 glyph = scr_readw(p++) & mask;
|
||||
*uni_buf++ = inverse_translate(vc, glyph, true);
|
||||
@ -580,64 +557,31 @@ void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed,
|
||||
}
|
||||
}
|
||||
|
||||
/* this is for validation and debugging only */
|
||||
static void vc_uniscr_debug_check(struct vc_data *vc)
|
||||
static void con_scroll(struct vc_data *vc, unsigned int top,
|
||||
unsigned int bottom, enum con_scroll dir,
|
||||
unsigned int nr)
|
||||
{
|
||||
struct uni_screen *uniscr = get_vc_uniscr(vc);
|
||||
unsigned short *p;
|
||||
int x, y, mask;
|
||||
unsigned int rows = bottom - top;
|
||||
u16 *clear, *dst, *src;
|
||||
|
||||
if (!VC_UNI_SCREEN_DEBUG || !uniscr)
|
||||
if (top + nr >= bottom)
|
||||
nr = rows - 1;
|
||||
if (bottom > vc->vc_rows || top >= bottom || nr < 1)
|
||||
return;
|
||||
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
/*
|
||||
* Make sure our unicode screen translates into the same glyphs
|
||||
* as the actual screen. This is brutal indeed.
|
||||
*/
|
||||
p = (unsigned short *)vc->vc_origin;
|
||||
mask = vc->vc_hi_font_mask | 0xff;
|
||||
for (y = 0; y < vc->vc_rows; y++) {
|
||||
char32_t *line = uniscr->lines[y];
|
||||
for (x = 0; x < vc->vc_cols; x++) {
|
||||
u16 glyph = scr_readw(p++) & mask;
|
||||
char32_t uc = line[x];
|
||||
int tc = conv_uni_to_pc(vc, uc);
|
||||
if (tc == -4)
|
||||
tc = conv_uni_to_pc(vc, 0xfffd);
|
||||
if (tc == -4)
|
||||
tc = conv_uni_to_pc(vc, '?');
|
||||
if (tc != glyph)
|
||||
pr_err_ratelimited(
|
||||
"%s: mismatch at %d,%d: glyph=%#x tc=%#x\n",
|
||||
__func__, x, y, glyph, tc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void con_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
|
||||
enum con_scroll dir, unsigned int nr)
|
||||
{
|
||||
u16 *clear, *d, *s;
|
||||
|
||||
if (t + nr >= b)
|
||||
nr = b - t - 1;
|
||||
if (b > vc->vc_rows || t >= b || nr < 1)
|
||||
return;
|
||||
vc_uniscr_scroll(vc, t, b, dir, nr);
|
||||
if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, dir, nr))
|
||||
vc_uniscr_scroll(vc, top, bottom, dir, nr);
|
||||
if (con_is_visible(vc) &&
|
||||
vc->vc_sw->con_scroll(vc, top, bottom, dir, nr))
|
||||
return;
|
||||
|
||||
s = clear = (u16 *)(vc->vc_origin + vc->vc_size_row * t);
|
||||
d = (u16 *)(vc->vc_origin + vc->vc_size_row * (t + nr));
|
||||
src = clear = (u16 *)(vc->vc_origin + vc->vc_size_row * top);
|
||||
dst = (u16 *)(vc->vc_origin + vc->vc_size_row * (top + nr));
|
||||
|
||||
if (dir == SM_UP) {
|
||||
clear = s + (b - t - nr) * vc->vc_cols;
|
||||
swap(s, d);
|
||||
clear = src + (rows - nr) * vc->vc_cols;
|
||||
swap(src, dst);
|
||||
}
|
||||
scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
|
||||
scr_memmovew(dst, src, (rows - nr) * vc->vc_size_row);
|
||||
scr_memsetw(clear, vc->vc_video_erase_char, vc->vc_size_row * nr);
|
||||
}
|
||||
|
||||
@ -1201,7 +1145,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
|
||||
unsigned int new_cols, new_rows, new_row_size, new_screen_size;
|
||||
unsigned int user;
|
||||
unsigned short *oldscreen, *newscreen;
|
||||
struct uni_screen *new_uniscr = NULL;
|
||||
u32 **new_uniscr = NULL;
|
||||
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
@ -1245,7 +1189,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
|
||||
if (!newscreen)
|
||||
return -ENOMEM;
|
||||
|
||||
if (get_vc_uniscr(vc)) {
|
||||
if (vc->vc_uni_lines) {
|
||||
new_uniscr = vc_uniscr_alloc(new_cols, new_rows);
|
||||
if (!new_uniscr) {
|
||||
kfree(newscreen);
|
||||
@ -1297,7 +1241,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
|
||||
end = old_origin + old_row_size * min(old_rows, new_rows);
|
||||
|
||||
vc_uniscr_copy_area(new_uniscr, new_cols, new_rows,
|
||||
get_vc_uniscr(vc), rlth/2, first_copied_row,
|
||||
vc->vc_uni_lines, rlth/2, first_copied_row,
|
||||
min(old_rows, new_rows));
|
||||
vc_uniscr_set(vc, new_uniscr);
|
||||
|
||||
@ -2959,7 +2903,6 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
|
||||
goto rescan_last_byte;
|
||||
}
|
||||
con_flush(vc, &draw);
|
||||
vc_uniscr_debug_check(vc);
|
||||
console_conditional_schedule();
|
||||
notify_update(vc);
|
||||
console_unlock();
|
||||
@ -3156,8 +3099,14 @@ static struct tty_driver *vt_console_device(struct console *c, int *index)
|
||||
return console_driver;
|
||||
}
|
||||
|
||||
static int vt_console_setup(struct console *co, char *options)
|
||||
{
|
||||
return co->index >= MAX_NR_CONSOLES ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
static struct console vt_console_driver = {
|
||||
.name = "tty",
|
||||
.setup = vt_console_setup,
|
||||
.write = vt_console_print,
|
||||
.device = vt_console_device,
|
||||
.unblank = unblank_screen,
|
||||
@ -4574,26 +4523,30 @@ void reset_palette(struct vc_data *vc)
|
||||
/*
|
||||
* Font switching
|
||||
*
|
||||
* Currently we only support fonts up to 32 pixels wide, at a maximum height
|
||||
* of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints,
|
||||
* depending on width) reserved for each character which is kinda wasty, but
|
||||
* this is done in order to maintain compatibility with the EGA/VGA fonts. It
|
||||
* is up to the actual low-level console-driver convert data into its favorite
|
||||
* format (maybe we should add a `fontoffset' field to the `display'
|
||||
* structure so we won't have to convert the fontdata all the time.
|
||||
* Currently we only support fonts up to 128 pixels wide, at a maximum height
|
||||
* of 128 pixels. Userspace fontdata may have to be stored with 32 bytes
|
||||
* (shorts/ints, depending on width) reserved for each character which is
|
||||
* kinda wasty, but this is done in order to maintain compatibility with the
|
||||
* EGA/VGA fonts. It is up to the actual low-level console-driver convert data
|
||||
* into its favorite format (maybe we should add a `fontoffset' field to the
|
||||
* `display' structure so we won't have to convert the fontdata all the time.
|
||||
* /Jes
|
||||
*/
|
||||
|
||||
#define max_font_size 65536
|
||||
#define max_font_width 64
|
||||
#define max_font_height 128
|
||||
#define max_font_glyphs 512
|
||||
#define max_font_size (max_font_glyphs*max_font_width*max_font_height)
|
||||
|
||||
static int con_font_get(struct vc_data *vc, struct console_font_op *op)
|
||||
{
|
||||
struct console_font font;
|
||||
int rc = -EINVAL;
|
||||
int c;
|
||||
unsigned int vpitch = op->op == KD_FONT_OP_GET_TALL ? op->height : 32;
|
||||
|
||||
if (op->data) {
|
||||
font.data = kmalloc(max_font_size, GFP_KERNEL);
|
||||
font.data = kvmalloc(max_font_size, GFP_KERNEL);
|
||||
if (!font.data)
|
||||
return -ENOMEM;
|
||||
} else
|
||||
@ -4603,7 +4556,7 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
|
||||
if (vc->vc_mode != KD_TEXT)
|
||||
rc = -EINVAL;
|
||||
else if (vc->vc_sw->con_font_get)
|
||||
rc = vc->vc_sw->con_font_get(vc, &font);
|
||||
rc = vc->vc_sw->con_font_get(vc, &font, vpitch);
|
||||
else
|
||||
rc = -ENOSYS;
|
||||
console_unlock();
|
||||
@ -4611,7 +4564,7 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
c = (font.width+7)/8 * 32 * font.charcount;
|
||||
c = (font.width+7)/8 * vpitch * font.charcount;
|
||||
|
||||
if (op->data && font.charcount > op->charcount)
|
||||
rc = -ENOSPC;
|
||||
@ -4628,7 +4581,7 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
|
||||
rc = -EFAULT;
|
||||
|
||||
out:
|
||||
kfree(font.data);
|
||||
kvfree(font.data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -4637,16 +4590,20 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op)
|
||||
struct console_font font;
|
||||
int rc = -EINVAL;
|
||||
int size;
|
||||
unsigned int vpitch = op->op == KD_FONT_OP_SET_TALL ? op->height : 32;
|
||||
|
||||
if (vc->vc_mode != KD_TEXT)
|
||||
return -EINVAL;
|
||||
if (!op->data)
|
||||
return -EINVAL;
|
||||
if (op->charcount > 512)
|
||||
if (op->charcount > max_font_glyphs)
|
||||
return -EINVAL;
|
||||
if (op->width <= 0 || op->width > 32 || !op->height || op->height > 32)
|
||||
if (op->width <= 0 || op->width > max_font_width || !op->height ||
|
||||
op->height > max_font_height)
|
||||
return -EINVAL;
|
||||
size = (op->width+7)/8 * 32 * op->charcount;
|
||||
if (vpitch < op->height)
|
||||
return -EINVAL;
|
||||
size = (op->width+7)/8 * vpitch * op->charcount;
|
||||
if (size > max_font_size)
|
||||
return -ENOSPC;
|
||||
|
||||
@ -4664,7 +4621,7 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op)
|
||||
else if (vc->vc_sw->con_font_set) {
|
||||
if (vc_is_sel(vc))
|
||||
clear_selection();
|
||||
rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
|
||||
rc = vc->vc_sw->con_font_set(vc, &font, vpitch, op->flags);
|
||||
} else
|
||||
rc = -ENOSYS;
|
||||
console_unlock();
|
||||
@ -4710,8 +4667,10 @@ int con_font_op(struct vc_data *vc, struct console_font_op *op)
|
||||
{
|
||||
switch (op->op) {
|
||||
case KD_FONT_OP_SET:
|
||||
case KD_FONT_OP_SET_TALL:
|
||||
return con_font_set(vc, op);
|
||||
case KD_FONT_OP_GET:
|
||||
case KD_FONT_OP_GET_TALL:
|
||||
return con_font_get(vc, op);
|
||||
case KD_FONT_OP_SET_DEFAULT:
|
||||
return con_font_default(vc, op);
|
||||
@ -4740,10 +4699,11 @@ EXPORT_SYMBOL_GPL(screen_glyph);
|
||||
|
||||
u32 screen_glyph_unicode(const struct vc_data *vc, int n)
|
||||
{
|
||||
struct uni_screen *uniscr = get_vc_uniscr(vc);
|
||||
u32 **uni_lines = vc->vc_uni_lines;
|
||||
|
||||
if (uni_lines)
|
||||
return uni_lines[n / vc->vc_cols][n % vc->vc_cols];
|
||||
|
||||
if (uniscr)
|
||||
return uniscr->lines[n / vc->vc_cols][n % vc->vc_cols];
|
||||
return inverse_translate(vc, screen_glyph(vc, n * 2), true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(screen_glyph_unicode);
|
||||
|
@ -651,13 +651,13 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
|
||||
return tty_port_open(&acm->port, tty, filp);
|
||||
}
|
||||
|
||||
static void acm_port_dtr_rts(struct tty_port *port, int raise)
|
||||
static void acm_port_dtr_rts(struct tty_port *port, bool active)
|
||||
{
|
||||
struct acm *acm = container_of(port, struct acm, port);
|
||||
int val;
|
||||
int res;
|
||||
|
||||
if (raise)
|
||||
if (active)
|
||||
val = USB_CDC_CTRL_DTR | USB_CDC_CTRL_RTS;
|
||||
else
|
||||
val = 0;
|
||||
|
@ -169,7 +169,7 @@ static int usb_console_setup(struct console *co, char *options)
|
||||
tty_save_termios(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_set_initialized(&port->port, 1);
|
||||
tty_port_set_initialized(&port->port, true);
|
||||
}
|
||||
/* Now that any required fake tty operations are completed restore
|
||||
* the tty port count */
|
||||
|
@ -754,7 +754,7 @@ static struct usb_serial_driver *search_serial_device(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int serial_port_carrier_raised(struct tty_port *port)
|
||||
static bool serial_port_carrier_raised(struct tty_port *port)
|
||||
{
|
||||
struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
|
||||
struct usb_serial_driver *drv = p->serial->type;
|
||||
@ -762,10 +762,10 @@ static int serial_port_carrier_raised(struct tty_port *port)
|
||||
if (drv->carrier_raised)
|
||||
return drv->carrier_raised(p);
|
||||
/* No carrier control - don't block */
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void serial_port_dtr_rts(struct tty_port *port, int on)
|
||||
static void serial_port_dtr_rts(struct tty_port *port, bool on)
|
||||
{
|
||||
struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
|
||||
struct usb_serial_driver *drv = p->serial->type;
|
||||
|
@ -497,7 +497,7 @@ static int newport_blank(struct vc_data *c, int blank, int mode_switch)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int newport_set_font(int unit, struct console_font *op)
|
||||
static int newport_set_font(int unit, struct console_font *op, unsigned int vpitch)
|
||||
{
|
||||
int w = op->width;
|
||||
int h = op->height;
|
||||
@ -507,7 +507,7 @@ static int newport_set_font(int unit, struct console_font *op)
|
||||
|
||||
/* ladis: when I grow up, there will be a day... and more sizes will
|
||||
* be supported ;-) */
|
||||
if ((w != 8) || (h != 16)
|
||||
if ((w != 8) || (h != 16) || (vpitch != 32)
|
||||
|| (op->charcount != 256 && op->charcount != 512))
|
||||
return -EINVAL;
|
||||
|
||||
@ -569,9 +569,10 @@ static int newport_font_default(struct vc_data *vc, struct console_font *op, cha
|
||||
return newport_set_def_font(vc->vc_num, op);
|
||||
}
|
||||
|
||||
static int newport_font_set(struct vc_data *vc, struct console_font *font, unsigned flags)
|
||||
static int newport_font_set(struct vc_data *vc, struct console_font *font,
|
||||
unsigned int vpitch, unsigned int flags)
|
||||
{
|
||||
return newport_set_font(vc->vc_num, font);
|
||||
return newport_set_font(vc->vc_num, font, vpitch);
|
||||
}
|
||||
|
||||
static bool newport_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
|
||||
|
@ -169,7 +169,8 @@ static int sticon_set_def_font(int unit, struct console_font *op)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sticon_set_font(struct vc_data *vc, struct console_font *op)
|
||||
static int sticon_set_font(struct vc_data *vc, struct console_font *op,
|
||||
unsigned int vpitch)
|
||||
{
|
||||
struct sti_struct *sti = sticon_sti;
|
||||
int vc_cols, vc_rows, vc_old_cols, vc_old_rows;
|
||||
@ -181,7 +182,7 @@ static int sticon_set_font(struct vc_data *vc, struct console_font *op)
|
||||
struct sti_cooked_font *cooked_font;
|
||||
unsigned char *data = op->data, *p;
|
||||
|
||||
if ((w < 6) || (h < 6) || (w > 32) || (h > 32)
|
||||
if ((w < 6) || (h < 6) || (w > 32) || (h > 32) || (vpitch != 32)
|
||||
|| (op->charcount != 256 && op->charcount != 512))
|
||||
return -EINVAL;
|
||||
pitch = ALIGN(w, 8) / 8;
|
||||
@ -267,9 +268,9 @@ static int sticon_font_default(struct vc_data *vc, struct console_font *op, char
|
||||
}
|
||||
|
||||
static int sticon_font_set(struct vc_data *vc, struct console_font *font,
|
||||
unsigned int flags)
|
||||
unsigned int vpitch, unsigned int flags)
|
||||
{
|
||||
return sticon_set_font(vc, font);
|
||||
return sticon_set_font(vc, font, vpitch);
|
||||
}
|
||||
|
||||
static void sticon_init(struct vc_data *c, int init)
|
||||
|
@ -1029,7 +1029,7 @@ static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
|
||||
}
|
||||
|
||||
static int vgacon_font_set(struct vc_data *c, struct console_font *font,
|
||||
unsigned int flags)
|
||||
unsigned int vpitch, unsigned int flags)
|
||||
{
|
||||
unsigned charcount = font->charcount;
|
||||
int rc;
|
||||
@ -1037,7 +1037,7 @@ static int vgacon_font_set(struct vc_data *c, struct console_font *font,
|
||||
if (vga_video_type < VIDEO_TYPE_EGAM)
|
||||
return -EINVAL;
|
||||
|
||||
if (font->width != VGA_FONTWIDTH ||
|
||||
if (font->width != VGA_FONTWIDTH || font->height > 32 || vpitch != 32 ||
|
||||
(charcount != 256 && charcount != 512))
|
||||
return -EINVAL;
|
||||
|
||||
@ -1050,9 +1050,9 @@ static int vgacon_font_set(struct vc_data *c, struct console_font *font,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int vgacon_font_get(struct vc_data *c, struct console_font *font)
|
||||
static int vgacon_font_get(struct vc_data *c, struct console_font *font, unsigned int vpitch)
|
||||
{
|
||||
if (vga_video_type < VIDEO_TYPE_EGAM)
|
||||
if (vga_video_type < VIDEO_TYPE_EGAM || vpitch != 32)
|
||||
return -EINVAL;
|
||||
|
||||
font->width = VGA_FONTWIDTH;
|
||||
|
@ -2266,7 +2266,7 @@ static int fbcon_debug_leave(struct vc_data *vc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
|
||||
static int fbcon_get_font(struct vc_data *vc, struct console_font *font, unsigned int vpitch)
|
||||
{
|
||||
u8 *fontdata = vc->vc_font.data;
|
||||
u8 *data = font->data;
|
||||
@ -2274,6 +2274,8 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
|
||||
|
||||
font->width = vc->vc_font.width;
|
||||
font->height = vc->vc_font.height;
|
||||
if (font->height > vpitch)
|
||||
return -ENOSPC;
|
||||
font->charcount = vc->vc_hi_font_mask ? 512 : 256;
|
||||
if (!font->data)
|
||||
return 0;
|
||||
@ -2285,8 +2287,8 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
|
||||
|
||||
for (i = 0; i < font->charcount; i++) {
|
||||
memcpy(data, fontdata, j);
|
||||
memset(data + j, 0, 32 - j);
|
||||
data += 32;
|
||||
memset(data + j, 0, vpitch - j);
|
||||
data += vpitch;
|
||||
fontdata += j;
|
||||
}
|
||||
} else if (font->width <= 16) {
|
||||
@ -2296,8 +2298,8 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
|
||||
|
||||
for (i = 0; i < font->charcount; i++) {
|
||||
memcpy(data, fontdata, j);
|
||||
memset(data + j, 0, 64 - j);
|
||||
data += 64;
|
||||
memset(data + j, 0, 2*vpitch - j);
|
||||
data += 2*vpitch;
|
||||
fontdata += j;
|
||||
}
|
||||
} else if (font->width <= 24) {
|
||||
@ -2311,8 +2313,8 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
|
||||
*data++ = fontdata[2];
|
||||
fontdata += sizeof(u32);
|
||||
}
|
||||
memset(data, 0, 3 * (32 - j));
|
||||
data += 3 * (32 - j);
|
||||
memset(data, 0, 3 * (vpitch - j));
|
||||
data += 3 * (vpitch - j);
|
||||
}
|
||||
} else {
|
||||
j = vc->vc_font.height * 4;
|
||||
@ -2321,8 +2323,8 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
|
||||
|
||||
for (i = 0; i < font->charcount; i++) {
|
||||
memcpy(data, fontdata, j);
|
||||
memset(data + j, 0, 128 - j);
|
||||
data += 128;
|
||||
memset(data + j, 0, 4 * vpitch - j);
|
||||
data += 4 * vpitch;
|
||||
fontdata += j;
|
||||
}
|
||||
}
|
||||
@ -2457,19 +2459,12 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
|
||||
}
|
||||
|
||||
/*
|
||||
* User asked to set font; we are guaranteed that
|
||||
* a) width and height are in range 1..32
|
||||
* b) charcount does not exceed 512
|
||||
* but lets not assume that, since someone might someday want to use larger
|
||||
* fonts. And charcount of 512 is small for unicode support.
|
||||
*
|
||||
* However, user space gives the font in 32 rows , regardless of
|
||||
* actual font height. So a new API is needed if support for larger fonts
|
||||
* is ever implemented.
|
||||
* User asked to set font; we are guaranteed that charcount does not exceed 512
|
||||
* but lets not assume that, since charcount of 512 is small for unicode support.
|
||||
*/
|
||||
|
||||
static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
|
||||
unsigned int flags)
|
||||
unsigned int vpitch, unsigned int flags)
|
||||
{
|
||||
struct fb_info *info = fbcon_info_from_console(vc->vc_num);
|
||||
unsigned charcount = font->charcount;
|
||||
@ -2515,7 +2510,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
|
||||
FNTSIZE(new_data) = size;
|
||||
REFCOUNT(new_data) = 0; /* usage counter */
|
||||
for (i=0; i< charcount; i++) {
|
||||
memcpy(new_data + i*h*pitch, data + i*32*pitch, h*pitch);
|
||||
memcpy(new_data + i*h*pitch, data + i*vpitch*pitch, h*pitch);
|
||||
}
|
||||
|
||||
/* Since linux has a nice crc32 function use it for counting font
|
||||
|
@ -60,8 +60,9 @@ struct consw {
|
||||
int (*con_switch)(struct vc_data *vc);
|
||||
int (*con_blank)(struct vc_data *vc, int blank, int mode_switch);
|
||||
int (*con_font_set)(struct vc_data *vc, struct console_font *font,
|
||||
unsigned int flags);
|
||||
int (*con_font_get)(struct vc_data *vc, struct console_font *font);
|
||||
unsigned int vpitch, unsigned int flags);
|
||||
int (*con_font_get)(struct vc_data *vc, struct console_font *font,
|
||||
unsigned int vpitch);
|
||||
int (*con_font_default)(struct vc_data *vc,
|
||||
struct console_font *font, char *name);
|
||||
int (*con_resize)(struct vc_data *vc, unsigned int width,
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
struct uni_pagedict;
|
||||
struct uni_screen;
|
||||
|
||||
#define NPAR 16
|
||||
#define VC_TABSTOPS_COUNT 256U
|
||||
@ -159,7 +158,7 @@ struct vc_data {
|
||||
struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */
|
||||
struct uni_pagedict *uni_pagedict;
|
||||
struct uni_pagedict **uni_pagedict_loc; /* [!] Location of uni_pagedict variable for this console */
|
||||
struct uni_screen *vc_uni_screen; /* unicode screen content */
|
||||
u32 **vc_uni_lines; /* unicode screen content */
|
||||
/* additional information is in vt_kern.h */
|
||||
};
|
||||
|
||||
|
@ -27,11 +27,15 @@ enum dfl_id_type {
|
||||
* @id: id of the dfl device.
|
||||
* @type: type of DFL FIU of the device. See enum dfl_id_type.
|
||||
* @feature_id: feature identifier local to its DFL FIU type.
|
||||
* @revision: revision of this dfl device feature.
|
||||
* @mmio_res: mmio resource of this dfl device.
|
||||
* @irqs: list of Linux IRQ numbers of this dfl device.
|
||||
* @num_irqs: number of IRQs supported by this dfl device.
|
||||
* @cdev: pointer to DFL FPGA container device this dfl device belongs to.
|
||||
* @id_entry: matched id entry in dfl driver's id table.
|
||||
* @dfh_version: version of DFH for the device
|
||||
* @param_size: size of the block parameters in bytes
|
||||
* @params: pointer to block of parameters copied memory
|
||||
*/
|
||||
struct dfl_device {
|
||||
struct device dev;
|
||||
@ -44,6 +48,9 @@ struct dfl_device {
|
||||
unsigned int num_irqs;
|
||||
struct dfl_fpga_cdev *cdev;
|
||||
const struct dfl_device_id *id_entry;
|
||||
u8 dfh_version;
|
||||
unsigned int param_size;
|
||||
void *params;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -84,4 +91,5 @@ void dfl_driver_unregister(struct dfl_driver *dfl_drv);
|
||||
module_driver(__dfl_driver, dfl_driver_register, \
|
||||
dfl_driver_unregister)
|
||||
|
||||
void *dfh_find_param(struct dfl_device *dfl_dev, int param_id, size_t *pcount);
|
||||
#endif /* __LINUX_DFL_H */
|
||||
|
@ -12,6 +12,11 @@
|
||||
#include <uapi/linux/serial.h>
|
||||
#include <uapi/linux/serial_reg.h>
|
||||
|
||||
#define UART_IER_ALL_INTR (UART_IER_MSI | \
|
||||
UART_IER_RLSI | \
|
||||
UART_IER_THRI | \
|
||||
UART_IER_RDI)
|
||||
|
||||
/* Helper for dealing with UART_LCR_WLEN* defines */
|
||||
#define UART_LCR_WLEN(x) ((x) - 5)
|
||||
|
||||
@ -23,6 +28,11 @@ static inline bool uart_lsr_tx_empty(u16 lsr)
|
||||
return (lsr & UART_LSR_BOTH_EMPTY) == UART_LSR_BOTH_EMPTY;
|
||||
}
|
||||
|
||||
#define UART_MSR_STATUS_BITS (UART_MSR_DCD | \
|
||||
UART_MSR_RI | \
|
||||
UART_MSR_DSR | \
|
||||
UART_MSR_CTS)
|
||||
|
||||
/*
|
||||
* Counters of the input lines (CTS, DSR, RI, CD) interrupts
|
||||
*/
|
||||
|
@ -579,6 +579,7 @@ struct uart_port {
|
||||
struct serial_rs485 rs485;
|
||||
struct serial_rs485 rs485_supported; /* Supported mask for serial_rs485 */
|
||||
struct gpio_desc *rs485_term_gpio; /* enable RS485 bus termination */
|
||||
struct gpio_desc *rs485_rx_during_tx_gpio; /* Output GPIO that sets the state of RS485 RX during TX */
|
||||
struct serial_iso7816 iso7816;
|
||||
void *private_data; /* generic platform data pointer */
|
||||
};
|
||||
@ -781,7 +782,7 @@ static inline int uart_poll_timeout(struct uart_port *port)
|
||||
struct earlycon_device {
|
||||
struct console *con;
|
||||
struct uart_port port;
|
||||
char options[16]; /* e.g., 115200n8 */
|
||||
char options[32]; /* e.g., 115200n8 */
|
||||
unsigned int baud;
|
||||
};
|
||||
|
||||
@ -896,10 +897,8 @@ static inline bool uart_softcts_mode(struct uart_port *uport)
|
||||
* The following are helper functions for the low level drivers.
|
||||
*/
|
||||
|
||||
extern void uart_handle_dcd_change(struct uart_port *uport,
|
||||
unsigned int status);
|
||||
extern void uart_handle_cts_change(struct uart_port *uport,
|
||||
unsigned int status);
|
||||
extern void uart_handle_dcd_change(struct uart_port *uport, bool active);
|
||||
extern void uart_handle_cts_change(struct uart_port *uport, bool active);
|
||||
|
||||
extern void uart_insert_char(struct uart_port *port, unsigned int status,
|
||||
unsigned int overrun, unsigned int ch, unsigned int flag);
|
||||
|
@ -103,6 +103,7 @@ struct geni_se {
|
||||
#define SE_DMA_TX_FSM_RST 0xc58
|
||||
#define SE_DMA_RX_IRQ_STAT 0xd40
|
||||
#define SE_DMA_RX_IRQ_CLR 0xd44
|
||||
#define SE_DMA_RX_LEN_IN 0xd54
|
||||
#define SE_DMA_RX_FSM_RST 0xd58
|
||||
#define SE_HW_PARAM_0 0xe24
|
||||
#define SE_HW_PARAM_1 0xe28
|
||||
@ -235,6 +236,8 @@ struct geni_se {
|
||||
#define RX_SBE BIT(2)
|
||||
#define RX_RESET_DONE BIT(3)
|
||||
#define RX_FLUSH_DONE BIT(4)
|
||||
#define RX_DMA_PARITY_ERR BIT(5)
|
||||
#define RX_DMA_BREAK GENMASK(8, 7)
|
||||
#define RX_GENI_GP_IRQ GENMASK(10, 5)
|
||||
#define RX_GENI_CANCEL_IRQ BIT(11)
|
||||
#define RX_GENI_GP_IRQ_EXT GENMASK(13, 12)
|
@ -453,7 +453,7 @@ unsigned char tty_get_char_size(unsigned int cflag);
|
||||
unsigned char tty_get_frame_size(unsigned int cflag);
|
||||
|
||||
void tty_termios_copy_hw(struct ktermios *new, const struct ktermios *old);
|
||||
int tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b);
|
||||
bool tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b);
|
||||
int tty_set_termios(struct tty_struct *tty, struct ktermios *kt);
|
||||
|
||||
void tty_wakeup(struct tty_struct *tty);
|
||||
|
@ -170,7 +170,7 @@ int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass,
|
||||
* send, please arise a tasklet or workqueue to do the real data transfer.
|
||||
* Do not send data in this hook, it may lead to a deadlock.
|
||||
*
|
||||
* @dcd_change: [DRV] ``void ()(struct tty_struct *tty, unsigned int status)``
|
||||
* @dcd_change: [DRV] ``void ()(struct tty_struct *tty, bool active)``
|
||||
*
|
||||
* Tells the discipline that the DCD pin has changed its status. Used
|
||||
* exclusively by the %N_PPS (Pulse-Per-Second) line discipline.
|
||||
@ -238,7 +238,7 @@ struct tty_ldisc_ops {
|
||||
void (*receive_buf)(struct tty_struct *tty, const unsigned char *cp,
|
||||
const char *fp, int count);
|
||||
void (*write_wakeup)(struct tty_struct *tty);
|
||||
void (*dcd_change)(struct tty_struct *tty, unsigned int status);
|
||||
void (*dcd_change)(struct tty_struct *tty, bool active);
|
||||
int (*receive_buf2)(struct tty_struct *tty, const unsigned char *cp,
|
||||
const char *fp, int count);
|
||||
void (*lookahead_buf)(struct tty_struct *tty, const unsigned char *cp,
|
||||
|
@ -15,8 +15,8 @@ struct tty_struct;
|
||||
|
||||
/**
|
||||
* struct tty_port_operations -- operations on tty_port
|
||||
* @carrier_raised: return 1 if the carrier is raised on @port
|
||||
* @dtr_rts: raise the DTR line if @raise is nonzero, otherwise lower DTR
|
||||
* @carrier_raised: return true if the carrier is raised on @port
|
||||
* @dtr_rts: raise the DTR line if @active is true, otherwise lower DTR
|
||||
* @shutdown: called when the last close completes or a hangup finishes IFF the
|
||||
* port was initialized. Do not use to free resources. Turn off the device
|
||||
* only. Called under the port mutex to serialize against @activate and
|
||||
@ -31,8 +31,8 @@ struct tty_struct;
|
||||
* the port itself.
|
||||
*/
|
||||
struct tty_port_operations {
|
||||
int (*carrier_raised)(struct tty_port *port);
|
||||
void (*dtr_rts)(struct tty_port *port, int raise);
|
||||
bool (*carrier_raised)(struct tty_port *port);
|
||||
void (*dtr_rts)(struct tty_port *port, bool active);
|
||||
void (*shutdown)(struct tty_port *port);
|
||||
int (*activate)(struct tty_port *port, struct tty_struct *tty);
|
||||
void (*destruct)(struct tty_port *port);
|
||||
@ -230,7 +230,7 @@ static inline void tty_port_set_kopened(struct tty_port *port, bool val)
|
||||
|
||||
struct tty_struct *tty_port_tty_get(struct tty_port *port);
|
||||
void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty);
|
||||
int tty_port_carrier_raised(struct tty_port *port);
|
||||
bool tty_port_carrier_raised(struct tty_port *port);
|
||||
void tty_port_raise_dtr_rts(struct tty_port *port);
|
||||
void tty_port_lower_dtr_rts(struct tty_port *port);
|
||||
void tty_port_hangup(struct tty_port *port);
|
||||
|
@ -19,8 +19,7 @@ struct gsm_config
|
||||
unsigned int mtu;
|
||||
unsigned int k;
|
||||
unsigned int i;
|
||||
unsigned int unused[8]; /* Padding for expansion without
|
||||
breaking stuff */
|
||||
unsigned int unused[8]; /* Can not be used */
|
||||
};
|
||||
|
||||
#define GSMIOC_GETCONF _IOR('G', 0, struct gsm_config)
|
||||
@ -29,9 +28,9 @@ struct gsm_config
|
||||
struct gsm_netconfig {
|
||||
unsigned int adaption; /* Adaption to use in network mode */
|
||||
unsigned short protocol;/* Protocol to use - only ETH_P_IP supported */
|
||||
unsigned short unused2;
|
||||
unsigned short unused2; /* Can not be used */
|
||||
char if_name[IFNAMSIZ]; /* interface name format string */
|
||||
__u8 unused[28]; /* For future use */
|
||||
__u8 unused[28]; /* Can not be used */
|
||||
};
|
||||
|
||||
#define GSMIOC_ENABLE_NET _IOW('G', 2, struct gsm_netconfig)
|
||||
@ -40,4 +39,14 @@ struct gsm_netconfig {
|
||||
/* get the base tty number for a configured gsmmux tty */
|
||||
#define GSMIOC_GETFIRST _IOR('G', 4, __u32)
|
||||
|
||||
struct gsm_config_ext {
|
||||
__u32 keep_alive; /* Control channel keep-alive in 1/100th of a
|
||||
* second (0 to disable)
|
||||
*/
|
||||
__u32 reserved[7]; /* For future use, must be initialized to zero */
|
||||
};
|
||||
|
||||
#define GSMIOC_GETCONF_EXT _IOR('G', 5, struct gsm_config_ext)
|
||||
#define GSMIOC_SETCONF_EXT _IOW('G', 6, struct gsm_config_ext)
|
||||
|
||||
#endif
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user