TTY / Serial driver update for 5.16-rc1
Here is the big set of tty and serial driver updates for 5.16-rc1. Nothing major in here at all, just lots of tiny serial and tty driver updates for various reported things, and some good cleanups. These include: - more good tty api cleanups from Jiri - stm32 serial driver updates - softlockup fix for non-preempt systems under high serial load - rpmsg serial driver update - 8250 drivers updates and fixes - n_gsm line discipline fixes and updates as people are finally starting to use it. All of these have been in linux-next for a while now with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYYPczQ8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ykWbwCfaIScbUoCUx+h/uP93nKKD8B3KgYAoMvFuhhD D/fTLggs12x5NsvLBgtZ =rq0R -----END PGP SIGNATURE----- Merge tag 'tty-5.16-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 tty and serial driver updates for 5.16-rc1. Nothing major in here at all, just lots of tiny serial and tty driver updates for various reported things, and some good cleanups. These include: - more good tty api cleanups from Jiri - stm32 serial driver updates - softlockup fix for non-preempt systems under high serial load - rpmsg serial driver update - 8250 drivers updates and fixes - n_gsm line discipline fixes and updates as people are finally starting to use it. All of these have been in linux-next for a while now with no reported issues" * tag 'tty-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (86 commits) tty: Fix extra "not" in TTY_DRIVER_REAL_RAW description serial: cpm_uart: Protect udbg definitions by CONFIG_SERIAL_CPM_CONSOLE tty: rpmsg: Define tty name via constant string literal tty: rpmsg: Add pr_fmt() to prefix messages tty: rpmsg: Use dev_err_probe() in ->probe() tty: rpmsg: Unify variable used to keep an error code tty: rpmsg: Assign returned id to a local variable serial: stm32: push DMA RX data before suspending serial: stm32: terminate / restart DMA transfer at suspend / resume serial: stm32: rework RX dma initialization and release serial: 8250_pci: Remove empty stub pci_quatech_exit() serial: 8250_pci: Replace custom pci_match_id() implementation serial: xilinx_uartps: Fix race condition causing stuck TX serial: sunzilog: Mark sunzilog_putchar() __maybe_unused Revert "tty: hvc: pass DMA capable memory to put_chars()" Revert "virtio-console: remove unnecessary kmemdup()" serial: 8250_pci: Replace dev_*() by pci_*() macros serial: 8250_pci: Get rid of redundant 'else' keyword serial: 8250_pci: Refactor the loop in pci_ite887x_init() tty: add rpmsg driver ...
This commit is contained in:
commit
abfecb3909
@ -86,7 +86,7 @@ required:
|
|||||||
- reg
|
- reg
|
||||||
- interrupts
|
- interrupts
|
||||||
|
|
||||||
additionalProperties: false
|
unevaluatedProperties: false
|
||||||
|
|
||||||
if:
|
if:
|
||||||
properties:
|
properties:
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
* BCM63xx UART
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
|
|
||||||
- compatible: "brcm,bcm6345-uart"
|
|
||||||
|
|
||||||
- reg: The base address of the UART register bank.
|
|
||||||
|
|
||||||
- interrupts: A single interrupt specifier.
|
|
||||||
|
|
||||||
- clocks: Clock driving the hardware; used to figure out the baud rate
|
|
||||||
divisor.
|
|
||||||
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
|
|
||||||
- clock-names: Should be "refclk".
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
uart0: serial@14e00520 {
|
|
||||||
compatible = "brcm,bcm6345-uart";
|
|
||||||
reg = <0x14e00520 0x18>;
|
|
||||||
interrupt-parent = <&periph_intc>;
|
|
||||||
interrupts = <2>;
|
|
||||||
clocks = <&periph_clk>;
|
|
||||||
clock-names = "refclk";
|
|
||||||
};
|
|
||||||
|
|
||||||
clocks {
|
|
||||||
periph_clk: periph_clk@0 {
|
|
||||||
compatible = "fixed-clock";
|
|
||||||
#clock-cells = <0>;
|
|
||||||
clock-frequency = <54000000>;
|
|
||||||
};
|
|
||||||
};
|
|
@ -0,0 +1,47 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/serial/brcm,bcm6345-uart.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: BCM63xx UART
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Rafał Miłecki <rafal@milecki.pl>
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: serial.yaml#
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
const: brcm,bcm6345-uart
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
const: refclk
|
||||||
|
|
||||||
|
unevaluatedProperties: false
|
||||||
|
|
||||||
|
required:
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
- clocks
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
serial@14e00520 {
|
||||||
|
compatible = "brcm,bcm6345-uart";
|
||||||
|
reg = <0x14e00520 0x18>;
|
||||||
|
interrupt-parent = <&periph_intc>;
|
||||||
|
interrupts = <2>;
|
||||||
|
clocks = <&periph_clk>;
|
||||||
|
clock-names = "refclk";
|
||||||
|
};
|
@ -26,6 +26,7 @@ properties:
|
|||||||
- samsung,s3c6400-uart
|
- samsung,s3c6400-uart
|
||||||
- samsung,s5pv210-uart
|
- samsung,s5pv210-uart
|
||||||
- samsung,exynos4210-uart
|
- samsung,exynos4210-uart
|
||||||
|
- samsung,exynos850-uart
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
@ -19,6 +19,7 @@ properties:
|
|||||||
- enum:
|
- enum:
|
||||||
- sprd,sc9860-uart
|
- sprd,sc9860-uart
|
||||||
- sprd,sc9863a-uart
|
- sprd,sc9863a-uart
|
||||||
|
- sprd,ums512-uart
|
||||||
- const: sprd,sc9836-uart
|
- const: sprd,sc9836-uart
|
||||||
- const: sprd,sc9836-uart
|
- const: sprd,sc9836-uart
|
||||||
|
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
Xilinx Axi Uartlite controller Device Tree Bindings
|
|
||||||
---------------------------------------------------------
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible : Can be either of
|
|
||||||
"xlnx,xps-uartlite-1.00.a"
|
|
||||||
"xlnx,opb-uartlite-1.00.b"
|
|
||||||
- reg : Physical base address and size of the Axi Uartlite
|
|
||||||
registers map.
|
|
||||||
- interrupts : Should contain the UART controller interrupt.
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
- port-number : Set Uart port number
|
|
||||||
- clock-names : Should be "s_axi_aclk"
|
|
||||||
- clocks : Input clock specifier. Refer to common clock bindings.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
serial@800c0000 {
|
|
||||||
compatible = "xlnx,xps-uartlite-1.00.a";
|
|
||||||
reg = <0x0 0x800c0000 0x10000>;
|
|
||||||
interrupts = <0x0 0x6e 0x1>;
|
|
||||||
port-number = <0>;
|
|
||||||
};
|
|
@ -0,0 +1,89 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/serial/xlnx,opb-uartlite.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Xilinx Axi Uartlite
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Peter Korsgaard <jacmet@sunsite.dk>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
enum:
|
||||||
|
- xlnx,xps-uartlite-1.00.a
|
||||||
|
- xlnx,opb-uartlite-1.00.b
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
port-number:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
description: Set Uart port number
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
const: s_axi_aclk
|
||||||
|
|
||||||
|
current-speed:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
description:
|
||||||
|
The fixed baud rate that the device was configured for.
|
||||||
|
|
||||||
|
xlnx,data-bits:
|
||||||
|
enum: [5, 6, 7, 8]
|
||||||
|
description:
|
||||||
|
The fixed number of data bits that the device was configured for.
|
||||||
|
|
||||||
|
xlnx,use-parity:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
enum: [0, 1]
|
||||||
|
description:
|
||||||
|
Whether parity checking was enabled when the device was configured.
|
||||||
|
|
||||||
|
xlnx,odd-parity:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
enum: [0, 1]
|
||||||
|
description:
|
||||||
|
Whether odd parity was configured.
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
- current-speed
|
||||||
|
- xlnx,data-bits
|
||||||
|
- xlnx,use-parity
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/serial.yaml#
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
xlnx,use-parity:
|
||||||
|
contains:
|
||||||
|
const: 1
|
||||||
|
then:
|
||||||
|
required:
|
||||||
|
- xlnx,odd-parity
|
||||||
|
|
||||||
|
unevaluatedProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
serial@800c0000 {
|
||||||
|
compatible = "xlnx,xps-uartlite-1.00.a";
|
||||||
|
reg = <0x800c0000 0x10000>;
|
||||||
|
interrupts = <0x0 0x6e 0x1>;
|
||||||
|
port-number = <0>;
|
||||||
|
current-speed = <115200>;
|
||||||
|
xlnx,data-bits = <8>;
|
||||||
|
xlnx,use-parity = <0>;
|
||||||
|
};
|
||||||
|
...
|
@ -12,13 +12,16 @@ modems connected to a physical serial port.
|
|||||||
|
|
||||||
How to use it
|
How to use it
|
||||||
-------------
|
-------------
|
||||||
1. initialize the modem in 0710 mux mode (usually AT+CMUX= command) through
|
1. config initiator
|
||||||
its serial port. Depending on the modem used, you can pass more or less
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
parameters to this command,
|
|
||||||
2. switch the serial line to using the n_gsm line discipline by using
|
1.1 initialize the modem in 0710 mux mode (usually AT+CMUX= command) through
|
||||||
TIOCSETD ioctl,
|
its serial port. Depending on the modem used, you can pass more or less
|
||||||
3. configure the mux using GSMIOC_GETCONF / GSMIOC_SETCONF ioctl,
|
parameters to this command.
|
||||||
4. obtain base gsmtty number for the used serial port,
|
1.2 switch the serial line to using the n_gsm line discipline by using
|
||||||
|
TIOCSETD ioctl.
|
||||||
|
1.3 configure the mux using GSMIOC_GETCONF / GSMIOC_SETCONF ioctl.
|
||||||
|
1.4 obtain base gsmtty number for the used serial port.
|
||||||
|
|
||||||
Major parts of the initialization program :
|
Major parts of the initialization program :
|
||||||
(a good starting point is util-linux-ng/sys-utils/ldattach.c)::
|
(a good starting point is util-linux-ng/sys-utils/ldattach.c)::
|
||||||
@ -70,14 +73,14 @@ Major parts of the initialization program :
|
|||||||
daemon(0,0);
|
daemon(0,0);
|
||||||
pause();
|
pause();
|
||||||
|
|
||||||
5. use these devices as plain serial ports.
|
1.5 use these devices as plain serial ports.
|
||||||
|
|
||||||
for example, it's possible:
|
for example, it's possible:
|
||||||
|
|
||||||
- and to use gnokii to send / receive SMS on ttygsm1
|
- and to use gnokii to send / receive SMS on ttygsm1
|
||||||
- to use ppp to establish a datalink on ttygsm2
|
- to use ppp to establish a datalink on ttygsm2
|
||||||
|
|
||||||
6. first close all virtual ports before closing the physical port.
|
1.6 first close all virtual ports before closing the physical port.
|
||||||
|
|
||||||
Note that after closing the physical port the modem is still in multiplexing
|
Note that after closing the physical port the modem is still in multiplexing
|
||||||
mode. This may prevent a successful re-opening of the port later. To avoid
|
mode. This may prevent a successful re-opening of the port later. To avoid
|
||||||
@ -87,6 +90,56 @@ Major parts of the initialization program :
|
|||||||
|
|
||||||
0xf9, 0x03, 0xef, 0x03, 0xc3, 0x16, 0xf9.
|
0xf9, 0x03, 0xef, 0x03, 0xc3, 0x16, 0xf9.
|
||||||
|
|
||||||
|
2. config requester
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
2.1 receive string "AT+CMUX= command" through its serial port,initialize
|
||||||
|
mux mode config
|
||||||
|
2.2 switch the serial line to using the n_gsm line discipline by using
|
||||||
|
TIOCSETD ioctl.
|
||||||
|
2.3 configure the mux using GSMIOC_GETCONF / GSMIOC_SETCONF ioctl.
|
||||||
|
2.4 obtain base gsmtty number for the used serial port,
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <linux/gsmmux.h>
|
||||||
|
#include <linux/tty.h>
|
||||||
|
#define DEFAULT_SPEED B115200
|
||||||
|
#define SERIAL_PORT /dev/ttyS0
|
||||||
|
|
||||||
|
int ldisc = N_GSM0710;
|
||||||
|
struct gsm_config c;
|
||||||
|
struct termios configuration;
|
||||||
|
uint32_t first;
|
||||||
|
|
||||||
|
/* open the serial port */
|
||||||
|
fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY);
|
||||||
|
|
||||||
|
/* configure the serial port : speed, flow control ... */
|
||||||
|
|
||||||
|
/* get serial data and check "AT+CMUX=command" parameter ... */
|
||||||
|
|
||||||
|
/* use n_gsm line discipline */
|
||||||
|
ioctl(fd, TIOCSETD, &ldisc);
|
||||||
|
|
||||||
|
/* get n_gsm configuration */
|
||||||
|
ioctl(fd, GSMIOC_GETCONF, &c);
|
||||||
|
/* we are requester and need encoding 0 (basic) */
|
||||||
|
c.initiator = 0;
|
||||||
|
c.encapsulation = 0;
|
||||||
|
/* our modem defaults to a maximum size of 127 bytes */
|
||||||
|
c.mru = 127;
|
||||||
|
c.mtu = 127;
|
||||||
|
/* set the new configuration */
|
||||||
|
ioctl(fd, GSMIOC_SETCONF, &c);
|
||||||
|
/* get first gsmtty device node */
|
||||||
|
ioctl(fd, GSMIOC_GETFIRST, &first);
|
||||||
|
printf("first muxed line: /dev/gsmtty%i\n", first);
|
||||||
|
|
||||||
|
/* and wait for ever to keep the line discipline enabled */
|
||||||
|
daemon(0,0);
|
||||||
|
pause();
|
||||||
|
|
||||||
Additional Documentation
|
Additional Documentation
|
||||||
------------------------
|
------------------------
|
||||||
More practical details on the protocol and how it's supported by industrial
|
More practical details on the protocol and how it's supported by industrial
|
||||||
|
@ -58,7 +58,7 @@ close() This is called on a terminal when the line
|
|||||||
hangup() Called when the tty line is hung up.
|
hangup() Called when the tty line is hung up.
|
||||||
The line discipline should cease I/O to the tty.
|
The line discipline should cease I/O to the tty.
|
||||||
No further calls into the ldisc code will occur.
|
No further calls into the ldisc code will occur.
|
||||||
The return value is ignored. Can sleep.
|
Can sleep.
|
||||||
|
|
||||||
read() (optional) A process requests reading data from
|
read() (optional) A process requests reading data from
|
||||||
the line. Multiple read calls may occur in parallel
|
the line. Multiple read calls may occur in parallel
|
||||||
|
@ -88,6 +88,8 @@
|
|||||||
clock-frequency = <125000000>;
|
clock-frequency = <125000000>;
|
||||||
compatible = "xlnx,xps-uartlite-1.00.a";
|
compatible = "xlnx,xps-uartlite-1.00.a";
|
||||||
current-speed = <19200>;
|
current-speed = <19200>;
|
||||||
|
xlnx,use-parity = <0>;
|
||||||
|
xlnx,data-bits = <8>;
|
||||||
device_type = "serial";
|
device_type = "serial";
|
||||||
interrupts = <0x12>;
|
interrupts = <0x12>;
|
||||||
port-number = <0>;
|
port-number = <0>;
|
||||||
|
@ -793,7 +793,7 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file *file,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
err = n_tty_ioctl_helper(tty, file, cmd, arg);
|
err = n_tty_ioctl_helper(tty, cmd, arg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,7 +244,7 @@ static int serport_ldisc_compat_ioctl(struct tty_struct *tty,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int serport_ldisc_hangup(struct tty_struct *tty)
|
static void serport_ldisc_hangup(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
struct serport *serport = (struct serport *) tty->disc_data;
|
struct serport *serport = (struct serport *) tty->disc_data;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
@ -254,7 +254,6 @@ static int serport_ldisc_hangup(struct tty_struct *tty)
|
|||||||
spin_unlock_irqrestore(&serport->lock, flags);
|
spin_unlock_irqrestore(&serport->lock, flags);
|
||||||
|
|
||||||
wake_up_interruptible(&serport->wait);
|
wake_up_interruptible(&serport->wait);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serport_ldisc_write_wakeup(struct tty_struct * tty)
|
static void serport_ldisc_write_wakeup(struct tty_struct * tty)
|
||||||
|
@ -664,10 +664,9 @@ static void slcan_close(struct tty_struct *tty)
|
|||||||
/* This will complete via sl_free_netdev */
|
/* This will complete via sl_free_netdev */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int slcan_hangup(struct tty_struct *tty)
|
static void slcan_hangup(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
slcan_close(tty);
|
slcan_close(tty);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform I/O control on an active SLCAN channel. */
|
/* Perform I/O control on an active SLCAN channel. */
|
||||||
@ -692,7 +691,7 @@ static int slcan_ioctl(struct tty_struct *tty, struct file *file,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return tty_mode_ioctl(tty, file, cmd, arg);
|
return tty_mode_ioctl(tty, cmd, arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,7 +732,7 @@ static int sixpack_ioctl(struct tty_struct *tty, struct file *file,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
err = tty_mode_ioctl(tty, file, cmd, arg);
|
err = tty_mode_ioctl(tty, cmd, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
sp_put(sp);
|
sp_put(sp);
|
||||||
|
@ -247,10 +247,9 @@ ppp_asynctty_close(struct tty_struct *tty)
|
|||||||
* Wait for I/O to driver to complete and unregister PPP channel.
|
* Wait for I/O to driver to complete and unregister PPP channel.
|
||||||
* This is already done by the close routine, so just call that.
|
* This is already done by the close routine, so just call that.
|
||||||
*/
|
*/
|
||||||
static int ppp_asynctty_hangup(struct tty_struct *tty)
|
static void ppp_asynctty_hangup(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
ppp_asynctty_close(tty);
|
ppp_asynctty_close(tty);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -311,7 +310,7 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
|
|||||||
/* flush our buffers and the serial port's buffer */
|
/* flush our buffers and the serial port's buffer */
|
||||||
if (arg == TCIOFLUSH || arg == TCOFLUSH)
|
if (arg == TCIOFLUSH || arg == TCOFLUSH)
|
||||||
ppp_async_flush_output(ap);
|
ppp_async_flush_output(ap);
|
||||||
err = n_tty_ioctl_helper(tty, file, cmd, arg);
|
err = n_tty_ioctl_helper(tty, cmd, arg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FIONREAD:
|
case FIONREAD:
|
||||||
@ -323,7 +322,7 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
/* Try the various mode ioctls */
|
/* Try the various mode ioctls */
|
||||||
err = tty_mode_ioctl(tty, file, cmd, arg);
|
err = tty_mode_ioctl(tty, cmd, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
ap_put(ap);
|
ap_put(ap);
|
||||||
|
@ -245,10 +245,9 @@ ppp_sync_close(struct tty_struct *tty)
|
|||||||
* Wait for I/O to driver to complete and unregister PPP channel.
|
* Wait for I/O to driver to complete and unregister PPP channel.
|
||||||
* This is already done by the close routine, so just call that.
|
* This is already done by the close routine, so just call that.
|
||||||
*/
|
*/
|
||||||
static int ppp_sync_hangup(struct tty_struct *tty)
|
static void ppp_sync_hangup(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
ppp_sync_close(tty);
|
ppp_sync_close(tty);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -304,7 +303,7 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file,
|
|||||||
/* flush our buffers and the serial port's buffer */
|
/* flush our buffers and the serial port's buffer */
|
||||||
if (arg == TCIOFLUSH || arg == TCOFLUSH)
|
if (arg == TCIOFLUSH || arg == TCOFLUSH)
|
||||||
ppp_sync_flush_output(ap);
|
ppp_sync_flush_output(ap);
|
||||||
err = n_tty_ioctl_helper(tty, file, cmd, arg);
|
err = n_tty_ioctl_helper(tty, cmd, arg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FIONREAD:
|
case FIONREAD:
|
||||||
@ -315,7 +314,7 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
err = tty_mode_ioctl(tty, file, cmd, arg);
|
err = tty_mode_ioctl(tty, cmd, arg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -907,10 +907,9 @@ static void slip_close(struct tty_struct *tty)
|
|||||||
/* This will complete via sl_free_netdev */
|
/* This will complete via sl_free_netdev */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int slip_hangup(struct tty_struct *tty)
|
static void slip_hangup(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
slip_close(tty);
|
slip_close(tty);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* STANDARD SLIP ENCAPSULATION *
|
* STANDARD SLIP ENCAPSULATION *
|
||||||
@ -1174,7 +1173,7 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file,
|
|||||||
/* VSV changes end */
|
/* VSV changes end */
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
return tty_mode_ioctl(tty, file, cmd, arg);
|
return tty_mode_ioctl(tty, cmd, arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,6 +327,27 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(rpmsg_trysend_offchannel);
|
EXPORT_SYMBOL(rpmsg_trysend_offchannel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rpmsg_get_mtu() - get maximum transmission buffer size for sending message.
|
||||||
|
* @ept: the rpmsg endpoint
|
||||||
|
*
|
||||||
|
* This function returns maximum buffer size available for a single outgoing message.
|
||||||
|
*
|
||||||
|
* Return: the maximum transmission size on success and an appropriate error
|
||||||
|
* value on failure.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ssize_t rpmsg_get_mtu(struct rpmsg_endpoint *ept)
|
||||||
|
{
|
||||||
|
if (WARN_ON(!ept))
|
||||||
|
return -EINVAL;
|
||||||
|
if (!ept->ops->get_mtu)
|
||||||
|
return -ENOTSUPP;
|
||||||
|
|
||||||
|
return ept->ops->get_mtu(ept);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(rpmsg_get_mtu);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* match a rpmsg channel with a channel info struct.
|
* match a rpmsg channel with a channel info struct.
|
||||||
* this is used to make sure we're not creating rpmsg devices for channels
|
* this is used to make sure we're not creating rpmsg devices for channels
|
||||||
|
@ -53,6 +53,7 @@ struct rpmsg_device_ops {
|
|||||||
* @trysendto: see @rpmsg_trysendto(), optional
|
* @trysendto: see @rpmsg_trysendto(), optional
|
||||||
* @trysend_offchannel: see @rpmsg_trysend_offchannel(), optional
|
* @trysend_offchannel: see @rpmsg_trysend_offchannel(), optional
|
||||||
* @poll: see @rpmsg_poll(), optional
|
* @poll: see @rpmsg_poll(), optional
|
||||||
|
* @get_mtu: see @rpmsg_get_mtu(), optional
|
||||||
*
|
*
|
||||||
* Indirection table for the operations that a rpmsg backend should implement.
|
* Indirection table for the operations that a rpmsg backend should implement.
|
||||||
* In addition to @destroy_ept, the backend must at least implement @send and
|
* In addition to @destroy_ept, the backend must at least implement @send and
|
||||||
@ -72,6 +73,7 @@ struct rpmsg_endpoint_ops {
|
|||||||
void *data, int len);
|
void *data, int len);
|
||||||
__poll_t (*poll)(struct rpmsg_endpoint *ept, struct file *filp,
|
__poll_t (*poll)(struct rpmsg_endpoint *ept, struct file *filp,
|
||||||
poll_table *wait);
|
poll_table *wait);
|
||||||
|
ssize_t (*get_mtu)(struct rpmsg_endpoint *ept);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct device *rpmsg_find_device(struct device *parent,
|
struct device *rpmsg_find_device(struct device *parent,
|
||||||
|
@ -149,6 +149,7 @@ static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data,
|
|||||||
int len, u32 dst);
|
int len, u32 dst);
|
||||||
static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src,
|
static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src,
|
||||||
u32 dst, void *data, int len);
|
u32 dst, void *data, int len);
|
||||||
|
static ssize_t virtio_rpmsg_get_mtu(struct rpmsg_endpoint *ept);
|
||||||
static struct rpmsg_device *__rpmsg_create_channel(struct virtproc_info *vrp,
|
static struct rpmsg_device *__rpmsg_create_channel(struct virtproc_info *vrp,
|
||||||
struct rpmsg_channel_info *chinfo);
|
struct rpmsg_channel_info *chinfo);
|
||||||
|
|
||||||
@ -160,6 +161,7 @@ static const struct rpmsg_endpoint_ops virtio_endpoint_ops = {
|
|||||||
.trysend = virtio_rpmsg_trysend,
|
.trysend = virtio_rpmsg_trysend,
|
||||||
.trysendto = virtio_rpmsg_trysendto,
|
.trysendto = virtio_rpmsg_trysendto,
|
||||||
.trysend_offchannel = virtio_rpmsg_trysend_offchannel,
|
.trysend_offchannel = virtio_rpmsg_trysend_offchannel,
|
||||||
|
.get_mtu = virtio_rpmsg_get_mtu,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -696,6 +698,14 @@ static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src,
|
|||||||
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
|
return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t virtio_rpmsg_get_mtu(struct rpmsg_endpoint *ept)
|
||||||
|
{
|
||||||
|
struct rpmsg_device *rpdev = ept->rpdev;
|
||||||
|
struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev);
|
||||||
|
|
||||||
|
return vch->vrp->buf_size - sizeof(struct rpmsg_hdr);
|
||||||
|
}
|
||||||
|
|
||||||
static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
|
static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
|
||||||
struct rpmsg_hdr *msg, unsigned int len)
|
struct rpmsg_hdr *msg, unsigned int len)
|
||||||
{
|
{
|
||||||
|
@ -368,6 +368,18 @@ config VCC
|
|||||||
|
|
||||||
source "drivers/tty/hvc/Kconfig"
|
source "drivers/tty/hvc/Kconfig"
|
||||||
|
|
||||||
|
config RPMSG_TTY
|
||||||
|
tristate "RPMSG tty driver"
|
||||||
|
depends on RPMSG
|
||||||
|
help
|
||||||
|
Say y here to export rpmsg endpoints as tty devices, usually found
|
||||||
|
in /dev/ttyRPMSGx.
|
||||||
|
This makes it possible for user-space programs to send and receive
|
||||||
|
rpmsg messages as a standard tty protocol.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the module will be
|
||||||
|
called rpmsg_tty.
|
||||||
|
|
||||||
endif # TTY
|
endif # TTY
|
||||||
|
|
||||||
source "drivers/tty/serdev/Kconfig"
|
source "drivers/tty/serdev/Kconfig"
|
||||||
|
@ -26,5 +26,6 @@ obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o
|
|||||||
obj-$(CONFIG_GOLDFISH_TTY) += goldfish.o
|
obj-$(CONFIG_GOLDFISH_TTY) += goldfish.o
|
||||||
obj-$(CONFIG_MIPS_EJTAG_FDC_TTY) += mips_ejtag_fdc.o
|
obj-$(CONFIG_MIPS_EJTAG_FDC_TTY) += mips_ejtag_fdc.o
|
||||||
obj-$(CONFIG_VCC) += vcc.o
|
obj-$(CONFIG_VCC) += vcc.o
|
||||||
|
obj-$(CONFIG_RPMSG_TTY) += rpmsg_tty.o
|
||||||
|
|
||||||
obj-y += ipwireless/
|
obj-y += ipwireless/
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
#define N_OUTBUF 16
|
#define N_OUTBUF 16
|
||||||
#define N_INBUF 16
|
#define N_INBUF 16
|
||||||
|
|
||||||
#define __ALIGNED__ __attribute__((__aligned__(sizeof(long))))
|
#define __ALIGNED__ __attribute__((__aligned__(L1_CACHE_BYTES)))
|
||||||
|
|
||||||
static struct tty_driver *hvc_driver;
|
static struct tty_driver *hvc_driver;
|
||||||
static struct task_struct *hvc_task;
|
static struct task_struct *hvc_task;
|
||||||
|
@ -45,7 +45,307 @@
|
|||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
#include "moxa.h"
|
#define MOXA 0x400
|
||||||
|
#define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */
|
||||||
|
#define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */
|
||||||
|
#define MOXA_GETDATACOUNT (MOXA + 23)
|
||||||
|
#define MOXA_GET_IOQUEUE (MOXA + 27)
|
||||||
|
#define MOXA_FLUSH_QUEUE (MOXA + 28)
|
||||||
|
#define MOXA_GETMSTATUS (MOXA + 65)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* System Configuration
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define Magic_code 0x404
|
||||||
|
|
||||||
|
/*
|
||||||
|
* for C218 BIOS initialization
|
||||||
|
*/
|
||||||
|
#define C218_ConfBase 0x800
|
||||||
|
#define C218_status (C218_ConfBase + 0) /* BIOS running status */
|
||||||
|
#define C218_diag (C218_ConfBase + 2) /* diagnostic status */
|
||||||
|
#define C218_key (C218_ConfBase + 4) /* WORD (0x218 for C218) */
|
||||||
|
#define C218DLoad_len (C218_ConfBase + 6) /* WORD */
|
||||||
|
#define C218check_sum (C218_ConfBase + 8) /* BYTE */
|
||||||
|
#define C218chksum_ok (C218_ConfBase + 0x0a) /* BYTE (1:ok) */
|
||||||
|
#define C218_TestRx (C218_ConfBase + 0x10) /* 8 bytes for 8 ports */
|
||||||
|
#define C218_TestTx (C218_ConfBase + 0x18) /* 8 bytes for 8 ports */
|
||||||
|
#define C218_RXerr (C218_ConfBase + 0x20) /* 8 bytes for 8 ports */
|
||||||
|
#define C218_ErrFlag (C218_ConfBase + 0x28) /* 8 bytes for 8 ports */
|
||||||
|
|
||||||
|
#define C218_LoadBuf 0x0F00
|
||||||
|
#define C218_KeyCode 0x218
|
||||||
|
#define CP204J_KeyCode 0x204
|
||||||
|
|
||||||
|
/*
|
||||||
|
* for C320 BIOS initialization
|
||||||
|
*/
|
||||||
|
#define C320_ConfBase 0x800
|
||||||
|
#define C320_LoadBuf 0x0f00
|
||||||
|
#define STS_init 0x05 /* for C320_status */
|
||||||
|
|
||||||
|
#define C320_status C320_ConfBase + 0 /* BIOS running status */
|
||||||
|
#define C320_diag C320_ConfBase + 2 /* diagnostic status */
|
||||||
|
#define C320_key C320_ConfBase + 4 /* WORD (0320H for C320) */
|
||||||
|
#define C320DLoad_len C320_ConfBase + 6 /* WORD */
|
||||||
|
#define C320check_sum C320_ConfBase + 8 /* WORD */
|
||||||
|
#define C320chksum_ok C320_ConfBase + 0x0a /* WORD (1:ok) */
|
||||||
|
#define C320bapi_len C320_ConfBase + 0x0c /* WORD */
|
||||||
|
#define C320UART_no C320_ConfBase + 0x0e /* WORD */
|
||||||
|
|
||||||
|
#define C320_KeyCode 0x320
|
||||||
|
|
||||||
|
#define FixPage_addr 0x0000 /* starting addr of static page */
|
||||||
|
#define DynPage_addr 0x2000 /* starting addr of dynamic page */
|
||||||
|
#define C218_start 0x3000 /* starting addr of C218 BIOS prg */
|
||||||
|
#define Control_reg 0x1ff0 /* select page and reset control */
|
||||||
|
#define HW_reset 0x80
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Function Codes
|
||||||
|
*/
|
||||||
|
#define FC_CardReset 0x80
|
||||||
|
#define FC_ChannelReset 1 /* C320 firmware not supported */
|
||||||
|
#define FC_EnableCH 2
|
||||||
|
#define FC_DisableCH 3
|
||||||
|
#define FC_SetParam 4
|
||||||
|
#define FC_SetMode 5
|
||||||
|
#define FC_SetRate 6
|
||||||
|
#define FC_LineControl 7
|
||||||
|
#define FC_LineStatus 8
|
||||||
|
#define FC_XmitControl 9
|
||||||
|
#define FC_FlushQueue 10
|
||||||
|
#define FC_SendBreak 11
|
||||||
|
#define FC_StopBreak 12
|
||||||
|
#define FC_LoopbackON 13
|
||||||
|
#define FC_LoopbackOFF 14
|
||||||
|
#define FC_ClrIrqTable 15
|
||||||
|
#define FC_SendXon 16
|
||||||
|
#define FC_SetTermIrq 17 /* C320 firmware not supported */
|
||||||
|
#define FC_SetCntIrq 18 /* C320 firmware not supported */
|
||||||
|
#define FC_SetBreakIrq 19
|
||||||
|
#define FC_SetLineIrq 20
|
||||||
|
#define FC_SetFlowCtl 21
|
||||||
|
#define FC_GenIrq 22
|
||||||
|
#define FC_InCD180 23
|
||||||
|
#define FC_OutCD180 24
|
||||||
|
#define FC_InUARTreg 23
|
||||||
|
#define FC_OutUARTreg 24
|
||||||
|
#define FC_SetXonXoff 25
|
||||||
|
#define FC_OutCD180CCR 26
|
||||||
|
#define FC_ExtIQueue 27
|
||||||
|
#define FC_ExtOQueue 28
|
||||||
|
#define FC_ClrLineIrq 29
|
||||||
|
#define FC_HWFlowCtl 30
|
||||||
|
#define FC_GetClockRate 35
|
||||||
|
#define FC_SetBaud 36
|
||||||
|
#define FC_SetDataMode 41
|
||||||
|
#define FC_GetCCSR 43
|
||||||
|
#define FC_GetDataError 45
|
||||||
|
#define FC_RxControl 50
|
||||||
|
#define FC_ImmSend 51
|
||||||
|
#define FC_SetXonState 52
|
||||||
|
#define FC_SetXoffState 53
|
||||||
|
#define FC_SetRxFIFOTrig 54
|
||||||
|
#define FC_SetTxFIFOCnt 55
|
||||||
|
#define FC_UnixRate 56
|
||||||
|
#define FC_UnixResetTimer 57
|
||||||
|
|
||||||
|
#define RxFIFOTrig1 0
|
||||||
|
#define RxFIFOTrig4 1
|
||||||
|
#define RxFIFOTrig8 2
|
||||||
|
#define RxFIFOTrig14 3
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dual-Ported RAM
|
||||||
|
*/
|
||||||
|
#define DRAM_global 0
|
||||||
|
#define INT_data (DRAM_global + 0)
|
||||||
|
#define Config_base (DRAM_global + 0x108)
|
||||||
|
|
||||||
|
#define IRQindex (INT_data + 0)
|
||||||
|
#define IRQpending (INT_data + 4)
|
||||||
|
#define IRQtable (INT_data + 8)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interrupt Status
|
||||||
|
*/
|
||||||
|
#define IntrRx 0x01 /* receiver data O.K. */
|
||||||
|
#define IntrTx 0x02 /* transmit buffer empty */
|
||||||
|
#define IntrFunc 0x04 /* function complete */
|
||||||
|
#define IntrBreak 0x08 /* received break */
|
||||||
|
#define IntrLine 0x10 /* line status change
|
||||||
|
for transmitter */
|
||||||
|
#define IntrIntr 0x20 /* received INTR code */
|
||||||
|
#define IntrQuit 0x40 /* received QUIT code */
|
||||||
|
#define IntrEOF 0x80 /* received EOF code */
|
||||||
|
|
||||||
|
#define IntrRxTrigger 0x100 /* rx data count reach trigger value */
|
||||||
|
#define IntrTxTrigger 0x200 /* tx data count below trigger value */
|
||||||
|
|
||||||
|
#define Magic_no (Config_base + 0)
|
||||||
|
#define Card_model_no (Config_base + 2)
|
||||||
|
#define Total_ports (Config_base + 4)
|
||||||
|
#define Module_cnt (Config_base + 8)
|
||||||
|
#define Module_no (Config_base + 10)
|
||||||
|
#define Timer_10ms (Config_base + 14)
|
||||||
|
#define Disable_IRQ (Config_base + 20)
|
||||||
|
#define TMS320_PORT1 (Config_base + 22)
|
||||||
|
#define TMS320_PORT2 (Config_base + 24)
|
||||||
|
#define TMS320_CLOCK (Config_base + 26)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DATA BUFFER in DRAM
|
||||||
|
*/
|
||||||
|
#define Extern_table 0x400 /* Base address of the external table
|
||||||
|
(24 words * 64) total 3K bytes
|
||||||
|
(24 words * 128) total 6K bytes */
|
||||||
|
#define Extern_size 0x60 /* 96 bytes */
|
||||||
|
#define RXrptr 0x00 /* read pointer for RX buffer */
|
||||||
|
#define RXwptr 0x02 /* write pointer for RX buffer */
|
||||||
|
#define TXrptr 0x04 /* read pointer for TX buffer */
|
||||||
|
#define TXwptr 0x06 /* write pointer for TX buffer */
|
||||||
|
#define HostStat 0x08 /* IRQ flag and general flag */
|
||||||
|
#define FlagStat 0x0A
|
||||||
|
#define FlowControl 0x0C /* B7 B6 B5 B4 B3 B2 B1 B0 */
|
||||||
|
/* x x x x | | | | */
|
||||||
|
/* | | | + CTS flow */
|
||||||
|
/* | | +--- RTS flow */
|
||||||
|
/* | +------ TX Xon/Xoff */
|
||||||
|
/* +--------- RX Xon/Xoff */
|
||||||
|
#define Break_cnt 0x0E /* received break count */
|
||||||
|
#define CD180TXirq 0x10 /* if non-0: enable TX irq */
|
||||||
|
#define RX_mask 0x12
|
||||||
|
#define TX_mask 0x14
|
||||||
|
#define Ofs_rxb 0x16
|
||||||
|
#define Ofs_txb 0x18
|
||||||
|
#define Page_rxb 0x1A
|
||||||
|
#define Page_txb 0x1C
|
||||||
|
#define EndPage_rxb 0x1E
|
||||||
|
#define EndPage_txb 0x20
|
||||||
|
#define Data_error 0x22
|
||||||
|
#define RxTrigger 0x28
|
||||||
|
#define TxTrigger 0x2a
|
||||||
|
|
||||||
|
#define rRXwptr 0x34
|
||||||
|
#define Low_water 0x36
|
||||||
|
|
||||||
|
#define FuncCode 0x40
|
||||||
|
#define FuncArg 0x42
|
||||||
|
#define FuncArg1 0x44
|
||||||
|
|
||||||
|
#define C218rx_size 0x2000 /* 8K bytes */
|
||||||
|
#define C218tx_size 0x8000 /* 32K bytes */
|
||||||
|
|
||||||
|
#define C218rx_mask (C218rx_size - 1)
|
||||||
|
#define C218tx_mask (C218tx_size - 1)
|
||||||
|
|
||||||
|
#define C320p8rx_size 0x2000
|
||||||
|
#define C320p8tx_size 0x8000
|
||||||
|
#define C320p8rx_mask (C320p8rx_size - 1)
|
||||||
|
#define C320p8tx_mask (C320p8tx_size - 1)
|
||||||
|
|
||||||
|
#define C320p16rx_size 0x2000
|
||||||
|
#define C320p16tx_size 0x4000
|
||||||
|
#define C320p16rx_mask (C320p16rx_size - 1)
|
||||||
|
#define C320p16tx_mask (C320p16tx_size - 1)
|
||||||
|
|
||||||
|
#define C320p24rx_size 0x2000
|
||||||
|
#define C320p24tx_size 0x2000
|
||||||
|
#define C320p24rx_mask (C320p24rx_size - 1)
|
||||||
|
#define C320p24tx_mask (C320p24tx_size - 1)
|
||||||
|
|
||||||
|
#define C320p32rx_size 0x1000
|
||||||
|
#define C320p32tx_size 0x1000
|
||||||
|
#define C320p32rx_mask (C320p32rx_size - 1)
|
||||||
|
#define C320p32tx_mask (C320p32tx_size - 1)
|
||||||
|
|
||||||
|
#define Page_size 0x2000U
|
||||||
|
#define Page_mask (Page_size - 1)
|
||||||
|
#define C218rx_spage 3
|
||||||
|
#define C218tx_spage 4
|
||||||
|
#define C218rx_pageno 1
|
||||||
|
#define C218tx_pageno 4
|
||||||
|
#define C218buf_pageno 5
|
||||||
|
|
||||||
|
#define C320p8rx_spage 3
|
||||||
|
#define C320p8tx_spage 4
|
||||||
|
#define C320p8rx_pgno 1
|
||||||
|
#define C320p8tx_pgno 4
|
||||||
|
#define C320p8buf_pgno 5
|
||||||
|
|
||||||
|
#define C320p16rx_spage 3
|
||||||
|
#define C320p16tx_spage 4
|
||||||
|
#define C320p16rx_pgno 1
|
||||||
|
#define C320p16tx_pgno 2
|
||||||
|
#define C320p16buf_pgno 3
|
||||||
|
|
||||||
|
#define C320p24rx_spage 3
|
||||||
|
#define C320p24tx_spage 4
|
||||||
|
#define C320p24rx_pgno 1
|
||||||
|
#define C320p24tx_pgno 1
|
||||||
|
#define C320p24buf_pgno 2
|
||||||
|
|
||||||
|
#define C320p32rx_spage 3
|
||||||
|
#define C320p32tx_ofs C320p32rx_size
|
||||||
|
#define C320p32tx_spage 3
|
||||||
|
#define C320p32buf_pgno 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Host Status
|
||||||
|
*/
|
||||||
|
#define WakeupRx 0x01
|
||||||
|
#define WakeupTx 0x02
|
||||||
|
#define WakeupBreak 0x08
|
||||||
|
#define WakeupLine 0x10
|
||||||
|
#define WakeupIntr 0x20
|
||||||
|
#define WakeupQuit 0x40
|
||||||
|
#define WakeupEOF 0x80 /* used in VTIME control */
|
||||||
|
#define WakeupRxTrigger 0x100
|
||||||
|
#define WakeupTxTrigger 0x200
|
||||||
|
/*
|
||||||
|
* Flag status
|
||||||
|
*/
|
||||||
|
#define Rx_over 0x01
|
||||||
|
#define Xoff_state 0x02
|
||||||
|
#define Tx_flowOff 0x04
|
||||||
|
#define Tx_enable 0x08
|
||||||
|
#define CTS_state 0x10
|
||||||
|
#define DSR_state 0x20
|
||||||
|
#define DCD_state 0x80
|
||||||
|
/*
|
||||||
|
* FlowControl
|
||||||
|
*/
|
||||||
|
#define CTS_FlowCtl 1
|
||||||
|
#define RTS_FlowCtl 2
|
||||||
|
#define Tx_FlowCtl 4
|
||||||
|
#define Rx_FlowCtl 8
|
||||||
|
#define IXM_IXANY 0x10
|
||||||
|
|
||||||
|
#define LowWater 128
|
||||||
|
|
||||||
|
#define DTR_ON 1
|
||||||
|
#define RTS_ON 2
|
||||||
|
#define CTS_ON 1
|
||||||
|
#define DSR_ON 2
|
||||||
|
#define DCD_ON 8
|
||||||
|
|
||||||
|
/* mode definition */
|
||||||
|
#define MX_CS8 0x03
|
||||||
|
#define MX_CS7 0x02
|
||||||
|
#define MX_CS6 0x01
|
||||||
|
#define MX_CS5 0x00
|
||||||
|
|
||||||
|
#define MX_STOP1 0x00
|
||||||
|
#define MX_STOP15 0x04
|
||||||
|
#define MX_STOP2 0x08
|
||||||
|
|
||||||
|
#define MX_PARNONE 0x00
|
||||||
|
#define MX_PAREVEN 0x40
|
||||||
|
#define MX_PARODD 0xC0
|
||||||
|
#define MX_PARMARK 0xA0
|
||||||
|
#define MX_PARSPACE 0x20
|
||||||
|
|
||||||
#define MOXA_VERSION "6.0k"
|
#define MOXA_VERSION "6.0k"
|
||||||
|
|
||||||
|
@ -1,307 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
|
||||||
#ifndef MOXA_H_FILE
|
|
||||||
#define MOXA_H_FILE
|
|
||||||
|
|
||||||
#define MOXA 0x400
|
|
||||||
#define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */
|
|
||||||
#define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */
|
|
||||||
#define MOXA_GETDATACOUNT (MOXA + 23)
|
|
||||||
#define MOXA_GET_IOQUEUE (MOXA + 27)
|
|
||||||
#define MOXA_FLUSH_QUEUE (MOXA + 28)
|
|
||||||
#define MOXA_GETMSTATUS (MOXA + 65)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* System Configuration
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define Magic_code 0x404
|
|
||||||
|
|
||||||
/*
|
|
||||||
* for C218 BIOS initialization
|
|
||||||
*/
|
|
||||||
#define C218_ConfBase 0x800
|
|
||||||
#define C218_status (C218_ConfBase + 0) /* BIOS running status */
|
|
||||||
#define C218_diag (C218_ConfBase + 2) /* diagnostic status */
|
|
||||||
#define C218_key (C218_ConfBase + 4) /* WORD (0x218 for C218) */
|
|
||||||
#define C218DLoad_len (C218_ConfBase + 6) /* WORD */
|
|
||||||
#define C218check_sum (C218_ConfBase + 8) /* BYTE */
|
|
||||||
#define C218chksum_ok (C218_ConfBase + 0x0a) /* BYTE (1:ok) */
|
|
||||||
#define C218_TestRx (C218_ConfBase + 0x10) /* 8 bytes for 8 ports */
|
|
||||||
#define C218_TestTx (C218_ConfBase + 0x18) /* 8 bytes for 8 ports */
|
|
||||||
#define C218_RXerr (C218_ConfBase + 0x20) /* 8 bytes for 8 ports */
|
|
||||||
#define C218_ErrFlag (C218_ConfBase + 0x28) /* 8 bytes for 8 ports */
|
|
||||||
|
|
||||||
#define C218_LoadBuf 0x0F00
|
|
||||||
#define C218_KeyCode 0x218
|
|
||||||
#define CP204J_KeyCode 0x204
|
|
||||||
|
|
||||||
/*
|
|
||||||
* for C320 BIOS initialization
|
|
||||||
*/
|
|
||||||
#define C320_ConfBase 0x800
|
|
||||||
#define C320_LoadBuf 0x0f00
|
|
||||||
#define STS_init 0x05 /* for C320_status */
|
|
||||||
|
|
||||||
#define C320_status C320_ConfBase + 0 /* BIOS running status */
|
|
||||||
#define C320_diag C320_ConfBase + 2 /* diagnostic status */
|
|
||||||
#define C320_key C320_ConfBase + 4 /* WORD (0320H for C320) */
|
|
||||||
#define C320DLoad_len C320_ConfBase + 6 /* WORD */
|
|
||||||
#define C320check_sum C320_ConfBase + 8 /* WORD */
|
|
||||||
#define C320chksum_ok C320_ConfBase + 0x0a /* WORD (1:ok) */
|
|
||||||
#define C320bapi_len C320_ConfBase + 0x0c /* WORD */
|
|
||||||
#define C320UART_no C320_ConfBase + 0x0e /* WORD */
|
|
||||||
|
|
||||||
#define C320_KeyCode 0x320
|
|
||||||
|
|
||||||
#define FixPage_addr 0x0000 /* starting addr of static page */
|
|
||||||
#define DynPage_addr 0x2000 /* starting addr of dynamic page */
|
|
||||||
#define C218_start 0x3000 /* starting addr of C218 BIOS prg */
|
|
||||||
#define Control_reg 0x1ff0 /* select page and reset control */
|
|
||||||
#define HW_reset 0x80
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function Codes
|
|
||||||
*/
|
|
||||||
#define FC_CardReset 0x80
|
|
||||||
#define FC_ChannelReset 1 /* C320 firmware not supported */
|
|
||||||
#define FC_EnableCH 2
|
|
||||||
#define FC_DisableCH 3
|
|
||||||
#define FC_SetParam 4
|
|
||||||
#define FC_SetMode 5
|
|
||||||
#define FC_SetRate 6
|
|
||||||
#define FC_LineControl 7
|
|
||||||
#define FC_LineStatus 8
|
|
||||||
#define FC_XmitControl 9
|
|
||||||
#define FC_FlushQueue 10
|
|
||||||
#define FC_SendBreak 11
|
|
||||||
#define FC_StopBreak 12
|
|
||||||
#define FC_LoopbackON 13
|
|
||||||
#define FC_LoopbackOFF 14
|
|
||||||
#define FC_ClrIrqTable 15
|
|
||||||
#define FC_SendXon 16
|
|
||||||
#define FC_SetTermIrq 17 /* C320 firmware not supported */
|
|
||||||
#define FC_SetCntIrq 18 /* C320 firmware not supported */
|
|
||||||
#define FC_SetBreakIrq 19
|
|
||||||
#define FC_SetLineIrq 20
|
|
||||||
#define FC_SetFlowCtl 21
|
|
||||||
#define FC_GenIrq 22
|
|
||||||
#define FC_InCD180 23
|
|
||||||
#define FC_OutCD180 24
|
|
||||||
#define FC_InUARTreg 23
|
|
||||||
#define FC_OutUARTreg 24
|
|
||||||
#define FC_SetXonXoff 25
|
|
||||||
#define FC_OutCD180CCR 26
|
|
||||||
#define FC_ExtIQueue 27
|
|
||||||
#define FC_ExtOQueue 28
|
|
||||||
#define FC_ClrLineIrq 29
|
|
||||||
#define FC_HWFlowCtl 30
|
|
||||||
#define FC_GetClockRate 35
|
|
||||||
#define FC_SetBaud 36
|
|
||||||
#define FC_SetDataMode 41
|
|
||||||
#define FC_GetCCSR 43
|
|
||||||
#define FC_GetDataError 45
|
|
||||||
#define FC_RxControl 50
|
|
||||||
#define FC_ImmSend 51
|
|
||||||
#define FC_SetXonState 52
|
|
||||||
#define FC_SetXoffState 53
|
|
||||||
#define FC_SetRxFIFOTrig 54
|
|
||||||
#define FC_SetTxFIFOCnt 55
|
|
||||||
#define FC_UnixRate 56
|
|
||||||
#define FC_UnixResetTimer 57
|
|
||||||
|
|
||||||
#define RxFIFOTrig1 0
|
|
||||||
#define RxFIFOTrig4 1
|
|
||||||
#define RxFIFOTrig8 2
|
|
||||||
#define RxFIFOTrig14 3
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dual-Ported RAM
|
|
||||||
*/
|
|
||||||
#define DRAM_global 0
|
|
||||||
#define INT_data (DRAM_global + 0)
|
|
||||||
#define Config_base (DRAM_global + 0x108)
|
|
||||||
|
|
||||||
#define IRQindex (INT_data + 0)
|
|
||||||
#define IRQpending (INT_data + 4)
|
|
||||||
#define IRQtable (INT_data + 8)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Interrupt Status
|
|
||||||
*/
|
|
||||||
#define IntrRx 0x01 /* receiver data O.K. */
|
|
||||||
#define IntrTx 0x02 /* transmit buffer empty */
|
|
||||||
#define IntrFunc 0x04 /* function complete */
|
|
||||||
#define IntrBreak 0x08 /* received break */
|
|
||||||
#define IntrLine 0x10 /* line status change
|
|
||||||
for transmitter */
|
|
||||||
#define IntrIntr 0x20 /* received INTR code */
|
|
||||||
#define IntrQuit 0x40 /* received QUIT code */
|
|
||||||
#define IntrEOF 0x80 /* received EOF code */
|
|
||||||
|
|
||||||
#define IntrRxTrigger 0x100 /* rx data count reach trigger value */
|
|
||||||
#define IntrTxTrigger 0x200 /* tx data count below trigger value */
|
|
||||||
|
|
||||||
#define Magic_no (Config_base + 0)
|
|
||||||
#define Card_model_no (Config_base + 2)
|
|
||||||
#define Total_ports (Config_base + 4)
|
|
||||||
#define Module_cnt (Config_base + 8)
|
|
||||||
#define Module_no (Config_base + 10)
|
|
||||||
#define Timer_10ms (Config_base + 14)
|
|
||||||
#define Disable_IRQ (Config_base + 20)
|
|
||||||
#define TMS320_PORT1 (Config_base + 22)
|
|
||||||
#define TMS320_PORT2 (Config_base + 24)
|
|
||||||
#define TMS320_CLOCK (Config_base + 26)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* DATA BUFFER in DRAM
|
|
||||||
*/
|
|
||||||
#define Extern_table 0x400 /* Base address of the external table
|
|
||||||
(24 words * 64) total 3K bytes
|
|
||||||
(24 words * 128) total 6K bytes */
|
|
||||||
#define Extern_size 0x60 /* 96 bytes */
|
|
||||||
#define RXrptr 0x00 /* read pointer for RX buffer */
|
|
||||||
#define RXwptr 0x02 /* write pointer for RX buffer */
|
|
||||||
#define TXrptr 0x04 /* read pointer for TX buffer */
|
|
||||||
#define TXwptr 0x06 /* write pointer for TX buffer */
|
|
||||||
#define HostStat 0x08 /* IRQ flag and general flag */
|
|
||||||
#define FlagStat 0x0A
|
|
||||||
#define FlowControl 0x0C /* B7 B6 B5 B4 B3 B2 B1 B0 */
|
|
||||||
/* x x x x | | | | */
|
|
||||||
/* | | | + CTS flow */
|
|
||||||
/* | | +--- RTS flow */
|
|
||||||
/* | +------ TX Xon/Xoff */
|
|
||||||
/* +--------- RX Xon/Xoff */
|
|
||||||
#define Break_cnt 0x0E /* received break count */
|
|
||||||
#define CD180TXirq 0x10 /* if non-0: enable TX irq */
|
|
||||||
#define RX_mask 0x12
|
|
||||||
#define TX_mask 0x14
|
|
||||||
#define Ofs_rxb 0x16
|
|
||||||
#define Ofs_txb 0x18
|
|
||||||
#define Page_rxb 0x1A
|
|
||||||
#define Page_txb 0x1C
|
|
||||||
#define EndPage_rxb 0x1E
|
|
||||||
#define EndPage_txb 0x20
|
|
||||||
#define Data_error 0x22
|
|
||||||
#define RxTrigger 0x28
|
|
||||||
#define TxTrigger 0x2a
|
|
||||||
|
|
||||||
#define rRXwptr 0x34
|
|
||||||
#define Low_water 0x36
|
|
||||||
|
|
||||||
#define FuncCode 0x40
|
|
||||||
#define FuncArg 0x42
|
|
||||||
#define FuncArg1 0x44
|
|
||||||
|
|
||||||
#define C218rx_size 0x2000 /* 8K bytes */
|
|
||||||
#define C218tx_size 0x8000 /* 32K bytes */
|
|
||||||
|
|
||||||
#define C218rx_mask (C218rx_size - 1)
|
|
||||||
#define C218tx_mask (C218tx_size - 1)
|
|
||||||
|
|
||||||
#define C320p8rx_size 0x2000
|
|
||||||
#define C320p8tx_size 0x8000
|
|
||||||
#define C320p8rx_mask (C320p8rx_size - 1)
|
|
||||||
#define C320p8tx_mask (C320p8tx_size - 1)
|
|
||||||
|
|
||||||
#define C320p16rx_size 0x2000
|
|
||||||
#define C320p16tx_size 0x4000
|
|
||||||
#define C320p16rx_mask (C320p16rx_size - 1)
|
|
||||||
#define C320p16tx_mask (C320p16tx_size - 1)
|
|
||||||
|
|
||||||
#define C320p24rx_size 0x2000
|
|
||||||
#define C320p24tx_size 0x2000
|
|
||||||
#define C320p24rx_mask (C320p24rx_size - 1)
|
|
||||||
#define C320p24tx_mask (C320p24tx_size - 1)
|
|
||||||
|
|
||||||
#define C320p32rx_size 0x1000
|
|
||||||
#define C320p32tx_size 0x1000
|
|
||||||
#define C320p32rx_mask (C320p32rx_size - 1)
|
|
||||||
#define C320p32tx_mask (C320p32tx_size - 1)
|
|
||||||
|
|
||||||
#define Page_size 0x2000U
|
|
||||||
#define Page_mask (Page_size - 1)
|
|
||||||
#define C218rx_spage 3
|
|
||||||
#define C218tx_spage 4
|
|
||||||
#define C218rx_pageno 1
|
|
||||||
#define C218tx_pageno 4
|
|
||||||
#define C218buf_pageno 5
|
|
||||||
|
|
||||||
#define C320p8rx_spage 3
|
|
||||||
#define C320p8tx_spage 4
|
|
||||||
#define C320p8rx_pgno 1
|
|
||||||
#define C320p8tx_pgno 4
|
|
||||||
#define C320p8buf_pgno 5
|
|
||||||
|
|
||||||
#define C320p16rx_spage 3
|
|
||||||
#define C320p16tx_spage 4
|
|
||||||
#define C320p16rx_pgno 1
|
|
||||||
#define C320p16tx_pgno 2
|
|
||||||
#define C320p16buf_pgno 3
|
|
||||||
|
|
||||||
#define C320p24rx_spage 3
|
|
||||||
#define C320p24tx_spage 4
|
|
||||||
#define C320p24rx_pgno 1
|
|
||||||
#define C320p24tx_pgno 1
|
|
||||||
#define C320p24buf_pgno 2
|
|
||||||
|
|
||||||
#define C320p32rx_spage 3
|
|
||||||
#define C320p32tx_ofs C320p32rx_size
|
|
||||||
#define C320p32tx_spage 3
|
|
||||||
#define C320p32buf_pgno 1
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Host Status
|
|
||||||
*/
|
|
||||||
#define WakeupRx 0x01
|
|
||||||
#define WakeupTx 0x02
|
|
||||||
#define WakeupBreak 0x08
|
|
||||||
#define WakeupLine 0x10
|
|
||||||
#define WakeupIntr 0x20
|
|
||||||
#define WakeupQuit 0x40
|
|
||||||
#define WakeupEOF 0x80 /* used in VTIME control */
|
|
||||||
#define WakeupRxTrigger 0x100
|
|
||||||
#define WakeupTxTrigger 0x200
|
|
||||||
/*
|
|
||||||
* Flag status
|
|
||||||
*/
|
|
||||||
#define Rx_over 0x01
|
|
||||||
#define Xoff_state 0x02
|
|
||||||
#define Tx_flowOff 0x04
|
|
||||||
#define Tx_enable 0x08
|
|
||||||
#define CTS_state 0x10
|
|
||||||
#define DSR_state 0x20
|
|
||||||
#define DCD_state 0x80
|
|
||||||
/*
|
|
||||||
* FlowControl
|
|
||||||
*/
|
|
||||||
#define CTS_FlowCtl 1
|
|
||||||
#define RTS_FlowCtl 2
|
|
||||||
#define Tx_FlowCtl 4
|
|
||||||
#define Rx_FlowCtl 8
|
|
||||||
#define IXM_IXANY 0x10
|
|
||||||
|
|
||||||
#define LowWater 128
|
|
||||||
|
|
||||||
#define DTR_ON 1
|
|
||||||
#define RTS_ON 2
|
|
||||||
#define CTS_ON 1
|
|
||||||
#define DSR_ON 2
|
|
||||||
#define DCD_ON 8
|
|
||||||
|
|
||||||
/* mode definition */
|
|
||||||
#define MX_CS8 0x03
|
|
||||||
#define MX_CS7 0x02
|
|
||||||
#define MX_CS6 0x01
|
|
||||||
#define MX_CS5 0x00
|
|
||||||
|
|
||||||
#define MX_STOP1 0x00
|
|
||||||
#define MX_STOP15 0x04
|
|
||||||
#define MX_STOP2 0x08
|
|
||||||
|
|
||||||
#define MX_PARNONE 0x00
|
|
||||||
#define MX_PAREVEN 0x40
|
|
||||||
#define MX_PARODD 0xC0
|
|
||||||
#define MX_PARMARK 0xA0
|
|
||||||
#define MX_PARSPACE 0x20
|
|
||||||
|
|
||||||
#endif
|
|
@ -249,8 +249,9 @@ struct mxser_port {
|
|||||||
unsigned char x_char; /* xon/xoff character */
|
unsigned char x_char; /* xon/xoff character */
|
||||||
u8 IER; /* Interrupt Enable Register */
|
u8 IER; /* Interrupt Enable Register */
|
||||||
u8 MCR; /* Modem control register */
|
u8 MCR; /* Modem control register */
|
||||||
|
u8 FCR; /* FIFO control register */
|
||||||
|
|
||||||
unsigned char ldisc_stop_rx;
|
bool ldisc_stop_rx;
|
||||||
|
|
||||||
struct async_icount icount; /* kernel counters for 4 input interrupts */
|
struct async_icount icount; /* kernel counters for 4 input interrupts */
|
||||||
unsigned int timeout;
|
unsigned int timeout;
|
||||||
@ -559,14 +560,20 @@ static void mxser_handle_cts(struct tty_struct *tty, struct mxser_port *info,
|
|||||||
* This routine is called to set the UART divisor registers to match
|
* This routine is called to set the UART divisor registers to match
|
||||||
* the specified baud rate for a serial port.
|
* the specified baud rate for a serial port.
|
||||||
*/
|
*/
|
||||||
static void mxser_change_speed(struct tty_struct *tty)
|
static void mxser_change_speed(struct tty_struct *tty, struct ktermios *old_termios)
|
||||||
{
|
{
|
||||||
struct mxser_port *info = tty->driver_data;
|
struct mxser_port *info = tty->driver_data;
|
||||||
unsigned cflag, cval, fcr;
|
unsigned cflag, cval;
|
||||||
|
|
||||||
cflag = tty->termios.c_cflag;
|
cflag = tty->termios.c_cflag;
|
||||||
|
|
||||||
mxser_set_baud(tty, tty_get_baud_rate(tty));
|
if (mxser_set_baud(tty, tty_get_baud_rate(tty))) {
|
||||||
|
/* Use previous rate on a failure */
|
||||||
|
if (old_termios) {
|
||||||
|
speed_t baud = tty_termios_baud_rate(old_termios);
|
||||||
|
tty_encode_baud_rate(tty, baud, baud);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* byte size and parity */
|
/* byte size and parity */
|
||||||
switch (cflag & CSIZE) {
|
switch (cflag & CSIZE) {
|
||||||
@ -594,33 +601,26 @@ static void mxser_change_speed(struct tty_struct *tty)
|
|||||||
if (cflag & CMSPAR)
|
if (cflag & CMSPAR)
|
||||||
cval |= UART_LCR_SPAR;
|
cval |= UART_LCR_SPAR;
|
||||||
|
|
||||||
if ((info->type == PORT_8250) || (info->type == PORT_16450)) {
|
info->FCR = 0;
|
||||||
if (info->board->must_hwid) {
|
if (info->board->must_hwid) {
|
||||||
fcr = UART_FCR_ENABLE_FIFO;
|
info->FCR |= UART_FCR_ENABLE_FIFO |
|
||||||
fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
|
MOXA_MUST_FCR_GDA_MODE_ENABLE;
|
||||||
mxser_set_must_fifo_value(info);
|
mxser_set_must_fifo_value(info);
|
||||||
} else
|
} else if (info->type != PORT_8250 && info->type != PORT_16450) {
|
||||||
fcr = 0;
|
info->FCR |= UART_FCR_ENABLE_FIFO;
|
||||||
} else {
|
switch (info->rx_high_water) {
|
||||||
fcr = UART_FCR_ENABLE_FIFO;
|
case 1:
|
||||||
if (info->board->must_hwid) {
|
info->FCR |= UART_FCR_TRIGGER_1;
|
||||||
fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
|
break;
|
||||||
mxser_set_must_fifo_value(info);
|
case 4:
|
||||||
} else {
|
info->FCR |= UART_FCR_TRIGGER_4;
|
||||||
switch (info->rx_high_water) {
|
break;
|
||||||
case 1:
|
case 8:
|
||||||
fcr |= UART_FCR_TRIGGER_1;
|
info->FCR |= UART_FCR_TRIGGER_8;
|
||||||
break;
|
break;
|
||||||
case 4:
|
default:
|
||||||
fcr |= UART_FCR_TRIGGER_4;
|
info->FCR |= UART_FCR_TRIGGER_14;
|
||||||
break;
|
break;
|
||||||
case 8:
|
|
||||||
fcr |= UART_FCR_TRIGGER_8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fcr |= UART_FCR_TRIGGER_14;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -680,7 +680,7 @@ static void mxser_change_speed(struct tty_struct *tty)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
outb(fcr, info->ioaddr + UART_FCR); /* set fcr */
|
outb(info->FCR, info->ioaddr + UART_FCR);
|
||||||
outb(cval, info->ioaddr + UART_LCR);
|
outb(cval, info->ioaddr + UART_LCR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -707,6 +707,16 @@ static void mxser_check_modem_status(struct tty_struct *tty,
|
|||||||
mxser_handle_cts(tty, port, status);
|
mxser_handle_cts(tty, port, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mxser_disable_and_clear_FIFO(struct mxser_port *info)
|
||||||
|
{
|
||||||
|
u8 fcr = UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;
|
||||||
|
|
||||||
|
if (info->board->must_hwid)
|
||||||
|
fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
|
||||||
|
|
||||||
|
outb(fcr, info->ioaddr + UART_FCR);
|
||||||
|
}
|
||||||
|
|
||||||
static int mxser_activate(struct tty_port *port, struct tty_struct *tty)
|
static int mxser_activate(struct tty_port *port, struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
struct mxser_port *info = container_of(port, struct mxser_port, port);
|
struct mxser_port *info = container_of(port, struct mxser_port, port);
|
||||||
@ -731,13 +741,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty)
|
|||||||
* Clear the FIFO buffers and disable them
|
* Clear the FIFO buffers and disable them
|
||||||
* (they will be reenabled in mxser_change_speed())
|
* (they will be reenabled in mxser_change_speed())
|
||||||
*/
|
*/
|
||||||
if (info->board->must_hwid)
|
mxser_disable_and_clear_FIFO(info);
|
||||||
outb((UART_FCR_CLEAR_RCVR |
|
|
||||||
UART_FCR_CLEAR_XMIT |
|
|
||||||
MOXA_MUST_FCR_GDA_MODE_ENABLE), info->ioaddr + UART_FCR);
|
|
||||||
else
|
|
||||||
outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
|
|
||||||
info->ioaddr + UART_FCR);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* At this point there's no way the LSR could still be 0xFF;
|
* At this point there's no way the LSR could still be 0xFF;
|
||||||
@ -791,7 +795,7 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty)
|
|||||||
/*
|
/*
|
||||||
* and set the speed of the serial port
|
* and set the speed of the serial port
|
||||||
*/
|
*/
|
||||||
mxser_change_speed(tty);
|
mxser_change_speed(tty, NULL);
|
||||||
spin_unlock_irqrestore(&info->slock, flags);
|
spin_unlock_irqrestore(&info->slock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -825,13 +829,7 @@ static void mxser_shutdown_port(struct tty_port *port)
|
|||||||
outb(0x00, info->ioaddr + UART_IER);
|
outb(0x00, info->ioaddr + UART_IER);
|
||||||
|
|
||||||
/* clear Rx/Tx FIFO's */
|
/* clear Rx/Tx FIFO's */
|
||||||
if (info->board->must_hwid)
|
mxser_disable_and_clear_FIFO(info);
|
||||||
outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
|
|
||||||
MOXA_MUST_FCR_GDA_MODE_ENABLE,
|
|
||||||
info->ioaddr + UART_FCR);
|
|
||||||
else
|
|
||||||
outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
|
|
||||||
info->ioaddr + UART_FCR);
|
|
||||||
|
|
||||||
/* read data port to reset things */
|
/* read data port to reset things */
|
||||||
(void) inb(info->ioaddr + UART_RX);
|
(void) inb(info->ioaddr + UART_RX);
|
||||||
@ -862,17 +860,14 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
|
|||||||
static void mxser_flush_buffer(struct tty_struct *tty)
|
static void mxser_flush_buffer(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
struct mxser_port *info = tty->driver_data;
|
struct mxser_port *info = tty->driver_data;
|
||||||
char fcr;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
|
||||||
spin_lock_irqsave(&info->slock, flags);
|
spin_lock_irqsave(&info->slock, flags);
|
||||||
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
|
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
|
||||||
|
|
||||||
fcr = inb(info->ioaddr + UART_FCR);
|
outb(info->FCR | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
|
||||||
outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
|
|
||||||
info->ioaddr + UART_FCR);
|
info->ioaddr + UART_FCR);
|
||||||
outb(fcr, info->ioaddr + UART_FCR);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&info->slock, flags);
|
spin_unlock_irqrestore(&info->slock, flags);
|
||||||
|
|
||||||
@ -1119,7 +1114,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
|
|||||||
if (tty_port_initialized(port)) {
|
if (tty_port_initialized(port)) {
|
||||||
if (old_speed != (port->flags & ASYNC_SPD_MASK)) {
|
if (old_speed != (port->flags & ASYNC_SPD_MASK)) {
|
||||||
spin_lock_irqsave(&info->slock, sl_flags);
|
spin_lock_irqsave(&info->slock, sl_flags);
|
||||||
mxser_change_speed(tty);
|
mxser_change_speed(tty, NULL);
|
||||||
spin_unlock_irqrestore(&info->slock, sl_flags);
|
spin_unlock_irqrestore(&info->slock, sl_flags);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1335,7 +1330,7 @@ static void mxser_stoprx(struct tty_struct *tty)
|
|||||||
{
|
{
|
||||||
struct mxser_port *info = tty->driver_data;
|
struct mxser_port *info = tty->driver_data;
|
||||||
|
|
||||||
info->ldisc_stop_rx = 1;
|
info->ldisc_stop_rx = true;
|
||||||
if (I_IXOFF(tty)) {
|
if (I_IXOFF(tty)) {
|
||||||
if (info->board->must_hwid) {
|
if (info->board->must_hwid) {
|
||||||
info->IER &= ~MOXA_MUST_RECV_ISR;
|
info->IER &= ~MOXA_MUST_RECV_ISR;
|
||||||
@ -1368,7 +1363,7 @@ static void mxser_unthrottle(struct tty_struct *tty)
|
|||||||
struct mxser_port *info = tty->driver_data;
|
struct mxser_port *info = tty->driver_data;
|
||||||
|
|
||||||
/* startrx */
|
/* startrx */
|
||||||
info->ldisc_stop_rx = 0;
|
info->ldisc_stop_rx = false;
|
||||||
if (I_IXOFF(tty)) {
|
if (I_IXOFF(tty)) {
|
||||||
if (info->x_char)
|
if (info->x_char)
|
||||||
info->x_char = 0;
|
info->x_char = 0;
|
||||||
@ -1425,7 +1420,7 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&info->slock, flags);
|
spin_lock_irqsave(&info->slock, flags);
|
||||||
mxser_change_speed(tty);
|
mxser_change_speed(tty, old_termios);
|
||||||
spin_unlock_irqrestore(&info->slock, flags);
|
spin_unlock_irqrestore(&info->slock, flags);
|
||||||
|
|
||||||
if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
|
if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
|
||||||
@ -1544,11 +1539,7 @@ static bool mxser_receive_chars_new(struct tty_struct *tty,
|
|||||||
|
|
||||||
if (hwid == MOXA_OTHER_UART)
|
if (hwid == MOXA_OTHER_UART)
|
||||||
return false;
|
return false;
|
||||||
if (status & UART_LSR_BRK_ERROR_BITS)
|
if (status & (UART_LSR_BRK_ERROR_BITS | MOXA_MUST_LSR_RERR))
|
||||||
return false;
|
|
||||||
if (hwid == MOXA_MUST_MU860_HWID && (status & MOXA_MUST_LSR_RERR))
|
|
||||||
return false;
|
|
||||||
if (status & MOXA_MUST_LSR_RERR)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
gdl = inb(port->ioaddr + MOXA_MUST_GDL_REGISTER);
|
gdl = inb(port->ioaddr + MOXA_MUST_GDL_REGISTER);
|
||||||
@ -1582,8 +1573,7 @@ static u8 mxser_receive_chars_old(struct tty_struct *tty,
|
|||||||
|
|
||||||
ch = inb(port->ioaddr + UART_RX);
|
ch = inb(port->ioaddr + UART_RX);
|
||||||
if (hwid && (status & UART_LSR_OE))
|
if (hwid && (status & UART_LSR_OE))
|
||||||
outb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
|
outb(port->FCR | UART_FCR_CLEAR_RCVR,
|
||||||
MOXA_MUST_FCR_GDA_MODE_ENABLE,
|
|
||||||
port->ioaddr + UART_FCR);
|
port->ioaddr + UART_FCR);
|
||||||
status &= port->read_status_mask;
|
status &= port->read_status_mask;
|
||||||
if (status & port->ignore_status_mask) {
|
if (status & port->ignore_status_mask) {
|
||||||
@ -1695,8 +1685,7 @@ static bool mxser_port_isr(struct mxser_port *port)
|
|||||||
tty = tty_port_tty_get(&port->port);
|
tty = tty_port_tty_get(&port->port);
|
||||||
if (!tty || port->closing || !tty_port_initialized(&port->port)) {
|
if (!tty || port->closing || !tty_port_initialized(&port->port)) {
|
||||||
status = inb(port->ioaddr + UART_LSR);
|
status = inb(port->ioaddr + UART_LSR);
|
||||||
outb(MOXA_MUST_FCR_GDA_MODE_ENABLE | UART_FCR_ENABLE_FIFO |
|
outb(port->FCR | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
|
||||||
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
|
|
||||||
port->ioaddr + UART_FCR);
|
port->ioaddr + UART_FCR);
|
||||||
inb(port->ioaddr + UART_MSR);
|
inb(port->ioaddr + UART_MSR);
|
||||||
|
|
||||||
@ -1847,7 +1836,7 @@ static void mxser_initbrd(struct mxser_board *brd, bool high_baud)
|
|||||||
tty_port_init(&info->port);
|
tty_port_init(&info->port);
|
||||||
info->port.ops = &mxser_port_ops;
|
info->port.ops = &mxser_port_ops;
|
||||||
info->board = brd;
|
info->board = brd;
|
||||||
info->ldisc_stop_rx = 0;
|
info->ldisc_stop_rx = false;
|
||||||
|
|
||||||
/* Enhance mode enabled here */
|
/* Enhance mode enabled here */
|
||||||
if (brd->must_hwid != MOXA_OTHER_UART)
|
if (brd->must_hwid != MOXA_OTHER_UART)
|
||||||
|
@ -271,6 +271,10 @@ static DEFINE_SPINLOCK(gsm_mux_lock);
|
|||||||
|
|
||||||
static struct tty_driver *gsm_tty_driver;
|
static struct tty_driver *gsm_tty_driver;
|
||||||
|
|
||||||
|
/* Save dlci open address */
|
||||||
|
static int addr_open[256] = { 0 };
|
||||||
|
/* Save dlci open count */
|
||||||
|
static int addr_cnt;
|
||||||
/*
|
/*
|
||||||
* This section of the driver logic implements the GSM encodings
|
* This section of the driver logic implements the GSM encodings
|
||||||
* both the basic and the 'advanced'. Reliable transport is not
|
* both the basic and the 'advanced'. Reliable transport is not
|
||||||
@ -587,6 +591,10 @@ static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
gsmld_output(gsm, cbuf, len);
|
gsmld_output(gsm, cbuf, len);
|
||||||
|
if (!gsm->initiator) {
|
||||||
|
cr = cr & gsm->initiator;
|
||||||
|
control = control & ~PF;
|
||||||
|
}
|
||||||
gsm_print_packet("-->", addr, cr, control, NULL, 0);
|
gsm_print_packet("-->", addr, cr, control, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -601,7 +609,7 @@ static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
|
|||||||
|
|
||||||
static inline void gsm_response(struct gsm_mux *gsm, int addr, int control)
|
static inline void gsm_response(struct gsm_mux *gsm, int addr, int control)
|
||||||
{
|
{
|
||||||
gsm_send(gsm, addr, 0, control);
|
gsm_send(gsm, addr, 1, control);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -687,7 +695,7 @@ static void gsm_data_kick(struct gsm_mux *gsm, struct gsm_dlci *dlci)
|
|||||||
print_hex_dump_bytes("gsm_data_kick: ",
|
print_hex_dump_bytes("gsm_data_kick: ",
|
||||||
DUMP_PREFIX_OFFSET,
|
DUMP_PREFIX_OFFSET,
|
||||||
gsm->txframe, len);
|
gsm->txframe, len);
|
||||||
if (gsmld_output(gsm, gsm->txframe, len) < 0)
|
if (gsmld_output(gsm, gsm->txframe, len) <= 0)
|
||||||
break;
|
break;
|
||||||
/* FIXME: Can eliminate one SOF in many more cases */
|
/* FIXME: Can eliminate one SOF in many more cases */
|
||||||
gsm->tx_bytes -= msg->len;
|
gsm->tx_bytes -= msg->len;
|
||||||
@ -1177,6 +1185,7 @@ static void gsm_control_rls(struct gsm_mux *gsm, const u8 *data, int clen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void gsm_dlci_begin_close(struct gsm_dlci *dlci);
|
static void gsm_dlci_begin_close(struct gsm_dlci *dlci);
|
||||||
|
static void gsm_dlci_close(struct gsm_dlci *dlci);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gsm_control_message - DLCI 0 control processing
|
* gsm_control_message - DLCI 0 control processing
|
||||||
@ -1195,15 +1204,28 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
|
|||||||
{
|
{
|
||||||
u8 buf[1];
|
u8 buf[1];
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
struct gsm_dlci *dlci;
|
||||||
|
int i;
|
||||||
|
int address;
|
||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case CMD_CLD: {
|
case CMD_CLD: {
|
||||||
struct gsm_dlci *dlci = gsm->dlci[0];
|
if (addr_cnt > 0) {
|
||||||
|
for (i = 0; i < addr_cnt; i++) {
|
||||||
|
address = addr_open[i];
|
||||||
|
dlci = gsm->dlci[address];
|
||||||
|
gsm_dlci_close(dlci);
|
||||||
|
addr_open[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* Modem wishes to close down */
|
/* Modem wishes to close down */
|
||||||
|
dlci = gsm->dlci[0];
|
||||||
if (dlci) {
|
if (dlci) {
|
||||||
dlci->dead = true;
|
dlci->dead = true;
|
||||||
gsm->dead = true;
|
gsm->dead = true;
|
||||||
gsm_dlci_begin_close(dlci);
|
gsm_dlci_close(dlci);
|
||||||
|
addr_cnt = 0;
|
||||||
|
gsm_response(gsm, 0, UA|PF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1429,6 +1451,8 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
|
|||||||
kfifo_reset(&dlci->fifo);
|
kfifo_reset(&dlci->fifo);
|
||||||
} else
|
} else
|
||||||
dlci->gsm->dead = true;
|
dlci->gsm->dead = true;
|
||||||
|
/* Unregister gsmtty driver,report gsmtty dev remove uevent for user */
|
||||||
|
tty_unregister_device(gsm_tty_driver, dlci->addr);
|
||||||
wake_up(&dlci->gsm->event);
|
wake_up(&dlci->gsm->event);
|
||||||
/* A DLCI 0 close is a MUX termination so we need to kick that
|
/* A DLCI 0 close is a MUX termination so we need to kick that
|
||||||
back to userspace somehow */
|
back to userspace somehow */
|
||||||
@ -1450,6 +1474,8 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
|
|||||||
dlci->state = DLCI_OPEN;
|
dlci->state = DLCI_OPEN;
|
||||||
if (debug & 8)
|
if (debug & 8)
|
||||||
pr_debug("DLCI %d goes open.\n", dlci->addr);
|
pr_debug("DLCI %d goes open.\n", dlci->addr);
|
||||||
|
/* Register gsmtty driver,report gsmtty dev add uevent for user */
|
||||||
|
tty_register_device(gsm_tty_driver, dlci->addr, NULL);
|
||||||
wake_up(&dlci->gsm->event);
|
wake_up(&dlci->gsm->event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1748,6 +1774,7 @@ static void gsm_queue(struct gsm_mux *gsm)
|
|||||||
struct gsm_dlci *dlci;
|
struct gsm_dlci *dlci;
|
||||||
u8 cr;
|
u8 cr;
|
||||||
int address;
|
int address;
|
||||||
|
int i, j, k, address_tmp;
|
||||||
/* We have to sneak a look at the packet body to do the FCS.
|
/* We have to sneak a look at the packet body to do the FCS.
|
||||||
A somewhat layering violation in the spec */
|
A somewhat layering violation in the spec */
|
||||||
|
|
||||||
@ -1779,29 +1806,59 @@ static void gsm_queue(struct gsm_mux *gsm)
|
|||||||
|
|
||||||
switch (gsm->control) {
|
switch (gsm->control) {
|
||||||
case SABM|PF:
|
case SABM|PF:
|
||||||
if (cr == 0)
|
if (cr == 1)
|
||||||
goto invalid;
|
goto invalid;
|
||||||
if (dlci == NULL)
|
if (dlci == NULL)
|
||||||
dlci = gsm_dlci_alloc(gsm, address);
|
dlci = gsm_dlci_alloc(gsm, address);
|
||||||
if (dlci == NULL)
|
if (dlci == NULL)
|
||||||
return;
|
return;
|
||||||
if (dlci->dead)
|
if (dlci->dead)
|
||||||
gsm_response(gsm, address, DM);
|
gsm_response(gsm, address, DM|PF);
|
||||||
else {
|
else {
|
||||||
gsm_response(gsm, address, UA);
|
gsm_response(gsm, address, UA|PF);
|
||||||
gsm_dlci_open(dlci);
|
gsm_dlci_open(dlci);
|
||||||
|
/* Save dlci open address */
|
||||||
|
if (address) {
|
||||||
|
addr_open[addr_cnt] = address;
|
||||||
|
addr_cnt++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DISC|PF:
|
case DISC|PF:
|
||||||
if (cr == 0)
|
if (cr == 1)
|
||||||
goto invalid;
|
goto invalid;
|
||||||
if (dlci == NULL || dlci->state == DLCI_CLOSED) {
|
if (dlci == NULL || dlci->state == DLCI_CLOSED) {
|
||||||
gsm_response(gsm, address, DM);
|
gsm_response(gsm, address, DM|PF);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Real close complete */
|
/* Real close complete */
|
||||||
gsm_response(gsm, address, UA);
|
if (!address) {
|
||||||
gsm_dlci_close(dlci);
|
if (addr_cnt > 0) {
|
||||||
|
for (i = 0; i < addr_cnt; i++) {
|
||||||
|
address = addr_open[i];
|
||||||
|
dlci = gsm->dlci[address];
|
||||||
|
gsm_dlci_close(dlci);
|
||||||
|
addr_open[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dlci = gsm->dlci[0];
|
||||||
|
gsm_dlci_close(dlci);
|
||||||
|
addr_cnt = 0;
|
||||||
|
gsm_response(gsm, 0, UA|PF);
|
||||||
|
} else {
|
||||||
|
gsm_response(gsm, address, UA|PF);
|
||||||
|
gsm_dlci_close(dlci);
|
||||||
|
/* clear dlci address */
|
||||||
|
for (j = 0; j < addr_cnt; j++) {
|
||||||
|
address_tmp = addr_open[j];
|
||||||
|
if (address_tmp == address) {
|
||||||
|
for (k = j; k < addr_cnt; k++)
|
||||||
|
addr_open[k] = addr_open[k+1];
|
||||||
|
addr_cnt--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case UA:
|
case UA:
|
||||||
case UA|PF:
|
case UA|PF:
|
||||||
@ -2300,7 +2357,7 @@ static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c)
|
|||||||
* configuration
|
* configuration
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (need_close || need_restart) {
|
if (gsm->initiator && (need_close || need_restart)) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = gsm_disconnect(gsm);
|
ret = gsm_disconnect(gsm);
|
||||||
@ -2358,8 +2415,7 @@ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len)
|
|||||||
if (debug & 4)
|
if (debug & 4)
|
||||||
print_hex_dump_bytes("gsmld_output: ", DUMP_PREFIX_OFFSET,
|
print_hex_dump_bytes("gsmld_output: ", DUMP_PREFIX_OFFSET,
|
||||||
data, len);
|
data, len);
|
||||||
gsm->tty->ops->write(gsm->tty, data, len);
|
return gsm->tty->ops->write(gsm->tty, data, len);
|
||||||
return len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2384,17 +2440,19 @@ static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
|
|||||||
else {
|
else {
|
||||||
/* Don't register device 0 - this is the control channel and not
|
/* Don't register device 0 - this is the control channel and not
|
||||||
a usable tty interface */
|
a usable tty interface */
|
||||||
base = mux_num_to_base(gsm); /* Base for this MUX */
|
if (gsm->initiator) {
|
||||||
for (i = 1; i < NUM_DLCI; i++) {
|
base = mux_num_to_base(gsm); /* Base for this MUX */
|
||||||
struct device *dev;
|
for (i = 1; i < NUM_DLCI; i++) {
|
||||||
|
struct device *dev;
|
||||||
|
|
||||||
dev = tty_register_device(gsm_tty_driver,
|
dev = tty_register_device(gsm_tty_driver,
|
||||||
base + i, NULL);
|
base + i, NULL);
|
||||||
if (IS_ERR(dev)) {
|
if (IS_ERR(dev)) {
|
||||||
for (i--; i >= 1; i--)
|
for (i--; i >= 1; i--)
|
||||||
tty_unregister_device(gsm_tty_driver,
|
tty_unregister_device(gsm_tty_driver,
|
||||||
base + i);
|
base + i);
|
||||||
return PTR_ERR(dev);
|
return PTR_ERR(dev);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2416,8 +2474,10 @@ static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
WARN_ON(tty != gsm->tty);
|
WARN_ON(tty != gsm->tty);
|
||||||
for (i = 1; i < NUM_DLCI; i++)
|
if (gsm->initiator) {
|
||||||
tty_unregister_device(gsm_tty_driver, base + i);
|
for (i = 1; i < NUM_DLCI; i++)
|
||||||
|
tty_unregister_device(gsm_tty_driver, base + i);
|
||||||
|
}
|
||||||
gsm_cleanup_mux(gsm);
|
gsm_cleanup_mux(gsm);
|
||||||
tty_kref_put(gsm->tty);
|
tty_kref_put(gsm->tty);
|
||||||
gsm->tty = NULL;
|
gsm->tty = NULL;
|
||||||
@ -2651,7 +2711,7 @@ static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
|
|||||||
base = mux_num_to_base(gsm);
|
base = mux_num_to_base(gsm);
|
||||||
return put_user(base + 1, (__u32 __user *)arg);
|
return put_user(base + 1, (__u32 __user *)arg);
|
||||||
default:
|
default:
|
||||||
return n_tty_ioctl_helper(tty, file, cmd, arg);
|
return n_tty_ioctl_helper(tty, cmd, arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3000,6 +3060,7 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)
|
|||||||
{
|
{
|
||||||
struct gsm_dlci *dlci = tty->driver_data;
|
struct gsm_dlci *dlci = tty->driver_data;
|
||||||
struct tty_port *port = &dlci->port;
|
struct tty_port *port = &dlci->port;
|
||||||
|
struct gsm_mux *gsm = dlci->gsm;
|
||||||
|
|
||||||
port->count++;
|
port->count++;
|
||||||
tty_port_tty_set(port, tty);
|
tty_port_tty_set(port, tty);
|
||||||
@ -3009,7 +3070,8 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)
|
|||||||
a DM straight back. This is ok as that will have caused a hangup */
|
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, 1);
|
||||||
/* Start sending off SABM messages */
|
/* Start sending off SABM messages */
|
||||||
gsm_dlci_begin_open(dlci);
|
if (gsm->initiator)
|
||||||
|
gsm_dlci_begin_open(dlci);
|
||||||
/* And wait for virtual carrier */
|
/* And wait for virtual carrier */
|
||||||
return tty_port_block_til_ready(port, tty, filp);
|
return tty_port_block_til_ready(port, tty, filp);
|
||||||
}
|
}
|
||||||
|
@ -630,7 +630,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
|
|||||||
fallthrough; /* to default */
|
fallthrough; /* to default */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
error = n_tty_ioctl_helper(tty, file, cmd, arg);
|
error = n_tty_ioctl_helper(tty, cmd, arg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
|
@ -2418,7 +2418,7 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
|
|||||||
up_write(&tty->termios_rwsem);
|
up_write(&tty->termios_rwsem);
|
||||||
return put_user(retval, (unsigned int __user *) arg);
|
return put_user(retval, (unsigned int __user *) arg);
|
||||||
default:
|
default:
|
||||||
return n_tty_ioctl_helper(tty, file, cmd, arg);
|
return n_tty_ioctl_helper(tty, cmd, arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2450,7 +2450,6 @@ void n_tty_inherit_ops(struct tty_ldisc_ops *ops)
|
|||||||
{
|
{
|
||||||
*ops = n_tty_ops;
|
*ops = n_tty_ops;
|
||||||
ops->owner = NULL;
|
ops->owner = NULL;
|
||||||
ops->flags = 0;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(n_tty_inherit_ops);
|
EXPORT_SYMBOL_GPL(n_tty_inherit_ops);
|
||||||
|
|
||||||
|
275
drivers/tty/rpmsg_tty.c
Normal file
275
drivers/tty/rpmsg_tty.c
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2021 STMicroelectronics - All Rights Reserved
|
||||||
|
*
|
||||||
|
* The rpmsg tty driver implements serial communication on the RPMsg bus to makes
|
||||||
|
* possible for user-space programs to send and receive rpmsg messages as a standard
|
||||||
|
* tty protocol.
|
||||||
|
*
|
||||||
|
* The remote processor can instantiate a new tty by requesting a "rpmsg-tty" RPMsg service.
|
||||||
|
* The "rpmsg-tty" service is directly used for data exchange. No flow control is implemented yet.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/rpmsg.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/tty.h>
|
||||||
|
#include <linux/tty_flip.h>
|
||||||
|
|
||||||
|
#define RPMSG_TTY_NAME "ttyRPMSG"
|
||||||
|
#define MAX_TTY_RPMSG 32
|
||||||
|
|
||||||
|
static DEFINE_IDR(tty_idr); /* tty instance id */
|
||||||
|
static DEFINE_MUTEX(idr_lock); /* protects tty_idr */
|
||||||
|
|
||||||
|
static struct tty_driver *rpmsg_tty_driver;
|
||||||
|
|
||||||
|
struct rpmsg_tty_port {
|
||||||
|
struct tty_port port; /* TTY port data */
|
||||||
|
int id; /* TTY rpmsg index */
|
||||||
|
struct rpmsg_device *rpdev; /* rpmsg device */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int rpmsg_tty_cb(struct rpmsg_device *rpdev, void *data, int len, void *priv, u32 src)
|
||||||
|
{
|
||||||
|
struct rpmsg_tty_port *cport = dev_get_drvdata(&rpdev->dev);
|
||||||
|
int copied;
|
||||||
|
|
||||||
|
if (!len)
|
||||||
|
return -EINVAL;
|
||||||
|
copied = tty_insert_flip_string(&cport->port, data, len);
|
||||||
|
if (copied != len)
|
||||||
|
dev_err_ratelimited(&rpdev->dev, "Trunc buffer: available space is %d\n", copied);
|
||||||
|
tty_flip_buffer_push(&cport->port);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rpmsg_tty_install(struct tty_driver *driver, struct tty_struct *tty)
|
||||||
|
{
|
||||||
|
struct rpmsg_tty_port *cport = idr_find(&tty_idr, tty->index);
|
||||||
|
|
||||||
|
tty->driver_data = cport;
|
||||||
|
|
||||||
|
return tty_port_install(&cport->port, driver, tty);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rpmsg_tty_open(struct tty_struct *tty, struct file *filp)
|
||||||
|
{
|
||||||
|
return tty_port_open(tty->port, tty, filp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rpmsg_tty_close(struct tty_struct *tty, struct file *filp)
|
||||||
|
{
|
||||||
|
return tty_port_close(tty->port, tty, filp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rpmsg_tty_write(struct tty_struct *tty, const u8 *buf, int len)
|
||||||
|
{
|
||||||
|
struct rpmsg_tty_port *cport = tty->driver_data;
|
||||||
|
struct rpmsg_device *rpdev;
|
||||||
|
int msg_max_size, msg_size;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
rpdev = cport->rpdev;
|
||||||
|
|
||||||
|
msg_max_size = rpmsg_get_mtu(rpdev->ept);
|
||||||
|
if (msg_max_size < 0)
|
||||||
|
return msg_max_size;
|
||||||
|
|
||||||
|
msg_size = min(len, msg_max_size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use rpmsg_trysend instead of rpmsg_send to send the message so the caller is not
|
||||||
|
* hung until a rpmsg buffer is available. In such case rpmsg_trysend returns -ENOMEM.
|
||||||
|
*/
|
||||||
|
ret = rpmsg_trysend(rpdev->ept, (void *)buf, msg_size);
|
||||||
|
if (ret) {
|
||||||
|
dev_dbg_ratelimited(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int rpmsg_tty_write_room(struct tty_struct *tty)
|
||||||
|
{
|
||||||
|
struct rpmsg_tty_port *cport = tty->driver_data;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
size = rpmsg_get_mtu(cport->rpdev->ept);
|
||||||
|
if (size < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct tty_operations rpmsg_tty_ops = {
|
||||||
|
.install = rpmsg_tty_install,
|
||||||
|
.open = rpmsg_tty_open,
|
||||||
|
.close = rpmsg_tty_close,
|
||||||
|
.write = rpmsg_tty_write,
|
||||||
|
.write_room = rpmsg_tty_write_room,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct rpmsg_tty_port *rpmsg_tty_alloc_cport(void)
|
||||||
|
{
|
||||||
|
struct rpmsg_tty_port *cport;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
cport = kzalloc(sizeof(*cport), GFP_KERNEL);
|
||||||
|
if (!cport)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
mutex_lock(&idr_lock);
|
||||||
|
ret = idr_alloc(&tty_idr, cport, 0, MAX_TTY_RPMSG, GFP_KERNEL);
|
||||||
|
mutex_unlock(&idr_lock);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
kfree(cport);
|
||||||
|
return ERR_PTR(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
cport->id = ret;
|
||||||
|
|
||||||
|
return cport;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rpmsg_tty_release_cport(struct rpmsg_tty_port *cport)
|
||||||
|
{
|
||||||
|
mutex_lock(&idr_lock);
|
||||||
|
idr_remove(&tty_idr, cport->id);
|
||||||
|
mutex_unlock(&idr_lock);
|
||||||
|
|
||||||
|
kfree(cport);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct tty_port_operations rpmsg_tty_port_ops = { };
|
||||||
|
|
||||||
|
static int rpmsg_tty_probe(struct rpmsg_device *rpdev)
|
||||||
|
{
|
||||||
|
struct rpmsg_tty_port *cport;
|
||||||
|
struct device *dev = &rpdev->dev;
|
||||||
|
struct device *tty_dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
cport = rpmsg_tty_alloc_cport();
|
||||||
|
if (IS_ERR(cport))
|
||||||
|
return dev_err_probe(dev, PTR_ERR(cport), "Failed to alloc tty port\n");
|
||||||
|
|
||||||
|
tty_port_init(&cport->port);
|
||||||
|
cport->port.ops = &rpmsg_tty_port_ops;
|
||||||
|
|
||||||
|
tty_dev = tty_port_register_device(&cport->port, rpmsg_tty_driver,
|
||||||
|
cport->id, dev);
|
||||||
|
if (IS_ERR(tty_dev)) {
|
||||||
|
ret = dev_err_probe(dev, PTR_ERR(tty_dev), "Failed to register tty port\n");
|
||||||
|
goto err_destroy;
|
||||||
|
}
|
||||||
|
|
||||||
|
cport->rpdev = rpdev;
|
||||||
|
|
||||||
|
dev_set_drvdata(dev, cport);
|
||||||
|
|
||||||
|
dev_dbg(dev, "New channel: 0x%x -> 0x%x: " RPMSG_TTY_NAME "%d\n",
|
||||||
|
rpdev->src, rpdev->dst, cport->id);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_destroy:
|
||||||
|
tty_port_destroy(&cport->port);
|
||||||
|
rpmsg_tty_release_cport(cport);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rpmsg_tty_remove(struct rpmsg_device *rpdev)
|
||||||
|
{
|
||||||
|
struct rpmsg_tty_port *cport = dev_get_drvdata(&rpdev->dev);
|
||||||
|
|
||||||
|
dev_dbg(&rpdev->dev, "Removing rpmsg tty device %d\n", cport->id);
|
||||||
|
|
||||||
|
/* User hang up to release the tty */
|
||||||
|
if (tty_port_initialized(&cport->port))
|
||||||
|
tty_port_tty_hangup(&cport->port, false);
|
||||||
|
|
||||||
|
tty_unregister_device(rpmsg_tty_driver, cport->id);
|
||||||
|
|
||||||
|
tty_port_destroy(&cport->port);
|
||||||
|
rpmsg_tty_release_cport(cport);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct rpmsg_device_id rpmsg_driver_tty_id_table[] = {
|
||||||
|
{ .name = "rpmsg-tty" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_tty_id_table);
|
||||||
|
|
||||||
|
static struct rpmsg_driver rpmsg_tty_rpmsg_drv = {
|
||||||
|
.drv.name = KBUILD_MODNAME,
|
||||||
|
.id_table = rpmsg_driver_tty_id_table,
|
||||||
|
.probe = rpmsg_tty_probe,
|
||||||
|
.callback = rpmsg_tty_cb,
|
||||||
|
.remove = rpmsg_tty_remove,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init rpmsg_tty_init(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
rpmsg_tty_driver = tty_alloc_driver(MAX_TTY_RPMSG, TTY_DRIVER_REAL_RAW |
|
||||||
|
TTY_DRIVER_DYNAMIC_DEV);
|
||||||
|
if (IS_ERR(rpmsg_tty_driver))
|
||||||
|
return PTR_ERR(rpmsg_tty_driver);
|
||||||
|
|
||||||
|
rpmsg_tty_driver->driver_name = "rpmsg_tty";
|
||||||
|
rpmsg_tty_driver->name = RPMSG_TTY_NAME;
|
||||||
|
rpmsg_tty_driver->major = 0;
|
||||||
|
rpmsg_tty_driver->type = TTY_DRIVER_TYPE_CONSOLE;
|
||||||
|
|
||||||
|
/* Disable unused mode by default */
|
||||||
|
rpmsg_tty_driver->init_termios = tty_std_termios;
|
||||||
|
rpmsg_tty_driver->init_termios.c_lflag &= ~(ECHO | ICANON);
|
||||||
|
rpmsg_tty_driver->init_termios.c_oflag &= ~(OPOST | ONLCR);
|
||||||
|
|
||||||
|
tty_set_operations(rpmsg_tty_driver, &rpmsg_tty_ops);
|
||||||
|
|
||||||
|
ret = tty_register_driver(rpmsg_tty_driver);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_err("Couldn't install driver: %d\n", ret);
|
||||||
|
goto error_put;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = register_rpmsg_driver(&rpmsg_tty_rpmsg_drv);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_err("Couldn't register driver: %d\n", ret);
|
||||||
|
goto error_unregister;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_unregister:
|
||||||
|
tty_unregister_driver(rpmsg_tty_driver);
|
||||||
|
|
||||||
|
error_put:
|
||||||
|
tty_driver_kref_put(rpmsg_tty_driver);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit rpmsg_tty_exit(void)
|
||||||
|
{
|
||||||
|
unregister_rpmsg_driver(&rpmsg_tty_rpmsg_drv);
|
||||||
|
tty_unregister_driver(rpmsg_tty_driver);
|
||||||
|
tty_driver_kref_put(rpmsg_tty_driver);
|
||||||
|
idr_destroy(&tty_idr);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(rpmsg_tty_init);
|
||||||
|
module_exit(rpmsg_tty_exit);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>");
|
||||||
|
MODULE_DESCRIPTION("remote processor messaging tty driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
@ -338,23 +338,16 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
|
|||||||
rate = clk_round_rate(d->clk, newrate);
|
rate = clk_round_rate(d->clk, newrate);
|
||||||
if (rate > 0) {
|
if (rate > 0) {
|
||||||
/*
|
/*
|
||||||
* Premilinary set the uartclk to the new clock rate so the
|
* Note that any clock-notifer worker will block in
|
||||||
* clock update event handler caused by the clk_set_rate()
|
* serial8250_update_uartclk() until we are done.
|
||||||
* calling wouldn't actually update the UART divisor since
|
|
||||||
* we about to do this anyway.
|
|
||||||
*/
|
*/
|
||||||
swap(p->uartclk, rate);
|
|
||||||
ret = clk_set_rate(d->clk, newrate);
|
ret = clk_set_rate(d->clk, newrate);
|
||||||
if (ret)
|
if (!ret)
|
||||||
swap(p->uartclk, rate);
|
p->uartclk = rate;
|
||||||
}
|
}
|
||||||
clk_prepare_enable(d->clk);
|
clk_prepare_enable(d->clk);
|
||||||
|
|
||||||
p->status &= ~UPSTAT_AUTOCTS;
|
dw8250_do_set_termios(p, termios, old);
|
||||||
if (termios->c_cflag & CRTSCTS)
|
|
||||||
p->status |= UPSTAT_AUTOCTS;
|
|
||||||
|
|
||||||
serial8250_do_set_termios(p, termios, old);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios)
|
static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios)
|
||||||
@ -393,8 +386,9 @@ static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
|
|||||||
|
|
||||||
static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
|
static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
|
||||||
{
|
{
|
||||||
if (p->dev->of_node) {
|
struct device_node *np = p->dev->of_node;
|
||||||
struct device_node *np = p->dev->of_node;
|
|
||||||
|
if (np) {
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
/* get index of serial line, if found in DT aliases */
|
/* get index of serial line, if found in DT aliases */
|
||||||
@ -411,11 +405,13 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
|
|||||||
data->skip_autocfg = true;
|
data->skip_autocfg = true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (of_device_is_big_endian(p->dev->of_node)) {
|
|
||||||
|
if (of_device_is_big_endian(np)) {
|
||||||
p->iotype = UPIO_MEM32BE;
|
p->iotype = UPIO_MEM32BE;
|
||||||
p->serial_in = dw8250_serial_in32be;
|
p->serial_in = dw8250_serial_in32be;
|
||||||
p->serial_out = dw8250_serial_out32be;
|
p->serial_out = dw8250_serial_out32be;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (of_device_is_compatible(np, "marvell,armada-38x-uart"))
|
if (of_device_is_compatible(np, "marvell,armada-38x-uart"))
|
||||||
p->serial_out = dw8250_serial_out38x;
|
p->serial_out = dw8250_serial_out38x;
|
||||||
|
|
||||||
@ -726,7 +722,7 @@ static struct platform_driver dw8250_platform_driver = {
|
|||||||
.name = "dw-apb-uart",
|
.name = "dw-apb-uart",
|
||||||
.pm = &dw8250_pm_ops,
|
.pm = &dw8250_pm_ops,
|
||||||
.of_match_table = dw8250_of_match,
|
.of_match_table = dw8250_of_match,
|
||||||
.acpi_match_table = ACPI_PTR(dw8250_acpi_match),
|
.acpi_match_table = dw8250_acpi_match,
|
||||||
},
|
},
|
||||||
.probe = dw8250_probe,
|
.probe = dw8250_probe,
|
||||||
.remove = dw8250_remove,
|
.remove = dw8250_remove,
|
||||||
|
@ -77,6 +77,16 @@ static void dw8250_set_divisor(struct uart_port *p, unsigned int baud,
|
|||||||
serial8250_do_set_divisor(p, baud, quot, quot_frac);
|
serial8250_do_set_divisor(p, baud, quot, quot_frac);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old)
|
||||||
|
{
|
||||||
|
p->status &= ~UPSTAT_AUTOCTS;
|
||||||
|
if (termios->c_cflag & CRTSCTS)
|
||||||
|
p->status |= UPSTAT_AUTOCTS;
|
||||||
|
|
||||||
|
serial8250_do_set_termios(p, termios, old);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(dw8250_do_set_termios);
|
||||||
|
|
||||||
void dw8250_setup_port(struct uart_port *p)
|
void dw8250_setup_port(struct uart_port *p)
|
||||||
{
|
{
|
||||||
struct uart_8250_port *up = up_to_u8250p(p);
|
struct uart_8250_port *up = up_to_u8250p(p);
|
||||||
|
@ -16,4 +16,5 @@ struct dw8250_port_data {
|
|||||||
u8 dlf_size;
|
u8 dlf_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old);
|
||||||
void dw8250_setup_port(struct uart_port *p);
|
void dw8250_setup_port(struct uart_port *p);
|
||||||
|
@ -23,10 +23,6 @@
|
|||||||
|
|
||||||
#include "8250.h"
|
#include "8250.h"
|
||||||
|
|
||||||
struct fsl8250_data {
|
|
||||||
int line;
|
|
||||||
};
|
|
||||||
|
|
||||||
int fsl8250_handle_irq(struct uart_port *port)
|
int fsl8250_handle_irq(struct uart_port *port)
|
||||||
{
|
{
|
||||||
unsigned char lsr, orig_lsr;
|
unsigned char lsr, orig_lsr;
|
||||||
@ -90,6 +86,10 @@ int fsl8250_handle_irq(struct uart_port *port)
|
|||||||
EXPORT_SYMBOL_GPL(fsl8250_handle_irq);
|
EXPORT_SYMBOL_GPL(fsl8250_handle_irq);
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
|
struct fsl8250_data {
|
||||||
|
int line;
|
||||||
|
};
|
||||||
|
|
||||||
static int fsl8250_acpi_probe(struct platform_device *pdev)
|
static int fsl8250_acpi_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct fsl8250_data *data;
|
struct fsl8250_data *data;
|
||||||
|
@ -100,11 +100,7 @@ static void byt_set_termios(struct uart_port *p, struct ktermios *termios,
|
|||||||
reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE;
|
reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE;
|
||||||
writel(reg, p->membase + BYT_PRV_CLK);
|
writel(reg, p->membase + BYT_PRV_CLK);
|
||||||
|
|
||||||
p->status &= ~UPSTAT_AUTOCTS;
|
dw8250_do_set_termios(p, termios, old);
|
||||||
if (termios->c_cflag & CRTSCTS)
|
|
||||||
p->status |= UPSTAT_AUTOCTS;
|
|
||||||
|
|
||||||
serial8250_do_set_termios(p, termios, old);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int byt_get_mctrl(struct uart_port *port)
|
static unsigned int byt_get_mctrl(struct uart_port *port)
|
||||||
@ -168,6 +164,9 @@ static int ehl_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
|
|||||||
* matching with the registered General Purpose DMA controllers.
|
* matching with the registered General Purpose DMA controllers.
|
||||||
*/
|
*/
|
||||||
up->dma = dma;
|
up->dma = dma;
|
||||||
|
|
||||||
|
port->set_termios = dw8250_do_set_termios;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,13 +75,12 @@ static int pci_default_setup(struct serial_private*,
|
|||||||
|
|
||||||
static void moan_device(const char *str, struct pci_dev *dev)
|
static void moan_device(const char *str, struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
dev_err(&dev->dev,
|
pci_err(dev, "%s\n"
|
||||||
"%s: %s\n"
|
|
||||||
"Please send the output of lspci -vv, this\n"
|
"Please send the output of lspci -vv, this\n"
|
||||||
"message (0x%04x,0x%04x,0x%04x,0x%04x), the\n"
|
"message (0x%04x,0x%04x,0x%04x,0x%04x), the\n"
|
||||||
"manufacturer and name of serial board or\n"
|
"manufacturer and name of serial board or\n"
|
||||||
"modem board to <linux-serial@vger.kernel.org>.\n",
|
"modem board to <linux-serial@vger.kernel.org>.\n",
|
||||||
pci_name(dev), str, dev->vendor, dev->device,
|
str, dev->vendor, dev->device,
|
||||||
dev->subsystem_vendor, dev->subsystem_device);
|
dev->subsystem_vendor, dev->subsystem_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +237,7 @@ static int pci_inteli960ni_init(struct pci_dev *dev)
|
|||||||
/* is firmware started? */
|
/* is firmware started? */
|
||||||
pci_read_config_dword(dev, 0x44, &oldval);
|
pci_read_config_dword(dev, 0x44, &oldval);
|
||||||
if (oldval == 0x00001000L) { /* RESET value */
|
if (oldval == 0x00001000L) { /* RESET value */
|
||||||
dev_dbg(&dev->dev, "Local i960 firmware missing\n");
|
pci_dbg(dev, "Local i960 firmware missing\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -515,7 +514,7 @@ static int pci_siig_init(struct pci_dev *dev)
|
|||||||
|
|
||||||
if (type == 0x1000)
|
if (type == 0x1000)
|
||||||
return pci_siig10x_init(dev);
|
return pci_siig10x_init(dev);
|
||||||
else if (type == 0x2000)
|
if (type == 0x2000)
|
||||||
return pci_siig20x_init(dev);
|
return pci_siig20x_init(dev);
|
||||||
|
|
||||||
moan_device("Unknown SIIG card", dev);
|
moan_device("Unknown SIIG card", dev);
|
||||||
@ -588,9 +587,8 @@ static int pci_timedia_probe(struct pci_dev *dev)
|
|||||||
* (0,2,3,5,6: serial only -- 7,8,9: serial + parallel)
|
* (0,2,3,5,6: serial only -- 7,8,9: serial + parallel)
|
||||||
*/
|
*/
|
||||||
if ((dev->subsystem_device & 0x00f0) >= 0x70) {
|
if ((dev->subsystem_device & 0x00f0) >= 0x70) {
|
||||||
dev_info(&dev->dev,
|
pci_info(dev, "ignoring Timedia subdevice %04x for parport_serial\n",
|
||||||
"ignoring Timedia subdevice %04x for parport_serial\n",
|
dev->subsystem_device);
|
||||||
dev->subsystem_device);
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -792,9 +790,9 @@ static int pci_netmos_9900_setup(struct serial_private *priv,
|
|||||||
bar = 3 * idx;
|
bar = 3 * idx;
|
||||||
|
|
||||||
return setup_port(priv, port, bar, 0, board->reg_shift);
|
return setup_port(priv, port, bar, 0, board->reg_shift);
|
||||||
} else {
|
|
||||||
return pci_default_setup(priv, board, port, idx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return pci_default_setup(priv, board, port, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the 99xx series comes with a range of device IDs and a variety
|
/* the 99xx series comes with a range of device IDs and a variety
|
||||||
@ -827,8 +825,7 @@ static int pci_netmos_9900_numports(struct pci_dev *dev)
|
|||||||
if (sub_serports > 0)
|
if (sub_serports > 0)
|
||||||
return sub_serports;
|
return sub_serports;
|
||||||
|
|
||||||
dev_err(&dev->dev,
|
pci_err(dev, "NetMos/Mostech serial driver ignoring port on ambiguous config.\n");
|
||||||
"NetMos/Mostech serial driver ignoring port on ambiguous config.\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -897,18 +894,16 @@ static int pci_netmos_init(struct pci_dev *dev)
|
|||||||
/* enable IO_Space bit */
|
/* enable IO_Space bit */
|
||||||
#define ITE_887x_POSIO_ENABLE (1 << 31)
|
#define ITE_887x_POSIO_ENABLE (1 << 31)
|
||||||
|
|
||||||
|
/* inta_addr are the configuration addresses of the ITE */
|
||||||
|
static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0, 0x200, 0x280 };
|
||||||
static int pci_ite887x_init(struct pci_dev *dev)
|
static int pci_ite887x_init(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
/* inta_addr are the configuration addresses of the ITE */
|
|
||||||
static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0,
|
|
||||||
0x200, 0x280, 0 };
|
|
||||||
int ret, i, type;
|
int ret, i, type;
|
||||||
struct resource *iobase = NULL;
|
struct resource *iobase = NULL;
|
||||||
u32 miscr, uartbar, ioport;
|
u32 miscr, uartbar, ioport;
|
||||||
|
|
||||||
/* search for the base-ioport */
|
/* search for the base-ioport */
|
||||||
i = 0;
|
for (i = 0; i < ARRAY_SIZE(inta_addr); i++) {
|
||||||
while (inta_addr[i] && iobase == NULL) {
|
|
||||||
iobase = request_region(inta_addr[i], ITE_887x_IOSIZE,
|
iobase = request_region(inta_addr[i], ITE_887x_IOSIZE,
|
||||||
"ite887x");
|
"ite887x");
|
||||||
if (iobase != NULL) {
|
if (iobase != NULL) {
|
||||||
@ -925,13 +920,11 @@ static int pci_ite887x_init(struct pci_dev *dev)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
release_region(iobase->start, ITE_887x_IOSIZE);
|
release_region(iobase->start, ITE_887x_IOSIZE);
|
||||||
iobase = NULL;
|
|
||||||
}
|
}
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inta_addr[i]) {
|
if (i == ARRAY_SIZE(inta_addr)) {
|
||||||
dev_err(&dev->dev, "ite887x: could not find iobase\n");
|
pci_err(dev, "could not find iobase\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1026,9 +1019,7 @@ static int pci_endrun_init(struct pci_dev *dev)
|
|||||||
/* EndRun device */
|
/* EndRun device */
|
||||||
if (deviceID == 0x07000200) {
|
if (deviceID == 0x07000200) {
|
||||||
number_uarts = ioread8(p + 4);
|
number_uarts = ioread8(p + 4);
|
||||||
dev_dbg(&dev->dev,
|
pci_dbg(dev, "%d ports detected on EndRun PCI Express device\n", number_uarts);
|
||||||
"%d ports detected on EndRun PCI Express device\n",
|
|
||||||
number_uarts);
|
|
||||||
}
|
}
|
||||||
pci_iounmap(dev, p);
|
pci_iounmap(dev, p);
|
||||||
return number_uarts;
|
return number_uarts;
|
||||||
@ -1058,9 +1049,7 @@ static int pci_oxsemi_tornado_init(struct pci_dev *dev)
|
|||||||
/* Tornado device */
|
/* Tornado device */
|
||||||
if (deviceID == 0x07000200) {
|
if (deviceID == 0x07000200) {
|
||||||
number_uarts = ioread8(p + 4);
|
number_uarts = ioread8(p + 4);
|
||||||
dev_dbg(&dev->dev,
|
pci_dbg(dev, "%d ports detected on Oxford PCI Express device\n", number_uarts);
|
||||||
"%d ports detected on Oxford PCI Express device\n",
|
|
||||||
number_uarts);
|
|
||||||
}
|
}
|
||||||
pci_iounmap(dev, p);
|
pci_iounmap(dev, p);
|
||||||
return number_uarts;
|
return number_uarts;
|
||||||
@ -1074,13 +1063,6 @@ static int pci_asix_setup(struct serial_private *priv,
|
|||||||
return pci_default_setup(priv, board, port, idx);
|
return pci_default_setup(priv, board, port, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Quatech devices have their own extra interface features */
|
|
||||||
|
|
||||||
struct quatech_feature {
|
|
||||||
u16 devid;
|
|
||||||
bool amcc;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define QPCR_TEST_FOR1 0x3F
|
#define QPCR_TEST_FOR1 0x3F
|
||||||
#define QPCR_TEST_GET1 0x00
|
#define QPCR_TEST_GET1 0x00
|
||||||
#define QPCR_TEST_FOR2 0x40
|
#define QPCR_TEST_FOR2 0x40
|
||||||
@ -1096,42 +1078,30 @@ struct quatech_feature {
|
|||||||
#define QOPR_CLOCK_X8 0x0003
|
#define QOPR_CLOCK_X8 0x0003
|
||||||
#define QOPR_CLOCK_RATE_MASK 0x0003
|
#define QOPR_CLOCK_RATE_MASK 0x0003
|
||||||
|
|
||||||
|
/* Quatech devices have their own extra interface features */
|
||||||
static struct quatech_feature quatech_cards[] = {
|
static struct pci_device_id quatech_cards[] = {
|
||||||
{ PCI_DEVICE_ID_QUATECH_QSC100, 1 },
|
{ PCI_DEVICE_DATA(QUATECH, QSC100, 1) },
|
||||||
{ PCI_DEVICE_ID_QUATECH_DSC100, 1 },
|
{ PCI_DEVICE_DATA(QUATECH, DSC100, 1) },
|
||||||
{ PCI_DEVICE_ID_QUATECH_DSC100E, 0 },
|
{ PCI_DEVICE_DATA(QUATECH, DSC100E, 0) },
|
||||||
{ PCI_DEVICE_ID_QUATECH_DSC200, 1 },
|
{ PCI_DEVICE_DATA(QUATECH, DSC200, 1) },
|
||||||
{ PCI_DEVICE_ID_QUATECH_DSC200E, 0 },
|
{ PCI_DEVICE_DATA(QUATECH, DSC200E, 0) },
|
||||||
{ PCI_DEVICE_ID_QUATECH_ESC100D, 1 },
|
{ PCI_DEVICE_DATA(QUATECH, ESC100D, 1) },
|
||||||
{ PCI_DEVICE_ID_QUATECH_ESC100M, 1 },
|
{ PCI_DEVICE_DATA(QUATECH, ESC100M, 1) },
|
||||||
{ PCI_DEVICE_ID_QUATECH_QSCP100, 1 },
|
{ PCI_DEVICE_DATA(QUATECH, QSCP100, 1) },
|
||||||
{ PCI_DEVICE_ID_QUATECH_DSCP100, 1 },
|
{ PCI_DEVICE_DATA(QUATECH, DSCP100, 1) },
|
||||||
{ PCI_DEVICE_ID_QUATECH_QSCP200, 1 },
|
{ PCI_DEVICE_DATA(QUATECH, QSCP200, 1) },
|
||||||
{ PCI_DEVICE_ID_QUATECH_DSCP200, 1 },
|
{ PCI_DEVICE_DATA(QUATECH, DSCP200, 1) },
|
||||||
{ PCI_DEVICE_ID_QUATECH_ESCLP100, 0 },
|
{ PCI_DEVICE_DATA(QUATECH, ESCLP100, 0) },
|
||||||
{ PCI_DEVICE_ID_QUATECH_QSCLP100, 0 },
|
{ PCI_DEVICE_DATA(QUATECH, QSCLP100, 0) },
|
||||||
{ PCI_DEVICE_ID_QUATECH_DSCLP100, 0 },
|
{ PCI_DEVICE_DATA(QUATECH, DSCLP100, 0) },
|
||||||
{ PCI_DEVICE_ID_QUATECH_SSCLP100, 0 },
|
{ PCI_DEVICE_DATA(QUATECH, SSCLP100, 0) },
|
||||||
{ PCI_DEVICE_ID_QUATECH_QSCLP200, 0 },
|
{ PCI_DEVICE_DATA(QUATECH, QSCLP200, 0) },
|
||||||
{ PCI_DEVICE_ID_QUATECH_DSCLP200, 0 },
|
{ PCI_DEVICE_DATA(QUATECH, DSCLP200, 0) },
|
||||||
{ PCI_DEVICE_ID_QUATECH_SSCLP200, 0 },
|
{ PCI_DEVICE_DATA(QUATECH, SSCLP200, 0) },
|
||||||
{ PCI_DEVICE_ID_QUATECH_SPPXP_100, 0 },
|
{ PCI_DEVICE_DATA(QUATECH, SPPXP_100, 0) },
|
||||||
{ 0, }
|
{ 0, }
|
||||||
};
|
};
|
||||||
|
|
||||||
static int pci_quatech_amcc(u16 devid)
|
|
||||||
{
|
|
||||||
struct quatech_feature *qf = &quatech_cards[0];
|
|
||||||
while (qf->devid) {
|
|
||||||
if (qf->devid == devid)
|
|
||||||
return qf->amcc;
|
|
||||||
qf++;
|
|
||||||
}
|
|
||||||
pr_err("quatech: unknown port type '0x%04X'.\n", devid);
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int pci_quatech_rqopr(struct uart_8250_port *port)
|
static int pci_quatech_rqopr(struct uart_8250_port *port)
|
||||||
{
|
{
|
||||||
unsigned long base = port->port.iobase;
|
unsigned long base = port->port.iobase;
|
||||||
@ -1291,7 +1261,16 @@ static int pci_quatech_rs422(struct uart_8250_port *port)
|
|||||||
|
|
||||||
static int pci_quatech_init(struct pci_dev *dev)
|
static int pci_quatech_init(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
if (pci_quatech_amcc(dev->device)) {
|
const struct pci_device_id *match;
|
||||||
|
bool amcc = false;
|
||||||
|
|
||||||
|
match = pci_match_id(quatech_cards, dev);
|
||||||
|
if (match)
|
||||||
|
amcc = match->driver_data;
|
||||||
|
else
|
||||||
|
pci_err(dev, "unknown port type '0x%04X'.\n", dev->device);
|
||||||
|
|
||||||
|
if (amcc) {
|
||||||
unsigned long base = pci_resource_start(dev, 0);
|
unsigned long base = pci_resource_start(dev, 0);
|
||||||
if (base) {
|
if (base) {
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
@ -1315,14 +1294,10 @@ static int pci_quatech_setup(struct serial_private *priv,
|
|||||||
port->port.uartclk = pci_quatech_clock(port);
|
port->port.uartclk = pci_quatech_clock(port);
|
||||||
/* For now just warn about RS422 */
|
/* For now just warn about RS422 */
|
||||||
if (pci_quatech_rs422(port))
|
if (pci_quatech_rs422(port))
|
||||||
pr_warn("quatech: software control of RS422 features not currently supported.\n");
|
pci_warn(priv->dev, "software control of RS422 features not currently supported.\n");
|
||||||
return pci_default_setup(priv, board, port, idx);
|
return pci_default_setup(priv, board, port, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pci_quatech_exit(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pci_default_setup(struct serial_private *priv,
|
static int pci_default_setup(struct serial_private *priv,
|
||||||
const struct pciserial_board *board,
|
const struct pciserial_board *board,
|
||||||
struct uart_8250_port *port, int idx)
|
struct uart_8250_port *port, int idx)
|
||||||
@ -1525,7 +1500,7 @@ static int pci_fintek_setup(struct serial_private *priv,
|
|||||||
/* Get the io address from configuration space */
|
/* Get the io address from configuration space */
|
||||||
pci_read_config_word(pdev, config_base + 4, &iobase);
|
pci_read_config_word(pdev, config_base + 4, &iobase);
|
||||||
|
|
||||||
dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%x", __func__, idx, iobase);
|
pci_dbg(pdev, "idx=%d iobase=0x%x", idx, iobase);
|
||||||
|
|
||||||
port->port.iotype = UPIO_PORT;
|
port->port.iotype = UPIO_PORT;
|
||||||
port->port.iobase = iobase;
|
port->port.iobase = iobase;
|
||||||
@ -1689,7 +1664,7 @@ static int skip_tx_en_setup(struct serial_private *priv,
|
|||||||
struct uart_8250_port *port, int idx)
|
struct uart_8250_port *port, int idx)
|
||||||
{
|
{
|
||||||
port->port.quirks |= UPQ_NO_TXEN_TEST;
|
port->port.quirks |= UPQ_NO_TXEN_TEST;
|
||||||
dev_dbg(&priv->dev->dev,
|
pci_dbg(priv->dev,
|
||||||
"serial8250: skipping TxEn test for device [%04x:%04x] subsystem [%04x:%04x]\n",
|
"serial8250: skipping TxEn test for device [%04x:%04x] subsystem [%04x:%04x]\n",
|
||||||
priv->dev->vendor, priv->dev->device,
|
priv->dev->vendor, priv->dev->device,
|
||||||
priv->dev->subsystem_vendor, priv->dev->subsystem_device);
|
priv->dev->subsystem_vendor, priv->dev->subsystem_device);
|
||||||
@ -2197,7 +2172,6 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
|
|||||||
.subdevice = PCI_ANY_ID,
|
.subdevice = PCI_ANY_ID,
|
||||||
.init = pci_quatech_init,
|
.init = pci_quatech_init,
|
||||||
.setup = pci_quatech_setup,
|
.setup = pci_quatech_setup,
|
||||||
.exit = pci_quatech_exit,
|
|
||||||
},
|
},
|
||||||
/*
|
/*
|
||||||
* Panacom
|
* Panacom
|
||||||
@ -3981,9 +3955,7 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
|
|||||||
nr_ports = rc;
|
nr_ports = rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv = kzalloc(sizeof(struct serial_private) +
|
priv = kzalloc(struct_size(priv, line, nr_ports), GFP_KERNEL);
|
||||||
sizeof(unsigned int) * nr_ports,
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!priv) {
|
if (!priv) {
|
||||||
priv = ERR_PTR(-ENOMEM);
|
priv = ERR_PTR(-ENOMEM);
|
||||||
goto err_deinit;
|
goto err_deinit;
|
||||||
@ -4000,12 +3972,12 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
|
|||||||
uart.port.irq = 0;
|
uart.port.irq = 0;
|
||||||
} else {
|
} else {
|
||||||
if (pci_match_id(pci_use_msi, dev)) {
|
if (pci_match_id(pci_use_msi, dev)) {
|
||||||
dev_dbg(&dev->dev, "Using MSI(-X) interrupts\n");
|
pci_dbg(dev, "Using MSI(-X) interrupts\n");
|
||||||
pci_set_master(dev);
|
pci_set_master(dev);
|
||||||
uart.port.flags &= ~UPF_SHARE_IRQ;
|
uart.port.flags &= ~UPF_SHARE_IRQ;
|
||||||
rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_ALL_TYPES);
|
rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_ALL_TYPES);
|
||||||
} else {
|
} else {
|
||||||
dev_dbg(&dev->dev, "Using legacy interrupts\n");
|
pci_dbg(dev, "Using legacy interrupts\n");
|
||||||
rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY);
|
rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY);
|
||||||
}
|
}
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
@ -4023,12 +3995,12 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
|
|||||||
if (quirk->setup(priv, board, &uart, i))
|
if (quirk->setup(priv, board, &uart, i))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
dev_dbg(&dev->dev, "Setup PCI port: port %lx, irq %d, type %d\n",
|
pci_dbg(dev, "Setup PCI port: port %lx, irq %d, type %d\n",
|
||||||
uart.port.iobase, uart.port.irq, uart.port.iotype);
|
uart.port.iobase, uart.port.irq, uart.port.iotype);
|
||||||
|
|
||||||
priv->line[i] = serial8250_register_8250_port(&uart);
|
priv->line[i] = serial8250_register_8250_port(&uart);
|
||||||
if (priv->line[i] < 0) {
|
if (priv->line[i] < 0) {
|
||||||
dev_err(&dev->dev,
|
pci_err(dev,
|
||||||
"Couldn't register serial port %lx, irq %d, type %d, error %d\n",
|
"Couldn't register serial port %lx, irq %d, type %d, error %d\n",
|
||||||
uart.port.iobase, uart.port.irq,
|
uart.port.iobase, uart.port.irq,
|
||||||
uart.port.iotype, priv->line[i]);
|
uart.port.iotype, priv->line[i]);
|
||||||
@ -4124,8 +4096,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ent->driver_data >= ARRAY_SIZE(pci_boards)) {
|
if (ent->driver_data >= ARRAY_SIZE(pci_boards)) {
|
||||||
dev_err(&dev->dev, "invalid driver_data: %ld\n",
|
pci_err(dev, "invalid driver_data: %ld\n", ent->driver_data);
|
||||||
ent->driver_data);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4208,7 +4179,7 @@ static int pciserial_resume_one(struct device *dev)
|
|||||||
err = pci_enable_device(pdev);
|
err = pci_enable_device(pdev);
|
||||||
/* FIXME: We cannot simply error out here */
|
/* FIXME: We cannot simply error out here */
|
||||||
if (err)
|
if (err)
|
||||||
dev_err(dev, "Unable to re-enable ports, trying to continue.\n");
|
pci_err(pdev, "Unable to re-enable ports, trying to continue.\n");
|
||||||
pciserial_resume_ports(priv);
|
pciserial_resume_ports(priv);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -56,10 +56,6 @@ static const struct pnp_device_id pnp_dev_table[] = {
|
|||||||
{ "BRI1400", 0 },
|
{ "BRI1400", 0 },
|
||||||
/* Boca 33.6 Kbps Internal FD34FSVD */
|
/* Boca 33.6 Kbps Internal FD34FSVD */
|
||||||
{ "BRI3400", 0 },
|
{ "BRI3400", 0 },
|
||||||
/* Boca 33.6 Kbps Internal FD34FSVD */
|
|
||||||
{ "BRI0A49", 0 },
|
|
||||||
/* Best Data Products Inc. Smart One 336F PnP Modem */
|
|
||||||
{ "BDP3336", 0 },
|
|
||||||
/* Computer Peripherals Inc */
|
/* Computer Peripherals Inc */
|
||||||
/* EuroViVa CommCenter-33.6 SP PnP */
|
/* EuroViVa CommCenter-33.6 SP PnP */
|
||||||
{ "CPI4050", 0 },
|
{ "CPI4050", 0 },
|
||||||
|
@ -1338,7 +1338,7 @@ static void autoconfig(struct uart_8250_port *up)
|
|||||||
up->tx_loadsz = uart_config[port->type].tx_loadsz;
|
up->tx_loadsz = uart_config[port->type].tx_loadsz;
|
||||||
|
|
||||||
if (port->type == PORT_UNKNOWN)
|
if (port->type == PORT_UNKNOWN)
|
||||||
goto out_lock;
|
goto out_unlock;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reset the UART.
|
* Reset the UART.
|
||||||
@ -1355,7 +1355,7 @@ static void autoconfig(struct uart_8250_port *up)
|
|||||||
else
|
else
|
||||||
serial_out(up, UART_IER, 0);
|
serial_out(up, UART_IER, 0);
|
||||||
|
|
||||||
out_lock:
|
out_unlock:
|
||||||
spin_unlock_irqrestore(&port->lock, flags);
|
spin_unlock_irqrestore(&port->lock, flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2696,21 +2696,32 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port,
|
|||||||
void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk)
|
void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk)
|
||||||
{
|
{
|
||||||
struct uart_8250_port *up = up_to_u8250p(port);
|
struct uart_8250_port *up = up_to_u8250p(port);
|
||||||
|
struct tty_port *tport = &port->state->port;
|
||||||
unsigned int baud, quot, frac = 0;
|
unsigned int baud, quot, frac = 0;
|
||||||
struct ktermios *termios;
|
struct ktermios *termios;
|
||||||
|
struct tty_struct *tty;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
mutex_lock(&port->state->port.mutex);
|
tty = tty_port_tty_get(tport);
|
||||||
|
if (!tty) {
|
||||||
|
mutex_lock(&tport->mutex);
|
||||||
|
port->uartclk = uartclk;
|
||||||
|
mutex_unlock(&tport->mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
down_write(&tty->termios_rwsem);
|
||||||
|
mutex_lock(&tport->mutex);
|
||||||
|
|
||||||
if (port->uartclk == uartclk)
|
if (port->uartclk == uartclk)
|
||||||
goto out_lock;
|
goto out_unlock;
|
||||||
|
|
||||||
port->uartclk = uartclk;
|
port->uartclk = uartclk;
|
||||||
|
|
||||||
if (!tty_port_initialized(&port->state->port))
|
if (!tty_port_initialized(tport))
|
||||||
goto out_lock;
|
goto out_unlock;
|
||||||
|
|
||||||
termios = &port->state->port.tty->termios;
|
termios = &tty->termios;
|
||||||
|
|
||||||
baud = serial8250_get_baud_rate(port, termios, NULL);
|
baud = serial8250_get_baud_rate(port, termios, NULL);
|
||||||
quot = serial8250_get_divisor(port, baud, &frac);
|
quot = serial8250_get_divisor(port, baud, &frac);
|
||||||
@ -2726,8 +2737,10 @@ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk)
|
|||||||
spin_unlock_irqrestore(&port->lock, flags);
|
spin_unlock_irqrestore(&port->lock, flags);
|
||||||
serial8250_rpm_put(up);
|
serial8250_rpm_put(up);
|
||||||
|
|
||||||
out_lock:
|
out_unlock:
|
||||||
mutex_unlock(&port->state->port.mutex);
|
mutex_unlock(&tport->mutex);
|
||||||
|
up_write(&tty->termios_rwsem);
|
||||||
|
tty_kref_put(tty);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(serial8250_update_uartclk);
|
EXPORT_SYMBOL_GPL(serial8250_update_uartclk);
|
||||||
|
|
||||||
|
@ -380,7 +380,7 @@ config SERIAL_8250_DW
|
|||||||
config SERIAL_8250_EM
|
config SERIAL_8250_EM
|
||||||
tristate "Support for Emma Mobile integrated serial port"
|
tristate "Support for Emma Mobile integrated serial port"
|
||||||
depends on SERIAL_8250 && HAVE_CLK
|
depends on SERIAL_8250 && HAVE_CLK
|
||||||
depends on ARM || COMPILE_TEST
|
depends on (ARM && ARCH_RENESAS) || COMPILE_TEST
|
||||||
help
|
help
|
||||||
Selecting this option will add support for the integrated serial
|
Selecting this option will add support for the integrated serial
|
||||||
port hardware found on the Emma Mobile line of processors.
|
port hardware found on the Emma Mobile line of processors.
|
||||||
|
@ -239,10 +239,11 @@ config SERIAL_SAMSUNG
|
|||||||
depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || ARCH_APPLE || COMPILE_TEST
|
depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || ARCH_APPLE || COMPILE_TEST
|
||||||
select SERIAL_CORE
|
select SERIAL_CORE
|
||||||
help
|
help
|
||||||
Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
|
Support for the on-chip UARTs on the Samsung
|
||||||
providing /dev/ttySAC0, 1 and 2 (note, some machines may not
|
S3C24xx/S3C64xx/S5Pv210/Exynos and Apple M1 SoCs, providing
|
||||||
provide all of these ports, depending on how the serial port
|
/dev/ttySAC0, 1 and 2 (note, some machines may not provide all of
|
||||||
pins are configured.
|
these ports, depending on how the serial port pins are configured.
|
||||||
|
Choose Y/M here only if you build for such SoC.
|
||||||
|
|
||||||
config SERIAL_SAMSUNG_UARTS_4
|
config SERIAL_SAMSUNG_UARTS_4
|
||||||
bool
|
bool
|
||||||
|
@ -2084,7 +2084,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state,
|
|||||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case 0:
|
case UART_PM_STATE_ON:
|
||||||
/*
|
/*
|
||||||
* Enable the peripheral clock for this serial port.
|
* Enable the peripheral clock for this serial port.
|
||||||
* This is called on uart_open() or a resume event.
|
* This is called on uart_open() or a resume event.
|
||||||
@ -2094,7 +2094,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state,
|
|||||||
/* re-enable interrupts if we disabled some on suspend */
|
/* re-enable interrupts if we disabled some on suspend */
|
||||||
atmel_uart_writel(port, ATMEL_US_IER, atmel_port->backup_imr);
|
atmel_uart_writel(port, ATMEL_US_IER, atmel_port->backup_imr);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case UART_PM_STATE_OFF:
|
||||||
/* Back up the interrupt mask and disable all interrupts */
|
/* Back up the interrupt mask and disable all interrupts */
|
||||||
atmel_port->backup_imr = atmel_uart_readl(port, ATMEL_US_IMR);
|
atmel_port->backup_imr = atmel_uart_readl(port, ATMEL_US_IMR);
|
||||||
atmel_uart_writel(port, ATMEL_US_IDR, -1);
|
atmel_uart_writel(port, ATMEL_US_IDR, -1);
|
||||||
|
@ -1090,6 +1090,7 @@ static void cpm_put_poll_char(struct uart_port *port,
|
|||||||
cpm_uart_early_write(pinfo, ch, 1, false);
|
cpm_uart_early_write(pinfo, ch, 1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_CPM_CONSOLE
|
||||||
static struct uart_port *udbg_port;
|
static struct uart_port *udbg_port;
|
||||||
|
|
||||||
static void udbg_cpm_putc(char c)
|
static void udbg_cpm_putc(char c)
|
||||||
@ -1114,6 +1115,7 @@ static int udbg_cpm_getc(void)
|
|||||||
cpu_relax();
|
cpu_relax();
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
#endif /* CONFIG_SERIAL_CPM_CONSOLE */
|
||||||
|
|
||||||
#endif /* CONFIG_CONSOLE_POLL */
|
#endif /* CONFIG_CONSOLE_POLL */
|
||||||
|
|
||||||
|
@ -2017,7 +2017,7 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count)
|
|||||||
* If the port was already initialised (eg, by a boot loader),
|
* If the port was already initialised (eg, by a boot loader),
|
||||||
* try to determine the current setup.
|
* try to determine the current setup.
|
||||||
*/
|
*/
|
||||||
static void __init
|
static void
|
||||||
imx_uart_console_get_options(struct imx_port *sport, int *baud,
|
imx_uart_console_get_options(struct imx_port *sport, int *baud,
|
||||||
int *parity, int *bits)
|
int *parity, int *bits)
|
||||||
{
|
{
|
||||||
@ -2076,7 +2076,7 @@ imx_uart_console_get_options(struct imx_port *sport, int *baud,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init
|
static int
|
||||||
imx_uart_console_setup(struct console *co, char *options)
|
imx_uart_console_setup(struct console *co, char *options)
|
||||||
{
|
{
|
||||||
struct imx_port *sport;
|
struct imx_port *sport;
|
||||||
@ -2124,12 +2124,24 @@ error_console:
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
imx_uart_console_exit(struct console *co)
|
||||||
|
{
|
||||||
|
struct imx_port *sport = imx_uart_ports[co->index];
|
||||||
|
|
||||||
|
clk_disable_unprepare(sport->clk_per);
|
||||||
|
clk_disable_unprepare(sport->clk_ipg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct uart_driver imx_uart_uart_driver;
|
static struct uart_driver imx_uart_uart_driver;
|
||||||
static struct console imx_uart_console = {
|
static struct console imx_uart_console = {
|
||||||
.name = DEV_NAME,
|
.name = DEV_NAME,
|
||||||
.write = imx_uart_console_write,
|
.write = imx_uart_console_write,
|
||||||
.device = uart_console_device,
|
.device = uart_console_device,
|
||||||
.setup = imx_uart_console_setup,
|
.setup = imx_uart_console_setup,
|
||||||
|
.exit = imx_uart_console_exit,
|
||||||
.flags = CON_PRINTBUFFER,
|
.flags = CON_PRINTBUFFER,
|
||||||
.index = -1,
|
.index = -1,
|
||||||
.data = &imx_uart_uart_driver,
|
.data = &imx_uart_uart_driver,
|
||||||
|
@ -1426,7 +1426,7 @@ out_clk:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int max310x_remove(struct device *dev)
|
static void max310x_remove(struct device *dev)
|
||||||
{
|
{
|
||||||
struct max310x_port *s = dev_get_drvdata(dev);
|
struct max310x_port *s = dev_get_drvdata(dev);
|
||||||
int i;
|
int i;
|
||||||
@ -1441,8 +1441,6 @@ static int max310x_remove(struct device *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
clk_disable_unprepare(s->clk);
|
clk_disable_unprepare(s->clk);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id __maybe_unused max310x_dt_ids[] = {
|
static const struct of_device_id __maybe_unused max310x_dt_ids[] = {
|
||||||
@ -1491,7 +1489,8 @@ static int max310x_spi_probe(struct spi_device *spi)
|
|||||||
|
|
||||||
static int max310x_spi_remove(struct spi_device *spi)
|
static int max310x_spi_remove(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
return max310x_remove(&spi->dev);
|
max310x_remove(&spi->dev);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct spi_device_id max310x_id_table[] = {
|
static const struct spi_device_id max310x_id_table[] = {
|
||||||
|
@ -65,7 +65,7 @@ enum s3c24xx_port_type {
|
|||||||
struct s3c24xx_uart_info {
|
struct s3c24xx_uart_info {
|
||||||
char *name;
|
char *name;
|
||||||
enum s3c24xx_port_type type;
|
enum s3c24xx_port_type type;
|
||||||
unsigned int has_usi;
|
bool has_usi;
|
||||||
unsigned int port_type;
|
unsigned int port_type;
|
||||||
unsigned int fifosize;
|
unsigned int fifosize;
|
||||||
unsigned long rx_fifomask;
|
unsigned long rx_fifomask;
|
||||||
@ -2780,7 +2780,7 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_ARCH_EXYNOS)
|
#if defined(CONFIG_ARCH_EXYNOS)
|
||||||
#define EXYNOS_COMMON_SERIAL_DRV_DATA_USI(_has_usi) \
|
#define EXYNOS_COMMON_SERIAL_DRV_DATA(_has_usi) \
|
||||||
.info = &(struct s3c24xx_uart_info) { \
|
.info = &(struct s3c24xx_uart_info) { \
|
||||||
.name = "Samsung Exynos UART", \
|
.name = "Samsung Exynos UART", \
|
||||||
.type = TYPE_S3C6400, \
|
.type = TYPE_S3C6400, \
|
||||||
@ -2804,21 +2804,18 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
|
|||||||
.has_fracval = 1, \
|
.has_fracval = 1, \
|
||||||
} \
|
} \
|
||||||
|
|
||||||
#define EXYNOS_COMMON_SERIAL_DRV_DATA \
|
|
||||||
EXYNOS_COMMON_SERIAL_DRV_DATA_USI(0)
|
|
||||||
|
|
||||||
static struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = {
|
static struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = {
|
||||||
EXYNOS_COMMON_SERIAL_DRV_DATA,
|
EXYNOS_COMMON_SERIAL_DRV_DATA(false),
|
||||||
.fifosize = { 256, 64, 16, 16 },
|
.fifosize = { 256, 64, 16, 16 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = {
|
static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = {
|
||||||
EXYNOS_COMMON_SERIAL_DRV_DATA,
|
EXYNOS_COMMON_SERIAL_DRV_DATA(false),
|
||||||
.fifosize = { 64, 256, 16, 256 },
|
.fifosize = { 64, 256, 16, 256 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct s3c24xx_serial_drv_data exynos850_serial_drv_data = {
|
static struct s3c24xx_serial_drv_data exynos850_serial_drv_data = {
|
||||||
EXYNOS_COMMON_SERIAL_DRV_DATA_USI(1),
|
EXYNOS_COMMON_SERIAL_DRV_DATA(true),
|
||||||
.fifosize = { 256, 64, 64, 64 },
|
.fifosize = { 256, 64, 64, 64 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1365,7 +1365,7 @@ out_clk:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sc16is7xx_remove(struct device *dev)
|
static void sc16is7xx_remove(struct device *dev)
|
||||||
{
|
{
|
||||||
struct sc16is7xx_port *s = dev_get_drvdata(dev);
|
struct sc16is7xx_port *s = dev_get_drvdata(dev);
|
||||||
int i;
|
int i;
|
||||||
@ -1385,8 +1385,6 @@ static int sc16is7xx_remove(struct device *dev)
|
|||||||
kthread_stop(s->kworker_task);
|
kthread_stop(s->kworker_task);
|
||||||
|
|
||||||
clk_disable_unprepare(s->clk);
|
clk_disable_unprepare(s->clk);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = {
|
static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = {
|
||||||
@ -1444,7 +1442,9 @@ static int sc16is7xx_spi_probe(struct spi_device *spi)
|
|||||||
|
|
||||||
static int sc16is7xx_spi_remove(struct spi_device *spi)
|
static int sc16is7xx_spi_remove(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
return sc16is7xx_remove(&spi->dev);
|
sc16is7xx_remove(&spi->dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct spi_device_id sc16is7xx_spi_id_table[] = {
|
static const struct spi_device_id sc16is7xx_spi_id_table[] = {
|
||||||
@ -1497,7 +1497,9 @@ static int sc16is7xx_i2c_probe(struct i2c_client *i2c,
|
|||||||
|
|
||||||
static int sc16is7xx_i2c_remove(struct i2c_client *client)
|
static int sc16is7xx_i2c_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
return sc16is7xx_remove(&client->dev);
|
sc16is7xx_remove(&client->dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct i2c_device_id sc16is7xx_i2c_id_table[] = {
|
static const struct i2c_device_id sc16is7xx_i2c_id_table[] = {
|
||||||
|
@ -222,7 +222,11 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
|
|||||||
if (retval == 0) {
|
if (retval == 0) {
|
||||||
if (uart_console(uport) && uport->cons->cflag) {
|
if (uart_console(uport) && uport->cons->cflag) {
|
||||||
tty->termios.c_cflag = uport->cons->cflag;
|
tty->termios.c_cflag = uport->cons->cflag;
|
||||||
|
tty->termios.c_ispeed = uport->cons->ispeed;
|
||||||
|
tty->termios.c_ospeed = uport->cons->ospeed;
|
||||||
uport->cons->cflag = 0;
|
uport->cons->cflag = 0;
|
||||||
|
uport->cons->ispeed = 0;
|
||||||
|
uport->cons->ospeed = 0;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Initialise the hardware port settings.
|
* Initialise the hardware port settings.
|
||||||
@ -290,8 +294,11 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
|
|||||||
/*
|
/*
|
||||||
* Turn off DTR and RTS early.
|
* Turn off DTR and RTS early.
|
||||||
*/
|
*/
|
||||||
if (uport && uart_console(uport) && tty)
|
if (uport && uart_console(uport) && tty) {
|
||||||
uport->cons->cflag = tty->termios.c_cflag;
|
uport->cons->cflag = tty->termios.c_cflag;
|
||||||
|
uport->cons->ispeed = tty->termios.c_ispeed;
|
||||||
|
uport->cons->ospeed = tty->termios.c_ospeed;
|
||||||
|
}
|
||||||
|
|
||||||
if (!tty || C_HUPCL(tty))
|
if (!tty || C_HUPCL(tty))
|
||||||
uart_port_dtr_rts(uport, 0);
|
uart_port_dtr_rts(uport, 0);
|
||||||
@ -2094,8 +2101,11 @@ uart_set_options(struct uart_port *port, struct console *co,
|
|||||||
* Allow the setting of the UART parameters with a NULL console
|
* Allow the setting of the UART parameters with a NULL console
|
||||||
* too:
|
* too:
|
||||||
*/
|
*/
|
||||||
if (co)
|
if (co) {
|
||||||
co->cflag = termios.c_cflag;
|
co->cflag = termios.c_cflag;
|
||||||
|
co->ispeed = termios.c_ispeed;
|
||||||
|
co->ospeed = termios.c_ospeed;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2229,6 +2239,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
|
|||||||
*/
|
*/
|
||||||
memset(&termios, 0, sizeof(struct ktermios));
|
memset(&termios, 0, sizeof(struct ktermios));
|
||||||
termios.c_cflag = uport->cons->cflag;
|
termios.c_cflag = uport->cons->cflag;
|
||||||
|
termios.c_ispeed = uport->cons->ispeed;
|
||||||
|
termios.c_ospeed = uport->cons->ospeed;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If that's unset, use the tty termios setting.
|
* If that's unset, use the tty termios setting.
|
||||||
|
@ -887,7 +887,7 @@ static void __ssp_add_console_port(struct sifive_serial_port *ssp)
|
|||||||
|
|
||||||
static void __ssp_remove_console_port(struct sifive_serial_port *ssp)
|
static void __ssp_remove_console_port(struct sifive_serial_port *ssp)
|
||||||
{
|
{
|
||||||
sifive_serial_console_ports[ssp->port.line] = 0;
|
sifive_serial_console_ports[ssp->port.line] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SIFIVE_SERIAL_CONSOLE (&sifive_serial_console)
|
#define SIFIVE_SERIAL_CONSOLE (&sifive_serial_console)
|
||||||
|
@ -165,63 +165,61 @@ static int stm32_usart_init_rs485(struct uart_port *port,
|
|||||||
return uart_get_rs485_mode(port);
|
return uart_get_rs485_mode(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stm32_usart_pending_rx(struct uart_port *port, u32 *sr,
|
static bool stm32_usart_rx_dma_enabled(struct uart_port *port)
|
||||||
int *last_res, bool threaded)
|
|
||||||
{
|
{
|
||||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||||
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||||
enum dma_status status;
|
|
||||||
struct dma_tx_state state;
|
|
||||||
|
|
||||||
*sr = readl_relaxed(port->membase + ofs->isr);
|
if (!stm32_port->rx_ch)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (threaded && stm32_port->rx_ch) {
|
return !!(readl_relaxed(port->membase + ofs->cr3) & USART_CR3_DMAR);
|
||||||
status = dmaengine_tx_status(stm32_port->rx_ch,
|
|
||||||
stm32_port->rx_ch->cookie,
|
|
||||||
&state);
|
|
||||||
if (status == DMA_IN_PROGRESS && (*last_res != state.residue))
|
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
} else if (*sr & USART_SR_RXNE) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long stm32_usart_get_char(struct uart_port *port, u32 *sr,
|
/* Return true when data is pending (in pio mode), and false when no data is pending. */
|
||||||
int *last_res)
|
static bool stm32_usart_pending_rx_pio(struct uart_port *port, u32 *sr)
|
||||||
|
{
|
||||||
|
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||||
|
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||||
|
|
||||||
|
*sr = readl_relaxed(port->membase + ofs->isr);
|
||||||
|
/* Get pending characters in RDR or FIFO */
|
||||||
|
if (*sr & USART_SR_RXNE) {
|
||||||
|
/* Get all pending characters from the RDR or the FIFO when using interrupts */
|
||||||
|
if (!stm32_usart_rx_dma_enabled(port))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* Handle only RX data errors when using DMA */
|
||||||
|
if (*sr & USART_SR_ERR_MASK)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long stm32_usart_get_char_pio(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||||
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||||
unsigned long c;
|
unsigned long c;
|
||||||
|
|
||||||
if (stm32_port->rx_ch) {
|
c = readl_relaxed(port->membase + ofs->rdr);
|
||||||
c = stm32_port->rx_buf[RX_BUF_L - (*last_res)--];
|
/* Apply RDR data mask */
|
||||||
if ((*last_res) == 0)
|
c &= stm32_port->rdr_mask;
|
||||||
*last_res = RX_BUF_L;
|
|
||||||
} else {
|
|
||||||
c = readl_relaxed(port->membase + ofs->rdr);
|
|
||||||
/* apply RDR data mask */
|
|
||||||
c &= stm32_port->rdr_mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stm32_usart_receive_chars(struct uart_port *port, bool threaded)
|
static unsigned int stm32_usart_receive_chars_pio(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct tty_port *tport = &port->state->port;
|
|
||||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||||
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||||
unsigned long c;
|
unsigned long c;
|
||||||
|
unsigned int size = 0;
|
||||||
u32 sr;
|
u32 sr;
|
||||||
char flag;
|
char flag;
|
||||||
|
|
||||||
spin_lock(&port->lock);
|
while (stm32_usart_pending_rx_pio(port, &sr)) {
|
||||||
|
|
||||||
while (stm32_usart_pending_rx(port, &sr, &stm32_port->last_res,
|
|
||||||
threaded)) {
|
|
||||||
sr |= USART_SR_DUMMY_RX;
|
sr |= USART_SR_DUMMY_RX;
|
||||||
flag = TTY_NORMAL;
|
flag = TTY_NORMAL;
|
||||||
|
|
||||||
@ -240,8 +238,9 @@ static void stm32_usart_receive_chars(struct uart_port *port, bool threaded)
|
|||||||
writel_relaxed(sr & USART_SR_ERR_MASK,
|
writel_relaxed(sr & USART_SR_ERR_MASK,
|
||||||
port->membase + ofs->icr);
|
port->membase + ofs->icr);
|
||||||
|
|
||||||
c = stm32_usart_get_char(port, &sr, &stm32_port->last_res);
|
c = stm32_usart_get_char_pio(port);
|
||||||
port->icount.rx++;
|
port->icount.rx++;
|
||||||
|
size++;
|
||||||
if (sr & USART_SR_ERR_MASK) {
|
if (sr & USART_SR_ERR_MASK) {
|
||||||
if (sr & USART_SR_ORE) {
|
if (sr & USART_SR_ORE) {
|
||||||
port->icount.overrun++;
|
port->icount.overrun++;
|
||||||
@ -275,9 +274,95 @@ static void stm32_usart_receive_chars(struct uart_port *port, bool threaded)
|
|||||||
uart_insert_char(port, sr, USART_SR_ORE, c, flag);
|
uart_insert_char(port, sr, USART_SR_ORE, c, flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
uart_unlock_and_check_sysrq(port);
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
tty_flip_buffer_push(tport);
|
static void stm32_usart_push_buffer_dma(struct uart_port *port, unsigned int dma_size)
|
||||||
|
{
|
||||||
|
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||||
|
struct tty_port *ttyport = &stm32_port->port.state->port;
|
||||||
|
unsigned char *dma_start;
|
||||||
|
int dma_count, i;
|
||||||
|
|
||||||
|
dma_start = stm32_port->rx_buf + (RX_BUF_L - stm32_port->last_res);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Apply rdr_mask on buffer in order to mask parity bit.
|
||||||
|
* This loop is useless in cs8 mode because DMA copies only
|
||||||
|
* 8 bits and already ignores parity bit.
|
||||||
|
*/
|
||||||
|
if (!(stm32_port->rdr_mask == (BIT(8) - 1)))
|
||||||
|
for (i = 0; i < dma_size; i++)
|
||||||
|
*(dma_start + i) &= stm32_port->rdr_mask;
|
||||||
|
|
||||||
|
dma_count = tty_insert_flip_string(ttyport, dma_start, dma_size);
|
||||||
|
port->icount.rx += dma_count;
|
||||||
|
if (dma_count != dma_size)
|
||||||
|
port->icount.buf_overrun++;
|
||||||
|
stm32_port->last_res -= dma_count;
|
||||||
|
if (stm32_port->last_res == 0)
|
||||||
|
stm32_port->last_res = RX_BUF_L;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int stm32_usart_receive_chars_dma(struct uart_port *port)
|
||||||
|
{
|
||||||
|
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||||
|
unsigned int dma_size, size = 0;
|
||||||
|
|
||||||
|
/* DMA buffer is configured in cyclic mode and handles the rollback of the buffer. */
|
||||||
|
if (stm32_port->rx_dma_state.residue > stm32_port->last_res) {
|
||||||
|
/* Conditional first part: from last_res to end of DMA buffer */
|
||||||
|
dma_size = stm32_port->last_res;
|
||||||
|
stm32_usart_push_buffer_dma(port, dma_size);
|
||||||
|
size = dma_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
dma_size = stm32_port->last_res - stm32_port->rx_dma_state.residue;
|
||||||
|
stm32_usart_push_buffer_dma(port, dma_size);
|
||||||
|
size += dma_size;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int stm32_usart_receive_chars(struct uart_port *port, bool force_dma_flush)
|
||||||
|
{
|
||||||
|
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||||
|
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||||
|
enum dma_status rx_dma_status;
|
||||||
|
u32 sr;
|
||||||
|
unsigned int size = 0;
|
||||||
|
|
||||||
|
if (stm32_usart_rx_dma_enabled(port) || force_dma_flush) {
|
||||||
|
rx_dma_status = dmaengine_tx_status(stm32_port->rx_ch,
|
||||||
|
stm32_port->rx_ch->cookie,
|
||||||
|
&stm32_port->rx_dma_state);
|
||||||
|
if (rx_dma_status == DMA_IN_PROGRESS) {
|
||||||
|
/* Empty DMA buffer */
|
||||||
|
size = stm32_usart_receive_chars_dma(port);
|
||||||
|
sr = readl_relaxed(port->membase + ofs->isr);
|
||||||
|
if (sr & USART_SR_ERR_MASK) {
|
||||||
|
/* Disable DMA request line */
|
||||||
|
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR);
|
||||||
|
|
||||||
|
/* Switch to PIO mode to handle the errors */
|
||||||
|
size += stm32_usart_receive_chars_pio(port);
|
||||||
|
|
||||||
|
/* Switch back to DMA mode */
|
||||||
|
stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Disable RX DMA */
|
||||||
|
dmaengine_terminate_async(stm32_port->rx_ch);
|
||||||
|
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR);
|
||||||
|
/* Fall back to interrupt mode */
|
||||||
|
dev_dbg(port->dev, "DMA error, fallback to irq mode\n");
|
||||||
|
size = stm32_usart_receive_chars_pio(port);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
size = stm32_usart_receive_chars_pio(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stm32_usart_tx_dma_complete(void *arg)
|
static void stm32_usart_tx_dma_complete(void *arg)
|
||||||
@ -312,6 +397,20 @@ static void stm32_usart_tx_interrupt_enable(struct uart_port *port)
|
|||||||
stm32_usart_set_bits(port, ofs->cr1, USART_CR1_TXEIE);
|
stm32_usart_set_bits(port, ofs->cr1, USART_CR1_TXEIE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void stm32_usart_rx_dma_complete(void *arg)
|
||||||
|
{
|
||||||
|
struct uart_port *port = arg;
|
||||||
|
struct tty_port *tport = &port->state->port;
|
||||||
|
unsigned int size;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&port->lock, flags);
|
||||||
|
size = stm32_usart_receive_chars(port, false);
|
||||||
|
uart_unlock_and_check_sysrq_irqrestore(port, flags);
|
||||||
|
if (size)
|
||||||
|
tty_flip_buffer_push(tport);
|
||||||
|
}
|
||||||
|
|
||||||
static void stm32_usart_tx_interrupt_disable(struct uart_port *port)
|
static void stm32_usart_tx_interrupt_disable(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||||
@ -462,6 +561,7 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
|
|||||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||||
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||||
u32 sr;
|
u32 sr;
|
||||||
|
unsigned int size;
|
||||||
|
|
||||||
sr = readl_relaxed(port->membase + ofs->isr);
|
sr = readl_relaxed(port->membase + ofs->isr);
|
||||||
|
|
||||||
@ -478,8 +578,20 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
|
|||||||
pm_wakeup_event(tport->tty->dev, 0);
|
pm_wakeup_event(tport->tty->dev, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch))
|
/*
|
||||||
stm32_usart_receive_chars(port, false);
|
* rx errors in dma mode has to be handled ASAP to avoid overrun as the DMA request
|
||||||
|
* line has been masked by HW and rx data are stacking in FIFO.
|
||||||
|
*/
|
||||||
|
if (!stm32_port->throttled) {
|
||||||
|
if (((sr & USART_SR_RXNE) && !stm32_usart_rx_dma_enabled(port)) ||
|
||||||
|
((sr & USART_SR_ERR_MASK) && stm32_usart_rx_dma_enabled(port))) {
|
||||||
|
spin_lock(&port->lock);
|
||||||
|
size = stm32_usart_receive_chars(port, false);
|
||||||
|
uart_unlock_and_check_sysrq(port);
|
||||||
|
if (size)
|
||||||
|
tty_flip_buffer_push(tport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) {
|
if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) {
|
||||||
spin_lock(&port->lock);
|
spin_lock(&port->lock);
|
||||||
@ -487,7 +599,7 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
|
|||||||
spin_unlock(&port->lock);
|
spin_unlock(&port->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stm32_port->rx_ch)
|
if (stm32_usart_rx_dma_enabled(port))
|
||||||
return IRQ_WAKE_THREAD;
|
return IRQ_WAKE_THREAD;
|
||||||
else
|
else
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
@ -496,10 +608,19 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
|
|||||||
static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr)
|
static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr)
|
||||||
{
|
{
|
||||||
struct uart_port *port = ptr;
|
struct uart_port *port = ptr;
|
||||||
|
struct tty_port *tport = &port->state->port;
|
||||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||||
|
unsigned int size;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
if (stm32_port->rx_ch)
|
/* Receiver timeout irq for DMA RX */
|
||||||
stm32_usart_receive_chars(port, true);
|
if (!stm32_port->throttled) {
|
||||||
|
spin_lock_irqsave(&port->lock, flags);
|
||||||
|
size = stm32_usart_receive_chars(port, false);
|
||||||
|
uart_unlock_and_check_sysrq_irqrestore(port, flags);
|
||||||
|
if (size)
|
||||||
|
tty_flip_buffer_push(tport);
|
||||||
|
}
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
@ -612,10 +733,19 @@ static void stm32_usart_throttle(struct uart_port *port)
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&port->lock, flags);
|
spin_lock_irqsave(&port->lock, flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable DMA request line if enabled, so the RX data gets queued into the FIFO.
|
||||||
|
* Hardware flow control is triggered when RX FIFO is full.
|
||||||
|
*/
|
||||||
|
if (stm32_usart_rx_dma_enabled(port))
|
||||||
|
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR);
|
||||||
|
|
||||||
stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq);
|
stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq);
|
||||||
if (stm32_port->cr3_irq)
|
if (stm32_port->cr3_irq)
|
||||||
stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq);
|
stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq);
|
||||||
|
|
||||||
|
stm32_port->throttled = true;
|
||||||
spin_unlock_irqrestore(&port->lock, flags);
|
spin_unlock_irqrestore(&port->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,6 +761,14 @@ static void stm32_usart_unthrottle(struct uart_port *port)
|
|||||||
if (stm32_port->cr3_irq)
|
if (stm32_port->cr3_irq)
|
||||||
stm32_usart_set_bits(port, ofs->cr3, stm32_port->cr3_irq);
|
stm32_usart_set_bits(port, ofs->cr3, stm32_port->cr3_irq);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Switch back to DMA mode (re-enable DMA request line).
|
||||||
|
* Hardware flow control is stopped when FIFO is not full any more.
|
||||||
|
*/
|
||||||
|
if (stm32_port->rx_ch)
|
||||||
|
stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR);
|
||||||
|
|
||||||
|
stm32_port->throttled = false;
|
||||||
spin_unlock_irqrestore(&port->lock, flags);
|
spin_unlock_irqrestore(&port->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -640,6 +778,10 @@ static void stm32_usart_stop_rx(struct uart_port *port)
|
|||||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||||
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||||
|
|
||||||
|
/* Disable DMA request line. */
|
||||||
|
if (stm32_port->rx_ch)
|
||||||
|
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR);
|
||||||
|
|
||||||
stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq);
|
stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq);
|
||||||
if (stm32_port->cr3_irq)
|
if (stm32_port->cr3_irq)
|
||||||
stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq);
|
stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq);
|
||||||
@ -650,6 +792,48 @@ static void stm32_usart_break_ctl(struct uart_port *port, int break_state)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int stm32_usart_start_rx_dma_cyclic(struct uart_port *port)
|
||||||
|
{
|
||||||
|
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||||
|
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||||
|
struct dma_async_tx_descriptor *desc;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
stm32_port->last_res = RX_BUF_L;
|
||||||
|
/* Prepare a DMA cyclic transaction */
|
||||||
|
desc = dmaengine_prep_dma_cyclic(stm32_port->rx_ch,
|
||||||
|
stm32_port->rx_dma_buf,
|
||||||
|
RX_BUF_L, RX_BUF_P,
|
||||||
|
DMA_DEV_TO_MEM,
|
||||||
|
DMA_PREP_INTERRUPT);
|
||||||
|
if (!desc) {
|
||||||
|
dev_err(port->dev, "rx dma prep cyclic failed\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
desc->callback = stm32_usart_rx_dma_complete;
|
||||||
|
desc->callback_param = port;
|
||||||
|
|
||||||
|
/* Push current DMA transaction in the pending queue */
|
||||||
|
ret = dma_submit_error(dmaengine_submit(desc));
|
||||||
|
if (ret) {
|
||||||
|
dmaengine_terminate_sync(stm32_port->rx_ch);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Issue pending DMA requests */
|
||||||
|
dma_async_issue_pending(stm32_port->rx_ch);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DMA request line not re-enabled at resume when port is throttled.
|
||||||
|
* It will be re-enabled by unthrottle ops.
|
||||||
|
*/
|
||||||
|
if (!stm32_port->throttled)
|
||||||
|
stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int stm32_usart_startup(struct uart_port *port)
|
static int stm32_usart_startup(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||||
@ -676,6 +860,14 @@ static int stm32_usart_startup(struct uart_port *port)
|
|||||||
if (ofs->rqr != UNDEF_REG)
|
if (ofs->rqr != UNDEF_REG)
|
||||||
writel_relaxed(USART_RQR_RXFRQ, port->membase + ofs->rqr);
|
writel_relaxed(USART_RQR_RXFRQ, port->membase + ofs->rqr);
|
||||||
|
|
||||||
|
if (stm32_port->rx_ch) {
|
||||||
|
ret = stm32_usart_start_rx_dma_cyclic(port);
|
||||||
|
if (ret) {
|
||||||
|
free_irq(port->irq, port);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* RX enabling */
|
/* RX enabling */
|
||||||
val = stm32_port->cr1_irq | USART_CR1_RE | BIT(cfg->uart_enable_bit);
|
val = stm32_port->cr1_irq | USART_CR1_RE | BIT(cfg->uart_enable_bit);
|
||||||
stm32_usart_set_bits(port, ofs->cr1, val);
|
stm32_usart_set_bits(port, ofs->cr1, val);
|
||||||
@ -708,6 +900,10 @@ static void stm32_usart_shutdown(struct uart_port *port)
|
|||||||
if (ret)
|
if (ret)
|
||||||
dev_err(port->dev, "Transmission is not complete\n");
|
dev_err(port->dev, "Transmission is not complete\n");
|
||||||
|
|
||||||
|
/* Disable RX DMA. */
|
||||||
|
if (stm32_port->rx_ch)
|
||||||
|
dmaengine_terminate_async(stm32_port->rx_ch);
|
||||||
|
|
||||||
/* flush RX & TX FIFO */
|
/* flush RX & TX FIFO */
|
||||||
if (ofs->rqr != UNDEF_REG)
|
if (ofs->rqr != UNDEF_REG)
|
||||||
writel_relaxed(USART_RQR_TXFRQ | USART_RQR_RXFRQ,
|
writel_relaxed(USART_RQR_TXFRQ | USART_RQR_RXFRQ,
|
||||||
@ -810,9 +1006,11 @@ static void stm32_usart_set_termios(struct uart_port *port,
|
|||||||
stm32_port->cr1_irq = USART_CR1_RTOIE;
|
stm32_port->cr1_irq = USART_CR1_RTOIE;
|
||||||
writel_relaxed(bits, port->membase + ofs->rtor);
|
writel_relaxed(bits, port->membase + ofs->rtor);
|
||||||
cr2 |= USART_CR2_RTOEN;
|
cr2 |= USART_CR2_RTOEN;
|
||||||
/* Not using dma, enable fifo threshold irq */
|
/*
|
||||||
if (!stm32_port->rx_ch)
|
* Enable fifo threshold irq in two cases, either when there is no DMA, or when
|
||||||
stm32_port->cr3_irq = USART_CR3_RXFTIE;
|
* wake up over usart, from low power until the DMA gets re-enabled by resume.
|
||||||
|
*/
|
||||||
|
stm32_port->cr3_irq = USART_CR3_RXFTIE;
|
||||||
}
|
}
|
||||||
|
|
||||||
cr1 |= stm32_port->cr1_irq;
|
cr1 |= stm32_port->cr1_irq;
|
||||||
@ -875,8 +1073,16 @@ static void stm32_usart_set_termios(struct uart_port *port,
|
|||||||
if ((termios->c_cflag & CREAD) == 0)
|
if ((termios->c_cflag & CREAD) == 0)
|
||||||
port->ignore_status_mask |= USART_SR_DUMMY_RX;
|
port->ignore_status_mask |= USART_SR_DUMMY_RX;
|
||||||
|
|
||||||
if (stm32_port->rx_ch)
|
if (stm32_port->rx_ch) {
|
||||||
|
/*
|
||||||
|
* Setup DMA to collect only valid data and enable error irqs.
|
||||||
|
* This also enables break reception when using DMA.
|
||||||
|
*/
|
||||||
|
cr1 |= USART_CR1_PEIE;
|
||||||
|
cr3 |= USART_CR3_EIE;
|
||||||
cr3 |= USART_CR3_DMAR;
|
cr3 |= USART_CR3_DMAR;
|
||||||
|
cr3 |= USART_CR3_DDRE;
|
||||||
|
}
|
||||||
|
|
||||||
if (rs485conf->flags & SER_RS485_ENABLED) {
|
if (rs485conf->flags & SER_RS485_ENABLED) {
|
||||||
stm32_usart_config_reg_rs485(&cr1, &cr3,
|
stm32_usart_config_reg_rs485(&cr1, &cr3,
|
||||||
@ -1166,7 +1372,6 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port,
|
|||||||
struct uart_port *port = &stm32port->port;
|
struct uart_port *port = &stm32port->port;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct dma_slave_config config;
|
struct dma_slave_config config;
|
||||||
struct dma_async_tx_descriptor *desc = NULL;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1194,32 +1399,6 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prepare a DMA cyclic transaction */
|
|
||||||
desc = dmaengine_prep_dma_cyclic(stm32port->rx_ch,
|
|
||||||
stm32port->rx_dma_buf,
|
|
||||||
RX_BUF_L, RX_BUF_P, DMA_DEV_TO_MEM,
|
|
||||||
DMA_PREP_INTERRUPT);
|
|
||||||
if (!desc) {
|
|
||||||
dev_err(dev, "rx dma prep cyclic failed\n");
|
|
||||||
stm32_usart_of_dma_rx_remove(stm32port, pdev);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* No callback as dma buffer is drained on usart interrupt */
|
|
||||||
desc->callback = NULL;
|
|
||||||
desc->callback_param = NULL;
|
|
||||||
|
|
||||||
/* Push current DMA transaction in the pending queue */
|
|
||||||
ret = dma_submit_error(dmaengine_submit(desc));
|
|
||||||
if (ret) {
|
|
||||||
dmaengine_terminate_sync(stm32port->rx_ch);
|
|
||||||
stm32_usart_of_dma_rx_remove(stm32port, pdev);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Issue pending DMA requests */
|
|
||||||
dma_async_issue_pending(stm32port->rx_ch);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1372,6 +1551,7 @@ static int stm32_usart_serial_remove(struct platform_device *pdev)
|
|||||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||||
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||||
int err;
|
int err;
|
||||||
|
u32 cr3;
|
||||||
|
|
||||||
pm_runtime_get_sync(&pdev->dev);
|
pm_runtime_get_sync(&pdev->dev);
|
||||||
err = uart_remove_one_port(&stm32_usart_driver, port);
|
err = uart_remove_one_port(&stm32_usart_driver, port);
|
||||||
@ -1382,7 +1562,12 @@ static int stm32_usart_serial_remove(struct platform_device *pdev)
|
|||||||
pm_runtime_set_suspended(&pdev->dev);
|
pm_runtime_set_suspended(&pdev->dev);
|
||||||
pm_runtime_put_noidle(&pdev->dev);
|
pm_runtime_put_noidle(&pdev->dev);
|
||||||
|
|
||||||
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR);
|
stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_PEIE);
|
||||||
|
cr3 = readl_relaxed(port->membase + ofs->cr3);
|
||||||
|
cr3 &= ~USART_CR3_EIE;
|
||||||
|
cr3 &= ~USART_CR3_DMAR;
|
||||||
|
cr3 &= ~USART_CR3_DDRE;
|
||||||
|
writel_relaxed(cr3, port->membase + ofs->cr3);
|
||||||
|
|
||||||
if (stm32_port->tx_ch) {
|
if (stm32_port->tx_ch) {
|
||||||
dmaengine_terminate_async(stm32_port->tx_ch);
|
dmaengine_terminate_async(stm32_port->tx_ch);
|
||||||
@ -1391,7 +1576,6 @@ static int stm32_usart_serial_remove(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (stm32_port->rx_ch) {
|
if (stm32_port->rx_ch) {
|
||||||
dmaengine_terminate_async(stm32_port->rx_ch);
|
|
||||||
stm32_usart_of_dma_rx_remove(stm32_port, pdev);
|
stm32_usart_of_dma_rx_remove(stm32_port, pdev);
|
||||||
dma_release_channel(stm32_port->rx_ch);
|
dma_release_channel(stm32_port->rx_ch);
|
||||||
}
|
}
|
||||||
@ -1504,14 +1688,18 @@ static struct uart_driver stm32_usart_driver = {
|
|||||||
.cons = STM32_SERIAL_CONSOLE,
|
.cons = STM32_SERIAL_CONSOLE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port,
|
static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port,
|
||||||
bool enable)
|
bool enable)
|
||||||
{
|
{
|
||||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||||
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||||
|
struct tty_port *tport = &port->state->port;
|
||||||
|
int ret;
|
||||||
|
unsigned int size;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
if (!stm32_port->wakeup_src)
|
if (!stm32_port->wakeup_src || !tty_port_initialized(tport))
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable low-power wake-up and wake-up irq if argument is set to
|
* Enable low-power wake-up and wake-up irq if argument is set to
|
||||||
@ -1520,20 +1708,52 @@ static void __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port,
|
|||||||
if (enable) {
|
if (enable) {
|
||||||
stm32_usart_set_bits(port, ofs->cr1, USART_CR1_UESM);
|
stm32_usart_set_bits(port, ofs->cr1, USART_CR1_UESM);
|
||||||
stm32_usart_set_bits(port, ofs->cr3, USART_CR3_WUFIE);
|
stm32_usart_set_bits(port, ofs->cr3, USART_CR3_WUFIE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When DMA is used for reception, it must be disabled before
|
||||||
|
* entering low-power mode and re-enabled when exiting from
|
||||||
|
* low-power mode.
|
||||||
|
*/
|
||||||
|
if (stm32_port->rx_ch) {
|
||||||
|
spin_lock_irqsave(&port->lock, flags);
|
||||||
|
/* Avoid race with RX IRQ when DMAR is cleared */
|
||||||
|
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR);
|
||||||
|
/* Poll data from DMA RX buffer if any */
|
||||||
|
size = stm32_usart_receive_chars(port, true);
|
||||||
|
dmaengine_terminate_async(stm32_port->rx_ch);
|
||||||
|
uart_unlock_and_check_sysrq_irqrestore(port, flags);
|
||||||
|
if (size)
|
||||||
|
tty_flip_buffer_push(tport);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Poll data from RX FIFO if any */
|
||||||
|
stm32_usart_receive_chars(port, false);
|
||||||
} else {
|
} else {
|
||||||
|
if (stm32_port->rx_ch) {
|
||||||
|
ret = stm32_usart_start_rx_dma_cyclic(port);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_UESM);
|
stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_UESM);
|
||||||
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE);
|
stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __maybe_unused stm32_usart_serial_suspend(struct device *dev)
|
static int __maybe_unused stm32_usart_serial_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct uart_port *port = dev_get_drvdata(dev);
|
struct uart_port *port = dev_get_drvdata(dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
uart_suspend_port(&stm32_usart_driver, port);
|
uart_suspend_port(&stm32_usart_driver, port);
|
||||||
|
|
||||||
if (device_may_wakeup(dev) || device_wakeup_path(dev))
|
if (device_may_wakeup(dev) || device_wakeup_path(dev)) {
|
||||||
stm32_usart_serial_en_wakeup(port, true);
|
ret = stm32_usart_serial_en_wakeup(port, true);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When "no_console_suspend" is enabled, keep the pinctrl default state
|
* When "no_console_suspend" is enabled, keep the pinctrl default state
|
||||||
@ -1554,11 +1774,15 @@ static int __maybe_unused stm32_usart_serial_suspend(struct device *dev)
|
|||||||
static int __maybe_unused stm32_usart_serial_resume(struct device *dev)
|
static int __maybe_unused stm32_usart_serial_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct uart_port *port = dev_get_drvdata(dev);
|
struct uart_port *port = dev_get_drvdata(dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
pinctrl_pm_select_default_state(dev);
|
pinctrl_pm_select_default_state(dev);
|
||||||
|
|
||||||
if (device_may_wakeup(dev) || device_wakeup_path(dev))
|
if (device_may_wakeup(dev) || device_wakeup_path(dev)) {
|
||||||
stm32_usart_serial_en_wakeup(port, false);
|
ret = stm32_usart_serial_en_wakeup(port, false);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
return uart_resume_port(&stm32_usart_driver, port);
|
return uart_resume_port(&stm32_usart_driver, port);
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,7 @@ struct stm32_usart_info stm32h7_info = {
|
|||||||
/* USART_SR (F4) / USART_ISR (F7) */
|
/* USART_SR (F4) / USART_ISR (F7) */
|
||||||
#define USART_SR_PE BIT(0)
|
#define USART_SR_PE BIT(0)
|
||||||
#define USART_SR_FE BIT(1)
|
#define USART_SR_FE BIT(1)
|
||||||
#define USART_SR_NF BIT(2)
|
#define USART_SR_NE BIT(2) /* F7 (NF for F4) */
|
||||||
#define USART_SR_ORE BIT(3)
|
#define USART_SR_ORE BIT(3)
|
||||||
#define USART_SR_IDLE BIT(4)
|
#define USART_SR_IDLE BIT(4)
|
||||||
#define USART_SR_RXNE BIT(5)
|
#define USART_SR_RXNE BIT(5)
|
||||||
@ -126,7 +126,8 @@ struct stm32_usart_info stm32h7_info = {
|
|||||||
#define USART_SR_SBKF BIT(18) /* F7 */
|
#define USART_SR_SBKF BIT(18) /* F7 */
|
||||||
#define USART_SR_WUF BIT(20) /* H7 */
|
#define USART_SR_WUF BIT(20) /* H7 */
|
||||||
#define USART_SR_TEACK BIT(21) /* F7 */
|
#define USART_SR_TEACK BIT(21) /* F7 */
|
||||||
#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_FE | USART_SR_PE)
|
#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_NE | USART_SR_FE |\
|
||||||
|
USART_SR_PE)
|
||||||
/* Dummy bits */
|
/* Dummy bits */
|
||||||
#define USART_SR_DUMMY_RX BIT(16)
|
#define USART_SR_DUMMY_RX BIT(16)
|
||||||
|
|
||||||
@ -246,9 +247,9 @@ struct stm32_usart_info stm32h7_info = {
|
|||||||
#define STM32_SERIAL_NAME "ttySTM"
|
#define STM32_SERIAL_NAME "ttySTM"
|
||||||
#define STM32_MAX_PORTS 8
|
#define STM32_MAX_PORTS 8
|
||||||
|
|
||||||
#define RX_BUF_L 200 /* dma rx buffer length */
|
#define RX_BUF_L 4096 /* dma rx buffer length */
|
||||||
#define RX_BUF_P RX_BUF_L /* dma rx buffer period */
|
#define RX_BUF_P (RX_BUF_L / 2) /* dma rx buffer period */
|
||||||
#define TX_BUF_L 200 /* dma tx buffer length */
|
#define TX_BUF_L RX_BUF_L /* dma tx buffer length */
|
||||||
|
|
||||||
struct stm32_port {
|
struct stm32_port {
|
||||||
struct uart_port port;
|
struct uart_port port;
|
||||||
@ -264,6 +265,7 @@ struct stm32_port {
|
|||||||
u32 cr3_irq; /* USART_CR3_RXFTIE */
|
u32 cr3_irq; /* USART_CR3_RXFTIE */
|
||||||
int last_res;
|
int last_res;
|
||||||
bool tx_dma_busy; /* dma tx busy */
|
bool tx_dma_busy; /* dma tx busy */
|
||||||
|
bool throttled; /* port throttled */
|
||||||
bool hw_flow_control;
|
bool hw_flow_control;
|
||||||
bool swap; /* swap RX & TX pins */
|
bool swap; /* swap RX & TX pins */
|
||||||
bool fifoen;
|
bool fifoen;
|
||||||
@ -272,6 +274,7 @@ struct stm32_port {
|
|||||||
bool wakeup_src;
|
bool wakeup_src;
|
||||||
int rdr_mask; /* receive data register mask */
|
int rdr_mask; /* receive data register mask */
|
||||||
struct mctrl_gpios *gpios; /* modem control gpios */
|
struct mctrl_gpios *gpios; /* modem control gpios */
|
||||||
|
struct dma_tx_state rx_dma_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct stm32_port stm32_ports[STM32_MAX_PORTS];
|
static struct stm32_port stm32_ports[STM32_MAX_PORTS];
|
||||||
|
@ -1125,7 +1125,7 @@ static void sunzilog_free_tables(void)
|
|||||||
|
|
||||||
#define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */
|
#define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */
|
||||||
|
|
||||||
static void sunzilog_putchar(struct uart_port *port, int ch)
|
static void __maybe_unused sunzilog_putchar(struct uart_port *port, int ch)
|
||||||
{
|
{
|
||||||
struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
|
struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
|
||||||
int loops = ZS_PUT_CHAR_MAX_DELAY;
|
int loops = ZS_PUT_CHAR_MAX_DELAY;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/bitfield.h>
|
||||||
#include <linux/console.h>
|
#include <linux/console.h>
|
||||||
#include <linux/serial.h>
|
#include <linux/serial.h>
|
||||||
#include <linux/serial_core.h>
|
#include <linux/serial_core.h>
|
||||||
@ -63,9 +64,18 @@
|
|||||||
static struct uart_port *console_port;
|
static struct uart_port *console_port;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct uartlite_data: Driver private data
|
||||||
|
* reg_ops: Functions to read/write registers
|
||||||
|
* clk: Our parent clock, if present
|
||||||
|
* baud: The baud rate configured when this device was synthesized
|
||||||
|
* cflags: The cflags for parity and data bits
|
||||||
|
*/
|
||||||
struct uartlite_data {
|
struct uartlite_data {
|
||||||
const struct uartlite_reg_ops *reg_ops;
|
const struct uartlite_reg_ops *reg_ops;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
|
unsigned int baud;
|
||||||
|
tcflag_t cflags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct uartlite_reg_ops {
|
struct uartlite_reg_ops {
|
||||||
@ -119,6 +129,8 @@ static inline void uart_out32(u32 val, u32 offset, struct uart_port *port)
|
|||||||
|
|
||||||
static struct uart_port ulite_ports[ULITE_NR_UARTS];
|
static struct uart_port ulite_ports[ULITE_NR_UARTS];
|
||||||
|
|
||||||
|
static struct uart_driver ulite_uart_driver;
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------
|
/* ---------------------------------------------------------------------
|
||||||
* Core UART driver operations
|
* Core UART driver operations
|
||||||
*/
|
*/
|
||||||
@ -306,7 +318,12 @@ static void ulite_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||||||
struct ktermios *old)
|
struct ktermios *old)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned int baud;
|
struct uartlite_data *pdata = port->private_data;
|
||||||
|
|
||||||
|
/* Set termios to what the hardware supports */
|
||||||
|
termios->c_cflag &= ~(BRKINT | CSTOPB | PARENB | PARODD | CSIZE);
|
||||||
|
termios->c_cflag |= pdata->cflags & (PARENB | PARODD | CSIZE);
|
||||||
|
tty_termios_encode_baud_rate(termios, pdata->baud, pdata->baud);
|
||||||
|
|
||||||
spin_lock_irqsave(&port->lock, flags);
|
spin_lock_irqsave(&port->lock, flags);
|
||||||
|
|
||||||
@ -329,8 +346,7 @@ static void ulite_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||||||
| ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
|
| ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
|
||||||
|
|
||||||
/* update timeout */
|
/* update timeout */
|
||||||
baud = uart_get_baud_rate(port, termios, old, 0, 460800);
|
uart_update_timeout(port, termios->c_cflag, pdata->baud);
|
||||||
uart_update_timeout(port, termios->c_cflag, baud);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&port->lock, flags);
|
spin_unlock_irqrestore(&port->lock, flags);
|
||||||
}
|
}
|
||||||
@ -532,8 +548,6 @@ static int ulite_console_setup(struct console *co, char *options)
|
|||||||
return uart_set_options(port, co, baud, parity, bits, flow);
|
return uart_set_options(port, co, baud, parity, bits, flow);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct uart_driver ulite_uart_driver;
|
|
||||||
|
|
||||||
static struct console ulite_console = {
|
static struct console ulite_console = {
|
||||||
.name = ULITE_NAME,
|
.name = ULITE_NAME,
|
||||||
.write = ulite_console_write,
|
.write = ulite_console_write,
|
||||||
@ -765,18 +779,73 @@ static int ulite_probe(struct platform_device *pdev)
|
|||||||
struct uartlite_data *pdata;
|
struct uartlite_data *pdata;
|
||||||
int irq, ret;
|
int irq, ret;
|
||||||
int id = pdev->id;
|
int id = pdev->id;
|
||||||
#ifdef CONFIG_OF
|
|
||||||
const __be32 *prop;
|
|
||||||
|
|
||||||
prop = of_get_property(pdev->dev.of_node, "port-number", NULL);
|
|
||||||
if (prop)
|
|
||||||
id = be32_to_cpup(prop);
|
|
||||||
#endif
|
|
||||||
pdata = devm_kzalloc(&pdev->dev, sizeof(struct uartlite_data),
|
pdata = devm_kzalloc(&pdev->dev, sizeof(struct uartlite_data),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!pdata)
|
if (!pdata)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_OF)) {
|
||||||
|
const char *prop;
|
||||||
|
struct device_node *np = pdev->dev.of_node;
|
||||||
|
u32 val = 0;
|
||||||
|
|
||||||
|
prop = "port-number";
|
||||||
|
ret = of_property_read_u32(np, prop, &id);
|
||||||
|
if (ret && ret != -EINVAL)
|
||||||
|
of_err:
|
||||||
|
return dev_err_probe(&pdev->dev, ret,
|
||||||
|
"could not read %s\n", prop);
|
||||||
|
|
||||||
|
prop = "current-speed";
|
||||||
|
ret = of_property_read_u32(np, prop, &pdata->baud);
|
||||||
|
if (ret)
|
||||||
|
goto of_err;
|
||||||
|
|
||||||
|
prop = "xlnx,use-parity";
|
||||||
|
ret = of_property_read_u32(np, prop, &val);
|
||||||
|
if (ret && ret != -EINVAL)
|
||||||
|
goto of_err;
|
||||||
|
|
||||||
|
if (val) {
|
||||||
|
prop = "xlnx,odd-parity";
|
||||||
|
ret = of_property_read_u32(np, prop, &val);
|
||||||
|
if (ret)
|
||||||
|
goto of_err;
|
||||||
|
|
||||||
|
if (val)
|
||||||
|
pdata->cflags |= PARODD;
|
||||||
|
pdata->cflags |= PARENB;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = 8;
|
||||||
|
prop = "xlnx,data-bits";
|
||||||
|
ret = of_property_read_u32(np, prop, &val);
|
||||||
|
if (ret && ret != -EINVAL)
|
||||||
|
goto of_err;
|
||||||
|
|
||||||
|
switch (val) {
|
||||||
|
case 5:
|
||||||
|
pdata->cflags |= CS5;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
pdata->cflags |= CS6;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
pdata->cflags |= CS7;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
pdata->cflags |= CS8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||||
|
"bad data bits %d\n", val);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pdata->baud = 9600;
|
||||||
|
pdata->cflags = CS8;
|
||||||
|
}
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
if (!res)
|
if (!res)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
@ -601,9 +601,10 @@ static void cdns_uart_start_tx(struct uart_port *port)
|
|||||||
if (uart_circ_empty(&port->state->xmit))
|
if (uart_circ_empty(&port->state->xmit))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR);
|
||||||
|
|
||||||
cdns_uart_handle_tx(port);
|
cdns_uart_handle_tx(port);
|
||||||
|
|
||||||
writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_ISR);
|
|
||||||
/* Enable the TX Empty interrupt */
|
/* Enable the TX Empty interrupt */
|
||||||
writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER);
|
writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IER);
|
||||||
}
|
}
|
||||||
|
@ -843,6 +843,8 @@ static bool sysrq_handle_keypress(struct sysrq_state *sysrq,
|
|||||||
sysrq->shift = KEY_RESERVED;
|
sysrq->shift = KEY_RESERVED;
|
||||||
else if (value != 2)
|
else if (value != 2)
|
||||||
sysrq->shift = code;
|
sysrq->shift = code;
|
||||||
|
if (sysrq->active)
|
||||||
|
sysrq->shift_use = sysrq->shift;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY_SYSRQ:
|
case KEY_SYSRQ:
|
||||||
|
@ -154,7 +154,7 @@ void tty_termios_encode_baud_rate(struct ktermios *termios,
|
|||||||
termios->c_ospeed = obaud;
|
termios->c_ospeed = obaud;
|
||||||
|
|
||||||
#ifdef IBSHIFT
|
#ifdef IBSHIFT
|
||||||
if ((termios->c_cflag >> IBSHIFT) & CBAUD)
|
if (((termios->c_cflag >> IBSHIFT) & CBAUD) != B0)
|
||||||
ibinput = 1; /* An input speed was specified */
|
ibinput = 1; /* An input speed was specified */
|
||||||
#endif
|
#endif
|
||||||
#ifdef BOTHER
|
#ifdef BOTHER
|
||||||
|
@ -544,6 +544,9 @@ static void flush_to_ldisc(struct work_struct *work)
|
|||||||
if (!count)
|
if (!count)
|
||||||
break;
|
break;
|
||||||
head->read += count;
|
head->read += count;
|
||||||
|
|
||||||
|
if (need_resched())
|
||||||
|
cond_resched();
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&buf->lock);
|
mutex_unlock(&buf->lock);
|
||||||
|
@ -675,7 +675,6 @@ static int tty_change_softcar(struct tty_struct *tty, int arg)
|
|||||||
/**
|
/**
|
||||||
* tty_mode_ioctl - mode related ioctls
|
* tty_mode_ioctl - mode related ioctls
|
||||||
* @tty: tty for the ioctl
|
* @tty: tty for the ioctl
|
||||||
* @file: file pointer for the tty
|
|
||||||
* @cmd: command
|
* @cmd: command
|
||||||
* @arg: ioctl argument
|
* @arg: ioctl argument
|
||||||
*
|
*
|
||||||
@ -684,16 +683,13 @@ static int tty_change_softcar(struct tty_struct *tty, int arg)
|
|||||||
* consistent mode setting.
|
* consistent mode setting.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
|
int tty_mode_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
|
||||||
unsigned int cmd, unsigned long arg)
|
|
||||||
{
|
{
|
||||||
struct tty_struct *real_tty;
|
struct tty_struct *real_tty;
|
||||||
void __user *p = (void __user *)arg;
|
void __user *p = (void __user *)arg;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct ktermios kterm;
|
struct ktermios kterm;
|
||||||
|
|
||||||
BUG_ON(file == NULL);
|
|
||||||
|
|
||||||
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||||
tty->driver->subtype == PTY_TYPE_MASTER)
|
tty->driver->subtype == PTY_TYPE_MASTER)
|
||||||
real_tty = tty->link;
|
real_tty = tty->link;
|
||||||
@ -858,8 +854,8 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(tty_perform_flush);
|
EXPORT_SYMBOL_GPL(tty_perform_flush);
|
||||||
|
|
||||||
int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
|
int n_tty_ioctl_helper(struct tty_struct *tty, unsigned int cmd,
|
||||||
unsigned int cmd, unsigned long arg)
|
unsigned long arg)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
@ -904,7 +900,7 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
|
|||||||
return __tty_perform_flush(tty, arg);
|
return __tty_perform_flush(tty, arg);
|
||||||
default:
|
default:
|
||||||
/* Try the mode commands */
|
/* Try the mode commands */
|
||||||
return tty_mode_ioctl(tty, file, cmd, arg);
|
return tty_mode_ioctl(tty, cmd, arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(n_tty_ioctl_helper);
|
EXPORT_SYMBOL(n_tty_ioctl_helper);
|
||||||
|
@ -149,6 +149,8 @@ struct console {
|
|||||||
short flags;
|
short flags;
|
||||||
short index;
|
short index;
|
||||||
int cflag;
|
int cflag;
|
||||||
|
uint ispeed;
|
||||||
|
uint ospeed;
|
||||||
void *data;
|
void *data;
|
||||||
struct console *next;
|
struct console *next;
|
||||||
};
|
};
|
||||||
|
@ -186,6 +186,8 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
|
|||||||
__poll_t rpmsg_poll(struct rpmsg_endpoint *ept, struct file *filp,
|
__poll_t rpmsg_poll(struct rpmsg_endpoint *ept, struct file *filp,
|
||||||
poll_table *wait);
|
poll_table *wait);
|
||||||
|
|
||||||
|
ssize_t rpmsg_get_mtu(struct rpmsg_endpoint *ept);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static inline int rpmsg_register_device(struct rpmsg_device *rpdev)
|
static inline int rpmsg_register_device(struct rpmsg_device *rpdev)
|
||||||
@ -296,6 +298,14 @@ static inline __poll_t rpmsg_poll(struct rpmsg_endpoint *ept,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline ssize_t rpmsg_get_mtu(struct rpmsg_endpoint *ept)
|
||||||
|
{
|
||||||
|
/* This shouldn't be possible */
|
||||||
|
WARN_ON(1);
|
||||||
|
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* IS_ENABLED(CONFIG_RPMSG) */
|
#endif /* IS_ENABLED(CONFIG_RPMSG) */
|
||||||
|
|
||||||
/* use a macro to avoid include chaining to get THIS_MODULE */
|
/* use a macro to avoid include chaining to get THIS_MODULE */
|
||||||
|
@ -252,20 +252,20 @@ static inline bool tty_throttled(struct tty_struct *tty)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_TTY
|
#ifdef CONFIG_TTY
|
||||||
extern void tty_kref_put(struct tty_struct *tty);
|
void tty_kref_put(struct tty_struct *tty);
|
||||||
extern struct pid *tty_get_pgrp(struct tty_struct *tty);
|
struct pid *tty_get_pgrp(struct tty_struct *tty);
|
||||||
extern void tty_vhangup_self(void);
|
void tty_vhangup_self(void);
|
||||||
extern void disassociate_ctty(int priv);
|
void disassociate_ctty(int priv);
|
||||||
extern dev_t tty_devnum(struct tty_struct *tty);
|
dev_t tty_devnum(struct tty_struct *tty);
|
||||||
extern void proc_clear_tty(struct task_struct *p);
|
void proc_clear_tty(struct task_struct *p);
|
||||||
extern struct tty_struct *get_current_tty(void);
|
struct tty_struct *get_current_tty(void);
|
||||||
/* tty_io.c */
|
/* tty_io.c */
|
||||||
extern int __init tty_init(void);
|
int __init tty_init(void);
|
||||||
extern const char *tty_name(const struct tty_struct *tty);
|
const char *tty_name(const struct tty_struct *tty);
|
||||||
extern struct tty_struct *tty_kopen_exclusive(dev_t device);
|
struct tty_struct *tty_kopen_exclusive(dev_t device);
|
||||||
extern struct tty_struct *tty_kopen_shared(dev_t device);
|
struct tty_struct *tty_kopen_shared(dev_t device);
|
||||||
extern void tty_kclose(struct tty_struct *tty);
|
void tty_kclose(struct tty_struct *tty);
|
||||||
extern int tty_dev_name_to_number(const char *name, dev_t *number);
|
int tty_dev_name_to_number(const char *name, dev_t *number);
|
||||||
#else
|
#else
|
||||||
static inline void tty_kref_put(struct tty_struct *tty)
|
static inline void tty_kref_put(struct tty_struct *tty)
|
||||||
{ }
|
{ }
|
||||||
@ -296,7 +296,7 @@ static inline int tty_dev_name_to_number(const char *name, dev_t *number)
|
|||||||
|
|
||||||
extern struct ktermios tty_std_termios;
|
extern struct ktermios tty_std_termios;
|
||||||
|
|
||||||
extern int vcs_init(void);
|
int vcs_init(void);
|
||||||
|
|
||||||
extern struct class *tty_class;
|
extern struct class *tty_class;
|
||||||
|
|
||||||
@ -316,34 +316,34 @@ static inline struct tty_struct *tty_kref_get(struct tty_struct *tty)
|
|||||||
return tty;
|
return tty;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern const char *tty_driver_name(const struct tty_struct *tty);
|
const char *tty_driver_name(const struct tty_struct *tty);
|
||||||
extern void tty_wait_until_sent(struct tty_struct *tty, long timeout);
|
void tty_wait_until_sent(struct tty_struct *tty, long timeout);
|
||||||
extern void stop_tty(struct tty_struct *tty);
|
void stop_tty(struct tty_struct *tty);
|
||||||
extern void start_tty(struct tty_struct *tty);
|
void start_tty(struct tty_struct *tty);
|
||||||
extern void tty_write_message(struct tty_struct *tty, char *msg);
|
void tty_write_message(struct tty_struct *tty, char *msg);
|
||||||
extern int tty_send_xchar(struct tty_struct *tty, char ch);
|
int tty_send_xchar(struct tty_struct *tty, char ch);
|
||||||
extern int tty_put_char(struct tty_struct *tty, unsigned char c);
|
int tty_put_char(struct tty_struct *tty, unsigned char c);
|
||||||
extern unsigned int tty_chars_in_buffer(struct tty_struct *tty);
|
unsigned int tty_chars_in_buffer(struct tty_struct *tty);
|
||||||
extern unsigned int tty_write_room(struct tty_struct *tty);
|
unsigned int tty_write_room(struct tty_struct *tty);
|
||||||
extern void tty_driver_flush_buffer(struct tty_struct *tty);
|
void tty_driver_flush_buffer(struct tty_struct *tty);
|
||||||
extern void tty_unthrottle(struct tty_struct *tty);
|
void tty_unthrottle(struct tty_struct *tty);
|
||||||
extern int tty_throttle_safe(struct tty_struct *tty);
|
int tty_throttle_safe(struct tty_struct *tty);
|
||||||
extern int tty_unthrottle_safe(struct tty_struct *tty);
|
int tty_unthrottle_safe(struct tty_struct *tty);
|
||||||
extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws);
|
int tty_do_resize(struct tty_struct *tty, struct winsize *ws);
|
||||||
extern int tty_get_icount(struct tty_struct *tty,
|
int tty_get_icount(struct tty_struct *tty,
|
||||||
struct serial_icounter_struct *icount);
|
struct serial_icounter_struct *icount);
|
||||||
extern int is_current_pgrp_orphaned(void);
|
int is_current_pgrp_orphaned(void);
|
||||||
extern void tty_hangup(struct tty_struct *tty);
|
void tty_hangup(struct tty_struct *tty);
|
||||||
extern void tty_vhangup(struct tty_struct *tty);
|
void tty_vhangup(struct tty_struct *tty);
|
||||||
extern int tty_hung_up_p(struct file *filp);
|
int tty_hung_up_p(struct file *filp);
|
||||||
extern void do_SAK(struct tty_struct *tty);
|
void do_SAK(struct tty_struct *tty);
|
||||||
extern void __do_SAK(struct tty_struct *tty);
|
void __do_SAK(struct tty_struct *tty);
|
||||||
extern void no_tty(void);
|
void no_tty(void);
|
||||||
extern speed_t tty_termios_baud_rate(struct ktermios *termios);
|
speed_t tty_termios_baud_rate(struct ktermios *termios);
|
||||||
extern void tty_termios_encode_baud_rate(struct ktermios *termios,
|
void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud,
|
||||||
speed_t ibaud, speed_t obaud);
|
speed_t obaud);
|
||||||
extern void tty_encode_baud_rate(struct tty_struct *tty,
|
void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud,
|
||||||
speed_t ibaud, speed_t obaud);
|
speed_t obaud);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tty_get_baud_rate - get tty bit rates
|
* tty_get_baud_rate - get tty bit rates
|
||||||
@ -363,37 +363,36 @@ static inline speed_t tty_get_baud_rate(struct tty_struct *tty)
|
|||||||
unsigned char tty_get_char_size(unsigned int cflag);
|
unsigned char tty_get_char_size(unsigned int cflag);
|
||||||
unsigned char tty_get_frame_size(unsigned int cflag);
|
unsigned char tty_get_frame_size(unsigned int cflag);
|
||||||
|
|
||||||
extern void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old);
|
void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old);
|
||||||
extern int tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b);
|
int tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b);
|
||||||
extern int tty_set_termios(struct tty_struct *tty, struct ktermios *kt);
|
int tty_set_termios(struct tty_struct *tty, struct ktermios *kt);
|
||||||
|
|
||||||
extern void tty_wakeup(struct tty_struct *tty);
|
void tty_wakeup(struct tty_struct *tty);
|
||||||
|
|
||||||
extern int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
|
int tty_mode_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg);
|
||||||
unsigned int cmd, unsigned long arg);
|
int tty_perform_flush(struct tty_struct *tty, unsigned long arg);
|
||||||
extern int tty_perform_flush(struct tty_struct *tty, unsigned long arg);
|
struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx);
|
||||||
extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx);
|
void tty_release_struct(struct tty_struct *tty, int idx);
|
||||||
extern void tty_release_struct(struct tty_struct *tty, int idx);
|
void tty_init_termios(struct tty_struct *tty);
|
||||||
extern void tty_init_termios(struct tty_struct *tty);
|
void tty_save_termios(struct tty_struct *tty);
|
||||||
extern void tty_save_termios(struct tty_struct *tty);
|
int tty_standard_install(struct tty_driver *driver,
|
||||||
extern int tty_standard_install(struct tty_driver *driver,
|
|
||||||
struct tty_struct *tty);
|
struct tty_struct *tty);
|
||||||
|
|
||||||
extern struct mutex tty_mutex;
|
extern struct mutex tty_mutex;
|
||||||
|
|
||||||
/* n_tty.c */
|
/* n_tty.c */
|
||||||
extern void n_tty_inherit_ops(struct tty_ldisc_ops *ops);
|
void n_tty_inherit_ops(struct tty_ldisc_ops *ops);
|
||||||
#ifdef CONFIG_TTY
|
#ifdef CONFIG_TTY
|
||||||
extern void __init n_tty_init(void);
|
void __init n_tty_init(void);
|
||||||
#else
|
#else
|
||||||
static inline void n_tty_init(void) { }
|
static inline void n_tty_init(void) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* tty_audit.c */
|
/* tty_audit.c */
|
||||||
#ifdef CONFIG_AUDIT
|
#ifdef CONFIG_AUDIT
|
||||||
extern void tty_audit_exit(void);
|
void tty_audit_exit(void);
|
||||||
extern void tty_audit_fork(struct signal_struct *sig);
|
void tty_audit_fork(struct signal_struct *sig);
|
||||||
extern int tty_audit_push(void);
|
int tty_audit_push(void);
|
||||||
#else
|
#else
|
||||||
static inline void tty_audit_exit(void)
|
static inline void tty_audit_exit(void)
|
||||||
{
|
{
|
||||||
@ -408,24 +407,23 @@ static inline int tty_audit_push(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* tty_ioctl.c */
|
/* tty_ioctl.c */
|
||||||
extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
|
int n_tty_ioctl_helper(struct tty_struct *tty, unsigned int cmd,
|
||||||
unsigned int cmd, unsigned long arg);
|
unsigned long arg);
|
||||||
|
|
||||||
/* vt.c */
|
/* vt.c */
|
||||||
|
|
||||||
extern int vt_ioctl(struct tty_struct *tty,
|
int vt_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg);
|
||||||
unsigned int cmd, unsigned long arg);
|
|
||||||
|
|
||||||
extern long vt_compat_ioctl(struct tty_struct *tty,
|
long vt_compat_ioctl(struct tty_struct *tty, unsigned int cmd,
|
||||||
unsigned int cmd, unsigned long arg);
|
unsigned long arg);
|
||||||
|
|
||||||
/* tty_mutex.c */
|
/* tty_mutex.c */
|
||||||
/* functions for preparation of BKL removal */
|
/* functions for preparation of BKL removal */
|
||||||
extern void tty_lock(struct tty_struct *tty);
|
void tty_lock(struct tty_struct *tty);
|
||||||
extern int tty_lock_interruptible(struct tty_struct *tty);
|
int tty_lock_interruptible(struct tty_struct *tty);
|
||||||
extern void tty_unlock(struct tty_struct *tty);
|
void tty_unlock(struct tty_struct *tty);
|
||||||
extern void tty_lock_slave(struct tty_struct *tty);
|
void tty_lock_slave(struct tty_struct *tty);
|
||||||
extern void tty_unlock_slave(struct tty_struct *tty);
|
void tty_unlock_slave(struct tty_struct *tty);
|
||||||
extern void tty_set_lock_subclass(struct tty_struct *tty);
|
void tty_set_lock_subclass(struct tty_struct *tty);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -327,11 +327,11 @@ struct tty_driver {
|
|||||||
|
|
||||||
extern struct list_head tty_drivers;
|
extern struct list_head tty_drivers;
|
||||||
|
|
||||||
extern struct tty_driver *__tty_alloc_driver(unsigned int lines,
|
struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
|
||||||
struct module *owner, unsigned long flags);
|
unsigned long flags);
|
||||||
extern struct tty_driver *tty_find_polling_driver(char *name, int *line);
|
struct tty_driver *tty_find_polling_driver(char *name, int *line);
|
||||||
|
|
||||||
extern void tty_driver_kref_put(struct tty_driver *driver);
|
void tty_driver_kref_put(struct tty_driver *driver);
|
||||||
|
|
||||||
/* Use TTY_DRIVER_* flags below */
|
/* Use TTY_DRIVER_* flags below */
|
||||||
#define tty_alloc_driver(lines, flags) \
|
#define tty_alloc_driver(lines, flags) \
|
||||||
@ -360,7 +360,7 @@ static inline void tty_set_operations(struct tty_driver *driver,
|
|||||||
* Used for PTY's, in particular.
|
* Used for PTY's, in particular.
|
||||||
*
|
*
|
||||||
* TTY_DRIVER_REAL_RAW --- if set, indicates that the driver will
|
* TTY_DRIVER_REAL_RAW --- if set, indicates that the driver will
|
||||||
* guarantee never not to set any special character handling
|
* guarantee never to set any special character handling
|
||||||
* flags if ((IGNBRK || (!BRKINT && !PARMRK)) && (IGNPAR ||
|
* flags if ((IGNBRK || (!BRKINT && !PARMRK)) && (IGNPAR ||
|
||||||
* !INPCK)). That is, if there is no reason for the driver to
|
* !INPCK)). That is, if there is no reason for the driver to
|
||||||
* send notifications of parity and break characters up to the
|
* send notifications of parity and break characters up to the
|
||||||
|
@ -7,16 +7,16 @@
|
|||||||
|
|
||||||
struct tty_ldisc;
|
struct tty_ldisc;
|
||||||
|
|
||||||
extern int tty_buffer_set_limit(struct tty_port *port, int limit);
|
int tty_buffer_set_limit(struct tty_port *port, int limit);
|
||||||
extern unsigned int tty_buffer_space_avail(struct tty_port *port);
|
unsigned int tty_buffer_space_avail(struct tty_port *port);
|
||||||
extern int tty_buffer_request_room(struct tty_port *port, size_t size);
|
int tty_buffer_request_room(struct tty_port *port, size_t size);
|
||||||
extern int tty_insert_flip_string_flags(struct tty_port *port,
|
int tty_insert_flip_string_flags(struct tty_port *port,
|
||||||
const unsigned char *chars, const char *flags, size_t size);
|
const unsigned char *chars, const char *flags, size_t size);
|
||||||
extern int tty_insert_flip_string_fixed_flag(struct tty_port *port,
|
int tty_insert_flip_string_fixed_flag(struct tty_port *port,
|
||||||
const unsigned char *chars, char flag, size_t size);
|
const unsigned char *chars, char flag, size_t size);
|
||||||
extern int tty_prepare_flip_string(struct tty_port *port,
|
int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars,
|
||||||
unsigned char **chars, size_t size);
|
size_t size);
|
||||||
extern void tty_flip_buffer_push(struct tty_port *port);
|
void tty_flip_buffer_push(struct tty_port *port);
|
||||||
void tty_schedule_flip(struct tty_port *port);
|
void tty_schedule_flip(struct tty_port *port);
|
||||||
int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag);
|
int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag);
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ static inline int tty_insert_flip_string(struct tty_port *port,
|
|||||||
int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p,
|
int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p,
|
||||||
const char *f, int count);
|
const char *f, int count);
|
||||||
|
|
||||||
extern void tty_buffer_lock_exclusive(struct tty_port *port);
|
void tty_buffer_lock_exclusive(struct tty_port *port);
|
||||||
extern void tty_buffer_unlock_exclusive(struct tty_port *port);
|
void tty_buffer_unlock_exclusive(struct tty_port *port);
|
||||||
|
|
||||||
#endif /* _LINUX_TTY_FLIP_H */
|
#endif /* _LINUX_TTY_FLIP_H */
|
||||||
|
@ -146,7 +146,7 @@ struct ld_semaphore {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void __init_ldsem(struct ld_semaphore *sem, const char *name,
|
void __init_ldsem(struct ld_semaphore *sem, const char *name,
|
||||||
struct lock_class_key *key);
|
struct lock_class_key *key);
|
||||||
|
|
||||||
#define init_ldsem(sem) \
|
#define init_ldsem(sem) \
|
||||||
@ -157,18 +157,18 @@ do { \
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
extern int ldsem_down_read(struct ld_semaphore *sem, long timeout);
|
int ldsem_down_read(struct ld_semaphore *sem, long timeout);
|
||||||
extern int ldsem_down_read_trylock(struct ld_semaphore *sem);
|
int ldsem_down_read_trylock(struct ld_semaphore *sem);
|
||||||
extern int ldsem_down_write(struct ld_semaphore *sem, long timeout);
|
int ldsem_down_write(struct ld_semaphore *sem, long timeout);
|
||||||
extern int ldsem_down_write_trylock(struct ld_semaphore *sem);
|
int ldsem_down_write_trylock(struct ld_semaphore *sem);
|
||||||
extern void ldsem_up_read(struct ld_semaphore *sem);
|
void ldsem_up_read(struct ld_semaphore *sem);
|
||||||
extern void ldsem_up_write(struct ld_semaphore *sem);
|
void ldsem_up_write(struct ld_semaphore *sem);
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||||
extern int ldsem_down_read_nested(struct ld_semaphore *sem, int subclass,
|
int ldsem_down_read_nested(struct ld_semaphore *sem, int subclass,
|
||||||
long timeout);
|
long timeout);
|
||||||
extern int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass,
|
int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass,
|
||||||
long timeout);
|
long timeout);
|
||||||
#else
|
#else
|
||||||
# define ldsem_down_read_nested(sem, subclass, timeout) \
|
# define ldsem_down_read_nested(sem, subclass, timeout) \
|
||||||
ldsem_down_read(sem, timeout)
|
ldsem_down_read(sem, timeout)
|
||||||
@ -180,7 +180,6 @@ extern int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass,
|
|||||||
struct tty_ldisc_ops {
|
struct tty_ldisc_ops {
|
||||||
char *name;
|
char *name;
|
||||||
int num;
|
int num;
|
||||||
int flags;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following routines are called from above.
|
* The following routines are called from above.
|
||||||
@ -200,7 +199,7 @@ struct tty_ldisc_ops {
|
|||||||
void (*set_termios)(struct tty_struct *tty, struct ktermios *old);
|
void (*set_termios)(struct tty_struct *tty, struct ktermios *old);
|
||||||
__poll_t (*poll)(struct tty_struct *, struct file *,
|
__poll_t (*poll)(struct tty_struct *, struct file *,
|
||||||
struct poll_table_struct *);
|
struct poll_table_struct *);
|
||||||
int (*hangup)(struct tty_struct *tty);
|
void (*hangup)(struct tty_struct *tty);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following routines are called from below.
|
* The following routines are called from below.
|
||||||
@ -220,8 +219,6 @@ struct tty_ldisc {
|
|||||||
struct tty_struct *tty;
|
struct tty_struct *tty;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define LDISC_FLAG_DEFINED 0x00000001
|
|
||||||
|
|
||||||
#define MODULE_ALIAS_LDISC(ldisc) \
|
#define MODULE_ALIAS_LDISC(ldisc) \
|
||||||
MODULE_ALIAS("tty-ldisc-" __stringify(ldisc))
|
MODULE_ALIAS("tty-ldisc-" __stringify(ldisc))
|
||||||
|
|
||||||
|
@ -337,7 +337,7 @@ static int nci_uart_tty_ioctl(struct tty_struct *tty, struct file *file,
|
|||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
err = n_tty_ioctl_helper(tty, file, cmd, arg);
|
err = n_tty_ioctl_helper(tty, cmd, arg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,10 +252,9 @@ static void v253_close(struct tty_struct *tty)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Line discipline .hangup() */
|
/* Line discipline .hangup() */
|
||||||
static int v253_hangup(struct tty_struct *tty)
|
static void v253_hangup(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
v253_close(tty);
|
v253_close(tty);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Line discipline .receive_buf() */
|
/* Line discipline .receive_buf() */
|
||||||
|
@ -330,10 +330,9 @@ static void cx81801_close(struct tty_struct *tty)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Line discipline .hangup() */
|
/* Line discipline .hangup() */
|
||||||
static int cx81801_hangup(struct tty_struct *tty)
|
static void cx81801_hangup(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
cx81801_close(tty);
|
cx81801_close(tty);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Line discipline .receive_buf() */
|
/* Line discipline .receive_buf() */
|
||||||
|
Loading…
Reference in New Issue
Block a user