Commit 336722eb authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'tty-4.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty/serial driver updates from Greg KH:
 "Here is the big tty and serial driver pull request for 4.19-rc1.

  It's not all that big, just a number of small serial driver updates
  and fixes, along with some better vt handling for unicode characters
  for those using braille terminals.

  All of these patches have been in linux-next for a long time with no
  reported issues"

* tag 'tty-4.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (73 commits)
  tty: serial: 8250: Revert NXP SC16C2552 workaround
  serial: 8250_exar: Read INT0 from slave device, too
  tty: rocket: Fix possible buffer overwrite on register_PCI
  serial: 8250_dw: Add ACPI support for uart on Broadcom SoC
  serial: 8250_dw: always set baud rate in dw8250_set_termios
  dt-bindings: serial: Add binding for uartlite
  tty: serial: uartlite: Add support for suspend and resume
  tty: serial: uartlite: Add clock adaptation
  tty: serial: uartlite: Add structure for private data
  serial: sh-sci: Improve support for separate TEI and DRI interrupts
  serial: sh-sci: Remove SCIx_RZ_SCIFA_REGTYPE
  serial: sh-sci: Allow for compressed SCIF address
  serial: sh-sci: Improve interrupts description
  serial: 8250: Use cached port name directly in messages
  serial: 8250_exar: Drop unused variable in pci_xr17v35x_setup()
  vt: drop unused struct vt_struct
  vt: avoid a VLA in the unicode screen scroll function
  vt: add /dev/vcsu* to devices.txt
  vt: coherence validation code for the unicode screen buffer
  vt: selection: take screen contents from uniscr if available
  ...
parents 5695d5d1 47ac7666
...@@ -173,14 +173,18 @@ ...@@ -173,14 +173,18 @@
they are redirected through the parport multiplex layer. they are redirected through the parport multiplex layer.
7 char Virtual console capture devices 7 char Virtual console capture devices
0 = /dev/vcs Current vc text contents 0 = /dev/vcs Current vc text (glyph) contents
1 = /dev/vcs1 tty1 text contents 1 = /dev/vcs1 tty1 text (glyph) contents
... ...
63 = /dev/vcs63 tty63 text contents 63 = /dev/vcs63 tty63 text (glyph) contents
128 = /dev/vcsa Current vc text/attribute contents 64 = /dev/vcsu Current vc text (unicode) contents
129 = /dev/vcsa1 tty1 text/attribute contents 65 = /dev/vcsu1 tty1 text (unicode) contents
... ...
191 = /dev/vcsa63 tty63 text/attribute contents 127 = /dev/vcsu63 tty63 text (unicode) contents
128 = /dev/vcsa Current vc text/attribute (glyph) contents
129 = /dev/vcsa1 tty1 text/attribute (glyph) contents
...
191 = /dev/vcsa63 tty63 text/attribute (glyph) contents
NOTE: These devices permit both read and write access. NOTE: These devices permit both read and write access.
......
...@@ -11,6 +11,7 @@ compatible: Must contain one of ...@@ -11,6 +11,7 @@ compatible: Must contain one of
"mediatek,mt6589" "mediatek,mt6589"
"mediatek,mt6592" "mediatek,mt6592"
"mediatek,mt6755" "mediatek,mt6755"
"mediatek,mt6765"
"mediatek,mt6795" "mediatek,mt6795"
"mediatek,mt6797" "mediatek,mt6797"
"mediatek,mt7622" "mediatek,mt7622"
...@@ -41,6 +42,9 @@ Supported boards: ...@@ -41,6 +42,9 @@ Supported boards:
- Evaluation phone for MT6755(Helio P10): - Evaluation phone for MT6755(Helio P10):
Required root node properties: Required root node properties:
- compatible = "mediatek,mt6755-evb", "mediatek,mt6755"; - compatible = "mediatek,mt6755-evb", "mediatek,mt6755";
- Evaluation board for MT6765(Helio P22):
Required root node properties:
- compatible = "mediatek,mt6765-evb", "mediatek,mt6765";
- Evaluation board for MT6795(Helio X10): - Evaluation board for MT6795(Helio X10):
Required root node properties: Required root node properties:
- compatible = "mediatek,mt6795-evb", "mediatek,mt6795"; - compatible = "mediatek,mt6795-evb", "mediatek,mt6795";
......
...@@ -11,6 +11,7 @@ Required properties: ...@@ -11,6 +11,7 @@ Required properties:
"mediatek,mt7622-sysirq", "mediatek,mt6577-sysirq": for MT7622 "mediatek,mt7622-sysirq", "mediatek,mt6577-sysirq": for MT7622
"mediatek,mt6795-sysirq", "mediatek,mt6577-sysirq": for MT6795 "mediatek,mt6795-sysirq", "mediatek,mt6577-sysirq": for MT6795
"mediatek,mt6797-sysirq", "mediatek,mt6577-sysirq": for MT6797 "mediatek,mt6797-sysirq", "mediatek,mt6577-sysirq": for MT6797
"mediatek,mt6765-sysirq", "mediatek,mt6577-sysirq": for MT6765
"mediatek,mt6755-sysirq", "mediatek,mt6577-sysirq": for MT6755 "mediatek,mt6755-sysirq", "mediatek,mt6577-sysirq": for MT6755
"mediatek,mt6592-sysirq", "mediatek,mt6577-sysirq": for MT6592 "mediatek,mt6592-sysirq", "mediatek,mt6577-sysirq": for MT6592
"mediatek,mt6589-sysirq", "mediatek,mt6577-sysirq": for MT6589 "mediatek,mt6589-sysirq", "mediatek,mt6577-sysirq": for MT6589
......
...@@ -9,7 +9,11 @@ Optional properties: ...@@ -9,7 +9,11 @@ Optional properties:
- 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.
- rs485-rts-delay, rs485-rts-active-low, rs485-rx-during-tx, - rs485-rts-delay, rs485-rts-active-low, rs485-rx-during-tx,
linux,rs485-enabled-at-boot-time: see rs485.txt linux,rs485-enabled-at-boot-time: see rs485.txt. Note that for RS485
you must enable either the "uart-has-rtscts" or the "rts-gpios"
properties. In case you use "uart-has-rtscts" the signal that controls
the transceiver is actually CTS_B, not RTS_B. CTS_B is always output,
and RTS_B is input, regardless of dte-mode.
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.
......
...@@ -8,6 +8,7 @@ Required properties: ...@@ -8,6 +8,7 @@ Required properties:
* "mediatek,mt6582-uart" for MT6582 compatible UARTS * "mediatek,mt6582-uart" for MT6582 compatible UARTS
* "mediatek,mt6589-uart" for MT6589 compatible UARTS * "mediatek,mt6589-uart" for MT6589 compatible UARTS
* "mediatek,mt6755-uart" for MT6755 compatible UARTS * "mediatek,mt6755-uart" for MT6755 compatible UARTS
* "mediatek,mt6765-uart" for MT6765 compatible UARTS
* "mediatek,mt6795-uart" for MT6795 compatible UARTS * "mediatek,mt6795-uart" for MT6795 compatible UARTS
* "mediatek,mt6797-uart" for MT6797 compatible UARTS * "mediatek,mt6797-uart" for MT6797 compatible UARTS
* "mediatek,mt7622-uart" for MT7622 compatible UARTS * "mediatek,mt7622-uart" for MT7622 compatible UARTS
......
OMAP UART controller OMAP UART controller
Required properties: Required properties:
- compatible : should be "ti,am654-uart" for AM654 controllers
- compatible : should be "ti,omap2-uart" for OMAP2 controllers - compatible : should be "ti,omap2-uart" for OMAP2 controllers
- compatible : should be "ti,omap3-uart" for OMAP3 controllers - compatible : should be "ti,omap3-uart" for OMAP3 controllers
- compatible : should be "ti,omap4-uart" for OMAP4 controllers - compatible : should be "ti,omap4-uart" for OMAP4 controllers
......
Renesas RZ/N1 UART
This controller is based on the Synopsys DesignWare ABP UART and inherits all
properties defined in snps-dw-apb-uart.txt except for the compatible property.
Required properties:
- compatible : The device specific string followed by the generic RZ/N1 string.
Therefore it must be one of:
"renesas,r9a06g032-uart", "renesas,rzn1-uart"
"renesas,r9a06g033-uart", "renesas,rzn1-uart"
...@@ -5,6 +5,7 @@ Required properties: ...@@ -5,6 +5,7 @@ Required properties:
- compatible: Must contain one or more of the following: - compatible: Must contain one or more of the following:
- "renesas,scif-r7s72100" for R7S72100 (RZ/A1H) SCIF compatible UART. - "renesas,scif-r7s72100" for R7S72100 (RZ/A1H) SCIF compatible UART.
- "renesas,scif-r7s9210" for R7S9210 (RZ/A2) SCIF compatible UART.
- "renesas,scifa-r8a73a4" for R8A73A4 (R-Mobile APE6) SCIFA compatible UART. - "renesas,scifa-r8a73a4" for R8A73A4 (R-Mobile APE6) SCIFA compatible UART.
- "renesas,scifb-r8a73a4" for R8A73A4 (R-Mobile APE6) SCIFB compatible UART. - "renesas,scifb-r8a73a4" for R8A73A4 (R-Mobile APE6) SCIFB compatible UART.
- "renesas,scifa-r8a7740" for R8A7740 (R-Mobile A1) SCIFA compatible UART. - "renesas,scifa-r8a7740" for R8A7740 (R-Mobile A1) SCIFA compatible UART.
...@@ -72,7 +73,21 @@ Required properties: ...@@ -72,7 +73,21 @@ Required properties:
family-specific and/or generic versions. family-specific and/or generic versions.
- reg: Base address and length of the I/O registers used by the UART. - reg: Base address and length of the I/O registers used by the UART.
- interrupts: Must contain an interrupt-specifier for the SCIx interrupt. - interrupts: Must contain one or more interrupt-specifiers for the SCIx.
If a single interrupt is expressed, then all events are
multiplexed into this single interrupt.
If multiple interrupts are provided by the hardware, the order
in which the interrupts are listed must match order below. Note
that some HW interrupt events may be muxed together resulting
in duplicate entries.
The interrupt order is as follows:
1. Error (ERI)
2. Receive buffer full (RXI)
3. Transmit buffer empty (TXI)
4. Break (BRI)
5. Data Ready (DRI)
6. Transmit End (TEI)
- clocks: Must contain a phandle and clock-specifier pair for each entry - clocks: Must contain a phandle and clock-specifier pair for each entry
in clock-names. in clock-names.
...@@ -89,7 +104,7 @@ Required properties: ...@@ -89,7 +104,7 @@ Required properties:
- "scif_clk" for the optional external clock source for the frequency - "scif_clk" for the optional external clock source for the frequency
divider (SCIF_CLK). divider (SCIF_CLK).
Note: Each enabled SCIx UART should have an alias correctly numbered in the Note: Each enabled SCIx UART may have an optional "serialN" alias in the
"aliases" node. "aliases" node.
Optional properties: Optional properties:
......
Xilinx Axi Uartlite controller Device Tree Bindings
---------------------------------------------------------
Required properties:
- compatible : Can be either of
"xlnx,xps-uartlite-1.00.a"
"xlnx,opb-uartlite-1.00.b"
- reg : Physical base address and size of the Axi Uartlite
registers map.
- interrupts : Should contain the UART controller interrupt.
Optional properties:
- port-number : Set Uart port number
- clock-names : Should be "s_axi_aclk"
- clocks : Input clock specifier. Refer to common clock bindings.
Example:
serial@800c0000 {
compatible = "xlnx,xps-uartlite-1.00.a";
reg = <0x0 0x800c0000 0x10000>;
interrupts = <0x0 0x6e 0x1>;
port-number = <0>;
};
...@@ -46,7 +46,7 @@ Child nodes should conform to I2C bus binding as described in i2c.txt. ...@@ -46,7 +46,7 @@ Child nodes should conform to I2C bus binding as described in i2c.txt.
Qualcomm Technologies Inc. GENI Serial Engine based UART Controller Qualcomm Technologies Inc. GENI Serial Engine based UART Controller
Required properties: Required properties:
- compatible: Must be "qcom,geni-debug-uart". - compatible: Must be "qcom,geni-debug-uart" or "qcom,geni-uart".
- reg: Must contain UART register location and length. - reg: Must contain UART register location and length.
- interrupts: Must contain UART core interrupts. - interrupts: Must contain UART core interrupts.
- clock-names: Must contain "se". - clock-names: Must contain "se".
......
...@@ -58,6 +58,7 @@ enum parport_pc_pci_cards { ...@@ -58,6 +58,7 @@ enum parport_pc_pci_cards {
timedia_9079c, timedia_9079c,
wch_ch353_1s1p, wch_ch353_1s1p,
wch_ch353_2s1p, wch_ch353_2s1p,
wch_ch382_0s1p,
wch_ch382_2s1p, wch_ch382_2s1p,
brainboxes_5s1p, brainboxes_5s1p,
sunix_2s1p, sunix_2s1p,
...@@ -147,6 +148,7 @@ static struct parport_pc_pci cards[] = { ...@@ -147,6 +148,7 @@ static struct parport_pc_pci cards[] = {
/* timedia_9079c */ { 1, { { 2, 3 }, } }, /* timedia_9079c */ { 1, { { 2, 3 }, } },
/* wch_ch353_1s1p*/ { 1, { { 1, -1}, } }, /* wch_ch353_1s1p*/ { 1, { { 1, -1}, } },
/* wch_ch353_2s1p*/ { 1, { { 2, -1}, } }, /* wch_ch353_2s1p*/ { 1, { { 2, -1}, } },
/* wch_ch382_0s1p*/ { 1, { { 2, -1}, } },
/* wch_ch382_2s1p*/ { 1, { { 2, -1}, } }, /* wch_ch382_2s1p*/ { 1, { { 2, -1}, } },
/* brainboxes_5s1p */ { 1, { { 3, -1 }, } }, /* brainboxes_5s1p */ { 1, { { 3, -1 }, } },
/* sunix_2s1p */ { 1, { { 3, -1 }, } }, /* sunix_2s1p */ { 1, { { 3, -1 }, } },
...@@ -252,6 +254,7 @@ static struct pci_device_id parport_serial_pci_tbl[] = { ...@@ -252,6 +254,7 @@ static struct pci_device_id parport_serial_pci_tbl[] = {
/* WCH CARDS */ /* WCH CARDS */
{ 0x4348, 0x5053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, wch_ch353_1s1p}, { 0x4348, 0x5053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, wch_ch353_1s1p},
{ 0x4348, 0x7053, 0x4348, 0x3253, 0, 0, wch_ch353_2s1p}, { 0x4348, 0x7053, 0x4348, 0x3253, 0, 0, wch_ch353_2s1p},
{ 0x1c00, 0x3050, 0x1c00, 0x3050, 0, 0, wch_ch382_0s1p},
{ 0x1c00, 0x3250, 0x1c00, 0x3250, 0, 0, wch_ch382_2s1p}, { 0x1c00, 0x3250, 0x1c00, 0x3250, 0, 0, wch_ch382_2s1p},
/* BrainBoxes PX272/PX306 MIO card */ /* BrainBoxes PX272/PX306 MIO card */
...@@ -494,6 +497,12 @@ static struct pciserial_board pci_parport_serial_boards[] = { ...@@ -494,6 +497,12 @@ static struct pciserial_board pci_parport_serial_boards[] = {
.base_baud = 115200, .base_baud = 115200,
.uart_offset = 8, .uart_offset = 8,
}, },
[wch_ch382_0s1p] = {
.flags = FL_BASE0,
.num_ports = 0,
.base_baud = 115200,
.uart_offset = 8,
},
[wch_ch382_2s1p] = { [wch_ch382_2s1p] = {
.flags = FL_BASE0, .flags = FL_BASE0,
.num_ports = 2, .num_ports = 2,
......
...@@ -39,8 +39,34 @@ static const int kbd_max_vals[] = { ...@@ -39,8 +39,34 @@ static const int kbd_max_vals[] = {
}; };
static const int KBD_NR_TYPES = ARRAY_SIZE(kbd_max_vals); static const int KBD_NR_TYPES = ARRAY_SIZE(kbd_max_vals);
static unsigned char ret_diacr[NR_DEAD] = { static const unsigned char ret_diacr[NR_DEAD] = {
'`', '\'', '^', '~', '"', ',' '`', /* dead_grave */
'\'', /* dead_acute */
'^', /* dead_circumflex */
'~', /* dead_tilda */
'"', /* dead_diaeresis */
',', /* dead_cedilla */
'_', /* dead_macron */
'U', /* dead_breve */
'.', /* dead_abovedot */
'*', /* dead_abovering */
'=', /* dead_doubleacute */
'c', /* dead_caron */
'k', /* dead_ogonek */
'i', /* dead_iota */
'#', /* dead_voiced_sound */
'o', /* dead_semivoiced_sound */
'!', /* dead_belowdot */
'?', /* dead_hook */
'+', /* dead_horn */
'-', /* dead_stroke */
')', /* dead_abovecomma */
'(', /* dead_abovereversedcomma */
':', /* dead_doublegrave */
'n', /* dead_invertedbreve */
';', /* dead_belowcomma */
'$', /* dead_currency */
'@', /* dead_greek */
}; };
/* /*
......
...@@ -625,7 +625,7 @@ int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags) ...@@ -625,7 +625,7 @@ int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags)
if (tty->driver != ptm_driver) if (tty->driver != ptm_driver)
return -EIO; return -EIO;
fd = get_unused_fd_flags(0); fd = get_unused_fd_flags(flags);
if (fd < 0) { if (fd < 0) {
retval = fd; retval = fd;
goto err; goto err;
......
...@@ -1881,7 +1881,7 @@ static __init int register_PCI(int i, struct pci_dev *dev) ...@@ -1881,7 +1881,7 @@ static __init int register_PCI(int i, struct pci_dev *dev)
ByteIO_t UPCIRingInd = 0; ByteIO_t UPCIRingInd = 0;
if (!dev || !pci_match_id(rocket_pci_ids, dev) || if (!dev || !pci_match_id(rocket_pci_ids, dev) ||
pci_enable_device(dev)) pci_enable_device(dev) || i >= NUM_BOARDS)
return 0; return 0;
rcktpt_io_addr[i] = pci_resource_start(dev, 0); rcktpt_io_addr[i] = pci_resource_start(dev, 0);
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/serdev.h> #include <linux/serdev.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -143,11 +145,28 @@ EXPORT_SYMBOL_GPL(serdev_device_remove); ...@@ -143,11 +145,28 @@ EXPORT_SYMBOL_GPL(serdev_device_remove);
int serdev_device_open(struct serdev_device *serdev) int serdev_device_open(struct serdev_device *serdev)
{ {
struct serdev_controller *ctrl = serdev->ctrl; struct serdev_controller *ctrl = serdev->ctrl;
int ret;
if (!ctrl || !ctrl->ops->open) if (!ctrl || !ctrl->ops->open)
return -EINVAL; return -EINVAL;
return ctrl->ops->open(ctrl); ret = ctrl->ops->open(ctrl);
if (ret)
return ret;
ret = pm_runtime_get_sync(&ctrl->dev);
if (ret < 0) {
pm_runtime_put_noidle(&ctrl->dev);
goto err_close;
}
return 0;
err_close:
if (ctrl->ops->close)
ctrl->ops->close(ctrl);
return ret;
} }
EXPORT_SYMBOL_GPL(serdev_device_open); EXPORT_SYMBOL_GPL(serdev_device_open);
...@@ -158,6 +177,8 @@ void serdev_device_close(struct serdev_device *serdev) ...@@ -158,6 +177,8 @@ void serdev_device_close(struct serdev_device *serdev)
if (!ctrl || !ctrl->ops->close) if (!ctrl || !ctrl->ops->close)
return; return;
pm_runtime_put(&ctrl->dev);
ctrl->ops->close(ctrl); ctrl->ops->close(ctrl);
} }
EXPORT_SYMBOL_GPL(serdev_device_close); EXPORT_SYMBOL_GPL(serdev_device_close);
...@@ -330,8 +351,17 @@ EXPORT_SYMBOL_GPL(serdev_device_set_tiocm); ...@@ -330,8 +351,17 @@ EXPORT_SYMBOL_GPL(serdev_device_set_tiocm);
static int serdev_drv_probe(struct device *dev) static int serdev_drv_probe(struct device *dev)
{ {
const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver); const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver);
int ret;
ret = dev_pm_domain_attach(dev, true);
if (ret)
return ret;
ret = sdrv->probe(to_serdev_device(dev));
if (ret)
dev_pm_domain_detach(dev, true);
return sdrv->probe(to_serdev_device(dev)); return ret;
} }
static int serdev_drv_remove(struct device *dev) static int serdev_drv_remove(struct device *dev)
...@@ -339,6 +369,9 @@ static int serdev_drv_remove(struct device *dev) ...@@ -339,6 +369,9 @@ static int serdev_drv_remove(struct device *dev)
const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver); const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver);
if (sdrv->remove) if (sdrv->remove)
sdrv->remove(to_serdev_device(dev)); sdrv->remove(to_serdev_device(dev));
dev_pm_domain_detach(dev, true);
return 0; return 0;
} }
...@@ -416,6 +449,9 @@ struct serdev_controller *serdev_controller_alloc(struct device *parent, ...@@ -416,6 +449,9 @@ struct serdev_controller *serdev_controller_alloc(struct device *parent,
dev_set_name(&ctrl->dev, "serial%d", id); dev_set_name(&ctrl->dev, "serial%d", id);
pm_runtime_no_callbacks(&ctrl->dev);
pm_suspend_ignore_children(&ctrl->dev, true);
dev_dbg(&ctrl->dev, "allocated controller 0x%p id %d\n", ctrl, id); dev_dbg(&ctrl->dev, "allocated controller 0x%p id %d\n", ctrl, id);
return ctrl; return ctrl;
...@@ -547,20 +583,23 @@ int serdev_controller_add(struct serdev_controller *ctrl) ...@@ -547,20 +583,23 @@ int serdev_controller_add(struct serdev_controller *ctrl)
if (ret) if (ret)
return ret; return ret;
pm_runtime_enable(&ctrl->dev);
ret_of = of_serdev_register_devices(ctrl); ret_of = of_serdev_register_devices(ctrl);
ret_acpi = acpi_serdev_register_devices(ctrl); ret_acpi = acpi_serdev_register_devices(ctrl);
if (ret_of && ret_acpi) { if (ret_of && ret_acpi) {
dev_dbg(&ctrl->dev, "no devices registered: of:%d acpi:%d\n", dev_dbg(&ctrl->dev, "no devices registered: of:%d acpi:%d\n",
ret_of, ret_acpi); ret_of, ret_acpi);
ret = -ENODEV; ret = -ENODEV;
goto out_dev_del; goto err_rpm_disable;
} }
dev_dbg(&ctrl->dev, "serdev%d registered: dev:%p\n", dev_dbg(&ctrl->dev, "serdev%d registered: dev:%p\n",
ctrl->nr, &ctrl->dev); ctrl->nr, &ctrl->dev);
return 0; return 0;
out_dev_del: err_rpm_disable:
pm_runtime_disable(&ctrl->dev);
device_del(&ctrl->dev); device_del(&ctrl->dev);
return ret; return ret;
}; };
...@@ -591,6 +630,7 @@ void serdev_controller_remove(struct serdev_controller *ctrl) ...@@ -591,6 +630,7 @@ void serdev_controller_remove(struct serdev_controller *ctrl)
dummy = device_for_each_child(&ctrl->dev, NULL, dummy = device_for_each_child(&ctrl->dev, NULL,
serdev_remove_device); serdev_remove_device);
pm_runtime_disable(&ctrl->dev);
device_del(&ctrl->dev); device_del(&ctrl->dev);
} }
EXPORT_SYMBOL_GPL(serdev_controller_remove); EXPORT_SYMBOL_GPL(serdev_controller_remove);
......
...@@ -323,7 +323,7 @@ static int univ8250_setup_irq(struct uart_8250_port *up) ...@@ -323,7 +323,7 @@ static int univ8250_setup_irq(struct uart_8250_port *up)
* the port is opened so this value needs to be preserved. * the port is opened so this value needs to be preserved.
*/ */
if (up->bugs & UART_BUG_THRE) { if (up->bugs & UART_BUG_THRE) {
pr_debug("ttyS%d - using backup timer\n", serial_index(port)); pr_debug("%s - using backup timer\n", port->name);
up->timer.function = serial8250_backup_timeout; up->timer.function = serial8250_backup_timeout;
mod_timer(&up->timer, jiffies + mod_timer(&up->timer, jiffies +
...@@ -1023,6 +1023,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up) ...@@ -1023,6 +1023,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart->port.get_mctrl = up->port.get_mctrl; uart->port.get_mctrl = up->port.get_mctrl;
if (up->port.set_mctrl) if (up->port.set_mctrl)
uart->port.set_mctrl = up->port.set_mctrl; uart->port.set_mctrl = up->port.set_mctrl;
if (up->port.get_divisor)
uart->port.get_divisor = up->port.get_divisor;
if (up->port.set_divisor)
uart->port.set_divisor = up->port.set_divisor;
if (up->port.startup) if (up->port.startup)
uart->port.startup = up->port.startup; uart->port.startup = up->port.startup;
if (up->port.shutdown) if (up->port.shutdown)
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
/* Offsets for the DesignWare specific registers */ /* Offsets for the DesignWare specific registers */
#define DW_UART_USR 0x1f /* UART Status Register */ #define DW_UART_USR 0x1f /* UART Status Register */
#define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */
#define DW_UART_CPR 0xf4 /* Component Parameter Register */ #define DW_UART_CPR 0xf4 /* Component Parameter Register */
#define DW_UART_UCV 0xf8 /* UART Component Version */ #define DW_UART_UCV 0xf8 /* UART Component Version */
...@@ -55,6 +56,7 @@ ...@@ -55,6 +56,7 @@
struct dw8250_data { struct dw8250_data {
u8 usr_reg; u8 usr_reg;
u8 dlf_size;
int line; int line;
int msr_mask_on; int msr_mask_on;
int msr_mask_off; int msr_mask_off;
...@@ -67,6 +69,21 @@ struct dw8250_data { ...@@ -67,6 +69,21 @@ struct dw8250_data {
unsigned int uart_16550_compatible:1; unsigned int uart_16550_compatible:1;
}; };
static inline u32 dw8250_readl_ext(struct uart_port *p, int offset)
{
if (p->iotype == UPIO_MEM32BE)
return ioread32be(p->membase + offset);
return readl(p->membase + offset);
}
static inline void dw8250_writel_ext(struct uart_port *p, int offset, u32 reg)
{
if (p->iotype == UPIO_MEM32BE)
iowrite32be(reg, p->membase + offset);
else
writel(reg, p->membase + offset);
}
static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
{ {
struct dw8250_data *d = p->private_data; struct dw8250_data *d = p->private_data;
...@@ -293,7 +310,7 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, ...@@ -293,7 +310,7 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
long rate; long rate;
int ret; int ret;
if (IS_ERR(d->clk) || !old) if (IS_ERR(d->clk))
goto out; goto out;
clk_disable_unprepare(d->clk); clk_disable_unprepare(d->clk);
...@@ -351,6 +368,37 @@ static bool dw8250_idma_filter(struct dma_chan *chan, void *param) ...@@ -351,6 +368,37 @@ static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
return param == chan->device->dev->parent; return param == chan->device->dev->parent;
} }
/*
* divisor = div(I) + div(F)
* "I" means integer, "F" means fractional
* quot = div(I) = clk / (16 * baud)
* frac = div(F) * 2^dlf_size
*
* let rem = clk % (16 * baud)
* we have: div(F) * (16 * baud) = rem
* so frac = 2^dlf_size * rem / (16 * baud) = (rem << dlf_size) / (16 * baud)
*/
static unsigned int dw8250_get_divisor(struct uart_port *p,
unsigned int baud,
unsigned int *frac)
{
unsigned int quot, rem, base_baud = baud * 16;
struct dw8250_data *d = p->private_data;
quot = p->uartclk / base_baud;
rem = p->uartclk % base_baud;
*frac = DIV_ROUND_CLOSEST(rem << d->dlf_size, base_baud);
return quot;
}
static void dw8250_set_divisor(struct uart_port *p, unsigned int baud,
unsigned int quot, unsigned int quot_frac)
{
dw8250_writel_ext(p, DW_UART_DLF, quot_frac);
serial8250_do_set_divisor(p, baud, quot, quot_frac);
}
static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
{ {
if (p->dev->of_node) { if (p->dev->of_node) {
...@@ -404,20 +452,26 @@ static void dw8250_setup_port(struct uart_port *p) ...@@ -404,20 +452,26 @@ static void dw8250_setup_port(struct uart_port *p)
* If the Component Version Register returns zero, we know that * If the Component Version Register returns zero, we know that
* ADDITIONAL_FEATURES are not enabled. No need to go any further. * ADDITIONAL_FEATURES are not enabled. No need to go any further.
*/ */
if (p->iotype == UPIO_MEM32BE) reg = dw8250_readl_ext(p, DW_UART_UCV);
reg = ioread32be(p->membase + DW_UART_UCV);
else
reg = readl(p->membase + DW_UART_UCV);
if (!reg) if (!reg)
return; return;
dev_dbg(p->dev, "Designware UART version %c.%c%c\n", dev_dbg(p->dev, "Designware UART version %c.%c%c\n",
(reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
if (p->iotype == UPIO_MEM32BE) dw8250_writel_ext(p, DW_UART_DLF, ~0U);
reg = ioread32be(p->membase + DW_UART_CPR); reg = dw8250_readl_ext(p, DW_UART_DLF);
else dw8250_writel_ext(p, DW_UART_DLF, 0);
reg = readl(p->membase + DW_UART_CPR);
if (reg) {
struct dw8250_data *d = p->private_data;
d->dlf_size = fls(reg);
p->get_divisor = dw8250_get_divisor;
p->set_divisor = dw8250_set_divisor;
}
reg = dw8250_readl_ext(p, DW_UART_CPR);
if (!reg) if (!reg)
return; return;
...@@ -693,6 +747,7 @@ static const struct of_device_id dw8250_of_match[] = { ...@@ -693,6 +747,7 @@ static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "snps,dw-apb-uart" }, { .compatible = "snps,dw-apb-uart" },
{ .compatible = "cavium,octeon-3860-uart" }, { .compatible = "cavium,octeon-3860-uart" },
{ .compatible = "marvell,armada-38x-uart" }, { .compatible = "marvell,armada-38x-uart" },
{ .compatible = "renesas,rzn1-uart" },
{ /* Sentinel */ } { /* Sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, dw8250_of_match); MODULE_DEVICE_TABLE(of, dw8250_of_match);
...@@ -707,6 +762,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = { ...@@ -707,6 +762,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = {
{ "APMC0D08", 0}, { "APMC0D08", 0},
{ "AMD0020", 0 }, { "AMD0020", 0 },
{ "AMDI0020", 0 }, { "AMDI0020", 0 },
{ "BRCM2032", 0 },
{ "HISI0031", 0 }, { "HISI0031", 0 },
{ }, { },
}; };
......
...@@ -109,11 +109,12 @@ struct exar8250_platform { ...@@ -109,11 +109,12 @@ struct exar8250_platform {
* struct exar8250_board - board information * struct exar8250_board - board information
* @num_ports: number of serial ports * @num_ports: number of serial ports
* @reg_shift: describes UART register mapping in PCI memory * @reg_shift: describes UART register mapping in PCI memory
* @setup: quirk run at ->probe() stage
* @exit: quirk run at ->remove() stage
*/ */
struct exar8250_board { struct exar8250_board {
unsigned int num_ports; unsigned int num_ports;
unsigned int reg_shift; unsigned int reg_shift;
bool has_slave;
int (*setup)(struct exar8250 *, struct pci_dev *, int (*setup)(struct exar8250 *, struct pci_dev *,
struct uart_8250_port *, int); struct uart_8250_port *, int);
void (*exit)(struct pci_dev *pcidev); void (*exit)(struct pci_dev *pcidev);
...@@ -272,8 +273,32 @@ static int xr17v35x_register_gpio(struct pci_dev *pcidev, ...@@ -272,8 +273,32 @@ static int xr17v35x_register_gpio(struct pci_dev *pcidev,
return 0; return 0;
} }
static int generic_rs485_config(struct uart_port *port,
struct serial_rs485 *rs485)
{
bool is_rs485 = !!(rs485->flags & SER_RS485_ENABLED);
u8 __iomem *p = port->membase;
u8 value;
value = readb(p + UART_EXAR_FCTR);
if (is_rs485)
value |= UART_FCTR_EXAR_485;
else
value &= ~UART_FCTR_EXAR_485;
writeb(value, p + UART_EXAR_FCTR);
if (is_rs485)
writeb(UART_EXAR_RS485_DLY(4), p + UART_MSR);
port->rs485 = *rs485;
return 0;
}
static const struct exar8250_platform exar8250_default_platform = { static const struct exar8250_platform exar8250_default_platform = {
.register_gpio = xr17v35x_register_gpio, .register_gpio = xr17v35x_register_gpio,
.rs485_config = generic_rs485_config,
}; };
static int iot2040_rs485_config(struct uart_port *port, static int iot2040_rs485_config(struct uart_port *port,
...@@ -306,19 +331,7 @@ static int iot2040_rs485_config(struct uart_port *port, ...@@ -306,19 +331,7 @@ static int iot2040_rs485_config(struct uart_port *port,
value |= mode; value |= mode;
writeb(value, p + UART_EXAR_MPIOLVL_7_0); writeb(value, p + UART_EXAR_MPIOLVL_7_0);
value = readb(p + UART_EXAR_FCTR); return generic_rs485_config(port, rs485);
if (is_rs485)
value |= UART_FCTR_EXAR_485;
else
value &= ~UART_FCTR_EXAR_485;
writeb(value, p + UART_EXAR_FCTR);
if (is_rs485)
writeb(UART_EXAR_RS485_DLY(4), p + UART_MSR);
port->rs485 = *rs485;
return 0;
} }
static const struct property_entry iot2040_gpio_properties[] = { static const struct property_entry iot2040_gpio_properties[] = {
...@@ -364,7 +377,6 @@ static int ...@@ -364,7 +377,6 @@ static int
pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev, pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev,
struct uart_8250_port *port, int idx) struct uart_8250_port *port, int idx)
{ {
const struct exar8250_board *board = priv->board;
const struct exar8250_platform *platform; const struct exar8250_platform *platform;
const struct dmi_system_id *dmi_match; const struct dmi_system_id *dmi_match;
unsigned int offset = idx * 0x400; unsigned int offset = idx * 0x400;
...@@ -382,10 +394,10 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev, ...@@ -382,10 +394,10 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev,
port->port.rs485_config = platform->rs485_config; port->port.rs485_config = platform->rs485_config;
/* /*
* Setup the uart clock for the devices on expansion slot to * Setup the UART clock for the devices on expansion slot to
* half the clock speed of the main chip (which is 125MHz) * half the clock speed of the main chip (which is 125MHz)
*/ */
if (board->has_slave && idx >= 8) if (idx >= 8)
port->port.uartclk /= 2; port->port.uartclk /= 2;
ret = default_setup(priv, pcidev, idx, offset, port); ret = default_setup(priv, pcidev, idx, offset, port);
...@@ -433,7 +445,11 @@ static irqreturn_t exar_misc_handler(int irq, void *data) ...@@ -433,7 +445,11 @@ static irqreturn_t exar_misc_handler(int irq, void *data)
struct exar8250 *priv = data; struct exar8250 *priv = data;
/* Clear all PCI interrupts by reading INT0. No effect on IIR */ /* Clear all PCI interrupts by reading INT0. No effect on IIR */
ioread8(priv->virt + UART_EXAR_INT0); readb(priv->virt + UART_EXAR_INT0);
/* Clear INT0 for Expansion Interface slave ports, too */
if (priv->board->num_ports > 8)
readb(priv->virt + 0x2000 + UART_EXAR_INT0);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -590,14 +606,12 @@ static const struct exar8250_board pbn_exar_XR17V35x = { ...@@ -590,14 +606,12 @@ static const struct exar8250_board pbn_exar_XR17V35x = {
static const struct exar8250_board pbn_exar_XR17V4358 = { static const struct exar8250_board pbn_exar_XR17V4358 = {
.num_ports = 12, .num_ports = 12,
.has_slave = true,
.setup = pci_xr17v35x_setup, .setup = pci_xr17v35x_setup,
.exit = pci_xr17v35x_exit, .exit = pci_xr17v35x_exit,
}; };
static const struct exar8250_board pbn_exar_XR17V8358 = { static const struct exar8250_board pbn_exar_XR17V8358 = {
.num_ports = 16, .num_ports = 16,
.has_slave = true,
.setup = pci_xr17v35x_setup, .setup = pci_xr17v35x_setup,
.exit = pci_xr17v35x_exit, .exit = pci_xr17v35x_exit,
}; };
......
...@@ -124,7 +124,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev, ...@@ -124,7 +124,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n", dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n",
prop); prop);
ret = -EINVAL; ret = -EINVAL;
goto err_dispose; goto err_unprepare;
} }
} }
port->flags |= UPF_IOREMAP; port->flags |= UPF_IOREMAP;
...@@ -144,6 +144,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev, ...@@ -144,6 +144,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
port->line = ret; port->line = ret;
port->irq = irq_of_parse_and_map(np, 0); port->irq = irq_of_parse_and_map(np, 0);
if (!port->irq) {
ret = -EPROBE_DEFER;
goto err_unprepare;
}
info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL); info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL);
if (IS_ERR(info->rst)) { if (IS_ERR(info->rst)) {
......
...@@ -1115,6 +1115,7 @@ static const u8 am3352_habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE; ...@@ -1115,6 +1115,7 @@ static const u8 am3352_habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE;
static const u8 dra742_habit = UART_ERRATA_CLOCK_DISABLE; static const u8 dra742_habit = UART_ERRATA_CLOCK_DISABLE;
static const struct of_device_id omap8250_dt_ids[] = { static const struct of_device_id omap8250_dt_ids[] = {
{ .compatible = "ti,am654-uart" },
{ .compatible = "ti,omap2-uart" }, { .compatible = "ti,omap2-uart" },
{ .compatible = "ti,omap3-uart" }, { .compatible = "ti,omap3-uart" },
{ .compatible = "ti,omap4-uart", .data = &omap4_habit, }, { .compatible = "ti,omap4-uart", .data = &omap4_habit, },
......
...@@ -90,8 +90,7 @@ static const struct serial8250_config uart_config[] = { ...@@ -90,8 +90,7 @@ static const struct serial8250_config uart_config[] = {
.name = "16550A", .name = "16550A",
.fifo_size = 16, .fifo_size = 16,
.tx_loadsz = 16, .tx_loadsz = 16,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
.rxtrig_bytes = {1, 4, 8, 14}, .rxtrig_bytes = {1, 4, 8, 14},
.flags = UART_CAP_FIFO, .flags = UART_CAP_FIFO,
}, },
...@@ -1211,8 +1210,8 @@ static void autoconfig(struct uart_8250_port *up) ...@@ -1211,8 +1210,8 @@ static void autoconfig(struct uart_8250_port *up)
if (!port->iobase && !port->mapbase && !port->membase) if (!port->iobase && !port->mapbase && !port->membase)
return; return;
DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ", DEBUG_AUTOCONF("%s: autoconf (0x%04lx, 0x%p): ",
serial_index(port), port->iobase, port->membase); port->name, port->iobase, port->membase);
/* /*
* We really do need global IRQs disabled here - we're going to * We really do need global IRQs disabled here - we're going to
...@@ -1363,9 +1362,8 @@ static void autoconfig(struct uart_8250_port *up) ...@@ -1363,9 +1362,8 @@ static void autoconfig(struct uart_8250_port *up)
fintek_8250_probe(up); fintek_8250_probe(up);
if (up->capabilities != old_capabilities) { if (up->capabilities != old_capabilities) {
pr_warn("ttyS%d: detected caps %08x should be %08x\n", pr_warn("%s: detected caps %08x should be %08x\n",
serial_index(port), old_capabilities, port->name, old_capabilities, up->capabilities);
up->capabilities);
} }
out: out:
DEBUG_AUTOCONF("iir=%d ", scratch); DEBUG_AUTOCONF("iir=%d ", scratch);
...@@ -2212,8 +2210,7 @@ int serial8250_do_startup(struct uart_port *port) ...@@ -2212,8 +2210,7 @@ int serial8250_do_startup(struct uart_port *port)
*/ */
if (!(port->flags & UPF_BUGGY_UART) && if (!(port->flags & UPF_BUGGY_UART) &&
(serial_port_in(port, UART_LSR) == 0xff)) { (serial_port_in(port, UART_LSR) == 0xff)) {
printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n", pr_info_ratelimited("%s: LSR safety check engaged!\n", port->name);
serial_index(port));
retval = -ENODEV; retval = -ENODEV;
goto out; goto out;
} }
...@@ -2245,8 +2242,8 @@ int serial8250_do_startup(struct uart_port *port) ...@@ -2245,8 +2242,8 @@ int serial8250_do_startup(struct uart_port *port)
(port->type == PORT_ALTR_16550_F128)) && (port->fifosize > 1)) { (port->type == PORT_ALTR_16550_F128)) && (port->fifosize > 1)) {
/* Bounds checking of TX threshold (valid 0 to fifosize-2) */ /* Bounds checking of TX threshold (valid 0 to fifosize-2) */
if ((up->tx_loadsz < 2) || (up->tx_loadsz > port->fifosize)) { if ((up->tx_loadsz < 2) || (up->tx_loadsz > port->fifosize)) {
pr_err("ttyS%d TX FIFO Threshold errors, skipping\n", pr_err("%s TX FIFO Threshold errors, skipping\n",
serial_index(port)); port->name);
} else { } else {
serial_port_out(port, UART_ALTR_AFR, serial_port_out(port, UART_ALTR_AFR,
UART_ALTR_EN_TXFIFO_LW); UART_ALTR_EN_TXFIFO_LW);
...@@ -2343,8 +2340,8 @@ int serial8250_do_startup(struct uart_port *port) ...@@ -2343,8 +2340,8 @@ int serial8250_do_startup(struct uart_port *port)
if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
if (!(up->bugs & UART_BUG_TXEN)) { if (!(up->bugs & UART_BUG_TXEN)) {
up->bugs |= UART_BUG_TXEN; up->bugs |= UART_BUG_TXEN;
pr_debug("ttyS%d - enabling bad tx status workarounds\n", pr_debug("%s - enabling bad tx status workarounds\n",
serial_index(port)); port->name);
} }
} else { } else {
up->bugs &= ~UART_BUG_TXEN; up->bugs &= ~UART_BUG_TXEN;
...@@ -2373,8 +2370,8 @@ int serial8250_do_startup(struct uart_port *port) ...@@ -2373,8 +2370,8 @@ int serial8250_do_startup(struct uart_port *port)
if (up->dma) { if (up->dma) {
retval = serial8250_request_dma(up); retval = serial8250_request_dma(up);
if (retval) { if (retval) {
pr_warn_ratelimited("ttyS%d - failed to request DMA\n", pr_warn_ratelimited("%s - failed to request DMA\n",
serial_index(port)); port->name);
up->dma = NULL; up->dma = NULL;
} }
} }
...@@ -2498,11 +2495,11 @@ static unsigned int npcm_get_divisor(struct uart_8250_port *up, ...@@ -2498,11 +2495,11 @@ static unsigned int npcm_get_divisor(struct uart_8250_port *up,
return DIV_ROUND_CLOSEST(port->uartclk, 16 * baud + 2) - 2; return DIV_ROUND_CLOSEST(port->uartclk, 16 * baud + 2) - 2;
} }
static unsigned int serial8250_get_divisor(struct uart_8250_port *up, static unsigned int serial8250_do_get_divisor(struct uart_port *port,
unsigned int baud, unsigned int baud,
unsigned int *frac) unsigned int *frac)
{ {
struct uart_port *port = &up->port; struct uart_8250_port *up = up_to_u8250p(port);
unsigned int quot; unsigned int quot;
/* /*
...@@ -2532,6 +2529,16 @@ static unsigned int serial8250_get_divisor(struct uart_8250_port *up, ...@@ -2532,6 +2529,16 @@ static unsigned int serial8250_get_divisor(struct uart_8250_port *up,
return quot; return quot;
} }
static unsigned int serial8250_get_divisor(struct uart_port *port,
unsigned int baud,
unsigned int *frac)
{
if (port->get_divisor)
return port->get_divisor(port, baud, frac);
return serial8250_do_get_divisor(port, baud, frac);
}
static unsigned char serial8250_compute_lcr(struct uart_8250_port *up, static unsigned char serial8250_compute_lcr(struct uart_8250_port *up,
tcflag_t c_cflag) tcflag_t c_cflag)
{ {
...@@ -2570,7 +2577,7 @@ static unsigned char serial8250_compute_lcr(struct uart_8250_port *up, ...@@ -2570,7 +2577,7 @@ static unsigned char serial8250_compute_lcr(struct uart_8250_port *up,
return cval; return cval;
} }
static void serial8250_set_divisor(struct uart_port *port, unsigned int baud, void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud,
unsigned int quot, unsigned int quot_frac) unsigned int quot, unsigned int quot_frac)
{ {
struct uart_8250_port *up = up_to_u8250p(port); struct uart_8250_port *up = up_to_u8250p(port);
...@@ -2602,6 +2609,16 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud, ...@@ -2602,6 +2609,16 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
serial_port_out(port, 0x2, quot_frac); serial_port_out(port, 0x2, quot_frac);
} }
} }
EXPORT_SYMBOL_GPL(serial8250_do_set_divisor);
static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
unsigned int quot, unsigned int quot_frac)
{
if (port->set_divisor)
port->set_divisor(port, baud, quot, quot_frac);
else
serial8250_do_set_divisor(port, baud, quot, quot_frac);
}
static unsigned int serial8250_get_baud_rate(struct uart_port *port, static unsigned int serial8250_get_baud_rate(struct uart_port *port,
struct ktermios *termios, struct ktermios *termios,
...@@ -2636,7 +2653,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, ...@@ -2636,7 +2653,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
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);
quot = serial8250_get_divisor(up, baud, &frac); quot = serial8250_get_divisor(port, baud, &frac);
/* /*
* Ok, we're now changing the port state. Do it with * Ok, we're now changing the port state. Do it with
...@@ -3197,7 +3214,7 @@ static void serial8250_console_restore(struct uart_8250_port *up) ...@@ -3197,7 +3214,7 @@ static void serial8250_console_restore(struct uart_8250_port *up)
termios.c_cflag = port->state->port.tty->termios.c_cflag; termios.c_cflag = port->state->port.tty->termios.c_cflag;
baud = serial8250_get_baud_rate(port, &termios, NULL); baud = serial8250_get_baud_rate(port, &termios, NULL);
quot = serial8250_get_divisor(up, baud, &frac); quot = serial8250_get_divisor(port, baud, &frac);
serial8250_set_divisor(port, baud, quot, frac); serial8250_set_divisor(port, baud, quot, frac);
serial_port_out(port, UART_LCR, up->lcr); serial_port_out(port, UART_LCR, up->lcr);
......
...@@ -638,8 +638,10 @@ static int serial_config(struct pcmcia_device *link) ...@@ -638,8 +638,10 @@ static int serial_config(struct pcmcia_device *link)
(link->has_func_id) && (link->has_func_id) &&
(link->socket->pcmcia_pfc == 0) && (link->socket->pcmcia_pfc == 0) &&
((link->func_id == CISTPL_FUNCID_MULTI) || ((link->func_id == CISTPL_FUNCID_MULTI) ||
(link->func_id == CISTPL_FUNCID_SERIAL))) (link->func_id == CISTPL_FUNCID_SERIAL))) {
pcmcia_loop_config(link, serial_check_for_multi, info); if (pcmcia_loop_config(link, serial_check_for_multi, info))
goto failed;
}
/* /*
* Apply any multi-port quirk. * Apply any multi-port quirk.
......
...@@ -314,7 +314,8 @@ static u32 imx_uart_readl(struct imx_port *sport, u32 offset) ...@@ -314,7 +314,8 @@ static u32 imx_uart_readl(struct imx_port *sport, u32 offset)
/* /*
* UCR2_SRST is the only bit in the cached registers that might * UCR2_SRST is the only bit in the cached registers that might
* differ from the value that was last written. As it only * differ from the value that was last written. As it only
* clears after being set, reread conditionally. * automatically becomes one after being cleared, reread
* conditionally.
*/ */
if (!(sport->ucr2 & UCR2_SRST)) if (!(sport->ucr2 & UCR2_SRST))
sport->ucr2 = readl(sport->port.membase + offset); sport->ucr2 = readl(sport->port.membase + offset);
...@@ -1051,7 +1052,7 @@ static void imx_uart_dma_rx_callback(void *data) ...@@ -1051,7 +1052,7 @@ static void imx_uart_dma_rx_callback(void *data)
unsigned int r_bytes; unsigned int r_bytes;
unsigned int bd_size; unsigned int bd_size;
status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state); status = dmaengine_tx_status(chan, sport->rx_cookie, &state);
if (status == DMA_ERROR) { if (status == DMA_ERROR) {
imx_uart_clear_rx_errors(sport); imx_uart_clear_rx_errors(sport);
......
...@@ -430,7 +430,6 @@ int jsm_uart_port_init(struct jsm_board *brd) ...@@ -430,7 +430,6 @@ int jsm_uart_port_init(struct jsm_board *brd)
{ {
int i, rc; int i, rc;
unsigned int line; unsigned int line;
struct jsm_channel *ch;
if (!brd) if (!brd)
return -ENXIO; return -ENXIO;
...@@ -444,7 +443,7 @@ int jsm_uart_port_init(struct jsm_board *brd) ...@@ -444,7 +443,7 @@ int jsm_uart_port_init(struct jsm_board *brd)
brd->nasync = brd->maxports; brd->nasync = brd->maxports;
/* Set up channel variables */ /* Set up channel variables */
for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) { for (i = 0; i < brd->nasync; i++) {
if (!brd->channels[i]) if (!brd->channels[i])
continue; continue;
......
...@@ -531,8 +531,8 @@ static int max310x_update_best_err(unsigned long f, long *besterr) ...@@ -531,8 +531,8 @@ static int max310x_update_best_err(unsigned long f, long *besterr)
return 1; return 1;
} }
static int max310x_set_ref_clk(struct max310x_port *s, unsigned long freq, static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
bool xtal) unsigned long freq, bool xtal)
{ {
unsigned int div, clksrc, pllcfg = 0; unsigned int div, clksrc, pllcfg = 0;
long besterr = -1; long besterr = -1;
...@@ -588,8 +588,14 @@ static int max310x_set_ref_clk(struct max310x_port *s, unsigned long freq, ...@@ -588,8 +588,14 @@ static int max310x_set_ref_clk(struct max310x_port *s, unsigned long freq,
regmap_write(s->regmap, MAX310X_CLKSRC_REG, clksrc); regmap_write(s->regmap, MAX310X_CLKSRC_REG, clksrc);
/* Wait for crystal */ /* Wait for crystal */
if (pllcfg && xtal) if (xtal) {
unsigned int val;
msleep(10); msleep(10);
regmap_read(s->regmap, MAX310X_STS_IRQSTS_REG, &val);
if (!(val & MAX310X_STS_CLKREADY_BIT)) {
dev_warn(dev, "clock is not stable yet\n");
}
}
return (int)bestfreq; return (int)bestfreq;
} }
...@@ -1260,7 +1266,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, ...@@ -1260,7 +1266,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
MAX310X_MODE1_AUTOSLEEP_BIT); MAX310X_MODE1_AUTOSLEEP_BIT);
} }
uartclk = max310x_set_ref_clk(s, freq, xtal); uartclk = max310x_set_ref_clk(dev, s, freq, xtal);
dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk); dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk);
mutex_init(&s->mutex); mutex_init(&s->mutex);
......
...@@ -887,7 +887,8 @@ static int serial_pxa_probe(struct platform_device *dev) ...@@ -887,7 +887,8 @@ static int serial_pxa_probe(struct platform_device *dev)
goto err_clk; goto err_clk;
if (sport->port.line >= ARRAY_SIZE(serial_pxa_ports)) { if (sport->port.line >= ARRAY_SIZE(serial_pxa_ports)) {
dev_err(&dev->dev, "serial%d out of range\n", sport->port.line); dev_err(&dev->dev, "serial%d out of range\n", sport->port.line);
return -EINVAL; ret = -EINVAL;
goto err_clk;
} }
snprintf(sport->name, PXA_NAME_LEN - 1, "UART%d", sport->port.line + 1); snprintf(sport->name, PXA_NAME_LEN - 1, "UART%d", sport->port.line + 1);
......
This diff is collapsed.
...@@ -182,6 +182,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, ...@@ -182,6 +182,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
{ {
struct uart_port *uport = uart_port_check(state); struct uart_port *uport = uart_port_check(state);
unsigned long page; unsigned long page;
unsigned long flags = 0;
int retval = 0; int retval = 0;
if (uport->type == PORT_UNKNOWN) if (uport->type == PORT_UNKNOWN)
...@@ -196,15 +197,18 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, ...@@ -196,15 +197,18 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
* Initialise and allocate the transmit and temporary * Initialise and allocate the transmit and temporary
* buffer. * buffer.
*/ */
if (!state->xmit.buf) {
/* This is protected by the per port mutex */
page = get_zeroed_page(GFP_KERNEL); page = get_zeroed_page(GFP_KERNEL);
if (!page) if (!page)
return -ENOMEM; return -ENOMEM;
uart_port_lock(state, flags);
if (!state->xmit.buf) {
state->xmit.buf = (unsigned char *) page; state->xmit.buf = (unsigned char *) page;
uart_circ_clear(&state->xmit); uart_circ_clear(&state->xmit);
} else {
free_page(page);
} }
uart_port_unlock(uport, flags);
retval = uport->ops->startup(uport); retval = uport->ops->startup(uport);
if (retval == 0) { if (retval == 0) {
...@@ -263,6 +267,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) ...@@ -263,6 +267,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
{ {
struct uart_port *uport = uart_port_check(state); struct uart_port *uport = uart_port_check(state);
struct tty_port *port = &state->port; struct tty_port *port = &state->port;
unsigned long flags = 0;
/* /*
* Set the TTY IO error marker * Set the TTY IO error marker
...@@ -295,10 +300,12 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) ...@@ -295,10 +300,12 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
/* /*
* Free the transmit buffer page. * Free the transmit buffer page.
*/ */
uart_port_lock(state, flags);
if (state->xmit.buf) { if (state->xmit.buf) {
free_page((unsigned long)state->xmit.buf); free_page((unsigned long)state->xmit.buf);
state->xmit.buf = NULL; state->xmit.buf = NULL;
} }
uart_port_unlock(uport, flags);
} }
/** /**
......
This diff is collapsed.
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/clk.h>
#define ULITE_NAME "ttyUL" #define ULITE_NAME "ttyUL"
#define ULITE_MAJOR 204 #define ULITE_MAJOR 204
...@@ -54,6 +55,11 @@ ...@@ -54,6 +55,11 @@
#define ULITE_CONTROL_RST_RX 0x02 #define ULITE_CONTROL_RST_RX 0x02
#define ULITE_CONTROL_IE 0x10 #define ULITE_CONTROL_IE 0x10
struct uartlite_data {
const struct uartlite_reg_ops *reg_ops;
struct clk *clk;
};
struct uartlite_reg_ops { struct uartlite_reg_ops {
u32 (*in)(void __iomem *addr); u32 (*in)(void __iomem *addr);
void (*out)(u32 val, void __iomem *addr); void (*out)(u32 val, void __iomem *addr);
...@@ -91,16 +97,16 @@ static const struct uartlite_reg_ops uartlite_le = { ...@@ -91,16 +97,16 @@ static const struct uartlite_reg_ops uartlite_le = {
static inline u32 uart_in32(u32 offset, struct uart_port *port) static inline u32 uart_in32(u32 offset, struct uart_port *port)
{ {
const struct uartlite_reg_ops *reg_ops = port->private_data; struct uartlite_data *pdata = port->private_data;
return reg_ops->in(port->membase + offset); return pdata->reg_ops->in(port->membase + offset);
} }
static inline void uart_out32(u32 val, u32 offset, struct uart_port *port) static inline void uart_out32(u32 val, u32 offset, struct uart_port *port)
{ {
const struct uartlite_reg_ops *reg_ops = port->private_data; struct uartlite_data *pdata = port->private_data;
reg_ops->out(val, port->membase + offset); pdata->reg_ops->out(val, port->membase + offset);
} }
static struct uart_port ulite_ports[ULITE_NR_UARTS]; static struct uart_port ulite_ports[ULITE_NR_UARTS];
...@@ -257,8 +263,15 @@ static void ulite_break_ctl(struct uart_port *port, int ctl) ...@@ -257,8 +263,15 @@ static void ulite_break_ctl(struct uart_port *port, int ctl)
static int ulite_startup(struct uart_port *port) static int ulite_startup(struct uart_port *port)
{ {
struct uartlite_data *pdata = port->private_data;
int ret; int ret;
ret = clk_enable(pdata->clk);
if (ret) {
dev_err(port->dev, "Failed to enable clock\n");
return ret;
}
ret = request_irq(port->irq, ulite_isr, IRQF_SHARED | IRQF_TRIGGER_RISING, ret = request_irq(port->irq, ulite_isr, IRQF_SHARED | IRQF_TRIGGER_RISING,
"uartlite", port); "uartlite", port);
if (ret) if (ret)
...@@ -273,9 +286,12 @@ static int ulite_startup(struct uart_port *port) ...@@ -273,9 +286,12 @@ static int ulite_startup(struct uart_port *port)
static void ulite_shutdown(struct uart_port *port) static void ulite_shutdown(struct uart_port *port)
{ {
struct uartlite_data *pdata = port->private_data;
uart_out32(0, ULITE_CONTROL, port); uart_out32(0, ULITE_CONTROL, port);
uart_in32(ULITE_CONTROL, port); /* dummy */ uart_in32(ULITE_CONTROL, port); /* dummy */
free_irq(port->irq, port); free_irq(port->irq, port);
clk_disable(pdata->clk);
} }
static void ulite_set_termios(struct uart_port *port, struct ktermios *termios, static void ulite_set_termios(struct uart_port *port, struct ktermios *termios,
...@@ -325,6 +341,7 @@ static void ulite_release_port(struct uart_port *port) ...@@ -325,6 +341,7 @@ static void ulite_release_port(struct uart_port *port)
static int ulite_request_port(struct uart_port *port) static int ulite_request_port(struct uart_port *port)
{ {
struct uartlite_data *pdata = port->private_data;
int ret; int ret;
pr_debug("ulite console: port=%p; port->mapbase=%llx\n", pr_debug("ulite console: port=%p; port->mapbase=%llx\n",
...@@ -342,13 +359,13 @@ static int ulite_request_port(struct uart_port *port) ...@@ -342,13 +359,13 @@ static int ulite_request_port(struct uart_port *port)
return -EBUSY; return -EBUSY;
} }
port->private_data = (void *)&uartlite_be; pdata->reg_ops = &uartlite_be;
ret = uart_in32(ULITE_CONTROL, port); ret = uart_in32(ULITE_CONTROL, port);
uart_out32(ULITE_CONTROL_RST_TX, ULITE_CONTROL, port); uart_out32(ULITE_CONTROL_RST_TX, ULITE_CONTROL, port);
ret = uart_in32(ULITE_STATUS, port); ret = uart_in32(ULITE_STATUS, port);
/* Endianess detection */ /* Endianess detection */
if ((ret & ULITE_STATUS_TXEMPTY) != ULITE_STATUS_TXEMPTY) if ((ret & ULITE_STATUS_TXEMPTY) != ULITE_STATUS_TXEMPTY)
port->private_data = (void *)&uartlite_le; pdata->reg_ops = &uartlite_le;
return 0; return 0;
} }
...@@ -365,6 +382,17 @@ static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser) ...@@ -365,6 +382,17 @@ static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
return -EINVAL; return -EINVAL;
} }
static void ulite_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
struct uartlite_data *pdata = port->private_data;
if (!state)
clk_enable(pdata->clk);
else
clk_disable(pdata->clk);
}
#ifdef CONFIG_CONSOLE_POLL #ifdef CONFIG_CONSOLE_POLL
static int ulite_get_poll_char(struct uart_port *port) static int ulite_get_poll_char(struct uart_port *port)
{ {
...@@ -400,6 +428,7 @@ static const struct uart_ops ulite_ops = { ...@@ -400,6 +428,7 @@ static const struct uart_ops ulite_ops = {
.request_port = ulite_request_port, .request_port = ulite_request_port,
.config_port = ulite_config_port, .config_port = ulite_config_port,
.verify_port = ulite_verify_port, .verify_port = ulite_verify_port,
.pm = ulite_pm,
#ifdef CONFIG_CONSOLE_POLL #ifdef CONFIG_CONSOLE_POLL
.poll_get_char = ulite_get_poll_char, .poll_get_char = ulite_get_poll_char,
.poll_put_char = ulite_put_poll_char, .poll_put_char = ulite_put_poll_char,
...@@ -585,10 +614,12 @@ static struct uart_driver ulite_uart_driver = { ...@@ -585,10 +614,12 @@ static struct uart_driver ulite_uart_driver = {
* @id: requested id number. Pass -1 for automatic port assignment * @id: requested id number. Pass -1 for automatic port assignment
* @base: base address of uartlite registers * @base: base address of uartlite registers
* @irq: irq number for uartlite * @irq: irq number for uartlite
* @pdata: private data for uartlite
* *
* Returns: 0 on success, <0 otherwise * Returns: 0 on success, <0 otherwise
*/ */
static int ulite_assign(struct device *dev, int id, u32 base, int irq) static int ulite_assign(struct device *dev, int id, u32 base, int irq,
struct uartlite_data *pdata)
{ {
struct uart_port *port; struct uart_port *port;
int rc; int rc;
...@@ -625,6 +656,7 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq) ...@@ -625,6 +656,7 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq)
port->dev = dev; port->dev = dev;
port->type = PORT_UNKNOWN; port->type = PORT_UNKNOWN;
port->line = id; port->line = id;
port->private_data = pdata;
dev_set_drvdata(dev, port); dev_set_drvdata(dev, port);
...@@ -658,10 +690,44 @@ static int ulite_release(struct device *dev) ...@@ -658,10 +690,44 @@ static int ulite_release(struct device *dev)
return rc; return rc;
} }
/**
* ulite_suspend - Stop the device.
*
* @dev: handle to the device structure.
* Return: 0 always.
*/
static int __maybe_unused ulite_suspend(struct device *dev)
{
struct uart_port *port = dev_get_drvdata(dev);
if (port)
uart_suspend_port(&ulite_uart_driver, port);
return 0;
}
/**
* ulite_resume - Resume the device.
*
* @dev: handle to the device structure.
* Return: 0 on success, errno otherwise.
*/
static int __maybe_unused ulite_resume(struct device *dev)
{
struct uart_port *port = dev_get_drvdata(dev);
if (port)
uart_resume_port(&ulite_uart_driver, port);
return 0;
}
/* --------------------------------------------------------------------- /* ---------------------------------------------------------------------
* Platform bus binding * Platform bus binding
*/ */
static SIMPLE_DEV_PM_OPS(ulite_pm_ops, ulite_suspend, ulite_resume);
#if defined(CONFIG_OF) #if defined(CONFIG_OF)
/* Match table for of_platform binding */ /* Match table for of_platform binding */
static const struct of_device_id ulite_of_match[] = { static const struct of_device_id ulite_of_match[] = {
...@@ -675,7 +741,8 @@ MODULE_DEVICE_TABLE(of, ulite_of_match); ...@@ -675,7 +741,8 @@ MODULE_DEVICE_TABLE(of, ulite_of_match);
static int ulite_probe(struct platform_device *pdev) static int ulite_probe(struct platform_device *pdev)
{ {
struct resource *res; struct resource *res;
int irq; struct uartlite_data *pdata;
int irq, ret;
int id = pdev->id; int id = pdev->id;
#ifdef CONFIG_OF #ifdef CONFIG_OF
const __be32 *prop; const __be32 *prop;
...@@ -684,6 +751,10 @@ static int ulite_probe(struct platform_device *pdev) ...@@ -684,6 +751,10 @@ static int ulite_probe(struct platform_device *pdev)
if (prop) if (prop)
id = be32_to_cpup(prop); id = be32_to_cpup(prop);
#endif #endif
pdata = devm_kzalloc(&pdev->dev, sizeof(struct uartlite_data),
GFP_KERNEL);
if (!pdata)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) if (!res)
...@@ -693,11 +764,33 @@ static int ulite_probe(struct platform_device *pdev) ...@@ -693,11 +764,33 @@ static int ulite_probe(struct platform_device *pdev)
if (irq <= 0) if (irq <= 0)
return -ENXIO; return -ENXIO;
return ulite_assign(&pdev->dev, id, res->start, irq); pdata->clk = devm_clk_get(&pdev->dev, "s_axi_aclk");
if (IS_ERR(pdata->clk)) {
if (PTR_ERR(pdata->clk) != -ENOENT)
return PTR_ERR(pdata->clk);
/*
* Clock framework support is optional, continue on
* anyways if we don't find a matching clock.
*/
pdata->clk = NULL;
}
ret = clk_prepare(pdata->clk);
if (ret) {
dev_err(&pdev->dev, "Failed to prepare clock\n");
return ret;
}
return ulite_assign(&pdev->dev, id, res->start, irq, pdata);
} }
static int ulite_remove(struct platform_device *pdev) static int ulite_remove(struct platform_device *pdev)
{ {
struct uart_port *port = dev_get_drvdata(&pdev->dev);
struct uartlite_data *pdata = port->private_data;
clk_disable_unprepare(pdata->clk);
return ulite_release(&pdev->dev); return ulite_release(&pdev->dev);
} }
...@@ -710,6 +803,7 @@ static struct platform_driver ulite_platform_driver = { ...@@ -710,6 +803,7 @@ static struct platform_driver ulite_platform_driver = {
.driver = { .driver = {
.name = "uartlite", .name = "uartlite",
.of_match_table = of_match_ptr(ulite_of_match), .of_match_table = of_match_ptr(ulite_of_match),
.pm = &ulite_pm_ops,
}, },
}; };
......
...@@ -167,6 +167,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); ...@@ -167,6 +167,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
#define CDNS_UART_SR_TXEMPTY 0x00000008 /* TX FIFO empty */ #define CDNS_UART_SR_TXEMPTY 0x00000008 /* TX FIFO empty */
#define CDNS_UART_SR_TXFULL 0x00000010 /* TX FIFO full */ #define CDNS_UART_SR_TXFULL 0x00000010 /* TX FIFO full */
#define CDNS_UART_SR_RXTRIG 0x00000001 /* Rx Trigger */ #define CDNS_UART_SR_RXTRIG 0x00000001 /* Rx Trigger */
#define CDNS_UART_SR_TACTIVE 0x00000800 /* TX state machine active */
/* baud dividers min/max values */ /* baud dividers min/max values */
#define CDNS_UART_BDIV_MIN 4 #define CDNS_UART_BDIV_MIN 4
...@@ -829,7 +830,7 @@ static int cdns_uart_startup(struct uart_port *port) ...@@ -829,7 +830,7 @@ static int cdns_uart_startup(struct uart_port *port)
* the receiver. * the receiver.
*/ */
status = readl(port->membase + CDNS_UART_CR); status = readl(port->membase + CDNS_UART_CR);
status &= CDNS_UART_CR_RX_DIS; status &= ~CDNS_UART_CR_RX_DIS;
status |= CDNS_UART_CR_RX_EN; status |= CDNS_UART_CR_RX_EN;
writel(status, port->membase + CDNS_UART_CR); writel(status, port->membase + CDNS_UART_CR);
...@@ -1098,16 +1099,6 @@ static const struct uart_ops cdns_uart_ops = { ...@@ -1098,16 +1099,6 @@ static const struct uart_ops cdns_uart_ops = {
}; };
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
/**
* cdns_uart_console_wait_tx - Wait for the TX to be full
* @port: Handle to the uart port structure
*/
static void cdns_uart_console_wait_tx(struct uart_port *port)
{
while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY))
barrier();
}
/** /**
* cdns_uart_console_putchar - write the character to the FIFO buffer * cdns_uart_console_putchar - write the character to the FIFO buffer
* @port: Handle to the uart port structure * @port: Handle to the uart port structure
...@@ -1115,7 +1106,8 @@ static void cdns_uart_console_wait_tx(struct uart_port *port) ...@@ -1115,7 +1106,8 @@ static void cdns_uart_console_wait_tx(struct uart_port *port)
*/ */
static void cdns_uart_console_putchar(struct uart_port *port, int ch) static void cdns_uart_console_putchar(struct uart_port *port, int ch)
{ {
cdns_uart_console_wait_tx(port); while (readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)
cpu_relax();
writel(ch, port->membase + CDNS_UART_FIFO); writel(ch, port->membase + CDNS_UART_FIFO);
} }
...@@ -1206,9 +1198,10 @@ static void cdns_uart_console_write(struct console *co, const char *s, ...@@ -1206,9 +1198,10 @@ static void cdns_uart_console_write(struct console *co, const char *s,
writel(ctrl, port->membase + CDNS_UART_CR); writel(ctrl, port->membase + CDNS_UART_CR);
uart_console_write(port, s, count, cdns_uart_console_putchar); uart_console_write(port, s, count, cdns_uart_console_putchar);
cdns_uart_console_wait_tx(port); while ((readl(port->membase + CDNS_UART_SR) &
(CDNS_UART_SR_TXEMPTY | CDNS_UART_SR_TACTIVE)) !=
writel(ctrl, port->membase + CDNS_UART_CR); CDNS_UART_SR_TXEMPTY)
cpu_relax();
/* restore interrupt state */ /* restore interrupt state */
writel(imr, port->membase + CDNS_UART_IER); writel(imr, port->membase + CDNS_UART_IER);
......
...@@ -100,11 +100,11 @@ speed_t tty_termios_input_baud_rate(struct ktermios *termios) ...@@ -100,11 +100,11 @@ speed_t tty_termios_input_baud_rate(struct ktermios *termios)
if (cbaud == B0) if (cbaud == B0)
return tty_termios_baud_rate(termios); return tty_termios_baud_rate(termios);
#ifdef BOTHER
/* Magic token for arbitrary speed via c_ispeed*/ /* Magic token for arbitrary speed via c_ispeed*/
if (cbaud == BOTHER) if (cbaud == BOTHER)
return termios->c_ispeed; return termios->c_ispeed;
#endif
if (cbaud & CBAUDEX) { if (cbaud & CBAUDEX) {
cbaud &= ~CBAUDEX; cbaud &= ~CBAUDEX;
...@@ -114,9 +114,9 @@ speed_t tty_termios_input_baud_rate(struct ktermios *termios) ...@@ -114,9 +114,9 @@ speed_t tty_termios_input_baud_rate(struct ktermios *termios)
cbaud += 15; cbaud += 15;
} }
return baud_table[cbaud]; return baud_table[cbaud];
#else #else /* IBSHIFT */
return tty_termios_baud_rate(termios); return tty_termios_baud_rate(termios);
#endif #endif /* IBSHIFT */
} }
EXPORT_SYMBOL(tty_termios_input_baud_rate); EXPORT_SYMBOL(tty_termios_input_baud_rate);
...@@ -156,19 +156,27 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, ...@@ -156,19 +156,27 @@ void tty_termios_encode_baud_rate(struct ktermios *termios,
termios->c_ispeed = ibaud; termios->c_ispeed = ibaud;
termios->c_ospeed = obaud; termios->c_ospeed = obaud;
#ifdef IBSHIFT
if ((termios->c_cflag >> IBSHIFT) & CBAUD)
ibinput = 1; /* An input speed was specified */
#endif
#ifdef BOTHER #ifdef BOTHER
/* If the user asked for a precise weird speed give a precise weird /* If the user asked for a precise weird speed give a precise weird
answer. If they asked for a Bfoo speed they may have problems answer. If they asked for a Bfoo speed they may have problems
digesting non-exact replies so fuzz a bit */ digesting non-exact replies so fuzz a bit */
if ((termios->c_cflag & CBAUD) == BOTHER) if ((termios->c_cflag & CBAUD) == BOTHER) {
oclose = 0; oclose = 0;
if (!ibinput)
iclose = 0;
}
if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER) if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
iclose = 0; iclose = 0;
if ((termios->c_cflag >> IBSHIFT) & CBAUD)
ibinput = 1; /* An input speed was specified */
#endif #endif
termios->c_cflag &= ~CBAUD; termios->c_cflag &= ~CBAUD;
#ifdef IBSHIFT
termios->c_cflag &= ~(CBAUD << IBSHIFT);
#endif
/* /*
* Our goal is to find a close match to the standard baud rate * Our goal is to find a close match to the standard baud rate
......
...@@ -814,9 +814,9 @@ void start_tty(struct tty_struct *tty) ...@@ -814,9 +814,9 @@ void start_tty(struct tty_struct *tty)
} }
EXPORT_SYMBOL(start_tty); EXPORT_SYMBOL(start_tty);
static void tty_update_time(struct timespec *time) static void tty_update_time(struct timespec64 *time)
{ {
unsigned long sec = get_seconds(); time64_t sec = ktime_get_real_seconds();
/* /*
* We only care if the two values differ in anything other than the * We only care if the two values differ in anything other than the
...@@ -867,13 +867,8 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count, ...@@ -867,13 +867,8 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
i = -EIO; i = -EIO;
tty_ldisc_deref(ld); tty_ldisc_deref(ld);
if (i > 0) { if (i > 0)
struct timespec ts; tty_update_time(&inode->i_atime);
ts = timespec64_to_timespec(inode->i_atime);
tty_update_time(&ts);
inode->i_atime = timespec_to_timespec64(ts);
}
return i; return i;
} }
...@@ -974,11 +969,7 @@ static inline ssize_t do_tty_write( ...@@ -974,11 +969,7 @@ static inline ssize_t do_tty_write(
cond_resched(); cond_resched();
} }
if (written) { if (written) {
struct timespec ts; tty_update_time(&file_inode(file)->i_mtime);
ts = timespec64_to_timespec(file_inode(file)->i_mtime);
tty_update_time(&ts);
file_inode(file)->i_mtime = timespec_to_timespec64(ts);
ret = written; ret = written;
} }
out: out:
......
...@@ -74,28 +74,6 @@ struct ldsem_waiter { ...@@ -74,28 +74,6 @@ struct ldsem_waiter {
struct task_struct *task; struct task_struct *task;
}; };
static inline long ldsem_atomic_update(long delta, struct ld_semaphore *sem)
{
return atomic_long_add_return(delta, (atomic_long_t *)&sem->count);
}
/*
* ldsem_cmpxchg() updates @*old with the last-known sem->count value.
* Returns 1 if count was successfully changed; @*old will have @new value.
* Returns 0 if count was not changed; @*old will have most recent sem->count
*/
static inline int ldsem_cmpxchg(long *old, long new, struct ld_semaphore *sem)
{
long tmp = atomic_long_cmpxchg(&sem->count, *old, new);
if (tmp == *old) {
*old = new;
return 1;
} else {
*old = tmp;
return 0;
}
}
/* /*
* Initialize an ldsem: * Initialize an ldsem:
*/ */
...@@ -109,7 +87,7 @@ void __init_ldsem(struct ld_semaphore *sem, const char *name, ...@@ -109,7 +87,7 @@ void __init_ldsem(struct ld_semaphore *sem, const char *name,
debug_check_no_locks_freed((void *)sem, sizeof(*sem)); debug_check_no_locks_freed((void *)sem, sizeof(*sem));
lockdep_init_map(&sem->dep_map, name, key, 0); lockdep_init_map(&sem->dep_map, name, key, 0);
#endif #endif
sem->count = LDSEM_UNLOCKED; atomic_long_set(&sem->count, LDSEM_UNLOCKED);
sem->wait_readers = 0; sem->wait_readers = 0;
raw_spin_lock_init(&sem->wait_lock); raw_spin_lock_init(&sem->wait_lock);
INIT_LIST_HEAD(&sem->read_wait); INIT_LIST_HEAD(&sem->read_wait);
...@@ -122,16 +100,17 @@ static void __ldsem_wake_readers(struct ld_semaphore *sem) ...@@ -122,16 +100,17 @@ static void __ldsem_wake_readers(struct ld_semaphore *sem)
struct task_struct *tsk; struct task_struct *tsk;
long adjust, count; long adjust, count;
/* Try to grant read locks to all readers on the read wait list. /*
* Try to grant read locks to all readers on the read wait list.
* Note the 'active part' of the count is incremented by * Note the 'active part' of the count is incremented by
* the number of readers before waking any processes up. * the number of readers before waking any processes up.
*/ */
adjust = sem->wait_readers * (LDSEM_ACTIVE_BIAS - LDSEM_WAIT_BIAS); adjust = sem->wait_readers * (LDSEM_ACTIVE_BIAS - LDSEM_WAIT_BIAS);
count = ldsem_atomic_update(adjust, sem); count = atomic_long_add_return(adjust, &sem->count);
do { do {
if (count > 0) if (count > 0)
break; break;
if (ldsem_cmpxchg(&count, count - adjust, sem)) if (atomic_long_try_cmpxchg(&sem->count, &count, count - adjust))
return; return;
} while (1); } while (1);
...@@ -148,14 +127,15 @@ static void __ldsem_wake_readers(struct ld_semaphore *sem) ...@@ -148,14 +127,15 @@ static void __ldsem_wake_readers(struct ld_semaphore *sem)
static inline int writer_trylock(struct ld_semaphore *sem) static inline int writer_trylock(struct ld_semaphore *sem)
{ {
/* only wake this writer if the active part of the count can be /*
* Only wake this writer if the active part of the count can be
* transitioned from 0 -> 1 * transitioned from 0 -> 1
*/ */
long count = ldsem_atomic_update(LDSEM_ACTIVE_BIAS, sem); long count = atomic_long_add_return(LDSEM_ACTIVE_BIAS, &sem->count);
do { do {
if ((count & LDSEM_ACTIVE_MASK) == LDSEM_ACTIVE_BIAS) if ((count & LDSEM_ACTIVE_MASK) == LDSEM_ACTIVE_BIAS)
return 1; return 1;
if (ldsem_cmpxchg(&count, count - LDSEM_ACTIVE_BIAS, sem)) if (atomic_long_try_cmpxchg(&sem->count, &count, count - LDSEM_ACTIVE_BIAS))
return 0; return 0;
} while (1); } while (1);
} }
...@@ -205,12 +185,16 @@ down_read_failed(struct ld_semaphore *sem, long count, long timeout) ...@@ -205,12 +185,16 @@ down_read_failed(struct ld_semaphore *sem, long count, long timeout)
/* set up my own style of waitqueue */ /* set up my own style of waitqueue */
raw_spin_lock_irq(&sem->wait_lock); raw_spin_lock_irq(&sem->wait_lock);
/* Try to reverse the lock attempt but if the count has changed /*
* Try to reverse the lock attempt but if the count has changed
* so that reversing fails, check if there are are no waiters, * so that reversing fails, check if there are are no waiters,
* and early-out if not */ * and early-out if not
*/
do { do {
if (ldsem_cmpxchg(&count, count + adjust, sem)) if (atomic_long_try_cmpxchg(&sem->count, &count, count + adjust)) {
count += adjust;
break; break;
}
if (count > 0) { if (count > 0) {
raw_spin_unlock_irq(&sem->wait_lock); raw_spin_unlock_irq(&sem->wait_lock);
return sem; return sem;
...@@ -243,12 +227,14 @@ down_read_failed(struct ld_semaphore *sem, long count, long timeout) ...@@ -243,12 +227,14 @@ down_read_failed(struct ld_semaphore *sem, long count, long timeout)
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
if (!timeout) { if (!timeout) {
/* lock timed out but check if this task was just /*
* Lock timed out but check if this task was just
* granted lock ownership - if so, pretend there * granted lock ownership - if so, pretend there
* was no timeout; otherwise, cleanup lock wait */ * was no timeout; otherwise, cleanup lock wait.
*/
raw_spin_lock_irq(&sem->wait_lock); raw_spin_lock_irq(&sem->wait_lock);
if (waiter.task) { if (waiter.task) {
ldsem_atomic_update(-LDSEM_WAIT_BIAS, sem); atomic_long_add_return(-LDSEM_WAIT_BIAS, &sem->count);
list_del(&waiter.list); list_del(&waiter.list);
raw_spin_unlock_irq(&sem->wait_lock); raw_spin_unlock_irq(&sem->wait_lock);
put_task_struct(waiter.task); put_task_struct(waiter.task);
...@@ -273,11 +259,13 @@ down_write_failed(struct ld_semaphore *sem, long count, long timeout) ...@@ -273,11 +259,13 @@ down_write_failed(struct ld_semaphore *sem, long count, long timeout)
/* set up my own style of waitqueue */ /* set up my own style of waitqueue */
raw_spin_lock_irq(&sem->wait_lock); raw_spin_lock_irq(&sem->wait_lock);
/* Try to reverse the lock attempt but if the count has changed /*
* Try to reverse the lock attempt but if the count has changed
* so that reversing fails, check if the lock is now owned, * so that reversing fails, check if the lock is now owned,
* and early-out if so */ * and early-out if so.
*/
do { do {
if (ldsem_cmpxchg(&count, count + adjust, sem)) if (atomic_long_try_cmpxchg(&sem->count, &count, count + adjust))
break; break;
if ((count & LDSEM_ACTIVE_MASK) == LDSEM_ACTIVE_BIAS) { if ((count & LDSEM_ACTIVE_MASK) == LDSEM_ACTIVE_BIAS) {
raw_spin_unlock_irq(&sem->wait_lock); raw_spin_unlock_irq(&sem->wait_lock);
...@@ -303,7 +291,7 @@ down_write_failed(struct ld_semaphore *sem, long count, long timeout) ...@@ -303,7 +291,7 @@ down_write_failed(struct ld_semaphore *sem, long count, long timeout)
} }
if (!locked) if (!locked)
ldsem_atomic_update(-LDSEM_WAIT_BIAS, sem); atomic_long_add_return(-LDSEM_WAIT_BIAS, &sem->count);
list_del(&waiter.list); list_del(&waiter.list);
raw_spin_unlock_irq(&sem->wait_lock); raw_spin_unlock_irq(&sem->wait_lock);
...@@ -324,7 +312,7 @@ static int __ldsem_down_read_nested(struct ld_semaphore *sem, ...@@ -324,7 +312,7 @@ static int __ldsem_down_read_nested(struct ld_semaphore *sem,
lockdep_acquire_read(sem, subclass, 0, _RET_IP_); lockdep_acquire_read(sem, subclass, 0, _RET_IP_);
count = ldsem_atomic_update(LDSEM_READ_BIAS, sem); count = atomic_long_add_return(LDSEM_READ_BIAS, &sem->count);
if (count <= 0) { if (count <= 0) {
lock_stat(sem, contended); lock_stat(sem, contended);
if (!down_read_failed(sem, count, timeout)) { if (!down_read_failed(sem, count, timeout)) {
...@@ -343,7 +331,7 @@ static int __ldsem_down_write_nested(struct ld_semaphore *sem, ...@@ -343,7 +331,7 @@ static int __ldsem_down_write_nested(struct ld_semaphore *sem,
lockdep_acquire(sem, subclass, 0, _RET_IP_); lockdep_acquire(sem, subclass, 0, _RET_IP_);
count = ldsem_atomic_update(LDSEM_WRITE_BIAS, sem); count = atomic_long_add_return(LDSEM_WRITE_BIAS, &sem->count);
if ((count & LDSEM_ACTIVE_MASK) != LDSEM_ACTIVE_BIAS) { if ((count & LDSEM_ACTIVE_MASK) != LDSEM_ACTIVE_BIAS) {
lock_stat(sem, contended); lock_stat(sem, contended);
if (!down_write_failed(sem, count, timeout)) { if (!down_write_failed(sem, count, timeout)) {
...@@ -370,10 +358,10 @@ int __sched ldsem_down_read(struct ld_semaphore *sem, long timeout) ...@@ -370,10 +358,10 @@ int __sched ldsem_down_read(struct ld_semaphore *sem, long timeout)
*/ */
int ldsem_down_read_trylock(struct ld_semaphore *sem) int ldsem_down_read_trylock(struct ld_semaphore *sem)
{ {
long count = sem->count; long count = atomic_long_read(&sem->count);
while (count >= 0) { while (count >= 0) {
if (ldsem_cmpxchg(&count, count + LDSEM_READ_BIAS, sem)) { if (atomic_long_try_cmpxchg(&sem->count, &count, count + LDSEM_READ_BIAS)) {
lockdep_acquire_read(sem, 0, 1, _RET_IP_); lockdep_acquire_read(sem, 0, 1, _RET_IP_);
lock_stat(sem, acquired); lock_stat(sem, acquired);
return 1; return 1;
...@@ -396,10 +384,10 @@ int __sched ldsem_down_write(struct ld_semaphore *sem, long timeout) ...@@ -396,10 +384,10 @@ int __sched ldsem_down_write(struct ld_semaphore *sem, long timeout)
*/ */
int ldsem_down_write_trylock(struct ld_semaphore *sem) int ldsem_down_write_trylock(struct ld_semaphore *sem)
{ {
long count = sem->count; long count = atomic_long_read(&sem->count);
while ((count & LDSEM_ACTIVE_MASK) == 0) { while ((count & LDSEM_ACTIVE_MASK) == 0) {
if (ldsem_cmpxchg(&count, count + LDSEM_WRITE_BIAS, sem)) { if (atomic_long_try_cmpxchg(&sem->count, &count, count + LDSEM_WRITE_BIAS)) {
lockdep_acquire(sem, 0, 1, _RET_IP_); lockdep_acquire(sem, 0, 1, _RET_IP_);
lock_stat(sem, acquired); lock_stat(sem, acquired);
return 1; return 1;
...@@ -417,7 +405,7 @@ void ldsem_up_read(struct ld_semaphore *sem) ...@@ -417,7 +405,7 @@ void ldsem_up_read(struct ld_semaphore *sem)
lockdep_release(sem, 1, _RET_IP_); lockdep_release(sem, 1, _RET_IP_);
count = ldsem_atomic_update(-LDSEM_READ_BIAS, sem); count = atomic_long_add_return(-LDSEM_READ_BIAS, &sem->count);
if (count < 0 && (count & LDSEM_ACTIVE_MASK) == 0) if (count < 0 && (count & LDSEM_ACTIVE_MASK) == 0)
ldsem_wake(sem); ldsem_wake(sem);
} }
...@@ -431,7 +419,7 @@ void ldsem_up_write(struct ld_semaphore *sem) ...@@ -431,7 +419,7 @@ void ldsem_up_write(struct ld_semaphore *sem)
lockdep_release(sem, 1, _RET_IP_); lockdep_release(sem, 1, _RET_IP_);
count = ldsem_atomic_update(-LDSEM_WRITE_BIAS, sem); count = atomic_long_add_return(-LDSEM_WRITE_BIAS, &sem->count);
if (count < 0) if (count < 0)
ldsem_wake(sem); ldsem_wake(sem);
} }
......
...@@ -690,7 +690,35 @@ static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag) ...@@ -690,7 +690,35 @@ static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag)
*/ */
static void k_dead(struct vc_data *vc, unsigned char value, char up_flag) static void k_dead(struct vc_data *vc, unsigned char value, char up_flag)
{ {
static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; static const unsigned char ret_diacr[NR_DEAD] = {
'`', /* dead_grave */
'\'', /* dead_acute */
'^', /* dead_circumflex */
'~', /* dead_tilda */
'"', /* dead_diaeresis */
',', /* dead_cedilla */
'_', /* dead_macron */
'U', /* dead_breve */
'.', /* dead_abovedot */
'*', /* dead_abovering */
'=', /* dead_doubleacute */
'c', /* dead_caron */
'k', /* dead_ogonek */
'i', /* dead_iota */
'#', /* dead_voiced_sound */
'o', /* dead_semivoiced_sound */
'!', /* dead_belowdot */
'?', /* dead_hook */
'+', /* dead_horn */
'-', /* dead_stroke */
')', /* dead_abovecomma */
'(', /* dead_abovereversedcomma */
':', /* dead_doublegrave */
'n', /* dead_invertedbreve */
';', /* dead_belowcomma */
'$', /* dead_currency */
'@', /* dead_greek */
};
k_deadunicode(vc, ret_diacr[value], up_flag); k_deadunicode(vc, ret_diacr[value], up_flag);
} }
......
...@@ -57,11 +57,13 @@ static inline void highlight_pointer(const int where) ...@@ -57,11 +57,13 @@ static inline void highlight_pointer(const int where)
complement_pos(sel_cons, where); complement_pos(sel_cons, where);
} }
static u16 static u32
sel_pos(int n) sel_pos(int n)
{ {
if (use_unicode)
return screen_glyph_unicode(sel_cons, n / 2);
return inverse_translate(sel_cons, screen_glyph(sel_cons, n), return inverse_translate(sel_cons, screen_glyph(sel_cons, n),
use_unicode); 0);
} }
/** /**
...@@ -90,7 +92,8 @@ static u32 inwordLut[]={ ...@@ -90,7 +92,8 @@ static u32 inwordLut[]={
0x07FFFFFE, /* lowercase */ 0x07FFFFFE, /* lowercase */
}; };
static inline int inword(const u16 c) { static inline int inword(const u32 c)
{
return c > 0x7f || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1); return c > 0x7f || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1);
} }
...@@ -116,14 +119,8 @@ static inline int atedge(const int p, int size_row) ...@@ -116,14 +119,8 @@ static inline int atedge(const int p, int size_row)
return (!(p % size_row) || !((p + 2) % size_row)); return (!(p % size_row) || !((p + 2) % size_row));
} }
/* constrain v such that v <= u */ /* stores the char in UTF8 and returns the number of bytes used (1-4) */
static inline unsigned short limit(const unsigned short v, const unsigned short u) static int store_utf8(u32 c, char *p)
{
return (v > u) ? u : v;
}
/* stores the char in UTF8 and returns the number of bytes used (1-3) */
static int store_utf8(u16 c, char *p)
{ {
if (c < 0x80) { if (c < 0x80) {
/* 0******* */ /* 0******* */
...@@ -134,12 +131,25 @@ static int store_utf8(u16 c, char *p) ...@@ -134,12 +131,25 @@ static int store_utf8(u16 c, char *p)
p[0] = 0xc0 | (c >> 6); p[0] = 0xc0 | (c >> 6);
p[1] = 0x80 | (c & 0x3f); p[1] = 0x80 | (c & 0x3f);
return 2; return 2;
} else { } else if (c < 0x10000) {
/* 1110**** 10****** 10****** */ /* 1110**** 10****** 10****** */
p[0] = 0xe0 | (c >> 12); p[0] = 0xe0 | (c >> 12);
p[1] = 0x80 | ((c >> 6) & 0x3f); p[1] = 0x80 | ((c >> 6) & 0x3f);
p[2] = 0x80 | (c & 0x3f); p[2] = 0x80 | (c & 0x3f);
return 3; return 3;
} else if (c < 0x110000) {
/* 11110*** 10****** 10****** 10****** */
p[0] = 0xf0 | (c >> 18);
p[1] = 0x80 | ((c >> 12) & 0x3f);
p[2] = 0x80 | ((c >> 6) & 0x3f);
p[3] = 0x80 | (c & 0x3f);
return 4;
} else {
/* outside Unicode, replace with U+FFFD */
p[0] = 0xef;
p[1] = 0xbf;
p[2] = 0xbd;
return 3;
} }
} }
...@@ -160,17 +170,17 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t ...@@ -160,17 +170,17 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t
struct tiocl_selection v; struct tiocl_selection v;
char *bp, *obp; char *bp, *obp;
int i, ps, pe, multiplier; int i, ps, pe, multiplier;
u16 c; u32 c;
int mode; int mode;
poke_blanked_console(); poke_blanked_console();
if (copy_from_user(&v, sel, sizeof(*sel))) if (copy_from_user(&v, sel, sizeof(*sel)))
return -EFAULT; return -EFAULT;
v.xs = limit(v.xs - 1, vc->vc_cols - 1); v.xs = min_t(u16, v.xs - 1, vc->vc_cols - 1);
v.ys = limit(v.ys - 1, vc->vc_rows - 1); v.ys = min_t(u16, v.ys - 1, vc->vc_rows - 1);
v.xe = limit(v.xe - 1, vc->vc_cols - 1); v.xe = min_t(u16, v.xe - 1, vc->vc_cols - 1);
v.ye = limit(v.ye - 1, vc->vc_rows - 1); v.ye = min_t(u16, v.ye - 1, vc->vc_rows - 1);
ps = v.ys * vc->vc_size_row + (v.xs << 1); ps = v.ys * vc->vc_size_row + (v.xs << 1);
pe = v.ye * vc->vc_size_row + (v.xe << 1); pe = v.ye * vc->vc_size_row + (v.xe << 1);
...@@ -279,7 +289,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t ...@@ -279,7 +289,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t
sel_end = new_sel_end; sel_end = new_sel_end;
/* Allocate a new buffer before freeing the old one ... */ /* Allocate a new buffer before freeing the old one ... */
multiplier = use_unicode ? 3 : 1; /* chars can take up to 3 bytes */ multiplier = use_unicode ? 4 : 1; /* chars can take up to 4 bytes */
bp = kmalloc_array((sel_end - sel_start) / 2 + 1, multiplier, bp = kmalloc_array((sel_end - sel_start) / 2 + 1, multiplier,
GFP_KERNEL); GFP_KERNEL);
if (!bp) { if (!bp) {
......
...@@ -10,6 +10,12 @@ ...@@ -10,6 +10,12 @@
* Attribute/character pair is in native endianity. * Attribute/character pair is in native endianity.
* [minor: N+128] * [minor: N+128]
* *
* /dev/vcsuN: similar to /dev/vcsaN but using 4-byte unicode values
* instead of 1-byte screen glyph values.
* [minor: N+64]
*
* /dev/vcsuaN: same idea as /dev/vcsaN for unicode (not yet implemented).
*
* This replaces screendump and part of selection, so that the system * This replaces screendump and part of selection, so that the system
* administrator can control access using file system permissions. * administrator can control access using file system permissions.
* *
...@@ -51,6 +57,26 @@ ...@@ -51,6 +57,26 @@
#define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE) #define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE)
/*
* Our minor space:
*
* 0 ... 63 glyph mode without attributes
* 64 ... 127 unicode mode without attributes
* 128 ... 191 glyph mode with attributes
* 192 ... 255 unused (reserved for unicode with attributes)
*
* This relies on MAX_NR_CONSOLES being <= 63, meaning 63 actual consoles
* with minors 0, 64, 128 and 192 being proxies for the foreground console.
*/
#if MAX_NR_CONSOLES > 63
#warning "/dev/vcs* devices may not accommodate more than 63 consoles"
#endif
#define console(inode) (iminor(inode) & 63)
#define use_unicode(inode) (iminor(inode) & 64)
#define use_attributes(inode) (iminor(inode) & 128)
struct vcs_poll_data { struct vcs_poll_data {
struct notifier_block notifier; struct notifier_block notifier;
unsigned int cons_num; unsigned int cons_num;
...@@ -102,7 +128,7 @@ vcs_poll_data_get(struct file *file) ...@@ -102,7 +128,7 @@ vcs_poll_data_get(struct file *file)
poll = kzalloc(sizeof(*poll), GFP_KERNEL); poll = kzalloc(sizeof(*poll), GFP_KERNEL);
if (!poll) if (!poll)
return NULL; return NULL;
poll->cons_num = iminor(file_inode(file)) & 127; poll->cons_num = console(file_inode(file));
init_waitqueue_head(&poll->waitq); init_waitqueue_head(&poll->waitq);
poll->notifier.notifier_call = vcs_notifier; poll->notifier.notifier_call = vcs_notifier;
if (register_vt_notifier(&poll->notifier) != 0) { if (register_vt_notifier(&poll->notifier) != 0) {
...@@ -140,7 +166,7 @@ vcs_poll_data_get(struct file *file) ...@@ -140,7 +166,7 @@ vcs_poll_data_get(struct file *file)
static struct vc_data* static struct vc_data*
vcs_vc(struct inode *inode, int *viewed) vcs_vc(struct inode *inode, int *viewed)
{ {
unsigned int currcons = iminor(inode) & 127; unsigned int currcons = console(inode);
WARN_CONSOLE_UNLOCKED(); WARN_CONSOLE_UNLOCKED();
...@@ -164,7 +190,6 @@ static int ...@@ -164,7 +190,6 @@ static int
vcs_size(struct inode *inode) vcs_size(struct inode *inode)
{ {
int size; int size;
int minor = iminor(inode);
struct vc_data *vc; struct vc_data *vc;
WARN_CONSOLE_UNLOCKED(); WARN_CONSOLE_UNLOCKED();
...@@ -175,8 +200,12 @@ vcs_size(struct inode *inode) ...@@ -175,8 +200,12 @@ vcs_size(struct inode *inode)
size = vc->vc_rows * vc->vc_cols; size = vc->vc_rows * vc->vc_cols;
if (minor & 128) if (use_attributes(inode)) {
if (use_unicode(inode))
return -EOPNOTSUPP;
size = 2*size + HEADER_SIZE; size = 2*size + HEADER_SIZE;
} else if (use_unicode(inode))
size *= 4;
return size; return size;
} }
...@@ -197,12 +226,10 @@ static ssize_t ...@@ -197,12 +226,10 @@ static ssize_t
vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{ {
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
unsigned int currcons = iminor(inode);
struct vc_data *vc; struct vc_data *vc;
struct vcs_poll_data *poll; struct vcs_poll_data *poll;
long pos; long pos, read;
long attr, read; int attr, uni_mode, row, col, maxcol, viewed;
int col, maxcol, viewed;
unsigned short *org = NULL; unsigned short *org = NULL;
ssize_t ret; ssize_t ret;
char *con_buf; char *con_buf;
...@@ -218,7 +245,8 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) ...@@ -218,7 +245,8 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
*/ */
console_lock(); console_lock();
attr = (currcons & 128); uni_mode = use_unicode(inode);
attr = use_attributes(inode);
ret = -ENXIO; ret = -ENXIO;
vc = vcs_vc(inode, &viewed); vc = vcs_vc(inode, &viewed);
if (!vc) if (!vc)
...@@ -227,6 +255,10 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) ...@@ -227,6 +255,10 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
ret = -EINVAL; ret = -EINVAL;
if (pos < 0) if (pos < 0)
goto unlock_out; goto unlock_out;
/* we enforce 32-bit alignment for pos and count in unicode mode */
if (uni_mode && (pos | count) & 3)
goto unlock_out;
poll = file->private_data; poll = file->private_data;
if (count && poll) if (count && poll)
poll->seen_last_update = true; poll->seen_last_update = true;
...@@ -266,7 +298,28 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) ...@@ -266,7 +298,28 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
con_buf_start = con_buf0 = con_buf; con_buf_start = con_buf0 = con_buf;
orig_count = this_round; orig_count = this_round;
maxcol = vc->vc_cols; maxcol = vc->vc_cols;
if (!attr) { if (uni_mode) {
unsigned int nr;
ret = vc_uniscr_check(vc);
if (ret)
break;
p /= 4;
row = p / vc->vc_cols;
col = p % maxcol;
nr = maxcol - col;
do {
if (nr > this_round/4)
nr = this_round/4;
vc_uniscr_copy_line(vc, con_buf0, viewed,
row, col, nr);
con_buf0 += nr * 4;
this_round -= nr * 4;
row++;
col = 0;
nr = maxcol;
} while (this_round);
} else if (!attr) {
org = screen_pos(vc, p, viewed); org = screen_pos(vc, p, viewed);
col = p % maxcol; col = p % maxcol;
p += maxcol - col; p += maxcol - col;
...@@ -375,7 +428,6 @@ static ssize_t ...@@ -375,7 +428,6 @@ static ssize_t
vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{ {
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
unsigned int currcons = iminor(inode);
struct vc_data *vc; struct vc_data *vc;
long pos; long pos;
long attr, size, written; long attr, size, written;
...@@ -396,7 +448,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) ...@@ -396,7 +448,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
*/ */
console_lock(); console_lock();
attr = (currcons & 128); attr = use_attributes(inode);
ret = -ENXIO; ret = -ENXIO;
vc = vcs_vc(inode, &viewed); vc = vcs_vc(inode, &viewed);
if (!vc) if (!vc)
...@@ -593,9 +645,15 @@ vcs_fasync(int fd, struct file *file, int on) ...@@ -593,9 +645,15 @@ vcs_fasync(int fd, struct file *file, int on)
static int static int
vcs_open(struct inode *inode, struct file *filp) vcs_open(struct inode *inode, struct file *filp)
{ {
unsigned int currcons = iminor(inode) & 127; unsigned int currcons = console(inode);
bool attr = use_attributes(inode);
bool uni_mode = use_unicode(inode);
int ret = 0; int ret = 0;
/* we currently don't support attributes in unicode mode */
if (attr && uni_mode)
return -EOPNOTSUPP;
console_lock(); console_lock();
if(currcons && !vc_cons_allocated(currcons-1)) if(currcons && !vc_cons_allocated(currcons-1))
ret = -ENXIO; ret = -ENXIO;
...@@ -628,6 +686,8 @@ void vcs_make_sysfs(int index) ...@@ -628,6 +686,8 @@ void vcs_make_sysfs(int index)
{ {
device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 1), NULL, device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 1), NULL,
"vcs%u", index + 1); "vcs%u", index + 1);
device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 65), NULL,
"vcsu%u", index + 1);
device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 129), NULL, device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 129), NULL,
"vcsa%u", index + 1); "vcsa%u", index + 1);
} }
...@@ -635,6 +695,7 @@ void vcs_make_sysfs(int index) ...@@ -635,6 +695,7 @@ void vcs_make_sysfs(int index)
void vcs_remove_sysfs(int index) void vcs_remove_sysfs(int index)
{ {
device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 1)); device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 1));
device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 65));
device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 129)); device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 129));
} }
...@@ -647,6 +708,7 @@ int __init vcs_init(void) ...@@ -647,6 +708,7 @@ int __init vcs_init(void)
vc_class = class_create(THIS_MODULE, "vc"); vc_class = class_create(THIS_MODULE, "vc");
device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs");
device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 64), NULL, "vcsu");
device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa"); device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa");
for (i = 0; i < MIN_NR_CONSOLES; i++) for (i = 0; i < MIN_NR_CONSOLES; i++)
vcs_make_sysfs(i); vcs_make_sysfs(i);
......
This diff is collapsed.
...@@ -17,8 +17,8 @@ ...@@ -17,8 +17,8 @@
#include <linux/vt.h> #include <linux/vt.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
struct vt_struct;
struct uni_pagedir; struct uni_pagedir;
struct uni_screen;
#define NPAR 16 #define NPAR 16
...@@ -140,6 +140,7 @@ struct vc_data { ...@@ -140,6 +140,7 @@ struct vc_data {
struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */ struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */
struct uni_pagedir *vc_uni_pagedir; struct uni_pagedir *vc_uni_pagedir;
struct uni_pagedir **vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */ struct uni_pagedir **vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */
struct uni_screen *vc_uni_screen; /* unicode screen content */
bool vc_panic_force_write; /* when oops/panic this VC can accept forced output/blanking */ bool vc_panic_force_write; /* when oops/panic this VC can accept forced output/blanking */
/* additional information is in vt_kern.h */ /* additional information is in vt_kern.h */
}; };
...@@ -148,7 +149,7 @@ struct vc { ...@@ -148,7 +149,7 @@ struct vc {
struct vc_data *d; struct vc_data *d;
struct work_struct SAK_work; struct work_struct SAK_work;
/* might add scrmem, vt_struct, kbd at some time, /* might add scrmem, kbd at some time,
to have everything in one place - the disadvantage to have everything in one place - the disadvantage
would be that vc_cons etc can no longer be static */ would be that vc_cons etc can no longer be static */
}; };
......
...@@ -32,6 +32,7 @@ extern unsigned char default_blu[]; ...@@ -32,6 +32,7 @@ extern unsigned char default_blu[];
extern unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed); extern unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed);
extern u16 screen_glyph(struct vc_data *vc, int offset); extern u16 screen_glyph(struct vc_data *vc, int offset);
extern u32 screen_glyph_unicode(struct vc_data *vc, int offset);
extern void complement_pos(struct vc_data *vc, int offset); extern void complement_pos(struct vc_data *vc, int offset);
extern void invert_screen(struct vc_data *vc, int offset, int count, int shift); extern void invert_screen(struct vc_data *vc, int offset, int count, int shift);
...@@ -42,4 +43,9 @@ extern u16 vcs_scr_readw(struct vc_data *vc, const u16 *org); ...@@ -42,4 +43,9 @@ extern u16 vcs_scr_readw(struct vc_data *vc, const u16 *org);
extern void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org); extern void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org);
extern void vcs_scr_updated(struct vc_data *vc); extern void vcs_scr_updated(struct vc_data *vc);
extern int vc_uniscr_check(struct vc_data *vc);
extern void vc_uniscr_copy_line(struct vc_data *vc, void *dest, int viewed,
unsigned int row, unsigned int col,
unsigned int nr);
#endif #endif
...@@ -160,6 +160,9 @@ extern void serial8250_do_shutdown(struct uart_port *port); ...@@ -160,6 +160,9 @@ extern void serial8250_do_shutdown(struct uart_port *port);
extern void serial8250_do_pm(struct uart_port *port, unsigned int state, extern void serial8250_do_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate); unsigned int oldstate);
extern void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl); extern void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl);
extern void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud,
unsigned int quot,
unsigned int quot_frac);
extern int fsl8250_handle_irq(struct uart_port *port); extern int fsl8250_handle_irq(struct uart_port *port);
int serial8250_handle_irq(struct uart_port *port, unsigned int iir); int serial8250_handle_irq(struct uart_port *port, unsigned int iir);
unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr); unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr);
......
...@@ -127,6 +127,13 @@ struct uart_port { ...@@ -127,6 +127,13 @@ struct uart_port {
struct ktermios *); struct ktermios *);
unsigned int (*get_mctrl)(struct uart_port *); unsigned int (*get_mctrl)(struct uart_port *);
void (*set_mctrl)(struct uart_port *, unsigned int); void (*set_mctrl)(struct uart_port *, unsigned int);
unsigned int (*get_divisor)(struct uart_port *,
unsigned int baud,
unsigned int *frac);
void (*set_divisor)(struct uart_port *,
unsigned int baud,
unsigned int quot,
unsigned int quot_frac);
int (*startup)(struct uart_port *port); int (*startup)(struct uart_port *port);
void (*shutdown)(struct uart_port *port); void (*shutdown)(struct uart_port *port);
void (*throttle)(struct uart_port *port); void (*throttle)(struct uart_port *port);
......
...@@ -119,13 +119,13 @@ ...@@ -119,13 +119,13 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/atomic.h>
/* /*
* the semaphore definition * the semaphore definition
*/ */
struct ld_semaphore { struct ld_semaphore {
long count; atomic_long_t count;
raw_spinlock_t wait_lock; raw_spinlock_t wait_lock;
unsigned int wait_readers; unsigned int wait_readers;
struct list_head read_wait; struct list_head read_wait;
......
...@@ -357,8 +357,29 @@ ...@@ -357,8 +357,29 @@
#define K_DTILDE K(KT_DEAD,3) #define K_DTILDE K(KT_DEAD,3)
#define K_DDIERE K(KT_DEAD,4) #define K_DDIERE K(KT_DEAD,4)
#define K_DCEDIL K(KT_DEAD,5) #define K_DCEDIL K(KT_DEAD,5)
#define K_DMACRON K(KT_DEAD,6)
#define K_DBREVE K(KT_DEAD,7)
#define K_DABDOT K(KT_DEAD,8)
#define K_DABRING K(KT_DEAD,9)
#define K_DDBACUTE K(KT_DEAD,10)
#define K_DCARON K(KT_DEAD,11)
#define K_DOGONEK K(KT_DEAD,12)
#define K_DIOTA K(KT_DEAD,13)
#define K_DVOICED K(KT_DEAD,14)
#define K_DSEMVOICED K(KT_DEAD,15)
#define K_DBEDOT K(KT_DEAD,16)
#define K_DHOOK K(KT_DEAD,17)
#define K_DHORN K(KT_DEAD,18)
#define K_DSTROKE K(KT_DEAD,19)
#define K_DABCOMMA K(KT_DEAD,20)
#define K_DABREVCOMMA K(KT_DEAD,21)
#define K_DDBGRAVE K(KT_DEAD,22)
#define K_DINVBREVE K(KT_DEAD,23)
#define K_DBECOMMA K(KT_DEAD,24)
#define K_DCURRENCY K(KT_DEAD,25)
#define K_DGREEK K(KT_DEAD,26)
#define NR_DEAD 6 #define NR_DEAD 27
#define K_DOWN K(KT_CUR,0) #define K_DOWN K(KT_CUR,0)
#define K_LEFT K(KT_CUR,1) #define K_LEFT K(KT_CUR,1)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment