mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
TTY/Serial patches for 4.13-rc1
Here is the large tty/serial patchset for 4.13-rc1. A lot of tty and serial driver updates are in here, along with some fixups for some __get/put_user usages that were reported. Nothing huge, just lots of development by a number of different developers, full details in the shortlog. All of these have been in linux-next for a while. There will be a merge issue with the arm-soc tree in the include/linux/platform_data/atmel.h file. Stephen has sent out a fixup for it, so it shouldn't be that difficult to merge. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWVpZ9w8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ylkTgCfV2HhbxIph/aEL1nJmwW64oCXFrMAoK59ZH65 tBZIosv0d91K1A+mObBT =adPL -----END PGP SIGNATURE----- Merge tag 'tty-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty/serial updates from Greg KH: "Here is the large tty/serial patchset for 4.13-rc1. A lot of tty and serial driver updates are in here, along with some fixups for some __get/put_user usages that were reported. Nothing huge, just lots of development by a number of different developers, full details in the shortlog. All of these have been in linux-next for a while" * tag 'tty-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (71 commits) tty: serial: lpuart: add a more accurate baud rate calculation method tty: serial: lpuart: add earlycon support for imx7ulp tty: serial: lpuart: add imx7ulp support dt-bindings: serial: fsl-lpuart: add i.MX7ULP support tty: serial: lpuart: add little endian 32 bit register support tty: serial: lpuart: refactor lpuart32_{read|write} prototype tty: serial: lpuart: introduce lpuart_soc_data to represent SoC property serial: imx-serial - move DMA buffer configuration to DT serial: imx: Enable RTSD only when needed serial: imx: Remove unused members from imx_port struct serial: 8250: 8250_omap: Fix race b/w dma completion and RX timeout serial: 8250: Fix THRE flag usage for CAP_MINI tty/serial: meson_uart: update to stable bindings dt-bindings: serial: Add bindings for the Amlogic Meson UARTs serial: Delete dead code for CIR serial ports serial: sirf: make of_device_ids const serial/mpsc: switch to dma_alloc_attrs tty: serial: Add Actions Semi Owl UART earlycon dt-bindings: serial: Document Actions Semi Owl UARTs tty/serial: atmel: make the driver DT only ...
This commit is contained in:
commit
9a715cd543
15
Documentation/ABI/stable/sysfs-driver-aspeed-vuart
Normal file
15
Documentation/ABI/stable/sysfs-driver-aspeed-vuart
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
What: /sys/bus/platform/drivers/aspeed-vuart/*/lpc_address
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Jeremy Kerr <jk@ozlabs.org>
|
||||||
|
Description: Configures which IO port the host side of the UART
|
||||||
|
will appear on the host <-> BMC LPC bus.
|
||||||
|
Users: OpenBMC. Proposed changes should be mailed to
|
||||||
|
openbmc@lists.ozlabs.org
|
||||||
|
|
||||||
|
What: /sys/bus/platform/drivers/aspeed-vuart*/sirq
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Jeremy Kerr <jk@ozlabs.org>
|
||||||
|
Description: Configures which interrupt number the host side of
|
||||||
|
the UART will appear on the host <-> BMC LPC bus.
|
||||||
|
Users: OpenBMC. Proposed changes should be mailed to
|
||||||
|
openbmc@lists.ozlabs.org
|
@ -954,6 +954,12 @@
|
|||||||
must already be setup and configured. Options are not
|
must already be setup and configured. Options are not
|
||||||
yet supported.
|
yet supported.
|
||||||
|
|
||||||
|
owl,<addr>
|
||||||
|
Start an early, polled-mode console on a serial port
|
||||||
|
of an Actions Semi SoC, such as S500 or S900, at the
|
||||||
|
specified address. The serial port must already be
|
||||||
|
setup and configured. Options are not yet supported.
|
||||||
|
|
||||||
smh Use ARM semihosting calls for early console.
|
smh Use ARM semihosting calls for early console.
|
||||||
|
|
||||||
s3c2410,<addr>
|
s3c2410,<addr>
|
||||||
|
@ -20,6 +20,8 @@ Required properties:
|
|||||||
- "fsl,16550-FIFO64"
|
- "fsl,16550-FIFO64"
|
||||||
- "fsl,ns16550"
|
- "fsl,ns16550"
|
||||||
- "ti,da830-uart"
|
- "ti,da830-uart"
|
||||||
|
- "aspeed,ast2400-vuart"
|
||||||
|
- "aspeed,ast2500-vuart"
|
||||||
- "serial" if the port type is unknown.
|
- "serial" if the port type is unknown.
|
||||||
- reg : offset and length of the register set for the device.
|
- reg : offset and length of the register set for the device.
|
||||||
- interrupts : should contain uart interrupt.
|
- interrupts : should contain uart interrupt.
|
||||||
@ -45,6 +47,7 @@ Optional properties:
|
|||||||
property.
|
property.
|
||||||
- tx-threshold: Specify the TX FIFO low water indication for parts with
|
- tx-threshold: Specify the TX FIFO low water indication for parts with
|
||||||
programmable TX FIFO thresholds.
|
programmable TX FIFO thresholds.
|
||||||
|
- resets : phandle + reset specifier pairs
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
* fsl,ns16550:
|
* fsl,ns16550:
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
Actions Semi Owl UART
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible : "actions,s500-uart", "actions,owl-uart" for S500
|
||||||
|
"actions,s900-uart", "actions,owl-uart" for S900
|
||||||
|
- reg : Offset and length of the register set for the device.
|
||||||
|
- interrupts : Should contain UART interrupt.
|
||||||
|
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
uart3: serial@b0126000 {
|
||||||
|
compatible = "actions,s500-uart", "actions,owl-uart";
|
||||||
|
reg = <0xb0126000 0x1000>;
|
||||||
|
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
};
|
@ -0,0 +1,38 @@
|
|||||||
|
Amlogic Meson SoC UART Serial Interface
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
The Amlogic Meson SoC UART Serial Interface is present on a large range
|
||||||
|
of SoCs, and can be present either in the "Always-On" power domain or the
|
||||||
|
"Everything-Else" power domain.
|
||||||
|
|
||||||
|
The particularity of the "Always-On" Serial Interface is that the hardware
|
||||||
|
is active since power-on and does not need any clock gating and is usable
|
||||||
|
as very early serial console.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible : compatible: value should be different for each SoC family as :
|
||||||
|
- Meson6 : "amlogic,meson6-uart"
|
||||||
|
- Meson8 : "amlogic,meson8-uart"
|
||||||
|
- Meson8b : "amlogic,meson8b-uart"
|
||||||
|
- GX (GXBB, GXL, GXM) : "amlogic,meson-gx-uart"
|
||||||
|
eventually followed by : "amlogic,meson-ao-uart" if this UART interface
|
||||||
|
is in the "Always-On" power domain.
|
||||||
|
- reg : offset and length of the register set for the device.
|
||||||
|
- interrupts : identifier to the device interrupt
|
||||||
|
- clocks : a list of phandle + clock-specifier pairs, one for each
|
||||||
|
entry in clock names.
|
||||||
|
- clocks-names :
|
||||||
|
* "xtal" for external xtal clock identifier
|
||||||
|
* "pclk" for the bus core clock, either the clk81 clock or the gate clock
|
||||||
|
* "baud" for the source of the baudrate generator, can be either the xtal
|
||||||
|
or the pclk.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
uart_A: serial@84c0 {
|
||||||
|
compatible = "amlogic,meson-gx-uart";
|
||||||
|
reg = <0x0 0x84c0 0x0 0x14>;
|
||||||
|
interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>;
|
||||||
|
/* Use xtal as baud rate clock source */
|
||||||
|
clocks = <&xtal>, <&clkc CLKID_UART0>, <&xtal>;
|
||||||
|
clock-names = "xtal", "pclk", "baud";
|
||||||
|
};
|
@ -9,6 +9,7 @@ Optional properties:
|
|||||||
- fsl,irda-mode : Indicate the uart supports irda mode
|
- fsl,irda-mode : Indicate the uart supports irda mode
|
||||||
- fsl,dte-mode : Indicate the uart works in DTE mode. The uart works
|
- fsl,dte-mode : Indicate the uart works in DTE mode. The uart works
|
||||||
in DCE mode by default.
|
in DCE mode by default.
|
||||||
|
- fsl,dma-size : Indicate the size of the DMA buffer and its periods
|
||||||
|
|
||||||
Please check Documentation/devicetree/bindings/serial/serial.txt
|
Please check Documentation/devicetree/bindings/serial/serial.txt
|
||||||
for the complete list of generic properties.
|
for the complete list of generic properties.
|
||||||
@ -28,4 +29,5 @@ uart1: serial@73fbc000 {
|
|||||||
interrupts = <31>;
|
interrupts = <31>;
|
||||||
uart-has-rtscts;
|
uart-has-rtscts;
|
||||||
fsl,dte-mode;
|
fsl,dte-mode;
|
||||||
|
fsl,dma-size = <1024 4>;
|
||||||
};
|
};
|
||||||
|
@ -6,6 +6,8 @@ Required properties:
|
|||||||
on Vybrid vf610 SoC with 8-bit register organization
|
on Vybrid vf610 SoC with 8-bit register organization
|
||||||
- "fsl,ls1021a-lpuart" for lpuart compatible with the one integrated
|
- "fsl,ls1021a-lpuart" for lpuart compatible with the one integrated
|
||||||
on LS1021A SoC with 32-bit big-endian register organization
|
on LS1021A SoC with 32-bit big-endian register organization
|
||||||
|
- "fsl,imx7ulp-lpuart" for lpuart compatible with the one integrated
|
||||||
|
on i.MX7ULP SoC with 32-bit little-endian register organization
|
||||||
- reg : Address and length of the register set for the device
|
- reg : Address and length of the register set for the device
|
||||||
- interrupts : Should contain uart interrupt
|
- interrupts : Should contain uart interrupt
|
||||||
- clocks : phandle + clock specifier pairs, one for each entry in clock-names
|
- clocks : phandle + clock specifier pairs, one for each entry in clock-names
|
||||||
|
@ -77,6 +77,13 @@ for example, it's possible :
|
|||||||
|
|
||||||
6- first close all virtual ports before closing the physical port.
|
6- first close all virtual ports before closing the physical port.
|
||||||
|
|
||||||
|
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
|
||||||
|
this situation either reset the modem if your hardware allows that or send
|
||||||
|
a disconnect command frame manually before initializing the multiplexing mode
|
||||||
|
for the second time. The byte sequence for the disconnect command frame is:
|
||||||
|
0xf9, 0x03, 0xef, 0x03, 0xc3, 0x16, 0xf9.
|
||||||
|
|
||||||
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
|
||||||
|
@ -8446,7 +8446,7 @@ T: git git://git.monstr.eu/linux-2.6-microblaze.git
|
|||||||
S: Supported
|
S: Supported
|
||||||
F: arch/microblaze/
|
F: arch/microblaze/
|
||||||
|
|
||||||
MICROCHIP / ATMEL AT91 / AT32 SERIAL DRIVER
|
MICROCHIP / ATMEL AT91 SERIAL DRIVER
|
||||||
M: Richard Genoud <richard.genoud@gmail.com>
|
M: Richard Genoud <richard.genoud@gmail.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/tty/serial/atmel_serial.c
|
F: drivers/tty/serial/atmel_serial.c
|
||||||
|
@ -100,6 +100,7 @@
|
|||||||
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
||||||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||||
|
#define TIOCGPTPEER _IOR('T', 0x41, int) /* Safely open the slave */
|
||||||
|
|
||||||
#define TIOCSERCONFIG 0x5453
|
#define TIOCSERCONFIG 0x5453
|
||||||
#define TIOCSERGWILD 0x5454
|
#define TIOCSERGWILD 0x5454
|
||||||
|
@ -387,19 +387,6 @@ static int activate(struct tty_port *port, struct tty_struct *tty)
|
|||||||
}
|
}
|
||||||
|
|
||||||
state->xmit.head = state->xmit.tail = 0;
|
state->xmit.head = state->xmit.tail = 0;
|
||||||
|
|
||||||
/*
|
|
||||||
* Set up the tty->alt_speed kludge
|
|
||||||
*/
|
|
||||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
|
|
||||||
tty->alt_speed = 57600;
|
|
||||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
|
|
||||||
tty->alt_speed = 115200;
|
|
||||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
|
|
||||||
tty->alt_speed = 230400;
|
|
||||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
|
|
||||||
tty->alt_speed = 460800;
|
|
||||||
|
|
||||||
errout:
|
errout:
|
||||||
local_irq_restore(flags);
|
local_irq_restore(flags);
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -91,6 +91,7 @@
|
|||||||
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
||||||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||||
|
#define TIOCGPTPEER _IOR('T', 0x41, int) /* Safely open the slave */
|
||||||
|
|
||||||
/* I hope the range from 0x5480 on is free ... */
|
/* I hope the range from 0x5480 on is free ... */
|
||||||
#define TIOCSCTTY 0x5480 /* become controlling tty */
|
#define TIOCSCTTY 0x5480 /* become controlling tty */
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
||||||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||||
|
#define TIOCGPTPEER _IOR('T', 0x41, int) /* Safely open the slave */
|
||||||
|
|
||||||
#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */
|
#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */
|
||||||
#define FIOCLEX 0x5451
|
#define FIOCLEX 0x5451
|
||||||
|
@ -100,6 +100,7 @@
|
|||||||
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
||||||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||||
|
#define TIOCGPTPEER _IOR('T', 0x41, int) /* Safely open the slave */
|
||||||
|
|
||||||
#define TIOCSERCONFIG 0x5453
|
#define TIOCSERCONFIG 0x5453
|
||||||
#define TIOCSERGWILD 0x5454
|
#define TIOCSERGWILD 0x5454
|
||||||
|
@ -93,6 +93,7 @@
|
|||||||
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
||||||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||||
|
#define TIOCGPTPEER _IOR('T', 0x41, int) /* Safely open the slave */
|
||||||
|
|
||||||
#define TIOCSERCONFIG _IO('T', 83) /* 0x5453 */
|
#define TIOCSERCONFIG _IO('T', 83) /* 0x5453 */
|
||||||
#define TIOCSERGWILD _IOR('T', 84, int) /* 0x5454 */
|
#define TIOCSERGWILD _IOR('T', 84, int) /* 0x5454 */
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
#define TIOCGRS485 _IOR('T', 0x41, struct serial_rs485)
|
#define TIOCGRS485 _IOR('T', 0x41, struct serial_rs485)
|
||||||
#define TIOCSRS485 _IOWR('T', 0x42, struct serial_rs485)
|
#define TIOCSRS485 _IOWR('T', 0x42, struct serial_rs485)
|
||||||
|
|
||||||
/* Note that all the ioctls that are not available in Linux have a
|
/* Note that all the ioctls that are not available in Linux have a
|
||||||
* double underscore on the front to: a) avoid some programs to
|
* double underscore on the front to: a) avoid some programs to
|
||||||
* think we support some ioctls under Linux (autoconfiguration stuff)
|
* think we support some ioctls under Linux (autoconfiguration stuff)
|
||||||
*/
|
*/
|
||||||
@ -88,6 +88,7 @@
|
|||||||
#define TIOCGPTN _IOR('t', 134, unsigned int) /* Get Pty Number */
|
#define TIOCGPTN _IOR('t', 134, unsigned int) /* Get Pty Number */
|
||||||
#define TIOCSPTLCK _IOW('t', 135, int) /* Lock/unlock PTY */
|
#define TIOCSPTLCK _IOW('t', 135, int) /* Lock/unlock PTY */
|
||||||
#define TIOCSIG _IOW('t', 136, int) /* Generate signal on Pty slave */
|
#define TIOCSIG _IOW('t', 136, int) /* Generate signal on Pty slave */
|
||||||
|
#define TIOCGPTPEER _IOR('t', 137, int) /* Safely open the slave */
|
||||||
|
|
||||||
/* Little f */
|
/* Little f */
|
||||||
#define FIOCLEX _IO('f', 1)
|
#define FIOCLEX _IO('f', 1)
|
||||||
|
@ -105,6 +105,7 @@
|
|||||||
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
||||||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||||
|
#define TIOCGPTPEER _IOR('T', 0x41, int) /* Safely open the slave */
|
||||||
|
|
||||||
#define TIOCSERCONFIG _IO('T', 83)
|
#define TIOCSERCONFIG _IO('T', 83)
|
||||||
#define TIOCSERGWILD _IOR('T', 84, int)
|
#define TIOCSERGWILD _IOR('T', 84, int)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
obj-$(CONFIG_TTY) += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
|
obj-$(CONFIG_TTY) += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
|
||||||
tty_buffer.o tty_port.o tty_mutex.o \
|
tty_buffer.o tty_port.o tty_mutex.o \
|
||||||
tty_ldsem.o tty_baudrate.o tty_jobctrl.o
|
tty_ldsem.o tty_baudrate.o tty_jobctrl.o \
|
||||||
|
n_null.o
|
||||||
obj-$(CONFIG_LEGACY_PTYS) += pty.o
|
obj-$(CONFIG_LEGACY_PTYS) += pty.o
|
||||||
obj-$(CONFIG_UNIX98_PTYS) += pty.o
|
obj-$(CONFIG_UNIX98_PTYS) += pty.o
|
||||||
obj-$(CONFIG_AUDIT) += tty_audit.o
|
obj-$(CONFIG_AUDIT) += tty_audit.o
|
||||||
|
@ -569,18 +569,6 @@ static int startup(struct tty_struct *tty, struct serial_state *info)
|
|||||||
clear_bit(TTY_IO_ERROR, &tty->flags);
|
clear_bit(TTY_IO_ERROR, &tty->flags);
|
||||||
info->xmit.head = info->xmit.tail = 0;
|
info->xmit.head = info->xmit.tail = 0;
|
||||||
|
|
||||||
/*
|
|
||||||
* Set up the tty->alt_speed kludge
|
|
||||||
*/
|
|
||||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
|
|
||||||
tty->alt_speed = 57600;
|
|
||||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
|
|
||||||
tty->alt_speed = 115200;
|
|
||||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
|
|
||||||
tty->alt_speed = 230400;
|
|
||||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
|
|
||||||
tty->alt_speed = 460800;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* and set the speed of the serial port
|
* and set the speed of the serial port
|
||||||
*/
|
*/
|
||||||
@ -1084,14 +1072,9 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
|
|||||||
check_and_exit:
|
check_and_exit:
|
||||||
if (tty_port_initialized(port)) {
|
if (tty_port_initialized(port)) {
|
||||||
if (change_spd) {
|
if (change_spd) {
|
||||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
|
/* warn about deprecation unless clearing */
|
||||||
tty->alt_speed = 57600;
|
if (new_serial.flags & ASYNC_SPD_MASK)
|
||||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
|
dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n");
|
||||||
tty->alt_speed = 115200;
|
|
||||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
|
|
||||||
tty->alt_speed = 230400;
|
|
||||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
|
|
||||||
tty->alt_speed = 460800;
|
|
||||||
change_speed(tty, state, NULL);
|
change_speed(tty, state, NULL);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
|
@ -1975,18 +1975,6 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
|
|||||||
cflag = tty->termios.c_cflag;
|
cflag = tty->termios.c_cflag;
|
||||||
iflag = tty->termios.c_iflag;
|
iflag = tty->termios.c_iflag;
|
||||||
|
|
||||||
/*
|
|
||||||
* Set up the tty->alt_speed kludge
|
|
||||||
*/
|
|
||||||
if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
|
|
||||||
tty->alt_speed = 57600;
|
|
||||||
if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
|
|
||||||
tty->alt_speed = 115200;
|
|
||||||
if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
|
|
||||||
tty->alt_speed = 230400;
|
|
||||||
if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
|
|
||||||
tty->alt_speed = 460800;
|
|
||||||
|
|
||||||
card = info->card;
|
card = info->card;
|
||||||
channel = info->line - card->first_line;
|
channel = info->line - card->first_line;
|
||||||
|
|
||||||
@ -2295,12 +2283,16 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
|
|||||||
struct serial_struct __user *new_info)
|
struct serial_struct __user *new_info)
|
||||||
{
|
{
|
||||||
struct serial_struct new_serial;
|
struct serial_struct new_serial;
|
||||||
|
int old_flags;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
|
if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
mutex_lock(&info->port.mutex);
|
mutex_lock(&info->port.mutex);
|
||||||
|
|
||||||
|
old_flags = info->port.flags;
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN)) {
|
if (!capable(CAP_SYS_ADMIN)) {
|
||||||
if (new_serial.close_delay != info->port.close_delay ||
|
if (new_serial.close_delay != info->port.close_delay ||
|
||||||
new_serial.baud_base != info->baud ||
|
new_serial.baud_base != info->baud ||
|
||||||
@ -2332,6 +2324,11 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
|
|||||||
|
|
||||||
check_and_exit:
|
check_and_exit:
|
||||||
if (tty_port_initialized(&info->port)) {
|
if (tty_port_initialized(&info->port)) {
|
||||||
|
if ((new_serial.flags ^ old_flags) & ASYNC_SPD_MASK) {
|
||||||
|
/* warn about deprecation unless clearing */
|
||||||
|
if (new_serial.flags & ASYNC_SPD_MASK)
|
||||||
|
dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n");
|
||||||
|
}
|
||||||
cy_set_line_char(info, tty);
|
cy_set_line_char(info, tty);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1242,8 +1242,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
|
|||||||
free_irq(irq, hvcsd);
|
free_irq(irq, hvcsd);
|
||||||
return;
|
return;
|
||||||
} else if (hvcsd->port.count < 0) {
|
} else if (hvcsd->port.count < 0) {
|
||||||
printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
|
printk(KERN_ERR "HVCS: vty-server@%X open_count: %d is mismanaged.\n",
|
||||||
" is missmanaged.\n",
|
|
||||||
hvcsd->vdev->unit_address, hvcsd->port.count);
|
hvcsd->vdev->unit_address, hvcsd->port.count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2015,6 +2015,33 @@ static void gsm_error(struct gsm_mux *gsm,
|
|||||||
gsm->io_error++;
|
gsm->io_error++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int gsm_disconnect(struct gsm_mux *gsm)
|
||||||
|
{
|
||||||
|
struct gsm_dlci *dlci = gsm->dlci[0];
|
||||||
|
struct gsm_control *gc;
|
||||||
|
|
||||||
|
if (!dlci)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* In theory disconnecting DLCI 0 is sufficient but for some
|
||||||
|
modems this is apparently not the case. */
|
||||||
|
gc = gsm_control_send(gsm, CMD_CLD, NULL, 0);
|
||||||
|
if (gc)
|
||||||
|
gsm_control_wait(gsm, gc);
|
||||||
|
|
||||||
|
del_timer_sync(&gsm->t2_timer);
|
||||||
|
/* Now we are sure T2 has stopped */
|
||||||
|
|
||||||
|
gsm_dlci_begin_close(dlci);
|
||||||
|
wait_event_interruptible(gsm->event,
|
||||||
|
dlci->state == DLCI_CLOSED);
|
||||||
|
|
||||||
|
if (signal_pending(current))
|
||||||
|
return -EINTR;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gsm_cleanup_mux - generic GSM protocol cleanup
|
* gsm_cleanup_mux - generic GSM protocol cleanup
|
||||||
* @gsm: our mux
|
* @gsm: our mux
|
||||||
@ -2029,7 +2056,6 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm)
|
|||||||
int i;
|
int i;
|
||||||
struct gsm_dlci *dlci = gsm->dlci[0];
|
struct gsm_dlci *dlci = gsm->dlci[0];
|
||||||
struct gsm_msg *txq, *ntxq;
|
struct gsm_msg *txq, *ntxq;
|
||||||
struct gsm_control *gc;
|
|
||||||
|
|
||||||
gsm->dead = 1;
|
gsm->dead = 1;
|
||||||
|
|
||||||
@ -2045,21 +2071,11 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm)
|
|||||||
if (i == MAX_MUX)
|
if (i == MAX_MUX)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* In theory disconnecting DLCI 0 is sufficient but for some
|
|
||||||
modems this is apparently not the case. */
|
|
||||||
if (dlci) {
|
|
||||||
gc = gsm_control_send(gsm, CMD_CLD, NULL, 0);
|
|
||||||
if (gc)
|
|
||||||
gsm_control_wait(gsm, gc);
|
|
||||||
}
|
|
||||||
del_timer_sync(&gsm->t2_timer);
|
del_timer_sync(&gsm->t2_timer);
|
||||||
/* Now we are sure T2 has stopped */
|
/* Now we are sure T2 has stopped */
|
||||||
if (dlci) {
|
if (dlci)
|
||||||
dlci->dead = 1;
|
dlci->dead = 1;
|
||||||
gsm_dlci_begin_close(dlci);
|
|
||||||
wait_event_interruptible(gsm->event,
|
|
||||||
dlci->state == DLCI_CLOSED);
|
|
||||||
}
|
|
||||||
/* Free up any link layer users */
|
/* Free up any link layer users */
|
||||||
mutex_lock(&gsm->mutex);
|
mutex_lock(&gsm->mutex);
|
||||||
for (i = 0; i < NUM_DLCI; i++)
|
for (i = 0; i < NUM_DLCI; i++)
|
||||||
@ -2519,12 +2535,12 @@ static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if (need_close || need_restart) {
|
if (need_close || need_restart) {
|
||||||
gsm_dlci_begin_close(gsm->dlci[0]);
|
int ret;
|
||||||
/* This will timeout if the link is down due to N2 expiring */
|
|
||||||
wait_event_interruptible(gsm->event,
|
ret = gsm_disconnect(gsm);
|
||||||
gsm->dlci[0]->state == DLCI_CLOSED);
|
|
||||||
if (signal_pending(current))
|
if (ret)
|
||||||
return -EINTR;
|
return ret;
|
||||||
}
|
}
|
||||||
if (need_restart)
|
if (need_restart)
|
||||||
gsm_cleanup_mux(gsm);
|
gsm_cleanup_mux(gsm);
|
||||||
|
80
drivers/tty/n_null.c
Normal file
80
drivers/tty/n_null.c
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/tty.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* n_null.c - Null line discipline used in the failure path
|
||||||
|
*
|
||||||
|
* Copyright (C) Intel 2017
|
||||||
|
*
|
||||||
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int n_null_open(struct tty_struct *tty)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void n_null_close(struct tty_struct *tty)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t n_null_read(struct tty_struct *tty, struct file *file,
|
||||||
|
unsigned char __user * buf, size_t nr)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t n_null_write(struct tty_struct *tty, struct file *file,
|
||||||
|
const unsigned char *buf, size_t nr)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void n_null_receivebuf(struct tty_struct *tty,
|
||||||
|
const unsigned char *cp, char *fp,
|
||||||
|
int cnt)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct tty_ldisc_ops null_ldisc = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.magic = TTY_LDISC_MAGIC,
|
||||||
|
.name = "n_null",
|
||||||
|
.open = n_null_open,
|
||||||
|
.close = n_null_close,
|
||||||
|
.read = n_null_read,
|
||||||
|
.write = n_null_write,
|
||||||
|
.receive_buf = n_null_receivebuf
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init n_null_init(void)
|
||||||
|
{
|
||||||
|
BUG_ON(tty_register_ldisc(N_NULL, &null_ldisc));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit n_null_exit(void)
|
||||||
|
{
|
||||||
|
tty_unregister_ldisc(N_NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(n_null_init);
|
||||||
|
module_exit(n_null_exit);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Alan Cox");
|
||||||
|
MODULE_ALIAS_LDISC(N_NULL);
|
||||||
|
MODULE_DESCRIPTION("Null ldisc driver");
|
@ -24,6 +24,9 @@
|
|||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/poll.h>
|
#include <linux/poll.h>
|
||||||
|
#include <linux/mount.h>
|
||||||
|
#include <linux/file.h>
|
||||||
|
#include <linux/ioctl.h>
|
||||||
|
|
||||||
#undef TTY_DEBUG_HANGUP
|
#undef TTY_DEBUG_HANGUP
|
||||||
#ifdef TTY_DEBUG_HANGUP
|
#ifdef TTY_DEBUG_HANGUP
|
||||||
@ -66,8 +69,13 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
|
|||||||
#ifdef CONFIG_UNIX98_PTYS
|
#ifdef CONFIG_UNIX98_PTYS
|
||||||
if (tty->driver == ptm_driver) {
|
if (tty->driver == ptm_driver) {
|
||||||
mutex_lock(&devpts_mutex);
|
mutex_lock(&devpts_mutex);
|
||||||
if (tty->link->driver_data)
|
if (tty->link->driver_data) {
|
||||||
devpts_pty_kill(tty->link->driver_data);
|
struct path *path = tty->link->driver_data;
|
||||||
|
|
||||||
|
devpts_pty_kill(path->dentry);
|
||||||
|
path_put(path);
|
||||||
|
kfree(path);
|
||||||
|
}
|
||||||
mutex_unlock(&devpts_mutex);
|
mutex_unlock(&devpts_mutex);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -440,6 +448,48 @@ err:
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pty_open_peer - open the peer of a pty
|
||||||
|
* @tty: the peer of the pty being opened
|
||||||
|
*
|
||||||
|
* Open the cached dentry in tty->link, providing a safe way for userspace
|
||||||
|
* to get the slave end of a pty (where they have the master fd and cannot
|
||||||
|
* access or trust the mount namespace /dev/pts was mounted inside).
|
||||||
|
*/
|
||||||
|
static struct file *pty_open_peer(struct tty_struct *tty, int flags)
|
||||||
|
{
|
||||||
|
if (tty->driver->subtype != PTY_TYPE_MASTER)
|
||||||
|
return ERR_PTR(-EIO);
|
||||||
|
return dentry_open(tty->link->driver_data, flags, current_cred());
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pty_get_peer(struct tty_struct *tty, int flags)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
struct file *filp = NULL;
|
||||||
|
int retval = -EINVAL;
|
||||||
|
|
||||||
|
fd = get_unused_fd_flags(0);
|
||||||
|
if (fd < 0) {
|
||||||
|
retval = fd;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
filp = pty_open_peer(tty, flags);
|
||||||
|
if (IS_ERR(filp)) {
|
||||||
|
retval = PTR_ERR(filp);
|
||||||
|
goto err_put;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd_install(fd, filp);
|
||||||
|
return fd;
|
||||||
|
|
||||||
|
err_put:
|
||||||
|
put_unused_fd(fd);
|
||||||
|
err:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
static void pty_cleanup(struct tty_struct *tty)
|
static void pty_cleanup(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
tty_port_put(tty->port);
|
tty_port_put(tty->port);
|
||||||
@ -481,6 +531,16 @@ static int pty_bsd_ioctl(struct tty_struct *tty,
|
|||||||
return -ENOIOCTLCMD;
|
return -ENOIOCTLCMD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static long pty_bsd_compat_ioctl(struct tty_struct *tty,
|
||||||
|
unsigned int cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* PTY ioctls don't require any special translation between 32-bit and
|
||||||
|
* 64-bit userspace, they are already compatible.
|
||||||
|
*/
|
||||||
|
return pty_bsd_ioctl(tty, cmd, arg);
|
||||||
|
}
|
||||||
|
|
||||||
static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
|
static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
|
||||||
/*
|
/*
|
||||||
* not really modular, but the easiest way to keep compat with existing
|
* not really modular, but the easiest way to keep compat with existing
|
||||||
@ -502,6 +562,7 @@ static const struct tty_operations master_pty_ops_bsd = {
|
|||||||
.chars_in_buffer = pty_chars_in_buffer,
|
.chars_in_buffer = pty_chars_in_buffer,
|
||||||
.unthrottle = pty_unthrottle,
|
.unthrottle = pty_unthrottle,
|
||||||
.ioctl = pty_bsd_ioctl,
|
.ioctl = pty_bsd_ioctl,
|
||||||
|
.compat_ioctl = pty_bsd_compat_ioctl,
|
||||||
.cleanup = pty_cleanup,
|
.cleanup = pty_cleanup,
|
||||||
.resize = pty_resize,
|
.resize = pty_resize,
|
||||||
.remove = pty_remove
|
.remove = pty_remove
|
||||||
@ -602,6 +663,8 @@ static int pty_unix98_ioctl(struct tty_struct *tty,
|
|||||||
return pty_get_pktmode(tty, (int __user *)arg);
|
return pty_get_pktmode(tty, (int __user *)arg);
|
||||||
case TIOCGPTN: /* Get PT Number */
|
case TIOCGPTN: /* Get PT Number */
|
||||||
return put_user(tty->index, (unsigned int __user *)arg);
|
return put_user(tty->index, (unsigned int __user *)arg);
|
||||||
|
case TIOCGPTPEER: /* Open the other end */
|
||||||
|
return pty_get_peer(tty, (int) arg);
|
||||||
case TIOCSIG: /* Send signal to other side of pty */
|
case TIOCSIG: /* Send signal to other side of pty */
|
||||||
return pty_signal(tty, (int) arg);
|
return pty_signal(tty, (int) arg);
|
||||||
}
|
}
|
||||||
@ -609,6 +672,16 @@ static int pty_unix98_ioctl(struct tty_struct *tty,
|
|||||||
return -ENOIOCTLCMD;
|
return -ENOIOCTLCMD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static long pty_unix98_compat_ioctl(struct tty_struct *tty,
|
||||||
|
unsigned int cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* PTY ioctls don't require any special translation between 32-bit and
|
||||||
|
* 64-bit userspace, they are already compatible.
|
||||||
|
*/
|
||||||
|
return pty_unix98_ioctl(tty, cmd, arg);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ptm_unix98_lookup - find a pty master
|
* ptm_unix98_lookup - find a pty master
|
||||||
* @driver: ptm driver
|
* @driver: ptm driver
|
||||||
@ -681,6 +754,7 @@ static const struct tty_operations ptm_unix98_ops = {
|
|||||||
.chars_in_buffer = pty_chars_in_buffer,
|
.chars_in_buffer = pty_chars_in_buffer,
|
||||||
.unthrottle = pty_unthrottle,
|
.unthrottle = pty_unthrottle,
|
||||||
.ioctl = pty_unix98_ioctl,
|
.ioctl = pty_unix98_ioctl,
|
||||||
|
.compat_ioctl = pty_unix98_compat_ioctl,
|
||||||
.resize = pty_resize,
|
.resize = pty_resize,
|
||||||
.cleanup = pty_cleanup
|
.cleanup = pty_cleanup
|
||||||
};
|
};
|
||||||
@ -718,6 +792,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
|
|||||||
{
|
{
|
||||||
struct pts_fs_info *fsi;
|
struct pts_fs_info *fsi;
|
||||||
struct tty_struct *tty;
|
struct tty_struct *tty;
|
||||||
|
struct path *pts_path;
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
int retval;
|
int retval;
|
||||||
int index;
|
int index;
|
||||||
@ -771,16 +846,26 @@ static int ptmx_open(struct inode *inode, struct file *filp)
|
|||||||
retval = PTR_ERR(dentry);
|
retval = PTR_ERR(dentry);
|
||||||
goto err_release;
|
goto err_release;
|
||||||
}
|
}
|
||||||
tty->link->driver_data = dentry;
|
/* We need to cache a fake path for TIOCGPTPEER. */
|
||||||
|
pts_path = kmalloc(sizeof(struct path), GFP_KERNEL);
|
||||||
|
if (!pts_path)
|
||||||
|
goto err_release;
|
||||||
|
pts_path->mnt = filp->f_path.mnt;
|
||||||
|
pts_path->dentry = dentry;
|
||||||
|
path_get(pts_path);
|
||||||
|
tty->link->driver_data = pts_path;
|
||||||
|
|
||||||
retval = ptm_driver->ops->open(tty, filp);
|
retval = ptm_driver->ops->open(tty, filp);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto err_release;
|
goto err_path_put;
|
||||||
|
|
||||||
tty_debug_hangup(tty, "opening (count=%d)\n", tty->count);
|
tty_debug_hangup(tty, "opening (count=%d)\n", tty->count);
|
||||||
|
|
||||||
tty_unlock(tty);
|
tty_unlock(tty);
|
||||||
return 0;
|
return 0;
|
||||||
|
err_path_put:
|
||||||
|
path_put(pts_path);
|
||||||
|
kfree(pts_path);
|
||||||
err_release:
|
err_release:
|
||||||
tty_unlock(tty);
|
tty_unlock(tty);
|
||||||
// This will also put-ref the fsi
|
// This will also put-ref the fsi
|
||||||
|
@ -947,18 +947,6 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
|
|||||||
|
|
||||||
tty_port_set_initialized(&info->port, 1);
|
tty_port_set_initialized(&info->port, 1);
|
||||||
|
|
||||||
/*
|
|
||||||
* Set up the tty->alt_speed kludge
|
|
||||||
*/
|
|
||||||
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
|
|
||||||
tty->alt_speed = 57600;
|
|
||||||
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
|
|
||||||
tty->alt_speed = 115200;
|
|
||||||
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
|
|
||||||
tty->alt_speed = 230400;
|
|
||||||
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
|
|
||||||
tty->alt_speed = 460800;
|
|
||||||
|
|
||||||
configure_r_port(tty, info, NULL);
|
configure_r_port(tty, info, NULL);
|
||||||
if (C_BAUD(tty)) {
|
if (C_BAUD(tty)) {
|
||||||
sSetDTR(cp);
|
sSetDTR(cp);
|
||||||
@ -1219,23 +1207,20 @@ static int set_config(struct tty_struct *tty, struct r_port *info,
|
|||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK));
|
info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK));
|
||||||
configure_r_port(tty, info, NULL);
|
|
||||||
mutex_unlock(&info->port.mutex);
|
mutex_unlock(&info->port.mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((new_serial.flags ^ info->flags) & ROCKET_SPD_MASK) {
|
||||||
|
/* warn about deprecation, unless clearing */
|
||||||
|
if (new_serial.flags & ROCKET_SPD_MASK)
|
||||||
|
dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n");
|
||||||
|
}
|
||||||
|
|
||||||
info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS));
|
info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS));
|
||||||
info->port.close_delay = new_serial.close_delay;
|
info->port.close_delay = new_serial.close_delay;
|
||||||
info->port.closing_wait = new_serial.closing_wait;
|
info->port.closing_wait = new_serial.closing_wait;
|
||||||
|
|
||||||
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
|
|
||||||
tty->alt_speed = 57600;
|
|
||||||
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
|
|
||||||
tty->alt_speed = 115200;
|
|
||||||
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
|
|
||||||
tty->alt_speed = 230400;
|
|
||||||
if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
|
|
||||||
tty->alt_speed = 460800;
|
|
||||||
mutex_unlock(&info->port.mutex);
|
mutex_unlock(&info->port.mutex);
|
||||||
|
|
||||||
configure_r_port(tty, info, NULL);
|
configure_r_port(tty, info, NULL);
|
||||||
|
@ -148,7 +148,7 @@ static unsigned int ttyport_set_baudrate(struct serdev_controller *ctrl, unsigne
|
|||||||
|
|
||||||
/* tty_set_termios() return not checked as it is always 0 */
|
/* tty_set_termios() return not checked as it is always 0 */
|
||||||
tty_set_termios(tty, &ktermios);
|
tty_set_termios(tty, &ktermios);
|
||||||
return speed;
|
return ktermios.c_ospeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ttyport_set_flow_control(struct serdev_controller *ctrl, bool enable)
|
static void ttyport_set_flow_control(struct serdev_controller *ctrl, bool enable)
|
||||||
|
@ -81,6 +81,9 @@ struct serial8250_config {
|
|||||||
#define UART_CAP_HFIFO (1 << 14) /* UART has a "hidden" FIFO */
|
#define UART_CAP_HFIFO (1 << 14) /* UART has a "hidden" FIFO */
|
||||||
#define UART_CAP_RPM (1 << 15) /* Runtime PM is active while idle */
|
#define UART_CAP_RPM (1 << 15) /* Runtime PM is active while idle */
|
||||||
#define UART_CAP_IRDA (1 << 16) /* UART supports IrDA line discipline */
|
#define UART_CAP_IRDA (1 << 16) /* UART supports IrDA line discipline */
|
||||||
|
#define UART_CAP_MINI (1 << 17) /* Mini UART on BCM283X family lacks:
|
||||||
|
* STOP PARITY EPAR SPAR WLEN5 WLEN6
|
||||||
|
*/
|
||||||
|
|
||||||
#define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */
|
#define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */
|
||||||
#define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */
|
#define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */
|
||||||
|
323
drivers/tty/serial/8250/8250_aspeed_vuart.c
Normal file
323
drivers/tty/serial/8250/8250_aspeed_vuart.c
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
/*
|
||||||
|
* Serial Port driver for Aspeed VUART device
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Jeremy Kerr <jk@ozlabs.org>, IBM Corp.
|
||||||
|
* Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version
|
||||||
|
* 2 of the License, or (at your option) any later version.
|
||||||
|
*/
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/of_irq.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
|
|
||||||
|
#include "8250.h"
|
||||||
|
|
||||||
|
#define ASPEED_VUART_GCRA 0x20
|
||||||
|
#define ASPEED_VUART_GCRA_VUART_EN BIT(0)
|
||||||
|
#define ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD BIT(5)
|
||||||
|
#define ASPEED_VUART_GCRB 0x24
|
||||||
|
#define ASPEED_VUART_GCRB_HOST_SIRQ_MASK GENMASK(7, 4)
|
||||||
|
#define ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT 4
|
||||||
|
#define ASPEED_VUART_ADDRL 0x28
|
||||||
|
#define ASPEED_VUART_ADDRH 0x2c
|
||||||
|
|
||||||
|
struct aspeed_vuart {
|
||||||
|
struct device *dev;
|
||||||
|
void __iomem *regs;
|
||||||
|
struct clk *clk;
|
||||||
|
int line;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The VUART is basically two UART 'front ends' connected by their FIFO
|
||||||
|
* (no actual serial line in between). One is on the BMC side (management
|
||||||
|
* controller) and one is on the host CPU side.
|
||||||
|
*
|
||||||
|
* It allows the BMC to provide to the host a "UART" that pipes into
|
||||||
|
* the BMC itself and can then be turned by the BMC into a network console
|
||||||
|
* of some sort for example.
|
||||||
|
*
|
||||||
|
* This driver is for the BMC side. The sysfs files allow the BMC
|
||||||
|
* userspace which owns the system configuration policy, to specify
|
||||||
|
* at what IO port and interrupt number the host side will appear
|
||||||
|
* to the host on the Host <-> BMC LPC bus. It could be different on a
|
||||||
|
* different system (though most of them use 3f8/4).
|
||||||
|
*/
|
||||||
|
|
||||||
|
static ssize_t lpc_address_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct aspeed_vuart *vuart = dev_get_drvdata(dev);
|
||||||
|
u16 addr;
|
||||||
|
|
||||||
|
addr = (readb(vuart->regs + ASPEED_VUART_ADDRH) << 8) |
|
||||||
|
(readb(vuart->regs + ASPEED_VUART_ADDRL));
|
||||||
|
|
||||||
|
return snprintf(buf, PAGE_SIZE - 1, "0x%x\n", addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t lpc_address_store(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct aspeed_vuart *vuart = dev_get_drvdata(dev);
|
||||||
|
unsigned long val;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = kstrtoul(buf, 0, &val);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
writeb(val >> 8, vuart->regs + ASPEED_VUART_ADDRH);
|
||||||
|
writeb(val >> 0, vuart->regs + ASPEED_VUART_ADDRL);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR_RW(lpc_address);
|
||||||
|
|
||||||
|
static ssize_t sirq_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct aspeed_vuart *vuart = dev_get_drvdata(dev);
|
||||||
|
u8 reg;
|
||||||
|
|
||||||
|
reg = readb(vuart->regs + ASPEED_VUART_GCRB);
|
||||||
|
reg &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
|
||||||
|
reg >>= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT;
|
||||||
|
|
||||||
|
return snprintf(buf, PAGE_SIZE - 1, "%u\n", reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t sirq_store(struct device *dev, struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct aspeed_vuart *vuart = dev_get_drvdata(dev);
|
||||||
|
unsigned long val;
|
||||||
|
int err;
|
||||||
|
u8 reg;
|
||||||
|
|
||||||
|
err = kstrtoul(buf, 0, &val);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
val <<= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT;
|
||||||
|
val &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
|
||||||
|
|
||||||
|
reg = readb(vuart->regs + ASPEED_VUART_GCRB);
|
||||||
|
reg &= ~ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
|
||||||
|
reg |= val;
|
||||||
|
writeb(reg, vuart->regs + ASPEED_VUART_GCRB);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR_RW(sirq);
|
||||||
|
|
||||||
|
static struct attribute *aspeed_vuart_attrs[] = {
|
||||||
|
&dev_attr_sirq.attr,
|
||||||
|
&dev_attr_lpc_address.attr,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group aspeed_vuart_attr_group = {
|
||||||
|
.attrs = aspeed_vuart_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void aspeed_vuart_set_enabled(struct aspeed_vuart *vuart, bool enabled)
|
||||||
|
{
|
||||||
|
u8 reg = readb(vuart->regs + ASPEED_VUART_GCRA);
|
||||||
|
|
||||||
|
if (enabled)
|
||||||
|
reg |= ASPEED_VUART_GCRA_VUART_EN;
|
||||||
|
else
|
||||||
|
reg &= ~ASPEED_VUART_GCRA_VUART_EN;
|
||||||
|
|
||||||
|
writeb(reg, vuart->regs + ASPEED_VUART_GCRA);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aspeed_vuart_set_host_tx_discard(struct aspeed_vuart *vuart,
|
||||||
|
bool discard)
|
||||||
|
{
|
||||||
|
u8 reg;
|
||||||
|
|
||||||
|
reg = readb(vuart->regs + ASPEED_VUART_GCRA);
|
||||||
|
|
||||||
|
/* If the DISABLE_HOST_TX_DISCARD bit is set, discard is disabled */
|
||||||
|
if (!discard)
|
||||||
|
reg |= ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD;
|
||||||
|
else
|
||||||
|
reg &= ~ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD;
|
||||||
|
|
||||||
|
writeb(reg, vuart->regs + ASPEED_VUART_GCRA);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int aspeed_vuart_startup(struct uart_port *uart_port)
|
||||||
|
{
|
||||||
|
struct uart_8250_port *uart_8250_port = up_to_u8250p(uart_port);
|
||||||
|
struct aspeed_vuart *vuart = uart_8250_port->port.private_data;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = serial8250_do_startup(uart_port);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
aspeed_vuart_set_host_tx_discard(vuart, false);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aspeed_vuart_shutdown(struct uart_port *uart_port)
|
||||||
|
{
|
||||||
|
struct uart_8250_port *uart_8250_port = up_to_u8250p(uart_port);
|
||||||
|
struct aspeed_vuart *vuart = uart_8250_port->port.private_data;
|
||||||
|
|
||||||
|
aspeed_vuart_set_host_tx_discard(vuart, true);
|
||||||
|
|
||||||
|
serial8250_do_shutdown(uart_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int aspeed_vuart_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct uart_8250_port port;
|
||||||
|
struct aspeed_vuart *vuart;
|
||||||
|
struct device_node *np;
|
||||||
|
struct resource *res;
|
||||||
|
u32 clk, prop;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
np = pdev->dev.of_node;
|
||||||
|
|
||||||
|
vuart = devm_kzalloc(&pdev->dev, sizeof(*vuart), GFP_KERNEL);
|
||||||
|
if (!vuart)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
vuart->dev = &pdev->dev;
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
vuart->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||||
|
if (IS_ERR(vuart->regs))
|
||||||
|
return PTR_ERR(vuart->regs);
|
||||||
|
|
||||||
|
memset(&port, 0, sizeof(port));
|
||||||
|
port.port.private_data = vuart;
|
||||||
|
port.port.membase = vuart->regs;
|
||||||
|
port.port.mapbase = res->start;
|
||||||
|
port.port.mapsize = resource_size(res);
|
||||||
|
port.port.startup = aspeed_vuart_startup;
|
||||||
|
port.port.shutdown = aspeed_vuart_shutdown;
|
||||||
|
port.port.dev = &pdev->dev;
|
||||||
|
|
||||||
|
rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if (of_property_read_u32(np, "clock-frequency", &clk)) {
|
||||||
|
vuart->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
|
if (IS_ERR(vuart->clk)) {
|
||||||
|
dev_warn(&pdev->dev,
|
||||||
|
"clk or clock-frequency not defined\n");
|
||||||
|
return PTR_ERR(vuart->clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = clk_prepare_enable(vuart->clk);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
clk = clk_get_rate(vuart->clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If current-speed was set, then try not to change it. */
|
||||||
|
if (of_property_read_u32(np, "current-speed", &prop) == 0)
|
||||||
|
port.port.custom_divisor = clk / (16 * prop);
|
||||||
|
|
||||||
|
/* Check for shifted address mapping */
|
||||||
|
if (of_property_read_u32(np, "reg-offset", &prop) == 0)
|
||||||
|
port.port.mapbase += prop;
|
||||||
|
|
||||||
|
/* Check for registers offset within the devices address range */
|
||||||
|
if (of_property_read_u32(np, "reg-shift", &prop) == 0)
|
||||||
|
port.port.regshift = prop;
|
||||||
|
|
||||||
|
/* Check for fifo size */
|
||||||
|
if (of_property_read_u32(np, "fifo-size", &prop) == 0)
|
||||||
|
port.port.fifosize = prop;
|
||||||
|
|
||||||
|
/* Check for a fixed line number */
|
||||||
|
rc = of_alias_get_id(np, "serial");
|
||||||
|
if (rc >= 0)
|
||||||
|
port.port.line = rc;
|
||||||
|
|
||||||
|
port.port.irq = irq_of_parse_and_map(np, 0);
|
||||||
|
port.port.irqflags = IRQF_SHARED;
|
||||||
|
port.port.iotype = UPIO_MEM;
|
||||||
|
port.port.type = PORT_16550A;
|
||||||
|
port.port.uartclk = clk;
|
||||||
|
port.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF
|
||||||
|
| UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_NO_THRE_TEST;
|
||||||
|
|
||||||
|
if (of_property_read_bool(np, "no-loopback-test"))
|
||||||
|
port.port.flags |= UPF_SKIP_TEST;
|
||||||
|
|
||||||
|
if (port.port.fifosize)
|
||||||
|
port.capabilities = UART_CAP_FIFO;
|
||||||
|
|
||||||
|
if (of_property_read_bool(np, "auto-flow-control"))
|
||||||
|
port.capabilities |= UART_CAP_AFE;
|
||||||
|
|
||||||
|
rc = serial8250_register_8250_port(&port);
|
||||||
|
if (rc < 0)
|
||||||
|
goto err_clk_disable;
|
||||||
|
|
||||||
|
vuart->line = rc;
|
||||||
|
|
||||||
|
aspeed_vuart_set_enabled(vuart, true);
|
||||||
|
aspeed_vuart_set_host_tx_discard(vuart, true);
|
||||||
|
platform_set_drvdata(pdev, vuart);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_clk_disable:
|
||||||
|
clk_disable_unprepare(vuart->clk);
|
||||||
|
irq_dispose_mapping(port.port.irq);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int aspeed_vuart_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct aspeed_vuart *vuart = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
aspeed_vuart_set_enabled(vuart, false);
|
||||||
|
serial8250_unregister_port(vuart->line);
|
||||||
|
sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
|
||||||
|
clk_disable_unprepare(vuart->clk);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id aspeed_vuart_table[] = {
|
||||||
|
{ .compatible = "aspeed,ast2400-vuart" },
|
||||||
|
{ .compatible = "aspeed,ast2500-vuart" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_driver aspeed_vuart_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "aspeed-vuart",
|
||||||
|
.of_match_table = aspeed_vuart_table,
|
||||||
|
},
|
||||||
|
.probe = aspeed_vuart_probe,
|
||||||
|
.remove = aspeed_vuart_remove,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(aspeed_vuart_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Jeremy Kerr <jk@ozlabs.org>");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_DESCRIPTION("Driver for Aspeed VUART device");
|
@ -39,7 +39,7 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
/* initialize data */
|
/* initialize data */
|
||||||
spin_lock_init(&data->uart.port.lock);
|
spin_lock_init(&data->uart.port.lock);
|
||||||
data->uart.capabilities = UART_CAP_FIFO;
|
data->uart.capabilities = UART_CAP_FIFO | UART_CAP_MINI;
|
||||||
data->uart.port.dev = &pdev->dev;
|
data->uart.port.dev = &pdev->dev;
|
||||||
data->uart.port.regshift = 2;
|
data->uart.port.regshift = 2;
|
||||||
data->uart.port.type = PORT_16550;
|
data->uart.port.type = PORT_16550;
|
||||||
|
@ -1043,24 +1043,13 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
|||||||
if (up->dl_write)
|
if (up->dl_write)
|
||||||
uart->dl_write = up->dl_write;
|
uart->dl_write = up->dl_write;
|
||||||
|
|
||||||
if (uart->port.type != PORT_8250_CIR) {
|
if (serial8250_isa_config != NULL)
|
||||||
if (serial8250_isa_config != NULL)
|
serial8250_isa_config(0, &uart->port,
|
||||||
serial8250_isa_config(0, &uart->port,
|
&uart->capabilities);
|
||||||
&uart->capabilities);
|
|
||||||
|
|
||||||
ret = uart_add_one_port(&serial8250_reg,
|
ret = uart_add_one_port(&serial8250_reg, &uart->port);
|
||||||
&uart->port);
|
if (ret == 0)
|
||||||
if (ret == 0)
|
ret = uart->port.line;
|
||||||
ret = uart->port.line;
|
|
||||||
} else {
|
|
||||||
dev_info(uart->port.dev,
|
|
||||||
"skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n",
|
|
||||||
uart->port.iobase,
|
|
||||||
(unsigned long long)uart->port.mapbase,
|
|
||||||
uart->port.irq);
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mutex_unlock(&serial_mutex);
|
mutex_unlock(&serial_mutex);
|
||||||
|
|
||||||
|
@ -109,7 +109,6 @@ pci_fastcom335_setup(struct exar8250 *priv, struct pci_dev *pcidev,
|
|||||||
u8 __iomem *p;
|
u8 __iomem *p;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
port->port.flags |= UPF_EXAR_EFR;
|
|
||||||
port->port.uartclk = baud * 16;
|
port->port.uartclk = baud * 16;
|
||||||
|
|
||||||
err = default_setup(priv, pcidev, idx, offset, port);
|
err = default_setup(priv, pcidev, idx, offset, port);
|
||||||
@ -171,19 +170,26 @@ pci_xr17c154_setup(struct exar8250 *priv, struct pci_dev *pcidev,
|
|||||||
return default_setup(priv, pcidev, idx, offset, port);
|
return default_setup(priv, pcidev, idx, offset, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_gpio(u8 __iomem *p)
|
static void setup_gpio(struct pci_dev *pcidev, u8 __iomem *p)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* The Commtech adapters required the MPIOs to be driven low. The Exar
|
||||||
|
* devices will export them as GPIOs, so we pre-configure them safely
|
||||||
|
* as inputs.
|
||||||
|
*/
|
||||||
|
u8 dir = pcidev->vendor == PCI_VENDOR_ID_EXAR ? 0xff : 0x00;
|
||||||
|
|
||||||
writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
|
writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
|
||||||
writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
|
writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
|
||||||
writeb(0x00, p + UART_EXAR_MPIO3T_7_0);
|
writeb(0x00, p + UART_EXAR_MPIO3T_7_0);
|
||||||
writeb(0x00, p + UART_EXAR_MPIOINV_7_0);
|
writeb(0x00, p + UART_EXAR_MPIOINV_7_0);
|
||||||
writeb(0x00, p + UART_EXAR_MPIOSEL_7_0);
|
writeb(dir, p + UART_EXAR_MPIOSEL_7_0);
|
||||||
writeb(0x00, p + UART_EXAR_MPIOOD_7_0);
|
writeb(0x00, p + UART_EXAR_MPIOOD_7_0);
|
||||||
writeb(0x00, p + UART_EXAR_MPIOINT_15_8);
|
writeb(0x00, p + UART_EXAR_MPIOINT_15_8);
|
||||||
writeb(0x00, p + UART_EXAR_MPIOLVL_15_8);
|
writeb(0x00, p + UART_EXAR_MPIOLVL_15_8);
|
||||||
writeb(0x00, p + UART_EXAR_MPIO3T_15_8);
|
writeb(0x00, p + UART_EXAR_MPIO3T_15_8);
|
||||||
writeb(0x00, p + UART_EXAR_MPIOINV_15_8);
|
writeb(0x00, p + UART_EXAR_MPIOINV_15_8);
|
||||||
writeb(0x00, p + UART_EXAR_MPIOSEL_15_8);
|
writeb(dir, p + UART_EXAR_MPIOSEL_15_8);
|
||||||
writeb(0x00, p + UART_EXAR_MPIOOD_15_8);
|
writeb(0x00, p + UART_EXAR_MPIOOD_15_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,7 +242,7 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev,
|
|||||||
|
|
||||||
if (idx == 0) {
|
if (idx == 0) {
|
||||||
/* Setup Multipurpose Input/Output pins. */
|
/* Setup Multipurpose Input/Output pins. */
|
||||||
setup_gpio(p);
|
setup_gpio(pcidev, p);
|
||||||
|
|
||||||
port->port.private_data = xr17v35x_register_gpio(pcidev);
|
port->port.private_data = xr17v35x_register_gpio(pcidev);
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,13 @@
|
|||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
#include <linux/reset.h>
|
||||||
|
|
||||||
#include "8250.h"
|
#include "8250.h"
|
||||||
|
|
||||||
struct of_serial_info {
|
struct of_serial_info {
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
|
struct reset_control *rst;
|
||||||
int type;
|
int type;
|
||||||
int line;
|
int line;
|
||||||
};
|
};
|
||||||
@ -132,6 +134,13 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL);
|
||||||
|
if (IS_ERR(info->rst))
|
||||||
|
goto out;
|
||||||
|
ret = reset_control_deassert(info->rst);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
port->type = type;
|
port->type = type;
|
||||||
port->uartclk = clk;
|
port->uartclk = clk;
|
||||||
port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
|
port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
|
||||||
@ -229,6 +238,7 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
|
|||||||
|
|
||||||
serial8250_unregister_port(info->line);
|
serial8250_unregister_port(info->line);
|
||||||
|
|
||||||
|
reset_control_assert(info->rst);
|
||||||
if (info->clk)
|
if (info->clk)
|
||||||
clk_disable_unprepare(info->clk);
|
clk_disable_unprepare(info->clk);
|
||||||
kfree(info);
|
kfree(info);
|
||||||
|
@ -613,6 +613,10 @@ static int omap_8250_startup(struct uart_port *port)
|
|||||||
up->lsr_saved_flags = 0;
|
up->lsr_saved_flags = 0;
|
||||||
up->msr_saved_flags = 0;
|
up->msr_saved_flags = 0;
|
||||||
|
|
||||||
|
/* Disable DMA for console UART */
|
||||||
|
if (uart_console(port))
|
||||||
|
up->dma = NULL;
|
||||||
|
|
||||||
if (up->dma) {
|
if (up->dma) {
|
||||||
ret = serial8250_request_dma(up);
|
ret = serial8250_request_dma(up);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@ -782,8 +786,27 @@ unlock:
|
|||||||
|
|
||||||
static void __dma_rx_complete(void *param)
|
static void __dma_rx_complete(void *param)
|
||||||
{
|
{
|
||||||
__dma_rx_do_complete(param);
|
struct uart_8250_port *p = param;
|
||||||
omap_8250_rx_dma(param);
|
struct uart_8250_dma *dma = p->dma;
|
||||||
|
struct dma_tx_state state;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&p->port.lock, flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the tx status is not DMA_COMPLETE, then this is a delayed
|
||||||
|
* completion callback. A previous RX timeout flush would have
|
||||||
|
* already pushed the data, so exit.
|
||||||
|
*/
|
||||||
|
if (dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state) !=
|
||||||
|
DMA_COMPLETE) {
|
||||||
|
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
__dma_rx_do_complete(p);
|
||||||
|
omap_8250_rx_dma(p);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
|
static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
|
||||||
|
@ -1764,6 +1764,10 @@ void serial8250_tx_chars(struct uart_8250_port *up)
|
|||||||
if ((up->capabilities & UART_CAP_HFIFO) &&
|
if ((up->capabilities & UART_CAP_HFIFO) &&
|
||||||
(serial_in(up, UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY)
|
(serial_in(up, UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY)
|
||||||
break;
|
break;
|
||||||
|
/* The BCM2835 MINI UART THRE bit is really a not-full bit. */
|
||||||
|
if ((up->capabilities & UART_CAP_MINI) &&
|
||||||
|
!(serial_in(up, UART_LSR) & UART_LSR_THRE))
|
||||||
|
break;
|
||||||
} while (--count > 0);
|
} while (--count > 0);
|
||||||
|
|
||||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||||
@ -2228,7 +2232,7 @@ int serial8250_do_startup(struct uart_port *port)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port->irq) {
|
if (port->irq && !(up->port.flags & UPF_NO_THRE_TEST)) {
|
||||||
unsigned char iir1;
|
unsigned char iir1;
|
||||||
/*
|
/*
|
||||||
* Test for UARTs that do not reassert THRE when the
|
* Test for UARTs that do not reassert THRE when the
|
||||||
@ -2585,6 +2589,12 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned int baud, quot, frac = 0;
|
unsigned int baud, quot, frac = 0;
|
||||||
|
|
||||||
|
if (up->capabilities & UART_CAP_MINI) {
|
||||||
|
termios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CMSPAR);
|
||||||
|
if ((termios->c_cflag & CSIZE) == CS5 ||
|
||||||
|
(termios->c_cflag & CSIZE) == CS6)
|
||||||
|
termios->c_cflag = (termios->c_cflag & ~CSIZE) | CS7;
|
||||||
|
}
|
||||||
cval = serial8250_compute_lcr(up, termios->c_cflag);
|
cval = serial8250_compute_lcr(up, termios->c_cflag);
|
||||||
|
|
||||||
baud = serial8250_get_baud_rate(port, termios, old);
|
baud = serial8250_get_baud_rate(port, termios, old);
|
||||||
|
@ -224,6 +224,16 @@ config SERIAL_8250_ACCENT
|
|||||||
To compile this driver as a module, choose M here: the module
|
To compile this driver as a module, choose M here: the module
|
||||||
will be called 8250_accent.
|
will be called 8250_accent.
|
||||||
|
|
||||||
|
config SERIAL_8250_ASPEED_VUART
|
||||||
|
tristate "Aspeed Virtual UART"
|
||||||
|
depends on SERIAL_8250
|
||||||
|
depends on OF
|
||||||
|
help
|
||||||
|
If you want to use the virtual UART (VUART) device on Aspeed
|
||||||
|
BMC platforms, enable this option. This enables the 16550A-
|
||||||
|
compatible device on the local LPC bus, giving a UART device
|
||||||
|
with no physical RS232 connections.
|
||||||
|
|
||||||
config SERIAL_8250_BOCA
|
config SERIAL_8250_BOCA
|
||||||
tristate "Support Boca cards"
|
tristate "Support Boca cards"
|
||||||
depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
|
depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
|
||||||
|
@ -14,6 +14,7 @@ obj-$(CONFIG_SERIAL_8250_EXAR) += 8250_exar.o
|
|||||||
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
|
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
|
||||||
obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
|
obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
|
||||||
obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
|
obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
|
||||||
|
obj-$(CONFIG_SERIAL_8250_ASPEED_VUART) += 8250_aspeed_vuart.o
|
||||||
obj-$(CONFIG_SERIAL_8250_BCM2835AUX) += 8250_bcm2835aux.o
|
obj-$(CONFIG_SERIAL_8250_BCM2835AUX) += 8250_bcm2835aux.o
|
||||||
obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
|
obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
|
||||||
obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o
|
obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o
|
||||||
|
@ -114,32 +114,32 @@ config SERIAL_SB1250_DUART_CONSOLE
|
|||||||
If unsure, say Y.
|
If unsure, say Y.
|
||||||
|
|
||||||
config SERIAL_ATMEL
|
config SERIAL_ATMEL
|
||||||
bool "AT91 / AT32 on-chip serial port support"
|
bool "AT91 on-chip serial port support"
|
||||||
depends on HAS_DMA
|
depends on HAS_DMA
|
||||||
depends on ARCH_AT91 || AVR32 || COMPILE_TEST
|
depends on ARCH_AT91 || COMPILE_TEST
|
||||||
select SERIAL_CORE
|
select SERIAL_CORE
|
||||||
select SERIAL_MCTRL_GPIO if GPIOLIB
|
select SERIAL_MCTRL_GPIO if GPIOLIB
|
||||||
help
|
help
|
||||||
This enables the driver for the on-chip UARTs of the Atmel
|
This enables the driver for the on-chip UARTs of the Atmel
|
||||||
AT91 and AT32 processors.
|
AT91 processors.
|
||||||
|
|
||||||
config SERIAL_ATMEL_CONSOLE
|
config SERIAL_ATMEL_CONSOLE
|
||||||
bool "Support for console on AT91 / AT32 serial port"
|
bool "Support for console on AT91 serial port"
|
||||||
depends on SERIAL_ATMEL=y
|
depends on SERIAL_ATMEL=y
|
||||||
select SERIAL_CORE_CONSOLE
|
select SERIAL_CORE_CONSOLE
|
||||||
help
|
help
|
||||||
Say Y here if you wish to use an on-chip UART on a Atmel
|
Say Y here if you wish to use an on-chip UART on a Atmel
|
||||||
AT91 or AT32 processor as the system console (the system
|
AT91 processor as the system console (the system
|
||||||
console is the device which receives all kernel messages and
|
console is the device which receives all kernel messages and
|
||||||
warnings and which allows logins in single user mode).
|
warnings and which allows logins in single user mode).
|
||||||
|
|
||||||
config SERIAL_ATMEL_PDC
|
config SERIAL_ATMEL_PDC
|
||||||
bool "Support DMA transfers on AT91 / AT32 serial port"
|
bool "Support DMA transfers on AT91 serial port"
|
||||||
depends on SERIAL_ATMEL
|
depends on SERIAL_ATMEL
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
Say Y here if you wish to use the PDC to do DMA transfers to
|
Say Y here if you wish to use the PDC to do DMA transfers to
|
||||||
and from the Atmel AT91 / AT32 serial port. In order to
|
and from the Atmel AT91 serial port. In order to
|
||||||
actually use DMA transfers, make sure that the use_dma_tx
|
actually use DMA transfers, make sure that the use_dma_tx
|
||||||
and use_dma_rx members in the atmel_uart_data struct is set
|
and use_dma_rx members in the atmel_uart_data struct is set
|
||||||
appropriately for each port.
|
appropriately for each port.
|
||||||
@ -152,7 +152,7 @@ config SERIAL_ATMEL_TTYAT
|
|||||||
bool "Install as device ttyATn instead of ttySn"
|
bool "Install as device ttyATn instead of ttySn"
|
||||||
depends on SERIAL_ATMEL=y
|
depends on SERIAL_ATMEL=y
|
||||||
help
|
help
|
||||||
Say Y here if you wish to have the internal AT91 / AT32 UARTs
|
Say Y here if you wish to have the internal AT91 UARTs
|
||||||
appear as /dev/ttyATn (major 204, minor starting at 154)
|
appear as /dev/ttyATn (major 204, minor starting at 154)
|
||||||
instead of the normal /dev/ttySn (major 4, minor starting at
|
instead of the normal /dev/ttySn (major 4, minor starting at
|
||||||
64). This is necessary if you also want other UARTs, such as
|
64). This is necessary if you also want other UARTs, such as
|
||||||
@ -1688,6 +1688,25 @@ config SERIAL_MVEBU_CONSOLE
|
|||||||
and warnings and which allows logins in single user mode)
|
and warnings and which allows logins in single user mode)
|
||||||
Otherwise, say 'N'.
|
Otherwise, say 'N'.
|
||||||
|
|
||||||
|
config SERIAL_OWL
|
||||||
|
bool "Actions Semi Owl serial port support"
|
||||||
|
depends on ARCH_ACTIONS || COMPILE_TEST
|
||||||
|
select SERIAL_CORE
|
||||||
|
help
|
||||||
|
This driver is for Actions Semiconductor S500/S900 SoC's UART.
|
||||||
|
Say 'Y' here if you wish to use the on-board serial port.
|
||||||
|
Otherwise, say 'N'.
|
||||||
|
|
||||||
|
config SERIAL_OWL_CONSOLE
|
||||||
|
bool "Console on Actions Semi Owl serial port"
|
||||||
|
depends on SERIAL_OWL=y
|
||||||
|
select SERIAL_CORE_CONSOLE
|
||||||
|
select SERIAL_EARLYCON
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Say 'Y' here if you wish to use Actions Semiconductor S500/S900 UART
|
||||||
|
as the system console. Only earlycon is implemented currently.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
config SERIAL_MCTRL_GPIO
|
config SERIAL_MCTRL_GPIO
|
||||||
|
@ -92,6 +92,7 @@ obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o
|
|||||||
obj-$(CONFIG_SERIAL_MVEBU_UART) += mvebu-uart.o
|
obj-$(CONFIG_SERIAL_MVEBU_UART) += mvebu-uart.o
|
||||||
obj-$(CONFIG_SERIAL_PIC32) += pic32_uart.o
|
obj-$(CONFIG_SERIAL_PIC32) += pic32_uart.o
|
||||||
obj-$(CONFIG_SERIAL_MPS2_UART) += mps2-uart.o
|
obj-$(CONFIG_SERIAL_MPS2_UART) += mps2-uart.o
|
||||||
|
obj-$(CONFIG_SERIAL_OWL) += owl-uart.o
|
||||||
|
|
||||||
# GPIOLIB helpers for modem control lines
|
# GPIOLIB helpers for modem control lines
|
||||||
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
|
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
|
||||||
|
@ -697,6 +697,7 @@ static struct console amba_console = {
|
|||||||
#define AMBA_CONSOLE NULL
|
#define AMBA_CONSOLE NULL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static DEFINE_MUTEX(amba_reg_lock);
|
||||||
static struct uart_driver amba_reg = {
|
static struct uart_driver amba_reg = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.driver_name = "ttyAM",
|
.driver_name = "ttyAM",
|
||||||
@ -749,6 +750,19 @@ static int pl010_probe(struct amba_device *dev, const struct amba_id *id)
|
|||||||
amba_ports[i] = uap;
|
amba_ports[i] = uap;
|
||||||
|
|
||||||
amba_set_drvdata(dev, uap);
|
amba_set_drvdata(dev, uap);
|
||||||
|
|
||||||
|
mutex_lock(&amba_reg_lock);
|
||||||
|
if (!amba_reg.state) {
|
||||||
|
ret = uart_register_driver(&amba_reg);
|
||||||
|
if (ret < 0) {
|
||||||
|
mutex_unlock(&amba_reg_lock);
|
||||||
|
dev_err(uap->port.dev,
|
||||||
|
"Failed to register AMBA-PL010 driver\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mutex_unlock(&amba_reg_lock);
|
||||||
|
|
||||||
ret = uart_add_one_port(&amba_reg, &uap->port);
|
ret = uart_add_one_port(&amba_reg, &uap->port);
|
||||||
if (ret)
|
if (ret)
|
||||||
amba_ports[i] = NULL;
|
amba_ports[i] = NULL;
|
||||||
@ -760,12 +774,18 @@ static int pl010_remove(struct amba_device *dev)
|
|||||||
{
|
{
|
||||||
struct uart_amba_port *uap = amba_get_drvdata(dev);
|
struct uart_amba_port *uap = amba_get_drvdata(dev);
|
||||||
int i;
|
int i;
|
||||||
|
bool busy = false;
|
||||||
|
|
||||||
uart_remove_one_port(&amba_reg, &uap->port);
|
uart_remove_one_port(&amba_reg, &uap->port);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
|
for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
|
||||||
if (amba_ports[i] == uap)
|
if (amba_ports[i] == uap)
|
||||||
amba_ports[i] = NULL;
|
amba_ports[i] = NULL;
|
||||||
|
else if (amba_ports[i])
|
||||||
|
busy = true;
|
||||||
|
|
||||||
|
if (!busy)
|
||||||
|
uart_unregister_driver(&amba_reg);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -816,23 +836,14 @@ static struct amba_driver pl010_driver = {
|
|||||||
|
|
||||||
static int __init pl010_init(void)
|
static int __init pl010_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
|
|
||||||
printk(KERN_INFO "Serial: AMBA driver\n");
|
printk(KERN_INFO "Serial: AMBA driver\n");
|
||||||
|
|
||||||
ret = uart_register_driver(&amba_reg);
|
return amba_driver_register(&pl010_driver);
|
||||||
if (ret == 0) {
|
|
||||||
ret = amba_driver_register(&pl010_driver);
|
|
||||||
if (ret)
|
|
||||||
uart_unregister_driver(&amba_reg);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit pl010_exit(void)
|
static void __exit pl010_exit(void)
|
||||||
{
|
{
|
||||||
amba_driver_unregister(&pl010_driver);
|
amba_driver_unregister(&pl010_driver);
|
||||||
uart_unregister_driver(&amba_reg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(pl010_init);
|
module_init(pl010_init);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Driver for Atmel AT91 / AT32 Serial ports
|
* Driver for Atmel AT91 Serial ports
|
||||||
* Copyright (C) 2003 Rick Bronson
|
* Copyright (C) 2003 Rick Bronson
|
||||||
*
|
*
|
||||||
* Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
|
* Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
|
||||||
@ -46,6 +46,7 @@
|
|||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
#include <linux/suspend.h>
|
#include <linux/suspend.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/ioctls.h>
|
#include <asm/ioctls.h>
|
||||||
@ -118,7 +119,6 @@ struct atmel_uart_char {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* at91: 6 USARTs and one DBGU port (SAM9260)
|
* at91: 6 USARTs and one DBGU port (SAM9260)
|
||||||
* avr32: 4
|
|
||||||
* samx7: 3 USARTs and 5 UARTs
|
* samx7: 3 USARTs and 5 UARTs
|
||||||
*/
|
*/
|
||||||
#define ATMEL_MAX_UART 8
|
#define ATMEL_MAX_UART 8
|
||||||
@ -228,21 +228,6 @@ static inline void atmel_uart_writel(struct uart_port *port, u32 reg, u32 value)
|
|||||||
__raw_writel(value, port->membase + reg);
|
__raw_writel(value, port->membase + reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_AVR32
|
|
||||||
|
|
||||||
/* AVR32 cannot handle 8 or 16bit I/O accesses but only 32bit I/O accesses */
|
|
||||||
static inline u8 atmel_uart_read_char(struct uart_port *port)
|
|
||||||
{
|
|
||||||
return __raw_readl(port->membase + ATMEL_US_RHR);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void atmel_uart_write_char(struct uart_port *port, u8 value)
|
|
||||||
{
|
|
||||||
__raw_writel(value, port->membase + ATMEL_US_THR);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
static inline u8 atmel_uart_read_char(struct uart_port *port)
|
static inline u8 atmel_uart_read_char(struct uart_port *port)
|
||||||
{
|
{
|
||||||
return __raw_readb(port->membase + ATMEL_US_RHR);
|
return __raw_readb(port->membase + ATMEL_US_RHR);
|
||||||
@ -253,8 +238,6 @@ static inline void atmel_uart_write_char(struct uart_port *port, u8 value)
|
|||||||
__raw_writeb(value, port->membase + ATMEL_US_THR);
|
__raw_writeb(value, port->membase + ATMEL_US_THR);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_ATMEL_PDC
|
#ifdef CONFIG_SERIAL_ATMEL_PDC
|
||||||
static bool atmel_use_pdc_rx(struct uart_port *port)
|
static bool atmel_use_pdc_rx(struct uart_port *port)
|
||||||
{
|
{
|
||||||
@ -959,7 +942,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port)
|
|||||||
sg_set_page(&atmel_port->sg_tx,
|
sg_set_page(&atmel_port->sg_tx,
|
||||||
virt_to_page(port->state->xmit.buf),
|
virt_to_page(port->state->xmit.buf),
|
||||||
UART_XMIT_SIZE,
|
UART_XMIT_SIZE,
|
||||||
(unsigned long)port->state->xmit.buf & ~PAGE_MASK);
|
offset_in_page(port->state->xmit.buf));
|
||||||
nent = dma_map_sg(port->dev,
|
nent = dma_map_sg(port->dev,
|
||||||
&atmel_port->sg_tx,
|
&atmel_port->sg_tx,
|
||||||
1,
|
1,
|
||||||
@ -1141,7 +1124,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
|
|||||||
sg_set_page(&atmel_port->sg_rx,
|
sg_set_page(&atmel_port->sg_rx,
|
||||||
virt_to_page(ring->buf),
|
virt_to_page(ring->buf),
|
||||||
sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE,
|
sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE,
|
||||||
(unsigned long)ring->buf & ~PAGE_MASK);
|
offset_in_page(ring->buf));
|
||||||
nent = dma_map_sg(port->dev,
|
nent = dma_map_sg(port->dev,
|
||||||
&atmel_port->sg_rx,
|
&atmel_port->sg_rx,
|
||||||
1,
|
1,
|
||||||
@ -1655,72 +1638,56 @@ static void atmel_init_property(struct atmel_uart_port *atmel_port,
|
|||||||
struct platform_device *pdev)
|
struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device_node *np = pdev->dev.of_node;
|
struct device_node *np = pdev->dev.of_node;
|
||||||
struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
|
|
||||||
|
|
||||||
if (np) {
|
/* DMA/PDC usage specification */
|
||||||
/* DMA/PDC usage specification */
|
if (of_property_read_bool(np, "atmel,use-dma-rx")) {
|
||||||
if (of_property_read_bool(np, "atmel,use-dma-rx")) {
|
if (of_property_read_bool(np, "dmas")) {
|
||||||
if (of_property_read_bool(np, "dmas")) {
|
atmel_port->use_dma_rx = true;
|
||||||
atmel_port->use_dma_rx = true;
|
atmel_port->use_pdc_rx = false;
|
||||||
atmel_port->use_pdc_rx = false;
|
|
||||||
} else {
|
|
||||||
atmel_port->use_dma_rx = false;
|
|
||||||
atmel_port->use_pdc_rx = true;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
atmel_port->use_dma_rx = false;
|
atmel_port->use_dma_rx = false;
|
||||||
atmel_port->use_pdc_rx = false;
|
atmel_port->use_pdc_rx = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (of_property_read_bool(np, "atmel,use-dma-tx")) {
|
|
||||||
if (of_property_read_bool(np, "dmas")) {
|
|
||||||
atmel_port->use_dma_tx = true;
|
|
||||||
atmel_port->use_pdc_tx = false;
|
|
||||||
} else {
|
|
||||||
atmel_port->use_dma_tx = false;
|
|
||||||
atmel_port->use_pdc_tx = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
atmel_port->use_dma_tx = false;
|
|
||||||
atmel_port->use_pdc_tx = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
atmel_port->use_pdc_rx = pdata->use_dma_rx;
|
|
||||||
atmel_port->use_pdc_tx = pdata->use_dma_tx;
|
|
||||||
atmel_port->use_dma_rx = false;
|
atmel_port->use_dma_rx = false;
|
||||||
atmel_port->use_dma_tx = false;
|
atmel_port->use_pdc_rx = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (of_property_read_bool(np, "atmel,use-dma-tx")) {
|
||||||
|
if (of_property_read_bool(np, "dmas")) {
|
||||||
|
atmel_port->use_dma_tx = true;
|
||||||
|
atmel_port->use_pdc_tx = false;
|
||||||
|
} else {
|
||||||
|
atmel_port->use_dma_tx = false;
|
||||||
|
atmel_port->use_pdc_tx = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
atmel_port->use_dma_tx = false;
|
||||||
|
atmel_port->use_pdc_tx = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void atmel_init_rs485(struct uart_port *port,
|
static void atmel_init_rs485(struct uart_port *port,
|
||||||
struct platform_device *pdev)
|
struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device_node *np = pdev->dev.of_node;
|
struct device_node *np = pdev->dev.of_node;
|
||||||
struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
|
|
||||||
|
|
||||||
if (np) {
|
struct serial_rs485 *rs485conf = &port->rs485;
|
||||||
struct serial_rs485 *rs485conf = &port->rs485;
|
u32 rs485_delay[2];
|
||||||
u32 rs485_delay[2];
|
|
||||||
/* rs485 properties */
|
|
||||||
if (of_property_read_u32_array(np, "rs485-rts-delay",
|
|
||||||
rs485_delay, 2) == 0) {
|
|
||||||
rs485conf->delay_rts_before_send = rs485_delay[0];
|
|
||||||
rs485conf->delay_rts_after_send = rs485_delay[1];
|
|
||||||
rs485conf->flags = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (of_get_property(np, "rs485-rx-during-tx", NULL))
|
/* rs485 properties */
|
||||||
rs485conf->flags |= SER_RS485_RX_DURING_TX;
|
if (of_property_read_u32_array(np, "rs485-rts-delay",
|
||||||
|
rs485_delay, 2) == 0) {
|
||||||
if (of_get_property(np, "linux,rs485-enabled-at-boot-time",
|
rs485conf->delay_rts_before_send = rs485_delay[0];
|
||||||
NULL))
|
rs485conf->delay_rts_after_send = rs485_delay[1];
|
||||||
rs485conf->flags |= SER_RS485_ENABLED;
|
rs485conf->flags = 0;
|
||||||
} else {
|
|
||||||
port->rs485 = pdata->rs485;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (of_get_property(np, "rs485-rx-during-tx", NULL))
|
||||||
|
rs485conf->flags |= SER_RS485_RX_DURING_TX;
|
||||||
|
|
||||||
|
if (of_get_property(np, "linux,rs485-enabled-at-boot-time", NULL))
|
||||||
|
rs485conf->flags |= SER_RS485_ENABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void atmel_set_ops(struct uart_port *port)
|
static void atmel_set_ops(struct uart_port *port)
|
||||||
@ -2402,7 +2369,6 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct uart_port *port = &atmel_port->uart;
|
struct uart_port *port = &atmel_port->uart;
|
||||||
struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
|
|
||||||
|
|
||||||
atmel_init_property(atmel_port, pdev);
|
atmel_init_property(atmel_port, pdev);
|
||||||
atmel_set_ops(port);
|
atmel_set_ops(port);
|
||||||
@ -2410,24 +2376,17 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
|
|||||||
atmel_init_rs485(port, pdev);
|
atmel_init_rs485(port, pdev);
|
||||||
|
|
||||||
port->iotype = UPIO_MEM;
|
port->iotype = UPIO_MEM;
|
||||||
port->flags = UPF_BOOT_AUTOCONF;
|
port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
|
||||||
port->ops = &atmel_pops;
|
port->ops = &atmel_pops;
|
||||||
port->fifosize = 1;
|
port->fifosize = 1;
|
||||||
port->dev = &pdev->dev;
|
port->dev = &pdev->dev;
|
||||||
port->mapbase = pdev->resource[0].start;
|
port->mapbase = pdev->resource[0].start;
|
||||||
port->irq = pdev->resource[1].start;
|
port->irq = pdev->resource[1].start;
|
||||||
port->rs485_config = atmel_config_rs485;
|
port->rs485_config = atmel_config_rs485;
|
||||||
|
port->membase = NULL;
|
||||||
|
|
||||||
memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
|
memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
|
||||||
|
|
||||||
if (pdata && pdata->regs) {
|
|
||||||
/* Already mapped by setup code */
|
|
||||||
port->membase = pdata->regs;
|
|
||||||
} else {
|
|
||||||
port->flags |= UPF_IOREMAP;
|
|
||||||
port->membase = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* for console, the clock could already be configured */
|
/* for console, the clock could already be configured */
|
||||||
if (!atmel_port->clk) {
|
if (!atmel_port->clk) {
|
||||||
atmel_port->clk = clk_get(&pdev->dev, "usart");
|
atmel_port->clk = clk_get(&pdev->dev, "usart");
|
||||||
@ -2460,8 +2419,6 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct platform_device *atmel_default_console_device; /* the serial console device */
|
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
|
#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
|
||||||
static void atmel_console_putchar(struct uart_port *port, int ch)
|
static void atmel_console_putchar(struct uart_port *port, int ch)
|
||||||
{
|
{
|
||||||
@ -2594,47 +2551,6 @@ static struct console atmel_console = {
|
|||||||
|
|
||||||
#define ATMEL_CONSOLE_DEVICE (&atmel_console)
|
#define ATMEL_CONSOLE_DEVICE (&atmel_console)
|
||||||
|
|
||||||
/*
|
|
||||||
* Early console initialization (before VM subsystem initialized).
|
|
||||||
*/
|
|
||||||
static int __init atmel_console_init(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
if (atmel_default_console_device) {
|
|
||||||
struct atmel_uart_data *pdata =
|
|
||||||
dev_get_platdata(&atmel_default_console_device->dev);
|
|
||||||
int id = pdata->num;
|
|
||||||
struct atmel_uart_port *atmel_port = &atmel_ports[id];
|
|
||||||
|
|
||||||
atmel_port->backup_imr = 0;
|
|
||||||
atmel_port->uart.line = id;
|
|
||||||
|
|
||||||
add_preferred_console(ATMEL_DEVICENAME, id, NULL);
|
|
||||||
ret = atmel_init_port(atmel_port, atmel_default_console_device);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
register_console(&atmel_console);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
console_initcall(atmel_console_init);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Late console initialization.
|
|
||||||
*/
|
|
||||||
static int __init atmel_late_console_init(void)
|
|
||||||
{
|
|
||||||
if (atmel_default_console_device
|
|
||||||
&& !(atmel_console.flags & CON_ENABLED))
|
|
||||||
register_console(&atmel_console);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
core_initcall(atmel_late_console_init);
|
|
||||||
|
|
||||||
static inline bool atmel_is_console_port(struct uart_port *port)
|
static inline bool atmel_is_console_port(struct uart_port *port)
|
||||||
{
|
{
|
||||||
return port->cons && port->cons->index == port->line;
|
return port->cons && port->cons->index == port->line;
|
||||||
@ -2804,19 +2720,13 @@ static int atmel_serial_probe(struct platform_device *pdev)
|
|||||||
{
|
{
|
||||||
struct atmel_uart_port *atmel_port;
|
struct atmel_uart_port *atmel_port;
|
||||||
struct device_node *np = pdev->dev.of_node;
|
struct device_node *np = pdev->dev.of_node;
|
||||||
struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
|
|
||||||
void *data;
|
void *data;
|
||||||
int ret = -ENODEV;
|
int ret = -ENODEV;
|
||||||
bool rs485_enabled;
|
bool rs485_enabled;
|
||||||
|
|
||||||
BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
|
BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
|
||||||
|
|
||||||
if (np)
|
ret = of_alias_get_id(np, "serial");
|
||||||
ret = of_alias_get_id(np, "serial");
|
|
||||||
else
|
|
||||||
if (pdata)
|
|
||||||
ret = pdata->num;
|
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
/* port id not found in platform data nor device-tree aliases:
|
/* port id not found in platform data nor device-tree aliases:
|
||||||
* auto-enumerate it */
|
* auto-enumerate it */
|
||||||
|
@ -140,6 +140,8 @@
|
|||||||
#define UARTBAUD_SBNS 0x00002000
|
#define UARTBAUD_SBNS 0x00002000
|
||||||
#define UARTBAUD_SBR 0x00000000
|
#define UARTBAUD_SBR 0x00000000
|
||||||
#define UARTBAUD_SBR_MASK 0x1fff
|
#define UARTBAUD_SBR_MASK 0x1fff
|
||||||
|
#define UARTBAUD_OSR_MASK 0x1f
|
||||||
|
#define UARTBAUD_OSR_SHIFT 24
|
||||||
|
|
||||||
#define UARTSTAT_LBKDIF 0x80000000
|
#define UARTSTAT_LBKDIF 0x80000000
|
||||||
#define UARTSTAT_RXEDGIF 0x40000000
|
#define UARTSTAT_RXEDGIF 0x40000000
|
||||||
@ -231,12 +233,14 @@
|
|||||||
#define DEV_NAME "ttyLP"
|
#define DEV_NAME "ttyLP"
|
||||||
#define UART_NR 6
|
#define UART_NR 6
|
||||||
|
|
||||||
|
/* IMX lpuart has four extra unused regs located at the beginning */
|
||||||
|
#define IMX_REG_OFF 0x10
|
||||||
|
|
||||||
struct lpuart_port {
|
struct lpuart_port {
|
||||||
struct uart_port port;
|
struct uart_port port;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
unsigned int txfifo_size;
|
unsigned int txfifo_size;
|
||||||
unsigned int rxfifo_size;
|
unsigned int rxfifo_size;
|
||||||
bool lpuart32;
|
|
||||||
|
|
||||||
bool lpuart_dma_tx_use;
|
bool lpuart_dma_tx_use;
|
||||||
bool lpuart_dma_rx_use;
|
bool lpuart_dma_rx_use;
|
||||||
@ -258,13 +262,28 @@ struct lpuart_port {
|
|||||||
wait_queue_head_t dma_wait;
|
wait_queue_head_t dma_wait;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct lpuart_soc_data {
|
||||||
|
char iotype;
|
||||||
|
u8 reg_off;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct lpuart_soc_data vf_data = {
|
||||||
|
.iotype = UPIO_MEM,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct lpuart_soc_data ls_data = {
|
||||||
|
.iotype = UPIO_MEM32BE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct lpuart_soc_data imx_data = {
|
||||||
|
.iotype = UPIO_MEM32,
|
||||||
|
.reg_off = IMX_REG_OFF,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct of_device_id lpuart_dt_ids[] = {
|
static const struct of_device_id lpuart_dt_ids[] = {
|
||||||
{
|
{ .compatible = "fsl,vf610-lpuart", .data = &vf_data, },
|
||||||
.compatible = "fsl,vf610-lpuart",
|
{ .compatible = "fsl,ls1021a-lpuart", .data = &ls_data, },
|
||||||
},
|
{ .compatible = "fsl,imx7ulp-lpuart", .data = &imx_data, },
|
||||||
{
|
|
||||||
.compatible = "fsl,ls1021a-lpuart",
|
|
||||||
},
|
|
||||||
{ /* sentinel */ }
|
{ /* sentinel */ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
|
MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
|
||||||
@ -272,14 +291,29 @@ MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
|
|||||||
/* Forward declare this for the dma callbacks*/
|
/* Forward declare this for the dma callbacks*/
|
||||||
static void lpuart_dma_tx_complete(void *arg);
|
static void lpuart_dma_tx_complete(void *arg);
|
||||||
|
|
||||||
static u32 lpuart32_read(void __iomem *addr)
|
static inline u32 lpuart32_read(struct uart_port *port, u32 off)
|
||||||
{
|
{
|
||||||
return ioread32be(addr);
|
switch (port->iotype) {
|
||||||
|
case UPIO_MEM32:
|
||||||
|
return readl(port->membase + off);
|
||||||
|
case UPIO_MEM32BE:
|
||||||
|
return ioread32be(port->membase + off);
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lpuart32_write(u32 val, void __iomem *addr)
|
static inline void lpuart32_write(struct uart_port *port, u32 val,
|
||||||
|
u32 off)
|
||||||
{
|
{
|
||||||
iowrite32be(val, addr);
|
switch (port->iotype) {
|
||||||
|
case UPIO_MEM32:
|
||||||
|
writel(val, port->membase + off);
|
||||||
|
break;
|
||||||
|
case UPIO_MEM32BE:
|
||||||
|
iowrite32be(val, port->membase + off);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lpuart_stop_tx(struct uart_port *port)
|
static void lpuart_stop_tx(struct uart_port *port)
|
||||||
@ -295,9 +329,9 @@ static void lpuart32_stop_tx(struct uart_port *port)
|
|||||||
{
|
{
|
||||||
unsigned long temp;
|
unsigned long temp;
|
||||||
|
|
||||||
temp = lpuart32_read(port->membase + UARTCTRL);
|
temp = lpuart32_read(port, UARTCTRL);
|
||||||
temp &= ~(UARTCTRL_TIE | UARTCTRL_TCIE);
|
temp &= ~(UARTCTRL_TIE | UARTCTRL_TCIE);
|
||||||
lpuart32_write(temp, port->membase + UARTCTRL);
|
lpuart32_write(port, temp, UARTCTRL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lpuart_stop_rx(struct uart_port *port)
|
static void lpuart_stop_rx(struct uart_port *port)
|
||||||
@ -312,8 +346,8 @@ static void lpuart32_stop_rx(struct uart_port *port)
|
|||||||
{
|
{
|
||||||
unsigned long temp;
|
unsigned long temp;
|
||||||
|
|
||||||
temp = lpuart32_read(port->membase + UARTCTRL);
|
temp = lpuart32_read(port, UARTCTRL);
|
||||||
lpuart32_write(temp & ~UARTCTRL_RE, port->membase + UARTCTRL);
|
lpuart32_write(port, temp & ~UARTCTRL_RE, UARTCTRL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lpuart_dma_tx(struct lpuart_port *sport)
|
static void lpuart_dma_tx(struct lpuart_port *sport)
|
||||||
@ -512,14 +546,14 @@ static inline void lpuart32_transmit_buffer(struct lpuart_port *sport)
|
|||||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||||
unsigned long txcnt;
|
unsigned long txcnt;
|
||||||
|
|
||||||
txcnt = lpuart32_read(sport->port.membase + UARTWATER);
|
txcnt = lpuart32_read(&sport->port, UARTWATER);
|
||||||
txcnt = txcnt >> UARTWATER_TXCNT_OFF;
|
txcnt = txcnt >> UARTWATER_TXCNT_OFF;
|
||||||
txcnt &= UARTWATER_COUNT_MASK;
|
txcnt &= UARTWATER_COUNT_MASK;
|
||||||
while (!uart_circ_empty(xmit) && (txcnt < sport->txfifo_size)) {
|
while (!uart_circ_empty(xmit) && (txcnt < sport->txfifo_size)) {
|
||||||
lpuart32_write(xmit->buf[xmit->tail], sport->port.membase + UARTDATA);
|
lpuart32_write(&sport->port, xmit->buf[xmit->tail], UARTDATA);
|
||||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||||
sport->port.icount.tx++;
|
sport->port.icount.tx++;
|
||||||
txcnt = lpuart32_read(sport->port.membase + UARTWATER);
|
txcnt = lpuart32_read(&sport->port, UARTWATER);
|
||||||
txcnt = txcnt >> UARTWATER_TXCNT_OFF;
|
txcnt = txcnt >> UARTWATER_TXCNT_OFF;
|
||||||
txcnt &= UARTWATER_COUNT_MASK;
|
txcnt &= UARTWATER_COUNT_MASK;
|
||||||
}
|
}
|
||||||
@ -555,10 +589,10 @@ static void lpuart32_start_tx(struct uart_port *port)
|
|||||||
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
|
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
|
||||||
unsigned long temp;
|
unsigned long temp;
|
||||||
|
|
||||||
temp = lpuart32_read(port->membase + UARTCTRL);
|
temp = lpuart32_read(port, UARTCTRL);
|
||||||
lpuart32_write(temp | UARTCTRL_TIE, port->membase + UARTCTRL);
|
lpuart32_write(port, temp | UARTCTRL_TIE, UARTCTRL);
|
||||||
|
|
||||||
if (lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TDRE)
|
if (lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE)
|
||||||
lpuart32_transmit_buffer(sport);
|
lpuart32_transmit_buffer(sport);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -581,7 +615,7 @@ static unsigned int lpuart_tx_empty(struct uart_port *port)
|
|||||||
|
|
||||||
static unsigned int lpuart32_tx_empty(struct uart_port *port)
|
static unsigned int lpuart32_tx_empty(struct uart_port *port)
|
||||||
{
|
{
|
||||||
return (lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TC) ?
|
return (lpuart32_read(port, UARTSTAT) & UARTSTAT_TC) ?
|
||||||
TIOCSER_TEMT : 0;
|
TIOCSER_TEMT : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -593,22 +627,22 @@ static irqreturn_t lpuart_txint(int irq, void *dev_id)
|
|||||||
|
|
||||||
spin_lock_irqsave(&sport->port.lock, flags);
|
spin_lock_irqsave(&sport->port.lock, flags);
|
||||||
if (sport->port.x_char) {
|
if (sport->port.x_char) {
|
||||||
if (sport->lpuart32)
|
if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
||||||
lpuart32_write(sport->port.x_char, sport->port.membase + UARTDATA);
|
lpuart32_write(&sport->port, sport->port.x_char, UARTDATA);
|
||||||
else
|
else
|
||||||
writeb(sport->port.x_char, sport->port.membase + UARTDR);
|
writeb(sport->port.x_char, sport->port.membase + UARTDR);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
|
if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
|
||||||
if (sport->lpuart32)
|
if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
||||||
lpuart32_stop_tx(&sport->port);
|
lpuart32_stop_tx(&sport->port);
|
||||||
else
|
else
|
||||||
lpuart_stop_tx(&sport->port);
|
lpuart_stop_tx(&sport->port);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sport->lpuart32)
|
if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
||||||
lpuart32_transmit_buffer(sport);
|
lpuart32_transmit_buffer(sport);
|
||||||
else
|
else
|
||||||
lpuart_transmit_buffer(sport);
|
lpuart_transmit_buffer(sport);
|
||||||
@ -694,15 +728,15 @@ static irqreturn_t lpuart32_rxint(int irq, void *dev_id)
|
|||||||
|
|
||||||
spin_lock_irqsave(&sport->port.lock, flags);
|
spin_lock_irqsave(&sport->port.lock, flags);
|
||||||
|
|
||||||
while (!(lpuart32_read(sport->port.membase + UARTFIFO) & UARTFIFO_RXEMPT)) {
|
while (!(lpuart32_read(&sport->port, UARTFIFO) & UARTFIFO_RXEMPT)) {
|
||||||
flg = TTY_NORMAL;
|
flg = TTY_NORMAL;
|
||||||
sport->port.icount.rx++;
|
sport->port.icount.rx++;
|
||||||
/*
|
/*
|
||||||
* to clear the FE, OR, NF, FE, PE flags,
|
* to clear the FE, OR, NF, FE, PE flags,
|
||||||
* read STAT then read DATA reg
|
* read STAT then read DATA reg
|
||||||
*/
|
*/
|
||||||
sr = lpuart32_read(sport->port.membase + UARTSTAT);
|
sr = lpuart32_read(&sport->port, UARTSTAT);
|
||||||
rx = lpuart32_read(sport->port.membase + UARTDATA);
|
rx = lpuart32_read(&sport->port, UARTDATA);
|
||||||
rx &= 0x3ff;
|
rx &= 0x3ff;
|
||||||
|
|
||||||
if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
|
if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
|
||||||
@ -769,18 +803,18 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id)
|
|||||||
struct lpuart_port *sport = dev_id;
|
struct lpuart_port *sport = dev_id;
|
||||||
unsigned long sts, rxcount;
|
unsigned long sts, rxcount;
|
||||||
|
|
||||||
sts = lpuart32_read(sport->port.membase + UARTSTAT);
|
sts = lpuart32_read(&sport->port, UARTSTAT);
|
||||||
rxcount = lpuart32_read(sport->port.membase + UARTWATER);
|
rxcount = lpuart32_read(&sport->port, UARTWATER);
|
||||||
rxcount = rxcount >> UARTWATER_RXCNT_OFF;
|
rxcount = rxcount >> UARTWATER_RXCNT_OFF;
|
||||||
|
|
||||||
if (sts & UARTSTAT_RDRF || rxcount > 0)
|
if (sts & UARTSTAT_RDRF || rxcount > 0)
|
||||||
lpuart32_rxint(irq, dev_id);
|
lpuart32_rxint(irq, dev_id);
|
||||||
|
|
||||||
if ((sts & UARTSTAT_TDRE) &&
|
if ((sts & UARTSTAT_TDRE) &&
|
||||||
!(lpuart32_read(sport->port.membase + UARTBAUD) & UARTBAUD_TDMAE))
|
!(lpuart32_read(&sport->port, UARTBAUD) & UARTBAUD_TDMAE))
|
||||||
lpuart_txint(irq, dev_id);
|
lpuart_txint(irq, dev_id);
|
||||||
|
|
||||||
lpuart32_write(sts, sport->port.membase + UARTSTAT);
|
lpuart32_write(&sport->port, sts, UARTSTAT);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1041,7 +1075,7 @@ static unsigned int lpuart32_get_mctrl(struct uart_port *port)
|
|||||||
unsigned int temp = 0;
|
unsigned int temp = 0;
|
||||||
unsigned long reg;
|
unsigned long reg;
|
||||||
|
|
||||||
reg = lpuart32_read(port->membase + UARTMODIR);
|
reg = lpuart32_read(port, UARTMODIR);
|
||||||
if (reg & UARTMODIR_TXCTSE)
|
if (reg & UARTMODIR_TXCTSE)
|
||||||
temp |= TIOCM_CTS;
|
temp |= TIOCM_CTS;
|
||||||
|
|
||||||
@ -1076,7 +1110,7 @@ static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
|||||||
{
|
{
|
||||||
unsigned long temp;
|
unsigned long temp;
|
||||||
|
|
||||||
temp = lpuart32_read(port->membase + UARTMODIR) &
|
temp = lpuart32_read(port, UARTMODIR) &
|
||||||
~(UARTMODIR_RXRTSE | UARTMODIR_TXCTSE);
|
~(UARTMODIR_RXRTSE | UARTMODIR_TXCTSE);
|
||||||
|
|
||||||
if (mctrl & TIOCM_RTS)
|
if (mctrl & TIOCM_RTS)
|
||||||
@ -1085,7 +1119,7 @@ static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
|||||||
if (mctrl & TIOCM_CTS)
|
if (mctrl & TIOCM_CTS)
|
||||||
temp |= UARTMODIR_TXCTSE;
|
temp |= UARTMODIR_TXCTSE;
|
||||||
|
|
||||||
lpuart32_write(temp, port->membase + UARTMODIR);
|
lpuart32_write(port, temp, UARTMODIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lpuart_break_ctl(struct uart_port *port, int break_state)
|
static void lpuart_break_ctl(struct uart_port *port, int break_state)
|
||||||
@ -1104,12 +1138,12 @@ static void lpuart32_break_ctl(struct uart_port *port, int break_state)
|
|||||||
{
|
{
|
||||||
unsigned long temp;
|
unsigned long temp;
|
||||||
|
|
||||||
temp = lpuart32_read(port->membase + UARTCTRL) & ~UARTCTRL_SBK;
|
temp = lpuart32_read(port, UARTCTRL) & ~UARTCTRL_SBK;
|
||||||
|
|
||||||
if (break_state != 0)
|
if (break_state != 0)
|
||||||
temp |= UARTCTRL_SBK;
|
temp |= UARTCTRL_SBK;
|
||||||
|
|
||||||
lpuart32_write(temp, port->membase + UARTCTRL);
|
lpuart32_write(port, temp, UARTCTRL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lpuart_setup_watermark(struct lpuart_port *sport)
|
static void lpuart_setup_watermark(struct lpuart_port *sport)
|
||||||
@ -1149,24 +1183,24 @@ static void lpuart32_setup_watermark(struct lpuart_port *sport)
|
|||||||
unsigned long val, ctrl;
|
unsigned long val, ctrl;
|
||||||
unsigned long ctrl_saved;
|
unsigned long ctrl_saved;
|
||||||
|
|
||||||
ctrl = lpuart32_read(sport->port.membase + UARTCTRL);
|
ctrl = lpuart32_read(&sport->port, UARTCTRL);
|
||||||
ctrl_saved = ctrl;
|
ctrl_saved = ctrl;
|
||||||
ctrl &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_TE |
|
ctrl &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_TE |
|
||||||
UARTCTRL_RIE | UARTCTRL_RE);
|
UARTCTRL_RIE | UARTCTRL_RE);
|
||||||
lpuart32_write(ctrl, sport->port.membase + UARTCTRL);
|
lpuart32_write(&sport->port, ctrl, UARTCTRL);
|
||||||
|
|
||||||
/* enable FIFO mode */
|
/* enable FIFO mode */
|
||||||
val = lpuart32_read(sport->port.membase + UARTFIFO);
|
val = lpuart32_read(&sport->port, UARTFIFO);
|
||||||
val |= UARTFIFO_TXFE | UARTFIFO_RXFE;
|
val |= UARTFIFO_TXFE | UARTFIFO_RXFE;
|
||||||
val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
|
val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
|
||||||
lpuart32_write(val, sport->port.membase + UARTFIFO);
|
lpuart32_write(&sport->port, val, UARTFIFO);
|
||||||
|
|
||||||
/* set the watermark */
|
/* set the watermark */
|
||||||
val = (0x1 << UARTWATER_RXWATER_OFF) | (0x0 << UARTWATER_TXWATER_OFF);
|
val = (0x1 << UARTWATER_RXWATER_OFF) | (0x0 << UARTWATER_TXWATER_OFF);
|
||||||
lpuart32_write(val, sport->port.membase + UARTWATER);
|
lpuart32_write(&sport->port, val, UARTWATER);
|
||||||
|
|
||||||
/* Restore cr2 */
|
/* Restore cr2 */
|
||||||
lpuart32_write(ctrl_saved, sport->port.membase + UARTCTRL);
|
lpuart32_write(&sport->port, ctrl_saved, UARTCTRL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rx_dma_timer_init(struct lpuart_port *sport)
|
static void rx_dma_timer_init(struct lpuart_port *sport)
|
||||||
@ -1242,7 +1276,7 @@ static int lpuart32_startup(struct uart_port *port)
|
|||||||
unsigned long temp;
|
unsigned long temp;
|
||||||
|
|
||||||
/* determine FIFO size */
|
/* determine FIFO size */
|
||||||
temp = lpuart32_read(sport->port.membase + UARTFIFO);
|
temp = lpuart32_read(&sport->port, UARTFIFO);
|
||||||
|
|
||||||
sport->txfifo_size = 0x1 << (((temp >> UARTFIFO_TXSIZE_OFF) &
|
sport->txfifo_size = 0x1 << (((temp >> UARTFIFO_TXSIZE_OFF) &
|
||||||
UARTFIFO_FIFOSIZE_MASK) - 1);
|
UARTFIFO_FIFOSIZE_MASK) - 1);
|
||||||
@ -1259,10 +1293,10 @@ static int lpuart32_startup(struct uart_port *port)
|
|||||||
|
|
||||||
lpuart32_setup_watermark(sport);
|
lpuart32_setup_watermark(sport);
|
||||||
|
|
||||||
temp = lpuart32_read(sport->port.membase + UARTCTRL);
|
temp = lpuart32_read(&sport->port, UARTCTRL);
|
||||||
temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE | UARTCTRL_TE);
|
temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE | UARTCTRL_TE);
|
||||||
temp |= UARTCTRL_ILIE;
|
temp |= UARTCTRL_ILIE;
|
||||||
lpuart32_write(temp, sport->port.membase + UARTCTRL);
|
lpuart32_write(&sport->port, temp, UARTCTRL);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||||
return 0;
|
return 0;
|
||||||
@ -1311,10 +1345,10 @@ static void lpuart32_shutdown(struct uart_port *port)
|
|||||||
spin_lock_irqsave(&port->lock, flags);
|
spin_lock_irqsave(&port->lock, flags);
|
||||||
|
|
||||||
/* disable Rx/Tx and interrupts */
|
/* disable Rx/Tx and interrupts */
|
||||||
temp = lpuart32_read(port->membase + UARTCTRL);
|
temp = lpuart32_read(port, UARTCTRL);
|
||||||
temp &= ~(UARTCTRL_TE | UARTCTRL_RE |
|
temp &= ~(UARTCTRL_TE | UARTCTRL_RE |
|
||||||
UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE);
|
UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE);
|
||||||
lpuart32_write(temp, port->membase + UARTCTRL);
|
lpuart32_write(port, temp, UARTCTRL);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&port->lock, flags);
|
spin_unlock_irqrestore(&port->lock, flags);
|
||||||
|
|
||||||
@ -1478,6 +1512,75 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lpuart32_serial_setbrg(struct lpuart_port *sport, unsigned int baudrate)
|
||||||
|
{
|
||||||
|
u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp;
|
||||||
|
u32 clk = sport->port.uartclk;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The idea is to use the best OSR (over-sampling rate) possible.
|
||||||
|
* Note, OSR is typically hard-set to 16 in other LPUART instantiations.
|
||||||
|
* Loop to find the best OSR value possible, one that generates minimum
|
||||||
|
* baud_diff iterate through the rest of the supported values of OSR.
|
||||||
|
*
|
||||||
|
* Calculation Formula:
|
||||||
|
* Baud Rate = baud clock / ((OSR+1) × SBR)
|
||||||
|
*/
|
||||||
|
baud_diff = baudrate;
|
||||||
|
osr = 0;
|
||||||
|
sbr = 0;
|
||||||
|
|
||||||
|
for (tmp_osr = 4; tmp_osr <= 32; tmp_osr++) {
|
||||||
|
/* calculate the temporary sbr value */
|
||||||
|
tmp_sbr = (clk / (baudrate * tmp_osr));
|
||||||
|
if (tmp_sbr == 0)
|
||||||
|
tmp_sbr = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* calculate the baud rate difference based on the temporary
|
||||||
|
* osr and sbr values
|
||||||
|
*/
|
||||||
|
tmp_diff = clk / (tmp_osr * tmp_sbr) - baudrate;
|
||||||
|
|
||||||
|
/* select best values between sbr and sbr+1 */
|
||||||
|
tmp = clk / (tmp_osr * (tmp_sbr + 1));
|
||||||
|
if (tmp_diff > (baudrate - tmp)) {
|
||||||
|
tmp_diff = baudrate - tmp;
|
||||||
|
tmp_sbr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tmp_diff <= baud_diff) {
|
||||||
|
baud_diff = tmp_diff;
|
||||||
|
osr = tmp_osr;
|
||||||
|
sbr = tmp_sbr;
|
||||||
|
|
||||||
|
if (!baud_diff)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* handle buadrate outside acceptable rate */
|
||||||
|
if (baud_diff > ((baudrate / 100) * 3))
|
||||||
|
dev_warn(sport->port.dev,
|
||||||
|
"unacceptable baud rate difference of more than 3%%\n");
|
||||||
|
|
||||||
|
tmp = lpuart32_read(&sport->port, UARTBAUD);
|
||||||
|
|
||||||
|
if ((osr > 3) && (osr < 8))
|
||||||
|
tmp |= UARTBAUD_BOTHEDGE;
|
||||||
|
|
||||||
|
tmp &= ~(UARTBAUD_OSR_MASK << UARTBAUD_OSR_SHIFT);
|
||||||
|
tmp |= (((osr-1) & UARTBAUD_OSR_MASK) << UARTBAUD_OSR_SHIFT);
|
||||||
|
|
||||||
|
tmp &= ~UARTBAUD_SBR_MASK;
|
||||||
|
tmp |= sbr & UARTBAUD_SBR_MASK;
|
||||||
|
|
||||||
|
tmp &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE);
|
||||||
|
|
||||||
|
lpuart32_write(&sport->port, tmp, UARTBAUD);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
|
lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
struct ktermios *old)
|
struct ktermios *old)
|
||||||
@ -1487,11 +1590,10 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||||||
unsigned long ctrl, old_ctrl, bd, modem;
|
unsigned long ctrl, old_ctrl, bd, modem;
|
||||||
unsigned int baud;
|
unsigned int baud;
|
||||||
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
|
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
|
||||||
unsigned int sbr;
|
|
||||||
|
|
||||||
ctrl = old_ctrl = lpuart32_read(sport->port.membase + UARTCTRL);
|
ctrl = old_ctrl = lpuart32_read(&sport->port, UARTCTRL);
|
||||||
bd = lpuart32_read(sport->port.membase + UARTBAUD);
|
bd = lpuart32_read(&sport->port, UARTBAUD);
|
||||||
modem = lpuart32_read(sport->port.membase + UARTMODIR);
|
modem = lpuart32_read(&sport->port, UARTMODIR);
|
||||||
/*
|
/*
|
||||||
* only support CS8 and CS7, and for CS7 must enable PE.
|
* only support CS8 and CS7, and for CS7 must enable PE.
|
||||||
* supported mode:
|
* supported mode:
|
||||||
@ -1577,21 +1679,16 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||||||
uart_update_timeout(port, termios->c_cflag, baud);
|
uart_update_timeout(port, termios->c_cflag, baud);
|
||||||
|
|
||||||
/* wait transmit engin complete */
|
/* wait transmit engin complete */
|
||||||
while (!(lpuart32_read(sport->port.membase + UARTSTAT) & UARTSTAT_TC))
|
while (!(lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_TC))
|
||||||
barrier();
|
barrier();
|
||||||
|
|
||||||
/* disable transmit and receive */
|
/* disable transmit and receive */
|
||||||
lpuart32_write(old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE),
|
lpuart32_write(&sport->port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE),
|
||||||
sport->port.membase + UARTCTRL);
|
UARTCTRL);
|
||||||
|
|
||||||
sbr = sport->port.uartclk / (16 * baud);
|
lpuart32_serial_setbrg(sport, baud);
|
||||||
bd &= ~UARTBAUD_SBR_MASK;
|
lpuart32_write(&sport->port, modem, UARTMODIR);
|
||||||
bd |= sbr & UARTBAUD_SBR_MASK;
|
lpuart32_write(&sport->port, ctrl, UARTCTRL);
|
||||||
bd |= UARTBAUD_BOTHEDGE;
|
|
||||||
bd &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE);
|
|
||||||
lpuart32_write(bd, sport->port.membase + UARTBAUD);
|
|
||||||
lpuart32_write(modem, sport->port.membase + UARTMODIR);
|
|
||||||
lpuart32_write(ctrl, sport->port.membase + UARTCTRL);
|
|
||||||
/* restore control register */
|
/* restore control register */
|
||||||
|
|
||||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||||
@ -1694,10 +1791,10 @@ static void lpuart_console_putchar(struct uart_port *port, int ch)
|
|||||||
|
|
||||||
static void lpuart32_console_putchar(struct uart_port *port, int ch)
|
static void lpuart32_console_putchar(struct uart_port *port, int ch)
|
||||||
{
|
{
|
||||||
while (!(lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TDRE))
|
while (!(lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE))
|
||||||
barrier();
|
barrier();
|
||||||
|
|
||||||
lpuart32_write(ch, port->membase + UARTDATA);
|
lpuart32_write(port, ch, UARTDATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1745,18 +1842,18 @@ lpuart32_console_write(struct console *co, const char *s, unsigned int count)
|
|||||||
spin_lock_irqsave(&sport->port.lock, flags);
|
spin_lock_irqsave(&sport->port.lock, flags);
|
||||||
|
|
||||||
/* first save CR2 and then disable interrupts */
|
/* first save CR2 and then disable interrupts */
|
||||||
cr = old_cr = lpuart32_read(sport->port.membase + UARTCTRL);
|
cr = old_cr = lpuart32_read(&sport->port, UARTCTRL);
|
||||||
cr |= (UARTCTRL_TE | UARTCTRL_RE);
|
cr |= (UARTCTRL_TE | UARTCTRL_RE);
|
||||||
cr &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE);
|
cr &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE);
|
||||||
lpuart32_write(cr, sport->port.membase + UARTCTRL);
|
lpuart32_write(&sport->port, cr, UARTCTRL);
|
||||||
|
|
||||||
uart_console_write(&sport->port, s, count, lpuart32_console_putchar);
|
uart_console_write(&sport->port, s, count, lpuart32_console_putchar);
|
||||||
|
|
||||||
/* wait for transmitter finish complete and restore CR2 */
|
/* wait for transmitter finish complete and restore CR2 */
|
||||||
while (!(lpuart32_read(sport->port.membase + UARTSTAT) & UARTSTAT_TC))
|
while (!(lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_TC))
|
||||||
barrier();
|
barrier();
|
||||||
|
|
||||||
lpuart32_write(old_cr, sport->port.membase + UARTCTRL);
|
lpuart32_write(&sport->port, old_cr, UARTCTRL);
|
||||||
|
|
||||||
if (locked)
|
if (locked)
|
||||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||||
@ -1822,14 +1919,14 @@ lpuart32_console_get_options(struct lpuart_port *sport, int *baud,
|
|||||||
unsigned long cr, bd;
|
unsigned long cr, bd;
|
||||||
unsigned int sbr, uartclk, baud_raw;
|
unsigned int sbr, uartclk, baud_raw;
|
||||||
|
|
||||||
cr = lpuart32_read(sport->port.membase + UARTCTRL);
|
cr = lpuart32_read(&sport->port, UARTCTRL);
|
||||||
cr &= UARTCTRL_TE | UARTCTRL_RE;
|
cr &= UARTCTRL_TE | UARTCTRL_RE;
|
||||||
if (!cr)
|
if (!cr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ok, the port was enabled */
|
/* ok, the port was enabled */
|
||||||
|
|
||||||
cr = lpuart32_read(sport->port.membase + UARTCTRL);
|
cr = lpuart32_read(&sport->port, UARTCTRL);
|
||||||
|
|
||||||
*parity = 'n';
|
*parity = 'n';
|
||||||
if (cr & UARTCTRL_PE) {
|
if (cr & UARTCTRL_PE) {
|
||||||
@ -1844,7 +1941,7 @@ lpuart32_console_get_options(struct lpuart_port *sport, int *baud,
|
|||||||
else
|
else
|
||||||
*bits = 8;
|
*bits = 8;
|
||||||
|
|
||||||
bd = lpuart32_read(sport->port.membase + UARTBAUD);
|
bd = lpuart32_read(&sport->port, UARTBAUD);
|
||||||
bd &= UARTBAUD_SBR_MASK;
|
bd &= UARTBAUD_SBR_MASK;
|
||||||
sbr = bd;
|
sbr = bd;
|
||||||
uartclk = clk_get_rate(sport->clk);
|
uartclk = clk_get_rate(sport->clk);
|
||||||
@ -1881,12 +1978,12 @@ static int __init lpuart_console_setup(struct console *co, char *options)
|
|||||||
if (options)
|
if (options)
|
||||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||||
else
|
else
|
||||||
if (sport->lpuart32)
|
if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
||||||
lpuart32_console_get_options(sport, &baud, &parity, &bits);
|
lpuart32_console_get_options(sport, &baud, &parity, &bits);
|
||||||
else
|
else
|
||||||
lpuart_console_get_options(sport, &baud, &parity, &bits);
|
lpuart_console_get_options(sport, &baud, &parity, &bits);
|
||||||
|
|
||||||
if (sport->lpuart32)
|
if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
||||||
lpuart32_setup_watermark(sport);
|
lpuart32_setup_watermark(sport);
|
||||||
else
|
else
|
||||||
lpuart_setup_watermark(sport);
|
lpuart_setup_watermark(sport);
|
||||||
@ -1945,12 +2042,26 @@ static int __init lpuart32_early_console_setup(struct earlycon_device *device,
|
|||||||
if (!device->port.membase)
|
if (!device->port.membase)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
device->port.iotype = UPIO_MEM32BE;
|
||||||
device->con->write = lpuart32_early_write;
|
device->con->write = lpuart32_early_write;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __init lpuart32_imx_early_console_setup(struct earlycon_device *device,
|
||||||
|
const char *opt)
|
||||||
|
{
|
||||||
|
if (!device->port.membase)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
device->port.iotype = UPIO_MEM32;
|
||||||
|
device->port.membase += IMX_REG_OFF;
|
||||||
|
device->con->write = lpuart32_early_write;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-lpuart", lpuart_early_console_setup);
|
OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-lpuart", lpuart_early_console_setup);
|
||||||
OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup);
|
OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup);
|
||||||
|
OF_EARLYCON_DECLARE(lpuart32, "fsl,imx7ulp-lpuart", lpuart32_imx_early_console_setup);
|
||||||
EARLYCON_DECLARE(lpuart, lpuart_early_console_setup);
|
EARLYCON_DECLARE(lpuart, lpuart_early_console_setup);
|
||||||
EARLYCON_DECLARE(lpuart32, lpuart32_early_console_setup);
|
EARLYCON_DECLARE(lpuart32, lpuart32_early_console_setup);
|
||||||
|
|
||||||
@ -1971,6 +2082,9 @@ static struct uart_driver lpuart_reg = {
|
|||||||
|
|
||||||
static int lpuart_probe(struct platform_device *pdev)
|
static int lpuart_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
const struct of_device_id *of_id = of_match_device(lpuart_dt_ids,
|
||||||
|
&pdev->dev);
|
||||||
|
const struct lpuart_soc_data *sdata = of_id->data;
|
||||||
struct device_node *np = pdev->dev.of_node;
|
struct device_node *np = pdev->dev.of_node;
|
||||||
struct lpuart_port *sport;
|
struct lpuart_port *sport;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
@ -1988,25 +2102,23 @@ static int lpuart_probe(struct platform_device *pdev)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
sport->port.line = ret;
|
sport->port.line = ret;
|
||||||
sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart");
|
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
sport->port.membase = devm_ioremap_resource(&pdev->dev, res);
|
sport->port.membase = devm_ioremap_resource(&pdev->dev, res);
|
||||||
if (IS_ERR(sport->port.membase))
|
if (IS_ERR(sport->port.membase))
|
||||||
return PTR_ERR(sport->port.membase);
|
return PTR_ERR(sport->port.membase);
|
||||||
|
|
||||||
|
sport->port.membase += sdata->reg_off;
|
||||||
sport->port.mapbase = res->start;
|
sport->port.mapbase = res->start;
|
||||||
sport->port.dev = &pdev->dev;
|
sport->port.dev = &pdev->dev;
|
||||||
sport->port.type = PORT_LPUART;
|
sport->port.type = PORT_LPUART;
|
||||||
sport->port.iotype = UPIO_MEM;
|
|
||||||
ret = platform_get_irq(pdev, 0);
|
ret = platform_get_irq(pdev, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "cannot obtain irq\n");
|
dev_err(&pdev->dev, "cannot obtain irq\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
sport->port.irq = ret;
|
sport->port.irq = ret;
|
||||||
|
sport->port.iotype = sdata->iotype;
|
||||||
if (sport->lpuart32)
|
if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
||||||
sport->port.ops = &lpuart32_pops;
|
sport->port.ops = &lpuart32_pops;
|
||||||
else
|
else
|
||||||
sport->port.ops = &lpuart_pops;
|
sport->port.ops = &lpuart_pops;
|
||||||
@ -2033,7 +2145,7 @@ static int lpuart_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
platform_set_drvdata(pdev, &sport->port);
|
platform_set_drvdata(pdev, &sport->port);
|
||||||
|
|
||||||
if (sport->lpuart32)
|
if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
||||||
lpuart_reg.cons = LPUART32_CONSOLE;
|
lpuart_reg.cons = LPUART32_CONSOLE;
|
||||||
else
|
else
|
||||||
lpuart_reg.cons = LPUART_CONSOLE;
|
lpuart_reg.cons = LPUART_CONSOLE;
|
||||||
@ -2086,11 +2198,11 @@ static int lpuart_suspend(struct device *dev)
|
|||||||
struct lpuart_port *sport = dev_get_drvdata(dev);
|
struct lpuart_port *sport = dev_get_drvdata(dev);
|
||||||
unsigned long temp;
|
unsigned long temp;
|
||||||
|
|
||||||
if (sport->lpuart32) {
|
if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE)) {
|
||||||
/* disable Rx/Tx and interrupts */
|
/* disable Rx/Tx and interrupts */
|
||||||
temp = lpuart32_read(sport->port.membase + UARTCTRL);
|
temp = lpuart32_read(&sport->port, UARTCTRL);
|
||||||
temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
|
temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
|
||||||
lpuart32_write(temp, sport->port.membase + UARTCTRL);
|
lpuart32_write(&sport->port, temp, UARTCTRL);
|
||||||
} else {
|
} else {
|
||||||
/* disable Rx/Tx and interrupts */
|
/* disable Rx/Tx and interrupts */
|
||||||
temp = readb(sport->port.membase + UARTCR2);
|
temp = readb(sport->port.membase + UARTCR2);
|
||||||
@ -2137,12 +2249,12 @@ static int lpuart_resume(struct device *dev)
|
|||||||
if (sport->port.suspended && !sport->port.irq_wake)
|
if (sport->port.suspended && !sport->port.irq_wake)
|
||||||
clk_prepare_enable(sport->clk);
|
clk_prepare_enable(sport->clk);
|
||||||
|
|
||||||
if (sport->lpuart32) {
|
if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE)) {
|
||||||
lpuart32_setup_watermark(sport);
|
lpuart32_setup_watermark(sport);
|
||||||
temp = lpuart32_read(sport->port.membase + UARTCTRL);
|
temp = lpuart32_read(&sport->port, UARTCTRL);
|
||||||
temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE |
|
temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE |
|
||||||
UARTCTRL_TE | UARTCTRL_ILIE);
|
UARTCTRL_TE | UARTCTRL_ILIE);
|
||||||
lpuart32_write(temp, sport->port.membase + UARTCTRL);
|
lpuart32_write(&sport->port, temp, UARTCTRL);
|
||||||
} else {
|
} else {
|
||||||
lpuart_setup_watermark(sport);
|
lpuart_setup_watermark(sport);
|
||||||
temp = readb(sport->port.membase + UARTCR2);
|
temp = readb(sport->port.membase + UARTCR2);
|
||||||
|
@ -186,6 +186,11 @@
|
|||||||
|
|
||||||
#define UART_NR 8
|
#define UART_NR 8
|
||||||
|
|
||||||
|
/* RX DMA buffer periods */
|
||||||
|
#define RX_DMA_PERIODS 4
|
||||||
|
#define RX_BUF_SIZE (PAGE_SIZE)
|
||||||
|
|
||||||
|
|
||||||
/* i.MX21 type uart runs on all i.mx except i.MX1 and i.MX6q */
|
/* i.MX21 type uart runs on all i.mx except i.MX1 and i.MX6q */
|
||||||
enum imx_uart_type {
|
enum imx_uart_type {
|
||||||
IMX1_UART,
|
IMX1_UART,
|
||||||
@ -207,9 +212,6 @@ struct imx_port {
|
|||||||
unsigned int have_rtscts:1;
|
unsigned int have_rtscts:1;
|
||||||
unsigned int have_rtsgpio:1;
|
unsigned int have_rtsgpio:1;
|
||||||
unsigned int dte_mode:1;
|
unsigned int dte_mode:1;
|
||||||
unsigned int irda_inv_rx:1;
|
|
||||||
unsigned int irda_inv_tx:1;
|
|
||||||
unsigned short trcv_delay; /* transceiver delay */
|
|
||||||
struct clk *clk_ipg;
|
struct clk *clk_ipg;
|
||||||
struct clk *clk_per;
|
struct clk *clk_per;
|
||||||
const struct imx_uart_data *devdata;
|
const struct imx_uart_data *devdata;
|
||||||
@ -224,6 +226,7 @@ struct imx_port {
|
|||||||
struct dma_chan *dma_chan_rx, *dma_chan_tx;
|
struct dma_chan *dma_chan_rx, *dma_chan_tx;
|
||||||
struct scatterlist rx_sgl, tx_sgl[2];
|
struct scatterlist rx_sgl, tx_sgl[2];
|
||||||
void *rx_buf;
|
void *rx_buf;
|
||||||
|
unsigned int rx_buf_size;
|
||||||
struct circ_buf rx_ring;
|
struct circ_buf rx_ring;
|
||||||
unsigned int rx_periods;
|
unsigned int rx_periods;
|
||||||
dma_cookie_t rx_cookie;
|
dma_cookie_t rx_cookie;
|
||||||
@ -964,8 +967,6 @@ static void imx_timeout(unsigned long data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RX_BUF_SIZE (PAGE_SIZE)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There are two kinds of RX DMA interrupts(such as in the MX6Q):
|
* There are two kinds of RX DMA interrupts(such as in the MX6Q):
|
||||||
* [1] the RX DMA buffer is full.
|
* [1] the RX DMA buffer is full.
|
||||||
@ -1048,9 +1049,6 @@ static void dma_rx_callback(void *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RX DMA buffer periods */
|
|
||||||
#define RX_DMA_PERIODS 4
|
|
||||||
|
|
||||||
static int start_rx_dma(struct imx_port *sport)
|
static int start_rx_dma(struct imx_port *sport)
|
||||||
{
|
{
|
||||||
struct scatterlist *sgl = &sport->rx_sgl;
|
struct scatterlist *sgl = &sport->rx_sgl;
|
||||||
@ -1061,9 +1059,8 @@ static int start_rx_dma(struct imx_port *sport)
|
|||||||
|
|
||||||
sport->rx_ring.head = 0;
|
sport->rx_ring.head = 0;
|
||||||
sport->rx_ring.tail = 0;
|
sport->rx_ring.tail = 0;
|
||||||
sport->rx_periods = RX_DMA_PERIODS;
|
|
||||||
|
|
||||||
sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE);
|
sg_init_one(sgl, sport->rx_buf, sport->rx_buf_size);
|
||||||
ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE);
|
ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
dev_err(dev, "DMA mapping error for RX.\n");
|
dev_err(dev, "DMA mapping error for RX.\n");
|
||||||
@ -1174,7 +1171,7 @@ static int imx_uart_dma_init(struct imx_port *sport)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
sport->rx_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
sport->rx_buf = kzalloc(sport->rx_buf_size, GFP_KERNEL);
|
||||||
if (!sport->rx_buf) {
|
if (!sport->rx_buf) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err;
|
goto err;
|
||||||
@ -1302,7 +1299,9 @@ static int imx_startup(struct uart_port *port)
|
|||||||
imx_enable_dma(sport);
|
imx_enable_dma(sport);
|
||||||
|
|
||||||
temp = readl(sport->port.membase + UCR1);
|
temp = readl(sport->port.membase + UCR1);
|
||||||
temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
|
temp |= UCR1_RRDYEN | UCR1_UARTEN;
|
||||||
|
if (sport->have_rtscts)
|
||||||
|
temp |= UCR1_RTSDEN;
|
||||||
|
|
||||||
writel(temp, sport->port.membase + UCR1);
|
writel(temp, sport->port.membase + UCR1);
|
||||||
|
|
||||||
@ -1340,29 +1339,13 @@ static int imx_startup(struct uart_port *port)
|
|||||||
imx_enable_ms(&sport->port);
|
imx_enable_ms(&sport->port);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the serial port is opened for reading start RX DMA immediately
|
* Start RX DMA immediately instead of waiting for RX FIFO interrupts.
|
||||||
* instead of waiting for RX FIFO interrupts. In our iMX53 the average
|
* In our iMX53 the average delay for the first reception dropped from
|
||||||
* delay for the first reception dropped from approximately 35000
|
* approximately 35000 microseconds to 1000 microseconds.
|
||||||
* microseconds to 1000 microseconds.
|
|
||||||
*/
|
*/
|
||||||
if (sport->dma_is_enabled) {
|
if (sport->dma_is_enabled) {
|
||||||
struct tty_struct *tty = sport->port.state->port.tty;
|
imx_disable_rx_int(sport);
|
||||||
struct tty_file_private *file_priv;
|
start_rx_dma(sport);
|
||||||
int readcnt = 0;
|
|
||||||
|
|
||||||
spin_lock(&tty->files_lock);
|
|
||||||
|
|
||||||
if (!list_empty(&tty->tty_files))
|
|
||||||
list_for_each_entry(file_priv, &tty->tty_files, list)
|
|
||||||
if (!(file_priv->file->f_flags & O_WRONLY))
|
|
||||||
readcnt++;
|
|
||||||
|
|
||||||
spin_unlock(&tty->files_lock);
|
|
||||||
|
|
||||||
if (readcnt > 0) {
|
|
||||||
imx_disable_rx_int(sport);
|
|
||||||
start_rx_dma(sport);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||||
@ -2053,6 +2036,7 @@ static int serial_imx_probe_dt(struct imx_port *sport,
|
|||||||
{
|
{
|
||||||
struct device_node *np = pdev->dev.of_node;
|
struct device_node *np = pdev->dev.of_node;
|
||||||
int ret;
|
int ret;
|
||||||
|
u32 dma_buf_size[2];
|
||||||
|
|
||||||
sport->devdata = of_device_get_match_data(&pdev->dev);
|
sport->devdata = of_device_get_match_data(&pdev->dev);
|
||||||
if (!sport->devdata)
|
if (!sport->devdata)
|
||||||
@ -2076,6 +2060,14 @@ static int serial_imx_probe_dt(struct imx_port *sport,
|
|||||||
if (of_get_property(np, "rts-gpios", NULL))
|
if (of_get_property(np, "rts-gpios", NULL))
|
||||||
sport->have_rtsgpio = 1;
|
sport->have_rtsgpio = 1;
|
||||||
|
|
||||||
|
if (!of_property_read_u32_array(np, "fsl,dma-size", dma_buf_size, 2)) {
|
||||||
|
sport->rx_buf_size = dma_buf_size[0] * dma_buf_size[1];
|
||||||
|
sport->rx_periods = dma_buf_size[1];
|
||||||
|
} else {
|
||||||
|
sport->rx_buf_size = RX_BUF_SIZE;
|
||||||
|
sport->rx_periods = RX_DMA_PERIODS;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -286,7 +286,7 @@ static int meson_uart_startup(struct uart_port *port)
|
|||||||
writel(val, port->membase + AML_UART_MISC);
|
writel(val, port->membase + AML_UART_MISC);
|
||||||
|
|
||||||
ret = request_irq(port->irq, meson_uart_interrupt, 0,
|
ret = request_irq(port->irq, meson_uart_interrupt, 0,
|
||||||
meson_uart_type(port), port);
|
port->name, port);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -298,8 +298,6 @@ static void meson_uart_change_speed(struct uart_port *port, unsigned long baud)
|
|||||||
while (!meson_uart_tx_empty(port))
|
while (!meson_uart_tx_empty(port))
|
||||||
cpu_relax();
|
cpu_relax();
|
||||||
|
|
||||||
val = readl(port->membase + AML_UART_REG5);
|
|
||||||
val &= ~AML_UART_BAUD_MASK;
|
|
||||||
if (port->uartclk == 24000000) {
|
if (port->uartclk == 24000000) {
|
||||||
val = ((port->uartclk / 3) / baud) - 1;
|
val = ((port->uartclk / 3) / baud) - 1;
|
||||||
val |= AML_UART_BAUD_XTAL;
|
val |= AML_UART_BAUD_XTAL;
|
||||||
@ -355,7 +353,7 @@ static void meson_uart_set_termios(struct uart_port *port,
|
|||||||
if (cflags & CSTOPB)
|
if (cflags & CSTOPB)
|
||||||
val |= AML_UART_STOP_BIN_2SB;
|
val |= AML_UART_STOP_BIN_2SB;
|
||||||
else
|
else
|
||||||
val &= ~AML_UART_STOP_BIN_1SB;
|
val |= AML_UART_STOP_BIN_1SB;
|
||||||
|
|
||||||
if (cflags & CRTSCTS)
|
if (cflags & CRTSCTS)
|
||||||
val &= ~AML_UART_TWO_WIRE_EN;
|
val &= ~AML_UART_TWO_WIRE_EN;
|
||||||
@ -395,51 +393,25 @@ static int meson_uart_verify_port(struct uart_port *port,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int meson_uart_res_size(struct uart_port *port)
|
|
||||||
{
|
|
||||||
struct platform_device *pdev = to_platform_device(port->dev);
|
|
||||||
struct resource *res;
|
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
||||||
if (!res) {
|
|
||||||
dev_err(port->dev, "cannot obtain I/O memory region");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
return resource_size(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void meson_uart_release_port(struct uart_port *port)
|
static void meson_uart_release_port(struct uart_port *port)
|
||||||
{
|
{
|
||||||
int size = meson_uart_res_size(port);
|
devm_iounmap(port->dev, port->membase);
|
||||||
|
port->membase = NULL;
|
||||||
if (port->flags & UPF_IOREMAP) {
|
devm_release_mem_region(port->dev, port->mapbase, port->mapsize);
|
||||||
devm_release_mem_region(port->dev, port->mapbase, size);
|
|
||||||
devm_iounmap(port->dev, port->membase);
|
|
||||||
port->membase = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int meson_uart_request_port(struct uart_port *port)
|
static int meson_uart_request_port(struct uart_port *port)
|
||||||
{
|
{
|
||||||
int size = meson_uart_res_size(port);
|
if (!devm_request_mem_region(port->dev, port->mapbase, port->mapsize,
|
||||||
|
|
||||||
if (size < 0)
|
|
||||||
return size;
|
|
||||||
|
|
||||||
if (!devm_request_mem_region(port->dev, port->mapbase, size,
|
|
||||||
dev_name(port->dev))) {
|
dev_name(port->dev))) {
|
||||||
dev_err(port->dev, "Memory region busy\n");
|
dev_err(port->dev, "Memory region busy\n");
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port->flags & UPF_IOREMAP) {
|
port->membase = devm_ioremap_nocache(port->dev, port->mapbase,
|
||||||
port->membase = devm_ioremap_nocache(port->dev,
|
port->mapsize);
|
||||||
port->mapbase,
|
if (!port->membase)
|
||||||
size);
|
return -ENOMEM;
|
||||||
if (port->membase == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -470,6 +442,14 @@ static struct uart_ops meson_uart_ops = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_MESON_CONSOLE
|
#ifdef CONFIG_SERIAL_MESON_CONSOLE
|
||||||
|
static void meson_uart_enable_tx_engine(struct uart_port *port)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
val = readl(port->membase + AML_UART_CONTROL);
|
||||||
|
val |= AML_UART_TX_EN;
|
||||||
|
writel(val, port->membase + AML_UART_CONTROL);
|
||||||
|
}
|
||||||
|
|
||||||
static void meson_console_putchar(struct uart_port *port, int ch)
|
static void meson_console_putchar(struct uart_port *port, int ch)
|
||||||
{
|
{
|
||||||
@ -499,7 +479,6 @@ static void meson_serial_port_write(struct uart_port *port, const char *s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
val = readl(port->membase + AML_UART_CONTROL);
|
val = readl(port->membase + AML_UART_CONTROL);
|
||||||
val |= AML_UART_TX_EN;
|
|
||||||
tmp = val & ~(AML_UART_TX_INT_EN | AML_UART_RX_INT_EN);
|
tmp = val & ~(AML_UART_TX_INT_EN | AML_UART_RX_INT_EN);
|
||||||
writel(tmp, port->membase + AML_UART_CONTROL);
|
writel(tmp, port->membase + AML_UART_CONTROL);
|
||||||
|
|
||||||
@ -538,6 +517,8 @@ static int meson_serial_console_setup(struct console *co, char *options)
|
|||||||
if (!port || !port->membase)
|
if (!port || !port->membase)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
meson_uart_enable_tx_engine(port);
|
||||||
|
|
||||||
if (options)
|
if (options)
|
||||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||||
|
|
||||||
@ -576,11 +557,16 @@ meson_serial_early_console_setup(struct earlycon_device *device, const char *opt
|
|||||||
if (!device->port.membase)
|
if (!device->port.membase)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
meson_uart_enable_tx_engine(&device->port);
|
||||||
device->con->write = meson_serial_early_console_write;
|
device->con->write = meson_serial_early_console_write;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
/* Legacy bindings, should be removed when no more used */
|
||||||
OF_EARLYCON_DECLARE(meson, "amlogic,meson-uart",
|
OF_EARLYCON_DECLARE(meson, "amlogic,meson-uart",
|
||||||
meson_serial_early_console_setup);
|
meson_serial_early_console_setup);
|
||||||
|
/* Stable bindings */
|
||||||
|
OF_EARLYCON_DECLARE(meson, "amlogic,meson-ao-uart",
|
||||||
|
meson_serial_early_console_setup);
|
||||||
|
|
||||||
#define MESON_SERIAL_CONSOLE (&meson_serial_console)
|
#define MESON_SERIAL_CONSOLE (&meson_serial_console)
|
||||||
#else
|
#else
|
||||||
@ -595,11 +581,76 @@ static struct uart_driver meson_uart_driver = {
|
|||||||
.cons = MESON_SERIAL_CONSOLE,
|
.cons = MESON_SERIAL_CONSOLE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline struct clk *meson_uart_probe_clock(struct device *dev,
|
||||||
|
const char *id)
|
||||||
|
{
|
||||||
|
struct clk *clk = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
clk = devm_clk_get(dev, id);
|
||||||
|
if (IS_ERR(clk))
|
||||||
|
return clk;
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(clk);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "couldn't enable clk\n");
|
||||||
|
return ERR_PTR(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
devm_add_action_or_reset(dev,
|
||||||
|
(void(*)(void *))clk_disable_unprepare,
|
||||||
|
clk);
|
||||||
|
|
||||||
|
return clk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function gets clocks in the legacy non-stable DT bindings.
|
||||||
|
* This code will be remove once all the platforms switch to the
|
||||||
|
* new DT bindings.
|
||||||
|
*/
|
||||||
|
static int meson_uart_probe_clocks_legacy(struct platform_device *pdev,
|
||||||
|
struct uart_port *port)
|
||||||
|
{
|
||||||
|
struct clk *clk = NULL;
|
||||||
|
|
||||||
|
clk = meson_uart_probe_clock(&pdev->dev, NULL);
|
||||||
|
if (IS_ERR(clk))
|
||||||
|
return PTR_ERR(clk);
|
||||||
|
|
||||||
|
port->uartclk = clk_get_rate(clk);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int meson_uart_probe_clocks(struct platform_device *pdev,
|
||||||
|
struct uart_port *port)
|
||||||
|
{
|
||||||
|
struct clk *clk_xtal = NULL;
|
||||||
|
struct clk *clk_pclk = NULL;
|
||||||
|
struct clk *clk_baud = NULL;
|
||||||
|
|
||||||
|
clk_pclk = meson_uart_probe_clock(&pdev->dev, "pclk");
|
||||||
|
if (IS_ERR(clk_pclk))
|
||||||
|
return PTR_ERR(clk_pclk);
|
||||||
|
|
||||||
|
clk_xtal = meson_uart_probe_clock(&pdev->dev, "xtal");
|
||||||
|
if (IS_ERR(clk_xtal))
|
||||||
|
return PTR_ERR(clk_xtal);
|
||||||
|
|
||||||
|
clk_baud = meson_uart_probe_clock(&pdev->dev, "baud");
|
||||||
|
if (IS_ERR(clk_baud))
|
||||||
|
return PTR_ERR(clk_baud);
|
||||||
|
|
||||||
|
port->uartclk = clk_get_rate(clk_baud);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int meson_uart_probe(struct platform_device *pdev)
|
static int meson_uart_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct resource *res_mem, *res_irq;
|
struct resource *res_mem, *res_irq;
|
||||||
struct uart_port *port;
|
struct uart_port *port;
|
||||||
struct clk *clk;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (pdev->dev.of_node)
|
if (pdev->dev.of_node)
|
||||||
@ -625,15 +676,20 @@ static int meson_uart_probe(struct platform_device *pdev)
|
|||||||
if (!port)
|
if (!port)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
clk = clk_get(&pdev->dev, NULL);
|
/* Use legacy way until all platforms switch to new bindings */
|
||||||
if (IS_ERR(clk))
|
if (of_device_is_compatible(pdev->dev.of_node, "amlogic,meson-uart"))
|
||||||
return PTR_ERR(clk);
|
ret = meson_uart_probe_clocks_legacy(pdev, port);
|
||||||
|
else
|
||||||
|
ret = meson_uart_probe_clocks(pdev, port);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
port->uartclk = clk_get_rate(clk);
|
|
||||||
port->iotype = UPIO_MEM;
|
port->iotype = UPIO_MEM;
|
||||||
port->mapbase = res_mem->start;
|
port->mapbase = res_mem->start;
|
||||||
|
port->mapsize = resource_size(res_mem);
|
||||||
port->irq = res_irq->start;
|
port->irq = res_irq->start;
|
||||||
port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_LOW_LATENCY;
|
port->flags = UPF_BOOT_AUTOCONF | UPF_LOW_LATENCY;
|
||||||
port->dev = &pdev->dev;
|
port->dev = &pdev->dev;
|
||||||
port->line = pdev->id;
|
port->line = pdev->id;
|
||||||
port->type = PORT_MESON;
|
port->type = PORT_MESON;
|
||||||
@ -668,9 +724,14 @@ static int meson_uart_remove(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const struct of_device_id meson_uart_dt_match[] = {
|
static const struct of_device_id meson_uart_dt_match[] = {
|
||||||
|
/* Legacy bindings, should be removed when no more used */
|
||||||
{ .compatible = "amlogic,meson-uart" },
|
{ .compatible = "amlogic,meson-uart" },
|
||||||
|
/* Stable bindings */
|
||||||
|
{ .compatible = "amlogic,meson6-uart" },
|
||||||
|
{ .compatible = "amlogic,meson8-uart" },
|
||||||
|
{ .compatible = "amlogic,meson8b-uart" },
|
||||||
|
{ .compatible = "amlogic,meson-gx-uart" },
|
||||||
{ /* sentinel */ },
|
{ /* sentinel */ },
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, meson_uart_dt_match);
|
MODULE_DEVICE_TABLE(of, meson_uart_dt_match);
|
||||||
|
@ -754,9 +754,10 @@ static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
|
|||||||
if (!dma_set_mask(pi->port.dev, 0xffffffff)) {
|
if (!dma_set_mask(pi->port.dev, 0xffffffff)) {
|
||||||
printk(KERN_ERR "MPSC: Inadequate DMA support\n");
|
printk(KERN_ERR "MPSC: Inadequate DMA support\n");
|
||||||
rc = -ENXIO;
|
rc = -ENXIO;
|
||||||
} else if ((pi->dma_region = dma_alloc_noncoherent(pi->port.dev,
|
} else if ((pi->dma_region = dma_alloc_attrs(pi->port.dev,
|
||||||
MPSC_DMA_ALLOC_SIZE,
|
MPSC_DMA_ALLOC_SIZE,
|
||||||
&pi->dma_region_p, GFP_KERNEL))
|
&pi->dma_region_p, GFP_KERNEL,
|
||||||
|
DMA_ATTR_NON_CONSISTENT))
|
||||||
== NULL) {
|
== NULL) {
|
||||||
printk(KERN_ERR "MPSC: Can't alloc Desc region\n");
|
printk(KERN_ERR "MPSC: Can't alloc Desc region\n");
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
@ -771,8 +772,9 @@ static void mpsc_free_ring_mem(struct mpsc_port_info *pi)
|
|||||||
pr_debug("mpsc_free_ring_mem[%d]: Freeing ring mem\n", pi->port.line);
|
pr_debug("mpsc_free_ring_mem[%d]: Freeing ring mem\n", pi->port.line);
|
||||||
|
|
||||||
if (pi->dma_region) {
|
if (pi->dma_region) {
|
||||||
dma_free_noncoherent(pi->port.dev, MPSC_DMA_ALLOC_SIZE,
|
dma_free_attrs(pi->port.dev, MPSC_DMA_ALLOC_SIZE,
|
||||||
pi->dma_region, pi->dma_region_p);
|
pi->dma_region, pi->dma_region_p,
|
||||||
|
DMA_ATTR_NON_CONSISTENT);
|
||||||
pi->dma_region = NULL;
|
pi->dma_region = NULL;
|
||||||
pi->dma_region_p = (dma_addr_t)NULL;
|
pi->dma_region_p = (dma_addr_t)NULL;
|
||||||
}
|
}
|
||||||
|
135
drivers/tty/serial/owl-uart.c
Normal file
135
drivers/tty/serial/owl-uart.c
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* Actions Semi Owl family serial console
|
||||||
|
*
|
||||||
|
* Copyright 2013 Actions Semi Inc.
|
||||||
|
* Author: Actions Semi, Inc.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016-2017 Andreas Färber
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/console.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/serial.h>
|
||||||
|
#include <linux/serial_core.h>
|
||||||
|
|
||||||
|
#define OWL_UART_CTL 0x000
|
||||||
|
#define OWL_UART_TXDAT 0x008
|
||||||
|
#define OWL_UART_STAT 0x00c
|
||||||
|
|
||||||
|
#define OWL_UART_CTL_TRFS_TX BIT(14)
|
||||||
|
#define OWL_UART_CTL_EN BIT(15)
|
||||||
|
#define OWL_UART_CTL_RXIE BIT(18)
|
||||||
|
#define OWL_UART_CTL_TXIE BIT(19)
|
||||||
|
|
||||||
|
#define OWL_UART_STAT_RIP BIT(0)
|
||||||
|
#define OWL_UART_STAT_TIP BIT(1)
|
||||||
|
#define OWL_UART_STAT_TFFU BIT(6)
|
||||||
|
#define OWL_UART_STAT_TRFL_MASK (0x1f << 11)
|
||||||
|
#define OWL_UART_STAT_UTBB BIT(17)
|
||||||
|
|
||||||
|
static inline void owl_uart_write(struct uart_port *port, u32 val, unsigned int off)
|
||||||
|
{
|
||||||
|
writel(val, port->membase + off);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 owl_uart_read(struct uart_port *port, unsigned int off)
|
||||||
|
{
|
||||||
|
return readl(port->membase + off);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_OWL_CONSOLE
|
||||||
|
|
||||||
|
static void owl_console_putchar(struct uart_port *port, int ch)
|
||||||
|
{
|
||||||
|
if (!port->membase)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU)
|
||||||
|
cpu_relax();
|
||||||
|
|
||||||
|
owl_uart_write(port, ch, OWL_UART_TXDAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void owl_uart_port_write(struct uart_port *port, const char *s,
|
||||||
|
u_int count)
|
||||||
|
{
|
||||||
|
u32 old_ctl, val;
|
||||||
|
unsigned long flags;
|
||||||
|
int locked;
|
||||||
|
|
||||||
|
local_irq_save(flags);
|
||||||
|
|
||||||
|
if (port->sysrq)
|
||||||
|
locked = 0;
|
||||||
|
else if (oops_in_progress)
|
||||||
|
locked = spin_trylock(&port->lock);
|
||||||
|
else {
|
||||||
|
spin_lock(&port->lock);
|
||||||
|
locked = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
old_ctl = owl_uart_read(port, OWL_UART_CTL);
|
||||||
|
val = old_ctl | OWL_UART_CTL_TRFS_TX;
|
||||||
|
/* disable IRQ */
|
||||||
|
val &= ~(OWL_UART_CTL_RXIE | OWL_UART_CTL_TXIE);
|
||||||
|
owl_uart_write(port, val, OWL_UART_CTL);
|
||||||
|
|
||||||
|
uart_console_write(port, s, count, owl_console_putchar);
|
||||||
|
|
||||||
|
/* wait until all contents have been sent out */
|
||||||
|
while (owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TRFL_MASK)
|
||||||
|
cpu_relax();
|
||||||
|
|
||||||
|
/* clear IRQ pending */
|
||||||
|
val = owl_uart_read(port, OWL_UART_STAT);
|
||||||
|
val |= OWL_UART_STAT_TIP | OWL_UART_STAT_RIP;
|
||||||
|
owl_uart_write(port, val, OWL_UART_STAT);
|
||||||
|
|
||||||
|
owl_uart_write(port, old_ctl, OWL_UART_CTL);
|
||||||
|
|
||||||
|
if (locked)
|
||||||
|
spin_unlock(&port->lock);
|
||||||
|
|
||||||
|
local_irq_restore(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void owl_uart_early_console_write(struct console *co,
|
||||||
|
const char *s,
|
||||||
|
u_int count)
|
||||||
|
{
|
||||||
|
struct earlycon_device *dev = co->data;
|
||||||
|
|
||||||
|
owl_uart_port_write(&dev->port, s, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init
|
||||||
|
owl_uart_early_console_setup(struct earlycon_device *device, const char *opt)
|
||||||
|
{
|
||||||
|
if (!device->port.membase)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
device->con->write = owl_uart_early_console_write;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
OF_EARLYCON_DECLARE(owl, "actions,owl-uart",
|
||||||
|
owl_uart_early_console_setup);
|
||||||
|
|
||||||
|
#endif /* CONFIG_SERIAL_OWL_CONSOLE */
|
@ -878,8 +878,7 @@ static int dma_handle_rx(struct eg20t_port *priv)
|
|||||||
sg_dma_len(sg) = priv->trigger_level;
|
sg_dma_len(sg) = priv->trigger_level;
|
||||||
|
|
||||||
sg_set_page(&priv->sg_rx, virt_to_page(priv->rx_buf_virt),
|
sg_set_page(&priv->sg_rx, virt_to_page(priv->rx_buf_virt),
|
||||||
sg_dma_len(sg), (unsigned long)priv->rx_buf_virt &
|
sg_dma_len(sg), offset_in_page(priv->rx_buf_virt));
|
||||||
~PAGE_MASK);
|
|
||||||
|
|
||||||
sg_dma_address(sg) = priv->rx_buf_dma;
|
sg_dma_address(sg) = priv->rx_buf_dma;
|
||||||
|
|
||||||
|
@ -884,14 +884,19 @@ static int sccnxp_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
clk = devm_clk_get(&pdev->dev, NULL);
|
clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
if (IS_ERR(clk)) {
|
if (IS_ERR(clk)) {
|
||||||
if (PTR_ERR(clk) == -EPROBE_DEFER) {
|
ret = PTR_ERR(clk);
|
||||||
ret = -EPROBE_DEFER;
|
if (ret == -EPROBE_DEFER)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
uartclk = 0;
|
||||||
|
} else {
|
||||||
|
clk_prepare_enable(clk);
|
||||||
|
uartclk = clk_get_rate(clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!uartclk) {
|
||||||
dev_notice(&pdev->dev, "Using default clock frequency\n");
|
dev_notice(&pdev->dev, "Using default clock frequency\n");
|
||||||
uartclk = s->chip->freq_std;
|
uartclk = s->chip->freq_std;
|
||||||
} else
|
}
|
||||||
uartclk = clk_get_rate(clk);
|
|
||||||
|
|
||||||
/* Check input frequency */
|
/* Check input frequency */
|
||||||
if ((uartclk < s->chip->freq_min) || (uartclk > s->chip->freq_max)) {
|
if ((uartclk < s->chip->freq_min) || (uartclk > s->chip->freq_max)) {
|
||||||
|
@ -954,11 +954,10 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
|
|||||||
old_custom_divisor != uport->custom_divisor) {
|
old_custom_divisor != uport->custom_divisor) {
|
||||||
/*
|
/*
|
||||||
* If they're setting up a custom divisor or speed,
|
* If they're setting up a custom divisor or speed,
|
||||||
* instead of clearing it, then bitch about it. No
|
* instead of clearing it, then bitch about it.
|
||||||
* need to rate-limit; it's CAP_SYS_ADMIN only.
|
|
||||||
*/
|
*/
|
||||||
if (uport->flags & UPF_SPD_MASK) {
|
if (uport->flags & UPF_SPD_MASK) {
|
||||||
dev_notice(uport->dev,
|
dev_notice_ratelimited(uport->dev,
|
||||||
"%s sets custom speed on %s. This is deprecated.\n",
|
"%s sets custom speed on %s. This is deprecated.\n",
|
||||||
current->comm,
|
current->comm,
|
||||||
tty_name(port->tty));
|
tty_name(port->tty));
|
||||||
|
@ -1450,8 +1450,7 @@ static struct dma_chan *sci_request_dma_chan(struct uart_port *port,
|
|||||||
chan = dma_request_slave_channel(port->dev,
|
chan = dma_request_slave_channel(port->dev,
|
||||||
dir == DMA_MEM_TO_DEV ? "tx" : "rx");
|
dir == DMA_MEM_TO_DEV ? "tx" : "rx");
|
||||||
if (!chan) {
|
if (!chan) {
|
||||||
dev_warn(port->dev,
|
dev_warn(port->dev, "dma_request_slave_channel failed\n");
|
||||||
"dma_request_slave_channel_compat failed\n");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1558,7 +1557,16 @@ static void sci_free_dma(struct uart_port *port)
|
|||||||
if (s->chan_rx)
|
if (s->chan_rx)
|
||||||
sci_rx_dma_release(s, false);
|
sci_rx_dma_release(s, false);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
|
static void sci_flush_buffer(struct uart_port *port)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* In uart_flush_buffer(), the xmit circular buffer has just been
|
||||||
|
* cleared, so we have to reset tx_dma_len accordingly.
|
||||||
|
*/
|
||||||
|
to_sci_port(port)->tx_dma_len = 0;
|
||||||
|
}
|
||||||
|
#else /* !CONFIG_SERIAL_SH_SCI_DMA */
|
||||||
static inline void sci_request_dma(struct uart_port *port)
|
static inline void sci_request_dma(struct uart_port *port)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -1566,7 +1574,9 @@ static inline void sci_request_dma(struct uart_port *port)
|
|||||||
static inline void sci_free_dma(struct uart_port *port)
|
static inline void sci_free_dma(struct uart_port *port)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
#define sci_flush_buffer NULL
|
||||||
|
#endif /* !CONFIG_SERIAL_SH_SCI_DMA */
|
||||||
|
|
||||||
static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
|
static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
|
||||||
{
|
{
|
||||||
@ -2581,6 +2591,7 @@ static const struct uart_ops sci_uart_ops = {
|
|||||||
.break_ctl = sci_break_ctl,
|
.break_ctl = sci_break_ctl,
|
||||||
.startup = sci_startup,
|
.startup = sci_startup,
|
||||||
.shutdown = sci_shutdown,
|
.shutdown = sci_shutdown,
|
||||||
|
.flush_buffer = sci_flush_buffer,
|
||||||
.set_termios = sci_set_termios,
|
.set_termios = sci_set_termios,
|
||||||
.pm = sci_pm,
|
.pm = sci_pm,
|
||||||
.type = sci_type,
|
.type = sci_type,
|
||||||
@ -2950,6 +2961,7 @@ static inline int sci_probe_earlyprintk(struct platform_device *pdev)
|
|||||||
|
|
||||||
static const char banner[] __initconst = "SuperH (H)SCI(F) driver initialized";
|
static const char banner[] __initconst = "SuperH (H)SCI(F) driver initialized";
|
||||||
|
|
||||||
|
static DEFINE_MUTEX(sci_uart_registration_lock);
|
||||||
static struct uart_driver sci_uart_driver = {
|
static struct uart_driver sci_uart_driver = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.driver_name = "sci",
|
.driver_name = "sci",
|
||||||
@ -3078,6 +3090,16 @@ static int sci_probe_single(struct platform_device *dev,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_lock(&sci_uart_registration_lock);
|
||||||
|
if (!sci_uart_driver.state) {
|
||||||
|
ret = uart_register_driver(&sci_uart_driver);
|
||||||
|
if (ret) {
|
||||||
|
mutex_unlock(&sci_uart_registration_lock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mutex_unlock(&sci_uart_registration_lock);
|
||||||
|
|
||||||
ret = sci_init_single(dev, sciport, index, p, false);
|
ret = sci_init_single(dev, sciport, index, p, false);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
@ -3201,24 +3223,17 @@ static struct platform_driver sci_driver = {
|
|||||||
|
|
||||||
static int __init sci_init(void)
|
static int __init sci_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
|
|
||||||
pr_info("%s\n", banner);
|
pr_info("%s\n", banner);
|
||||||
|
|
||||||
ret = uart_register_driver(&sci_uart_driver);
|
return platform_driver_register(&sci_driver);
|
||||||
if (likely(ret == 0)) {
|
|
||||||
ret = platform_driver_register(&sci_driver);
|
|
||||||
if (unlikely(ret))
|
|
||||||
uart_unregister_driver(&sci_uart_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit sci_exit(void)
|
static void __exit sci_exit(void)
|
||||||
{
|
{
|
||||||
platform_driver_unregister(&sci_driver);
|
platform_driver_unregister(&sci_driver);
|
||||||
uart_unregister_driver(&sci_uart_driver);
|
|
||||||
|
if (sci_uart_driver.state)
|
||||||
|
uart_unregister_driver(&sci_uart_driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
|
#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
|
||||||
|
@ -1253,7 +1253,7 @@ next_hrt:
|
|||||||
return HRTIMER_RESTART;
|
return HRTIMER_RESTART;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct of_device_id sirfsoc_uart_ids[] = {
|
static const struct of_device_id sirfsoc_uart_ids[] = {
|
||||||
{ .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,},
|
{ .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,},
|
||||||
{ .compatible = "sirf,atlas7-uart", .data = &sirfsoc_uart},
|
{ .compatible = "sirf,atlas7-uart", .data = &sirfsoc_uart},
|
||||||
{ .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp},
|
{ .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp},
|
||||||
|
@ -186,6 +186,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
|
|||||||
* @pclk: APB clock
|
* @pclk: APB clock
|
||||||
* @baud: Current baud rate
|
* @baud: Current baud rate
|
||||||
* @clk_rate_change_nb: Notifier block for clock changes
|
* @clk_rate_change_nb: Notifier block for clock changes
|
||||||
|
* @quirks: Flags for RXBS support.
|
||||||
*/
|
*/
|
||||||
struct cdns_uart {
|
struct cdns_uart {
|
||||||
struct uart_port *port;
|
struct uart_port *port;
|
||||||
@ -1587,20 +1588,21 @@ static int cdns_uart_probe(struct platform_device *pdev)
|
|||||||
if (rc) {
|
if (rc) {
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
"uart_add_one_port() failed; err=%i\n", rc);
|
"uart_add_one_port() failed; err=%i\n", rc);
|
||||||
goto err_out_notif_unreg;
|
goto err_out_pm_disable;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_out_pm_disable:
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
pm_runtime_set_suspended(&pdev->dev);
|
||||||
|
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||||
err_out_notif_unreg:
|
err_out_notif_unreg:
|
||||||
#ifdef CONFIG_COMMON_CLK
|
#ifdef CONFIG_COMMON_CLK
|
||||||
clk_notifier_unregister(cdns_uart_data->uartclk,
|
clk_notifier_unregister(cdns_uart_data->uartclk,
|
||||||
&cdns_uart_data->clk_rate_change_nb);
|
&cdns_uart_data->clk_rate_change_nb);
|
||||||
#endif
|
#endif
|
||||||
err_out_clk_disable:
|
err_out_clk_disable:
|
||||||
pm_runtime_disable(&pdev->dev);
|
|
||||||
pm_runtime_set_suspended(&pdev->dev);
|
|
||||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
|
||||||
clk_disable_unprepare(cdns_uart_data->uartclk);
|
clk_disable_unprepare(cdns_uart_data->uartclk);
|
||||||
err_out_clk_dis_pclk:
|
err_out_clk_dis_pclk:
|
||||||
clk_disable_unprepare(cdns_uart_data->pclk);
|
clk_disable_unprepare(cdns_uart_data->pclk);
|
||||||
|
@ -491,6 +491,29 @@ static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
|
|||||||
tty_ldisc_debug(tty, "%p: closed\n", ld);
|
tty_ldisc_debug(tty, "%p: closed\n", ld);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tty_ldisc_failto - helper for ldisc failback
|
||||||
|
* @tty: tty to open the ldisc on
|
||||||
|
* @ld: ldisc we are trying to fail back to
|
||||||
|
*
|
||||||
|
* Helper to try and recover a tty when switching back to the old
|
||||||
|
* ldisc fails and we need something attached.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int tty_ldisc_failto(struct tty_struct *tty, int ld)
|
||||||
|
{
|
||||||
|
struct tty_ldisc *disc = tty_ldisc_get(tty, ld);
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (IS_ERR(disc))
|
||||||
|
return PTR_ERR(disc);
|
||||||
|
tty->ldisc = disc;
|
||||||
|
tty_set_termios_ldisc(tty, ld);
|
||||||
|
if ((r = tty_ldisc_open(tty, disc)) < 0)
|
||||||
|
tty_ldisc_put(disc);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tty_ldisc_restore - helper for tty ldisc change
|
* tty_ldisc_restore - helper for tty ldisc change
|
||||||
* @tty: tty to recover
|
* @tty: tty to recover
|
||||||
@ -502,9 +525,6 @@ static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
|
|||||||
|
|
||||||
static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
|
static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
|
||||||
{
|
{
|
||||||
struct tty_ldisc *new_ldisc;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
/* There is an outstanding reference here so this is safe */
|
/* There is an outstanding reference here so this is safe */
|
||||||
old = tty_ldisc_get(tty, old->ops->num);
|
old = tty_ldisc_get(tty, old->ops->num);
|
||||||
WARN_ON(IS_ERR(old));
|
WARN_ON(IS_ERR(old));
|
||||||
@ -512,17 +532,13 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
|
|||||||
tty_set_termios_ldisc(tty, old->ops->num);
|
tty_set_termios_ldisc(tty, old->ops->num);
|
||||||
if (tty_ldisc_open(tty, old) < 0) {
|
if (tty_ldisc_open(tty, old) < 0) {
|
||||||
tty_ldisc_put(old);
|
tty_ldisc_put(old);
|
||||||
/* This driver is always present */
|
/* The traditional behaviour is to fall back to N_TTY, we
|
||||||
new_ldisc = tty_ldisc_get(tty, N_TTY);
|
want to avoid falling back to N_NULL unless we have no
|
||||||
if (IS_ERR(new_ldisc))
|
choice to avoid the risk of breaking anything */
|
||||||
panic("n_tty: get");
|
if (tty_ldisc_failto(tty, N_TTY) < 0 &&
|
||||||
tty->ldisc = new_ldisc;
|
tty_ldisc_failto(tty, N_NULL) < 0)
|
||||||
tty_set_termios_ldisc(tty, N_TTY);
|
panic("Couldn't open N_NULL ldisc for %s.",
|
||||||
r = tty_ldisc_open(tty, new_ldisc);
|
tty_name(tty));
|
||||||
if (r < 0)
|
|
||||||
panic("Couldn't open N_TTY ldisc for "
|
|
||||||
"%s --- error %d.",
|
|
||||||
tty_name(tty), r);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,15 +322,13 @@ int con_set_trans_old(unsigned char __user * arg)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned short inbuf[E_TABSZ];
|
unsigned short inbuf[E_TABSZ];
|
||||||
|
unsigned char ubuf[E_TABSZ];
|
||||||
|
|
||||||
if (!access_ok(VERIFY_READ, arg, E_TABSZ))
|
if (copy_from_user(ubuf, arg, E_TABSZ))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
for (i = 0; i < E_TABSZ ; i++) {
|
for (i = 0; i < E_TABSZ ; i++)
|
||||||
unsigned char uc;
|
inbuf[i] = UNI_DIRECT_BASE | ubuf[i];
|
||||||
__get_user(uc, arg+i);
|
|
||||||
inbuf[i] = UNI_DIRECT_BASE | uc;
|
|
||||||
}
|
|
||||||
|
|
||||||
console_lock();
|
console_lock();
|
||||||
memcpy(translations[USER_MAP], inbuf, sizeof(inbuf));
|
memcpy(translations[USER_MAP], inbuf, sizeof(inbuf));
|
||||||
@ -345,9 +343,6 @@ int con_get_trans_old(unsigned char __user * arg)
|
|||||||
unsigned short *p = translations[USER_MAP];
|
unsigned short *p = translations[USER_MAP];
|
||||||
unsigned char outbuf[E_TABSZ];
|
unsigned char outbuf[E_TABSZ];
|
||||||
|
|
||||||
if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
console_lock();
|
console_lock();
|
||||||
for (i = 0; i < E_TABSZ ; i++)
|
for (i = 0; i < E_TABSZ ; i++)
|
||||||
{
|
{
|
||||||
@ -356,22 +351,16 @@ int con_get_trans_old(unsigned char __user * arg)
|
|||||||
}
|
}
|
||||||
console_unlock();
|
console_unlock();
|
||||||
|
|
||||||
for (i = 0; i < E_TABSZ ; i++)
|
return copy_to_user(arg, outbuf, sizeof(outbuf)) ? -EFAULT : 0;
|
||||||
__put_user(outbuf[i], arg+i);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int con_set_trans_new(ushort __user * arg)
|
int con_set_trans_new(ushort __user * arg)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
unsigned short inbuf[E_TABSZ];
|
unsigned short inbuf[E_TABSZ];
|
||||||
|
|
||||||
if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
|
if (copy_from_user(inbuf, arg, sizeof(inbuf)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
for (i = 0; i < E_TABSZ ; i++)
|
|
||||||
__get_user(inbuf[i], arg+i);
|
|
||||||
|
|
||||||
console_lock();
|
console_lock();
|
||||||
memcpy(translations[USER_MAP], inbuf, sizeof(inbuf));
|
memcpy(translations[USER_MAP], inbuf, sizeof(inbuf));
|
||||||
update_user_maps();
|
update_user_maps();
|
||||||
@ -381,19 +370,13 @@ int con_set_trans_new(ushort __user * arg)
|
|||||||
|
|
||||||
int con_get_trans_new(ushort __user * arg)
|
int con_get_trans_new(ushort __user * arg)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
unsigned short outbuf[E_TABSZ];
|
unsigned short outbuf[E_TABSZ];
|
||||||
|
|
||||||
if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
console_lock();
|
console_lock();
|
||||||
memcpy(outbuf, translations[USER_MAP], sizeof(outbuf));
|
memcpy(outbuf, translations[USER_MAP], sizeof(outbuf));
|
||||||
console_unlock();
|
console_unlock();
|
||||||
|
|
||||||
for (i = 0; i < E_TABSZ ; i++)
|
return copy_to_user(arg, outbuf, sizeof(outbuf)) ? -EFAULT : 0;
|
||||||
__put_user(outbuf[i], arg+i);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -557,14 +540,9 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
|||||||
if (!ct)
|
if (!ct)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
unilist = kmalloc_array(ct, sizeof(struct unipair), GFP_KERNEL);
|
unilist = memdup_user(list, ct * sizeof(struct unipair));
|
||||||
if (!unilist)
|
if (IS_ERR(unilist))
|
||||||
return -ENOMEM;
|
return PTR_ERR(unilist);
|
||||||
|
|
||||||
for (i = ct, plist = unilist; i; i--, plist++, list++) {
|
|
||||||
__get_user(plist->unicode, &list->unicode);
|
|
||||||
__get_user(plist->fontpos, &list->fontpos);
|
|
||||||
}
|
|
||||||
|
|
||||||
console_lock();
|
console_lock();
|
||||||
|
|
||||||
@ -757,11 +735,11 @@ EXPORT_SYMBOL(con_copy_unimap);
|
|||||||
*/
|
*/
|
||||||
int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
|
int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
|
||||||
{
|
{
|
||||||
int i, j, k;
|
int i, j, k, ret = 0;
|
||||||
ushort ect;
|
ushort ect;
|
||||||
u16 **p1, *p2;
|
u16 **p1, *p2;
|
||||||
struct uni_pagedir *p;
|
struct uni_pagedir *p;
|
||||||
struct unipair *unilist, *plist;
|
struct unipair *unilist;
|
||||||
|
|
||||||
unilist = kmalloc_array(ct, sizeof(struct unipair), GFP_KERNEL);
|
unilist = kmalloc_array(ct, sizeof(struct unipair), GFP_KERNEL);
|
||||||
if (!unilist)
|
if (!unilist)
|
||||||
@ -792,13 +770,11 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
console_unlock();
|
console_unlock();
|
||||||
for (i = min(ect, ct), plist = unilist; i; i--, list++, plist++) {
|
if (copy_to_user(list, unilist, min(ect, ct) * sizeof(struct unipair)))
|
||||||
__put_user(plist->unicode, &list->unicode);
|
ret = -EFAULT;
|
||||||
__put_user(plist->fontpos, &list->fontpos);
|
put_user(ect, uct);
|
||||||
}
|
|
||||||
__put_user(ect, uct);
|
|
||||||
kfree(unilist);
|
kfree(unilist);
|
||||||
return ((ect <= ct) ? 0 : -ENOMEM);
|
return ret ? ret : (ect <= ct) ? 0 : -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1203,8 +1203,7 @@ DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
|
|||||||
#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
|
#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
|
||||||
defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
|
defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
|
||||||
defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
|
defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
|
||||||
(defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) ||\
|
(defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC))
|
||||||
defined(CONFIG_AVR32)
|
|
||||||
|
|
||||||
#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
|
#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
|
||||||
((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
|
((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
|
||||||
|
@ -425,7 +425,7 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
|
|||||||
else if (_underline)
|
else if (_underline)
|
||||||
a = (a & 0xf0) | vc->vc_ulcolor;
|
a = (a & 0xf0) | vc->vc_ulcolor;
|
||||||
else if (_intensity == 0)
|
else if (_intensity == 0)
|
||||||
a = (a & 0xf0) | vc->vc_ulcolor;
|
a = (a & 0xf0) | vc->vc_halfcolor;
|
||||||
if (_reverse)
|
if (_reverse)
|
||||||
a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
|
a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
|
||||||
if (_blink)
|
if (_blink)
|
||||||
@ -2709,13 +2709,13 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
|
|||||||
* related to the kernel should not use this.
|
* related to the kernel should not use this.
|
||||||
*/
|
*/
|
||||||
data = vt_get_shift_state();
|
data = vt_get_shift_state();
|
||||||
ret = __put_user(data, p);
|
ret = put_user(data, p);
|
||||||
break;
|
break;
|
||||||
case TIOCL_GETMOUSEREPORTING:
|
case TIOCL_GETMOUSEREPORTING:
|
||||||
console_lock(); /* May be overkill */
|
console_lock(); /* May be overkill */
|
||||||
data = mouse_reporting();
|
data = mouse_reporting();
|
||||||
console_unlock();
|
console_unlock();
|
||||||
ret = __put_user(data, p);
|
ret = put_user(data, p);
|
||||||
break;
|
break;
|
||||||
case TIOCL_SETVESABLANK:
|
case TIOCL_SETVESABLANK:
|
||||||
console_lock();
|
console_lock();
|
||||||
@ -2724,7 +2724,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
|
|||||||
break;
|
break;
|
||||||
case TIOCL_GETKMSGREDIRECT:
|
case TIOCL_GETKMSGREDIRECT:
|
||||||
data = vt_get_kmsg_redirect();
|
data = vt_get_kmsg_redirect();
|
||||||
ret = __put_user(data, p);
|
ret = put_user(data, p);
|
||||||
break;
|
break;
|
||||||
case TIOCL_SETKMSGREDIRECT:
|
case TIOCL_SETKMSGREDIRECT:
|
||||||
if (!capable(CAP_SYS_ADMIN)) {
|
if (!capable(CAP_SYS_ADMIN)) {
|
||||||
|
@ -266,10 +266,6 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_
|
|||||||
|
|
||||||
if (copy_from_user(&tmp, user_ud, sizeof tmp))
|
if (copy_from_user(&tmp, user_ud, sizeof tmp))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (tmp.entries)
|
|
||||||
if (!access_ok(VERIFY_WRITE, tmp.entries,
|
|
||||||
tmp.entry_ct*sizeof(struct unipair)))
|
|
||||||
return -EFAULT;
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case PIO_UNIMAP:
|
case PIO_UNIMAP:
|
||||||
if (!perm)
|
if (!perm)
|
||||||
@ -1170,10 +1166,6 @@ compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud,
|
|||||||
if (copy_from_user(&tmp, user_ud, sizeof tmp))
|
if (copy_from_user(&tmp, user_ud, sizeof tmp))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
tmp_entries = compat_ptr(tmp.entries);
|
tmp_entries = compat_ptr(tmp.entries);
|
||||||
if (tmp_entries)
|
|
||||||
if (!access_ok(VERIFY_WRITE, tmp_entries,
|
|
||||||
tmp.entry_ct*sizeof(struct unipair)))
|
|
||||||
return -EFAULT;
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case PIO_UNIMAP:
|
case PIO_UNIMAP:
|
||||||
if (!perm)
|
if (!perm)
|
||||||
|
@ -1244,42 +1244,13 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty,
|
|||||||
int div_okay = 1;
|
int div_okay = 1;
|
||||||
int baud;
|
int baud;
|
||||||
|
|
||||||
/*
|
|
||||||
* The logic involved in setting the baudrate can be cleanly split into
|
|
||||||
* 3 steps.
|
|
||||||
* 1. Standard baud rates are set in tty->termios->c_cflag
|
|
||||||
* 2. If these are not enough, you can set any speed using alt_speed as
|
|
||||||
* follows:
|
|
||||||
* - set tty->termios->c_cflag speed to B38400
|
|
||||||
* - set your real speed in tty->alt_speed; it gets ignored when
|
|
||||||
* alt_speed==0, (or)
|
|
||||||
* - call TIOCSSERIAL ioctl with (struct serial_struct) set as
|
|
||||||
* follows:
|
|
||||||
* flags & ASYNC_SPD_MASK == ASYNC_SPD_[HI, VHI, SHI, WARP],
|
|
||||||
* this just sets alt_speed to (HI: 57600, VHI: 115200,
|
|
||||||
* SHI: 230400, WARP: 460800)
|
|
||||||
* ** Steps 1, 2 are done courtesy of tty_get_baud_rate
|
|
||||||
* 3. You can also set baud rate by setting custom divisor as follows
|
|
||||||
* - set tty->termios->c_cflag speed to B38400
|
|
||||||
* - call TIOCSSERIAL ioctl with (struct serial_struct) set as
|
|
||||||
* follows:
|
|
||||||
* o flags & ASYNC_SPD_MASK == ASYNC_SPD_CUST
|
|
||||||
* o custom_divisor set to baud_base / your_new_baudrate
|
|
||||||
* ** Step 3 is done courtesy of code borrowed from serial.c
|
|
||||||
* I should really spend some time and separate + move this common
|
|
||||||
* code to serial.c, it is replicated in nearly every serial driver
|
|
||||||
* you see.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* 1. Get the baud rate from the tty settings, this observes
|
|
||||||
alt_speed hack */
|
|
||||||
|
|
||||||
baud = tty_get_baud_rate(tty);
|
baud = tty_get_baud_rate(tty);
|
||||||
dev_dbg(dev, "%s - tty_get_baud_rate reports speed %d\n", __func__, baud);
|
dev_dbg(dev, "%s - tty_get_baud_rate reports speed %d\n", __func__, baud);
|
||||||
|
|
||||||
/* 2. Observe async-compatible custom_divisor hack, update baudrate
|
/*
|
||||||
if needed */
|
* Observe deprecated async-compatible custom_divisor hack, update
|
||||||
|
* baudrate if needed.
|
||||||
|
*/
|
||||||
if (baud == 38400 &&
|
if (baud == 38400 &&
|
||||||
((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
|
((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
|
||||||
(priv->custom_divisor)) {
|
(priv->custom_divisor)) {
|
||||||
@ -1288,8 +1259,6 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty,
|
|||||||
__func__, priv->custom_divisor, baud);
|
__func__, priv->custom_divisor, baud);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 3. Convert baudrate to device-specific divisor */
|
|
||||||
|
|
||||||
if (!baud)
|
if (!baud)
|
||||||
baud = 9600;
|
baud = 9600;
|
||||||
switch (priv->chip_type) {
|
switch (priv->chip_type) {
|
||||||
@ -1505,8 +1474,7 @@ static int set_serial_info(struct tty_struct *tty,
|
|||||||
/* Do error checking and permission checking */
|
/* Do error checking and permission checking */
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN)) {
|
if (!capable(CAP_SYS_ADMIN)) {
|
||||||
if (((new_serial.flags & ~ASYNC_USR_MASK) !=
|
if ((new_serial.flags ^ priv->flags) & ~ASYNC_USR_MASK) {
|
||||||
(priv->flags & ~ASYNC_USR_MASK))) {
|
|
||||||
mutex_unlock(&priv->cfg_lock);
|
mutex_unlock(&priv->cfg_lock);
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
@ -1530,23 +1498,14 @@ static int set_serial_info(struct tty_struct *tty,
|
|||||||
check_and_exit:
|
check_and_exit:
|
||||||
write_latency_timer(port);
|
write_latency_timer(port);
|
||||||
|
|
||||||
if ((old_priv.flags & ASYNC_SPD_MASK) !=
|
if ((priv->flags ^ old_priv.flags) & ASYNC_SPD_MASK ||
|
||||||
(priv->flags & ASYNC_SPD_MASK)) {
|
((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
|
||||||
if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
|
priv->custom_divisor != old_priv.custom_divisor)) {
|
||||||
tty->alt_speed = 57600;
|
|
||||||
else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
|
/* warn about deprecation unless clearing */
|
||||||
tty->alt_speed = 115200;
|
if (priv->flags & ASYNC_SPD_MASK)
|
||||||
else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
|
dev_warn_ratelimited(&port->dev, "use of SPD flags is deprecated\n");
|
||||||
tty->alt_speed = 230400;
|
|
||||||
else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
|
|
||||||
tty->alt_speed = 460800;
|
|
||||||
else
|
|
||||||
tty->alt_speed = 0;
|
|
||||||
}
|
|
||||||
if (((old_priv.flags & ASYNC_SPD_MASK) !=
|
|
||||||
(priv->flags & ASYNC_SPD_MASK)) ||
|
|
||||||
(((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
|
|
||||||
(old_priv.custom_divisor != priv->custom_divisor))) {
|
|
||||||
change_speed(tty, port);
|
change_speed(tty, port);
|
||||||
mutex_unlock(&priv->cfg_lock);
|
mutex_unlock(&priv->cfg_lock);
|
||||||
}
|
}
|
||||||
|
@ -866,8 +866,6 @@ COMPATIBLE_IOCTL(TIOCGDEV)
|
|||||||
COMPATIBLE_IOCTL(TIOCCBRK)
|
COMPATIBLE_IOCTL(TIOCCBRK)
|
||||||
COMPATIBLE_IOCTL(TIOCGSID)
|
COMPATIBLE_IOCTL(TIOCGSID)
|
||||||
COMPATIBLE_IOCTL(TIOCGICOUNT)
|
COMPATIBLE_IOCTL(TIOCGICOUNT)
|
||||||
COMPATIBLE_IOCTL(TIOCGPKT)
|
|
||||||
COMPATIBLE_IOCTL(TIOCGPTLCK)
|
|
||||||
COMPATIBLE_IOCTL(TIOCGEXCL)
|
COMPATIBLE_IOCTL(TIOCGEXCL)
|
||||||
/* Little t */
|
/* Little t */
|
||||||
COMPATIBLE_IOCTL(TIOCGETD)
|
COMPATIBLE_IOCTL(TIOCGETD)
|
||||||
@ -883,16 +881,12 @@ COMPATIBLE_IOCTL(TIOCMGET)
|
|||||||
COMPATIBLE_IOCTL(TIOCMBIC)
|
COMPATIBLE_IOCTL(TIOCMBIC)
|
||||||
COMPATIBLE_IOCTL(TIOCMBIS)
|
COMPATIBLE_IOCTL(TIOCMBIS)
|
||||||
COMPATIBLE_IOCTL(TIOCMSET)
|
COMPATIBLE_IOCTL(TIOCMSET)
|
||||||
COMPATIBLE_IOCTL(TIOCPKT)
|
|
||||||
COMPATIBLE_IOCTL(TIOCNOTTY)
|
COMPATIBLE_IOCTL(TIOCNOTTY)
|
||||||
COMPATIBLE_IOCTL(TIOCSTI)
|
COMPATIBLE_IOCTL(TIOCSTI)
|
||||||
COMPATIBLE_IOCTL(TIOCOUTQ)
|
COMPATIBLE_IOCTL(TIOCOUTQ)
|
||||||
COMPATIBLE_IOCTL(TIOCSPGRP)
|
COMPATIBLE_IOCTL(TIOCSPGRP)
|
||||||
COMPATIBLE_IOCTL(TIOCGPGRP)
|
COMPATIBLE_IOCTL(TIOCGPGRP)
|
||||||
COMPATIBLE_IOCTL(TIOCGPTN)
|
|
||||||
COMPATIBLE_IOCTL(TIOCSPTLCK)
|
|
||||||
COMPATIBLE_IOCTL(TIOCSERGETLSR)
|
COMPATIBLE_IOCTL(TIOCSERGETLSR)
|
||||||
COMPATIBLE_IOCTL(TIOCSIG)
|
|
||||||
#ifdef TIOCSRS485
|
#ifdef TIOCSRS485
|
||||||
COMPATIBLE_IOCTL(TIOCSRS485)
|
COMPATIBLE_IOCTL(TIOCSRS485)
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
#include <linux/mtd/nand.h>
|
#include <linux/mtd/nand.h>
|
||||||
#include <linux/mtd/partitions.h>
|
#include <linux/mtd/partitions.h>
|
||||||
#include <linux/serial.h>
|
|
||||||
|
|
||||||
/* Compact Flash */
|
/* Compact Flash */
|
||||||
struct at91_cf_data {
|
struct at91_cf_data {
|
||||||
@ -42,15 +41,6 @@ struct atmel_nand_data {
|
|||||||
bool need_reset_workaround;
|
bool need_reset_workaround;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Serial */
|
|
||||||
struct atmel_uart_data {
|
|
||||||
int num; /* port num */
|
|
||||||
short use_dma_tx; /* use transmit DMA? */
|
|
||||||
short use_dma_rx; /* use receive DMA? */
|
|
||||||
void __iomem *regs; /* virt. base address, if any */
|
|
||||||
struct serial_rs485 rs485; /* rs485 settings */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* FIXME: this needs a better location, but gets stuff building again */
|
/* FIXME: this needs a better location, but gets stuff building again */
|
||||||
extern int at91_suspend_entering_slow_clock(void);
|
extern int at91_suspend_entering_slow_clock(void);
|
||||||
|
|
||||||
|
@ -195,6 +195,7 @@ struct uart_port {
|
|||||||
#define UPF_NO_TXEN_TEST ((__force upf_t) (1 << 15))
|
#define UPF_NO_TXEN_TEST ((__force upf_t) (1 << 15))
|
||||||
#define UPF_MAGIC_MULTIPLIER ((__force upf_t) ASYNC_MAGIC_MULTIPLIER /* 16 */ )
|
#define UPF_MAGIC_MULTIPLIER ((__force upf_t) ASYNC_MAGIC_MULTIPLIER /* 16 */ )
|
||||||
|
|
||||||
|
#define UPF_NO_THRE_TEST ((__force upf_t) (1 << 19))
|
||||||
/* Port has hardware-assisted h/w flow control */
|
/* Port has hardware-assisted h/w flow control */
|
||||||
#define UPF_AUTO_CTS ((__force upf_t) (1 << 20))
|
#define UPF_AUTO_CTS ((__force upf_t) (1 << 20))
|
||||||
#define UPF_AUTO_RTS ((__force upf_t) (1 << 21))
|
#define UPF_AUTO_RTS ((__force upf_t) (1 << 21))
|
||||||
|
@ -316,7 +316,6 @@ struct tty_struct {
|
|||||||
|
|
||||||
struct tty_struct *link;
|
struct tty_struct *link;
|
||||||
struct fasync_struct *fasync;
|
struct fasync_struct *fasync;
|
||||||
int alt_speed; /* For magic substitution of 38400 bps */
|
|
||||||
wait_queue_head_t write_wait;
|
wait_queue_head_t write_wait;
|
||||||
wait_queue_head_t read_wait;
|
wait_queue_head_t read_wait;
|
||||||
struct work_struct hangup_work;
|
struct work_struct hangup_work;
|
||||||
|
@ -77,6 +77,7 @@
|
|||||||
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
|
||||||
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
|
||||||
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
|
||||||
|
#define TIOCGPTPEER _IOR('T', 0x41, int) /* Safely open the slave */
|
||||||
|
|
||||||
#define FIONCLEX 0x5450
|
#define FIONCLEX 0x5450
|
||||||
#define FIOCLEX 0x5451
|
#define FIOCLEX 0x5451
|
||||||
|
@ -122,6 +122,9 @@ struct serial_rs485 {
|
|||||||
#define SER_RS485_RTS_AFTER_SEND (1 << 2) /* Logical level for
|
#define SER_RS485_RTS_AFTER_SEND (1 << 2) /* Logical level for
|
||||||
RTS pin after sent*/
|
RTS pin after sent*/
|
||||||
#define SER_RS485_RX_DURING_TX (1 << 4)
|
#define SER_RS485_RX_DURING_TX (1 << 4)
|
||||||
|
#define SER_RS485_TERMINATE_BUS (1 << 5) /* Enable bus
|
||||||
|
termination
|
||||||
|
(if supported) */
|
||||||
__u32 delay_rts_before_send; /* Delay before send (milliseconds) */
|
__u32 delay_rts_before_send; /* Delay before send (milliseconds) */
|
||||||
__u32 delay_rts_after_send; /* Delay after send (milliseconds) */
|
__u32 delay_rts_after_send; /* Delay after send (milliseconds) */
|
||||||
__u32 padding[5]; /* Memory is cheap, new structs
|
__u32 padding[5]; /* Memory is cheap, new structs
|
||||||
|
@ -83,7 +83,7 @@
|
|||||||
/* Parisc type numbers. */
|
/* Parisc type numbers. */
|
||||||
#define PORT_MUX 48
|
#define PORT_MUX 48
|
||||||
|
|
||||||
/* Atmel AT91 / AT32 SoC */
|
/* Atmel AT91 SoC */
|
||||||
#define PORT_ATMEL 49
|
#define PORT_ATMEL 49
|
||||||
|
|
||||||
/* Macintosh Zilog type numbers */
|
/* Macintosh Zilog type numbers */
|
||||||
|
@ -36,5 +36,6 @@
|
|||||||
#define N_TRACEROUTER 24 /* Trace data routing for MIPI P1149.7 */
|
#define N_TRACEROUTER 24 /* Trace data routing for MIPI P1149.7 */
|
||||||
#define N_NCI 25 /* NFC NCI UART */
|
#define N_NCI 25 /* NFC NCI UART */
|
||||||
#define N_SPEAKUP 26 /* Speakup communication with synths */
|
#define N_SPEAKUP 26 /* Speakup communication with synths */
|
||||||
|
#define N_NULL 27 /* Null ldisc used for error handling */
|
||||||
|
|
||||||
#endif /* _UAPI_LINUX_TTY_H */
|
#endif /* _UAPI_LINUX_TTY_H */
|
||||||
|
@ -97,33 +97,7 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self,
|
|||||||
self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN;
|
self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN;
|
||||||
}
|
}
|
||||||
tty_port_set_check_carrier(&self->port, ~cflag & CLOCAL);
|
tty_port_set_check_carrier(&self->port, ~cflag & CLOCAL);
|
||||||
#if 0
|
|
||||||
/*
|
|
||||||
* Set up parity check flag
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (I_INPCK(self->tty))
|
|
||||||
driver->read_status_mask |= LSR_FE | LSR_PE;
|
|
||||||
if (I_BRKINT(driver->tty) || I_PARMRK(driver->tty))
|
|
||||||
driver->read_status_mask |= LSR_BI;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Characters to ignore
|
|
||||||
*/
|
|
||||||
driver->ignore_status_mask = 0;
|
|
||||||
if (I_IGNPAR(driver->tty))
|
|
||||||
driver->ignore_status_mask |= LSR_PE | LSR_FE;
|
|
||||||
|
|
||||||
if (I_IGNBRK(self->tty)) {
|
|
||||||
self->ignore_status_mask |= LSR_BI;
|
|
||||||
/*
|
|
||||||
* If we're ignore parity and break indicators, ignore
|
|
||||||
* overruns too. (For real raw support).
|
|
||||||
*/
|
|
||||||
if (I_IGNPAR(self->tty))
|
|
||||||
self->ignore_status_mask |= LSR_OE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
self->settings.data_format = cval;
|
self->settings.data_format = cval;
|
||||||
|
|
||||||
ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE);
|
ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE);
|
||||||
@ -271,67 +245,6 @@ static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self,
|
|||||||
static int ircomm_tty_set_serial_info(struct ircomm_tty_cb *self,
|
static int ircomm_tty_set_serial_info(struct ircomm_tty_cb *self,
|
||||||
struct serial_struct __user *new_info)
|
struct serial_struct __user *new_info)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
struct serial_struct new_serial;
|
|
||||||
struct ircomm_tty_cb old_state, *state;
|
|
||||||
|
|
||||||
if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
|
|
||||||
state = self
|
|
||||||
old_state = *self;
|
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN)) {
|
|
||||||
if ((new_serial.baud_base != state->settings.data_rate) ||
|
|
||||||
(new_serial.close_delay != state->close_delay) ||
|
|
||||||
((new_serial.flags & ~ASYNC_USR_MASK) !=
|
|
||||||
(self->flags & ~ASYNC_USR_MASK)))
|
|
||||||
return -EPERM;
|
|
||||||
state->flags = ((state->flags & ~ASYNC_USR_MASK) |
|
|
||||||
(new_serial.flags & ASYNC_USR_MASK));
|
|
||||||
self->flags = ((self->flags & ~ASYNC_USR_MASK) |
|
|
||||||
(new_serial.flags & ASYNC_USR_MASK));
|
|
||||||
/* self->custom_divisor = new_serial.custom_divisor; */
|
|
||||||
goto check_and_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* OK, past this point, all the error checking has been done.
|
|
||||||
* At this point, we start making changes.....
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (self->settings.data_rate != new_serial.baud_base) {
|
|
||||||
self->settings.data_rate = new_serial.baud_base;
|
|
||||||
ircomm_param_request(self, IRCOMM_DATA_RATE, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
self->close_delay = new_serial.close_delay * HZ/100;
|
|
||||||
self->closing_wait = new_serial.closing_wait * HZ/100;
|
|
||||||
/* self->custom_divisor = new_serial.custom_divisor; */
|
|
||||||
|
|
||||||
self->flags = ((self->flags & ~ASYNC_FLAGS) |
|
|
||||||
(new_serial.flags & ASYNC_FLAGS));
|
|
||||||
self->tty->low_latency = (self->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
|
||||||
|
|
||||||
check_and_exit:
|
|
||||||
|
|
||||||
if (tty_port_initialized(self)) {
|
|
||||||
if (((old_state.flags & ASYNC_SPD_MASK) !=
|
|
||||||
(self->flags & ASYNC_SPD_MASK)) ||
|
|
||||||
(old_driver.custom_divisor != driver->custom_divisor)) {
|
|
||||||
if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
|
|
||||||
driver->tty->alt_speed = 57600;
|
|
||||||
if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
|
|
||||||
driver->tty->alt_speed = 115200;
|
|
||||||
if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
|
|
||||||
driver->tty->alt_speed = 230400;
|
|
||||||
if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
|
|
||||||
driver->tty->alt_speed = 460800;
|
|
||||||
ircomm_tty_change_speed(driver);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,24 +280,6 @@ int ircomm_tty_ioctl(struct tty_struct *tty,
|
|||||||
|
|
||||||
case TIOCGICOUNT:
|
case TIOCGICOUNT:
|
||||||
pr_debug("%s(), TIOCGICOUNT not impl!\n", __func__);
|
pr_debug("%s(), TIOCGICOUNT not impl!\n", __func__);
|
||||||
#if 0
|
|
||||||
save_flags(flags); cli();
|
|
||||||
cnow = driver->icount;
|
|
||||||
restore_flags(flags);
|
|
||||||
p_cuser = (struct serial_icounter_struct __user *) arg;
|
|
||||||
if (put_user(cnow.cts, &p_cuser->cts) ||
|
|
||||||
put_user(cnow.dsr, &p_cuser->dsr) ||
|
|
||||||
put_user(cnow.rng, &p_cuser->rng) ||
|
|
||||||
put_user(cnow.dcd, &p_cuser->dcd) ||
|
|
||||||
put_user(cnow.rx, &p_cuser->rx) ||
|
|
||||||
put_user(cnow.tx, &p_cuser->tx) ||
|
|
||||||
put_user(cnow.frame, &p_cuser->frame) ||
|
|
||||||
put_user(cnow.overrun, &p_cuser->overrun) ||
|
|
||||||
put_user(cnow.parity, &p_cuser->parity) ||
|
|
||||||
put_user(cnow.brk, &p_cuser->brk) ||
|
|
||||||
put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
|
|
||||||
return -EFAULT;
|
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
ret = -ENOIOCTLCMD; /* ioctls which we must ignore */
|
ret = -ENOIOCTLCMD; /* ioctls which we must ignore */
|
||||||
|
Loading…
Reference in New Issue
Block a user