summaryrefslogtreecommitdiff
path: root/drivers/tty
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/Kconfig21
-rw-r--r--drivers/tty/hvc/hvc_iucv.c7
-rw-r--r--drivers/tty/ipwireless/hardware.c6
-rw-r--r--drivers/tty/mips_ejtag_fdc.c7
-rw-r--r--drivers/tty/moxa.c253
-rw-r--r--drivers/tty/mxser.c4
-rw-r--r--drivers/tty/n_gsm.c22
-rw-r--r--drivers/tty/n_tty.c209
-rw-r--r--drivers/tty/serdev/core.c19
-rw-r--r--drivers/tty/serdev/serdev-ttyport.c9
-rw-r--r--drivers/tty/serial/8250/8250.h6
-rw-r--r--drivers/tty/serial/8250/8250_aspeed_vuart.c5
-rw-r--r--drivers/tty/serial/8250/8250_bcm7271.c3
-rw-r--r--drivers/tty/serial/8250/8250_core.c8
-rw-r--r--drivers/tty/serial/8250/8250_dw.c73
-rw-r--r--drivers/tty/serial/8250/8250_early.c2
-rw-r--r--drivers/tty/serial/8250/8250_fsl.c8
-rw-r--r--drivers/tty/serial/8250/8250_ni.c446
-rw-r--r--drivers/tty/serial/8250/8250_of.c15
-rw-r--r--drivers/tty/serial/8250/8250_omap.c27
-rw-r--r--drivers/tty/serial/8250/8250_pci1xxxx.c10
-rw-r--r--drivers/tty/serial/8250/8250_port.c85
-rw-r--r--drivers/tty/serial/8250/8250_rsa.c23
-rw-r--r--drivers/tty/serial/8250/Kconfig13
-rw-r--r--drivers/tty/serial/8250/Makefile1
-rw-r--r--drivers/tty/serial/Kconfig42
-rw-r--r--drivers/tty/serial/Makefile2
-rw-r--r--drivers/tty/serial/altera_uart.c4
-rw-r--r--drivers/tty/serial/amba-pl011.c166
-rw-r--r--drivers/tty/serial/atmel_serial.c8
-rw-r--r--drivers/tty/serial/fsl_lpuart.c235
-rw-r--r--drivers/tty/serial/icom.c9
-rw-r--r--drivers/tty/serial/imx.c33
-rw-r--r--drivers/tty/serial/jsm/jsm_tty.c1
-rw-r--r--drivers/tty/serial/kgdb_nmi.c280
-rw-r--r--drivers/tty/serial/kgdboc.c8
-rw-r--r--drivers/tty/serial/lantiq.c4
-rw-r--r--drivers/tty/serial/liteuart.c6
-rw-r--r--drivers/tty/serial/ma35d1_serial.c2
-rw-r--r--drivers/tty/serial/max3100.c9
-rw-r--r--drivers/tty/serial/max310x.c7
-rw-r--r--drivers/tty/serial/milbeaut_usio.c5
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c1
-rw-r--r--drivers/tty/serial/msm_serial.c6
-rw-r--r--drivers/tty/serial/mux.c2
-rw-r--r--drivers/tty/serial/pch_uart.c3
-rw-r--r--drivers/tty/serial/qcom_geni_serial.c25
-rw-r--r--drivers/tty/serial/sa1100.c6
-rw-r--r--drivers/tty/serial/samsung_tty.c6
-rw-r--r--drivers/tty/serial/sc16is7xx.c7
-rw-r--r--drivers/tty/serial/sccnxp.c4
-rw-r--r--drivers/tty/serial/serial_base_bus.c4
-rw-r--r--drivers/tty/serial/serial_core.c157
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.c62
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.h27
-rw-r--r--drivers/tty/serial/sh-sci-common.h167
-rw-r--r--drivers/tty/serial/sh-sci.c595
-rw-r--r--drivers/tty/serial/sh-sci.h2
-rw-r--r--drivers/tty/serial/sifive.c94
-rw-r--r--drivers/tty/serial/stm32-usart.c2
-rw-r--r--drivers/tty/serial/sunsu.c178
-rw-r--r--drivers/tty/serial/tegra-utc.c625
-rw-r--r--drivers/tty/serial/uartlite.c25
-rw-r--r--drivers/tty/serial/xilinx_uartps.c8
-rw-r--r--drivers/tty/synclink_gt.c12
-rw-r--r--drivers/tty/sysrq.c7
-rw-r--r--drivers/tty/tty_audit.c10
-rw-r--r--drivers/tty/tty_io.c104
-rw-r--r--drivers/tty/tty_ioctl.c50
-rw-r--r--drivers/tty/tty_ldsem.c17
-rw-r--r--drivers/tty/tty_port.c20
-rw-r--r--drivers/tty/vcc.c10
-rw-r--r--drivers/tty/vt/.gitignore3
-rw-r--r--drivers/tty/vt/Makefile34
-rw-r--r--drivers/tty/vt/consolemap.c2
-rwxr-xr-xdrivers/tty/vt/gen_ucs_fallback_table.py360
-rwxr-xr-xdrivers/tty/vt/gen_ucs_recompose_table.py257
-rwxr-xr-xdrivers/tty/vt/gen_ucs_width_table.py307
-rw-r--r--drivers/tty/vt/keyboard.c39
-rw-r--r--drivers/tty/vt/selection.c36
-rw-r--r--drivers/tty/vt/ucs.c251
-rw-r--r--drivers/tty/vt/ucs_fallback_table.h_shipped3346
-rw-r--r--drivers/tty/vt/ucs_recompose_table.h_shipped102
-rw-r--r--drivers/tty/vt/ucs_width_table.h_shipped453
-rw-r--r--drivers/tty/vt/vt.c249
-rw-r--r--drivers/tty/vt/vt_ioctl.c18
86 files changed, 8009 insertions, 1787 deletions
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index 63a494d36a1f..149f3d53b760 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -210,7 +210,7 @@ config SERIAL_NONSTANDARD
config MOXA_INTELLIO
tristate "Moxa Intellio support"
- depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
+ depends on SERIAL_NONSTANDARD && PCI
select FW_LOADER
help
Say Y here if you have a Moxa Intellio multiport serial card.
@@ -383,7 +383,24 @@ config NULL_TTY
available or desired.
In order to use this driver, you should redirect the console to this
- TTY, or boot the kernel with console=ttynull.
+ TTY, boot the kernel with console=ttynull, or enable
+ NULL_TTY_DEFAULT_CONSOLE.
+
+ If unsure, say N.
+
+config NULL_TTY_DEFAULT_CONSOLE
+ bool "Support for console on ttynull"
+ depends on NULL_TTY=y && !VT_CONSOLE
+ help
+ Say Y here if you want the NULL TTY to be used as a /dev/console
+ device by default.
+
+ For example, it might be useful to prevent a VT-less kernel from
+ writing the system log to a random device connected to the serial
+ port.
+
+ Another console driver still might get preferred via the command
+ line, SPCR, or the device tree.
If unsure, say N.
diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c
index ed4bf40278a7..4ca7472c38e0 100644
--- a/drivers/tty/hvc/hvc_iucv.c
+++ b/drivers/tty/hvc/hvc_iucv.c
@@ -24,6 +24,7 @@
#include <linux/tty.h>
#include <linux/wait.h>
#include <net/iucv/iucv.h>
+#include <asm/machine.h>
#include "hvc_console.h"
@@ -1240,7 +1241,7 @@ static int param_set_vmidfilter(const char *val, const struct kernel_param *kp)
{
int rc;
- if (!MACHINE_IS_VM || !hvc_iucv_devices)
+ if (!machine_is_vm() || !hvc_iucv_devices)
return -ENODEV;
if (!val)
@@ -1269,7 +1270,7 @@ static int param_get_vmidfilter(char *buffer, const struct kernel_param *kp)
size_t index, len;
void *start, *end;
- if (!MACHINE_IS_VM || !hvc_iucv_devices)
+ if (!machine_is_vm() || !hvc_iucv_devices)
return -ENODEV;
rc = 0;
@@ -1306,7 +1307,7 @@ static int __init hvc_iucv_init(void)
if (!hvc_iucv_devices)
return -ENODEV;
- if (!MACHINE_IS_VM) {
+ if (!machine_is_vm()) {
pr_notice("The z/VM IUCV HVC device driver cannot "
"be used without z/VM\n");
rc = -ENODEV;
diff --git a/drivers/tty/ipwireless/hardware.c b/drivers/tty/ipwireless/hardware.c
index 001ec318a918..e18848267be4 100644
--- a/drivers/tty/ipwireless/hardware.c
+++ b/drivers/tty/ipwireless/hardware.c
@@ -1496,7 +1496,7 @@ exit_nomem:
static void handle_setup_get_version_rsp(struct ipw_hardware *hw,
unsigned char vers_no)
{
- del_timer(&hw->setup_timer);
+ timer_delete(&hw->setup_timer);
hw->initializing = 0;
printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": card is ready.\n");
@@ -1676,7 +1676,7 @@ void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw)
static void ipwireless_setup_timer(struct timer_list *t)
{
- struct ipw_hardware *hw = from_timer(hw, t, setup_timer);
+ struct ipw_hardware *hw = timer_container_of(hw, t, setup_timer);
hw->init_loops++;
@@ -1721,7 +1721,7 @@ void ipwireless_stop_interrupts(struct ipw_hardware *hw)
if (!hw->shutting_down) {
/* Tell everyone we are going down. */
hw->shutting_down = 1;
- del_timer(&hw->setup_timer);
+ timer_delete(&hw->setup_timer);
/* Prevent the hardware from sending any more interrupts */
do_close_hardware(hw);
diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c
index 58b28be63c79..ba7690c3e15e 100644
--- a/drivers/tty/mips_ejtag_fdc.c
+++ b/drivers/tty/mips_ejtag_fdc.c
@@ -683,7 +683,8 @@ static irqreturn_t mips_ejtag_fdc_isr(int irq, void *dev_id)
*/
static void mips_ejtag_fdc_tty_timer(struct timer_list *t)
{
- struct mips_ejtag_fdc_tty *priv = from_timer(priv, t, poll_timer);
+ struct mips_ejtag_fdc_tty *priv = timer_container_of(priv, t,
+ poll_timer);
mips_ejtag_fdc_handle(priv);
if (!priv->removing)
@@ -1031,7 +1032,7 @@ err_stop_irq:
raw_spin_unlock_irq(&priv->lock);
} else {
priv->removing = true;
- del_timer_sync(&priv->poll_timer);
+ timer_delete_sync(&priv->poll_timer);
}
kthread_stop(priv->thread);
err_destroy_ports:
@@ -1061,7 +1062,7 @@ static int mips_ejtag_fdc_tty_cpu_down(struct mips_cdmm_device *dev)
raw_spin_unlock_irq(&priv->lock);
} else {
priv->removing = true;
- del_timer_sync(&priv->poll_timer);
+ timer_delete_sync(&priv->poll_timer);
}
kthread_stop(priv->thread);
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index ebaada8db929..329b30fac8fc 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -43,15 +43,6 @@
#include <linux/ratelimit.h>
#include <asm/io.h>
-#include <linux/uaccess.h>
-
-#define MOXA 0x400
-#define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */
-#define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */
-#define MOXA_GETDATACOUNT (MOXA + 23)
-#define MOXA_GET_IOQUEUE (MOXA + 27)
-#define MOXA_FLUSH_QUEUE (MOXA + 28)
-#define MOXA_GETMSTATUS (MOXA + 65)
/*
* System Configuration
@@ -347,8 +338,6 @@
#define MX_PARMARK 0xA0
#define MX_PARSPACE 0x20
-#define MOXA_VERSION "6.0k"
-
#define MOXA_FW_HDRLEN 32
#define MOXAMAJOR 172
@@ -357,33 +346,21 @@
#define MAX_PORTS_PER_BOARD 32 /* Don't change this value */
#define MAX_PORTS (MAX_BOARDS * MAX_PORTS_PER_BOARD)
-#define MOXA_IS_320(brd) ((brd)->boardType == MOXA_BOARD_C320_ISA || \
- (brd)->boardType == MOXA_BOARD_C320_PCI)
-
-/*
- * Define the Moxa PCI vendor and device IDs.
- */
-#define MOXA_BUS_TYPE_ISA 0
-#define MOXA_BUS_TYPE_PCI 1
+#define MOXA_IS_320(brd) ((brd)->boardType == MOXA_BOARD_C320_PCI)
enum {
MOXA_BOARD_C218_PCI = 1,
- MOXA_BOARD_C218_ISA,
MOXA_BOARD_C320_PCI,
- MOXA_BOARD_C320_ISA,
MOXA_BOARD_CP204J,
};
static char *moxa_brdname[] =
{
"C218 Turbo PCI series",
- "C218 Turbo ISA series",
"C320 Turbo PCI series",
- "C320 Turbo ISA series",
"CP-204J series",
};
-#ifdef CONFIG_PCI
static const struct pci_device_id moxa_pcibrds[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218),
.driver_data = MOXA_BOARD_C218_PCI },
@@ -394,14 +371,12 @@ static const struct pci_device_id moxa_pcibrds[] = {
{ 0 }
};
MODULE_DEVICE_TABLE(pci, moxa_pcibrds);
-#endif /* CONFIG_PCI */
struct moxa_port;
static struct moxa_board_conf {
int boardType;
int numPorts;
- int busType;
unsigned int ready;
@@ -413,19 +388,6 @@ static struct moxa_board_conf {
void __iomem *intTable;
} moxa_boards[MAX_BOARDS];
-struct mxser_mstatus {
- tcflag_t cflag;
- int cts;
- int dsr;
- int ri;
- int dcd;
-};
-
-struct moxaq_str {
- int inq;
- int outq;
-};
-
struct moxa_port {
struct tty_port port;
struct moxa_board_conf *board;
@@ -440,12 +402,6 @@ struct moxa_port {
u8 lowChkFlag;
};
-struct mon_str {
- int tick;
- int rxcnt[MAX_PORTS];
- int txcnt[MAX_PORTS];
-};
-
/* statusflags */
#define TXSTOPPED 1
#define LOWWAIT 2
@@ -455,17 +411,11 @@ struct mon_str {
#define WAKEUP_CHARS 256
static int ttymajor = MOXAMAJOR;
-static struct mon_str moxaLog;
static unsigned int moxaFuncTout = HZ / 2;
static unsigned int moxaLowWaterChk;
static DEFINE_MUTEX(moxa_openlock);
static DEFINE_SPINLOCK(moxa_lock);
-static unsigned long baseaddr[MAX_BOARDS];
-static unsigned int type[MAX_BOARDS];
-static unsigned int numports[MAX_BOARDS];
-static struct tty_port moxa_service_port;
-
MODULE_AUTHOR("William Chen");
MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
MODULE_LICENSE("GPL");
@@ -473,13 +423,6 @@ MODULE_FIRMWARE("c218tunx.cod");
MODULE_FIRMWARE("cp204unx.cod");
MODULE_FIRMWARE("c320tunx.cod");
-module_param_array(type, uint, NULL, 0);
-MODULE_PARM_DESC(type, "card type: C218=2, C320=4");
-module_param_hw_array(baseaddr, ulong, ioport, NULL, 0);
-MODULE_PARM_DESC(baseaddr, "base address");
-module_param_array(numports, uint, NULL, 0);
-MODULE_PARM_DESC(numports, "numports (ignored for C218)");
-
module_param(ttymajor, int, 0);
/*
@@ -583,104 +526,6 @@ static void moxa_low_water_check(void __iomem *ofsAddr)
* TTY operations
*/
-static int moxa_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct moxa_port *ch = tty->driver_data;
- void __user *argp = (void __user *)arg;
- int status, ret = 0;
-
- if (tty->index == MAX_PORTS) {
- if (cmd != MOXA_GETDATACOUNT && cmd != MOXA_GET_IOQUEUE &&
- cmd != MOXA_GETMSTATUS)
- return -EINVAL;
- } else if (!ch)
- return -ENODEV;
-
- switch (cmd) {
- case MOXA_GETDATACOUNT:
- moxaLog.tick = jiffies;
- if (copy_to_user(argp, &moxaLog, sizeof(moxaLog)))
- ret = -EFAULT;
- break;
- case MOXA_FLUSH_QUEUE:
- MoxaPortFlushData(ch, arg);
- break;
- case MOXA_GET_IOQUEUE: {
- struct moxaq_str __user *argm = argp;
- struct moxaq_str tmp;
- struct moxa_port *p;
- unsigned int i, j;
-
- for (i = 0; i < MAX_BOARDS; i++) {
- p = moxa_boards[i].ports;
- for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
- memset(&tmp, 0, sizeof(tmp));
- spin_lock_bh(&moxa_lock);
- if (moxa_boards[i].ready) {
- tmp.inq = MoxaPortRxQueue(p);
- tmp.outq = MoxaPortTxQueue(p);
- }
- spin_unlock_bh(&moxa_lock);
- if (copy_to_user(argm, &tmp, sizeof(tmp)))
- return -EFAULT;
- }
- }
- break;
- } case MOXA_GET_OQUEUE:
- status = MoxaPortTxQueue(ch);
- ret = put_user(status, (unsigned long __user *)argp);
- break;
- case MOXA_GET_IQUEUE:
- status = MoxaPortRxQueue(ch);
- ret = put_user(status, (unsigned long __user *)argp);
- break;
- case MOXA_GETMSTATUS: {
- struct mxser_mstatus __user *argm = argp;
- struct mxser_mstatus tmp;
- struct moxa_port *p;
- unsigned int i, j;
-
- for (i = 0; i < MAX_BOARDS; i++) {
- p = moxa_boards[i].ports;
- for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
- struct tty_struct *ttyp;
- memset(&tmp, 0, sizeof(tmp));
- spin_lock_bh(&moxa_lock);
- if (!moxa_boards[i].ready) {
- spin_unlock_bh(&moxa_lock);
- goto copy;
- }
-
- status = MoxaPortLineStatus(p);
- spin_unlock_bh(&moxa_lock);
-
- if (status & 1)
- tmp.cts = 1;
- if (status & 2)
- tmp.dsr = 1;
- if (status & 4)
- tmp.dcd = 1;
-
- ttyp = tty_port_tty_get(&p->port);
- if (!ttyp)
- tmp.cflag = p->cflag;
- else
- tmp.cflag = ttyp->termios.c_cflag;
- tty_kref_put(ttyp);
-copy:
- if (copy_to_user(argm, &tmp, sizeof(tmp)))
- return -EFAULT;
- }
- }
- break;
- }
- default:
- ret = -ENOIOCTLCMD;
- }
- return ret;
-}
-
static int moxa_break_ctl(struct tty_struct *tty, int state)
{
struct moxa_port *port = tty->driver_data;
@@ -697,7 +542,6 @@ static const struct tty_operations moxa_ops = {
.write_room = moxa_write_room,
.flush_buffer = moxa_flush_buffer,
.chars_in_buffer = moxa_chars_in_buffer,
- .ioctl = moxa_ioctl,
.set_termios = moxa_set_termios,
.stop = moxa_stop,
.start = moxa_start,
@@ -725,7 +569,6 @@ static DEFINE_TIMER(moxaTimer, moxa_poll);
static int moxa_check_fw_model(struct moxa_board_conf *brd, u8 model)
{
switch (brd->boardType) {
- case MOXA_BOARD_C218_ISA:
case MOXA_BOARD_C218_PCI:
if (model != 1)
goto err;
@@ -769,7 +612,6 @@ static int moxa_load_bios(struct moxa_board_conf *brd, const u8 *buf,
msleep(2000);
switch (brd->boardType) {
- case MOXA_BOARD_C218_ISA:
case MOXA_BOARD_C218_PCI:
tmp = readw(baseAddr + C218_key);
if (tmp != C218_KeyCode)
@@ -833,7 +675,6 @@ static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr,
switch (brd->boardType) {
case MOXA_BOARD_CP204J:
- case MOXA_BOARD_C218_ISA:
case MOXA_BOARD_C218_PCI:
key = C218_key;
loadbuf = C218_LoadBuf;
@@ -898,15 +739,9 @@ static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr,
return -EIO;
if (MOXA_IS_320(brd)) {
- if (brd->busType == MOXA_BUS_TYPE_PCI) { /* ASIC board */
- writew(0x3800, baseAddr + TMS320_PORT1);
- writew(0x3900, baseAddr + TMS320_PORT2);
- writew(28499, baseAddr + TMS320_CLOCK);
- } else {
- writew(0x3200, baseAddr + TMS320_PORT1);
- writew(0x3400, baseAddr + TMS320_PORT2);
- writew(19999, baseAddr + TMS320_CLOCK);
- }
+ writew(0x3800, baseAddr + TMS320_PORT1);
+ writew(0x3900, baseAddr + TMS320_PORT2);
+ writew(28499, baseAddr + TMS320_CLOCK);
}
writew(1, baseAddr + Disable_IRQ);
writew(0, baseAddr + Magic_no);
@@ -957,7 +792,6 @@ static int moxa_load_code(struct moxa_board_conf *brd, const void *ptr,
return retval;
switch (brd->boardType) {
- case MOXA_BOARD_C218_ISA:
case MOXA_BOARD_C218_PCI:
case MOXA_BOARD_CP204J:
port = brd->ports;
@@ -1141,7 +975,6 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
}
switch (brd->boardType) {
- case MOXA_BOARD_C218_ISA:
case MOXA_BOARD_C218_PCI:
file = "c218tunx.cod";
break;
@@ -1227,7 +1060,6 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
kfree(brd->ports);
}
-#ifdef CONFIG_PCI
static int moxa_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -1270,7 +1102,6 @@ static int moxa_pci_probe(struct pci_dev *pdev,
board->boardType = board_type;
switch (board_type) {
- case MOXA_BOARD_C218_ISA:
case MOXA_BOARD_C218_PCI:
board->numPorts = 8;
break;
@@ -1282,7 +1113,6 @@ static int moxa_pci_probe(struct pci_dev *pdev,
board->numPorts = 0;
break;
}
- board->busType = MOXA_BUS_TYPE_PCI;
retval = moxa_init_board(board, &pdev->dev);
if (retval)
@@ -1318,21 +1148,12 @@ static struct pci_driver moxa_pci_driver = {
.probe = moxa_pci_probe,
.remove = moxa_pci_remove
};
-#endif /* CONFIG_PCI */
static int __init moxa_init(void)
{
- unsigned int isabrds = 0;
int retval = 0;
- struct moxa_board_conf *brd = moxa_boards;
- unsigned int i;
-
- printk(KERN_INFO "MOXA Intellio family driver version %s\n",
- MOXA_VERSION);
- tty_port_init(&moxa_service_port);
-
- moxaDriver = tty_alloc_driver(MAX_PORTS + 1,
+ moxaDriver = tty_alloc_driver(MAX_PORTS,
TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV);
if (IS_ERR(moxaDriver))
@@ -1348,8 +1169,6 @@ static int __init moxa_init(void)
moxaDriver->init_termios.c_ispeed = 9600;
moxaDriver->init_termios.c_ospeed = 9600;
tty_set_operations(moxaDriver, &moxa_ops);
- /* Having one more port only for ioctls is ugly */
- tty_port_link_device(&moxa_service_port, moxaDriver, MAX_PORTS);
if (tty_register_driver(moxaDriver)) {
printk(KERN_ERR "can't register MOXA Smartio tty driver!\n");
@@ -1357,66 +1176,18 @@ static int __init moxa_init(void)
return -1;
}
- /* Find the boards defined from module args. */
-
- for (i = 0; i < MAX_BOARDS; i++) {
- if (!baseaddr[i])
- break;
- if (type[i] == MOXA_BOARD_C218_ISA ||
- type[i] == MOXA_BOARD_C320_ISA) {
- pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n",
- isabrds + 1, moxa_brdname[type[i] - 1],
- baseaddr[i]);
- brd->boardType = type[i];
- brd->numPorts = type[i] == MOXA_BOARD_C218_ISA ? 8 :
- numports[i];
- brd->busType = MOXA_BUS_TYPE_ISA;
- brd->basemem = ioremap(baseaddr[i], 0x4000);
- if (!brd->basemem) {
- printk(KERN_ERR "MOXA: can't remap %lx\n",
- baseaddr[i]);
- continue;
- }
- if (moxa_init_board(brd, NULL)) {
- iounmap(brd->basemem);
- brd->basemem = NULL;
- continue;
- }
-
- printk(KERN_INFO "MOXA isa board found at 0x%.8lx and "
- "ready (%u ports, firmware loaded)\n",
- baseaddr[i], brd->numPorts);
-
- brd++;
- isabrds++;
- }
- }
-
-#ifdef CONFIG_PCI
retval = pci_register_driver(&moxa_pci_driver);
- if (retval) {
+ if (retval)
printk(KERN_ERR "Can't register MOXA pci driver!\n");
- if (isabrds)
- retval = 0;
- }
-#endif
return retval;
}
static void __exit moxa_exit(void)
{
- unsigned int i;
-
-#ifdef CONFIG_PCI
pci_unregister_driver(&moxa_pci_driver);
-#endif
-
- for (i = 0; i < MAX_BOARDS; i++) /* ISA boards */
- if (moxa_boards[i].ready)
- moxa_board_deinit(&moxa_boards[i]);
- del_timer_sync(&moxaTimer);
+ timer_delete_sync(&moxaTimer);
tty_unregister_driver(moxaDriver);
tty_driver_kref_put(moxaDriver);
@@ -1457,9 +1228,6 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
int port;
port = tty->index;
- if (port == MAX_PORTS) {
- return capable(CAP_SYS_ADMIN) ? 0 : -EPERM;
- }
if (mutex_lock_interruptible(&moxa_openlock))
return -ERESTARTSYS;
brd = &moxa_boards[port / MAX_PORTS_PER_BOARD];
@@ -2182,7 +1950,6 @@ static ssize_t MoxaPortWriteData(struct tty_struct *tty, const u8 *buffer,
c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask);
if (c > len)
c = len;
- moxaLog.txcnt[port->port.tty->index] += c;
total = c;
if (spage == epage) {
bufhead = readw(ofsAddr + Ofs_txb);
@@ -2224,7 +1991,6 @@ static ssize_t MoxaPortWriteData(struct tty_struct *tty, const u8 *buffer,
static int MoxaPortReadData(struct moxa_port *port)
{
- struct tty_struct *tty = port->port.tty;
void __iomem *baseAddr, *ofsAddr, *ofs;
u8 *dst;
unsigned int count, len, total;
@@ -2243,7 +2009,6 @@ static int MoxaPortReadData(struct moxa_port *port)
return 0;
total = count;
- moxaLog.rxcnt[tty->index] += total;
if (spage == epage) {
bufhead = readw(ofsAddr + Ofs_rxb);
writew(spage, baseAddr + Control_reg);
@@ -2331,8 +2096,6 @@ static int moxa_get_serial_info(struct tty_struct *tty,
{
struct moxa_port *info = tty->driver_data;
- if (tty->index == MAX_PORTS)
- return -EINVAL;
if (!info)
return -ENODEV;
mutex_lock(&info->port.mutex);
@@ -2352,8 +2115,6 @@ static int moxa_set_serial_info(struct tty_struct *tty,
struct moxa_port *info = tty->driver_data;
unsigned int close_delay;
- if (tty->index == MAX_PORTS)
- return -EINVAL;
if (!info)
return -ENODEV;
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 4d45eca4929a..2fc13cc02cc5 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -1812,7 +1812,7 @@ static int mxser_probe(struct pci_dev *pdev,
/* io address */
ioaddress = pci_resource_start(pdev, 2);
- retval = pci_request_region(pdev, 2, "mxser(IO)");
+ retval = pcim_request_region(pdev, 2, "mxser(IO)");
if (retval)
goto err_zero;
@@ -1822,7 +1822,7 @@ static int mxser_probe(struct pci_dev *pdev,
/* vector */
ioaddress = pci_resource_start(pdev, 3);
- retval = pci_request_region(pdev, 3, "mxser(vector)");
+ retval = pcim_request_region(pdev, 3, "mxser(vector)");
if (retval)
goto err_zero;
brd->vector = ioaddress;
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 363afe11974f..7fc535452c0b 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -1941,7 +1941,7 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
/* Does the reply match our command */
if (ctrl != NULL && (command == ctrl->cmd || command == CMD_NSC)) {
/* Our command was replied to, kill the retry timer */
- del_timer(&gsm->t2_timer);
+ timer_delete(&gsm->t2_timer);
gsm->pending_cmd = NULL;
/* Rejected by the other end */
if (command == CMD_NSC)
@@ -1971,7 +1971,7 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
static void gsm_control_keep_alive(struct timer_list *t)
{
- struct gsm_mux *gsm = from_timer(gsm, t, ka_timer);
+ struct gsm_mux *gsm = timer_container_of(gsm, t, ka_timer);
unsigned long flags;
spin_lock_irqsave(&gsm->control_lock, flags);
@@ -2028,7 +2028,7 @@ static void gsm_control_transmit(struct gsm_mux *gsm, struct gsm_control *ctrl)
static void gsm_control_retransmit(struct timer_list *t)
{
- struct gsm_mux *gsm = from_timer(gsm, t, t2_timer);
+ struct gsm_mux *gsm = timer_container_of(gsm, t, t2_timer);
struct gsm_control *ctrl;
unsigned long flags;
spin_lock_irqsave(&gsm->control_lock, flags);
@@ -2131,7 +2131,7 @@ static int gsm_control_wait(struct gsm_mux *gsm, struct gsm_control *control)
static void gsm_dlci_close(struct gsm_dlci *dlci)
{
- del_timer(&dlci->t1);
+ timer_delete(&dlci->t1);
if (debug & DBG_ERRORS)
pr_debug("DLCI %d goes closed.\n", dlci->addr);
dlci->state = DLCI_CLOSED;
@@ -2144,7 +2144,7 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
tty_port_set_initialized(&dlci->port, false);
wake_up_interruptible(&dlci->port.open_wait);
} else {
- del_timer(&dlci->gsm->ka_timer);
+ timer_delete(&dlci->gsm->ka_timer);
dlci->gsm->dead = true;
}
/* A DLCI 0 close is a MUX termination so we need to kick that
@@ -2166,7 +2166,7 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
/* Note that SABM UA .. SABM UA first UA lost can mean that we go
open -> open */
- del_timer(&dlci->t1);
+ timer_delete(&dlci->t1);
/* This will let a tty open continue */
dlci->state = DLCI_OPEN;
dlci->constipated = false;
@@ -2229,7 +2229,7 @@ static int gsm_dlci_negotiate(struct gsm_dlci *dlci)
static void gsm_dlci_t1(struct timer_list *t)
{
- struct gsm_dlci *dlci = from_timer(dlci, t, t1);
+ struct gsm_dlci *dlci = timer_container_of(dlci, t, t1);
struct gsm_mux *gsm = dlci->gsm;
switch (dlci->state) {
@@ -2489,7 +2489,7 @@ static void gsm_dlci_command(struct gsm_dlci *dlci, const u8 *data, int len)
*/
static void gsm_kick_timer(struct timer_list *t)
{
- struct gsm_mux *gsm = from_timer(gsm, t, kick_timer);
+ struct gsm_mux *gsm = timer_container_of(gsm, t, kick_timer);
unsigned long flags;
int sent = 0;
@@ -3144,9 +3144,9 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc)
}
/* Finish outstanding timers, making sure they are done */
- del_timer_sync(&gsm->kick_timer);
- del_timer_sync(&gsm->t2_timer);
- del_timer_sync(&gsm->ka_timer);
+ timer_delete_sync(&gsm->kick_timer);
+ timer_delete_sync(&gsm->t2_timer);
+ timer_delete_sync(&gsm->ka_timer);
/* Finish writing to ldisc */
flush_work(&gsm->tx_work);
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 94fa981081fd..6af3f3a0b531 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -56,6 +56,8 @@
*/
#define WAKEUP_CHARS 256
+#define N_TTY_BUF_SIZE 4096
+
/*
* This defines the low- and high-watermarks for throttling and
* unthrottling the TTY driver. These watermarks are used for
@@ -79,14 +81,6 @@
#define ECHO_BLOCK 256
#define ECHO_DISCARD_WATERMARK N_TTY_BUF_SIZE - (ECHO_BLOCK + 32)
-
-#undef N_TTY_TRACE
-#ifdef N_TTY_TRACE
-# define n_tty_trace(f, args...) trace_printk(f, ##args)
-#else
-# define n_tty_trace(f, args...) no_printk(f, ##args)
-#endif
-
struct n_tty_data {
/* producer-published */
size_t read_head;
@@ -486,19 +480,13 @@ static int do_output_char(u8 c, struct tty_struct *tty, int space)
static int process_output(u8 c, struct tty_struct *tty)
{
struct n_tty_data *ldata = tty->disc_data;
- unsigned int space;
- int retval;
- mutex_lock(&ldata->output_lock);
-
- space = tty_write_room(tty);
- retval = do_output_char(c, tty, space);
+ guard(mutex)(&ldata->output_lock);
- mutex_unlock(&ldata->output_lock);
- if (retval < 0)
+ if (do_output_char(c, tty, tty_write_room(tty)) < 0)
return -1;
- else
- return 0;
+
+ return 0;
}
/**
@@ -523,17 +511,15 @@ static ssize_t process_output_block(struct tty_struct *tty,
const u8 *buf, unsigned int nr)
{
struct n_tty_data *ldata = tty->disc_data;
- unsigned int space;
- int i;
+ unsigned int space, i;
const u8 *cp;
- mutex_lock(&ldata->output_lock);
+ guard(mutex)(&ldata->output_lock);
space = tty_write_room(tty);
- if (space == 0) {
- mutex_unlock(&ldata->output_lock);
+ if (space == 0)
return 0;
- }
+
if (nr > space)
nr = space;
@@ -545,18 +531,18 @@ static ssize_t process_output_block(struct tty_struct *tty,
if (O_ONLRET(tty))
ldata->column = 0;
if (O_ONLCR(tty))
- goto break_out;
+ goto do_write;
ldata->canon_column = ldata->column;
break;
case '\r':
if (O_ONOCR(tty) && ldata->column == 0)
- goto break_out;
+ goto do_write;
if (O_OCRNL(tty))
- goto break_out;
+ goto do_write;
ldata->canon_column = ldata->column = 0;
break;
case '\t':
- goto break_out;
+ goto do_write;
case '\b':
if (ldata->column > 0)
ldata->column--;
@@ -564,18 +550,15 @@ static ssize_t process_output_block(struct tty_struct *tty,
default:
if (!iscntrl(c)) {
if (O_OLCUC(tty))
- goto break_out;
+ goto do_write;
if (!is_continuation(c, tty))
ldata->column++;
}
break;
}
}
-break_out:
- i = tty->ops->write(tty, buf, i);
-
- mutex_unlock(&ldata->output_lock);
- return i;
+do_write:
+ return tty->ops->write(tty, buf, i);
}
static int n_tty_process_echo_ops(struct tty_struct *tty, size_t *tail,
@@ -2035,9 +2018,6 @@ static bool canon_copy_from_read_buf(const struct tty_struct *tty, u8 **kbp,
tail = MASK(ldata->read_tail);
size = min_t(size_t, tail + n, N_TTY_BUF_SIZE);
- n_tty_trace("%s: nr:%zu tail:%zu n:%zu size:%zu\n",
- __func__, *nr, tail, n, size);
-
eol = find_next_bit(ldata->read_flags, size, tail);
more = n - (size - tail);
if (eol == N_TTY_BUF_SIZE && more) {
@@ -2055,9 +2035,6 @@ static bool canon_copy_from_read_buf(const struct tty_struct *tty, u8 **kbp,
if (!found || read_buf(ldata, eol) != __DISABLED_CHAR)
n = c;
- n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu tail:%zu more:%zu\n",
- __func__, eol, found, n, c, tail, more);
-
tty_copy(tty, *kbp, tail, n);
*kbp += n;
*nr -= n;
@@ -2134,6 +2111,66 @@ static int job_control(struct tty_struct *tty, struct file *file)
return __tty_check_change(tty, SIGTTIN);
}
+/*
+ * We still hold the atomic_read_lock and the termios_rwsem, and can just
+ * continue to copy data.
+ */
+static ssize_t n_tty_continue_cookie(struct tty_struct *tty, u8 *kbuf,
+ size_t nr, void **cookie)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ u8 *kb = kbuf;
+
+ if (ldata->icanon && !L_EXTPROC(tty)) {
+ /*
+ * If we have filled the user buffer, see if we should skip an
+ * EOF character before releasing the lock and returning done.
+ */
+ if (!nr)
+ canon_skip_eof(ldata);
+ else if (canon_copy_from_read_buf(tty, &kb, &nr))
+ return kb - kbuf;
+ } else {
+ if (copy_from_read_buf(tty, &kb, &nr))
+ return kb - kbuf;
+ }
+
+ /* No more data - release locks and stop retries */
+ n_tty_kick_worker(tty);
+ n_tty_check_unthrottle(tty);
+ up_read(&tty->termios_rwsem);
+ mutex_unlock(&ldata->atomic_read_lock);
+ *cookie = NULL;
+
+ return kb - kbuf;
+}
+
+static int n_tty_wait_for_input(struct tty_struct *tty, struct file *file,
+ struct wait_queue_entry *wait, long *timeout)
+{
+ if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+ return -EIO;
+ if (tty_hung_up_p(file))
+ return 0;
+ /*
+ * Abort readers for ttys which never actually get hung up.
+ * See __tty_hangup().
+ */
+ if (test_bit(TTY_HUPPING, &tty->flags))
+ return 0;
+ if (!*timeout)
+ return 0;
+ if (tty_io_nonblock(tty, file))
+ return -EAGAIN;
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
+ up_read(&tty->termios_rwsem);
+ *timeout = wait_woken(wait, TASK_INTERRUPTIBLE, *timeout);
+ down_read(&tty->termios_rwsem);
+
+ return 1;
+}
/**
* n_tty_read - read function for tty
@@ -2167,36 +2204,9 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, u8 *kbuf,
bool packet;
size_t old_tail;
- /*
- * Is this a continuation of a read started earler?
- *
- * If so, we still hold the atomic_read_lock and the
- * termios_rwsem, and can just continue to copy data.
- */
- if (*cookie) {
- if (ldata->icanon && !L_EXTPROC(tty)) {
- /*
- * If we have filled the user buffer, see
- * if we should skip an EOF character before
- * releasing the lock and returning done.
- */
- if (!nr)
- canon_skip_eof(ldata);
- else if (canon_copy_from_read_buf(tty, &kb, &nr))
- return kb - kbuf;
- } else {
- if (copy_from_read_buf(tty, &kb, &nr))
- return kb - kbuf;
- }
-
- /* No more data - release locks and stop retries */
- n_tty_kick_worker(tty);
- n_tty_check_unthrottle(tty);
- up_read(&tty->termios_rwsem);
- mutex_unlock(&ldata->atomic_read_lock);
- *cookie = NULL;
- return kb - kbuf;
- }
+ /* Is this a continuation of a read started earlier? */
+ if (*cookie)
+ return n_tty_continue_cookie(tty, kbuf, nr, cookie);
retval = job_control(tty, file);
if (retval < 0)
@@ -2251,34 +2261,12 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, u8 *kbuf,
tty_buffer_flush_work(tty->port);
down_read(&tty->termios_rwsem);
if (!input_available_p(tty, 0)) {
- if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
- retval = -EIO;
+ int ret = n_tty_wait_for_input(tty, file, &wait,
+ &timeout);
+ if (ret <= 0) {
+ retval = ret;
break;
}
- if (tty_hung_up_p(file))
- break;
- /*
- * Abort readers for ttys which never actually
- * get hung up. See __tty_hangup().
- */
- if (test_bit(TTY_HUPPING, &tty->flags))
- break;
- if (!timeout)
- break;
- if (tty_io_nonblock(tty, file)) {
- retval = -EAGAIN;
- break;
- }
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- up_read(&tty->termios_rwsem);
-
- timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
- timeout);
-
- down_read(&tty->termios_rwsem);
continue;
}
}
@@ -2293,21 +2281,8 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, u8 *kbuf,
nr--;
}
- /*
- * Copy data, and if there is more to be had
- * and we have nothing more to wait for, then
- * let's mark us for retries.
- *
- * NOTE! We return here with both the termios_sem
- * and atomic_read_lock still held, the retries
- * will release them when done.
- */
- if (copy_from_read_buf(tty, &kb, &nr) && kb - kbuf >= minimum) {
-more_to_be_read:
- remove_wait_queue(&tty->read_wait, &wait);
- *cookie = cookie;
- return kb - kbuf;
- }
+ if (copy_from_read_buf(tty, &kb, &nr) && kb - kbuf >= minimum)
+ goto more_to_be_read;
}
n_tty_check_unthrottle(tty);
@@ -2334,6 +2309,18 @@ more_to_be_read:
retval = kb - kbuf;
return retval;
+more_to_be_read:
+ /*
+ * There is more to be had and we have nothing more to wait for, so
+ * let's mark us for retries.
+ *
+ * NOTE! We return here with both the termios_sem and atomic_read_lock
+ * still held, the retries will release them when done.
+ */
+ remove_wait_queue(&tty->read_wait, &wait);
+ *cookie = cookie;
+
+ return kb - kbuf;
}
/**
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
index ebf0bbc2cff2..0213381fa358 100644
--- a/drivers/tty/serdev/core.c
+++ b/drivers/tty/serdev/core.c
@@ -118,12 +118,11 @@ int serdev_device_add(struct serdev_device *serdev)
err = device_add(&serdev->dev);
if (err < 0) {
- dev_err(&serdev->dev, "Can't add %s, status %pe\n",
- dev_name(&serdev->dev), ERR_PTR(err));
+ dev_err(&serdev->dev, "Failed to add serdev: %d\n", err);
goto err_clear_serdev;
}
- dev_dbg(&serdev->dev, "device %s registered\n", dev_name(&serdev->dev));
+ dev_dbg(&serdev->dev, "serdev registered successfully\n");
return 0;
@@ -316,17 +315,6 @@ void serdev_device_write_flush(struct serdev_device *serdev)
}
EXPORT_SYMBOL_GPL(serdev_device_write_flush);
-int serdev_device_write_room(struct serdev_device *serdev)
-{
- struct serdev_controller *ctrl = serdev->ctrl;
-
- if (!ctrl || !ctrl->ops->write_room)
- return 0;
-
- return serdev->ctrl->ops->write_room(ctrl);
-}
-EXPORT_SYMBOL_GPL(serdev_device_write_room);
-
unsigned int serdev_device_set_baudrate(struct serdev_device *serdev, unsigned int speed)
{
struct serdev_controller *ctrl = serdev->ctrl;
@@ -794,8 +782,7 @@ int serdev_controller_add(struct serdev_controller *ctrl)
goto err_rpm_disable;
}
- dev_dbg(&ctrl->dev, "serdev%d registered: dev:%p\n",
- ctrl->nr, &ctrl->dev);
+ dev_dbg(&ctrl->dev, "serdev controller registered: dev:%p\n", &ctrl->dev);
return 0;
err_rpm_disable:
diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c
index 3d7ae7fa5018..bab1b143b8a6 100644
--- a/drivers/tty/serdev/serdev-ttyport.c
+++ b/drivers/tty/serdev/serdev-ttyport.c
@@ -92,14 +92,6 @@ static void ttyport_write_flush(struct serdev_controller *ctrl)
tty_driver_flush_buffer(tty);
}
-static int ttyport_write_room(struct serdev_controller *ctrl)
-{
- struct serport *serport = serdev_controller_get_drvdata(ctrl);
- struct tty_struct *tty = serport->tty;
-
- return tty_write_room(tty);
-}
-
static int ttyport_open(struct serdev_controller *ctrl)
{
struct serport *serport = serdev_controller_get_drvdata(ctrl);
@@ -259,7 +251,6 @@ static int ttyport_break_ctl(struct serdev_controller *ctrl, unsigned int break_
static const struct serdev_controller_ops ctrl_ops = {
.write_buf = ttyport_write_buf,
.write_flush = ttyport_write_flush,
- .write_room = ttyport_write_room,
.open = ttyport_open,
.close = ttyport_close,
.set_flow_control = ttyport_set_flow_control,
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index b861585ca02a..18530c31a598 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -223,12 +223,6 @@ static inline bool serial8250_clear_THRI(struct uart_8250_port *up)
struct uart_8250_port *serial8250_setup_port(int index);
struct uart_8250_port *serial8250_get_port(int line);
-void serial8250_rpm_get(struct uart_8250_port *p);
-void serial8250_rpm_put(struct uart_8250_port *p);
-
-void serial8250_rpm_get_tx(struct uart_8250_port *p);
-void serial8250_rpm_put_tx(struct uart_8250_port *p);
-
int serial8250_em485_config(struct uart_port *port, struct ktermios *termios,
struct serial_rs485 *rs485);
void serial8250_em485_start_tx(struct uart_8250_port *p, bool toggle_ier);
diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c
index e5da9ce26006..26fc0464f1cc 100644
--- a/drivers/tty/serial/8250/8250_aspeed_vuart.c
+++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c
@@ -304,7 +304,8 @@ static void aspeed_vuart_unthrottle(struct uart_port *port)
static void aspeed_vuart_unthrottle_exp(struct timer_list *timer)
{
- struct aspeed_vuart *vuart = from_timer(vuart, timer, unthrottle_timer);
+ struct aspeed_vuart *vuart = timer_container_of(vuart, timer,
+ unthrottle_timer);
struct uart_8250_port *up = vuart->port;
if (!tty_buffer_space_avail(&up->port.state->port)) {
@@ -550,7 +551,7 @@ static void aspeed_vuart_remove(struct platform_device *pdev)
{
struct aspeed_vuart *vuart = platform_get_drvdata(pdev);
- del_timer_sync(&vuart->unthrottle_timer);
+ timer_delete_sync(&vuart->unthrottle_timer);
aspeed_vuart_set_enabled(vuart, false);
serial8250_unregister_port(vuart->line);
sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c
index d0b18358859e..742004d63c6f 100644
--- a/drivers/tty/serial/8250/8250_bcm7271.c
+++ b/drivers/tty/serial/8250/8250_bcm7271.c
@@ -1056,8 +1056,7 @@ static int brcmuart_probe(struct platform_device *pdev)
}
/* setup HR timer */
- hrtimer_init(&priv->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
- priv->hrt.function = brcmuart_hrtimer_func;
+ hrtimer_setup(&priv->hrt, brcmuart_hrtimer_func, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
up.port.shutdown = brcmuart_shutdown;
up.port.startup = brcmuart_startup;
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 6f676bb37ac3..7a6050f1c094 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -206,7 +206,7 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up)
*/
static void serial8250_timeout(struct timer_list *t)
{
- struct uart_8250_port *up = from_timer(up, t, timer);
+ struct uart_8250_port *up = timer_container_of(up, t, timer);
up->port.handle_irq(&up->port);
mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port));
@@ -214,7 +214,7 @@ static void serial8250_timeout(struct timer_list *t)
static void serial8250_backup_timeout(struct timer_list *t)
{
- struct uart_8250_port *up = from_timer(up, t, timer);
+ struct uart_8250_port *up = timer_container_of(up, t, timer);
unsigned int iir, ier = 0, lsr;
unsigned long flags;
@@ -298,7 +298,7 @@ static void univ8250_release_irq(struct uart_8250_port *up)
{
struct uart_port *port = &up->port;
- del_timer_sync(&up->timer);
+ timer_delete_sync(&up->timer);
up->timer.function = serial8250_timeout;
if (port->irq)
serial_unlink_irq_chain(up);
@@ -461,7 +461,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx,
char *options)
{
char match[] = "uart"; /* 8250-specific earlycon name */
- unsigned char iotype;
+ enum uart_iotype iotype;
resource_size_t addr;
int i;
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 6afcf27db3b8..1902f29444a1 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -107,11 +107,23 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
return value;
}
+/*
+ * This function is being called as part of the uart_port::serial_out()
+ * routine. Hence, it must not call serial_port_out() or serial_out()
+ * against the modified registers here, i.e. LCR.
+ */
static void dw8250_force_idle(struct uart_port *p)
{
struct uart_8250_port *up = up_to_u8250p(p);
unsigned int lsr;
+ /*
+ * The following call currently performs serial_out()
+ * against the FCR register. Because it differs to LCR
+ * there will be no infinite loop, but if it ever gets
+ * modified, we might need a new custom version of it
+ * that avoids infinite recursion.
+ */
serial8250_clear_and_reinit_fifos(up);
/*
@@ -120,14 +132,19 @@ static void dw8250_force_idle(struct uart_port *p)
* enabled.
*/
if (up->fcr & UART_FCR_ENABLE_FIFO) {
- lsr = p->serial_in(p, UART_LSR);
+ lsr = serial_port_in(p, UART_LSR);
if (!(lsr & UART_LSR_DR))
return;
}
- (void)p->serial_in(p, UART_RX);
+ serial_port_in(p, UART_RX);
}
+/*
+ * This function is being called as part of the uart_port::serial_out()
+ * routine. Hence, it must not call serial_port_out() or serial_out()
+ * against the modified registers here, i.e. LCR.
+ */
static void dw8250_check_lcr(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = to_dw8250_data(p->private_data);
@@ -139,7 +156,7 @@ static void dw8250_check_lcr(struct uart_port *p, int offset, int value)
/* Make sure LCR write wasn't ignored */
while (tries--) {
- unsigned int lcr = p->serial_in(p, offset);
+ unsigned int lcr = serial_port_in(p, offset);
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
return;
@@ -260,7 +277,7 @@ static int dw8250_handle_irq(struct uart_port *p)
{
struct uart_8250_port *up = up_to_u8250p(p);
struct dw8250_data *d = to_dw8250_data(p->private_data);
- unsigned int iir = p->serial_in(p, UART_IIR);
+ unsigned int iir = serial_port_in(p, UART_IIR);
bool rx_timeout = (iir & 0x3f) == UART_IIR_RX_TIMEOUT;
unsigned int quirks = d->pdata->quirks;
unsigned int status;
@@ -281,7 +298,7 @@ static int dw8250_handle_irq(struct uart_port *p)
status = serial_lsr_in(up);
if (!(status & (UART_LSR_DR | UART_LSR_BI)))
- (void) p->serial_in(p, UART_RX);
+ serial_port_in(p, UART_RX);
uart_port_unlock_irqrestore(p, flags);
}
@@ -303,7 +320,7 @@ static int dw8250_handle_irq(struct uart_port *p)
if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
/* Clear the USR */
- (void)p->serial_in(p, d->pdata->usr_reg);
+ serial_port_in(p, d->pdata->usr_reg);
return 1;
}
@@ -390,7 +407,7 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios)
{
struct uart_8250_port *up = up_to_u8250p(p);
- unsigned int mcr = p->serial_in(p, UART_MCR);
+ unsigned int mcr = serial_port_in(p, UART_MCR);
if (up->capabilities & UART_CAP_IRDA) {
if (termios->c_line == N_IRDA)
@@ -398,7 +415,7 @@ static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios)
else
mcr &= ~DW_UART_MCR_SIRE;
- p->serial_out(p, UART_MCR, mcr);
+ serial_port_out(p, UART_MCR, mcr);
}
serial8250_do_set_ldisc(p, termios);
}
@@ -421,6 +438,18 @@ static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
return param == chan->device->dev;
}
+static void dw8250_setup_dma_filter(struct uart_port *p, struct dw8250_data *data)
+{
+ /* Platforms with iDMA 64-bit */
+ if (platform_get_resource_byname(to_platform_device(p->dev), IORESOURCE_MEM, "lpss_priv")) {
+ data->data.dma.rx_param = p->dev->parent;
+ data->data.dma.tx_param = p->dev->parent;
+ data->data.dma.fn = dw8250_idma_filter;
+ } else {
+ data->data.dma.fn = dw8250_fallback_dma_filter;
+ }
+}
+
static u32 dw8250_rzn1_get_dmacr_burst(int max_burst)
{
if (max_burst >= 8)
@@ -459,8 +488,8 @@ static void dw8250_prepare_rx_dma(struct uart_8250_port *p)
static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
{
- unsigned int quirks = data->pdata ? data->pdata->quirks : 0;
- u32 cpr_value = data->pdata ? data->pdata->cpr_value : 0;
+ unsigned int quirks = data->pdata->quirks;
+ u32 cpr_value = data->pdata->cpr_value;
if (quirks & DW_UART_QUIRK_CPR_VALUE)
data->data.cpr_value = cpr_value;
@@ -491,14 +520,6 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
p->serial_in = dw8250_serial_in32;
data->uart_16550_compatible = true;
}
-
- /* Platforms with iDMA 64-bit */
- if (platform_get_resource_byname(to_platform_device(p->dev),
- IORESOURCE_MEM, "lpss_priv")) {
- data->data.dma.rx_param = p->dev->parent;
- data->data.dma.tx_param = p->dev->parent;
- data->data.dma.fn = dw8250_idma_filter;
- }
}
static void dw8250_reset_control_assert(void *data)
@@ -520,7 +541,6 @@ static int dw8250_probe(struct platform_device *pdev)
return dev_err_probe(dev, -EINVAL, "no registers defined\n");
spin_lock_init(&p->lock);
- p->handle_irq = dw8250_handle_irq;
p->pm = dw8250_do_pm;
p->type = PORT_8250;
p->flags = UPF_FIXED_PORT;
@@ -532,13 +552,8 @@ static int dw8250_probe(struct platform_device *pdev)
if (!data)
return -ENOMEM;
- data->data.dma.fn = dw8250_fallback_dma_filter;
- data->pdata = device_get_match_data(p->dev);
p->private_data = &data->data;
- data->uart_16550_compatible = device_property_read_bool(dev,
- "snps,uart-16550-compatible");
-
p->mapbase = regs->start;
p->mapsize = resource_size(regs);
@@ -626,11 +641,19 @@ static int dw8250_probe(struct platform_device *pdev)
if (err)
return err;
- dw8250_quirks(p, data);
+ data->uart_16550_compatible = device_property_read_bool(dev, "snps,uart-16550-compatible");
+
+ data->pdata = device_get_match_data(p->dev);
+ if (data->pdata)
+ dw8250_quirks(p, data);
/* If the Busy Functionality is not implemented, don't handle it */
if (data->uart_16550_compatible)
p->handle_irq = NULL;
+ else if (data->pdata)
+ p->handle_irq = dw8250_handle_irq;
+
+ dw8250_setup_dma_filter(p, data);
if (!data->skip_autocfg)
dw8250_setup_port(p);
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index 842422921765..dc0371857ecb 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -77,6 +77,8 @@ static void serial8250_early_out(struct uart_port *port, int offset, int value)
outb(value, port->iobase + offset);
break;
#endif
+ default:
+ break;
}
}
diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c
index 1b7bd55619c6..649ae5c8304d 100644
--- a/drivers/tty/serial/8250/8250_fsl.c
+++ b/drivers/tty/serial/8250/8250_fsl.c
@@ -32,7 +32,7 @@ int fsl8250_handle_irq(struct uart_port *port)
uart_port_lock_irqsave(&up->port, &flags);
- iir = port->serial_in(port, UART_IIR);
+ iir = serial_port_in(port, UART_IIR);
if (iir & UART_IIR_NO_INT) {
uart_port_unlock_irqrestore(&up->port, flags);
return 0;
@@ -54,12 +54,12 @@ int fsl8250_handle_irq(struct uart_port *port)
if (unlikely((iir & UART_IIR_ID) == UART_IIR_RLSI &&
(up->lsr_saved_flags & UART_LSR_BI))) {
up->lsr_saved_flags &= ~UART_LSR_BI;
- port->serial_in(port, UART_RX);
+ serial_port_in(port, UART_RX);
uart_port_unlock_irqrestore(&up->port, flags);
return 1;
}
- lsr = orig_lsr = up->port.serial_in(&up->port, UART_LSR);
+ lsr = orig_lsr = serial_port_in(port, UART_LSR);
/* Process incoming characters first */
if ((lsr & (UART_LSR_DR | UART_LSR_BI)) &&
@@ -71,7 +71,7 @@ int fsl8250_handle_irq(struct uart_port *port)
if ((orig_lsr & UART_LSR_OE) && (up->overrun_backoff_time_ms > 0)) {
unsigned long delay;
- up->ier = port->serial_in(port, UART_IER);
+ up->ier = serial_port_in(port, UART_IER);
if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
port->ops->stop_rx(port);
} else {
diff --git a/drivers/tty/serial/8250/8250_ni.c b/drivers/tty/serial/8250/8250_ni.c
new file mode 100644
index 000000000000..b0e44fb00b3a
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_ni.c
@@ -0,0 +1,446 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * NI 16550 UART Driver
+ *
+ * The National Instruments (NI) 16550 is a UART that is compatible with the
+ * TL16C550C and OX16C950B register interfaces, but has additional functions
+ * for RS-485 transceiver control. This driver implements support for the
+ * additional functionality on top of the standard serial8250 core.
+ *
+ * Copyright 2012-2023 National Instruments Corporation
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/serial_core.h>
+#include <linux/types.h>
+
+#include "8250.h"
+
+/* Extra bits in UART_ACR */
+#define NI16550_ACR_AUTO_DTR_EN BIT(4)
+
+/* TFS - TX FIFO Size */
+#define NI16550_TFS_OFFSET 0x0C
+/* RFS - RX FIFO Size */
+#define NI16550_RFS_OFFSET 0x0D
+
+/* PMR - Port Mode Register */
+#define NI16550_PMR_OFFSET 0x0E
+/* PMR[1:0] - Port Capabilities */
+#define NI16550_PMR_CAP_MASK GENMASK(1, 0)
+#define NI16550_PMR_NOT_IMPL FIELD_PREP(NI16550_PMR_CAP_MASK, 0) /* not implemented */
+#define NI16550_PMR_CAP_RS232 FIELD_PREP(NI16550_PMR_CAP_MASK, 1) /* RS-232 capable */
+#define NI16550_PMR_CAP_RS485 FIELD_PREP(NI16550_PMR_CAP_MASK, 2) /* RS-485 capable */
+#define NI16550_PMR_CAP_DUAL FIELD_PREP(NI16550_PMR_CAP_MASK, 3) /* dual-port */
+/* PMR[4] - Interface Mode */
+#define NI16550_PMR_MODE_MASK GENMASK(4, 4)
+#define NI16550_PMR_MODE_RS232 FIELD_PREP(NI16550_PMR_MODE_MASK, 0) /* currently 232 */
+#define NI16550_PMR_MODE_RS485 FIELD_PREP(NI16550_PMR_MODE_MASK, 1) /* currently 485 */
+
+/* PCR - Port Control Register */
+/*
+ * Wire Mode | Tx enabled? | Rx enabled?
+ * ---------------|----------------------|--------------------------
+ * PCR_RS422 | Always | Always
+ * PCR_ECHO_RS485 | When DTR asserted | Always
+ * PCR_DTR_RS485 | When DTR asserted | Disabled when TX enabled
+ * PCR_AUTO_RS485 | When data in TX FIFO | Disabled when TX enabled
+ */
+#define NI16550_PCR_OFFSET 0x0F
+#define NI16550_PCR_WIRE_MODE_MASK GENMASK(1, 0)
+#define NI16550_PCR_RS422 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 0)
+#define NI16550_PCR_ECHO_RS485 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 1)
+#define NI16550_PCR_DTR_RS485 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 2)
+#define NI16550_PCR_AUTO_RS485 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 3)
+#define NI16550_PCR_TXVR_ENABLE_BIT BIT(3)
+#define NI16550_PCR_RS485_TERMINATION_BIT BIT(6)
+
+/* flags for ni16550_device_info */
+#define NI_HAS_PMR BIT(0)
+
+struct ni16550_device_info {
+ u32 uartclk;
+ u8 prescaler;
+ u8 flags;
+};
+
+struct ni16550_data {
+ int line;
+ struct clk *clk;
+};
+
+static int ni16550_enable_transceivers(struct uart_port *port)
+{
+ u8 pcr;
+
+ pcr = port->serial_in(port, NI16550_PCR_OFFSET);
+ pcr |= NI16550_PCR_TXVR_ENABLE_BIT;
+ dev_dbg(port->dev, "enable transceivers: write pcr: 0x%02x\n", pcr);
+ port->serial_out(port, NI16550_PCR_OFFSET, pcr);
+
+ return 0;
+}
+
+static int ni16550_disable_transceivers(struct uart_port *port)
+{
+ u8 pcr;
+
+ pcr = serial_port_in(port, NI16550_PCR_OFFSET);
+ pcr &= ~NI16550_PCR_TXVR_ENABLE_BIT;
+ dev_dbg(port->dev, "disable transceivers: write pcr: 0x%02x\n", pcr);
+ serial_port_out(port, NI16550_PCR_OFFSET, pcr);
+
+ return 0;
+}
+
+static int ni16550_rs485_config(struct uart_port *port,
+ struct ktermios *termios,
+ struct serial_rs485 *rs485)
+{
+ struct uart_8250_port *up = container_of(port, struct uart_8250_port, port);
+ u8 pcr;
+
+ pcr = serial_port_in(port, NI16550_PCR_OFFSET);
+ pcr &= ~NI16550_PCR_WIRE_MODE_MASK;
+
+ if ((rs485->flags & SER_RS485_MODE_RS422) ||
+ !(rs485->flags & SER_RS485_ENABLED)) {
+ /* RS-422 */
+ pcr |= NI16550_PCR_RS422;
+ up->acr &= ~NI16550_ACR_AUTO_DTR_EN;
+ } else {
+ /* RS-485 2-wire Auto */
+ pcr |= NI16550_PCR_AUTO_RS485;
+ up->acr |= NI16550_ACR_AUTO_DTR_EN;
+ }
+
+ dev_dbg(port->dev, "config rs485: write pcr: 0x%02x, acr: %02x\n", pcr, up->acr);
+ serial_port_out(port, NI16550_PCR_OFFSET, pcr);
+ serial_icr_write(up, UART_ACR, up->acr);
+
+ return 0;
+}
+
+static bool is_pmr_rs232_mode(struct uart_8250_port *up)
+{
+ u8 pmr = serial_in(up, NI16550_PMR_OFFSET);
+ u8 pmr_mode = pmr & NI16550_PMR_MODE_MASK;
+ u8 pmr_cap = pmr & NI16550_PMR_CAP_MASK;
+
+ /*
+ * If the PMR is not implemented, then by default NI UARTs are
+ * connected to RS-485 transceivers
+ */
+ if (pmr_cap == NI16550_PMR_NOT_IMPL)
+ return false;
+
+ if (pmr_cap == NI16550_PMR_CAP_DUAL)
+ /*
+ * If the port is dual-mode capable, then read the mode bit
+ * to know the current mode
+ */
+ return pmr_mode == NI16550_PMR_MODE_RS232;
+ /*
+ * If it is not dual-mode capable, then decide based on the
+ * capability
+ */
+ return pmr_cap == NI16550_PMR_CAP_RS232;
+}
+
+static void ni16550_config_prescaler(struct uart_8250_port *up,
+ u8 prescaler)
+{
+ /*
+ * Page in the Enhanced Mode Registers
+ * Sets EFR[4] for Enhanced Mode.
+ */
+ u8 lcr_value;
+ u8 efr_value;
+
+ lcr_value = serial_in(up, UART_LCR);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+ efr_value = serial_in(up, UART_EFR);
+ efr_value |= UART_EFR_ECB;
+
+ serial_out(up, UART_EFR, efr_value);
+
+ /* Page out the Enhanced Mode Registers */
+ serial_out(up, UART_LCR, lcr_value);
+
+ /* Set prescaler to CPR register. */
+ serial_out(up, UART_SCR, UART_CPR);
+ serial_out(up, UART_ICR, prescaler);
+}
+
+static const struct serial_rs485 ni16550_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_MODE_RS422 | SER_RS485_RTS_ON_SEND |
+ SER_RS485_RTS_AFTER_SEND,
+ /*
+ * delay_rts_* and RX_DURING_TX are not supported.
+ *
+ * RTS_{ON,AFTER}_SEND are supported, but ignored; the transceiver
+ * is connected in only one way and we don't need userspace to tell
+ * us, but want to retain compatibility with applications that do.
+ */
+};
+
+static void ni16550_rs485_setup(struct uart_port *port)
+{
+ port->rs485_config = ni16550_rs485_config;
+ port->rs485_supported = ni16550_rs485_supported;
+ /*
+ * The hardware comes up by default in 2-wire auto mode and we
+ * set the flags to represent that
+ */
+ port->rs485.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND;
+}
+
+static int ni16550_port_startup(struct uart_port *port)
+{
+ int ret;
+
+ ret = serial8250_do_startup(port);
+ if (ret)
+ return ret;
+
+ return ni16550_enable_transceivers(port);
+}
+
+static void ni16550_port_shutdown(struct uart_port *port)
+{
+ ni16550_disable_transceivers(port);
+
+ serial8250_do_shutdown(port);
+}
+
+static int ni16550_get_regs(struct platform_device *pdev,
+ struct uart_port *port)
+{
+ struct resource *regs;
+
+ regs = platform_get_mem_or_io(pdev, 0);
+ if (!regs)
+ return dev_err_probe(&pdev->dev, -EINVAL, "no registers defined\n");
+
+ switch (resource_type(regs)) {
+ case IORESOURCE_IO:
+ port->iotype = UPIO_PORT;
+ port->iobase = regs->start;
+
+ return 0;
+ case IORESOURCE_MEM:
+ port->iotype = UPIO_MEM;
+ port->mapbase = regs->start;
+ port->mapsize = resource_size(regs);
+ port->flags |= UPF_IOREMAP;
+
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * Very old implementations don't have the TFS or RFS registers
+ * defined, so we may read all-0s or all-1s. For such devices,
+ * assume a FIFO size of 128.
+ */
+static u8 ni16550_read_fifo_size(struct uart_8250_port *uart, int reg)
+{
+ u8 value = serial_in(uart, reg);
+
+ if (value == 0x00 || value == 0xFF)
+ return 128;
+
+ return value;
+}
+
+static void ni16550_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ up->mcr |= UART_MCR_CLKSEL;
+ serial8250_do_set_mctrl(port, mctrl);
+}
+
+static int ni16550_probe(struct platform_device *pdev)
+{
+ const struct ni16550_device_info *info;
+ struct device *dev = &pdev->dev;
+ struct uart_8250_port uart = {};
+ unsigned int txfifosz, rxfifosz;
+ unsigned int prescaler;
+ struct ni16550_data *data;
+ const char *portmode;
+ bool rs232_property;
+ int ret;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ spin_lock_init(&uart.port.lock);
+
+ ret = ni16550_get_regs(pdev, &uart.port);
+ if (ret < 0)
+ return ret;
+
+ /* early setup so that serial_in()/serial_out() work */
+ serial8250_set_defaults(&uart);
+
+ info = device_get_match_data(dev);
+
+ uart.port.dev = dev;
+ uart.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE;
+ uart.port.startup = ni16550_port_startup;
+ uart.port.shutdown = ni16550_port_shutdown;
+
+ /*
+ * Hardware instantiation of FIFO sizes are held in registers.
+ */
+ txfifosz = ni16550_read_fifo_size(&uart, NI16550_TFS_OFFSET);
+ rxfifosz = ni16550_read_fifo_size(&uart, NI16550_RFS_OFFSET);
+
+ dev_dbg(dev, "NI 16550 has TX FIFO size %u, RX FIFO size %u\n",
+ txfifosz, rxfifosz);
+
+ uart.port.type = PORT_16550A;
+ uart.port.fifosize = txfifosz;
+ uart.tx_loadsz = txfifosz;
+ uart.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;
+ uart.capabilities = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR;
+
+ /*
+ * Declaration of the base clock frequency can come from one of:
+ * - static declaration in this driver (for older ACPI IDs)
+ * - a "clock-frequency" ACPI
+ */
+ uart.port.uartclk = info->uartclk;
+
+ ret = uart_read_port_properties(&uart.port);
+ if (ret)
+ return ret;
+
+ if (!uart.port.uartclk) {
+ data->clk = devm_clk_get_enabled(dev, NULL);
+ if (!IS_ERR(data->clk))
+ uart.port.uartclk = clk_get_rate(data->clk);
+ }
+
+ if (!uart.port.uartclk)
+ return dev_err_probe(dev, -ENODEV, "unable to determine clock frequency!\n");
+
+ prescaler = info->prescaler;
+ device_property_read_u32(dev, "clock-prescaler", &prescaler);
+ if (prescaler) {
+ uart.port.set_mctrl = ni16550_set_mctrl;
+ ni16550_config_prescaler(&uart, (u8)prescaler);
+ }
+
+ /*
+ * The determination of whether or not this is an RS-485 or RS-232 port
+ * can come from the PMR (if present), otherwise we're solely an RS-485
+ * port.
+ *
+ * This is a device-specific property, and there are old devices in the
+ * field using "transceiver" as an ACPI property, so we have to check
+ * for that as well.
+ */
+ if (!device_property_read_string(dev, "transceiver", &portmode)) {
+ rs232_property = strncmp(portmode, "RS-232", 6) == 0;
+
+ dev_dbg(dev, "port is in %s mode (via device property)\n",
+ rs232_property ? "RS-232" : "RS-485");
+ } else if (info->flags & NI_HAS_PMR) {
+ rs232_property = is_pmr_rs232_mode(&uart);
+
+ dev_dbg(dev, "port is in %s mode (via PMR)\n",
+ rs232_property ? "RS-232" : "RS-485");
+ } else {
+ rs232_property = 0;
+
+ dev_dbg(dev, "port is fixed as RS-485\n");
+ }
+
+ if (!rs232_property) {
+ /*
+ * Neither the 'transceiver' property nor the PMR indicate
+ * that this is an RS-232 port, so it must be an RS-485 one.
+ */
+ ni16550_rs485_setup(&uart.port);
+ }
+
+ ret = serial8250_register_8250_port(&uart);
+ if (ret < 0)
+ return ret;
+ data->line = ret;
+
+ platform_set_drvdata(pdev, data);
+ return 0;
+}
+
+static void ni16550_remove(struct platform_device *pdev)
+{
+ struct ni16550_data *data = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(data->line);
+}
+
+/* NI 16550 RS-485 Interface */
+static const struct ni16550_device_info nic7750 = {
+ .uartclk = 33333333,
+};
+
+/* NI CVS-145x RS-485 Interface */
+static const struct ni16550_device_info nic7772 = {
+ .uartclk = 1843200,
+ .flags = NI_HAS_PMR,
+};
+
+/* NI cRIO-904x RS-485 Interface */
+static const struct ni16550_device_info nic792b = {
+ /* Sets UART clock rate to 22.222 MHz with 1.125 prescale */
+ .uartclk = 22222222,
+ .prescaler = 0x09,
+};
+
+/* NI sbRIO 96x8 RS-232/485 Interfaces */
+static const struct ni16550_device_info nic7a69 = {
+ /* Set UART clock rate to 29.629 MHz with 1.125 prescale */
+ .uartclk = 29629629,
+ .prescaler = 0x09,
+};
+
+static const struct acpi_device_id ni16550_acpi_match[] = {
+ { "NIC7750", (kernel_ulong_t)&nic7750 },
+ { "NIC7772", (kernel_ulong_t)&nic7772 },
+ { "NIC792B", (kernel_ulong_t)&nic792b },
+ { "NIC7A69", (kernel_ulong_t)&nic7a69 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, ni16550_acpi_match);
+
+static struct platform_driver ni16550_driver = {
+ .driver = {
+ .name = "ni16550",
+ .acpi_match_table = ni16550_acpi_match,
+ },
+ .probe = ni16550_probe,
+ .remove = ni16550_remove,
+};
+
+module_platform_driver(ni16550_driver);
+
+MODULE_AUTHOR("Emerson Electric Co.");
+MODULE_DESCRIPTION("NI 16550 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index 11c860ea80f6..d178b6c54ea1 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -24,6 +24,7 @@
struct of_serial_info {
struct clk *clk;
+ struct clk *bus_clk;
struct reset_control *rst;
int type;
int line;
@@ -123,12 +124,22 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
/* Get clk rate through clk driver if present */
if (!port->uartclk) {
- info->clk = devm_clk_get_enabled(dev, NULL);
+ struct clk *bus_clk;
+
+ bus_clk = devm_clk_get_optional_enabled(dev, "bus");
+ if (IS_ERR(bus_clk)) {
+ ret = dev_err_probe(dev, PTR_ERR(bus_clk), "failed to get bus clock\n");
+ goto err_pmruntime;
+ }
+
+ /* If the bus clock is required, core clock must be named */
+ info->clk = devm_clk_get_enabled(dev, bus_clk ? "core" : NULL);
if (IS_ERR(info->clk)) {
ret = dev_err_probe(dev, PTR_ERR(info->clk), "failed to get clock\n");
goto err_pmruntime;
}
+ info->bus_clk = bus_clk;
port->uartclk = clk_get_rate(info->clk);
}
/* If current-speed was set, then try not to change it. */
@@ -290,6 +301,7 @@ static int of_serial_suspend(struct device *dev)
if (!uart_console(port) || console_suspend_enabled) {
pm_runtime_put_sync(dev);
clk_disable_unprepare(info->clk);
+ clk_disable_unprepare(info->bus_clk);
}
return 0;
}
@@ -302,6 +314,7 @@ static int of_serial_resume(struct device *dev)
if (!uart_console(port) || console_suspend_enabled) {
pm_runtime_get_sync(dev);
+ clk_prepare_enable(info->bus_clk);
clk_prepare_enable(info->clk);
}
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index c2b75e3f106d..72ae08d6204f 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -692,7 +692,7 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
/* Synchronize UART_IER access against the console. */
uart_port_lock(port);
- up->ier = port->serial_in(port, UART_IER);
+ up->ier = serial_port_in(port, UART_IER);
if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
port->ops->stop_rx(port);
} else {
@@ -1173,16 +1173,6 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
return 0;
}
- sg_init_table(&sg, 1);
- ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1,
- UART_XMIT_SIZE, dma->tx_addr);
- if (ret != 1) {
- serial8250_clear_THRI(p);
- return 0;
- }
-
- dma->tx_size = sg_dma_len(&sg);
-
if (priv->habit & OMAP_DMA_TX_KICK) {
unsigned char c;
u8 tx_lvl;
@@ -1207,18 +1197,22 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
ret = -EBUSY;
goto err;
}
- if (dma->tx_size < 4) {
+ if (kfifo_len(&tport->xmit_fifo) < 4) {
ret = -EINVAL;
goto err;
}
- if (!kfifo_get(&tport->xmit_fifo, &c)) {
+ if (!uart_fifo_out(&p->port, &c, 1)) {
ret = -EINVAL;
goto err;
}
skip_byte = c;
- /* now we need to recompute due to kfifo_get */
- kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1,
- UART_XMIT_SIZE, dma->tx_addr);
+ }
+
+ sg_init_table(&sg, 1);
+ ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1, UART_XMIT_SIZE, dma->tx_addr);
+ if (ret != 1) {
+ ret = -EINVAL;
+ goto err;
}
desc = dmaengine_prep_slave_sg(dma->txchan, &sg, 1, DMA_MEM_TO_DEV,
@@ -1228,6 +1222,7 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
goto err;
}
+ dma->tx_size = sg_dma_len(&sg);
dma->tx_running = 1;
desc->callback = omap_8250_dma_tx_complete;
diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c
index e9c51d4e447d..4c149db84692 100644
--- a/drivers/tty/serial/8250/8250_pci1xxxx.c
+++ b/drivers/tty/serial/8250/8250_pci1xxxx.c
@@ -115,6 +115,7 @@
#define UART_RESET_REG 0x94
#define UART_RESET_D3_RESET_DISABLE BIT(16)
+#define UART_RESET_HOT_RESET_DISABLE BIT(17)
#define UART_BURST_STATUS_REG 0x9C
#define UART_TX_BURST_FIFO 0xA0
@@ -620,6 +621,10 @@ static int pci1xxxx_suspend(struct device *dev)
}
data = readl(p + UART_RESET_REG);
+
+ if (priv->dev_rev >= 0xC0)
+ data |= UART_RESET_HOT_RESET_DISABLE;
+
writel(data | UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG);
if (wakeup)
@@ -647,7 +652,12 @@ static int pci1xxxx_resume(struct device *dev)
}
data = readl(p + UART_RESET_REG);
+
+ if (priv->dev_rev >= 0xC0)
+ data &= ~UART_RESET_HOT_RESET_DISABLE;
+
writel(data & ~UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG);
+
iounmap(p);
for (i = 0; i < priv->nr; i++) {
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 442967a6cd52..6d7b8c4667c9 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -517,22 +517,20 @@ void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
}
EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
-void serial8250_rpm_get(struct uart_8250_port *p)
+static void serial8250_rpm_get(struct uart_8250_port *p)
{
if (!(p->capabilities & UART_CAP_RPM))
return;
pm_runtime_get_sync(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_get);
-void serial8250_rpm_put(struct uart_8250_port *p)
+static void serial8250_rpm_put(struct uart_8250_port *p)
{
if (!(p->capabilities & UART_CAP_RPM))
return;
pm_runtime_mark_last_busy(p->port.dev);
pm_runtime_put_autosuspend(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_put);
/**
* serial8250_em485_init() - put uart_8250_port into rs485 emulating
@@ -566,12 +564,10 @@ static int serial8250_em485_init(struct uart_8250_port *p)
if (!p->em485)
return -ENOMEM;
- hrtimer_init(&p->em485->stop_tx_timer, CLOCK_MONOTONIC,
- HRTIMER_MODE_REL);
- hrtimer_init(&p->em485->start_tx_timer, CLOCK_MONOTONIC,
- HRTIMER_MODE_REL);
- p->em485->stop_tx_timer.function = &serial8250_em485_handle_stop_tx;
- p->em485->start_tx_timer.function = &serial8250_em485_handle_start_tx;
+ hrtimer_setup(&p->em485->stop_tx_timer, &serial8250_em485_handle_stop_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ hrtimer_setup(&p->em485->start_tx_timer, &serial8250_em485_handle_start_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
p->em485->port = p;
p->em485->active_timer = NULL;
p->em485->tx_stopped = true;
@@ -649,7 +645,7 @@ EXPORT_SYMBOL_GPL(serial8250_em485_config);
* once and disable_runtime_pm_tx() will still disable RPM because the fifo is
* empty and the HW can idle again.
*/
-void serial8250_rpm_get_tx(struct uart_8250_port *p)
+static void serial8250_rpm_get_tx(struct uart_8250_port *p)
{
unsigned char rpm_active;
@@ -661,9 +657,8 @@ void serial8250_rpm_get_tx(struct uart_8250_port *p)
return;
pm_runtime_get_sync(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_get_tx);
-void serial8250_rpm_put_tx(struct uart_8250_port *p)
+static void serial8250_rpm_put_tx(struct uart_8250_port *p)
{
unsigned char rpm_active;
@@ -676,7 +671,6 @@ void serial8250_rpm_put_tx(struct uart_8250_port *p)
pm_runtime_mark_last_busy(p->port.dev);
pm_runtime_put_autosuspend(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_put_tx);
/*
* IER sleep support. UARTs which have EFRs need the "extended
@@ -1680,7 +1674,7 @@ static void serial8250_disable_ms(struct uart_port *port)
if (up->bugs & UART_BUG_NOMSR)
return;
- mctrl_gpio_disable_ms(up->gpios);
+ mctrl_gpio_disable_ms_no_sync(up->gpios);
up->ier &= ~UART_IER_MSI;
serial_port_out(port, UART_IER, up->ier);
@@ -2408,28 +2402,26 @@ int serial8250_do_startup(struct uart_port *port)
* test if we receive TX irq. This way, we'll never enable
* UART_BUG_TXEN.
*/
- if (up->port.quirks & UPQ_NO_TXEN_TEST)
- goto dont_test_tx_en;
-
- /*
- * Do a quick test to see if we receive an interrupt when we enable
- * the TX irq.
- */
- serial_port_out(port, UART_IER, UART_IER_THRI);
- lsr = serial_port_in(port, UART_LSR);
- iir = serial_port_in(port, UART_IIR);
- serial_port_out(port, UART_IER, 0);
+ if (!(up->port.quirks & UPQ_NO_TXEN_TEST)) {
+ /*
+ * Do a quick test to see if we receive an interrupt when we
+ * enable the TX irq.
+ */
+ serial_port_out(port, UART_IER, UART_IER_THRI);
+ lsr = serial_port_in(port, UART_LSR);
+ iir = serial_port_in(port, UART_IIR);
+ serial_port_out(port, UART_IER, 0);
- if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
- if (!(up->bugs & UART_BUG_TXEN)) {
- up->bugs |= UART_BUG_TXEN;
- dev_dbg(port->dev, "enabling bad tx status workarounds\n");
+ if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
+ if (!(up->bugs & UART_BUG_TXEN)) {
+ up->bugs |= UART_BUG_TXEN;
+ dev_dbg(port->dev, "enabling bad tx status workarounds\n");
+ }
+ } else {
+ up->bugs &= ~UART_BUG_TXEN;
}
- } else {
- up->bugs &= ~UART_BUG_TXEN;
}
-dont_test_tx_en:
uart_port_unlock_irqrestore(port, flags);
/*
@@ -2970,7 +2962,6 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
{
unsigned int size = serial8250_port_size(up);
struct uart_port *port = &up->port;
- int ret = 0;
switch (port->iotype) {
case UPIO_AU:
@@ -2979,32 +2970,30 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
case UPIO_MEM32BE:
case UPIO_MEM16:
case UPIO_MEM:
- if (!port->mapbase) {
- ret = -EINVAL;
- break;
- }
+ if (!port->mapbase)
+ return -EINVAL;
- if (!request_mem_region(port->mapbase, size, "serial")) {
- ret = -EBUSY;
- break;
- }
+ if (!request_mem_region(port->mapbase, size, "serial"))
+ return -EBUSY;
if (port->flags & UPF_IOREMAP) {
port->membase = ioremap(port->mapbase, size);
if (!port->membase) {
release_mem_region(port->mapbase, size);
- ret = -ENOMEM;
+ return -ENOMEM;
}
}
- break;
-
+ return 0;
case UPIO_HUB6:
case UPIO_PORT:
if (!request_region(port->iobase, size, "serial"))
- ret = -EBUSY;
+ return -EBUSY;
+ return 0;
+ case UPIO_UNKNOWN:
break;
}
- return ret;
+
+ return 0;
}
static void serial8250_release_std_resource(struct uart_8250_port *up)
@@ -3034,6 +3023,8 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
case UPIO_PORT:
release_region(port->iobase, size);
break;
+ case UPIO_UNKNOWN:
+ break;
}
}
diff --git a/drivers/tty/serial/8250/8250_rsa.c b/drivers/tty/serial/8250/8250_rsa.c
index dfaa613e452d..4c8b9671bd41 100644
--- a/drivers/tty/serial/8250/8250_rsa.c
+++ b/drivers/tty/serial/8250/8250_rsa.c
@@ -16,36 +16,35 @@ static unsigned int probe_rsa_count;
static int rsa8250_request_resource(struct uart_8250_port *up)
{
- unsigned long start = UART_RSA_BASE << up->port.regshift;
- unsigned int size = 8 << up->port.regshift;
struct uart_port *port = &up->port;
- int ret = -EINVAL;
+ unsigned long start = UART_RSA_BASE << port->regshift;
+ unsigned int size = 8 << port->regshift;
switch (port->iotype) {
case UPIO_HUB6:
case UPIO_PORT:
start += port->iobase;
- if (request_region(start, size, "serial-rsa"))
- ret = 0;
- else
- ret = -EBUSY;
- break;
+ if (!request_region(start, size, "serial-rsa"))
+ return -EBUSY;
+ return 0;
+ default:
+ return -EINVAL;
}
-
- return ret;
}
static void rsa8250_release_resource(struct uart_8250_port *up)
{
- unsigned long offset = UART_RSA_BASE << up->port.regshift;
- unsigned int size = 8 << up->port.regshift;
struct uart_port *port = &up->port;
+ unsigned long offset = UART_RSA_BASE << port->regshift;
+ unsigned int size = 8 << port->regshift;
switch (port->iotype) {
case UPIO_HUB6:
case UPIO_PORT:
release_region(port->iobase + offset, size);
break;
+ default:
+ break;
}
}
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 55d26d16df9b..f64ef0819cd4 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -569,6 +569,19 @@ config SERIAL_8250_BCM7271
including DMA support and high accuracy BAUD rates, say
Y to this option. If unsure, say N.
+config SERIAL_8250_NI
+ tristate "NI 16550 based serial port"
+ depends on SERIAL_8250
+ depends on X86 || COMPILE_TEST
+ help
+ This driver supports the integrated serial ports on National
+ Instruments (NI) controller hardware. This is required for all NI
+ controller models with onboard RS-485 or dual-mode RS-485/RS-232
+ ports.
+
+ To compile this driver as a module, choose M here: the module
+ will be called 8250_ni.
+
config SERIAL_OF_PLATFORM
tristate "Devicetree based probing for 8250 ports"
depends on SERIAL_8250 && OF
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 1516de629b61..b04eeda03b23 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o
obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o
obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o
obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
+obj-$(CONFIG_SERIAL_8250_NI) += 8250_ni.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o
obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o
obj-$(CONFIG_SERIAL_8250_PARISC) += 8250_parisc.o
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 976dae3bb1bb..79a8186d3361 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -179,25 +179,6 @@ config SERIAL_ATMEL_TTYAT
Say Y if you have an external 8250/16C550 UART. If unsure, say N.
-config SERIAL_KGDB_NMI
- bool "Serial console over KGDB NMI debugger port"
- depends on KGDB_SERIAL_CONSOLE
- help
- This special driver allows you to temporary use NMI debugger port
- as a normal console (assuming that the port is attached to KGDB).
-
- Unlike KDB's disable_nmi command, with this driver you are always
- able to go back to the debugger using KGDB escape sequence ($3#33).
- This is because this console driver processes the input in NMI
- context, and thus is able to intercept the magic sequence.
-
- Note that since the console interprets input and uses polling
- communication methods, for things like PPP you still must fully
- detach debugger port from the KGDB NMI (i.e. disable_nmi), and
- use raw console.
-
- If unsure, say N.
-
config SERIAL_MESON
tristate "Meson serial port support"
depends on ARCH_MESON || COMPILE_TEST
@@ -306,6 +287,29 @@ config SERIAL_TEGRA_TCU_CONSOLE
If unsure, say Y.
+config SERIAL_TEGRA_UTC
+ tristate "NVIDIA Tegra UART Trace Controller"
+ depends on ARCH_TEGRA || COMPILE_TEST
+ select SERIAL_CORE
+ help
+ Support for Tegra UTC (UART Trace controller) client serial port.
+
+ UTC is a HW based serial port that allows multiplexing multiple data
+ streams of up to 16 UTC clients into a single hardware serial port.
+
+config SERIAL_TEGRA_UTC_CONSOLE
+ bool "Support for console on a Tegra UTC serial port"
+ depends on SERIAL_TEGRA_UTC
+ select SERIAL_CORE_CONSOLE
+ default SERIAL_TEGRA_UTC
+ help
+ If you say Y here, it will be possible to use a Tegra UTC client as
+ the system console (the system console is the device which receives
+ all kernel messages and warnings and which allows logins in single
+ user mode).
+
+ If unsure, say Y.
+
config SERIAL_MAX3100
tristate "MAX3100/3110/3111/3222 support"
depends on SPI
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 6ff74f0a9530..d58d9f719889 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -86,6 +86,7 @@ obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o
obj-$(CONFIG_SERIAL_SUNPLUS) += sunplus-uart.o
obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o
obj-$(CONFIG_SERIAL_TEGRA_TCU) += tegra-tcu.o
+obj-$(CONFIG_SERIAL_TEGRA_UTC) += tegra-utc.o
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
@@ -96,6 +97,5 @@ obj-$(CONFIG_SERIAL_ZS) += zs.o
# GPIOLIB helpers for modem control lines
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
-obj-$(CONFIG_SERIAL_KGDB_NMI) += kgdb_nmi.o
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
obj-$(CONFIG_SERIAL_NUVOTON_MA35D1) += ma35d1_serial.o
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index 1759137121cc..837991dc4db9 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -275,7 +275,7 @@ static irqreturn_t altera_uart_interrupt(int irq, void *data)
static void altera_uart_timer(struct timer_list *t)
{
- struct altera_uart *pp = from_timer(pp, t, tmr);
+ struct altera_uart *pp = timer_container_of(pp, t, tmr);
struct uart_port *port = &pp->port;
altera_uart_interrupt(0, port);
@@ -339,7 +339,7 @@ static void altera_uart_shutdown(struct uart_port *port)
if (port->irq)
free_irq(port->irq, port);
else
- del_timer_sync(&pp->tmr);
+ timer_delete_sync(&pp->tmr);
}
static const char *altera_uart_type(struct uart_port *port)
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 04212c823a91..22939841b1de 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -272,6 +272,7 @@ struct uart_amba_port {
enum pl011_rs485_tx_state rs485_tx_state;
struct hrtimer trigger_start_tx;
struct hrtimer trigger_stop_tx;
+ bool console_line_ended;
#ifdef CONFIG_DMA_ENGINE
/* DMA stuff */
unsigned int dmacr; /* dma control reg */
@@ -1045,7 +1046,7 @@ static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
*/
static void pl011_dma_rx_poll(struct timer_list *t)
{
- struct uart_amba_port *uap = from_timer(uap, t, dmarx.timer);
+ struct uart_amba_port *uap = timer_container_of(uap, t, dmarx.timer);
struct tty_port *port = &uap->port.state->port;
struct pl011_dmarx_data *dmarx = &uap->dmarx;
struct dma_chan *rxchan = uap->dmarx.chan;
@@ -1083,7 +1084,7 @@ static void pl011_dma_rx_poll(struct timer_list *t)
uap->dmarx.running = false;
dmaengine_terminate_all(rxchan);
- del_timer(&uap->dmarx.timer);
+ timer_delete(&uap->dmarx.timer);
} else {
mod_timer(&uap->dmarx.timer,
jiffies + msecs_to_jiffies(uap->dmarx.poll_rate));
@@ -1198,7 +1199,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a, DMA_FROM_DEVICE);
pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_b, DMA_FROM_DEVICE);
if (uap->dmarx.poll_rate)
- del_timer_sync(&uap->dmarx.timer);
+ timer_delete_sync(&uap->dmarx.timer);
uap->using_rx_dma = false;
}
}
@@ -2366,50 +2367,7 @@ static void pl011_console_putchar(struct uart_port *port, unsigned char ch)
while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
cpu_relax();
pl011_write(ch, uap, REG_DR);
-}
-
-static void
-pl011_console_write(struct console *co, const char *s, unsigned int count)
-{
- struct uart_amba_port *uap = amba_ports[co->index];
- unsigned int old_cr = 0, new_cr;
- unsigned long flags;
- int locked = 1;
-
- clk_enable(uap->clk);
-
- if (oops_in_progress)
- locked = uart_port_trylock_irqsave(&uap->port, &flags);
- else
- uart_port_lock_irqsave(&uap->port, &flags);
-
- /*
- * First save the CR then disable the interrupts
- */
- if (!uap->vendor->always_enabled) {
- old_cr = pl011_read(uap, REG_CR);
- new_cr = old_cr & ~UART011_CR_CTSEN;
- new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
- pl011_write(new_cr, uap, REG_CR);
- }
-
- uart_console_write(&uap->port, s, count, pl011_console_putchar);
-
- /*
- * Finally, wait for transmitter to become empty and restore the
- * TCR. Allow feature register bits to be inverted to work around
- * errata.
- */
- while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr)
- & uap->vendor->fr_busy)
- cpu_relax();
- if (!uap->vendor->always_enabled)
- pl011_write(old_cr, uap, REG_CR);
-
- if (locked)
- uart_port_unlock_irqrestore(&uap->port, flags);
-
- clk_disable(uap->clk);
+ uap->console_line_ended = (ch == '\n');
}
static void pl011_console_get_options(struct uart_amba_port *uap, int *baud,
@@ -2472,6 +2430,8 @@ static int pl011_console_setup(struct console *co, char *options)
if (ret)
return ret;
+ uap->console_line_ended = true;
+
if (dev_get_platdata(uap->port.dev)) {
struct amba_pl011_data *plat;
@@ -2516,7 +2476,7 @@ static int pl011_console_setup(struct console *co, char *options)
static int pl011_console_match(struct console *co, char *name, int idx,
char *options)
{
- unsigned char iotype;
+ enum uart_iotype iotype;
resource_size_t addr;
int i;
@@ -2555,14 +2515,105 @@ static int pl011_console_match(struct console *co, char *name, int idx,
return -ENODEV;
}
+static void
+pl011_console_write_atomic(struct console *co, struct nbcon_write_context *wctxt)
+{
+ struct uart_amba_port *uap = amba_ports[co->index];
+ unsigned int old_cr = 0;
+
+ if (!nbcon_enter_unsafe(wctxt))
+ return;
+
+ clk_enable(uap->clk);
+
+ if (!uap->vendor->always_enabled) {
+ old_cr = pl011_read(uap, REG_CR);
+ pl011_write((old_cr & ~UART011_CR_CTSEN) | (UART01x_CR_UARTEN | UART011_CR_TXE),
+ uap, REG_CR);
+ }
+
+ if (!uap->console_line_ended)
+ uart_console_write(&uap->port, "\n", 1, pl011_console_putchar);
+ uart_console_write(&uap->port, wctxt->outbuf, wctxt->len, pl011_console_putchar);
+
+ while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr) & uap->vendor->fr_busy)
+ cpu_relax();
+
+ if (!uap->vendor->always_enabled)
+ pl011_write(old_cr, uap, REG_CR);
+
+ clk_disable(uap->clk);
+
+ nbcon_exit_unsafe(wctxt);
+}
+
+static void
+pl011_console_write_thread(struct console *co, struct nbcon_write_context *wctxt)
+{
+ struct uart_amba_port *uap = amba_ports[co->index];
+ unsigned int old_cr = 0;
+
+ if (!nbcon_enter_unsafe(wctxt))
+ return;
+
+ clk_enable(uap->clk);
+
+ if (!uap->vendor->always_enabled) {
+ old_cr = pl011_read(uap, REG_CR);
+ pl011_write((old_cr & ~UART011_CR_CTSEN) | (UART01x_CR_UARTEN | UART011_CR_TXE),
+ uap, REG_CR);
+ }
+
+ if (nbcon_exit_unsafe(wctxt)) {
+ int i;
+ unsigned int len = READ_ONCE(wctxt->len);
+
+ for (i = 0; i < len; i++) {
+ if (!nbcon_enter_unsafe(wctxt))
+ break;
+ uart_console_write(&uap->port, wctxt->outbuf + i, 1, pl011_console_putchar);
+ if (!nbcon_exit_unsafe(wctxt))
+ break;
+ }
+ }
+
+ while (!nbcon_enter_unsafe(wctxt))
+ nbcon_reacquire_nobuf(wctxt);
+
+ while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr) & uap->vendor->fr_busy)
+ cpu_relax();
+
+ if (!uap->vendor->always_enabled)
+ pl011_write(old_cr, uap, REG_CR);
+
+ clk_disable(uap->clk);
+
+ nbcon_exit_unsafe(wctxt);
+}
+
+static void
+pl011_console_device_lock(struct console *co, unsigned long *flags)
+{
+ __uart_port_lock_irqsave(&amba_ports[co->index]->port, flags);
+}
+
+static void
+pl011_console_device_unlock(struct console *co, unsigned long flags)
+{
+ __uart_port_unlock_irqrestore(&amba_ports[co->index]->port, flags);
+}
+
static struct uart_driver amba_reg;
static struct console amba_console = {
.name = "ttyAMA",
- .write = pl011_console_write,
.device = uart_console_device,
.setup = pl011_console_setup,
.match = pl011_console_match,
- .flags = CON_PRINTBUFFER | CON_ANYTIME,
+ .write_atomic = pl011_console_write_atomic,
+ .write_thread = pl011_console_write_thread,
+ .device_lock = pl011_console_device_lock,
+ .device_unlock = pl011_console_device_unlock,
+ .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_NBCON,
.index = -1,
.data = &amba_reg,
};
@@ -2867,11 +2918,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
return -EINVAL;
}
}
-
- hrtimer_init(&uap->trigger_start_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- hrtimer_init(&uap->trigger_stop_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- uap->trigger_start_tx.function = pl011_trigger_start_tx;
- uap->trigger_stop_tx.function = pl011_trigger_stop_tx;
+ hrtimer_setup(&uap->trigger_start_tx, pl011_trigger_start_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ hrtimer_setup(&uap->trigger_stop_tx, pl011_trigger_stop_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr);
if (ret)
@@ -3001,7 +3051,7 @@ static const struct of_device_id sbsa_uart_of_match[] = {
};
MODULE_DEVICE_TABLE(of, sbsa_uart_of_match);
-static const struct acpi_device_id __maybe_unused sbsa_uart_acpi_match[] = {
+static const struct acpi_device_id sbsa_uart_acpi_match[] = {
{ "ARMH0011", 0 },
{ "ARMHB000", 0 },
{},
@@ -3014,8 +3064,8 @@ static struct platform_driver arm_sbsa_uart_platform_driver = {
.driver = {
.name = "sbsa-uart",
.pm = &pl011_dev_pm_ops,
- .of_match_table = of_match_ptr(sbsa_uart_of_match),
- .acpi_match_table = ACPI_PTR(sbsa_uart_acpi_match),
+ .of_match_table = sbsa_uart_of_match,
+ .acpi_match_table = sbsa_uart_acpi_match,
.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
},
};
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index f44f9d20a974..08dd8f887956 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -700,7 +700,7 @@ static void atmel_disable_ms(struct uart_port *port)
atmel_port->ms_irq_enabled = false;
- mctrl_gpio_disable_ms(atmel_port->gpios);
+ mctrl_gpio_disable_ms_no_sync(atmel_port->gpios);
if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS))
idr |= ATMEL_US_CTSIC;
@@ -1266,8 +1266,8 @@ chan_err:
static void atmel_uart_timer_callback(struct timer_list *t)
{
- struct atmel_uart_port *atmel_port = from_timer(atmel_port, t,
- uart_timer);
+ struct atmel_uart_port *atmel_port = timer_container_of(atmel_port, t,
+ uart_timer);
struct uart_port *port = &atmel_port->uart;
if (!atomic_read(&atmel_port->tasklet_shutdown)) {
@@ -2017,7 +2017,7 @@ static void atmel_shutdown(struct uart_port *port)
* Prevent any tasklets being scheduled during
* cleanup
*/
- del_timer_sync(&atmel_port->uart_timer);
+ timer_delete_sync(&atmel_port->uart_timer);
/* Make sure that no interrupt is on the fly */
synchronize_irq(port->irq);
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 9fdb66f2fcb8..2790b4078e7e 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -403,6 +403,8 @@ static inline void lpuart32_write(struct uart_port *port, u32 val,
case UPIO_MEM32BE:
iowrite32be(val, port->membase + off);
break;
+ default:
+ break;
}
}
@@ -441,36 +443,36 @@ static unsigned int lpuart_get_baud_clk_rate(struct lpuart_port *sport)
static void lpuart_stop_tx(struct uart_port *port)
{
- u8 temp;
+ u8 cr2;
- temp = readb(port->membase + UARTCR2);
- temp &= ~(UARTCR2_TIE | UARTCR2_TCIE);
- writeb(temp, port->membase + UARTCR2);
+ cr2 = readb(port->membase + UARTCR2);
+ cr2 &= ~(UARTCR2_TIE | UARTCR2_TCIE);
+ writeb(cr2, port->membase + UARTCR2);
}
static void lpuart32_stop_tx(struct uart_port *port)
{
- u32 temp;
+ u32 ctrl;
- temp = lpuart32_read(port, UARTCTRL);
- temp &= ~(UARTCTRL_TIE | UARTCTRL_TCIE);
- lpuart32_write(port, temp, UARTCTRL);
+ ctrl = lpuart32_read(port, UARTCTRL);
+ ctrl &= ~(UARTCTRL_TIE | UARTCTRL_TCIE);
+ lpuart32_write(port, ctrl, UARTCTRL);
}
static void lpuart_stop_rx(struct uart_port *port)
{
- u8 temp;
+ u8 cr2;
- temp = readb(port->membase + UARTCR2);
- writeb(temp & ~UARTCR2_RE, port->membase + UARTCR2);
+ cr2 = readb(port->membase + UARTCR2);
+ writeb(cr2 & ~UARTCR2_RE, port->membase + UARTCR2);
}
static void lpuart32_stop_rx(struct uart_port *port)
{
- u32 temp;
+ u32 ctrl;
- temp = lpuart32_read(port, UARTCTRL);
- lpuart32_write(port, temp & ~UARTCTRL_RE, UARTCTRL);
+ ctrl = lpuart32_read(port, UARTCTRL);
+ lpuart32_write(port, ctrl & ~UARTCTRL_RE, UARTCTRL);
}
static void lpuart_dma_tx(struct lpuart_port *sport)
@@ -563,8 +565,9 @@ static dma_addr_t lpuart_dma_datareg_addr(struct lpuart_port *sport)
return sport->port.mapbase + UARTDATA;
case UPIO_MEM32BE:
return sport->port.mapbase + UARTDATA + sizeof(u32) - 1;
+ default:
+ return sport->port.mapbase + UARTDR;
}
- return sport->port.mapbase + UARTDR;
}
static int lpuart_dma_tx_request(struct uart_port *port)
@@ -599,7 +602,7 @@ static void lpuart_flush_buffer(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
struct dma_chan *chan = sport->dma_tx_chan;
- u32 val;
+ u32 fifo;
if (sport->lpuart_dma_tx_use) {
if (sport->dma_tx_in_progress) {
@@ -611,13 +614,13 @@ static void lpuart_flush_buffer(struct uart_port *port)
}
if (lpuart_is_32(sport)) {
- val = lpuart32_read(port, UARTFIFO);
- val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
- lpuart32_write(port, val, UARTFIFO);
+ fifo = lpuart32_read(port, UARTFIFO);
+ fifo |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
+ lpuart32_write(port, fifo, UARTFIFO);
} else {
- val = readb(port->membase + UARTCFIFO);
- val |= UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH;
- writeb(val, port->membase + UARTCFIFO);
+ fifo = readb(port->membase + UARTCFIFO);
+ fifo |= UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH;
+ writeb(fifo, port->membase + UARTCFIFO);
}
}
@@ -640,7 +643,7 @@ static void lpuart32_wait_bit_set(struct uart_port *port, unsigned int offset,
static int lpuart_poll_init(struct uart_port *port)
{
unsigned long flags;
- u8 temp;
+ u8 fifo;
port->fifosize = 0;
@@ -648,9 +651,9 @@ static int lpuart_poll_init(struct uart_port *port)
/* Disable Rx & Tx */
writeb(0, port->membase + UARTCR2);
- temp = readb(port->membase + UARTPFIFO);
+ fifo = readb(port->membase + UARTPFIFO);
/* Enable Rx and Tx FIFO */
- writeb(temp | UARTPFIFO_RXFE | UARTPFIFO_TXFE,
+ writeb(fifo | UARTPFIFO_RXFE | UARTPFIFO_TXFE,
port->membase + UARTPFIFO);
/* flush Tx and Rx FIFO */
@@ -691,7 +694,7 @@ static int lpuart_poll_get_char(struct uart_port *port)
static int lpuart32_poll_init(struct uart_port *port)
{
unsigned long flags;
- u32 temp;
+ u32 fifo;
port->fifosize = 0;
@@ -700,10 +703,10 @@ static int lpuart32_poll_init(struct uart_port *port)
/* Disable Rx & Tx */
lpuart32_write(port, 0, UARTCTRL);
- temp = lpuart32_read(port, UARTFIFO);
+ fifo = lpuart32_read(port, UARTFIFO);
/* Enable Rx and Tx FIFO */
- lpuart32_write(port, temp | UARTFIFO_RXFE | UARTFIFO_TXFE, UARTFIFO);
+ lpuart32_write(port, fifo | UARTFIFO_RXFE | UARTFIFO_TXFE, UARTFIFO);
/* flush Tx and Rx FIFO */
lpuart32_write(port, UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH, UARTFIFO);
@@ -786,10 +789,10 @@ static void lpuart_start_tx(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
- u8 temp;
+ u8 cr2;
- temp = readb(port->membase + UARTCR2);
- writeb(temp | UARTCR2_TIE, port->membase + UARTCR2);
+ cr2 = readb(port->membase + UARTCR2);
+ writeb(cr2 | UARTCR2_TIE, port->membase + UARTCR2);
if (sport->lpuart_dma_tx_use) {
if (!lpuart_stopped_or_empty(port))
@@ -803,14 +806,14 @@ static void lpuart_start_tx(struct uart_port *port)
static void lpuart32_start_tx(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
- u32 temp;
+ u32 ctrl;
if (sport->lpuart_dma_tx_use) {
if (!lpuart_stopped_or_empty(port))
lpuart_dma_tx(sport);
} else {
- temp = lpuart32_read(port, UARTCTRL);
- lpuart32_write(port, temp | UARTCTRL_TIE, UARTCTRL);
+ ctrl = lpuart32_read(port, UARTCTRL);
+ lpuart32_write(port, ctrl | UARTCTRL_TIE, UARTCTRL);
if (lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE)
lpuart32_transmit_buffer(sport);
@@ -1304,7 +1307,7 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id)
*/
static void lpuart_timer_func(struct timer_list *t)
{
- struct lpuart_port *sport = from_timer(sport, t, lpuart_timer);
+ struct lpuart_port *sport = timer_container_of(sport, t, lpuart_timer);
enum dma_status dmastat;
struct dma_chan *chan = sport->dma_rx_chan;
struct circ_buf *ring = &sport->rx_ring;
@@ -1408,9 +1411,9 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
dma_async_issue_pending(chan);
if (lpuart_is_32(sport)) {
- u32 temp = lpuart32_read(&sport->port, UARTBAUD);
+ u32 baud = lpuart32_read(&sport->port, UARTBAUD);
- lpuart32_write(&sport->port, temp | UARTBAUD_RDMAE, UARTBAUD);
+ lpuart32_write(&sport->port, baud | UARTBAUD_RDMAE, UARTBAUD);
if (sport->dma_idle_int) {
u32 ctrl = lpuart32_read(&sport->port, UARTCTRL);
@@ -1433,7 +1436,7 @@ static void lpuart_dma_rx_free(struct uart_port *port)
dmaengine_terminate_sync(chan);
if (!sport->dma_idle_int)
- del_timer_sync(&sport->lpuart_timer);
+ timer_delete_sync(&sport->lpuart_timer);
dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
kfree(sport->rx_ring.buf);
@@ -1517,10 +1520,10 @@ static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termio
static unsigned int lpuart_get_mctrl(struct uart_port *port)
{
unsigned int mctrl = 0;
- u8 reg;
+ u8 cr1;
- reg = readb(port->membase + UARTCR1);
- if (reg & UARTCR1_LOOPS)
+ cr1 = readb(port->membase + UARTCR1);
+ if (cr1 & UARTCR1_LOOPS)
mctrl |= TIOCM_LOOP;
return mctrl;
@@ -1529,10 +1532,10 @@ static unsigned int lpuart_get_mctrl(struct uart_port *port)
static unsigned int lpuart32_get_mctrl(struct uart_port *port)
{
unsigned int mctrl = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
- u32 reg;
+ u32 ctrl;
- reg = lpuart32_read(port, UARTCTRL);
- if (reg & UARTCTRL_LOOPS)
+ ctrl = lpuart32_read(port, UARTCTRL);
+ if (ctrl & UARTCTRL_LOOPS)
mctrl |= TIOCM_LOOP;
return mctrl;
@@ -1540,49 +1543,49 @@ static unsigned int lpuart32_get_mctrl(struct uart_port *port)
static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- u8 reg;
+ u8 cr1;
- reg = readb(port->membase + UARTCR1);
+ cr1 = readb(port->membase + UARTCR1);
/* for internal loopback we need LOOPS=1 and RSRC=0 */
- reg &= ~(UARTCR1_LOOPS | UARTCR1_RSRC);
+ cr1 &= ~(UARTCR1_LOOPS | UARTCR1_RSRC);
if (mctrl & TIOCM_LOOP)
- reg |= UARTCR1_LOOPS;
+ cr1 |= UARTCR1_LOOPS;
- writeb(reg, port->membase + UARTCR1);
+ writeb(cr1, port->membase + UARTCR1);
}
static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- u32 reg;
+ u32 ctrl;
- reg = lpuart32_read(port, UARTCTRL);
+ ctrl = lpuart32_read(port, UARTCTRL);
/* for internal loopback we need LOOPS=1 and RSRC=0 */
- reg &= ~(UARTCTRL_LOOPS | UARTCTRL_RSRC);
+ ctrl &= ~(UARTCTRL_LOOPS | UARTCTRL_RSRC);
if (mctrl & TIOCM_LOOP)
- reg |= UARTCTRL_LOOPS;
+ ctrl |= UARTCTRL_LOOPS;
- lpuart32_write(port, reg, UARTCTRL);
+ lpuart32_write(port, ctrl, UARTCTRL);
}
static void lpuart_break_ctl(struct uart_port *port, int break_state)
{
- u8 temp;
+ u8 cr2;
- temp = readb(port->membase + UARTCR2) & ~UARTCR2_SBK;
+ cr2 = readb(port->membase + UARTCR2) & ~UARTCR2_SBK;
if (break_state != 0)
- temp |= UARTCR2_SBK;
+ cr2 |= UARTCR2_SBK;
- writeb(temp, port->membase + UARTCR2);
+ writeb(cr2, port->membase + UARTCR2);
}
static void lpuart32_break_ctl(struct uart_port *port, int break_state)
{
- u32 temp;
+ u32 ctrl;
- temp = lpuart32_read(port, UARTCTRL);
+ ctrl = lpuart32_read(port, UARTCTRL);
/*
* LPUART IP now has two known bugs, one is CTS has higher priority than the
@@ -1599,22 +1602,22 @@ static void lpuart32_break_ctl(struct uart_port *port, int break_state)
* Disable the transmitter to prevent any data from being sent out
* during break, then invert the TX line to send break.
*/
- temp &= ~UARTCTRL_TE;
- lpuart32_write(port, temp, UARTCTRL);
- temp |= UARTCTRL_TXINV;
- lpuart32_write(port, temp, UARTCTRL);
+ ctrl &= ~UARTCTRL_TE;
+ lpuart32_write(port, ctrl, UARTCTRL);
+ ctrl |= UARTCTRL_TXINV;
+ lpuart32_write(port, ctrl, UARTCTRL);
} else {
/* Disable the TXINV to turn off break and re-enable transmitter. */
- temp &= ~UARTCTRL_TXINV;
- lpuart32_write(port, temp, UARTCTRL);
- temp |= UARTCTRL_TE;
- lpuart32_write(port, temp, UARTCTRL);
+ ctrl &= ~UARTCTRL_TXINV;
+ lpuart32_write(port, ctrl, UARTCTRL);
+ ctrl |= UARTCTRL_TE;
+ lpuart32_write(port, ctrl, UARTCTRL);
}
}
static void lpuart_setup_watermark(struct lpuart_port *sport)
{
- u8 val, cr2, cr2_saved;
+ u8 fifo, cr2, cr2_saved;
cr2 = readb(sport->port.membase + UARTCR2);
cr2_saved = cr2;
@@ -1622,8 +1625,8 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
UARTCR2_RIE | UARTCR2_RE);
writeb(cr2, sport->port.membase + UARTCR2);
- val = readb(sport->port.membase + UARTPFIFO);
- writeb(val | UARTPFIFO_TXFE | UARTPFIFO_RXFE,
+ fifo = readb(sport->port.membase + UARTPFIFO);
+ writeb(fifo | UARTPFIFO_TXFE | UARTPFIFO_RXFE,
sport->port.membase + UARTPFIFO);
/* flush Tx and Rx FIFO */
@@ -1693,14 +1696,14 @@ static void lpuart32_setup_watermark(struct lpuart_port *sport)
static void lpuart32_setup_watermark_enable(struct lpuart_port *sport)
{
- u32 temp;
+ u32 ctrl;
lpuart32_setup_watermark(sport);
- temp = lpuart32_read(&sport->port, UARTCTRL);
- temp |= UARTCTRL_RE | UARTCTRL_TE;
- temp |= FIELD_PREP(UARTCTRL_IDLECFG, 0x7);
- lpuart32_write(&sport->port, temp, UARTCTRL);
+ ctrl = lpuart32_read(&sport->port, UARTCTRL);
+ ctrl |= UARTCTRL_RE | UARTCTRL_TE;
+ ctrl |= FIELD_PREP(UARTCTRL_IDLECFG, 0x7);
+ lpuart32_write(&sport->port, ctrl, UARTCTRL);
}
static void rx_dma_timer_init(struct lpuart_port *sport)
@@ -1817,16 +1820,16 @@ static void lpuart_hw_setup(struct lpuart_port *sport)
static int lpuart_startup(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
- u8 temp;
+ u8 fifo;
/* determine FIFO size and enable FIFO mode */
- temp = readb(port->membase + UARTPFIFO);
+ fifo = readb(port->membase + UARTPFIFO);
- sport->txfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_TXSIZE_OFF) &
+ sport->txfifo_size = UARTFIFO_DEPTH((fifo >> UARTPFIFO_TXSIZE_OFF) &
UARTPFIFO_FIFOSIZE_MASK);
port->fifosize = sport->txfifo_size;
- sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_RXSIZE_OFF) &
+ sport->rxfifo_size = UARTFIFO_DEPTH((fifo >> UARTPFIFO_RXSIZE_OFF) &
UARTPFIFO_FIFOSIZE_MASK);
lpuart_request_dma(sport);
@@ -1837,24 +1840,24 @@ static int lpuart_startup(struct uart_port *port)
static void lpuart32_hw_disable(struct lpuart_port *sport)
{
- u32 temp;
+ u32 ctrl;
- temp = lpuart32_read(&sport->port, UARTCTRL);
- temp &= ~(UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE |
+ ctrl = lpuart32_read(&sport->port, UARTCTRL);
+ ctrl &= ~(UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE |
UARTCTRL_TIE | UARTCTRL_TE);
- lpuart32_write(&sport->port, temp, UARTCTRL);
+ lpuart32_write(&sport->port, ctrl, UARTCTRL);
}
static void lpuart32_configure(struct lpuart_port *sport)
{
- u32 temp;
+ u32 ctrl;
- temp = lpuart32_read(&sport->port, UARTCTRL);
+ ctrl = lpuart32_read(&sport->port, UARTCTRL);
if (!sport->lpuart_dma_rx_use)
- temp |= UARTCTRL_RIE | UARTCTRL_ILIE;
+ ctrl |= UARTCTRL_RIE | UARTCTRL_ILIE;
if (!sport->lpuart_dma_tx_use)
- temp |= UARTCTRL_TIE;
- lpuart32_write(&sport->port, temp, UARTCTRL);
+ ctrl |= UARTCTRL_TIE;
+ lpuart32_write(&sport->port, ctrl, UARTCTRL);
}
static void lpuart32_hw_setup(struct lpuart_port *sport)
@@ -1877,16 +1880,16 @@ static void lpuart32_hw_setup(struct lpuart_port *sport)
static int lpuart32_startup(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
- u32 temp;
+ u32 fifo;
/* determine FIFO size */
- temp = lpuart32_read(port, UARTFIFO);
+ fifo = lpuart32_read(port, UARTFIFO);
- sport->txfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_TXSIZE_OFF) &
+ sport->txfifo_size = UARTFIFO_DEPTH((fifo >> UARTFIFO_TXSIZE_OFF) &
UARTFIFO_FIFOSIZE_MASK);
port->fifosize = sport->txfifo_size;
- sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_RXSIZE_OFF) &
+ sport->rxfifo_size = UARTFIFO_DEPTH((fifo >> UARTFIFO_RXSIZE_OFF) &
UARTFIFO_FIFOSIZE_MASK);
/*
@@ -1931,16 +1934,16 @@ static void lpuart_dma_shutdown(struct lpuart_port *sport)
static void lpuart_shutdown(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
- u8 temp;
+ u8 cr2;
unsigned long flags;
uart_port_lock_irqsave(port, &flags);
/* disable Rx/Tx and interrupts */
- temp = readb(port->membase + UARTCR2);
- temp &= ~(UARTCR2_TE | UARTCR2_RE |
+ cr2 = readb(port->membase + UARTCR2);
+ cr2 &= ~(UARTCR2_TE | UARTCR2_RE |
UARTCR2_TIE | UARTCR2_TCIE | UARTCR2_RIE);
- writeb(temp, port->membase + UARTCR2);
+ writeb(cr2, port->membase + UARTCR2);
uart_port_unlock_irqrestore(port, flags);
@@ -2071,7 +2074,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
* baud rate and restart Rx DMA path.
*
* Since timer function acqures port->lock, need to stop before
- * acquring same lock because otherwise del_timer_sync() can deadlock.
+ * acquring same lock because otherwise timer_delete_sync() can deadlock.
*/
if (old && sport->lpuart_dma_rx_use)
lpuart_dma_rx_free(port);
@@ -2138,7 +2141,7 @@ static void __lpuart32_serial_setbrg(struct uart_port *port,
unsigned int baudrate, bool use_rx_dma,
bool use_tx_dma)
{
- u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp;
+ u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, baud;
u32 clk = port->uartclk;
/*
@@ -2167,9 +2170,9 @@ static void __lpuart32_serial_setbrg(struct uart_port *port,
tmp_diff = clk / (tmp_osr * tmp_sbr) - baudrate;
/* select best values between sbr and sbr+1 */
- tmp = clk / (tmp_osr * (tmp_sbr + 1));
- if (tmp_diff > (baudrate - tmp)) {
- tmp_diff = baudrate - tmp;
+ baud = clk / (tmp_osr * (tmp_sbr + 1));
+ if (tmp_diff > (baudrate - baud)) {
+ tmp_diff = baudrate - baud;
tmp_sbr++;
}
@@ -2191,23 +2194,23 @@ static void __lpuart32_serial_setbrg(struct uart_port *port,
dev_warn(port->dev,
"unacceptable baud rate difference of more than 3%%\n");
- tmp = lpuart32_read(port, UARTBAUD);
+ baud = lpuart32_read(port, UARTBAUD);
if ((osr > 3) && (osr < 8))
- tmp |= UARTBAUD_BOTHEDGE;
+ baud |= UARTBAUD_BOTHEDGE;
- tmp &= ~(UARTBAUD_OSR_MASK << UARTBAUD_OSR_SHIFT);
- tmp |= ((osr-1) & UARTBAUD_OSR_MASK) << UARTBAUD_OSR_SHIFT;
+ baud &= ~(UARTBAUD_OSR_MASK << UARTBAUD_OSR_SHIFT);
+ baud |= ((osr-1) & UARTBAUD_OSR_MASK) << UARTBAUD_OSR_SHIFT;
- tmp &= ~UARTBAUD_SBR_MASK;
- tmp |= sbr & UARTBAUD_SBR_MASK;
+ baud &= ~UARTBAUD_SBR_MASK;
+ baud |= sbr & UARTBAUD_SBR_MASK;
if (!use_rx_dma)
- tmp &= ~UARTBAUD_RDMAE;
+ baud &= ~UARTBAUD_RDMAE;
if (!use_tx_dma)
- tmp &= ~UARTBAUD_TDMAE;
+ baud &= ~UARTBAUD_TDMAE;
- lpuart32_write(port, tmp, UARTBAUD);
+ lpuart32_write(port, baud, UARTBAUD);
}
static void lpuart32_serial_setbrg(struct lpuart_port *sport,
@@ -2316,7 +2319,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
* baud rate and restart Rx DMA path.
*
* Since timer function acqures port->lock, need to stop before
- * acquring same lock because otherwise del_timer_sync() can deadlock.
+ * acquring same lock because otherwise timer_delete_sync() can deadlock.
*/
if (old && sport->lpuart_dma_rx_use)
lpuart_dma_rx_free(port);
@@ -2962,7 +2965,7 @@ static int lpuart_probe(struct platform_device *pdev)
goto failed_attach_port;
ret = devm_request_irq(&pdev->dev, sport->port.irq, handler, 0,
- DRIVER_NAME, sport);
+ dev_name(&pdev->dev), sport);
if (ret)
goto failed_irq_request;
@@ -3084,7 +3087,7 @@ static int lpuart_suspend_noirq(struct device *dev)
static int lpuart_resume_noirq(struct device *dev)
{
struct lpuart_port *sport = dev_get_drvdata(dev);
- u32 val;
+ u32 stat;
pinctrl_pm_select_default_state(dev);
@@ -3093,8 +3096,8 @@ static int lpuart_resume_noirq(struct device *dev)
/* clear the wakeup flags */
if (lpuart_is_32(sport)) {
- val = lpuart32_read(&sport->port, UARTSTAT);
- lpuart32_write(&sport->port, val, UARTSTAT);
+ stat = lpuart32_read(&sport->port, UARTSTAT);
+ lpuart32_write(&sport->port, stat, UARTSTAT);
}
}
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
index 29e42831df39..7fb995a8490e 100644
--- a/drivers/tty/serial/icom.c
+++ b/drivers/tty/serial/icom.c
@@ -1764,11 +1764,10 @@ static int icom_probe(struct pci_dev *dev,
goto probe_exit1;
}
- /* save off irq and request irq line */
- retval = request_irq(dev->irq, icom_interrupt, IRQF_SHARED, ICOM_DRIVER_NAME, (void *)icom_adapter);
- if (retval) {
- goto probe_exit2;
- }
+ /* save off irq and request irq line */
+ retval = request_irq(dev->irq, icom_interrupt, IRQF_SHARED, ICOM_DRIVER_NAME, icom_adapter);
+ if (retval)
+ goto probe_exit2;
retval = icom_load_ports(icom_adapter);
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 9c59ec128bb4..500dfc009d03 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -235,6 +235,7 @@ struct imx_port {
enum imx_tx_state tx_state;
struct hrtimer trigger_start_tx;
struct hrtimer trigger_stop_tx;
+ unsigned int rxtl;
};
struct imx_port_ucrs {
@@ -1165,7 +1166,7 @@ static void imx_uart_break_ctl(struct uart_port *port, int break_state)
*/
static void imx_uart_timeout(struct timer_list *t)
{
- struct imx_port *sport = from_timer(sport, t, timer);
+ struct imx_port *sport = timer_container_of(sport, t, timer);
unsigned long flags;
if (sport->port.state) {
@@ -1339,6 +1340,7 @@ static void imx_uart_clear_rx_errors(struct imx_port *sport)
#define TXTL_DEFAULT 8
#define RXTL_DEFAULT 8 /* 8 characters or aging timer */
+#define RXTL_CONSOLE_DEFAULT 1
#define TXTL_DMA 8 /* DMA burst setting */
#define RXTL_DMA 9 /* DMA burst setting */
@@ -1457,7 +1459,7 @@ static void imx_uart_disable_dma(struct imx_port *sport)
ucr1 &= ~(UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN);
imx_uart_writel(sport, ucr1, UCR1);
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
sport->dma_is_enabled = 0;
}
@@ -1482,7 +1484,12 @@ static int imx_uart_startup(struct uart_port *port)
return retval;
}
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ if (uart_console(&sport->port))
+ sport->rxtl = RXTL_CONSOLE_DEFAULT;
+ else
+ sport->rxtl = RXTL_DEFAULT;
+
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
/* disable the DREN bit (Data Ready interrupt enable) before
* requesting IRQs
@@ -1608,7 +1615,7 @@ static void imx_uart_shutdown(struct uart_port *port)
imx_uart_dma_exit(sport);
}
- mctrl_gpio_disable_ms(sport->gpios);
+ mctrl_gpio_disable_ms_sync(sport->gpios);
uart_port_lock_irqsave(&sport->port, &flags);
ucr2 = imx_uart_readl(sport, UCR2);
@@ -1619,7 +1626,7 @@ static void imx_uart_shutdown(struct uart_port *port)
/*
* Stop our timer.
*/
- del_timer_sync(&sport->timer);
+ timer_delete_sync(&sport->timer);
/*
* Disable all interrupts, port and break condition.
@@ -1752,7 +1759,7 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
old_csize = CS8;
}
- del_timer_sync(&sport->timer);
+ timer_delete_sync(&sport->timer);
/*
* Ask the core to calculate the divisor for us.
@@ -1948,7 +1955,7 @@ static int imx_uart_poll_init(struct uart_port *port)
if (retval)
clk_disable_unprepare(sport->clk_ipg);
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
uart_port_lock_irqsave(&sport->port, &flags);
@@ -2040,7 +2047,7 @@ static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termio
/* If the receiver trigger is 0, set it to a default value */
ufcr = imx_uart_readl(sport, UFCR);
if ((ufcr & UFCR_RXTL_MASK) == 0)
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
imx_uart_start_rx(port);
}
@@ -2302,7 +2309,7 @@ imx_uart_console_setup(struct console *co, char *options)
else
imx_uart_console_get_options(sport, &baud, &parity, &bits);
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
retval = uart_set_options(&sport->port, co, baud, parity, bits, flow);
@@ -2582,10 +2589,10 @@ static int imx_uart_probe(struct platform_device *pdev)
imx_uart_writel(sport, ucr3, UCR3);
}
- hrtimer_init(&sport->trigger_start_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- hrtimer_init(&sport->trigger_stop_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- sport->trigger_start_tx.function = imx_trigger_start_tx;
- sport->trigger_stop_tx.function = imx_trigger_stop_tx;
+ hrtimer_setup(&sport->trigger_start_tx, imx_trigger_start_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ hrtimer_setup(&sport->trigger_stop_tx, imx_trigger_stop_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
/*
* Allocate the IRQ(s) i.MX1 has three interrupts whereas later
diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c
index ce0fef7e2c66..be2f130696b3 100644
--- a/drivers/tty/serial/jsm/jsm_tty.c
+++ b/drivers/tty/serial/jsm/jsm_tty.c
@@ -451,6 +451,7 @@ int jsm_uart_port_init(struct jsm_board *brd)
if (!brd->channels[i])
continue;
+ brd->channels[i]->uart_port.dev = &brd->pci_dev->dev;
brd->channels[i]->uart_port.irq = brd->irq;
brd->channels[i]->uart_port.uartclk = 14745600;
brd->channels[i]->uart_port.type = PORT_JSM;
diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c
deleted file mode 100644
index 2833708e369f..000000000000
--- a/drivers/tty/serial/kgdb_nmi.c
+++ /dev/null
@@ -1,280 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * KGDB NMI serial console
- *
- * Copyright 2010 Google, Inc.
- * Arve Hjønnevåg <arve@android.com>
- * Colin Cross <ccross@android.com>
- * Copyright 2012 Linaro Ltd.
- * Anton Vorontsov <anton.vorontsov@linaro.org>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/compiler.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/atomic.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/interrupt.h>
-#include <linux/hrtimer.h>
-#include <linux/tick.h>
-#include <linux/kfifo.h>
-#include <linux/kgdb.h>
-#include <linux/kdb.h>
-
-static atomic_t kgdb_nmi_num_readers = ATOMIC_INIT(0);
-
-static int kgdb_nmi_console_setup(struct console *co, char *options)
-{
- arch_kgdb_ops.enable_nmi(1);
-
- /* The NMI console uses the dbg_io_ops to issue console messages. To
- * avoid duplicate messages during kdb sessions we must inform kdb's
- * I/O utilities that messages sent to the console will automatically
- * be displayed on the dbg_io.
- */
- dbg_io_ops->cons = co;
-
- return 0;
-}
-
-static void kgdb_nmi_console_write(struct console *co, const char *s, uint c)
-{
- int i;
-
- for (i = 0; i < c; i++)
- dbg_io_ops->write_char(s[i]);
-}
-
-static struct tty_driver *kgdb_nmi_tty_driver;
-
-static struct tty_driver *kgdb_nmi_console_device(struct console *co, int *idx)
-{
- *idx = co->index;
- return kgdb_nmi_tty_driver;
-}
-
-static struct console kgdb_nmi_console = {
- .name = "ttyNMI",
- .setup = kgdb_nmi_console_setup,
- .write = kgdb_nmi_console_write,
- .device = kgdb_nmi_console_device,
- .flags = CON_PRINTBUFFER | CON_ANYTIME,
- .index = -1,
-};
-
-/*
- * This is usually the maximum rate on debug ports. We make fifo large enough
- * to make copy-pasting to the terminal usable.
- */
-#define KGDB_NMI_BAUD 115200
-#define KGDB_NMI_FIFO_SIZE roundup_pow_of_two(KGDB_NMI_BAUD / 8 / HZ)
-
-struct kgdb_nmi_tty_priv {
- struct tty_port port;
- struct timer_list timer;
- STRUCT_KFIFO(char, KGDB_NMI_FIFO_SIZE) fifo;
-};
-
-static struct tty_port *kgdb_nmi_port;
-
-/*
- * The tasklet is cheap, it does not cause wakeups when reschedules itself,
- * instead it waits for the next tick.
- */
-static void kgdb_nmi_tty_receiver(struct timer_list *t)
-{
- struct kgdb_nmi_tty_priv *priv = from_timer(priv, t, timer);
- char ch;
-
- priv->timer.expires = jiffies + (HZ/100);
- add_timer(&priv->timer);
-
- if (likely(!atomic_read(&kgdb_nmi_num_readers) ||
- !kfifo_len(&priv->fifo)))
- return;
-
- while (kfifo_out(&priv->fifo, &ch, 1))
- tty_insert_flip_char(&priv->port, ch, TTY_NORMAL);
- tty_flip_buffer_push(&priv->port);
-}
-
-static int kgdb_nmi_tty_activate(struct tty_port *port, struct tty_struct *tty)
-{
- struct kgdb_nmi_tty_priv *priv =
- container_of(port, struct kgdb_nmi_tty_priv, port);
-
- kgdb_nmi_port = port;
- priv->timer.expires = jiffies + (HZ/100);
- add_timer(&priv->timer);
-
- return 0;
-}
-
-static void kgdb_nmi_tty_shutdown(struct tty_port *port)
-{
- struct kgdb_nmi_tty_priv *priv =
- container_of(port, struct kgdb_nmi_tty_priv, port);
-
- del_timer(&priv->timer);
- kgdb_nmi_port = NULL;
-}
-
-static const struct tty_port_operations kgdb_nmi_tty_port_ops = {
- .activate = kgdb_nmi_tty_activate,
- .shutdown = kgdb_nmi_tty_shutdown,
-};
-
-static int kgdb_nmi_tty_install(struct tty_driver *drv, struct tty_struct *tty)
-{
- struct kgdb_nmi_tty_priv *priv;
- int ret;
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- INIT_KFIFO(priv->fifo);
- timer_setup(&priv->timer, kgdb_nmi_tty_receiver, 0);
- tty_port_init(&priv->port);
- priv->port.ops = &kgdb_nmi_tty_port_ops;
- tty->driver_data = priv;
-
- ret = tty_port_install(&priv->port, drv, tty);
- if (ret) {
- pr_err("%s: can't install tty port: %d\n", __func__, ret);
- goto err;
- }
- return 0;
-err:
- tty_port_destroy(&priv->port);
- kfree(priv);
- return ret;
-}
-
-static void kgdb_nmi_tty_cleanup(struct tty_struct *tty)
-{
- struct kgdb_nmi_tty_priv *priv = tty->driver_data;
-
- tty->driver_data = NULL;
- tty_port_destroy(&priv->port);
- kfree(priv);
-}
-
-static int kgdb_nmi_tty_open(struct tty_struct *tty, struct file *file)
-{
- struct kgdb_nmi_tty_priv *priv = tty->driver_data;
- unsigned int mode = file->f_flags & O_ACCMODE;
- int ret;
-
- ret = tty_port_open(&priv->port, tty, file);
- if (!ret && (mode == O_RDONLY || mode == O_RDWR))
- atomic_inc(&kgdb_nmi_num_readers);
-
- return ret;
-}
-
-static void kgdb_nmi_tty_close(struct tty_struct *tty, struct file *file)
-{
- struct kgdb_nmi_tty_priv *priv = tty->driver_data;
- unsigned int mode = file->f_flags & O_ACCMODE;
-
- if (mode == O_RDONLY || mode == O_RDWR)
- atomic_dec(&kgdb_nmi_num_readers);
-
- tty_port_close(&priv->port, tty, file);
-}
-
-static void kgdb_nmi_tty_hangup(struct tty_struct *tty)
-{
- struct kgdb_nmi_tty_priv *priv = tty->driver_data;
-
- tty_port_hangup(&priv->port);
-}
-
-static unsigned int kgdb_nmi_tty_write_room(struct tty_struct *tty)
-{
- /* Actually, we can handle any amount as we use polled writes. */
- return 2048;
-}
-
-static ssize_t kgdb_nmi_tty_write(struct tty_struct *tty, const u8 *buf,
- size_t c)
-{
- int i;
-
- for (i = 0; i < c; i++)
- dbg_io_ops->write_char(buf[i]);
- return c;
-}
-
-static const struct tty_operations kgdb_nmi_tty_ops = {
- .open = kgdb_nmi_tty_open,
- .close = kgdb_nmi_tty_close,
- .install = kgdb_nmi_tty_install,
- .cleanup = kgdb_nmi_tty_cleanup,
- .hangup = kgdb_nmi_tty_hangup,
- .write_room = kgdb_nmi_tty_write_room,
- .write = kgdb_nmi_tty_write,
-};
-
-int kgdb_register_nmi_console(void)
-{
- int ret;
-
- if (!arch_kgdb_ops.enable_nmi)
- return 0;
-
- kgdb_nmi_tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW);
- if (IS_ERR(kgdb_nmi_tty_driver)) {
- pr_err("%s: cannot allocate tty\n", __func__);
- return PTR_ERR(kgdb_nmi_tty_driver);
- }
- kgdb_nmi_tty_driver->driver_name = "ttyNMI";
- kgdb_nmi_tty_driver->name = "ttyNMI";
- kgdb_nmi_tty_driver->num = 1;
- kgdb_nmi_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
- kgdb_nmi_tty_driver->subtype = SERIAL_TYPE_NORMAL;
- kgdb_nmi_tty_driver->init_termios = tty_std_termios;
- tty_termios_encode_baud_rate(&kgdb_nmi_tty_driver->init_termios,
- KGDB_NMI_BAUD, KGDB_NMI_BAUD);
- tty_set_operations(kgdb_nmi_tty_driver, &kgdb_nmi_tty_ops);
-
- ret = tty_register_driver(kgdb_nmi_tty_driver);
- if (ret) {
- pr_err("%s: can't register tty driver: %d\n", __func__, ret);
- goto err_drv_reg;
- }
-
- register_console(&kgdb_nmi_console);
-
- return 0;
-err_drv_reg:
- tty_driver_kref_put(kgdb_nmi_tty_driver);
- return ret;
-}
-EXPORT_SYMBOL_GPL(kgdb_register_nmi_console);
-
-int kgdb_unregister_nmi_console(void)
-{
- int ret;
-
- if (!arch_kgdb_ops.enable_nmi)
- return 0;
- arch_kgdb_ops.enable_nmi(0);
-
- ret = unregister_console(&kgdb_nmi_console);
- if (ret)
- return ret;
-
- tty_unregister_driver(kgdb_nmi_tty_driver);
- tty_driver_kref_put(kgdb_nmi_tty_driver);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(kgdb_unregister_nmi_console);
diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index 58ea1e1391ce..85f6c5a76e0f 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -186,8 +186,6 @@ static void cleanup_kgdboc(void)
if (configured != 1)
return;
- if (kgdb_unregister_nmi_console())
- return;
kgdboc_unregister_kbd();
kgdb_unregister_io_module(&kgdboc_io_ops);
}
@@ -250,16 +248,10 @@ do_register:
if (err)
goto noconfig;
- err = kgdb_register_nmi_console();
- if (err)
- goto nmi_con_failed;
-
configured = 1;
return 0;
-nmi_con_failed:
- kgdb_unregister_io_module(&kgdboc_io_ops);
noconfig:
kgdboc_unregister_kbd();
configured = 0;
diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index 58a3ab030d67..62cd9e0bb377 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -773,10 +773,8 @@ static int fetch_irq_intel(struct device *dev, struct ltq_uart_port *ltq_port)
int ret;
ret = platform_get_irq(to_platform_device(dev), 0);
- if (ret < 0) {
- dev_err(dev, "failed to fetch IRQ for serial port\n");
+ if (ret < 0)
return ret;
- }
ltq_port->common_irq = ret;
port->irq = ret;
diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c
index 6c13cf1ab646..6429e8f11f36 100644
--- a/drivers/tty/serial/liteuart.c
+++ b/drivers/tty/serial/liteuart.c
@@ -96,7 +96,7 @@ static void liteuart_stop_rx(struct uart_port *port)
struct liteuart_port *uart = to_liteuart_port(port);
/* just delete timer */
- del_timer(&uart->timer);
+ timer_delete(&uart->timer);
}
static void liteuart_rx_chars(struct uart_port *port)
@@ -152,7 +152,7 @@ static irqreturn_t liteuart_interrupt(int irq, void *data)
static void liteuart_timer(struct timer_list *t)
{
- struct liteuart_port *uart = from_timer(uart, t, timer);
+ struct liteuart_port *uart = timer_container_of(uart, t, timer);
struct uart_port *port = &uart->port;
liteuart_interrupt(0, port);
@@ -220,7 +220,7 @@ static void liteuart_shutdown(struct uart_port *port)
if (port->irq)
free_irq(port->irq, port);
else
- del_timer_sync(&uart->timer);
+ timer_delete_sync(&uart->timer);
}
static void liteuart_set_termios(struct uart_port *port, struct ktermios *new,
diff --git a/drivers/tty/serial/ma35d1_serial.c b/drivers/tty/serial/ma35d1_serial.c
index 8dcad52eedfd..285b0fe41a86 100644
--- a/drivers/tty/serial/ma35d1_serial.c
+++ b/drivers/tty/serial/ma35d1_serial.c
@@ -799,7 +799,7 @@ static struct platform_driver ma35d1serial_driver = {
.resume = ma35d1serial_resume,
.driver = {
.name = "ma35d1-uart",
- .of_match_table = of_match_ptr(ma35d1_serial_of_match),
+ .of_match_table = ma35d1_serial_of_match,
},
};
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
index cde5f1c86353..67d80f8f801e 100644
--- a/drivers/tty/serial/max3100.c
+++ b/drivers/tty/serial/max3100.c
@@ -16,6 +16,7 @@
/* 4 MAX3100s should be enough for everyone */
#define MAX_MAX3100 4
+#include <linux/bitops.h>
#include <linux/container_of.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -133,7 +134,7 @@ static int max3100_do_parity(struct max3100_port *s, u16 c)
else
c &= 0xff;
- parity = parity ^ (hweight8(c) & 1);
+ parity = parity ^ parity8(c);
return parity;
}
@@ -308,7 +309,7 @@ static void max3100_dowork(struct max3100_port *s)
static void max3100_timeout(struct timer_list *t)
{
- struct max3100_port *s = from_timer(s, t, timer);
+ struct max3100_port *s = timer_container_of(s, t, timer);
max3100_dowork(s);
mod_timer(&s->timer, jiffies + uart_poll_timeout(&s->port));
@@ -506,7 +507,7 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios,
MAX3100_STATUS_PE | MAX3100_STATUS_FE |
MAX3100_STATUS_OE;
- del_timer_sync(&s->timer);
+ timer_delete_sync(&s->timer);
uart_update_timeout(port, termios->c_cflag, baud);
spin_lock(&s->conf_lock);
@@ -532,7 +533,7 @@ static void max3100_shutdown(struct uart_port *port)
s->force_end_work = 1;
- del_timer_sync(&s->timer);
+ timer_delete_sync(&s->timer);
if (s->workqueue) {
destroy_workqueue(s->workqueue);
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 35369a2f77b2..541c790c0109 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1189,13 +1189,16 @@ static int max310x_gpio_get(struct gpio_chip *chip, unsigned int offset)
return !!((val >> 4) & (1 << (offset % 4)));
}
-static void max310x_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+static int max310x_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct max310x_port *s = gpiochip_get_data(chip);
struct uart_port *port = &s->p[offset / 4].port;
max310x_port_update(port, MAX310X_GPIODATA_REG, 1 << (offset % 4),
value ? 1 << (offset % 4) : 0);
+
+ return 0;
}
static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
@@ -1411,7 +1414,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
s->gpio.direction_input = max310x_gpio_direction_input;
s->gpio.get = max310x_gpio_get;
s->gpio.direction_output= max310x_gpio_direction_output;
- s->gpio.set = max310x_gpio_set;
+ s->gpio.set_rv = max310x_gpio_set;
s->gpio.set_config = max310x_gpio_set_config;
s->gpio.base = -1;
s->gpio.ngpio = devtype->nr * 4;
diff --git a/drivers/tty/serial/milbeaut_usio.c b/drivers/tty/serial/milbeaut_usio.c
index 059bea18dbab..4e47dca2c4ed 100644
--- a/drivers/tty/serial/milbeaut_usio.c
+++ b/drivers/tty/serial/milbeaut_usio.c
@@ -523,7 +523,10 @@ static int mlb_usio_probe(struct platform_device *pdev)
}
port->membase = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
-
+ if (!port->membase) {
+ ret = -ENOMEM;
+ goto failed;
+ }
ret = platform_get_irq_byname(pdev, "rx");
mlb_usio_irq[index][RX] = ret;
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index 2204cc3e3b07..37eb701b0b46 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -1351,7 +1351,6 @@ static const struct uart_ops mpc52xx_uart_ops = {
.startup = mpc52xx_uart_startup,
.shutdown = mpc52xx_uart_shutdown,
.set_termios = mpc52xx_uart_set_termios,
-/* .pm = mpc52xx_uart_pm, Not supported yet */
.type = mpc52xx_uart_type,
.release_port = mpc52xx_uart_release_port,
.request_port = mpc52xx_uart_request_port,
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 1b137e068444..3449945493ce 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -1746,6 +1746,12 @@ msm_serial_early_console_setup_dm(struct earlycon_device *device,
if (!device->port.membase)
return -ENODEV;
+ /* Disable DM / single-character modes */
+ msm_write(&device->port, 0, UARTDM_DMEN);
+ msm_write(&device->port, MSM_UART_CR_CMD_RESET_RX, MSM_UART_CR);
+ msm_write(&device->port, MSM_UART_CR_CMD_RESET_TX, MSM_UART_CR);
+ msm_write(&device->port, MSM_UART_CR_TX_ENABLE, MSM_UART_CR);
+
device->con->write = msm_serial_early_write_dm;
return 0;
}
diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c
index 85ce1e9af44a..b417faead20f 100644
--- a/drivers/tty/serial/mux.c
+++ b/drivers/tty/serial/mux.c
@@ -563,7 +563,7 @@ static void __exit mux_exit(void)
{
/* Delete the Mux timer. */
if(port_cnt > 0) {
- del_timer_sync(&mux_timer);
+ timer_delete_sync(&mux_timer);
#ifdef CONFIG_SERIAL_MUX_CONSOLE
unregister_console(&mux_console);
#endif
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index c7cee5fee603..884fefbfd5a1 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -954,7 +954,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
__func__);
return 0;
}
- dma_sync_sg_for_device(port->dev, priv->sg_tx_p, nent, DMA_TO_DEVICE);
+ dma_sync_sg_for_device(port->dev, priv->sg_tx_p, num, DMA_TO_DEVICE);
priv->desc_tx = desc;
desc->callback = pch_dma_tx_complete;
desc->callback_param = priv;
@@ -1515,7 +1515,6 @@ static const struct uart_ops pch_uart_ops = {
.startup = pch_uart_startup,
.shutdown = pch_uart_shutdown,
.set_termios = pch_uart_set_termios,
-/* .pm = pch_uart_pm, Not supported yet */
.type = pch_uart_type,
.release_port = pch_uart_release_port,
.request_port = pch_uart_request_port,
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
index a80ce7aaf309..0293b6210aa6 100644
--- a/drivers/tty/serial/qcom_geni_serial.c
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -98,6 +98,8 @@
#define DMA_RX_BUF_SIZE 2048
+static DEFINE_IDA(port_ida);
+
struct qcom_geni_device_data {
bool console;
enum geni_se_xfer_mode mode;
@@ -253,10 +255,24 @@ static struct qcom_geni_serial_port *get_port_from_line(int line, bool console)
struct qcom_geni_serial_port *port;
int nr_ports = console ? GENI_UART_CONS_PORTS : GENI_UART_PORTS;
- if (line < 0 || line >= nr_ports)
- return ERR_PTR(-ENXIO);
+ if (console) {
+ if (line < 0 || line >= nr_ports)
+ return ERR_PTR(-ENXIO);
+
+ port = &qcom_geni_console_port;
+ } else {
+ int max_alias_num = of_alias_get_highest_id("serial");
+
+ if (line < 0 || line >= nr_ports)
+ line = ida_alloc_range(&port_ida, max_alias_num + 1, nr_ports, GFP_KERNEL);
+ else
+ line = ida_alloc_range(&port_ida, line, nr_ports, GFP_KERNEL);
+
+ if (line < 0)
+ return ERR_PTR(-ENXIO);
- port = console ? &qcom_geni_console_port : &qcom_geni_uart_ports[line];
+ port = &qcom_geni_uart_ports[line];
+ }
return port;
}
@@ -1761,6 +1777,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
port->wakeup_irq);
if (ret) {
device_init_wakeup(&pdev->dev, false);
+ ida_free(&port_ida, uport->line);
uart_remove_one_port(drv, uport);
return ret;
}
@@ -1772,10 +1789,12 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
static void qcom_geni_serial_remove(struct platform_device *pdev)
{
struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
+ struct uart_port *uport = &port->uport;
struct uart_driver *drv = port->private_data.drv;
dev_pm_clear_wake_irq(&pdev->dev);
device_init_wakeup(&pdev->dev, false);
+ ida_free(&port_ida, uport->line);
uart_remove_one_port(drv, &port->uport);
}
diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c
index 3c34027687d2..72b1bb76415c 100644
--- a/drivers/tty/serial/sa1100.c
+++ b/drivers/tty/serial/sa1100.c
@@ -111,7 +111,7 @@ static void sa1100_mctrl_check(struct sa1100_port *sport)
*/
static void sa1100_timeout(struct timer_list *t)
{
- struct sa1100_port *sport = from_timer(sport, t, timer);
+ struct sa1100_port *sport = timer_container_of(sport, t, timer);
unsigned long flags;
if (sport->port.state) {
@@ -369,7 +369,7 @@ static void sa1100_shutdown(struct uart_port *port)
/*
* Stop our timer.
*/
- del_timer_sync(&sport->timer);
+ timer_delete_sync(&sport->timer);
/*
* Free the interrupt
@@ -421,7 +421,7 @@ sa1100_set_termios(struct uart_port *port, struct ktermios *termios,
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
- del_timer_sync(&sport->timer);
+ timer_delete_sync(&sport->timer);
uart_port_lock_irqsave(&sport->port, &flags);
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 210fff7164c1..2fb58c626daf 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -52,7 +52,7 @@
#define S3C24XX_SERIAL_MINOR 64
#ifdef CONFIG_ARM64
-#define UART_NR 12
+#define UART_NR 18
#else
#define UART_NR CONFIG_SERIAL_SAMSUNG_UARTS
#endif
@@ -190,6 +190,8 @@ static void wr_reg(const struct uart_port *port, u32 reg, u32 val)
case UPIO_MEM32:
writel_relaxed(val, portaddr(port, reg));
break;
+ default:
+ break;
}
}
@@ -2713,6 +2715,8 @@ static void wr_reg_barrier(const struct uart_port *port, u32 reg, u32 val)
case UPIO_MEM32:
writel(val, portaddr(port, reg));
break;
+ default:
+ break;
}
}
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 560f45ed19ae..5ea8aadb6e69 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -1333,13 +1333,16 @@ static int sc16is7xx_gpio_get(struct gpio_chip *chip, unsigned offset)
return !!(val & BIT(offset));
}
-static void sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+static int sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int val)
{
struct sc16is7xx_port *s = gpiochip_get_data(chip);
struct uart_port *port = &s->p[0].port;
sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset),
val ? BIT(offset) : 0);
+
+ return 0;
}
static int sc16is7xx_gpio_direction_input(struct gpio_chip *chip,
@@ -1422,7 +1425,7 @@ static int sc16is7xx_setup_gpio_chip(struct sc16is7xx_port *s)
s->gpio.direction_input = sc16is7xx_gpio_direction_input;
s->gpio.get = sc16is7xx_gpio_get;
s->gpio.direction_output = sc16is7xx_gpio_direction_output;
- s->gpio.set = sc16is7xx_gpio_set;
+ s->gpio.set_rv = sc16is7xx_gpio_set;
s->gpio.base = -1;
s->gpio.ngpio = s->devtype->nr_gpio;
s->gpio.can_sleep = 1;
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c
index 4c851dae6624..4ceca11ce600 100644
--- a/drivers/tty/serial/sccnxp.c
+++ b/drivers/tty/serial/sccnxp.c
@@ -500,7 +500,7 @@ static void sccnxp_handle_events(struct sccnxp_port *s)
static void sccnxp_timer(struct timer_list *t)
{
- struct sccnxp_port *s = from_timer(s, t, timer);
+ struct sccnxp_port *s = timer_container_of(s, t, timer);
unsigned long flags;
spin_lock_irqsave(&s->lock, flags);
@@ -1033,7 +1033,7 @@ static void sccnxp_remove(struct platform_device *pdev)
if (!s->poll)
devm_free_irq(&pdev->dev, s->irq, s);
else
- del_timer_sync(&s->timer);
+ timer_delete_sync(&s->timer);
for (i = 0; i < s->uart.nr; i++)
uart_remove_one_port(&s->uart, &s->port[i]);
diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c
index 5d1677f1b651..22749ab0428a 100644
--- a/drivers/tty/serial/serial_base_bus.c
+++ b/drivers/tty/serial/serial_base_bus.c
@@ -13,6 +13,7 @@
#include <linux/device.h>
#include <linux/idr.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/serial_core.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -72,6 +73,7 @@ static int serial_base_device_init(struct uart_port *port,
dev->parent = parent_dev;
dev->bus = &serial_base_bus_type;
dev->release = release;
+ device_set_of_node_from_dev(dev, parent_dev);
if (!serial_base_initialized) {
dev_dbg(port->dev, "uart_add_one_port() called before arch_initcall()?\n");
@@ -92,6 +94,7 @@ static void serial_base_ctrl_release(struct device *dev)
{
struct serial_ctrl_device *ctrl_dev = to_serial_base_ctrl_device(dev);
+ of_node_put(dev->of_node);
kfree(ctrl_dev);
}
@@ -139,6 +142,7 @@ static void serial_base_port_release(struct device *dev)
{
struct serial_port_device *port_dev = to_serial_base_port_device(dev);
+ of_node_put(dev->of_node);
kfree(port_dev);
}
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 92f7e752f862..8a1482131257 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -75,22 +75,23 @@ static inline void uart_port_deref(struct uart_port *uport)
wake_up(&uport->state->remove_wait);
}
-#define uart_port_lock(state, flags) \
- ({ \
- struct uart_port *__uport = uart_port_ref(state); \
- if (__uport) \
- uart_port_lock_irqsave(__uport, &flags); \
- __uport; \
- })
-
-#define uart_port_unlock(uport, flags) \
- ({ \
- struct uart_port *__uport = uport; \
- if (__uport) { \
- uart_port_unlock_irqrestore(__uport, flags); \
- uart_port_deref(__uport); \
- } \
- })
+static inline struct uart_port *uart_port_ref_lock(struct uart_state *state, unsigned long *flags)
+{
+ struct uart_port *uport = uart_port_ref(state);
+
+ if (uport)
+ uart_port_lock_irqsave(uport, flags);
+
+ return uport;
+}
+
+static inline void uart_port_unlock_deref(struct uart_port *uport, unsigned long flags)
+{
+ if (uport) {
+ uart_port_unlock_irqrestore(uport, flags);
+ uart_port_deref(uport);
+ }
+}
static inline struct uart_port *uart_port_check(struct uart_state *state)
{
@@ -127,10 +128,10 @@ static void uart_stop(struct tty_struct *tty)
struct uart_port *port;
unsigned long flags;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (port)
port->ops->stop_tx(port);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
}
static void __uart_start(struct uart_state *state)
@@ -168,9 +169,9 @@ static void uart_start(struct tty_struct *tty)
struct uart_port *port;
unsigned long flags;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
__uart_start(state);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
}
static void
@@ -258,14 +259,14 @@ static int uart_alloc_xmit_buf(struct tty_port *port)
if (!page)
return -ENOMEM;
- uport = uart_port_lock(state, flags);
+ uport = uart_port_ref_lock(state, &flags);
if (!state->port.xmit_buf) {
state->port.xmit_buf = (unsigned char *)page;
kfifo_init(&state->port.xmit_fifo, state->port.xmit_buf,
PAGE_SIZE);
- uart_port_unlock(uport, flags);
+ uart_port_unlock_deref(uport, flags);
} else {
- uart_port_unlock(uport, flags);
+ uart_port_unlock_deref(uport, flags);
/*
* Do not free() the page under the port lock, see
* uart_free_xmit_buf().
@@ -289,11 +290,11 @@ static void uart_free_xmit_buf(struct tty_port *port)
* console driver may need to allocate/free a debug object, which
* can end up in printk() recursion.
*/
- uport = uart_port_lock(state, flags);
+ uport = uart_port_ref_lock(state, &flags);
xmit_buf = port->xmit_buf;
port->xmit_buf = NULL;
INIT_KFIFO(port->xmit_fifo);
- uart_port_unlock(uport, flags);
+ uart_port_unlock_deref(uport, flags);
free_page((unsigned long)xmit_buf);
}
@@ -592,15 +593,15 @@ static int uart_put_char(struct tty_struct *tty, u8 c)
unsigned long flags;
int ret = 0;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (!state->port.xmit_buf) {
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return 0;
}
if (port)
ret = kfifo_put(&state->port.xmit_fifo, c);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -623,9 +624,9 @@ static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count)
if (WARN_ON(!state))
return -EL3HLT;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (!state->port.xmit_buf) {
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return 0;
}
@@ -633,7 +634,7 @@ static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count)
ret = kfifo_in(&state->port.xmit_fifo, buf, count);
__uart_start(state);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -644,9 +645,9 @@ static unsigned int uart_write_room(struct tty_struct *tty)
unsigned long flags;
unsigned int ret;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
ret = kfifo_avail(&state->port.xmit_fifo);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -657,9 +658,9 @@ static unsigned int uart_chars_in_buffer(struct tty_struct *tty)
unsigned long flags;
unsigned int ret;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
ret = kfifo_len(&state->port.xmit_fifo);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -678,13 +679,13 @@ static void uart_flush_buffer(struct tty_struct *tty)
pr_debug("uart_flush_buffer(%d) called\n", tty->index);
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (!port)
return;
kfifo_reset(&state->port.xmit_fifo);
if (port->ops->flush_buffer)
port->ops->flush_buffer(port);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
tty_port_tty_wakeup(&state->port);
}
@@ -895,8 +896,8 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
{
struct uart_port *uport = uart_port_check(state);
unsigned long new_port;
- unsigned int change_irq, change_port, closing_wait;
- unsigned int old_custom_divisor, close_delay;
+ unsigned int old_custom_divisor, close_delay, closing_wait;
+ bool change_irq, change_port;
upf_t old_flags, new_flags;
int retval;
@@ -1275,14 +1276,13 @@ static int uart_get_icount(struct tty_struct *tty,
struct uart_state *state = tty->driver_data;
struct uart_icount cnow;
struct uart_port *uport;
+ unsigned long flags;
- uport = uart_port_ref(state);
+ uport = uart_port_ref_lock(state, &flags);
if (!uport)
return -EIO;
- uart_port_lock_irq(uport);
memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
- uart_port_unlock_irq(uport);
- uart_port_deref(uport);
+ uart_port_unlock_deref(uport, flags);
icount->cts = cnow.cts;
icount->dsr = cnow.dsr;
@@ -1337,28 +1337,28 @@ static void uart_sanitize_serial_rs485_delays(struct uart_port *port,
if (!port->rs485_supported.delay_rts_before_send) {
if (rs485->delay_rts_before_send) {
dev_warn_ratelimited(port->dev,
- "%s (%d): RTS delay before sending not supported\n",
+ "%s (%u): RTS delay before sending not supported\n",
port->name, port->line);
}
rs485->delay_rts_before_send = 0;
} else if (rs485->delay_rts_before_send > RS485_MAX_RTS_DELAY) {
rs485->delay_rts_before_send = RS485_MAX_RTS_DELAY;
dev_warn_ratelimited(port->dev,
- "%s (%d): RTS delay before sending clamped to %u ms\n",
+ "%s (%u): RTS delay before sending clamped to %u ms\n",
port->name, port->line, rs485->delay_rts_before_send);
}
if (!port->rs485_supported.delay_rts_after_send) {
if (rs485->delay_rts_after_send) {
dev_warn_ratelimited(port->dev,
- "%s (%d): RTS delay after sending not supported\n",
+ "%s (%u): RTS delay after sending not supported\n",
port->name, port->line);
}
rs485->delay_rts_after_send = 0;
} else if (rs485->delay_rts_after_send > RS485_MAX_RTS_DELAY) {
rs485->delay_rts_after_send = RS485_MAX_RTS_DELAY;
dev_warn_ratelimited(port->dev,
- "%s (%d): RTS delay after sending clamped to %u ms\n",
+ "%s (%u): RTS delay after sending clamped to %u ms\n",
port->name, port->line, rs485->delay_rts_after_send);
}
}
@@ -1388,14 +1388,14 @@ static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs4
rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
dev_warn_ratelimited(port->dev,
- "%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n",
+ "%s (%u): invalid RTS setting, using RTS_ON_SEND instead\n",
port->name, port->line);
} else {
rs485->flags |= SER_RS485_RTS_AFTER_SEND;
rs485->flags &= ~SER_RS485_RTS_ON_SEND;
dev_warn_ratelimited(port->dev,
- "%s (%d): invalid RTS setting, using RTS_AFTER_SEND instead\n",
+ "%s (%u): invalid RTS setting, using RTS_AFTER_SEND instead\n",
port->name, port->line);
}
}
@@ -1834,7 +1834,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
expire = jiffies + timeout;
- pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n",
+ pr_debug("uart_wait_until_sent(%u), jiffies=%lu, expire=%lu...\n",
port->line, jiffies, expire);
/*
@@ -1914,9 +1914,10 @@ static bool uart_carrier_raised(struct tty_port *port)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport;
+ unsigned long flags;
int mctrl;
- uport = uart_port_ref(state);
+ uport = uart_port_ref_lock(state, &flags);
/*
* Should never observe uport == NULL since checks for hangup should
* abort the tty_port_block_til_ready() loop before checking for carrier
@@ -1925,11 +1926,9 @@ static bool uart_carrier_raised(struct tty_port *port)
*/
if (WARN_ON(!uport))
return true;
- uart_port_lock_irq(uport);
uart_enable_ms(uport);
mctrl = uport->ops->get_mctrl(uport);
- uart_port_unlock_irq(uport);
- uart_port_deref(uport);
+ uart_port_unlock_deref(uport, flags);
return mctrl & TIOCM_CAR;
}
@@ -2013,9 +2012,8 @@ static const char *uart_type(struct uart_port *port)
#ifdef CONFIG_PROC_FS
-static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
+static void uart_line_info(struct seq_file *m, struct uart_state *state)
{
- struct uart_state *state = drv->state + i;
struct tty_port *port = &state->port;
enum uart_pm_state pm_state;
struct uart_port *uport;
@@ -2030,7 +2028,7 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
return;
mmio = uport->iotype >= UPIO_MEM;
- seq_printf(m, "%d: uart:%s %s%08llX irq:%d",
+ seq_printf(m, "%u: uart:%s %s%08llX irq:%u",
uport->line, uart_type(uport),
mmio ? "mmio:0x" : "port:",
mmio ? (unsigned long long)uport->mapbase
@@ -2052,18 +2050,18 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
if (pm_state != UART_PM_STATE_ON)
uart_change_pm(state, pm_state);
- seq_printf(m, " tx:%d rx:%d",
+ seq_printf(m, " tx:%u rx:%u",
uport->icount.tx, uport->icount.rx);
if (uport->icount.frame)
- seq_printf(m, " fe:%d", uport->icount.frame);
+ seq_printf(m, " fe:%u", uport->icount.frame);
if (uport->icount.parity)
- seq_printf(m, " pe:%d", uport->icount.parity);
+ seq_printf(m, " pe:%u", uport->icount.parity);
if (uport->icount.brk)
- seq_printf(m, " brk:%d", uport->icount.brk);
+ seq_printf(m, " brk:%u", uport->icount.brk);
if (uport->icount.overrun)
- seq_printf(m, " oe:%d", uport->icount.overrun);
+ seq_printf(m, " oe:%u", uport->icount.overrun);
if (uport->icount.buf_overrun)
- seq_printf(m, " bo:%d", uport->icount.buf_overrun);
+ seq_printf(m, " bo:%u", uport->icount.buf_overrun);
#define INFOBIT(bit, str) \
if (uport->mctrl & (bit)) \
@@ -2100,7 +2098,7 @@ static int uart_proc_show(struct seq_file *m, void *v)
seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", "", "", "");
for (i = 0; i < drv->nr; i++)
- uart_line_info(m, drv, i);
+ uart_line_info(m, drv->state + i);
return 0;
}
#endif
@@ -2179,8 +2177,8 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
*
* Returns: 0 on success or -%EINVAL on failure
*/
-int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
- char **options)
+int uart_parse_earlycon(char *p, enum uart_iotype *iotype,
+ resource_size_t *addr, char **options)
{
if (strncmp(p, "mmio,", 5) == 0) {
*iotype = UPIO_MEM;
@@ -2426,10 +2424,10 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
}
/*
- * Disable the console device before suspending.
+ * Suspend the console device before suspending the port.
*/
if (uart_console(uport))
- console_stop(uport->cons);
+ console_suspend(uport->cons);
uart_change_pm(state, UART_PM_STATE_OFF);
@@ -2484,7 +2482,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
uart_port_unlock_irq(uport);
}
if (console_suspend_enabled)
- console_start(uport->cons);
+ console_resume(uport->cons);
}
if (tty_port_suspended(port)) {
@@ -2555,7 +2553,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
break;
}
- pr_info("%s%s%s at %s (irq = %d, base_baud = %d) is a %s\n",
+ pr_info("%s%s%s at %s (irq = %u, base_baud = %u) is a %s\n",
port->dev ? dev_name(port->dev) : "",
port->dev ? ": " : "",
port->name,
@@ -2563,7 +2561,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
/* The magic multiplier feature is a bit obscure, so report it too. */
if (port->flags & UPF_MAGIC_MULTIPLIER)
- pr_info("%s%s%s extra baud rates supported: %d, %d",
+ pr_info("%s%s%s extra baud rates supported: %u, %u",
port->dev ? dev_name(port->dev) : "",
port->dev ? ": " : "",
port->name,
@@ -2962,7 +2960,7 @@ static ssize_t close_delay_show(struct device *dev,
struct tty_port *port = dev_get_drvdata(dev);
uart_get_info(port, &tmp);
- return sprintf(buf, "%d\n", tmp.close_delay);
+ return sprintf(buf, "%u\n", tmp.close_delay);
}
static ssize_t closing_wait_show(struct device *dev,
@@ -2972,7 +2970,7 @@ static ssize_t closing_wait_show(struct device *dev,
struct tty_port *port = dev_get_drvdata(dev);
uart_get_info(port, &tmp);
- return sprintf(buf, "%d\n", tmp.closing_wait);
+ return sprintf(buf, "%u\n", tmp.closing_wait);
}
static ssize_t custom_divisor_show(struct device *dev,
@@ -2992,7 +2990,7 @@ static ssize_t io_type_show(struct device *dev,
struct tty_port *port = dev_get_drvdata(dev);
uart_get_info(port, &tmp);
- return sprintf(buf, "%d\n", tmp.io_type);
+ return sprintf(buf, "%u\n", tmp.io_type);
}
static ssize_t iomem_base_show(struct device *dev,
@@ -3012,7 +3010,7 @@ static ssize_t iomem_reg_shift_show(struct device *dev,
struct tty_port *port = dev_get_drvdata(dev);
uart_get_info(port, &tmp);
- return sprintf(buf, "%d\n", tmp.iomem_reg_shift);
+ return sprintf(buf, "%u\n", tmp.iomem_reg_shift);
}
static ssize_t console_show(struct device *dev,
@@ -3148,7 +3146,7 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
state->pm_state = UART_PM_STATE_UNDEFINED;
uart_port_set_cons(uport, drv->cons);
uport->minor = drv->tty_driver->minor_start + uport->line;
- uport->name = kasprintf(GFP_KERNEL, "%s%d", drv->dev_name,
+ uport->name = kasprintf(GFP_KERNEL, "%s%u", drv->dev_name,
drv->tty_driver->name_base + uport->line);
if (!uport->name)
return -ENOMEM;
@@ -3156,7 +3154,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
if (uport->cons && uport->dev)
of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
- tty_port_link_device(port, drv->tty_driver, uport->line);
uart_configure_port(drv, state, uport);
port->console = uart_console(uport);
@@ -3188,7 +3185,7 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
device_set_wakeup_capable(tty_dev, 1);
} else {
uport->flags |= UPF_DEAD;
- dev_err(uport->dev, "Cannot register tty device on line %d\n",
+ dev_err(uport->dev, "Cannot register tty device on line %u\n",
uport->line);
}
@@ -3291,9 +3288,9 @@ bool uart_match_port(const struct uart_port *port1,
case UPIO_AU:
case UPIO_TSI:
return port1->mapbase == port2->mapbase;
+ default:
+ return false;
}
-
- return false;
}
EXPORT_SYMBOL(uart_match_port);
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
index 8855688a5b6c..7b02c5ca4afd 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.c
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -217,7 +217,7 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
*
* This will get the {cts,rts,...}-gpios from device tree if they are present
* and request them, set direction etc, and return an allocated structure.
- * `devm_*` functions are used, so there's no need to call mctrl_gpio_free().
+ * `devm_*` functions are used, so there's no need to explicitly free.
* As this sets up the irq handling, make sure to not handle changes to the
* gpio input lines in your driver, too.
*/
@@ -268,32 +268,6 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
EXPORT_SYMBOL_GPL(mctrl_gpio_init);
/**
- * mctrl_gpio_free - explicitly free uart gpios
- * @dev: uart port's device
- * @gpios: gpios structure to be freed
- *
- * This will free the requested gpios in mctrl_gpio_init(). As `devm_*`
- * functions are used, there's generally no need to call this function.
- */
-void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
-{
- enum mctrl_gpio_idx i;
-
- if (gpios == NULL)
- return;
-
- for (i = 0; i < UART_GPIO_MAX; i++) {
- if (gpios->irq[i])
- devm_free_irq(gpios->port->dev, gpios->irq[i], gpios);
-
- if (gpios->gpio[i])
- devm_gpiod_put(dev, gpios->gpio[i]);
- }
- devm_kfree(dev, gpios);
-}
-EXPORT_SYMBOL_GPL(mctrl_gpio_free);
-
-/**
* mctrl_gpio_enable_ms - enable irqs and handling of changes to the ms lines
* @gpios: gpios to enable
*/
@@ -322,11 +296,7 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
}
EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms);
-/**
- * mctrl_gpio_disable_ms - disable irqs and handling of changes to the ms lines
- * @gpios: gpios to disable
- */
-void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
+static void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios, bool sync)
{
enum mctrl_gpio_idx i;
@@ -342,10 +312,34 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
if (!gpios->irq[i])
continue;
- disable_irq(gpios->irq[i]);
+ if (sync)
+ disable_irq(gpios->irq[i]);
+ else
+ disable_irq_nosync(gpios->irq[i]);
}
}
-EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms);
+
+/**
+ * mctrl_gpio_disable_ms_sync - disable irqs and handling of changes to the ms
+ * lines, and wait for any pending IRQ to be processed
+ * @gpios: gpios to disable
+ */
+void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios)
+{
+ mctrl_gpio_disable_ms(gpios, true);
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms_sync);
+
+/**
+ * mctrl_gpio_disable_ms_no_sync - disable irqs and handling of changes to the
+ * ms lines, and return immediately
+ * @gpios: gpios to disable
+ */
+void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios)
+{
+ mctrl_gpio_disable_ms(gpios, false);
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms_no_sync);
void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios)
{
diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h
index fc76910fb105..961e4ba0c6f8 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.h
+++ b/drivers/tty/serial/serial_mctrl_gpio.h
@@ -59,7 +59,7 @@ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
/*
* Request and set direction of modem control line GPIOs and set up irq
* handling.
- * devm_* functions are used, so there's no need to call mctrl_gpio_free().
+ * devm_* functions are used, so there's no need to explicitly free.
* Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
* allocation error.
*/
@@ -67,7 +67,7 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx);
/*
* Request and set direction of modem control line GPIOs.
- * devm_* functions are used, so there's no need to call mctrl_gpio_free().
+ * devm_* functions are used, so there's no need to explicitly free.
* Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
* allocation error.
*/
@@ -75,21 +75,21 @@ struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev,
unsigned int idx);
/*
- * Free the mctrl_gpios structure.
- * Normally, this function will not be called, as the GPIOs will
- * be disposed of by the resource management code.
+ * Enable gpio interrupts to report status line changes.
*/
-void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios);
+void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios);
/*
- * Enable gpio interrupts to report status line changes.
+ * Disable gpio interrupts to report status line changes, and block until
+ * any corresponding IRQ is processed
*/
-void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios);
+void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios);
/*
- * Disable gpio interrupts to report status line changes.
+ * Disable gpio interrupts to report status line changes, and return
+ * immediately
*/
-void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios);
+void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios);
/*
* Enable gpio wakeup interrupts to enable wake up source.
@@ -139,16 +139,15 @@ struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
return NULL;
}
-static inline
-void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
+static inline void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
{
}
-static inline void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
+static inline void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios)
{
}
-static inline void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
+static inline void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios)
{
}
diff --git a/drivers/tty/serial/sh-sci-common.h b/drivers/tty/serial/sh-sci-common.h
new file mode 100644
index 000000000000..bd9d9cfac1c8
--- /dev/null
+++ b/drivers/tty/serial/sh-sci-common.h
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __SH_SCI_COMMON_H__
+#define __SH_SCI_COMMON_H__
+
+#include <linux/serial_core.h>
+
+enum SCI_CLKS {
+ SCI_FCK, /* Functional Clock */
+ SCI_SCK, /* Optional External Clock */
+ SCI_BRG_INT, /* Optional BRG Internal Clock Source */
+ SCI_SCIF_CLK, /* Optional BRG External Clock Source */
+ SCI_NUM_CLKS
+};
+
+/* Offsets into the sci_port->irqs array */
+enum {
+ SCIx_ERI_IRQ,
+ SCIx_RXI_IRQ,
+ SCIx_TXI_IRQ,
+ SCIx_BRI_IRQ,
+ SCIx_DRI_IRQ,
+ SCIx_TEI_IRQ,
+ SCIx_NR_IRQS,
+
+ SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */
+};
+
+/* Bit x set means sampling rate x + 1 is supported */
+#define SCI_SR(x) BIT((x) - 1)
+#define SCI_SR_RANGE(x, y) GENMASK((y) - 1, (x) - 1)
+
+void sci_release_port(struct uart_port *port);
+int sci_request_port(struct uart_port *port);
+void sci_config_port(struct uart_port *port, int flags);
+int sci_verify_port(struct uart_port *port, struct serial_struct *ser);
+void sci_pm(struct uart_port *port, unsigned int state,
+ unsigned int oldstate);
+
+struct plat_sci_reg {
+ u8 offset;
+ u8 size;
+};
+
+struct sci_port_params_bits {
+ unsigned int rxtx_enable;
+ unsigned int te_clear;
+ unsigned int poll_sent_bits;
+};
+
+struct sci_common_regs {
+ unsigned int status;
+ unsigned int control;
+};
+
+/* The actual number of needed registers. This is used by sci only */
+#define SCI_NR_REGS 20
+
+struct sci_port_params {
+ const struct plat_sci_reg regs[SCI_NR_REGS];
+ const struct sci_common_regs *common_regs;
+ const struct sci_port_params_bits *param_bits;
+ unsigned int fifosize;
+ unsigned int overrun_reg;
+ unsigned int overrun_mask;
+ unsigned int sampling_rate_mask;
+ unsigned int error_mask;
+ unsigned int error_clear;
+};
+
+struct sci_port_ops {
+ u32 (*read_reg)(struct uart_port *port, int reg);
+ void (*write_reg)(struct uart_port *port, int reg, int value);
+ void (*clear_SCxSR)(struct uart_port *port, unsigned int mask);
+
+ void (*transmit_chars)(struct uart_port *port);
+ void (*receive_chars)(struct uart_port *port);
+
+ void (*poll_put_char)(struct uart_port *port, unsigned char c);
+
+ int (*set_rtrg)(struct uart_port *port, int rx_trig);
+ int (*rtrg_enabled)(struct uart_port *port);
+
+ void (*shutdown_complete)(struct uart_port *port);
+
+ void (*prepare_console_write)(struct uart_port *port, u32 ctrl);
+ void (*console_save)(struct uart_port *port);
+ void (*console_restore)(struct uart_port *port);
+ size_t (*suspend_regs_size)(void);
+};
+
+struct sci_of_data {
+ const struct sci_port_params *params;
+ const struct uart_ops *uart_ops;
+ const struct sci_port_ops *ops;
+ unsigned short regtype;
+ unsigned short type;
+};
+
+struct sci_port {
+ struct uart_port port;
+
+ /* Platform configuration */
+ const struct sci_port_params *params;
+ const struct plat_sci_port *cfg;
+
+ unsigned int sampling_rate_mask;
+ resource_size_t reg_size;
+ struct mctrl_gpios *gpios;
+
+ /* Clocks */
+ struct clk *clks[SCI_NUM_CLKS];
+ unsigned long clk_rates[SCI_NUM_CLKS];
+
+ int irqs[SCIx_NR_IRQS];
+ char *irqstr[SCIx_NR_IRQS];
+
+ struct dma_chan *chan_tx;
+ struct dma_chan *chan_rx;
+
+ struct reset_control *rstc;
+ struct sci_suspend_regs *suspend_regs;
+
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+ struct dma_chan *chan_tx_saved;
+ struct dma_chan *chan_rx_saved;
+ dma_cookie_t cookie_tx;
+ dma_cookie_t cookie_rx[2];
+ dma_cookie_t active_rx;
+ dma_addr_t tx_dma_addr;
+ unsigned int tx_dma_len;
+ struct scatterlist sg_rx[2];
+ void *rx_buf[2];
+ size_t buf_len_rx;
+ struct work_struct work_tx;
+ struct hrtimer rx_timer;
+ unsigned int rx_timeout; /* microseconds */
+#endif
+ unsigned int rx_frame;
+ int rx_trigger;
+ struct timer_list rx_fifo_timer;
+ int rx_fifo_timeout;
+ u16 hscif_tot;
+
+ const struct sci_port_ops *ops;
+
+ bool has_rtscts;
+ bool autorts;
+ bool tx_occurred;
+};
+
+#define to_sci_port(uart) container_of((uart), struct sci_port, port)
+
+void sci_port_disable(struct sci_port *sci_port);
+void sci_port_enable(struct sci_port *sci_port);
+
+int sci_startup(struct uart_port *port);
+void sci_shutdown(struct uart_port *port);
+
+#define min_sr(_port) ffs((_port)->sampling_rate_mask)
+#define max_sr(_port) fls((_port)->sampling_rate_mask)
+
+#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON
+int __init scix_early_console_setup(struct earlycon_device *device, const struct sci_of_data *data);
+#endif
+
+#endif /* __SH_SCI_COMMON_H__ */
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index b1ea48f38248..1c356544a832 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -56,19 +56,7 @@
#include "serial_mctrl_gpio.h"
#include "sh-sci.h"
-
-/* Offsets into the sci_port->irqs array */
-enum {
- SCIx_ERI_IRQ,
- SCIx_RXI_IRQ,
- SCIx_TXI_IRQ,
- SCIx_BRI_IRQ,
- SCIx_DRI_IRQ,
- SCIx_TEI_IRQ,
- SCIx_NR_IRQS,
-
- SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */
-};
+#include "sh-sci-common.h"
#define SCIx_IRQ_IS_MUXED(port) \
((port)->irqs[SCIx_ERI_IRQ] == \
@@ -76,90 +64,15 @@ enum {
((port)->irqs[SCIx_ERI_IRQ] && \
((port)->irqs[SCIx_RXI_IRQ] < 0))
-enum SCI_CLKS {
- SCI_FCK, /* Functional Clock */
- SCI_SCK, /* Optional External Clock */
- SCI_BRG_INT, /* Optional BRG Internal Clock Source */
- SCI_SCIF_CLK, /* Optional BRG External Clock Source */
- SCI_NUM_CLKS
-};
-
-/* Bit x set means sampling rate x + 1 is supported */
-#define SCI_SR(x) BIT((x) - 1)
-#define SCI_SR_RANGE(x, y) GENMASK((y) - 1, (x) - 1)
-
#define SCI_SR_SCIFAB SCI_SR(5) | SCI_SR(7) | SCI_SR(11) | \
SCI_SR(13) | SCI_SR(16) | SCI_SR(17) | \
SCI_SR(19) | SCI_SR(27)
-#define min_sr(_port) ffs((_port)->sampling_rate_mask)
-#define max_sr(_port) fls((_port)->sampling_rate_mask)
-
/* Iterate over all supported sampling rates, from high to low */
#define for_each_sr(_sr, _port) \
for ((_sr) = max_sr(_port); (_sr) >= min_sr(_port); (_sr)--) \
if ((_port)->sampling_rate_mask & SCI_SR((_sr)))
-struct plat_sci_reg {
- u8 offset, size;
-};
-
-struct sci_port_params {
- const struct plat_sci_reg regs[SCIx_NR_REGS];
- unsigned int fifosize;
- unsigned int overrun_reg;
- unsigned int overrun_mask;
- unsigned int sampling_rate_mask;
- unsigned int error_mask;
- unsigned int error_clear;
-};
-
-struct sci_port {
- struct uart_port port;
-
- /* Platform configuration */
- const struct sci_port_params *params;
- const struct plat_sci_port *cfg;
- unsigned int sampling_rate_mask;
- resource_size_t reg_size;
- struct mctrl_gpios *gpios;
-
- /* Clocks */
- struct clk *clks[SCI_NUM_CLKS];
- unsigned long clk_rates[SCI_NUM_CLKS];
-
- int irqs[SCIx_NR_IRQS];
- char *irqstr[SCIx_NR_IRQS];
-
- struct dma_chan *chan_tx;
- struct dma_chan *chan_rx;
-
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
- struct dma_chan *chan_tx_saved;
- struct dma_chan *chan_rx_saved;
- dma_cookie_t cookie_tx;
- dma_cookie_t cookie_rx[2];
- dma_cookie_t active_rx;
- dma_addr_t tx_dma_addr;
- unsigned int tx_dma_len;
- struct scatterlist sg_rx[2];
- void *rx_buf[2];
- size_t buf_len_rx;
- struct work_struct work_tx;
- struct hrtimer rx_timer;
- unsigned int rx_timeout; /* microseconds */
-#endif
- unsigned int rx_frame;
- int rx_trigger;
- struct timer_list rx_fifo_timer;
- int rx_fifo_timeout;
- u16 hscif_tot;
-
- bool has_rtscts;
- bool autorts;
- bool tx_occurred;
-};
-
#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
static struct sci_port sci_ports[SCI_NPORTS];
@@ -168,10 +81,40 @@ static struct uart_driver sci_uart_driver;
static bool sci_uart_earlycon;
static bool sci_uart_earlycon_dev_probing;
-static inline struct sci_port *
-to_sci_port(struct uart_port *uart)
+static const struct sci_port_params_bits sci_sci_port_params_bits = {
+ .rxtx_enable = SCSCR_RE | SCSCR_TE,
+ .te_clear = SCSCR_TE | SCSCR_TEIE,
+ .poll_sent_bits = SCI_TDRE | SCI_TEND
+};
+
+static const struct sci_port_params_bits sci_scif_port_params_bits = {
+ .rxtx_enable = SCSCR_RE | SCSCR_TE,
+ .te_clear = SCSCR_TE | SCSCR_TEIE,
+ .poll_sent_bits = SCIF_TDFE | SCIF_TEND
+};
+
+static const struct sci_common_regs sci_common_regs = {
+ .status = SCxSR,
+ .control = SCSCR,
+};
+
+struct sci_suspend_regs {
+ u16 scdl;
+ u16 sccks;
+ u16 scsmr;
+ u16 scscr;
+ u16 scfcr;
+ u16 scsptr;
+ u16 hssrr;
+ u16 scpcr;
+ u16 scpdr;
+ u8 scbrr;
+ u8 semr;
+};
+
+static size_t sci_suspend_regs_size(void)
{
- return container_of(uart, struct sci_port, port);
+ return sizeof(struct sci_suspend_regs);
}
static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
@@ -194,6 +137,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCI_DEFAULT_ERROR_MASK | SCI_ORER,
.error_clear = SCI_ERROR_CLEAR & ~SCI_ORER,
+ .param_bits = &sci_sci_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -216,6 +161,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCI_DEFAULT_ERROR_MASK | SCI_ORER,
.error_clear = SCI_ERROR_CLEAR & ~SCI_ORER,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -240,6 +187,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR_SCIFAB,
.error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER,
.error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -265,6 +214,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR_SCIFAB,
.error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER,
.error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -290,10 +241,12 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
- * The "SCIFA" that is in RZ/A2, RZ/G2L and RZ/T.
+ * The "SCIFA" that is in RZ/A2, RZ/G2L and RZ/T1.
* It looks like a normal SCIF with FIFO data, but with a
* compressed address space. Also, the break out of interrupts
* are different: ERI/BRI, RXI, TXI, TEI, DRI.
@@ -318,6 +271,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -349,6 +304,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -371,6 +328,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -395,6 +354,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -422,6 +383,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -451,6 +414,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR_RANGE(8, 32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -475,6 +440,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -502,6 +469,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -525,6 +494,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(16),
.error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER,
.error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
};
@@ -562,7 +533,7 @@ static void sci_serial_out(struct uart_port *p, int offset, int value)
WARN(1, "Invalid register access\n");
}
-static void sci_port_enable(struct sci_port *sci_port)
+void sci_port_enable(struct sci_port *sci_port)
{
unsigned int i;
@@ -578,7 +549,7 @@ static void sci_port_enable(struct sci_port *sci_port)
sci_port->port.uartclk = sci_port->clk_rates[SCI_FCK];
}
-static void sci_port_disable(struct sci_port *sci_port)
+void sci_port_disable(struct sci_port *sci_port)
{
unsigned int i;
@@ -718,12 +689,13 @@ static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask)
static int sci_poll_get_char(struct uart_port *port)
{
unsigned short status;
+ struct sci_port *s = to_sci_port(port);
int c;
do {
status = sci_serial_in(port, SCxSR);
if (status & SCxSR_ERRORS(port)) {
- sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
continue;
}
break;
@@ -736,7 +708,7 @@ static int sci_poll_get_char(struct uart_port *port)
/* Dummy read */
sci_serial_in(port, SCxSR);
- sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
return c;
}
@@ -744,14 +716,16 @@ static int sci_poll_get_char(struct uart_port *port)
static void sci_poll_put_char(struct uart_port *port, unsigned char c)
{
- unsigned short status;
+ struct sci_port *s = to_sci_port(port);
+ const struct sci_common_regs *regs = s->params->common_regs;
+ unsigned int status;
do {
- status = sci_serial_in(port, SCxSR);
+ status = s->ops->read_reg(port, regs->status);
} while (!(status & SCxSR_TDxE(port)));
sci_serial_out(port, SCxTDR, c);
- sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
+ s->ops->clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
}
#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE ||
CONFIG_SERIAL_SH_SCI_EARLYCON */
@@ -894,7 +868,7 @@ static void sci_transmit_chars(struct uart_port *port)
port->icount.tx++;
} while (--count > 0);
- sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_TDxE_CLEAR(port));
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
@@ -913,6 +887,7 @@ static void sci_transmit_chars(struct uart_port *port)
static void sci_receive_chars(struct uart_port *port)
{
struct tty_port *tport = &port->state->port;
+ struct sci_port *s = to_sci_port(port);
int i, count, copied = 0;
unsigned short status;
unsigned char flag;
@@ -967,7 +942,7 @@ static void sci_receive_chars(struct uart_port *port)
}
sci_serial_in(port, SCxSR); /* dummy read */
- sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
copied += count;
port->icount.rx += count;
@@ -980,16 +955,17 @@ static void sci_receive_chars(struct uart_port *port)
/* TTY buffers full; read from RX reg to prevent lockup */
sci_serial_in(port, SCxRDR);
sci_serial_in(port, SCxSR); /* dummy read */
- sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
}
}
static int sci_handle_errors(struct uart_port *port)
{
int copied = 0;
- unsigned short status = sci_serial_in(port, SCxSR);
- struct tty_port *tport = &port->state->port;
struct sci_port *s = to_sci_port(port);
+ const struct sci_common_regs *regs = s->params->common_regs;
+ unsigned int status = s->ops->read_reg(port, regs->status);
+ struct tty_port *tport = &port->state->port;
/* Handle overruns */
if (status & s->params->overrun_mask) {
@@ -1144,11 +1120,11 @@ static int scif_rtrg_enabled(struct uart_port *port)
static void rx_fifo_timer_fn(struct timer_list *t)
{
- struct sci_port *s = from_timer(s, t, rx_fifo_timer);
+ struct sci_port *s = timer_container_of(s, t, rx_fifo_timer);
struct uart_port *port = &s->port;
dev_dbg(port->dev, "Rx timed out\n");
- scif_set_rtrg(port, 1);
+ s->ops->set_rtrg(port, 1);
}
static ssize_t rx_fifo_trigger_show(struct device *dev,
@@ -1173,9 +1149,9 @@ static ssize_t rx_fifo_trigger_store(struct device *dev,
if (ret)
return ret;
- sci->rx_trigger = scif_set_rtrg(port, r);
+ sci->rx_trigger = sci->ops->set_rtrg(port, r);
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
- scif_set_rtrg(port, 1);
+ sci->ops->set_rtrg(port, 1);
return count;
}
@@ -1218,7 +1194,7 @@ static ssize_t rx_fifo_timeout_store(struct device *dev,
sci->hscif_tot = r << HSSCR_TOT_SHIFT;
} else {
sci->rx_fifo_timeout = r;
- scif_set_rtrg(port, 1);
+ sci->ops->set_rtrg(port, 1);
if (r > 0)
timer_setup(&sci->rx_fifo_timer, rx_fifo_timer_fn, 0);
}
@@ -1343,7 +1319,7 @@ static void sci_dma_rx_reenable_irq(struct sci_port *s)
s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
enable_irq(s->irqs[SCIx_RXI_IRQ]);
if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE)
- scif_set_rtrg(port, s->rx_trigger);
+ s->ops->set_rtrg(port, s->rx_trigger);
else
scr &= ~SCSCR_RDRQE;
}
@@ -1702,8 +1678,7 @@ static void sci_request_dma(struct uart_port *port)
dma += s->buf_len_rx;
}
- hrtimer_init(&s->rx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- s->rx_timer.function = sci_dma_rx_timer_fn;
+ hrtimer_setup(&s->rx_timer, sci_dma_rx_timer_fn, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
s->chan_rx_saved = s->chan_rx = chan;
@@ -1782,7 +1757,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
disable_irq_nosync(s->irqs[SCIx_RXI_IRQ]);
if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
- scif_set_rtrg(port, 1);
+ s->ops->set_rtrg(port, 1);
scr |= SCSCR_RIE;
} else {
scr |= SCSCR_RDRQE;
@@ -1808,8 +1783,8 @@ handle_pio:
#endif
if (s->rx_trigger > 1 && s->rx_fifo_timeout > 0) {
- if (!scif_rtrg_enabled(port))
- scif_set_rtrg(port, s->rx_trigger);
+ if (!s->ops->rtrg_enabled(port))
+ s->ops->set_rtrg(port, s->rx_trigger);
mod_timer(&s->rx_fifo_timer, jiffies + DIV_ROUND_UP(
s->rx_frame * HZ * s->rx_fifo_timeout, 1000000));
@@ -1819,7 +1794,7 @@ handle_pio:
* of whether the I_IXOFF is set, otherwise, how is the interrupt
* to be disabled?
*/
- sci_receive_chars(port);
+ s->ops->receive_chars(port);
return IRQ_HANDLED;
}
@@ -1828,9 +1803,10 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
{
struct uart_port *port = ptr;
unsigned long flags;
+ struct sci_port *s = to_sci_port(port);
uart_port_lock_irqsave(port, &flags);
- sci_transmit_chars(port);
+ s->ops->transmit_chars(port);
uart_port_unlock_irqrestore(port, flags);
return IRQ_HANDLED;
@@ -1839,16 +1815,18 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr)
{
struct uart_port *port = ptr;
+ struct sci_port *s = to_sci_port(port);
+ const struct sci_common_regs *regs = s->params->common_regs;
unsigned long flags;
- unsigned short ctrl;
+ u32 ctrl;
if (port->type != PORT_SCI)
return sci_tx_interrupt(irq, ptr);
uart_port_lock_irqsave(port, &flags);
- ctrl = sci_serial_in(port, SCSCR);
- ctrl &= ~(SCSCR_TE | SCSCR_TEIE);
- sci_serial_out(port, SCSCR, ctrl);
+ ctrl = s->ops->read_reg(port, regs->control) &
+ ~(s->params->param_bits->te_clear);
+ s->ops->write_reg(port, regs->control, ctrl);
uart_port_unlock_irqrestore(port, flags);
return IRQ_HANDLED;
@@ -1857,6 +1835,7 @@ static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr)
static irqreturn_t sci_br_interrupt(int irq, void *ptr)
{
struct uart_port *port = ptr;
+ struct sci_port *s = to_sci_port(port);
/* Handle BREAKs */
sci_handle_breaks(port);
@@ -1864,7 +1843,7 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr)
/* drop invalid character received before break was detected */
sci_serial_in(port, SCxRDR);
- sci_clear_SCxSR(port, SCxSR_BREAK_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_BREAK_CLEAR(port));
return IRQ_HANDLED;
}
@@ -1892,15 +1871,15 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr)
if (sci_handle_errors(port)) {
/* discard character in rx buffer */
sci_serial_in(port, SCxSR);
- sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
}
} else {
sci_handle_fifo_overrun(port);
if (!s->chan_rx)
- sci_receive_chars(port);
+ s->ops->receive_chars(port);
}
- sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
/* Kick the transmission */
if (!s->chan_tx)
@@ -2270,7 +2249,17 @@ static void sci_break_ctl(struct uart_port *port, int break_state)
uart_port_unlock_irqrestore(port, flags);
}
-static int sci_startup(struct uart_port *port)
+static void sci_shutdown_complete(struct uart_port *port)
+{
+ struct sci_port *s = to_sci_port(port);
+ u16 scr;
+
+ scr = sci_serial_in(port, SCSCR);
+ sci_serial_out(port, SCSCR,
+ scr & (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot));
+}
+
+int sci_startup(struct uart_port *port)
{
struct sci_port *s = to_sci_port(port);
int ret;
@@ -2289,27 +2278,20 @@ static int sci_startup(struct uart_port *port)
return 0;
}
-static void sci_shutdown(struct uart_port *port)
+void sci_shutdown(struct uart_port *port)
{
struct sci_port *s = to_sci_port(port);
unsigned long flags;
- u16 scr;
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
s->autorts = false;
- mctrl_gpio_disable_ms(to_sci_port(port)->gpios);
+ mctrl_gpio_disable_ms_sync(to_sci_port(port)->gpios);
uart_port_lock_irqsave(port, &flags);
sci_stop_rx(port);
sci_stop_tx(port);
- /*
- * Stop RX and TX, disable related interrupts, keep clock source
- * and HSCIF TOT bits
- */
- scr = sci_serial_in(port, SCSCR);
- sci_serial_out(port, SCSCR,
- scr & (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot));
+ s->ops->shutdown_complete(port);
uart_port_unlock_irqrestore(port, flags);
#ifdef CONFIG_SERIAL_SH_SCI_DMA
@@ -2321,7 +2303,7 @@ static void sci_shutdown(struct uart_port *port)
#endif
if (s->rx_trigger > 1 && s->rx_fifo_timeout > 0)
- del_timer_sync(&s->rx_fifo_timer);
+ timer_delete_sync(&s->rx_fifo_timer);
sci_free_irq(s);
sci_free_dma(port);
}
@@ -2386,8 +2368,8 @@ static int sci_brg_calc(struct sci_port *s, unsigned int bps,
/* calculate sample rate, BRR, and clock select */
static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
- unsigned int *brr, unsigned int *srr,
- unsigned int *cks)
+ unsigned int *brr, unsigned int *srr,
+ unsigned int *cks)
{
unsigned long freq = s->clk_rates[SCI_FCK];
unsigned int sr, br, prediv, scrate, c;
@@ -2464,9 +2446,9 @@ static void sci_reset(struct uart_port *port)
if (reg->size)
sci_serial_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
- sci_clear_SCxSR(port,
- SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) &
- SCxSR_BREAK_CLEAR(port));
+ s->ops->clear_SCxSR(port,
+ SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) &
+ SCxSR_BREAK_CLEAR(port));
if (sci_getreg(port, SCLSR)->size) {
status = sci_serial_in(port, SCLSR);
status &= ~(SCLSR_TO | SCLSR_ORER);
@@ -2475,14 +2457,14 @@ static void sci_reset(struct uart_port *port)
if (s->rx_trigger > 1) {
if (s->rx_fifo_timeout) {
- scif_set_rtrg(port, 1);
+ s->ops->set_rtrg(port, 1);
timer_setup(&s->rx_fifo_timer, rx_fifo_timer_fn, 0);
} else {
if (port->type == PORT_SCIFA ||
port->type == PORT_SCIFB)
- scif_set_rtrg(port, 1);
+ s->ops->set_rtrg(port, 1);
else
- scif_set_rtrg(port, s->rx_trigger);
+ s->ops->set_rtrg(port, s->rx_trigger);
}
}
}
@@ -2742,7 +2724,7 @@ done:
sci_enable_ms(port);
}
-static void sci_pm(struct uart_port *port, unsigned int state,
+void sci_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
struct sci_port *sci_port = to_sci_port(port);
@@ -2805,7 +2787,7 @@ static int sci_remap_port(struct uart_port *port)
return 0;
}
-static void sci_release_port(struct uart_port *port)
+void sci_release_port(struct uart_port *port)
{
struct sci_port *sport = to_sci_port(port);
@@ -2817,7 +2799,7 @@ static void sci_release_port(struct uart_port *port)
release_mem_region(port->mapbase, sport->reg_size);
}
-static int sci_request_port(struct uart_port *port)
+int sci_request_port(struct uart_port *port)
{
struct resource *res;
struct sci_port *sport = to_sci_port(port);
@@ -2839,7 +2821,7 @@ static int sci_request_port(struct uart_port *port)
return 0;
}
-static void sci_config_port(struct uart_port *port, int flags)
+void sci_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE) {
struct sci_port *sport = to_sci_port(port);
@@ -2849,7 +2831,7 @@ static void sci_config_port(struct uart_port *port, int flags)
}
}
-static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
+int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
{
if (ser->baud_base < 2400)
/* No paper tape reader for Mitch.. */
@@ -2858,6 +2840,75 @@ static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
return 0;
}
+static void sci_prepare_console_write(struct uart_port *port, u32 ctrl)
+{
+ struct sci_port *s = to_sci_port(port);
+ u32 ctrl_temp =
+ s->params->param_bits->rxtx_enable |
+ (s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) |
+ (ctrl & (SCSCR_CKE1 | SCSCR_CKE0)) |
+ s->hscif_tot;
+ sci_serial_out(port, SCSCR, ctrl_temp);
+}
+
+static void sci_console_save(struct uart_port *port)
+{
+ struct sci_port *s = to_sci_port(port);
+ struct sci_suspend_regs *regs = s->suspend_regs;
+
+ if (sci_getreg(port, SCDL)->size)
+ regs->scdl = sci_serial_in(port, SCDL);
+ if (sci_getreg(port, SCCKS)->size)
+ regs->sccks = sci_serial_in(port, SCCKS);
+ if (sci_getreg(port, SCSMR)->size)
+ regs->scsmr = sci_serial_in(port, SCSMR);
+ if (sci_getreg(port, SCSCR)->size)
+ regs->scscr = sci_serial_in(port, SCSCR);
+ if (sci_getreg(port, SCFCR)->size)
+ regs->scfcr = sci_serial_in(port, SCFCR);
+ if (sci_getreg(port, SCSPTR)->size)
+ regs->scsptr = sci_serial_in(port, SCSPTR);
+ if (sci_getreg(port, SCBRR)->size)
+ regs->scbrr = sci_serial_in(port, SCBRR);
+ if (sci_getreg(port, HSSRR)->size)
+ regs->hssrr = sci_serial_in(port, HSSRR);
+ if (sci_getreg(port, SCPCR)->size)
+ regs->scpcr = sci_serial_in(port, SCPCR);
+ if (sci_getreg(port, SCPDR)->size)
+ regs->scpdr = sci_serial_in(port, SCPDR);
+ if (sci_getreg(port, SEMR)->size)
+ regs->semr = sci_serial_in(port, SEMR);
+}
+
+static void sci_console_restore(struct uart_port *port)
+{
+ struct sci_port *s = to_sci_port(port);
+ struct sci_suspend_regs *regs = s->suspend_regs;
+
+ if (sci_getreg(port, SCDL)->size)
+ sci_serial_out(port, SCDL, regs->scdl);
+ if (sci_getreg(port, SCCKS)->size)
+ sci_serial_out(port, SCCKS, regs->sccks);
+ if (sci_getreg(port, SCSMR)->size)
+ sci_serial_out(port, SCSMR, regs->scsmr);
+ if (sci_getreg(port, SCSCR)->size)
+ sci_serial_out(port, SCSCR, regs->scscr);
+ if (sci_getreg(port, SCFCR)->size)
+ sci_serial_out(port, SCFCR, regs->scfcr);
+ if (sci_getreg(port, SCSPTR)->size)
+ sci_serial_out(port, SCSPTR, regs->scsptr);
+ if (sci_getreg(port, SCBRR)->size)
+ sci_serial_out(port, SCBRR, regs->scbrr);
+ if (sci_getreg(port, HSSRR)->size)
+ sci_serial_out(port, HSSRR, regs->hssrr);
+ if (sci_getreg(port, SCPCR)->size)
+ sci_serial_out(port, SCPCR, regs->scpcr);
+ if (sci_getreg(port, SCPDR)->size)
+ sci_serial_out(port, SCPDR, regs->scpdr);
+ if (sci_getreg(port, SEMR)->size)
+ sci_serial_out(port, SEMR, regs->semr);
+}
+
static const struct uart_ops sci_uart_ops = {
.tx_empty = sci_tx_empty,
.set_mctrl = sci_set_mctrl,
@@ -2883,6 +2934,25 @@ static const struct uart_ops sci_uart_ops = {
#endif
};
+static const struct sci_port_ops sci_port_ops = {
+ .read_reg = sci_serial_in,
+ .write_reg = sci_serial_out,
+ .clear_SCxSR = sci_clear_SCxSR,
+ .transmit_chars = sci_transmit_chars,
+ .receive_chars = sci_receive_chars,
+#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \
+ defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
+ .poll_put_char = sci_poll_put_char,
+#endif
+ .set_rtrg = scif_set_rtrg,
+ .rtrg_enabled = scif_rtrg_enabled,
+ .shutdown_complete = sci_shutdown_complete,
+ .prepare_console_write = sci_prepare_console_write,
+ .console_save = sci_console_save,
+ .console_restore = sci_console_restore,
+ .suspend_regs_size = sci_suspend_regs_size,
+};
+
static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
{
const char *clk_names[] = {
@@ -2926,10 +2996,13 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
}
static const struct sci_port_params *
-sci_probe_regmap(const struct plat_sci_port *cfg)
+sci_probe_regmap(const struct plat_sci_port *cfg, struct sci_port *sci_port)
{
unsigned int regtype;
+ sci_port->ops = &sci_port_ops;
+ sci_port->port.ops = &sci_uart_ops;
+
if (cfg->regtype != SCIx_PROBE_REGTYPE)
return &sci_port_params[cfg->regtype];
@@ -2977,7 +3050,6 @@ static int sci_init_single(struct platform_device *dev,
sci_port->cfg = p;
- port->ops = &sci_uart_ops;
port->iotype = UPIO_MEM;
port->line = index;
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_SH_SCI_CONSOLE);
@@ -3017,10 +3089,6 @@ static int sci_init_single(struct platform_device *dev,
for (i = 1; i < ARRAY_SIZE(sci_port->irqs); i++)
sci_port->irqs[i] = sci_port->irqs[0];
- sci_port->params = sci_probe_regmap(p);
- if (unlikely(sci_port->params == NULL))
- return -EINVAL;
-
switch (p->type) {
case PORT_SCIFB:
sci_port->rx_trigger = 48;
@@ -3088,7 +3156,7 @@ static int sci_init_single(struct platform_device *dev,
defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
static void serial_console_putchar(struct uart_port *port, unsigned char ch)
{
- sci_poll_put_char(port, ch);
+ to_sci_port(port)->ops->poll_put_char(port, ch);
}
/*
@@ -3100,7 +3168,9 @@ static void serial_console_write(struct console *co, const char *s,
{
struct sci_port *sci_port = &sci_ports[co->index];
struct uart_port *port = &sci_port->port;
- unsigned short bits, ctrl, ctrl_temp;
+ const struct sci_common_regs *regs = sci_port->params->common_regs;
+ unsigned int bits;
+ u32 ctrl;
unsigned long flags;
int locked = 1;
@@ -3112,21 +3182,21 @@ static void serial_console_write(struct console *co, const char *s,
uart_port_lock_irqsave(port, &flags);
/* first save SCSCR then disable interrupts, keep clock source */
- ctrl = sci_serial_in(port, SCSCR);
- ctrl_temp = SCSCR_RE | SCSCR_TE |
- (sci_port->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) |
- (ctrl & (SCSCR_CKE1 | SCSCR_CKE0));
- sci_serial_out(port, SCSCR, ctrl_temp | sci_port->hscif_tot);
+
+ ctrl = sci_port->ops->read_reg(port, regs->control);
+ sci_port->ops->prepare_console_write(port, ctrl);
uart_console_write(port, s, count, serial_console_putchar);
/* wait until fifo is empty and last bit has been transmitted */
- bits = SCxSR_TDxE(port) | SCxSR_TEND(port);
- while ((sci_serial_in(port, SCxSR) & bits) != bits)
+
+ bits = sci_port->params->param_bits->poll_sent_bits;
+
+ while ((sci_port->ops->read_reg(port, regs->status) & bits) != bits)
cpu_relax();
/* restore the SCSCR */
- sci_serial_out(port, SCSCR, ctrl);
+ sci_port->ops->write_reg(port, regs->control, ctrl);
if (locked)
uart_port_unlock_irqrestore(port, flags);
@@ -3204,13 +3274,18 @@ static struct console early_serial_console = {
static int sci_probe_earlyprintk(struct platform_device *pdev)
{
const struct plat_sci_port *cfg = dev_get_platdata(&pdev->dev);
+ struct sci_port *sp = &sci_ports[pdev->id];
if (early_serial_console.data)
return -EEXIST;
early_serial_console.index = pdev->id;
- sci_init_single(pdev, &sci_ports[pdev->id], pdev->id, cfg, true);
+ sp->params = sci_probe_regmap(cfg, sp);
+ if (!sp->params)
+ return -ENODEV;
+
+ sci_init_single(pdev, sp, pdev->id, cfg, true);
if (!strstr(early_serial_buf, "keep"))
early_serial_console.flags |= CON_BOOT;
@@ -3259,59 +3334,126 @@ static void sci_remove(struct platform_device *dev)
device_remove_file(&dev->dev, &dev_attr_rx_fifo_timeout);
}
+static const struct sci_of_data of_sci_scif_sh2 = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SH2_SCIF_FIFODATA_REGTYPE],
+};
-#define SCI_OF_DATA(type, regtype) (void *)((type) << 16 | (regtype))
-#define SCI_OF_TYPE(data) ((unsigned long)(data) >> 16)
-#define SCI_OF_REGTYPE(data) ((unsigned long)(data) & 0xffff)
+static const struct sci_of_data of_sci_scif_rz_scifa = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_RZ_SCIFA_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_RZ_SCIFA_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_scif_rzv2h = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_RZV2H_SCIF_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_RZV2H_SCIF_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_rcar_scif = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_SH4_SCIF_BRG_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SH4_SCIF_BRG_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_scif_sh4 = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_SH4_SCIF_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SH4_SCIF_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_scifa = {
+ .type = PORT_SCIFA,
+ .regtype = SCIx_SCIFA_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SCIFA_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_scifb = {
+ .type = PORT_SCIFB,
+ .regtype = SCIx_SCIFB_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SCIFB_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_hscif = {
+ .type = PORT_HSCIF,
+ .regtype = SCIx_HSCIF_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_HSCIF_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_sci = {
+ .type = PORT_SCI,
+ .regtype = SCIx_SCI_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SCI_REGTYPE],
+};
static const struct of_device_id of_sci_match[] __maybe_unused = {
/* SoC-specific types */
{
.compatible = "renesas,scif-r7s72100",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH2_SCIF_FIFODATA_REGTYPE),
+ .data = &of_sci_scif_sh2,
},
{
.compatible = "renesas,scif-r7s9210",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE),
+ .data = &of_sci_scif_rz_scifa,
},
{
.compatible = "renesas,scif-r9a07g044",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE),
+ .data = &of_sci_scif_rz_scifa,
},
{
.compatible = "renesas,scif-r9a09g057",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZV2H_SCIF_REGTYPE),
+ .data = &of_sci_scif_rzv2h,
},
/* Family-specific types */
{
.compatible = "renesas,rcar-gen1-scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ .data = &of_sci_rcar_scif,
}, {
.compatible = "renesas,rcar-gen2-scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ .data = &of_sci_rcar_scif,
}, {
.compatible = "renesas,rcar-gen3-scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ .data = &of_sci_rcar_scif
}, {
.compatible = "renesas,rcar-gen4-scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ .data = &of_sci_rcar_scif
},
/* Generic types */
{
.compatible = "renesas,scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_REGTYPE),
+ .data = &of_sci_scif_sh4,
}, {
.compatible = "renesas,scifa",
- .data = SCI_OF_DATA(PORT_SCIFA, SCIx_SCIFA_REGTYPE),
+ .data = &of_sci_scifa,
}, {
.compatible = "renesas,scifb",
- .data = SCI_OF_DATA(PORT_SCIFB, SCIx_SCIFB_REGTYPE),
+ .data = &of_sci_scifb,
}, {
.compatible = "renesas,hscif",
- .data = SCI_OF_DATA(PORT_HSCIF, SCIx_HSCIF_REGTYPE),
+ .data = &of_sci_hscif,
}, {
.compatible = "renesas,sci",
- .data = SCI_OF_DATA(PORT_SCI, SCIx_SCI_REGTYPE),
+ .data = &of_sci_sci,
}, {
/* Terminator */
},
@@ -3330,7 +3472,7 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
struct reset_control *rstc;
struct plat_sci_port *p;
struct sci_port *sp;
- const void *data;
+ const struct sci_of_data *data;
int id, ret;
if (!IS_ENABLED(CONFIG_OF) || !np)
@@ -3374,10 +3516,15 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
}
sp = &sci_ports[id];
+ sp->rstc = rstc;
*dev_id = id;
- p->type = SCI_OF_TYPE(data);
- p->regtype = SCI_OF_REGTYPE(data);
+ p->type = data->type;
+ p->regtype = data->regtype;
+
+ sp->ops = data->ops;
+ sp->port.ops = data->uart_ops;
+ sp->params = data->params;
sp->has_rtscts = of_property_read_bool(np, "uart-has-rtscts");
@@ -3484,6 +3631,7 @@ static int sci_probe(struct platform_device *dev)
p = sci_parse_dt(dev, &dev_id);
if (IS_ERR(p))
return PTR_ERR(p);
+ sp = &sci_ports[dev_id];
} else {
p = dev->dev.platform_data;
if (p == NULL) {
@@ -3492,9 +3640,17 @@ static int sci_probe(struct platform_device *dev)
}
dev_id = dev->id;
+ sp = &sci_ports[dev_id];
+ sp->params = sci_probe_regmap(p, sp);
+ if (!sp->params)
+ return -ENODEV;
}
- sp = &sci_ports[dev_id];
+ sp->suspend_regs = devm_kzalloc(&dev->dev,
+ sp->ops->suspend_regs_size(),
+ GFP_KERNEL);
+ if (!sp->suspend_regs)
+ return -ENOMEM;
/*
* In case:
@@ -3550,9 +3706,17 @@ static __maybe_unused int sci_suspend(struct device *dev)
{
struct sci_port *sport = dev_get_drvdata(dev);
- if (sport)
+ if (sport) {
uart_suspend_port(&sci_uart_driver, &sport->port);
+ if (!console_suspend_enabled && uart_console(&sport->port)) {
+ if (sport->ops->console_save)
+ sport->ops->console_save(&sport->port);
+ }
+ else
+ return reset_control_assert(sport->rstc);
+ }
+
return 0;
}
@@ -3560,8 +3724,19 @@ static __maybe_unused int sci_resume(struct device *dev)
{
struct sci_port *sport = dev_get_drvdata(dev);
- if (sport)
+ if (sport) {
+ if (!console_suspend_enabled && uart_console(&sport->port)) {
+ if (sport->ops->console_restore)
+ sport->ops->console_restore(&sport->port);
+ } else {
+ int ret = reset_control_deassert(sport->rstc);
+
+ if (ret)
+ return ret;
+ }
+
uart_resume_port(&sci_uart_driver, &sport->port);
+ }
return 0;
}
@@ -3616,21 +3791,31 @@ static int early_console_exit(struct console *co)
return 0;
}
-static int __init early_console_setup(struct earlycon_device *device,
- int type)
+int __init scix_early_console_setup(struct earlycon_device *device,
+ const struct sci_of_data *data)
{
+ const struct sci_common_regs *regs;
+
if (!device->port.membase)
return -ENODEV;
- device->port.type = type;
+ device->port.type = data->type;
sci_ports[0].port = device->port;
- port_cfg.type = type;
+
+ port_cfg.type = data->type;
+ port_cfg.regtype = data->regtype;
+
sci_ports[0].cfg = &port_cfg;
- sci_ports[0].params = sci_probe_regmap(&port_cfg);
+ sci_ports[0].params = data->params;
+ sci_ports[0].ops = data->ops;
+ sci_ports[0].port.ops = data->uart_ops;
sci_uart_earlycon = true;
- port_cfg.scscr = sci_serial_in(&sci_ports[0].port, SCSCR);
- sci_serial_out(&sci_ports[0].port, SCSCR,
- SCSCR_RE | SCSCR_TE | port_cfg.scscr);
+ regs = sci_ports[0].params->common_regs;
+
+ port_cfg.scscr = sci_ports[0].ops->read_reg(&sci_ports[0].port, regs->control);
+ sci_ports[0].ops->write_reg(&sci_ports[0].port,
+ regs->control,
+ sci_ports[0].params->param_bits->rxtx_enable | port_cfg.scscr);
device->con->write = serial_console_write;
device->con->exit = early_console_exit;
@@ -3640,41 +3825,39 @@ static int __init early_console_setup(struct earlycon_device *device,
static int __init sci_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_SCI);
+ return scix_early_console_setup(device, &of_sci_sci);
}
static int __init scif_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_SCIF);
+ return scix_early_console_setup(device, &of_sci_scif_sh4);
}
static int __init rzscifa_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- port_cfg.regtype = SCIx_RZ_SCIFA_REGTYPE;
- return early_console_setup(device, PORT_SCIF);
+ return scix_early_console_setup(device, &of_sci_scif_rz_scifa);
}
static int __init rzv2hscif_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- port_cfg.regtype = SCIx_RZV2H_SCIF_REGTYPE;
- return early_console_setup(device, PORT_SCIF);
+ return scix_early_console_setup(device, &of_sci_scif_rzv2h);
}
static int __init scifa_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_SCIFA);
+ return scix_early_console_setup(device, &of_sci_scifa);
}
static int __init scifb_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_SCIFB);
+ return scix_early_console_setup(device, &of_sci_scifb);
}
static int __init hscif_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_HSCIF);
+ return scix_early_console_setup(device, &of_sci_hscif);
}
OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h
index 0b65563c4e9e..951681aba586 100644
--- a/drivers/tty/serial/sh-sci.h
+++ b/drivers/tty/serial/sh-sci.h
@@ -32,8 +32,6 @@ enum {
HSRTRGR, /* Rx FIFO Data Count Trigger Register */
HSTTRGR, /* Tx FIFO Data Count Trigger Register */
SEMR, /* Serial extended mode register */
-
- SCIx_NR_REGS,
};
diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c
index 5904a2d4cefa..110d67613192 100644
--- a/drivers/tty/serial/sifive.c
+++ b/drivers/tty/serial/sifive.c
@@ -141,6 +141,7 @@
* @baud_rate: UART serial line rate (e.g., 115200 baud)
* @clk: reference to this device's clock
* @clk_notifier: clock rate change notifier for upstream clock changes
+ * @console_line_ended: indicate that the console line is fully written
*
* Configuration data specific to this SiFive UART.
*/
@@ -151,6 +152,7 @@ struct sifive_serial_port {
unsigned long baud_rate;
struct clk *clk;
struct notifier_block clk_notifier;
+ bool console_line_ended;
};
/*
@@ -563,8 +565,11 @@ static void sifive_serial_break_ctl(struct uart_port *port, int break_state)
static int sifive_serial_startup(struct uart_port *port)
{
struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
+ unsigned long flags;
+ uart_port_lock_irqsave(&ssp->port, &flags);
__ssp_enable_rxwm(ssp);
+ uart_port_unlock_irqrestore(&ssp->port, flags);
return 0;
}
@@ -572,9 +577,12 @@ static int sifive_serial_startup(struct uart_port *port)
static void sifive_serial_shutdown(struct uart_port *port)
{
struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
+ unsigned long flags;
+ uart_port_lock_irqsave(&ssp->port, &flags);
__ssp_disable_rxwm(ssp);
__ssp_disable_txwm(ssp);
+ uart_port_unlock_irqrestore(&ssp->port, flags);
}
/**
@@ -779,33 +787,88 @@ static void sifive_serial_console_putchar(struct uart_port *port, unsigned char
__ssp_wait_for_xmitr(ssp);
__ssp_transmit_char(ssp, ch);
+
+ ssp->console_line_ended = (ch == '\n');
+}
+
+static void sifive_serial_device_lock(struct console *co, unsigned long *flags)
+{
+ struct uart_port *up = &sifive_serial_console_ports[co->index]->port;
+
+ __uart_port_lock_irqsave(up, flags);
}
-static void sifive_serial_console_write(struct console *co, const char *s,
- unsigned int count)
+static void sifive_serial_device_unlock(struct console *co, unsigned long flags)
+{
+ struct uart_port *up = &sifive_serial_console_ports[co->index]->port;
+
+ __uart_port_unlock_irqrestore(up, flags);
+}
+
+static void sifive_serial_console_write_atomic(struct console *co,
+ struct nbcon_write_context *wctxt)
{
struct sifive_serial_port *ssp = sifive_serial_console_ports[co->index];
- unsigned long flags;
+ struct uart_port *port = &ssp->port;
unsigned int ier;
- int locked = 1;
if (!ssp)
return;
- if (oops_in_progress)
- locked = uart_port_trylock_irqsave(&ssp->port, &flags);
- else
- uart_port_lock_irqsave(&ssp->port, &flags);
+ if (!nbcon_enter_unsafe(wctxt))
+ return;
ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS);
__ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp);
- uart_console_write(&ssp->port, s, count, sifive_serial_console_putchar);
+ if (!ssp->console_line_ended)
+ uart_console_write(port, "\n", 1, sifive_serial_console_putchar);
+ uart_console_write(port, wctxt->outbuf, wctxt->len,
+ sifive_serial_console_putchar);
__ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp);
- if (locked)
- uart_port_unlock_irqrestore(&ssp->port, flags);
+ nbcon_exit_unsafe(wctxt);
+}
+
+static void sifive_serial_console_write_thread(struct console *co,
+ struct nbcon_write_context *wctxt)
+{
+ struct sifive_serial_port *ssp = sifive_serial_console_ports[co->index];
+ struct uart_port *port = &ssp->port;
+ unsigned int ier;
+
+ if (!ssp)
+ return;
+
+ if (!nbcon_enter_unsafe(wctxt))
+ return;
+
+ ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS);
+ __ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp);
+
+ if (nbcon_exit_unsafe(wctxt)) {
+ int len = READ_ONCE(wctxt->len);
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (!nbcon_enter_unsafe(wctxt))
+ break;
+
+ uart_console_write(port, wctxt->outbuf + i, 1,
+ sifive_serial_console_putchar);
+
+ if (!nbcon_exit_unsafe(wctxt))
+ break;
+ }
+ }
+
+ while (!nbcon_enter_unsafe(wctxt))
+ nbcon_reacquire_nobuf(wctxt);
+
+ __ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp);
+
+ nbcon_exit_unsafe(wctxt);
}
static int sifive_serial_console_setup(struct console *co, char *options)
@@ -823,6 +886,8 @@ static int sifive_serial_console_setup(struct console *co, char *options)
if (!ssp)
return -ENODEV;
+ ssp->console_line_ended = true;
+
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -833,10 +898,13 @@ static struct uart_driver sifive_serial_uart_driver;
static struct console sifive_serial_console = {
.name = SIFIVE_TTY_PREFIX,
- .write = sifive_serial_console_write,
+ .write_atomic = sifive_serial_console_write_atomic,
+ .write_thread = sifive_serial_console_write_thread,
+ .device_lock = sifive_serial_device_lock,
+ .device_unlock = sifive_serial_device_unlock,
.device = uart_console_device,
.setup = sifive_serial_console_setup,
- .flags = CON_PRINTBUFFER,
+ .flags = CON_PRINTBUFFER | CON_NBCON,
.index = -1,
.data = &sifive_serial_uart_driver,
};
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 0854ad8c90cd..ad06b760cfca 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -944,7 +944,7 @@ static void stm32_usart_enable_ms(struct uart_port *port)
static void stm32_usart_disable_ms(struct uart_port *port)
{
- mctrl_gpio_disable_ms(to_stm32_port(port)->gpios);
+ mctrl_gpio_disable_ms_sync(to_stm32_port(port)->gpios);
}
/* Transmit stop */
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index 7f0fef07e141..383141fe7ba0 100644
--- a/drivers/tty/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
@@ -151,16 +151,6 @@ static void serial_out(struct uart_sunsu_port *up, int offset, int value)
}
/*
- * We used to support using pause I/O for certain machines. We
- * haven't supported this for a while, but just in case it's badly
- * needed for certain old 386 machines, I've left these #define's
- * in....
- */
-#define serial_inp(up, offset) serial_in(up, offset)
-#define serial_outp(up, offset, value) serial_out(up, offset, value)
-
-
-/*
* For the 16C950
*/
static void serial_icr_write(struct uart_sunsu_port *up, int offset, int value)
@@ -169,20 +159,6 @@ static void serial_icr_write(struct uart_sunsu_port *up, int offset, int value)
serial_out(up, UART_ICR, value);
}
-#if 0 /* Unused currently */
-static unsigned int serial_icr_read(struct uart_sunsu_port *up, int offset)
-{
- unsigned int value;
-
- serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD);
- serial_out(up, UART_SCR, offset);
- value = serial_in(up, UART_ICR);
- serial_icr_write(up, UART_ACR, up->acr);
-
- return value;
-}
-#endif
-
#ifdef CONFIG_SERIAL_8250_RSA
/*
* Attempts to turn on the RSA FIFO. Returns zero on failure.
@@ -193,12 +169,12 @@ static int __enable_rsa(struct uart_sunsu_port *up)
unsigned char mode;
int result;
- mode = serial_inp(up, UART_RSA_MSR);
+ mode = serial_in(up, UART_RSA_MSR);
result = mode & UART_RSA_MSR_FIFO;
if (!result) {
- serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
- mode = serial_inp(up, UART_RSA_MSR);
+ serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
+ mode = serial_in(up, UART_RSA_MSR);
result = mode & UART_RSA_MSR_FIFO;
}
@@ -217,7 +193,7 @@ static void enable_rsa(struct uart_sunsu_port *up)
uart_port_unlock_irq(&up->port);
}
if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
- serial_outp(up, UART_RSA_FRR, 0);
+ serial_out(up, UART_RSA_FRR, 0);
}
}
@@ -236,12 +212,12 @@ static void disable_rsa(struct uart_sunsu_port *up)
up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {
uart_port_lock_irq(&up->port);
- mode = serial_inp(up, UART_RSA_MSR);
+ mode = serial_in(up, UART_RSA_MSR);
result = !(mode & UART_RSA_MSR_FIFO);
if (!result) {
- serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
- mode = serial_inp(up, UART_RSA_MSR);
+ serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
+ mode = serial_in(up, UART_RSA_MSR);
result = !(mode & UART_RSA_MSR_FIFO);
}
@@ -326,7 +302,7 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status)
int saw_console_brk = 0;
do {
- ch = serial_inp(up, UART_RX);
+ ch = serial_in(up, UART_RX);
flag = TTY_NORMAL;
up->port.icount.rx++;
@@ -387,7 +363,7 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status)
*/
tty_insert_flip_char(port, 0, TTY_OVERRUN);
ignore_char:
- *status = serial_inp(up, UART_LSR);
+ *status = serial_in(up, UART_LSR);
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
if (saw_console_brk)
@@ -401,7 +377,7 @@ static void transmit_chars(struct uart_sunsu_port *up)
int count;
if (up->port.x_char) {
- serial_outp(up, UART_TX, up->port.x_char);
+ serial_out(up, UART_TX, up->port.x_char);
up->port.icount.tx++;
up->port.x_char = 0;
return;
@@ -460,7 +436,7 @@ static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id)
uart_port_lock_irqsave(&up->port, &flags);
do {
- status = serial_inp(up, UART_LSR);
+ status = serial_in(up, UART_LSR);
if (status & UART_LSR_DR)
receive_chars(up, &status);
check_modem_status(up);
@@ -498,7 +474,7 @@ static void sunsu_change_mouse_baud(struct uart_sunsu_port *up)
static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break)
{
do {
- unsigned char ch = serial_inp(up, UART_RX);
+ unsigned char ch = serial_in(up, UART_RX);
/* Stop-A is handled by drivers/char/keyboard.c now. */
if (up->su_type == SU_PORT_KBD) {
@@ -530,7 +506,7 @@ static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id)
struct uart_sunsu_port *up = dev_id;
if (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)) {
- unsigned char status = serial_inp(up, UART_LSR);
+ unsigned char status = serial_in(up, UART_LSR);
if ((status & UART_LSR_DR) || (status & UART_LSR_BI))
receive_kbd_ms_chars(up, (status & UART_LSR_BI) != 0);
@@ -619,14 +595,14 @@ static int sunsu_startup(struct uart_port *port)
if (up->port.type == PORT_16C950) {
/* Wake up and initialize UART */
up->acr = 0;
- serial_outp(up, UART_LCR, 0xBF);
- serial_outp(up, UART_EFR, UART_EFR_ECB);
- serial_outp(up, UART_IER, 0);
- serial_outp(up, UART_LCR, 0);
+ serial_out(up, UART_LCR, 0xBF);
+ serial_out(up, UART_EFR, UART_EFR_ECB);
+ serial_out(up, UART_IER, 0);
+ serial_out(up, UART_LCR, 0);
serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
- serial_outp(up, UART_LCR, 0xBF);
- serial_outp(up, UART_EFR, UART_EFR_ECB);
- serial_outp(up, UART_LCR, 0);
+ serial_out(up, UART_LCR, 0xBF);
+ serial_out(up, UART_EFR, UART_EFR_ECB);
+ serial_out(up, UART_LCR, 0);
}
#ifdef CONFIG_SERIAL_8250_RSA
@@ -642,19 +618,19 @@ static int sunsu_startup(struct uart_port *port)
* (they will be reenabled in set_termios())
*/
if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) {
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
- serial_outp(up, UART_FCR, 0);
+ serial_out(up, UART_FCR, 0);
}
/*
* Clear the interrupt registers.
*/
- (void) serial_inp(up, UART_LSR);
- (void) serial_inp(up, UART_RX);
- (void) serial_inp(up, UART_IIR);
- (void) serial_inp(up, UART_MSR);
+ (void) serial_in(up, UART_LSR);
+ (void) serial_in(up, UART_RX);
+ (void) serial_in(up, UART_IIR);
+ (void) serial_in(up, UART_MSR);
/*
* At this point, there's no way the LSR could still be 0xff;
@@ -662,7 +638,7 @@ static int sunsu_startup(struct uart_port *port)
* here.
*/
if (!(up->port.flags & UPF_BUGGY_UART) &&
- (serial_inp(up, UART_LSR) == 0xff)) {
+ (serial_in(up, UART_LSR) == 0xff)) {
printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
return -ENODEV;
}
@@ -682,7 +658,7 @@ static int sunsu_startup(struct uart_port *port)
/*
* Now, initialize the UART
*/
- serial_outp(up, UART_LCR, UART_LCR_WLEN8);
+ serial_out(up, UART_LCR, UART_LCR_WLEN8);
uart_port_lock_irqsave(&up->port, &flags);
@@ -697,7 +673,7 @@ static int sunsu_startup(struct uart_port *port)
* anyway, so we don't enable them here.
*/
up->ier = UART_IER_RLSI | UART_IER_RDI;
- serial_outp(up, UART_IER, up->ier);
+ serial_out(up, UART_IER, up->ier);
if (up->port.flags & UPF_FOURPORT) {
unsigned int icp;
@@ -712,10 +688,10 @@ static int sunsu_startup(struct uart_port *port)
/*
* And clear the interrupt registers again for luck.
*/
- (void) serial_inp(up, UART_LSR);
- (void) serial_inp(up, UART_RX);
- (void) serial_inp(up, UART_IIR);
- (void) serial_inp(up, UART_MSR);
+ (void) serial_in(up, UART_LSR);
+ (void) serial_in(up, UART_RX);
+ (void) serial_in(up, UART_IIR);
+ (void) serial_in(up, UART_MSR);
return 0;
}
@@ -730,7 +706,7 @@ static void sunsu_shutdown(struct uart_port *port)
* Disable interrupts from this port
*/
up->ier = 0;
- serial_outp(up, UART_IER, 0);
+ serial_out(up, UART_IER, 0);
uart_port_lock_irqsave(&up->port, &flags);
if (up->port.flags & UPF_FOURPORT) {
@@ -746,11 +722,11 @@ static void sunsu_shutdown(struct uart_port *port)
/*
* Disable break condition and FIFOs
*/
- serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+ serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT);
- serial_outp(up, UART_FCR, 0);
+ serial_out(up, UART_FCR, 0);
#ifdef CONFIG_SERIAL_8250_RSA
/*
@@ -872,22 +848,22 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag,
serial_out(up, UART_IER, up->ier);
if (uart_config[up->port.type].flags & UART_STARTECH) {
- serial_outp(up, UART_LCR, 0xBF);
- serial_outp(up, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0);
+ serial_out(up, UART_LCR, 0xBF);
+ serial_out(up, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0);
}
- serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
- serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */
- serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */
+ serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
+ serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */
+ serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */
if (up->port.type == PORT_16750)
- serial_outp(up, UART_FCR, fcr); /* set fcr */
- serial_outp(up, UART_LCR, cval); /* reset DLAB */
+ serial_out(up, UART_FCR, fcr); /* set fcr */
+ serial_out(up, UART_LCR, cval); /* reset DLAB */
up->lcr = cval; /* Save LCR */
if (up->port.type != PORT_16750) {
if (fcr & UART_FCR_ENABLE_FIFO) {
/* emulated UARTs (Lucent Venus 167x) need two steps */
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
}
- serial_outp(up, UART_FCR, fcr); /* set fcr */
+ serial_out(up, UART_FCR, fcr); /* set fcr */
}
up->cflag = cflag;
@@ -1051,18 +1027,18 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
* 0x80 is a non-existent port; which should be safe since
* include/asm/io.h also makes this assumption.
*/
- scratch = serial_inp(up, UART_IER);
- serial_outp(up, UART_IER, 0);
+ scratch = serial_in(up, UART_IER);
+ serial_out(up, UART_IER, 0);
#ifdef __i386__
outb(0xff, 0x080);
#endif
- scratch2 = serial_inp(up, UART_IER);
- serial_outp(up, UART_IER, 0x0f);
+ scratch2 = serial_in(up, UART_IER);
+ serial_out(up, UART_IER, 0x0f);
#ifdef __i386__
outb(0, 0x080);
#endif
- scratch3 = serial_inp(up, UART_IER);
- serial_outp(up, UART_IER, scratch);
+ scratch3 = serial_in(up, UART_IER);
+ serial_out(up, UART_IER, scratch);
if (scratch2 != 0 || scratch3 != 0x0F)
goto out; /* We failed; there's nothing here */
}
@@ -1080,16 +1056,16 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
* that conflicts with COM 1-4 --- we hope!
*/
if (!(up->port.flags & UPF_SKIP_TEST)) {
- serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A);
- status1 = serial_inp(up, UART_MSR) & 0xF0;
- serial_outp(up, UART_MCR, save_mcr);
+ serial_out(up, UART_MCR, UART_MCR_LOOP | 0x0A);
+ status1 = serial_in(up, UART_MSR) & 0xF0;
+ serial_out(up, UART_MCR, save_mcr);
if (status1 != 0x90)
goto out; /* We failed loopback test */
}
- serial_outp(up, UART_LCR, 0xBF); /* set up for StarTech test */
- serial_outp(up, UART_EFR, 0); /* EFR is the same as FCR */
- serial_outp(up, UART_LCR, 0);
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_out(up, UART_LCR, 0xBF); /* set up for StarTech test */
+ serial_out(up, UART_EFR, 0); /* EFR is the same as FCR */
+ serial_out(up, UART_LCR, 0);
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
scratch = serial_in(up, UART_IIR) >> 6;
switch (scratch) {
case 0:
@@ -1107,19 +1083,19 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
}
if (up->port.type == PORT_16550A) {
/* Check for Startech UART's */
- serial_outp(up, UART_LCR, UART_LCR_DLAB);
+ serial_out(up, UART_LCR, UART_LCR_DLAB);
if (serial_in(up, UART_EFR) == 0) {
up->port.type = PORT_16650;
} else {
- serial_outp(up, UART_LCR, 0xBF);
+ serial_out(up, UART_LCR, 0xBF);
if (serial_in(up, UART_EFR) == 0)
up->port.type = PORT_16650V2;
}
}
if (up->port.type == PORT_16550A) {
/* Check for TI 16750 */
- serial_outp(up, UART_LCR, save_lcr | UART_LCR_DLAB);
- serial_outp(up, UART_FCR,
+ serial_out(up, UART_LCR, save_lcr | UART_LCR_DLAB);
+ serial_out(up, UART_FCR,
UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
scratch = serial_in(up, UART_IIR) >> 5;
if (scratch == 7) {
@@ -1129,24 +1105,24 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
* mode if the UART_FCR7_64BYTE bit was set
* while UART_LCR_DLAB was latched.
*/
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
- serial_outp(up, UART_LCR, 0);
- serial_outp(up, UART_FCR,
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_out(up, UART_LCR, 0);
+ serial_out(up, UART_FCR,
UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
scratch = serial_in(up, UART_IIR) >> 5;
if (scratch == 6)
up->port.type = PORT_16750;
}
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
}
- serial_outp(up, UART_LCR, save_lcr);
+ serial_out(up, UART_LCR, save_lcr);
if (up->port.type == PORT_16450) {
scratch = serial_in(up, UART_SCR);
- serial_outp(up, UART_SCR, 0xa5);
+ serial_out(up, UART_SCR, 0xa5);
status1 = serial_in(up, UART_SCR);
- serial_outp(up, UART_SCR, 0x5a);
+ serial_out(up, UART_SCR, 0x5a);
status2 = serial_in(up, UART_SCR);
- serial_outp(up, UART_SCR, scratch);
+ serial_out(up, UART_SCR, scratch);
if ((status1 != 0xa5) || (status2 != 0x5a))
up->port.type = PORT_8250;
@@ -1163,15 +1139,15 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
*/
#ifdef CONFIG_SERIAL_8250_RSA
if (up->port.type == PORT_RSA)
- serial_outp(up, UART_RSA_FRR, 0);
+ serial_out(up, UART_RSA_FRR, 0);
#endif
- serial_outp(up, UART_MCR, save_mcr);
- serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO |
+ serial_out(up, UART_MCR, save_mcr);
+ serial_out(up, UART_FCR, (UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT));
- serial_outp(up, UART_FCR, 0);
+ serial_out(up, UART_FCR, 0);
(void)serial_in(up, UART_RX);
- serial_outp(up, UART_IER, 0);
+ serial_out(up, UART_IER, 0);
out:
uart_port_unlock_irqrestore(&up->port, flags);
diff --git a/drivers/tty/serial/tegra-utc.c b/drivers/tty/serial/tegra-utc.c
new file mode 100644
index 000000000000..0c70d3e7b9b9
--- /dev/null
+++ b/drivers/tty/serial/tegra-utc.c
@@ -0,0 +1,625 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// NVIDIA Tegra UTC (UART Trace Controller) driver.
+
+#include <linux/bits.h>
+#include <linux/console.h>
+#include <linux/container_of.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <linux/kfifo.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/property.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/types.h>
+
+#define TEGRA_UTC_ENABLE 0x000
+#define TEGRA_UTC_ENABLE_CLIENT_ENABLE BIT(0)
+
+#define TEGRA_UTC_FIFO_THRESHOLD 0x008
+
+#define TEGRA_UTC_COMMAND 0x00c
+#define TEGRA_UTC_COMMAND_RESET BIT(0)
+#define TEGRA_UTC_COMMAND_FLUSH BIT(1)
+
+#define TEGRA_UTC_DATA 0x020
+
+#define TEGRA_UTC_FIFO_STATUS 0x100
+#define TEGRA_UTC_FIFO_EMPTY BIT(0)
+#define TEGRA_UTC_FIFO_FULL BIT(1)
+#define TEGRA_UTC_FIFO_REQ BIT(2)
+#define TEGRA_UTC_FIFO_OVERFLOW BIT(3)
+#define TEGRA_UTC_FIFO_TIMEOUT BIT(4)
+
+#define TEGRA_UTC_FIFO_OCCUPANCY 0x104
+
+#define TEGRA_UTC_INTR_STATUS 0x108
+#define TEGRA_UTC_INTR_SET 0x10c
+#define TEGRA_UTC_INTR_MASK 0x110
+#define TEGRA_UTC_INTR_CLEAR 0x114
+#define TEGRA_UTC_INTR_EMPTY BIT(0)
+#define TEGRA_UTC_INTR_FULL BIT(1)
+#define TEGRA_UTC_INTR_REQ BIT(2)
+#define TEGRA_UTC_INTR_OVERFLOW BIT(3)
+#define TEGRA_UTC_INTR_TIMEOUT BIT(4)
+
+#define TEGRA_UTC_UART_NR 16
+
+#define TEGRA_UTC_INTR_COMMON (TEGRA_UTC_INTR_REQ | TEGRA_UTC_INTR_FULL | TEGRA_UTC_INTR_EMPTY)
+
+struct tegra_utc_port {
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
+ struct console console;
+#endif
+ struct uart_port port;
+
+ void __iomem *rx_base;
+ void __iomem *tx_base;
+
+ u32 tx_irqmask;
+ u32 rx_irqmask;
+
+ unsigned int fifosize;
+ u32 tx_threshold;
+ u32 rx_threshold;
+};
+
+static u32 tegra_utc_rx_readl(struct tegra_utc_port *tup, unsigned int offset)
+{
+ void __iomem *addr = tup->rx_base + offset;
+
+ return readl_relaxed(addr);
+}
+
+static void tegra_utc_rx_writel(struct tegra_utc_port *tup, u32 val, unsigned int offset)
+{
+ void __iomem *addr = tup->rx_base + offset;
+
+ writel_relaxed(val, addr);
+}
+
+static u32 tegra_utc_tx_readl(struct tegra_utc_port *tup, unsigned int offset)
+{
+ void __iomem *addr = tup->tx_base + offset;
+
+ return readl_relaxed(addr);
+}
+
+static void tegra_utc_tx_writel(struct tegra_utc_port *tup, u32 val, unsigned int offset)
+{
+ void __iomem *addr = tup->tx_base + offset;
+
+ writel_relaxed(val, addr);
+}
+
+static void tegra_utc_enable_tx_irq(struct tegra_utc_port *tup)
+{
+ tup->tx_irqmask = TEGRA_UTC_INTR_REQ;
+
+ tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_MASK);
+ tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_SET);
+}
+
+static void tegra_utc_disable_tx_irq(struct tegra_utc_port *tup)
+{
+ tup->tx_irqmask = 0x0;
+
+ tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_MASK);
+ tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_SET);
+}
+
+static void tegra_utc_stop_tx(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ tegra_utc_disable_tx_irq(tup);
+}
+
+static void tegra_utc_init_tx(struct tegra_utc_port *tup)
+{
+ /* Disable TX. */
+ tegra_utc_tx_writel(tup, 0x0, TEGRA_UTC_ENABLE);
+
+ /* Update the FIFO Threshold. */
+ tegra_utc_tx_writel(tup, tup->tx_threshold, TEGRA_UTC_FIFO_THRESHOLD);
+
+ /* Clear and mask all the interrupts. */
+ tegra_utc_tx_writel(tup, TEGRA_UTC_INTR_COMMON, TEGRA_UTC_INTR_CLEAR);
+ tegra_utc_disable_tx_irq(tup);
+
+ /* Enable TX. */
+ tegra_utc_tx_writel(tup, TEGRA_UTC_ENABLE_CLIENT_ENABLE, TEGRA_UTC_ENABLE);
+}
+
+static void tegra_utc_init_rx(struct tegra_utc_port *tup)
+{
+ tup->rx_irqmask = TEGRA_UTC_INTR_REQ | TEGRA_UTC_INTR_TIMEOUT;
+
+ tegra_utc_rx_writel(tup, TEGRA_UTC_COMMAND_RESET, TEGRA_UTC_COMMAND);
+ tegra_utc_rx_writel(tup, tup->rx_threshold, TEGRA_UTC_FIFO_THRESHOLD);
+
+ /* Clear all the pending interrupts. */
+ tegra_utc_rx_writel(tup, TEGRA_UTC_INTR_TIMEOUT | TEGRA_UTC_INTR_OVERFLOW |
+ TEGRA_UTC_INTR_COMMON, TEGRA_UTC_INTR_CLEAR);
+ tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_MASK);
+ tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_SET);
+
+ /* Enable RX. */
+ tegra_utc_rx_writel(tup, TEGRA_UTC_ENABLE_CLIENT_ENABLE, TEGRA_UTC_ENABLE);
+}
+
+static bool tegra_utc_tx_chars(struct tegra_utc_port *tup)
+{
+ struct uart_port *port = &tup->port;
+ unsigned int pending;
+ u8 c;
+
+ pending = uart_port_tx(port, c,
+ !(tegra_utc_tx_readl(tup, TEGRA_UTC_FIFO_STATUS) & TEGRA_UTC_FIFO_FULL),
+ tegra_utc_tx_writel(tup, c, TEGRA_UTC_DATA));
+
+ return pending;
+}
+
+static void tegra_utc_rx_chars(struct tegra_utc_port *tup)
+{
+ struct tty_port *port = &tup->port.state->port;
+ unsigned int max_chars = 256;
+ u32 status;
+ int sysrq;
+ u32 ch;
+
+ while (max_chars--) {
+ status = tegra_utc_rx_readl(tup, TEGRA_UTC_FIFO_STATUS);
+ if (status & TEGRA_UTC_FIFO_EMPTY)
+ break;
+
+ ch = tegra_utc_rx_readl(tup, TEGRA_UTC_DATA);
+ tup->port.icount.rx++;
+
+ if (status & TEGRA_UTC_FIFO_OVERFLOW)
+ tup->port.icount.overrun++;
+
+ uart_port_unlock(&tup->port);
+ sysrq = uart_handle_sysrq_char(&tup->port, ch);
+ uart_port_lock(&tup->port);
+
+ if (!sysrq)
+ tty_insert_flip_char(port, ch, TTY_NORMAL);
+ }
+
+ tty_flip_buffer_push(port);
+}
+
+static irqreturn_t tegra_utc_isr(int irq, void *dev_id)
+{
+ struct tegra_utc_port *tup = dev_id;
+ unsigned int handled = 0;
+ u32 status;
+
+ uart_port_lock(&tup->port);
+
+ /* Process RX_REQ and RX_TIMEOUT interrupts. */
+ do {
+ status = tegra_utc_rx_readl(tup, TEGRA_UTC_INTR_STATUS) & tup->rx_irqmask;
+ if (status) {
+ tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_CLEAR);
+ tegra_utc_rx_chars(tup);
+ handled = 1;
+ }
+ } while (status);
+
+ /* Process TX_REQ interrupt. */
+ do {
+ status = tegra_utc_tx_readl(tup, TEGRA_UTC_INTR_STATUS) & tup->tx_irqmask;
+ if (status) {
+ tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_CLEAR);
+ tegra_utc_tx_chars(tup);
+ handled = 1;
+ }
+ } while (status);
+
+ uart_port_unlock(&tup->port);
+
+ return IRQ_RETVAL(handled);
+}
+
+static unsigned int tegra_utc_tx_empty(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ return tegra_utc_tx_readl(tup, TEGRA_UTC_FIFO_OCCUPANCY) ? 0 : TIOCSER_TEMT;
+}
+
+static void tegra_utc_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static unsigned int tegra_utc_get_mctrl(struct uart_port *port)
+{
+ return 0;
+}
+
+static void tegra_utc_start_tx(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ if (tegra_utc_tx_chars(tup))
+ tegra_utc_enable_tx_irq(tup);
+}
+
+static void tegra_utc_stop_rx(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ tup->rx_irqmask = 0x0;
+ tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_MASK);
+ tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_SET);
+}
+
+static void tegra_utc_hw_init(struct tegra_utc_port *tup)
+{
+ tegra_utc_init_tx(tup);
+ tegra_utc_init_rx(tup);
+}
+
+static int tegra_utc_startup(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+ int ret;
+
+ tegra_utc_hw_init(tup);
+
+ /* Interrupt is dedicated to this UTC client. */
+ ret = request_irq(port->irq, tegra_utc_isr, 0, dev_name(port->dev), tup);
+ if (ret < 0)
+ dev_err(port->dev, "failed to register interrupt handler\n");
+
+ return ret;
+}
+
+static void tegra_utc_shutdown(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ tegra_utc_rx_writel(tup, 0x0, TEGRA_UTC_ENABLE);
+ free_irq(port->irq, tup);
+}
+
+static void tegra_utc_set_termios(struct uart_port *port, struct ktermios *termios,
+ const struct ktermios *old)
+{
+ /* The Tegra UTC clients supports only 8-N-1 configuration without HW flow control */
+ termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
+ termios->c_cflag &= ~(CMSPAR | CRTSCTS);
+ termios->c_cflag |= CS8 | CLOCAL;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+
+static int tegra_utc_poll_init(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ tegra_utc_hw_init(tup);
+ return 0;
+}
+
+static int tegra_utc_get_poll_char(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ if (tegra_utc_rx_readl(tup, TEGRA_UTC_FIFO_STATUS) & TEGRA_UTC_FIFO_EMPTY)
+ return NO_POLL_CHAR;
+
+ return tegra_utc_rx_readl(tup, TEGRA_UTC_DATA);
+}
+
+static void tegra_utc_put_poll_char(struct uart_port *port, unsigned char ch)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+ u32 val;
+
+ read_poll_timeout_atomic(tegra_utc_tx_readl, val, !(val & TEGRA_UTC_FIFO_FULL),
+ 0, USEC_PER_SEC, false, tup, TEGRA_UTC_FIFO_STATUS);
+
+ tegra_utc_tx_writel(tup, ch, TEGRA_UTC_DATA);
+}
+
+#endif
+
+static const struct uart_ops tegra_utc_uart_ops = {
+ .tx_empty = tegra_utc_tx_empty,
+ .set_mctrl = tegra_utc_set_mctrl,
+ .get_mctrl = tegra_utc_get_mctrl,
+ .stop_tx = tegra_utc_stop_tx,
+ .start_tx = tegra_utc_start_tx,
+ .stop_rx = tegra_utc_stop_rx,
+ .startup = tegra_utc_startup,
+ .shutdown = tegra_utc_shutdown,
+ .set_termios = tegra_utc_set_termios,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_init = tegra_utc_poll_init,
+ .poll_get_char = tegra_utc_get_poll_char,
+ .poll_put_char = tegra_utc_put_poll_char,
+#endif
+};
+
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
+#define TEGRA_UTC_DEFAULT_FIFO_THRESHOLD 4
+#define TEGRA_UTC_EARLYCON_MAX_BURST_SIZE 128
+
+static void tegra_utc_putc(struct uart_port *port, unsigned char c)
+{
+ writel(c, port->membase + TEGRA_UTC_DATA);
+}
+
+static void tegra_utc_early_write(struct console *con, const char *s, unsigned int n)
+{
+ struct earlycon_device *dev = con->data;
+
+ while (n) {
+ u32 burst_size = TEGRA_UTC_EARLYCON_MAX_BURST_SIZE;
+
+ burst_size -= readl(dev->port.membase + TEGRA_UTC_FIFO_OCCUPANCY);
+ if (n < burst_size)
+ burst_size = n;
+
+ uart_console_write(&dev->port, s, burst_size, tegra_utc_putc);
+
+ n -= burst_size;
+ s += burst_size;
+ }
+}
+
+static int __init tegra_utc_early_console_setup(struct earlycon_device *device, const char *opt)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ /* Configure TX */
+ writel(TEGRA_UTC_COMMAND_FLUSH | TEGRA_UTC_COMMAND_RESET,
+ device->port.membase + TEGRA_UTC_COMMAND);
+ writel(TEGRA_UTC_DEFAULT_FIFO_THRESHOLD, device->port.membase + TEGRA_UTC_FIFO_THRESHOLD);
+
+ /* Clear and mask all the interrupts. */
+ writel(TEGRA_UTC_INTR_COMMON, device->port.membase + TEGRA_UTC_INTR_CLEAR);
+
+ writel(0x0, device->port.membase + TEGRA_UTC_INTR_MASK);
+ writel(0x0, device->port.membase + TEGRA_UTC_INTR_SET);
+
+ /* Enable TX. */
+ writel(TEGRA_UTC_ENABLE_CLIENT_ENABLE, device->port.membase + TEGRA_UTC_ENABLE);
+
+ device->con->write = tegra_utc_early_write;
+
+ return 0;
+}
+OF_EARLYCON_DECLARE(tegra_utc, "nvidia,tegra264-utc", tegra_utc_early_console_setup);
+
+static void tegra_utc_console_putchar(struct uart_port *port, unsigned char ch)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ tegra_utc_tx_writel(tup, ch, TEGRA_UTC_DATA);
+}
+
+static void tegra_utc_console_write_atomic(struct console *cons, struct nbcon_write_context *wctxt)
+{
+ struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
+ unsigned int len;
+ char *outbuf;
+
+ if (!nbcon_enter_unsafe(wctxt))
+ return;
+
+ outbuf = wctxt->outbuf;
+ len = wctxt->len;
+
+ while (len) {
+ u32 burst_size = tup->fifosize;
+
+ burst_size -= tegra_utc_tx_readl(tup, TEGRA_UTC_FIFO_OCCUPANCY);
+ if (len < burst_size)
+ burst_size = len;
+
+ uart_console_write(&tup->port, outbuf, burst_size, tegra_utc_console_putchar);
+
+ outbuf += burst_size;
+ len -= burst_size;
+ }
+
+ nbcon_exit_unsafe(wctxt);
+}
+
+static void tegra_utc_console_write_thread(struct console *cons, struct nbcon_write_context *wctxt)
+{
+ struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
+ unsigned int len = READ_ONCE(wctxt->len);
+ unsigned int i;
+ u32 val;
+
+ for (i = 0; i < len; i++) {
+ if (!nbcon_enter_unsafe(wctxt))
+ break;
+
+ read_poll_timeout_atomic(tegra_utc_tx_readl, val, !(val & TEGRA_UTC_FIFO_FULL),
+ 0, USEC_PER_SEC, false, tup, TEGRA_UTC_FIFO_STATUS);
+ uart_console_write(&tup->port, wctxt->outbuf + i, 1, tegra_utc_console_putchar);
+
+ if (!nbcon_exit_unsafe(wctxt))
+ break;
+ }
+}
+
+static void tegra_utc_console_device_lock(struct console *cons, unsigned long *flags)
+{
+ struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
+ struct uart_port *port = &tup->port;
+
+ __uart_port_lock_irqsave(port, flags);
+}
+
+static void tegra_utc_console_device_unlock(struct console *cons, unsigned long flags)
+{
+ struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
+ struct uart_port *port = &tup->port;
+
+ __uart_port_unlock_irqrestore(port, flags);
+}
+
+static int tegra_utc_console_setup(struct console *cons, char *options)
+{
+ struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
+
+ tegra_utc_init_tx(tup);
+
+ return 0;
+}
+#endif
+
+static struct uart_driver tegra_utc_driver = {
+ .driver_name = "tegra-utc",
+ .dev_name = "ttyUTC",
+ .nr = TEGRA_UTC_UART_NR,
+};
+
+static int tegra_utc_setup_port(struct device *dev, struct tegra_utc_port *tup)
+{
+ tup->port.dev = dev;
+ tup->port.fifosize = tup->fifosize;
+ tup->port.flags = UPF_BOOT_AUTOCONF;
+ tup->port.iotype = UPIO_MEM;
+ tup->port.ops = &tegra_utc_uart_ops;
+ tup->port.type = PORT_TEGRA_TCU;
+ tup->port.private_data = tup;
+
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
+ strscpy(tup->console.name, "ttyUTC", sizeof(tup->console.name));
+ tup->console.write_atomic = tegra_utc_console_write_atomic;
+ tup->console.write_thread = tegra_utc_console_write_thread;
+ tup->console.device_lock = tegra_utc_console_device_lock;
+ tup->console.device_unlock = tegra_utc_console_device_unlock;
+ tup->console.device = uart_console_device;
+ tup->console.setup = tegra_utc_console_setup;
+ tup->console.flags = CON_PRINTBUFFER | CON_NBCON;
+ tup->console.data = &tegra_utc_driver;
+#endif
+
+ return uart_read_port_properties(&tup->port);
+}
+
+static int tegra_utc_register_port(struct tegra_utc_port *tup)
+{
+ int ret;
+
+ ret = uart_add_one_port(&tegra_utc_driver, &tup->port);
+ if (ret)
+ return ret;
+
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
+ register_console(&tup->console);
+#endif
+
+ return 0;
+}
+
+static int tegra_utc_probe(struct platform_device *pdev)
+{
+ const unsigned int *soc_fifosize;
+ struct device *dev = &pdev->dev;
+ struct tegra_utc_port *tup;
+ int ret;
+
+ tup = devm_kzalloc(dev, sizeof(*tup), GFP_KERNEL);
+ if (!tup)
+ return -ENOMEM;
+
+ ret = device_property_read_u32(dev, "tx-threshold", &tup->tx_threshold);
+ if (ret)
+ return dev_err_probe(dev, ret, "missing %s property\n", "tx-threshold");
+
+ ret = device_property_read_u32(dev, "rx-threshold", &tup->rx_threshold);
+ if (ret)
+ return dev_err_probe(dev, ret, "missing %s property\n", "rx-threshold");
+
+ soc_fifosize = device_get_match_data(dev);
+ tup->fifosize = *soc_fifosize;
+
+ tup->tx_base = devm_platform_ioremap_resource_byname(pdev, "tx");
+ if (IS_ERR(tup->tx_base))
+ return PTR_ERR(tup->tx_base);
+
+ tup->rx_base = devm_platform_ioremap_resource_byname(pdev, "rx");
+ if (IS_ERR(tup->rx_base))
+ return PTR_ERR(tup->rx_base);
+
+ ret = tegra_utc_setup_port(dev, tup);
+ if (ret)
+ dev_err_probe(dev, ret, "failed to setup uart port\n");
+
+ platform_set_drvdata(pdev, tup);
+
+ return tegra_utc_register_port(tup);
+}
+
+static void tegra_utc_remove(struct platform_device *pdev)
+{
+ struct tegra_utc_port *tup = platform_get_drvdata(pdev);
+
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
+ unregister_console(&tup->console);
+#endif
+ uart_remove_one_port(&tegra_utc_driver, &tup->port);
+}
+
+static const unsigned int tegra264_utc_soc = 128;
+
+static const struct of_device_id tegra_utc_of_match[] = {
+ { .compatible = "nvidia,tegra264-utc", .data = &tegra264_utc_soc },
+ {}
+};
+MODULE_DEVICE_TABLE(of, tegra_utc_of_match);
+
+static struct platform_driver tegra_utc_platform_driver = {
+ .probe = tegra_utc_probe,
+ .remove = tegra_utc_remove,
+ .driver = {
+ .name = "tegra-utc",
+ .of_match_table = tegra_utc_of_match,
+ },
+};
+
+static int __init tegra_utc_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&tegra_utc_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&tegra_utc_platform_driver);
+ if (ret)
+ uart_unregister_driver(&tegra_utc_driver);
+
+ return ret;
+}
+module_init(tegra_utc_init);
+
+static void __exit tegra_utc_exit(void)
+{
+ platform_driver_unregister(&tegra_utc_platform_driver);
+ uart_unregister_driver(&tegra_utc_driver);
+}
+module_exit(tegra_utc_exit);
+
+MODULE_AUTHOR("Kartik Rajput <kkartik@nvidia.com>");
+MODULE_DESCRIPTION("Tegra UART Trace Controller");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index a41e7fc373b7..39c1fd1ff9ce 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -880,16 +880,6 @@ of_err:
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- if (!ulite_uart_driver.state) {
- dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n");
- ret = uart_register_driver(&ulite_uart_driver);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to register driver\n");
- clk_disable_unprepare(pdata->clk);
- return ret;
- }
- }
-
ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata);
pm_runtime_mark_last_busy(&pdev->dev);
@@ -929,16 +919,25 @@ static struct platform_driver ulite_platform_driver = {
static int __init ulite_init(void)
{
+ int ret;
+
+ pr_debug("uartlite: calling uart_register_driver()\n");
+ ret = uart_register_driver(&ulite_uart_driver);
+ if (ret)
+ return ret;
pr_debug("uartlite: calling platform_driver_register()\n");
- return platform_driver_register(&ulite_platform_driver);
+ ret = platform_driver_register(&ulite_platform_driver);
+ if (ret)
+ uart_unregister_driver(&ulite_uart_driver);
+
+ return ret;
}
static void __exit ulite_exit(void)
{
platform_driver_unregister(&ulite_platform_driver);
- if (ulite_uart_driver.state)
- uart_unregister_driver(&ulite_uart_driver);
+ uart_unregister_driver(&ulite_uart_driver);
}
module_init(ulite_init);
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 92ec51870d1d..fe457bf1e15b 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -454,7 +454,7 @@ static void cdns_uart_handle_tx(void *dev_id)
if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED &&
(kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))) {
- cdns_uart->tx_timer.function = &cdns_rs485_rx_callback;
+ hrtimer_update_function(&cdns_uart->tx_timer, cdns_rs485_rx_callback);
hrtimer_start(&cdns_uart->tx_timer,
ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart)), HRTIMER_MODE_REL);
}
@@ -734,7 +734,7 @@ static void cdns_uart_start_tx(struct uart_port *port)
if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
if (!cdns_uart->rs485_tx_started) {
- cdns_uart->tx_timer.function = &cdns_rs485_tx_callback;
+ hrtimer_update_function(&cdns_uart->tx_timer, cdns_rs485_tx_callback);
cdns_rs485_tx_setup(cdns_uart);
return hrtimer_start(&cdns_uart->tx_timer,
ms_to_ktime(port->rs485.delay_rts_before_send),
@@ -1626,8 +1626,8 @@ static int cdns_rs485_config(struct uart_port *port, struct ktermios *termios,
writel(val, port->membase + CDNS_UART_MODEMCR);
/* Timer setup */
- hrtimer_init(&cdns_uart->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- cdns_uart->tx_timer.function = &cdns_rs485_tx_callback;
+ hrtimer_setup(&cdns_uart->tx_timer, &cdns_rs485_tx_callback, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
/* Disable transmitter and make Rx setup*/
cdns_uart_stop_tx(port);
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index bd8d92ee7c53..3865b10d2d43 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -2220,7 +2220,7 @@ static void isr_txeom(struct slgt_info *info, unsigned short status)
}
info->tx_active = false;
- del_timer(&info->tx_timer);
+ timer_delete(&info->tx_timer);
if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done) {
info->signals &= ~SerialSignal_RTS;
@@ -2375,8 +2375,8 @@ static void shutdown(struct slgt_info *info)
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
- del_timer_sync(&info->tx_timer);
- del_timer_sync(&info->rx_timer);
+ timer_delete_sync(&info->tx_timer);
+ timer_delete_sync(&info->rx_timer);
kfree(info->tx_buf);
info->tx_buf = NULL;
@@ -3955,7 +3955,7 @@ static void tx_stop(struct slgt_info *info)
{
unsigned short val;
- del_timer(&info->tx_timer);
+ timer_delete(&info->tx_timer);
tdma_reset(info);
@@ -5002,7 +5002,7 @@ static int adapter_test(struct slgt_info *info)
*/
static void tx_timeout(struct timer_list *t)
{
- struct slgt_info *info = from_timer(info, t, tx_timer);
+ struct slgt_info *info = timer_container_of(info, t, tx_timer);
unsigned long flags;
DBGINFO(("%s tx_timeout\n", info->device_name));
@@ -5026,7 +5026,7 @@ static void tx_timeout(struct timer_list *t)
*/
static void rx_timeout(struct timer_list *t)
{
- struct slgt_info *info = from_timer(info, t, rx_timer);
+ struct slgt_info *info = timer_container_of(info, t, rx_timer);
unsigned long flags;
DBGINFO(("%s rx_timeout\n", info->device_name));
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index f85ce02e4725..d77c03d22227 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -712,7 +712,8 @@ static void sysrq_parse_reset_sequence(struct sysrq_state *state)
static void sysrq_do_reset(struct timer_list *t)
{
- struct sysrq_state *state = from_timer(state, t, keyreset_timer);
+ struct sysrq_state *state = timer_container_of(state, t,
+ keyreset_timer);
state->reset_requested = true;
@@ -743,7 +744,7 @@ static void sysrq_detect_reset_sequence(struct sysrq_state *state,
*/
if (value && state->reset_seq_cnt) {
state->reset_canceled = true;
- del_timer(&state->keyreset_timer);
+ timer_delete(&state->keyreset_timer);
}
} else if (value == 0) {
/*
@@ -751,7 +752,7 @@ static void sysrq_detect_reset_sequence(struct sysrq_state *state,
* to be pressed and held for the reset timeout
* to hold.
*/
- del_timer(&state->keyreset_timer);
+ timer_delete(&state->keyreset_timer);
if (--state->reset_seq_cnt == 0)
state->reset_canceled = false;
diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c
index 1d81eeefb068..75542333c54a 100644
--- a/drivers/tty/tty_audit.c
+++ b/drivers/tty/tty_audit.c
@@ -12,12 +12,14 @@
#include <linux/tty.h>
#include "tty.h"
+#define TTY_AUDIT_BUF_SIZE 4096
+
struct tty_audit_buf {
struct mutex mutex; /* Protects all data below */
dev_t dev; /* The TTY which the data is from */
bool icanon;
size_t valid;
- u8 *data; /* Allocated size N_TTY_BUF_SIZE */
+ u8 *data; /* Allocated size TTY_AUDIT_BUF_SIZE */
};
static struct tty_audit_buf *tty_audit_buf_ref(void)
@@ -37,7 +39,7 @@ static struct tty_audit_buf *tty_audit_buf_alloc(void)
if (!buf)
goto err;
- buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+ buf->data = kmalloc(TTY_AUDIT_BUF_SIZE, GFP_KERNEL);
if (!buf->data)
goto err_buf;
@@ -235,14 +237,14 @@ void tty_audit_add_data(const struct tty_struct *tty, const void *data,
do {
size_t run;
- run = N_TTY_BUF_SIZE - buf->valid;
+ run = TTY_AUDIT_BUF_SIZE - buf->valid;
if (run > size)
run = size;
memcpy(buf->data + buf->valid, data, run);
buf->valid += run;
data += run;
size -= run;
- if (buf->valid == N_TTY_BUF_SIZE)
+ if (buf->valid == TTY_AUDIT_BUF_SIZE)
tty_audit_buf_push(buf);
} while (size != 0);
mutex_unlock(&buf->mutex);
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 449dbd216460..e2d92cf70eb7 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -276,11 +276,10 @@ static void check_tty_count(struct tty_struct *tty, const char *routine)
struct list_head *p;
int count = 0, kopen_count = 0;
- spin_lock(&tty->files_lock);
- list_for_each(p, &tty->tty_files) {
- count++;
- }
- spin_unlock(&tty->files_lock);
+ scoped_guard(spinlock, &tty->files_lock)
+ list_for_each(p, &tty->tty_files)
+ count++;
+
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_SLAVE &&
tty->link && tty->link->count)
@@ -378,7 +377,7 @@ EXPORT_SYMBOL_GPL(tty_dev_name_to_number);
*/
struct tty_driver *tty_find_polling_driver(char *name, int *line)
{
- struct tty_driver *p, *res = NULL;
+ struct tty_driver *p;
int tty_line = 0;
int len;
char *str, *stp;
@@ -392,7 +391,8 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
len = str - name;
tty_line = simple_strtoul(str, &str, 10);
- mutex_lock(&tty_mutex);
+ guard(mutex)(&tty_mutex);
+
/* Search through the tty devices to look for a match */
list_for_each_entry(p, &tty_drivers, tty_drivers) {
if (!len || strncmp(name, p->name, len) != 0)
@@ -405,14 +405,12 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
if (tty_line >= 0 && tty_line < p->num && p->ops &&
p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) {
- res = tty_driver_kref_get(p);
*line = tty_line;
- break;
+ return tty_driver_kref_get(p);
}
}
- mutex_unlock(&tty_mutex);
- return res;
+ return NULL;
}
EXPORT_SYMBOL_GPL(tty_find_polling_driver);
#endif
@@ -531,16 +529,15 @@ EXPORT_SYMBOL_GPL(tty_wakeup);
*/
static struct file *tty_release_redirect(struct tty_struct *tty)
{
- struct file *f = NULL;
+ guard(spinlock)(&redirect_lock);
- spin_lock(&redirect_lock);
if (redirect && file_tty(redirect) == tty) {
- f = redirect;
+ struct file *f = redirect;
redirect = NULL;
+ return f;
}
- spin_unlock(&redirect_lock);
- return f;
+ return NULL;
}
/**
@@ -765,11 +762,8 @@ void __stop_tty(struct tty_struct *tty)
*/
void stop_tty(struct tty_struct *tty)
{
- unsigned long flags;
-
- spin_lock_irqsave(&tty->flow.lock, flags);
+ guard(spinlock_irqsave)(&tty->flow.lock);
__stop_tty(tty);
- spin_unlock_irqrestore(&tty->flow.lock, flags);
}
EXPORT_SYMBOL(stop_tty);
@@ -796,11 +790,8 @@ void __start_tty(struct tty_struct *tty)
*/
void start_tty(struct tty_struct *tty)
{
- unsigned long flags;
-
- spin_lock_irqsave(&tty->flow.lock, flags);
+ guard(spinlock_irqsave)(&tty->flow.lock);
__start_tty(tty);
- spin_unlock_irqrestore(&tty->flow.lock, flags);
}
EXPORT_SYMBOL(start_tty);
@@ -809,7 +800,8 @@ static void tty_update_time(struct tty_struct *tty, bool mtime)
time64_t sec = ktime_get_real_seconds();
struct tty_file_private *priv;
- spin_lock(&tty->files_lock);
+ guard(spinlock)(&tty->files_lock);
+
list_for_each_entry(priv, &tty->tty_files, list) {
struct inode *inode = file_inode(priv->file);
struct timespec64 time = mtime ? inode_get_mtime(inode) : inode_get_atime(inode);
@@ -827,7 +819,6 @@ static void tty_update_time(struct tty_struct *tty, bool mtime)
inode_set_atime(inode, sec, 0);
}
}
- spin_unlock(&tty->files_lock);
}
/*
@@ -2314,13 +2305,12 @@ static int tiocsti(struct tty_struct *tty, u8 __user *p)
*/
static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
{
- int err;
+ guard(mutex)(&tty->winsize_mutex);
- mutex_lock(&tty->winsize_mutex);
- err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
- mutex_unlock(&tty->winsize_mutex);
+ if (copy_to_user(arg, &tty->winsize, sizeof(*arg)))
+ return -EFAULT;
- return err ? -EFAULT : 0;
+ return 0;
}
/**
@@ -2335,10 +2325,10 @@ int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
{
struct pid *pgrp;
- /* Lock the tty */
- mutex_lock(&tty->winsize_mutex);
+ guard(mutex)(&tty->winsize_mutex);
+
if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
- goto done;
+ return 0;
/* Signal the foreground process group */
pgrp = tty_get_pgrp(tty);
@@ -2347,8 +2337,7 @@ int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
put_pid(pgrp);
tty->winsize = *ws;
-done:
- mutex_unlock(&tty->winsize_mutex);
+
return 0;
}
EXPORT_SYMBOL(tty_do_resize);
@@ -2409,13 +2398,14 @@ static int tioccons(struct file *file)
return -EBADF;
if (!(file->f_mode & FMODE_CAN_WRITE))
return -EINVAL;
- spin_lock(&redirect_lock);
- if (redirect) {
- spin_unlock(&redirect_lock);
+
+ guard(spinlock)(&redirect_lock);
+
+ if (redirect)
return -EBUSY;
- }
+
redirect = get_file(file);
- spin_unlock(&redirect_lock);
+
return 0;
}
@@ -3028,11 +3018,9 @@ void __do_SAK(struct tty_struct *tty)
struct task_struct *g, *p;
struct pid *session;
int i;
- unsigned long flags;
- spin_lock_irqsave(&tty->ctrl.lock, flags);
- session = get_pid(tty->ctrl.session);
- spin_unlock_irqrestore(&tty->ctrl.lock, flags);
+ scoped_guard(spinlock_irqsave, &tty->ctrl.lock)
+ session = get_pid(tty->ctrl.session);
tty_ldisc_flush(tty);
@@ -3055,7 +3043,7 @@ void __do_SAK(struct tty_struct *tty)
PIDTYPE_SID);
continue;
}
- task_lock(p);
+ guard(task_lock)(p);
i = iterate_fd(p->files, 0, this_tty, tty);
if (i != 0) {
tty_notice(tty, "SAK: killed process %d (%s): by fd#%d\n",
@@ -3063,7 +3051,6 @@ void __do_SAK(struct tty_struct *tty)
group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p,
PIDTYPE_SID);
}
- task_unlock(p);
}
read_unlock(&tasklist_lock);
put_pid(session);
@@ -3329,10 +3316,12 @@ EXPORT_SYMBOL(tty_unregister_device);
* __tty_alloc_driver - allocate tty driver
* @lines: count of lines this driver can handle at most
* @owner: module which is responsible for this driver
- * @flags: some of %TTY_DRIVER_ flags, will be set in driver->flags
+ * @flags: some of enum tty_driver_flag, will be set in driver->flags
+ *
+ * This should not be called directly, tty_alloc_driver() should be used
+ * instead.
*
- * This should not be called directly, some of the provided macros should be
- * used instead. Use IS_ERR() and friends on @retval.
+ * Returns: struct tty_driver or a PTR-encoded error (use IS_ERR() and friends).
*/
struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
unsigned long flags)
@@ -3463,9 +3452,8 @@ int tty_register_driver(struct tty_driver *driver)
goto err_unreg_char;
}
- mutex_lock(&tty_mutex);
- list_add(&driver->tty_drivers, &tty_drivers);
- mutex_unlock(&tty_mutex);
+ scoped_guard(mutex, &tty_mutex)
+ list_add(&driver->tty_drivers, &tty_drivers);
if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
for (i = 0; i < driver->num; i++) {
@@ -3484,9 +3472,8 @@ err_unreg_devs:
for (i--; i >= 0; i--)
tty_unregister_device(driver, i);
- mutex_lock(&tty_mutex);
- list_del(&driver->tty_drivers);
- mutex_unlock(&tty_mutex);
+ scoped_guard(mutex, &tty_mutex)
+ list_del(&driver->tty_drivers);
err_unreg_char:
unregister_chrdev_region(dev, driver->num);
@@ -3505,9 +3492,8 @@ void tty_unregister_driver(struct tty_driver *driver)
{
unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
driver->num);
- mutex_lock(&tty_mutex);
- list_del(&driver->tty_drivers);
- mutex_unlock(&tty_mutex);
+ scoped_guard(mutex, &tty_mutex)
+ list_del(&driver->tty_drivers);
}
EXPORT_SYMBOL(tty_unregister_driver);
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index 85de90eebc7b..90c70d8d14e3 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -122,21 +122,19 @@ EXPORT_SYMBOL(tty_unthrottle);
*/
bool tty_throttle_safe(struct tty_struct *tty)
{
- bool ret = true;
-
- mutex_lock(&tty->throttle_mutex);
- if (!tty_throttled(tty)) {
- if (tty->flow_change != TTY_THROTTLE_SAFE)
- ret = false;
- else {
- set_bit(TTY_THROTTLED, &tty->flags);
- if (tty->ops->throttle)
- tty->ops->throttle(tty);
- }
- }
- mutex_unlock(&tty->throttle_mutex);
+ guard(mutex)(&tty->throttle_mutex);
- return ret;
+ if (tty_throttled(tty))
+ return true;
+
+ if (tty->flow_change != TTY_THROTTLE_SAFE)
+ return false;
+
+ set_bit(TTY_THROTTLED, &tty->flags);
+ if (tty->ops->throttle)
+ tty->ops->throttle(tty);
+
+ return true;
}
/**
@@ -152,21 +150,19 @@ bool tty_throttle_safe(struct tty_struct *tty)
*/
bool tty_unthrottle_safe(struct tty_struct *tty)
{
- bool ret = true;
+ guard(mutex)(&tty->throttle_mutex);
- mutex_lock(&tty->throttle_mutex);
- if (tty_throttled(tty)) {
- if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
- ret = false;
- else {
- clear_bit(TTY_THROTTLED, &tty->flags);
- if (tty->ops->unthrottle)
- tty->ops->unthrottle(tty);
- }
- }
- mutex_unlock(&tty->throttle_mutex);
+ if (!tty_throttled(tty))
+ return true;
- return ret;
+ if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
+ return false;
+
+ clear_bit(TTY_THROTTLED, &tty->flags);
+ if (tty->ops->unthrottle)
+ tty->ops->unthrottle(tty);
+
+ return true;
}
/**
diff --git a/drivers/tty/tty_ldsem.c b/drivers/tty/tty_ldsem.c
index 3be428c16260..4e18031a5ca3 100644
--- a/drivers/tty/tty_ldsem.c
+++ b/drivers/tty/tty_ldsem.c
@@ -367,23 +367,6 @@ int __sched ldsem_down_write(struct ld_semaphore *sem, long timeout)
}
/*
- * trylock for writing -- returns 1 if successful, 0 if contention
- */
-int ldsem_down_write_trylock(struct ld_semaphore *sem)
-{
- long count = atomic_long_read(&sem->count);
-
- while ((count & LDSEM_ACTIVE_MASK) == 0) {
- if (atomic_long_try_cmpxchg(&sem->count, &count, count + LDSEM_WRITE_BIAS)) {
- rwsem_acquire(&sem->dep_map, 0, 1, _RET_IP_);
- lock_acquired(&sem->dep_map, _RET_IP_);
- return 1;
- }
- }
- return 0;
-}
-
-/*
* release a read lock
*/
void ldsem_up_read(struct ld_semaphore *sem)
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index 14cca33d2269..4af1fbf73f51 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -200,26 +200,6 @@ struct device *tty_port_register_device_attr_serdev(struct tty_port *port,
EXPORT_SYMBOL_GPL(tty_port_register_device_attr_serdev);
/**
- * tty_port_register_device_serdev - register tty or serdev device
- * @port: tty_port of the device
- * @driver: tty_driver for this device
- * @index: index of the tty
- * @host: serial port hardware controller device
- * @parent: parent if exists, otherwise NULL
- *
- * Register a serdev or tty device depending on if the parent device has any
- * defined serdev clients or not.
- */
-struct device *tty_port_register_device_serdev(struct tty_port *port,
- struct tty_driver *driver, unsigned index,
- struct device *host, struct device *parent)
-{
- return tty_port_register_device_attr_serdev(port, driver, index,
- host, parent, NULL, NULL);
-}
-EXPORT_SYMBOL_GPL(tty_port_register_device_serdev);
-
-/**
* tty_port_unregister_device - deregister a tty or serdev device
* @port: tty_port of the device
* @driver: tty_driver for this device
diff --git a/drivers/tty/vcc.c b/drivers/tty/vcc.c
index 5b625f20233b..2960031ace72 100644
--- a/drivers/tty/vcc.c
+++ b/drivers/tty/vcc.c
@@ -356,7 +356,7 @@ done:
static void vcc_rx_timer(struct timer_list *t)
{
- struct vcc_port *port = from_timer(port, t, rx_timer);
+ struct vcc_port *port = timer_container_of(port, t, rx_timer);
struct vio_driver_state *vio;
unsigned long flags;
int rv;
@@ -382,7 +382,7 @@ done:
static void vcc_tx_timer(struct timer_list *t)
{
- struct vcc_port *port = from_timer(port, t, tx_timer);
+ struct vcc_port *port = timer_container_of(port, t, tx_timer);
struct vio_vcc *pkt;
unsigned long flags;
size_t tosend = 0;
@@ -683,8 +683,8 @@ static void vcc_remove(struct vio_dev *vdev)
{
struct vcc_port *port = dev_get_drvdata(&vdev->dev);
- del_timer_sync(&port->rx_timer);
- del_timer_sync(&port->tx_timer);
+ timer_delete_sync(&port->rx_timer);
+ timer_delete_sync(&port->tx_timer);
/* If there's a process with the device open, do a synchronous
* hangup of the TTY. This *may* cause the process to call close
@@ -700,7 +700,7 @@ static void vcc_remove(struct vio_dev *vdev)
tty_unregister_device(vcc_tty_driver, port->index);
- del_timer_sync(&port->vio.timer);
+ timer_delete_sync(&port->vio.timer);
vio_ldc_free(&port->vio);
sysfs_remove_group(&vdev->dev.kobj, &vcc_attribute_group);
dev_set_drvdata(&vdev->dev, NULL);
diff --git a/drivers/tty/vt/.gitignore b/drivers/tty/vt/.gitignore
index 0221709b177d..a74859bab862 100644
--- a/drivers/tty/vt/.gitignore
+++ b/drivers/tty/vt/.gitignore
@@ -2,3 +2,6 @@
/conmakehash
/consolemap_deftbl.c
/defkeymap.c
+/ucs_fallback_table.h
+/ucs_recompose_table.h
+/ucs_width_table.h
diff --git a/drivers/tty/vt/Makefile b/drivers/tty/vt/Makefile
index 2c8ce8b592ed..ae746dcdeec8 100644
--- a/drivers/tty/vt/Makefile
+++ b/drivers/tty/vt/Makefile
@@ -7,10 +7,12 @@ FONTMAPFILE = cp437.uni
obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o \
selection.o keyboard.o \
vt.o defkeymap.o
-obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o
+obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o \
+ ucs.o
# Files generated that shall be removed upon make clean
-clean-files := consolemap_deftbl.c defkeymap.c
+clean-files := consolemap_deftbl.c defkeymap.c \
+ ucs_width_table.h ucs_recompose_table.h ucs_fallback_table.h
hostprogs += conmakehash
@@ -33,3 +35,31 @@ $(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map
loadkeys --mktable --unicode $< > $@
endif
+
+$(obj)/ucs.o: $(src)/ucs.c $(obj)/ucs_width_table.h \
+ $(obj)/ucs_recompose_table.h $(obj)/ucs_fallback_table.h
+
+# You may uncomment one of those to have the UCS tables be regenerated
+# during the build process. By default the _shipped versions are used.
+#
+#GENERATE_UCS_TABLES := 1
+#GENERATE_UCS_TABLES := 2 # invokes gen_ucs_recompose_table.py with --full
+
+ifdef GENERATE_UCS_TABLES
+
+$(obj)/ucs_width_table.h: $(src)/gen_ucs_width_table.py
+ $(PYTHON3) $< -o $@
+
+ifeq ($(GENERATE_UCS_TABLES),2)
+gen_recomp_arg := --full
+else
+gen_recomp_arg :=
+endif
+
+$(obj)/ucs_recompose_table.h: $(src)/gen_ucs_recompose_table.py
+ $(PYTHON3) $< -o $@ $(gen_recomp_arg)
+
+$(obj)/ucs_fallback_table.h: $(src)/gen_ucs_fallback_table.py
+ $(PYTHON3) $< -o $@
+
+endif
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
index 82d70083fead..bb4bb272ebec 100644
--- a/drivers/tty/vt/consolemap.c
+++ b/drivers/tty/vt/consolemap.c
@@ -870,8 +870,6 @@ int conv_uni_to_pc(struct vc_data *conp, long ucs)
return -4; /* Not found */
else if (ucs < 0x20)
return -1; /* Not a printable character */
- else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f))
- return -2; /* Zero-width space */
/*
* UNI_DIRECT_BASE indicates the start of the region in the User Zone
* which always has a 1:1 mapping to the currently loaded font. The
diff --git a/drivers/tty/vt/gen_ucs_fallback_table.py b/drivers/tty/vt/gen_ucs_fallback_table.py
new file mode 100755
index 000000000000..6e09c1cb6d4b
--- /dev/null
+++ b/drivers/tty/vt/gen_ucs_fallback_table.py
@@ -0,0 +1,360 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+#
+# Leverage Python's unidecode module to generate ucs_fallback_table.h
+#
+# The generated table maps complex characters to their simpler fallback forms
+# for a terminal display when corresponding glyphs are unavailable.
+#
+# Usage:
+# python3 gen_ucs_fallback_table.py # Generate fallback tables
+# python3 gen_ucs_fallback_table.py -o FILE # Specify output file
+
+import unicodedata
+from unidecode import unidecode
+import sys
+import argparse
+from collections import defaultdict
+
+# Try to get unidecode version
+try:
+ from importlib.metadata import version
+ unidecode_version = version('unidecode')
+except:
+ unidecode_version = 'unknown'
+
+# This script's file name
+from pathlib import Path
+this_file = Path(__file__).name
+
+# Default output file name
+DEFAULT_OUT_FILE = "ucs_fallback_table.h"
+
+# Define the range marker value
+RANGE_MARKER = 0x00
+
+def generate_fallback_map():
+ """Generate a fallback map using unidecode for all relevant Unicode points."""
+ fallback_map = {}
+
+ # Process BMP characters (0x0000 - 0xFFFF) to keep table size manageable
+ for cp in range(0x0080, 0x10000): # Skip ASCII range (0x00-0x7F)
+ char = chr(cp)
+
+ # Skip unassigned/control characters
+ try:
+ if not unicodedata.name(char, ''):
+ continue
+ except ValueError:
+ continue
+
+ # Get the unidecode transliteration
+ ascii_version = unidecode(char)
+
+ # Only store if it results in a single character mapping
+ if len(ascii_version) == 1:
+ fallback_map[cp] = ord(ascii_version)
+
+ # Apply manual overrides for special cases
+ fallback_map.update(get_special_overrides())
+
+ return fallback_map
+
+def get_special_overrides():
+ """Get special case overrides that need different handling than unidecode
+ provides... or doesn't provide at all."""
+
+ overrides = {}
+
+ # Multi-character unidecode output
+ # These map to single chars instead of unidecode's multiple-char mappings
+ # In a terminal fallback context, we need a single character rather than multiple
+ overrides[0x00C6] = ord('E') # Æ LATIN CAPITAL LETTER AE -> E (unidecode: "AE")
+ overrides[0x00E6] = ord('e') # æ LATIN SMALL LETTER AE -> e (unidecode: "ae")
+ overrides[0x0152] = ord('E') # Œ LATIN CAPITAL LIGATURE OE -> E (unidecode: "OE")
+ overrides[0x0153] = ord('e') # œ LATIN SMALL LETTER LIGATURE OE -> e (unidecode: "oe")
+ overrides[0x00DF] = ord('s') # ß LATIN SMALL LETTER SHARP S -> s (unidecode: "ss")
+
+ # Comparison operators that unidecode renders as multiple characters
+ overrides[0x2264] = ord('<') # ≤ LESS-THAN OR EQUAL TO -> < (unidecode: "<=")
+ overrides[0x2265] = ord('>') # ≥ GREATER-THAN OR EQUAL TO -> > (unidecode: ">=")
+
+ # Unidecode returns an empty string for these
+ overrides[0x2260] = ord('#') # ≠ NOT EQUAL TO -> # (unidecode: empty string)
+
+ # Quadrant block characters that unidecode doesn't map
+ for cp in range(0x2596, 0x259F+1):
+ overrides[cp] = ord('#') # ▖ ▗ ▘ ▙ etc. - map to # (unidecode: empty string)
+
+ # Directional arrows
+ # These provide better semantic meaning than unidecode's mappings
+ overrides[0x2192] = ord('>') # → RIGHTWARDS ARROW -> > (unidecode: "-")
+ overrides[0x2190] = ord('<') # ← LEFTWARDS ARROW -> < (unidecode: "-")
+ overrides[0x2191] = ord('^') # ↑ UPWARDS ARROW -> ^ (unidecode: "|")
+ overrides[0x2193] = ord('v') # ↓ DOWNWARDS ARROW -> v (unidecode: "|")
+
+ # Double arrows with their directional semantic mappings
+ overrides[0x21D0] = ord('<') # ⇐ LEFTWARDS DOUBLE ARROW -> <
+ overrides[0x21D1] = ord('^') # ⇑ UPWARDS DOUBLE ARROW -> ^
+ overrides[0x21D2] = ord('>') # ⇒ RIGHTWARDS DOUBLE ARROW -> >
+ overrides[0x21D3] = ord('v') # ⇓ DOWNWARDS DOUBLE ARROW -> v
+
+ # Halfwidth arrows
+ # These need the same treatment as their normal-width counterparts
+ overrides[0xFFE9] = ord('<') # ← HALFWIDTH LEFTWARDS ARROW -> < (unidecode: "-")
+ overrides[0xFFEA] = ord('^') # ↑ HALFWIDTH UPWARDS ARROW -> ^ (unidecode: "|")
+ overrides[0xFFEB] = ord('>') # → HALFWIDTH RIGHTWARDS ARROW -> > (unidecode: "-")
+ overrides[0xFFEC] = ord('v') # ↓ HALFWIDTH DOWNWARDS ARROW -> v (unidecode: "|")
+
+ # Currency symbols - each mapped to a representative letter
+ overrides[0x00A2] = ord('c') # ¢ CENT SIGN -> c
+ overrides[0x00A3] = ord('L') # £ POUND SIGN -> L
+ overrides[0x00A5] = ord('Y') # ¥ YEN SIGN -> Y
+ overrides[0x20AC] = ord('E') # € EURO SIGN -> E
+
+ # Symbols mapped to letters
+ overrides[0x00A7] = ord('S') # § SECTION SIGN -> S
+ overrides[0x00A9] = ord('C') # © COPYRIGHT SIGN -> C
+ overrides[0x00AE] = ord('R') # ® REGISTERED SIGN -> R
+ overrides[0x2122] = ord('T') # ™ TRADE MARK SIGN -> T
+
+ # Degree-related symbols
+ overrides[0x00B0] = ord('o') # ° DEGREE SIGN -> o
+ overrides[0x2103] = ord('C') # ℃ DEGREE CELSIUS -> C
+ overrides[0x2109] = ord('F') # ℉ DEGREE FAHRENHEIT -> F
+
+ # Angle quotation marks
+ overrides[0x00AB] = ord('<') # « LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -> <
+ overrides[0x00BB] = ord('>') # » RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -> >
+
+ # Operators with circular shape
+ overrides[0x2218] = ord('o') # ∘ RING OPERATOR -> o
+ overrides[0x2219] = ord('.') # ∙ BULLET OPERATOR -> .
+
+ # Negated mathematical symbols (preserving the negation semantics)
+ # Negated symbols mapped to exclamation mark (semantically "not")
+ for cp in (0x2204, 0x2209, 0x220C, 0x2224, 0x2226, 0x226E, 0x226F, 0x2280, 0x2281, 0x2284, 0x2285):
+ overrides[cp] = ord('!') # Negated math symbols -> ! (not)
+
+ # Negated symbols mapped to hash sign (semantically "not equal")
+ for cp in (0x2241, 0x2244, 0x2249, 0x2262, 0x2268, 0x2269, 0x226D, 0x228A, 0x228B):
+ overrides[cp] = ord('#') # Negated equality symbols -> # (not equal)
+
+ # Negated arrows - all mapped to exclamation mark
+ for cp in (0x219A, 0x219B, 0x21AE, 0x21CD, 0x21CE, 0x21CF):
+ overrides[cp] = ord('!') # Negated arrows -> ! (not)
+
+ # Dashes and hyphens
+ for cp in (0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2043, 0x2052):
+ overrides[cp] = ord('-') # Dashes and hyphens -> -
+
+ # Question mark punctuation
+ for cp in (0x203D, 0x2047, 0x2048):
+ overrides[cp] = ord('?') # Question marks -> ?
+
+ # Exclamation mark punctuation
+ for cp in (0x203C, 0x2049):
+ overrides[cp] = ord('!') # Exclamation marks -> !
+
+ # Asterisk-like symbols
+ for cp in (0x2042, 0x2051, 0x2055):
+ overrides[cp] = ord('*')
+
+ # Other specific punctuation with unique mappings
+ overrides[0x201E] = ord('"') # „ DOUBLE LOW-9 QUOTATION MARK
+ overrides[0x2023] = ord('>') # ‣ TRIANGULAR BULLET
+ overrides[0x2026] = ord('.') # … HORIZONTAL ELLIPSIS
+ overrides[0x2033] = ord('"') # ″ DOUBLE PRIME
+ overrides[0x204B] = ord('P') # ⁋ REVERSED PILCROW SIGN
+ overrides[0x204C] = ord('<') # ⁌ BLACK LEFTWARDS BULLET
+ overrides[0x204D] = ord('>') # ⁍ BLACK RIGHTWARDS BULLET
+ overrides[0x204F] = ord(';') # ⁏ REVERSED SEMICOLON
+ overrides[0x205B] = ord(':') # ⁛ FOUR DOT MARK
+
+ # Check marks
+ overrides[0x2713] = ord('v') # ✓ CHECK MARK
+ overrides[0x2714] = ord('V') # ✔ HEAVY CHECK MARK
+
+ # X marks - lowercase for regular, uppercase for heavy
+ for cp in (0x2715, 0x2717):
+ overrides[cp] = ord('x') # Regular X marks -> x
+ for cp in (0x2716, 0x2718):
+ overrides[cp] = ord('X') # Heavy X marks -> X
+
+ # Stars and asterisk-like symbols mapped to '*'
+ for cp in (0x2605, 0x2606, 0x262A, 0x269D, 0x2698):
+ overrides[cp] = ord('*') # All star and asterisk symbols -> *
+ for cp in range(0x2721, 0x2746+1):
+ overrides[cp] = ord('*') # All star and asterisk symbols -> *
+ for cp in range(0x2749, 0x274B+1):
+ overrides[cp] = ord('*') # Last set of asterisk symbols -> *
+ for cp in (0x229B, 0x22C6, 0x235F, 0x2363):
+ overrides[cp] = ord('*') # Star operators -> *
+
+ # Special exclusions with fallback value of 0
+ # These will be filtered out in organize_by_pages()
+
+ # Exclude U+2028 (LINE SEPARATOR)
+ overrides[0x2028] = 0 # LINE SEPARATOR (unidecode: '\n')
+
+ # Full-width to ASCII mapping (covering all printable ASCII 33-126)
+ # 0xFF01 (!) to 0xFF5E (~) -> ASCII 33 (!) to 126 (~)
+ # Those are excluded here to reduce the table size.
+ # It is more efficient to process them programmatically in
+ # ucs.c:ucs_get_fallback().
+ for cp in range(0xFF01, 0xFF5E + 1):
+ overrides[cp] = 0 # Double-width ASCII characters
+
+ return overrides
+
+def organize_by_pages(fallback_map):
+ """Organize the fallback mappings by their high byte (page)."""
+ # Group by high byte (page)
+ page_groups = defaultdict(list)
+ for code, fallback in fallback_map.items():
+ # Skip characters with fallback value of 0 (excluded characters)
+ if fallback == 0:
+ continue
+
+ page = code >> 8 # Get the high byte (page)
+ offset = code & 0xFF # Get the low byte (offset within page)
+ page_groups[page].append((offset, fallback))
+
+ # Sort each page's entries by offset
+ for page in page_groups:
+ page_groups[page].sort()
+
+ return page_groups
+
+def compress_ranges(page_groups):
+ """Compress consecutive entries with the same fallback character into ranges.
+ A range is only compressed if it contains 3 or more consecutive entries."""
+
+ compressed_pages = {}
+
+ for page, entries in page_groups.items():
+ compressed_entries = []
+ i = 0
+ while i < len(entries):
+ start_offset, fallback = entries[i]
+
+ # Look ahead to find consecutive entries with the same fallback
+ j = i + 1
+ while (j < len(entries) and
+ entries[j][0] == entries[j-1][0] + 1 and # consecutive offsets
+ entries[j][1] == fallback): # same fallback
+ j += 1
+
+ # Calculate the range end
+ end_offset = entries[j-1][0]
+
+ # If we found a range with 3 or more entries (worth compressing)
+ if j - i >= 3:
+ # Add a range entry
+ compressed_entries.append((start_offset, RANGE_MARKER))
+ compressed_entries.append((end_offset, fallback))
+ else:
+ # Add the individual entries as is
+ for k in range(i, j):
+ compressed_entries.append(entries[k])
+
+ i = j
+
+ compressed_pages[page] = compressed_entries
+
+ return compressed_pages
+
+def cp_name(cp):
+ """Get the Unicode character name for a code point."""
+ try:
+ return unicodedata.name(chr(cp))
+ except:
+ return f"U+{cp:04X}"
+
+def generate_fallback_tables(out_file=DEFAULT_OUT_FILE):
+ """Generate the fallback character tables."""
+ # Generate fallback map using unidecode
+ fallback_map = generate_fallback_map()
+ print(f"Generated {len(fallback_map)} total fallback mappings")
+
+ # Organize by pages
+ page_groups = organize_by_pages(fallback_map)
+ print(f"Organized into {len(page_groups)} pages")
+
+ # Compress ranges
+ compressed_pages = compress_ranges(page_groups)
+ total_compressed_entries = sum(len(entries) for entries in compressed_pages.values())
+ print(f"Total compressed entries: {total_compressed_entries}")
+
+ # Create output file
+ with open(out_file, 'w') as f:
+ f.write(f"""\
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * {out_file} - Unicode character fallback table
+ *
+ * Auto-generated by {this_file}
+ *
+ * Unicode Version: {unicodedata.unidata_version}
+ * Unidecode Version: {unidecode_version}
+ *
+ * This file contains optimized tables that map complex Unicode characters
+ * to simpler fallback characters for terminal display when corresponding
+ * glyphs are unavailable.
+ */
+
+static const struct ucs_page_desc ucs_fallback_pages[] = {{
+""")
+
+ # Convert compressed_pages to a sorted list of (page, entries) tuples
+ sorted_pages = sorted(compressed_pages.items())
+
+ # Track the start index for each page
+ start_index = 0
+
+ # Write page descriptors
+ for page, entries in sorted_pages:
+ count = len(entries)
+ f.write(f"\t{{ 0x{page:02X}, {count}, {start_index} }},\n")
+ start_index += count
+
+ # Write entries array
+ f.write("""\
+};
+
+/* Page entries array (referenced by page descriptors) */
+static const struct ucs_page_entry ucs_fallback_entries[] = {
+""")
+
+ # Write all entries
+ for page, entries in sorted_pages:
+ page_hex = f"0x{page:02X}"
+ f.write(f"\t/* Entries for page {page_hex} */\n")
+
+ for i, (offset, fallback) in enumerate(entries):
+ # Convert to hex for better readability
+ offset_hex = f"0x{offset:02X}"
+ fallback_hex = f"0x{fallback:02X}"
+
+ # Handle comments
+ codepoint = (page << 8) | offset
+
+ if fallback == RANGE_MARKER:
+ comment = f"{cp_name(codepoint)} -> ..."
+ else:
+ comment = f"{cp_name(codepoint)} -> '{chr(fallback)}'"
+ f.write(f"\t{{ 0x{offset:02X}, 0x{fallback:02X} }}, /* {comment} */\n")
+
+ f.write(f"""\
+}};
+
+#define UCS_PAGE_ENTRY_RANGE_MARKER {RANGE_MARKER}
+""")
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="Generate Unicode fallback character tables")
+ parser.add_argument("-o", "--output", dest="output_file", default=DEFAULT_OUT_FILE,
+ help=f"Output file name (default: {DEFAULT_OUT_FILE})")
+ args = parser.parse_args()
+
+ generate_fallback_tables(out_file=args.output_file)
diff --git a/drivers/tty/vt/gen_ucs_recompose_table.py b/drivers/tty/vt/gen_ucs_recompose_table.py
new file mode 100755
index 000000000000..4434a436ac9e
--- /dev/null
+++ b/drivers/tty/vt/gen_ucs_recompose_table.py
@@ -0,0 +1,257 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+#
+# Leverage Python's unicodedata module to generate ucs_recompose_table.h
+#
+# The generated table maps base character + combining mark pairs to their
+# precomposed equivalents.
+#
+# Usage:
+# python3 gen_ucs_recompose_table.py # Generate with common recomposition pairs
+# python3 gen_ucs_recompose_table.py --full # Generate with all recomposition pairs
+
+import unicodedata
+import sys
+import argparse
+import textwrap
+
+# This script's file name
+from pathlib import Path
+this_file = Path(__file__).name
+
+# Default output file name
+DEFAULT_OUT_FILE = "ucs_recompose_table.h"
+
+common_recompose_description = "most commonly used Latin, Greek, and Cyrillic recomposition pairs only"
+COMMON_RECOMPOSITION_PAIRS = [
+ # Latin letters with accents - uppercase
+ (0x0041, 0x0300, 0x00C0), # A + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER A WITH GRAVE
+ (0x0041, 0x0301, 0x00C1), # A + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER A WITH ACUTE
+ (0x0041, 0x0302, 0x00C2), # A + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+ (0x0041, 0x0303, 0x00C3), # A + COMBINING TILDE = LATIN CAPITAL LETTER A WITH TILDE
+ (0x0041, 0x0308, 0x00C4), # A + COMBINING DIAERESIS = LATIN CAPITAL LETTER A WITH DIAERESIS
+ (0x0041, 0x030A, 0x00C5), # A + COMBINING RING ABOVE = LATIN CAPITAL LETTER A WITH RING ABOVE
+ (0x0043, 0x0327, 0x00C7), # C + COMBINING CEDILLA = LATIN CAPITAL LETTER C WITH CEDILLA
+ (0x0045, 0x0300, 0x00C8), # E + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER E WITH GRAVE
+ (0x0045, 0x0301, 0x00C9), # E + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER E WITH ACUTE
+ (0x0045, 0x0302, 0x00CA), # E + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+ (0x0045, 0x0308, 0x00CB), # E + COMBINING DIAERESIS = LATIN CAPITAL LETTER E WITH DIAERESIS
+ (0x0049, 0x0300, 0x00CC), # I + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER I WITH GRAVE
+ (0x0049, 0x0301, 0x00CD), # I + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER I WITH ACUTE
+ (0x0049, 0x0302, 0x00CE), # I + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+ (0x0049, 0x0308, 0x00CF), # I + COMBINING DIAERESIS = LATIN CAPITAL LETTER I WITH DIAERESIS
+ (0x004E, 0x0303, 0x00D1), # N + COMBINING TILDE = LATIN CAPITAL LETTER N WITH TILDE
+ (0x004F, 0x0300, 0x00D2), # O + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER O WITH GRAVE
+ (0x004F, 0x0301, 0x00D3), # O + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER O WITH ACUTE
+ (0x004F, 0x0302, 0x00D4), # O + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+ (0x004F, 0x0303, 0x00D5), # O + COMBINING TILDE = LATIN CAPITAL LETTER O WITH TILDE
+ (0x004F, 0x0308, 0x00D6), # O + COMBINING DIAERESIS = LATIN CAPITAL LETTER O WITH DIAERESIS
+ (0x0055, 0x0300, 0x00D9), # U + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER U WITH GRAVE
+ (0x0055, 0x0301, 0x00DA), # U + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER U WITH ACUTE
+ (0x0055, 0x0302, 0x00DB), # U + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+ (0x0055, 0x0308, 0x00DC), # U + COMBINING DIAERESIS = LATIN CAPITAL LETTER U WITH DIAERESIS
+ (0x0059, 0x0301, 0x00DD), # Y + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER Y WITH ACUTE
+
+ # Latin letters with accents - lowercase
+ (0x0061, 0x0300, 0x00E0), # a + COMBINING GRAVE ACCENT = LATIN SMALL LETTER A WITH GRAVE
+ (0x0061, 0x0301, 0x00E1), # a + COMBINING ACUTE ACCENT = LATIN SMALL LETTER A WITH ACUTE
+ (0x0061, 0x0302, 0x00E2), # a + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER A WITH CIRCUMFLEX
+ (0x0061, 0x0303, 0x00E3), # a + COMBINING TILDE = LATIN SMALL LETTER A WITH TILDE
+ (0x0061, 0x0308, 0x00E4), # a + COMBINING DIAERESIS = LATIN SMALL LETTER A WITH DIAERESIS
+ (0x0061, 0x030A, 0x00E5), # a + COMBINING RING ABOVE = LATIN SMALL LETTER A WITH RING ABOVE
+ (0x0063, 0x0327, 0x00E7), # c + COMBINING CEDILLA = LATIN SMALL LETTER C WITH CEDILLA
+ (0x0065, 0x0300, 0x00E8), # e + COMBINING GRAVE ACCENT = LATIN SMALL LETTER E WITH GRAVE
+ (0x0065, 0x0301, 0x00E9), # e + COMBINING ACUTE ACCENT = LATIN SMALL LETTER E WITH ACUTE
+ (0x0065, 0x0302, 0x00EA), # e + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER E WITH CIRCUMFLEX
+ (0x0065, 0x0308, 0x00EB), # e + COMBINING DIAERESIS = LATIN SMALL LETTER E WITH DIAERESIS
+ (0x0069, 0x0300, 0x00EC), # i + COMBINING GRAVE ACCENT = LATIN SMALL LETTER I WITH GRAVE
+ (0x0069, 0x0301, 0x00ED), # i + COMBINING ACUTE ACCENT = LATIN SMALL LETTER I WITH ACUTE
+ (0x0069, 0x0302, 0x00EE), # i + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER I WITH CIRCUMFLEX
+ (0x0069, 0x0308, 0x00EF), # i + COMBINING DIAERESIS = LATIN SMALL LETTER I WITH DIAERESIS
+ (0x006E, 0x0303, 0x00F1), # n + COMBINING TILDE = LATIN SMALL LETTER N WITH TILDE
+ (0x006F, 0x0300, 0x00F2), # o + COMBINING GRAVE ACCENT = LATIN SMALL LETTER O WITH GRAVE
+ (0x006F, 0x0301, 0x00F3), # o + COMBINING ACUTE ACCENT = LATIN SMALL LETTER O WITH ACUTE
+ (0x006F, 0x0302, 0x00F4), # o + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER O WITH CIRCUMFLEX
+ (0x006F, 0x0303, 0x00F5), # o + COMBINING TILDE = LATIN SMALL LETTER O WITH TILDE
+ (0x006F, 0x0308, 0x00F6), # o + COMBINING DIAERESIS = LATIN SMALL LETTER O WITH DIAERESIS
+ (0x0075, 0x0300, 0x00F9), # u + COMBINING GRAVE ACCENT = LATIN SMALL LETTER U WITH GRAVE
+ (0x0075, 0x0301, 0x00FA), # u + COMBINING ACUTE ACCENT = LATIN SMALL LETTER U WITH ACUTE
+ (0x0075, 0x0302, 0x00FB), # u + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER U WITH CIRCUMFLEX
+ (0x0075, 0x0308, 0x00FC), # u + COMBINING DIAERESIS = LATIN SMALL LETTER U WITH DIAERESIS
+ (0x0079, 0x0301, 0x00FD), # y + COMBINING ACUTE ACCENT = LATIN SMALL LETTER Y WITH ACUTE
+ (0x0079, 0x0308, 0x00FF), # y + COMBINING DIAERESIS = LATIN SMALL LETTER Y WITH DIAERESIS
+
+ # Common Greek characters
+ (0x0391, 0x0301, 0x0386), # Α + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER ALPHA WITH TONOS
+ (0x0395, 0x0301, 0x0388), # Ε + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER EPSILON WITH TONOS
+ (0x0397, 0x0301, 0x0389), # Η + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER ETA WITH TONOS
+ (0x0399, 0x0301, 0x038A), # Ι + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER IOTA WITH TONOS
+ (0x039F, 0x0301, 0x038C), # Ο + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER OMICRON WITH TONOS
+ (0x03A5, 0x0301, 0x038E), # Υ + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER UPSILON WITH TONOS
+ (0x03A9, 0x0301, 0x038F), # Ω + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER OMEGA WITH TONOS
+ (0x03B1, 0x0301, 0x03AC), # α + COMBINING ACUTE ACCENT = GREEK SMALL LETTER ALPHA WITH TONOS
+ (0x03B5, 0x0301, 0x03AD), # ε + COMBINING ACUTE ACCENT = GREEK SMALL LETTER EPSILON WITH TONOS
+ (0x03B7, 0x0301, 0x03AE), # η + COMBINING ACUTE ACCENT = GREEK SMALL LETTER ETA WITH TONOS
+ (0x03B9, 0x0301, 0x03AF), # ι + COMBINING ACUTE ACCENT = GREEK SMALL LETTER IOTA WITH TONOS
+ (0x03BF, 0x0301, 0x03CC), # ο + COMBINING ACUTE ACCENT = GREEK SMALL LETTER OMICRON WITH TONOS
+ (0x03C5, 0x0301, 0x03CD), # υ + COMBINING ACUTE ACCENT = GREEK SMALL LETTER UPSILON WITH TONOS
+ (0x03C9, 0x0301, 0x03CE), # ω + COMBINING ACUTE ACCENT = GREEK SMALL LETTER OMEGA WITH TONOS
+
+ # Common Cyrillic characters
+ (0x0418, 0x0306, 0x0419), # И + COMBINING BREVE = CYRILLIC CAPITAL LETTER SHORT I
+ (0x0438, 0x0306, 0x0439), # и + COMBINING BREVE = CYRILLIC SMALL LETTER SHORT I
+ (0x0423, 0x0306, 0x040E), # У + COMBINING BREVE = CYRILLIC CAPITAL LETTER SHORT U
+ (0x0443, 0x0306, 0x045E), # у + COMBINING BREVE = CYRILLIC SMALL LETTER SHORT U
+]
+
+full_recompose_description = "all possible recomposition pairs from the Unicode BMP"
+def collect_all_recomposition_pairs():
+ """Collect all possible recomposition pairs from the Unicode data."""
+ # Map to store recomposition pairs: (base, combining) -> recomposed
+ recompose_map = {}
+
+ # Process all assigned Unicode code points in BMP (Basic Multilingual Plane)
+ # We limit to BMP (0x0000-0xFFFF) to keep our table smaller with uint16_t
+ for cp in range(0, 0x10000):
+ try:
+ char = chr(cp)
+
+ # Skip unassigned or control characters
+ if not unicodedata.name(char, ''):
+ continue
+
+ # Find decomposition
+ decomp = unicodedata.decomposition(char)
+ if not decomp or '<' in decomp: # Skip compatibility decompositions
+ continue
+
+ # Parse the decomposition
+ parts = decomp.split()
+ if len(parts) == 2: # Simple base + combining mark
+ base = int(parts[0], 16)
+ combining = int(parts[1], 16)
+
+ # Only store if both are in BMP
+ if base < 0x10000 and combining < 0x10000:
+ recompose_map[(base, combining)] = cp
+
+ except (ValueError, TypeError):
+ continue
+
+ # Convert to a list of tuples and sort for binary search
+ recompose_list = [(base, combining, recomposed)
+ for (base, combining), recomposed in recompose_map.items()]
+ recompose_list.sort()
+
+ return recompose_list
+
+def validate_common_pairs(full_list):
+ """Validate that all common pairs are in the full list.
+
+ Raises:
+ ValueError: If any common pair is missing or has a different recomposition
+ value than what's in the full table.
+ """
+ full_pairs = {(base, combining): recomposed for base, combining, recomposed in full_list}
+ for base, combining, recomposed in COMMON_RECOMPOSITION_PAIRS:
+ full_recomposed = full_pairs.get((base, combining))
+ if full_recomposed is None:
+ error_msg = f"Error: Common pair (0x{base:04X}, 0x{combining:04X}) not found in full data"
+ print(error_msg)
+ raise ValueError(error_msg)
+ elif full_recomposed != recomposed:
+ error_msg = (f"Error: Common pair (0x{base:04X}, 0x{combining:04X}) has different recomposition: "
+ f"0x{recomposed:04X} vs 0x{full_recomposed:04X}")
+ print(error_msg)
+ raise ValueError(error_msg)
+
+def generate_recomposition_table(use_full_list=False, out_file=DEFAULT_OUT_FILE):
+ """Generate the recomposition C table."""
+
+ # Collect all recomposition pairs for validation
+ full_recompose_list = collect_all_recomposition_pairs()
+
+ # Decide which list to use
+ if use_full_list:
+ print("Using full recomposition list...")
+ recompose_list = full_recompose_list
+ table_description = full_recompose_description
+ alt_list = COMMON_RECOMPOSITION_PAIRS
+ alt_description = common_recompose_description
+ else:
+ print("Using common recomposition list...")
+ # Validate that all common pairs are in the full list
+ validate_common_pairs(full_recompose_list)
+ recompose_list = sorted(COMMON_RECOMPOSITION_PAIRS)
+ table_description = common_recompose_description
+ alt_list = full_recompose_list
+ alt_description = full_recompose_description
+ generation_mode = " --full" if use_full_list else ""
+ alternative_mode = " --full" if not use_full_list else ""
+ table_description_detail = f"{table_description} ({len(recompose_list)} entries)"
+ alt_description_detail = f"{alt_description} ({len(alt_list)} entries)"
+
+ # Calculate min/max values for boundary checks
+ min_base = min(base for base, _, _ in recompose_list)
+ max_base = max(base for base, _, _ in recompose_list)
+ min_combining = min(combining for _, combining, _ in recompose_list)
+ max_combining = max(combining for _, combining, _ in recompose_list)
+
+ # Generate implementation file
+ with open(out_file, 'w') as f:
+ f.write(f"""\
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * {out_file} - Unicode character recomposition
+ *
+ * Auto-generated by {this_file}{generation_mode}
+ *
+ * Unicode Version: {unicodedata.unidata_version}
+ *
+{textwrap.fill(
+ f"This file contains a table with {table_description_detail}. " +
+ f"To generate a table with {alt_description_detail} instead, run:",
+ width=75, initial_indent=" * ", subsequent_indent=" * ")}
+ *
+ * python3 {this_file}{alternative_mode}
+ */
+
+/*
+ * Table of {table_description}
+ * Sorted by base character and then combining mark for binary search
+ */
+static const struct ucs_recomposition ucs_recomposition_table[] = {{
+""")
+
+ for base, combining, recomposed in recompose_list:
+ try:
+ base_name = unicodedata.name(chr(base))
+ combining_name = unicodedata.name(chr(combining))
+ recomposed_name = unicodedata.name(chr(recomposed))
+ comment = f"/* {base_name} + {combining_name} = {recomposed_name} */"
+ except ValueError:
+ comment = f"/* U+{base:04X} + U+{combining:04X} = U+{recomposed:04X} */"
+ f.write(f"\t{{ 0x{base:04X}, 0x{combining:04X}, 0x{recomposed:04X} }}, {comment}\n")
+
+ f.write(f"""\
+}};
+
+/*
+ * Boundary values for quick rejection
+ * These are calculated by analyzing the table during generation
+ */
+#define UCS_RECOMPOSE_MIN_BASE 0x{min_base:04X}
+#define UCS_RECOMPOSE_MAX_BASE 0x{max_base:04X}
+#define UCS_RECOMPOSE_MIN_MARK 0x{min_combining:04X}
+#define UCS_RECOMPOSE_MAX_MARK 0x{max_combining:04X}
+""")
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description="Generate Unicode recomposition table")
+ parser.add_argument("--full", action="store_true",
+ help="Generate a full recomposition table (default: common pairs only)")
+ parser.add_argument("-o", "--output", dest="output_file", default=DEFAULT_OUT_FILE,
+ help=f"Output file name (default: {DEFAULT_OUT_FILE})")
+ args = parser.parse_args()
+
+ generate_recomposition_table(use_full_list=args.full, out_file=args.output_file)
diff --git a/drivers/tty/vt/gen_ucs_width_table.py b/drivers/tty/vt/gen_ucs_width_table.py
new file mode 100755
index 000000000000..76e80ebeff13
--- /dev/null
+++ b/drivers/tty/vt/gen_ucs_width_table.py
@@ -0,0 +1,307 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+#
+# Leverage Python's unicodedata module to generate ucs_width_table.h
+
+import unicodedata
+import sys
+import argparse
+
+# This script's file name
+from pathlib import Path
+this_file = Path(__file__).name
+
+# Default output file name
+DEFAULT_OUT_FILE = "ucs_width_table.h"
+
+# --- Global Constants for Width Assignments ---
+
+# Known zero-width characters
+KNOWN_ZERO_WIDTH = (
+ 0x200B, # ZERO WIDTH SPACE
+ 0x200C, # ZERO WIDTH NON-JOINER
+ 0x200D, # ZERO WIDTH JOINER
+ 0x2060, # WORD JOINER
+ 0xFEFF # ZERO WIDTH NO-BREAK SPACE (BOM)
+)
+
+# Zero-width emoji modifiers and components
+# NOTE: Some of these characters would normally be single-width according to
+# East Asian Width properties, but we deliberately override them to be
+# zero-width because they function as modifiers in emoji sequences.
+EMOJI_ZERO_WIDTH = [
+ # Skin tone modifiers
+ (0x1F3FB, 0x1F3FF), # Emoji modifiers (skin tones)
+
+ # Variation selectors (note: VS16 is treated specially in vt.c)
+ (0xFE00, 0xFE0F), # Variation Selectors 1-16
+
+ # Gender and hair style modifiers
+ # These would be single-width by Unicode properties, but are zero-width
+ # when part of emoji
+ (0x2640, 0x2640), # Female sign
+ (0x2642, 0x2642), # Male sign
+ (0x26A7, 0x26A7), # Transgender symbol
+ (0x1F9B0, 0x1F9B3), # Hair components (red, curly, white, bald)
+
+ # Tag characters
+ (0xE0020, 0xE007E), # Tags
+]
+
+# Regional indicators (flag components)
+REGIONAL_INDICATORS = (0x1F1E6, 0x1F1FF) # Regional indicator symbols A-Z
+
+# Double-width emoji ranges
+#
+# Many emoji characters are classified as single-width according to Unicode
+# Standard Annex #11 East Asian Width property (N or Neutral), but we
+# deliberately override them to be double-width. References:
+# 1. Unicode Technical Standard #51: Unicode Emoji
+# (https://www.unicode.org/reports/tr51/)
+# 2. Principle of "emoji presentation" in WHATWG CSS Text specification
+# (https://drafts.csswg.org/css-text-3/#character-properties)
+# 3. Terminal emulator implementations (iTerm2, Windows Terminal, etc.) which
+# universally render emoji as double-width characters regardless of their
+# Unicode EAW property
+# 4. W3C Work Item: Requirements for Japanese Text Layout - Section 3.8.1
+# Emoji width (https://www.w3.org/TR/jlreq/)
+EMOJI_RANGES = [
+ (0x1F000, 0x1F02F), # Mahjong Tiles (EAW: N, but displayed as double-width)
+ (0x1F0A0, 0x1F0FF), # Playing Cards (EAW: N, but displayed as double-width)
+ (0x1F300, 0x1F5FF), # Miscellaneous Symbols and Pictographs
+ (0x1F600, 0x1F64F), # Emoticons
+ (0x1F680, 0x1F6FF), # Transport and Map Symbols
+ (0x1F700, 0x1F77F), # Alchemical Symbols
+ (0x1F780, 0x1F7FF), # Geometric Shapes Extended
+ (0x1F800, 0x1F8FF), # Supplemental Arrows-C
+ (0x1F900, 0x1F9FF), # Supplemental Symbols and Pictographs
+ (0x1FA00, 0x1FA6F), # Chess Symbols
+ (0x1FA70, 0x1FAFF), # Symbols and Pictographs Extended-A
+]
+
+def create_width_tables():
+ """
+ Creates Unicode character width tables and returns the data structures.
+
+ Returns:
+ tuple: (zero_width_ranges, double_width_ranges)
+ """
+
+ # Width data mapping
+ width_map = {} # Maps code points to width (0, 1, 2)
+
+ # Mark emoji modifiers as zero-width
+ for start, end in EMOJI_ZERO_WIDTH:
+ for cp in range(start, end + 1):
+ width_map[cp] = 0
+
+ # Mark all regional indicators as single-width as they are usually paired
+ # providing a combined width of 2 when displayed together.
+ start, end = REGIONAL_INDICATORS
+ for cp in range(start, end + 1):
+ width_map[cp] = 1
+
+ # Process all assigned Unicode code points (Basic Multilingual Plane +
+ # Supplementary Planes) Range 0x0 to 0x10FFFF (the full Unicode range)
+ for block_start in range(0, 0x110000, 0x1000):
+ block_end = block_start + 0x1000
+ for cp in range(block_start, block_end):
+ try:
+ char = chr(cp)
+
+ # Skip if already processed
+ if cp in width_map:
+ continue
+
+ # Check for combining marks and a format characters
+ category = unicodedata.category(char)
+
+ # Combining marks
+ if category.startswith('M'):
+ width_map[cp] = 0
+ continue
+
+ # Format characters
+ # Since we have no support for bidirectional text, all format
+ # characters (category Cf) can be treated with width 0 (zero)
+ # for simplicity, as they don't need to occupy visual space
+ # in a non-bidirectional text environment.
+ if category == 'Cf':
+ width_map[cp] = 0
+ continue
+
+ # Known zero-width characters
+ if cp in KNOWN_ZERO_WIDTH:
+ width_map[cp] = 0
+ continue
+
+ # Use East Asian Width property
+ eaw = unicodedata.east_asian_width(char)
+ if eaw in ('F', 'W'): # Fullwidth or Wide
+ width_map[cp] = 2
+ elif eaw in ('Na', 'H', 'N', 'A'): # Narrow, Halfwidth, Neutral, Ambiguous
+ width_map[cp] = 1
+ else:
+ # Default to single-width for unknown
+ width_map[cp] = 1
+
+ except (ValueError, OverflowError):
+ # Skip invalid code points
+ continue
+
+ # Process Emoji - generally double-width
+ for start, end in EMOJI_RANGES:
+ for cp in range(start, end + 1):
+ if cp not in width_map or width_map[cp] != 0: # Don't override zero-width
+ try:
+ char = chr(cp)
+ width_map[cp] = 2
+ except (ValueError, OverflowError):
+ continue
+
+ # Optimize to create range tables
+ def ranges_optimize(width_data, target_width):
+ points = sorted([cp for cp, width in width_data.items() if width == target_width])
+ if not points:
+ return []
+
+ # Group consecutive code points into ranges
+ ranges = []
+ start = points[0]
+ prev = start
+
+ for cp in points[1:]:
+ if cp > prev + 1:
+ ranges.append((start, prev))
+ start = cp
+ prev = cp
+
+ # Add the last range
+ ranges.append((start, prev))
+ return ranges
+
+ # Extract ranges for each width
+ zero_width_ranges = ranges_optimize(width_map, 0)
+ double_width_ranges = ranges_optimize(width_map, 2)
+
+ return zero_width_ranges, double_width_ranges
+
+def write_tables(zero_width_ranges, double_width_ranges, out_file=DEFAULT_OUT_FILE):
+ """
+ Write the generated tables to C header file.
+
+ Args:
+ zero_width_ranges: List of (start, end) ranges for zero-width characters
+ double_width_ranges: List of (start, end) ranges for double-width characters
+ out_file: Output file name (default: DEFAULT_OUT_FILE)
+ """
+
+ # Function to split ranges into BMP (16-bit) and non-BMP (above 16-bit)
+ def split_ranges_by_size(ranges):
+ bmp_ranges = []
+ non_bmp_ranges = []
+
+ for start, end in ranges:
+ if end <= 0xFFFF:
+ bmp_ranges.append((start, end))
+ elif start > 0xFFFF:
+ non_bmp_ranges.append((start, end))
+ else:
+ # Split the range at 0xFFFF
+ bmp_ranges.append((start, 0xFFFF))
+ non_bmp_ranges.append((0x10000, end))
+
+ return bmp_ranges, non_bmp_ranges
+
+ # Split ranges into BMP and non-BMP
+ zero_width_bmp, zero_width_non_bmp = split_ranges_by_size(zero_width_ranges)
+ double_width_bmp, double_width_non_bmp = split_ranges_by_size(double_width_ranges)
+
+ # Function to generate code point description comments
+ def get_code_point_comment(start, end):
+ try:
+ start_char_desc = unicodedata.name(chr(start))
+ if start == end:
+ return f"/* {start_char_desc} */"
+ else:
+ end_char_desc = unicodedata.name(chr(end))
+ return f"/* {start_char_desc} - {end_char_desc} */"
+ except:
+ if start == end:
+ return f"/* U+{start:04X} */"
+ else:
+ return f"/* U+{start:04X} - U+{end:04X} */"
+
+ # Generate C tables
+ with open(out_file, 'w') as f:
+ f.write(f"""\
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * {out_file} - Unicode character width
+ *
+ * Auto-generated by {this_file}
+ *
+ * Unicode Version: {unicodedata.unidata_version}
+ */
+
+/* Zero-width character ranges (BMP - Basic Multilingual Plane, U+0000 to U+FFFF) */
+static const struct ucs_interval16 ucs_zero_width_bmp_ranges[] = {{
+""")
+
+ for start, end in zero_width_bmp:
+ comment = get_code_point_comment(start, end)
+ f.write(f"\t{{ 0x{start:04X}, 0x{end:04X} }}, {comment}\n")
+
+ f.write("""\
+};
+
+/* Zero-width character ranges (non-BMP, U+10000 and above) */
+static const struct ucs_interval32 ucs_zero_width_non_bmp_ranges[] = {
+""")
+
+ for start, end in zero_width_non_bmp:
+ comment = get_code_point_comment(start, end)
+ f.write(f"\t{{ 0x{start:05X}, 0x{end:05X} }}, {comment}\n")
+
+ f.write("""\
+};
+
+/* Double-width character ranges (BMP - Basic Multilingual Plane, U+0000 to U+FFFF) */
+static const struct ucs_interval16 ucs_double_width_bmp_ranges[] = {
+""")
+
+ for start, end in double_width_bmp:
+ comment = get_code_point_comment(start, end)
+ f.write(f"\t{{ 0x{start:04X}, 0x{end:04X} }}, {comment}\n")
+
+ f.write("""\
+};
+
+/* Double-width character ranges (non-BMP, U+10000 and above) */
+static const struct ucs_interval32 ucs_double_width_non_bmp_ranges[] = {
+""")
+
+ for start, end in double_width_non_bmp:
+ comment = get_code_point_comment(start, end)
+ f.write(f"\t{{ 0x{start:05X}, 0x{end:05X} }}, {comment}\n")
+
+ f.write("};\n")
+
+if __name__ == "__main__":
+ # Parse command line arguments
+ parser = argparse.ArgumentParser(description="Generate Unicode width tables")
+ parser.add_argument("-o", "--output", dest="output_file", default=DEFAULT_OUT_FILE,
+ help=f"Output file name (default: {DEFAULT_OUT_FILE})")
+ args = parser.parse_args()
+
+ # Write tables to header file
+ zero_width_ranges, double_width_ranges = create_width_tables()
+ write_tables(zero_width_ranges, double_width_ranges, out_file=args.output_file)
+
+ # Print summary
+ zero_width_count = sum(end - start + 1 for start, end in zero_width_ranges)
+ double_width_count = sum(end - start + 1 for start, end in double_width_ranges)
+ print(f"Generated {args.output_file} with:")
+ print(f"- {len(zero_width_ranges)} zero-width ranges covering ~{zero_width_count} code points")
+ print(f"- {len(double_width_ranges)} double-width ranges covering ~{double_width_count} code points")
+ print(f"- Unicode Version: {unicodedata.unidata_version}")
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 804355da46f5..dc585079c2fb 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -275,7 +275,7 @@ static DEFINE_TIMER(kd_mksound_timer, kd_nosound);
void kd_mksound(unsigned int hz, unsigned int ticks)
{
- del_timer_sync(&kd_mksound_timer);
+ timer_delete_sync(&kd_mksound_timer);
input_handler_for_each_handle(&kbd_handler, &hz, kd_sound_helper);
@@ -376,6 +376,17 @@ static void to_utf8(struct vc_data *vc, uint c)
}
}
+static void put_queue_utf8(struct vc_data *vc, u32 value)
+{
+ if (kbd->kbdmode == VC_UNICODE)
+ to_utf8(vc, value);
+ else {
+ int c = conv_uni_to_8bit(value);
+ if (c != -1)
+ put_queue(vc, c);
+ }
+}
+
/* FIXME: review locking for vt.c callers */
static void set_leds(void)
{
@@ -454,13 +465,7 @@ static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch)
if (ch == ' ' || ch == (BRL_UC_ROW|0) || ch == d)
return d;
- if (kbd->kbdmode == VC_UNICODE)
- to_utf8(vc, d);
- else {
- int c = conv_uni_to_8bit(d);
- if (c != -1)
- put_queue(vc, c);
- }
+ put_queue_utf8(vc, d);
return ch;
}
@@ -471,13 +476,7 @@ static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch)
static void fn_enter(struct vc_data *vc)
{
if (diacr) {
- if (kbd->kbdmode == VC_UNICODE)
- to_utf8(vc, diacr);
- else {
- int c = conv_uni_to_8bit(diacr);
- if (c != -1)
- put_queue(vc, c);
- }
+ put_queue_utf8(vc, diacr);
diacr = 0;
}
@@ -685,13 +684,7 @@ static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag)
diacr = value;
return;
}
- if (kbd->kbdmode == VC_UNICODE)
- to_utf8(vc, value);
- else {
- int c = conv_uni_to_8bit(value);
- if (c != -1)
- put_queue(vc, c);
- }
+ put_queue_utf8(vc, value);
}
/*
@@ -1519,7 +1512,7 @@ static void kbd_keycode(unsigned int keycode, int down, bool hw_raw)
if ((raw_mode || kbd->kbdmode == VC_OFF) && type != KT_SPEC && type != KT_SHIFT)
return;
- (*k_handler[type])(vc, keysym & 0xff, !down);
+ (*k_handler[type])(vc, KVAL(keysym), !down);
param.ledstate = kbd->ledflagstate;
atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, &param);
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index 0bd6544e30a6..24b0a53e5a79 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -193,13 +193,12 @@ int set_selection_user(const struct tiocl_selection __user *sel,
return -EFAULT;
/*
- * TIOCL_SELCLEAR, TIOCL_SELPOINTER and TIOCL_SELMOUSEREPORT are OK to
- * use without CAP_SYS_ADMIN as they do not modify the selection.
+ * TIOCL_SELCLEAR and TIOCL_SELPOINTER are OK to use without
+ * CAP_SYS_ADMIN as they do not modify the selection.
*/
switch (v.sel_mode) {
case TIOCL_SELCLEAR:
case TIOCL_SELPOINTER:
- case TIOCL_SELMOUSEREPORT:
break;
default:
if (!capable(CAP_SYS_ADMIN))
@@ -404,6 +403,12 @@ int paste_selection(struct tty_struct *tty)
DECLARE_WAITQUEUE(wait, current);
int ret = 0;
+ bool bp = vc->vc_bracketed_paste;
+ static const char bracketed_paste_start[] = "\033[200~";
+ static const char bracketed_paste_end[] = "\033[201~";
+ const char *bps = bp ? bracketed_paste_start : NULL;
+ const char *bpe = bp ? bracketed_paste_end : NULL;
+
console_lock();
poke_blanked_console();
console_unlock();
@@ -415,7 +420,7 @@ int paste_selection(struct tty_struct *tty)
add_wait_queue(&vc->paste_wait, &wait);
mutex_lock(&vc_sel.lock);
- while (vc_sel.buffer && vc_sel.buf_len > pasted) {
+ while (vc_sel.buffer && (vc_sel.buf_len > pasted || bpe)) {
set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current)) {
ret = -EINTR;
@@ -428,10 +433,27 @@ int paste_selection(struct tty_struct *tty)
continue;
}
__set_current_state(TASK_RUNNING);
+
+ if (bps) {
+ bps += tty_ldisc_receive_buf(ld, bps, NULL, strlen(bps));
+ if (*bps != '\0')
+ continue;
+ bps = NULL;
+ }
+
count = vc_sel.buf_len - pasted;
- count = tty_ldisc_receive_buf(ld, vc_sel.buffer + pasted, NULL,
- count);
- pasted += count;
+ if (count) {
+ pasted += tty_ldisc_receive_buf(ld, vc_sel.buffer + pasted,
+ NULL, count);
+ if (vc_sel.buf_len > pasted)
+ continue;
+ }
+
+ if (bpe) {
+ bpe += tty_ldisc_receive_buf(ld, bpe, NULL, strlen(bpe));
+ if (*bpe == '\0')
+ bpe = NULL;
+ }
}
mutex_unlock(&vc_sel.lock);
remove_wait_queue(&vc->paste_wait, &wait);
diff --git a/drivers/tty/vt/ucs.c b/drivers/tty/vt/ucs.c
new file mode 100644
index 000000000000..03877485dfb7
--- /dev/null
+++ b/drivers/tty/vt/ucs.c
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ucs.c - Universal Character Set processing
+ */
+
+#include <linux/array_size.h>
+#include <linux/bsearch.h>
+#include <linux/consolemap.h>
+#include <linux/minmax.h>
+
+struct ucs_interval16 {
+ u16 first;
+ u16 last;
+};
+
+struct ucs_interval32 {
+ u32 first;
+ u32 last;
+};
+
+#include "ucs_width_table.h"
+
+static int interval16_cmp(const void *key, const void *element)
+{
+ u16 cp = *(u16 *)key;
+ const struct ucs_interval16 *entry = element;
+
+ if (cp < entry->first)
+ return -1;
+ if (cp > entry->last)
+ return 1;
+ return 0;
+}
+
+static int interval32_cmp(const void *key, const void *element)
+{
+ u32 cp = *(u32 *)key;
+ const struct ucs_interval32 *entry = element;
+
+ if (cp < entry->first)
+ return -1;
+ if (cp > entry->last)
+ return 1;
+ return 0;
+}
+
+static bool cp_in_range16(u16 cp, const struct ucs_interval16 *ranges, size_t size)
+{
+ if (cp < ranges[0].first || cp > ranges[size - 1].last)
+ return false;
+
+ return __inline_bsearch(&cp, ranges, size, sizeof(*ranges),
+ interval16_cmp) != NULL;
+}
+
+static bool cp_in_range32(u32 cp, const struct ucs_interval32 *ranges, size_t size)
+{
+ if (cp < ranges[0].first || cp > ranges[size - 1].last)
+ return false;
+
+ return __inline_bsearch(&cp, ranges, size, sizeof(*ranges),
+ interval32_cmp) != NULL;
+}
+
+#define UCS_IS_BMP(cp) ((cp) <= 0xffff)
+
+/**
+ * ucs_is_zero_width() - Determine if a Unicode code point is zero-width.
+ * @cp: Unicode code point (UCS-4)
+ *
+ * Return: true if the character is zero-width, false otherwise
+ */
+bool ucs_is_zero_width(u32 cp)
+{
+ if (UCS_IS_BMP(cp))
+ return cp_in_range16(cp, ucs_zero_width_bmp_ranges,
+ ARRAY_SIZE(ucs_zero_width_bmp_ranges));
+ else
+ return cp_in_range32(cp, ucs_zero_width_non_bmp_ranges,
+ ARRAY_SIZE(ucs_zero_width_non_bmp_ranges));
+}
+
+/**
+ * ucs_is_double_width() - Determine if a Unicode code point is double-width.
+ * @cp: Unicode code point (UCS-4)
+ *
+ * Return: true if the character is double-width, false otherwise
+ */
+bool ucs_is_double_width(u32 cp)
+{
+ if (UCS_IS_BMP(cp))
+ return cp_in_range16(cp, ucs_double_width_bmp_ranges,
+ ARRAY_SIZE(ucs_double_width_bmp_ranges));
+ else
+ return cp_in_range32(cp, ucs_double_width_non_bmp_ranges,
+ ARRAY_SIZE(ucs_double_width_non_bmp_ranges));
+}
+
+/*
+ * Structure for base with combining mark pairs and resulting recompositions.
+ * Using u16 to save space since all values are within BMP range.
+ */
+struct ucs_recomposition {
+ u16 base; /* base character */
+ u16 mark; /* combining mark */
+ u16 recomposed; /* corresponding recomposed character */
+};
+
+#include "ucs_recompose_table.h"
+
+struct compare_key {
+ u16 base;
+ u16 mark;
+};
+
+static int recomposition_cmp(const void *key, const void *element)
+{
+ const struct compare_key *search_key = key;
+ const struct ucs_recomposition *entry = element;
+
+ /* Compare base character first */
+ if (search_key->base < entry->base)
+ return -1;
+ if (search_key->base > entry->base)
+ return 1;
+
+ /* Base characters match, now compare combining character */
+ if (search_key->mark < entry->mark)
+ return -1;
+ if (search_key->mark > entry->mark)
+ return 1;
+
+ /* Both match */
+ return 0;
+}
+
+/**
+ * ucs_recompose() - Attempt to recompose two Unicode characters into a single character.
+ * @base: Base Unicode code point (UCS-4)
+ * @mark: Combining mark Unicode code point (UCS-4)
+ *
+ * Return: Recomposed Unicode code point, or 0 if no recomposition is possible
+ */
+u32 ucs_recompose(u32 base, u32 mark)
+{
+ /* Check if characters are within the range of our table */
+ if (base < UCS_RECOMPOSE_MIN_BASE || base > UCS_RECOMPOSE_MAX_BASE ||
+ mark < UCS_RECOMPOSE_MIN_MARK || mark > UCS_RECOMPOSE_MAX_MARK)
+ return 0;
+
+ struct compare_key key = { base, mark };
+ struct ucs_recomposition *result =
+ __inline_bsearch(&key, ucs_recomposition_table,
+ ARRAY_SIZE(ucs_recomposition_table),
+ sizeof(*ucs_recomposition_table),
+ recomposition_cmp);
+
+ return result ? result->recomposed : 0;
+}
+
+/*
+ * The fallback table structures implement a 2-level lookup.
+ */
+
+struct ucs_page_desc {
+ u8 page; /* Page index (high byte of code points) */
+ u8 count; /* Number of entries in this page */
+ u16 start; /* Start index in entries array */
+};
+
+struct ucs_page_entry {
+ u8 offset; /* Offset within page (0-255) */
+ u8 fallback; /* Fallback character or range start marker */
+};
+
+#include "ucs_fallback_table.h"
+
+static int ucs_page_desc_cmp(const void *key, const void *element)
+{
+ u8 page = *(u8 *)key;
+ const struct ucs_page_desc *entry = element;
+
+ if (page < entry->page)
+ return -1;
+ if (page > entry->page)
+ return 1;
+ return 0;
+}
+
+static int ucs_page_entry_cmp(const void *key, const void *element)
+{
+ u8 offset = *(u8 *)key;
+ const struct ucs_page_entry *entry = element;
+
+ if (offset < entry->offset)
+ return -1;
+ if (entry->fallback == UCS_PAGE_ENTRY_RANGE_MARKER) {
+ if (offset > entry[1].offset)
+ return 1;
+ } else {
+ if (offset > entry->offset)
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * ucs_get_fallback() - Get a substitution for the provided Unicode character
+ * @cp: Unicode code point (UCS-4)
+ *
+ * Get a simpler fallback character for the provided Unicode character.
+ * This is used for terminal display when corresponding glyph is unavailable.
+ * The substitution may not be as good as the actual glyph for the original
+ * character but still way more helpful than a squared question mark.
+ *
+ * Return: Fallback Unicode code point, or 0 if none is available
+ */
+u32 ucs_get_fallback(u32 cp)
+{
+ const struct ucs_page_desc *page;
+ const struct ucs_page_entry *entry;
+ u8 page_idx = cp >> 8, offset = cp;
+
+ if (!UCS_IS_BMP(cp))
+ return 0;
+
+ /*
+ * Full-width to ASCII mapping (covering all printable ASCII 33-126)
+ * 0xFF01 (!) to 0xFF5E (~) -> ASCII 33 (!) to 126 (~)
+ * We process them programmatically to reduce the table size.
+ */
+ if (cp >= 0xFF01 && cp <= 0xFF5E)
+ return cp - 0xFF01 + 33;
+
+ page = __inline_bsearch(&page_idx, ucs_fallback_pages,
+ ARRAY_SIZE(ucs_fallback_pages),
+ sizeof(*ucs_fallback_pages),
+ ucs_page_desc_cmp);
+ if (!page)
+ return 0;
+
+ entry = __inline_bsearch(&offset, ucs_fallback_entries + page->start,
+ page->count, sizeof(*ucs_fallback_entries),
+ ucs_page_entry_cmp);
+ if (!entry)
+ return 0;
+
+ if (entry->fallback == UCS_PAGE_ENTRY_RANGE_MARKER)
+ entry++;
+ return entry->fallback;
+}
diff --git a/drivers/tty/vt/ucs_fallback_table.h_shipped b/drivers/tty/vt/ucs_fallback_table.h_shipped
new file mode 100644
index 000000000000..2da5a8fe1cf1
--- /dev/null
+++ b/drivers/tty/vt/ucs_fallback_table.h_shipped
@@ -0,0 +1,3346 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ucs_fallback_table.h - Unicode character fallback table
+ *
+ * Auto-generated by gen_ucs_fallback_table.py
+ *
+ * Unicode Version: 16.0.0
+ * Unidecode Version: 1.3.8
+ *
+ * This file contains optimized tables that map complex Unicode characters
+ * to simpler fallback characters for terminal display when corresponding
+ * glyphs are unavailable.
+ */
+
+static const struct ucs_page_desc ucs_fallback_pages[] = {
+ { 0x00, 62, 0 },
+ { 0x01, 218, 62 },
+ { 0x02, 196, 280 },
+ { 0x03, 96, 476 },
+ { 0x04, 113, 572 },
+ { 0x05, 100, 685 },
+ { 0x06, 119, 785 },
+ { 0x07, 91, 904 },
+ { 0x09, 99, 995 },
+ { 0x0A, 78, 1094 },
+ { 0x0B, 79, 1172 },
+ { 0x0C, 85, 1251 },
+ { 0x0D, 73, 1336 },
+ { 0x0E, 83, 1409 },
+ { 0x0F, 69, 1492 },
+ { 0x10, 93, 1561 },
+ { 0x11, 51, 1654 },
+ { 0x13, 22, 1705 },
+ { 0x14, 30, 1727 },
+ { 0x15, 17, 1757 },
+ { 0x16, 81, 1774 },
+ { 0x17, 47, 1855 },
+ { 0x18, 96, 1902 },
+ { 0x1D, 105, 1998 },
+ { 0x1E, 246, 2103 },
+ { 0x1F, 94, 2349 },
+ { 0x20, 107, 2443 },
+ { 0x21, 136, 2550 },
+ { 0x22, 34, 2686 },
+ { 0x23, 4, 2720 },
+ { 0x24, 72, 2724 },
+ { 0x25, 60, 2796 },
+ { 0x26, 6, 2856 },
+ { 0x27, 18, 2862 },
+ { 0x28, 64, 2880 },
+ { 0x29, 1, 2944 },
+ { 0x2C, 15, 2945 },
+ { 0x2E, 29, 2960 },
+ { 0x30, 53, 2989 },
+ { 0x31, 50, 3042 },
+ { 0x32, 5, 3092 },
+ { 0xA0, 4, 3097 },
+ { 0xC5, 2, 3101 },
+ { 0xC6, 2, 3103 },
+ { 0xC7, 1, 3105 },
+ { 0xFB, 35, 3106 },
+ { 0xFE, 37, 3141 },
+ { 0xFF, 50, 3178 },
+};
+
+/* Page entries array (referenced by page descriptors) */
+static const struct ucs_page_entry ucs_fallback_entries[] = {
+ /* Entries for page 0x00 */
+ { 0xA0, 0x20 }, /* NO-BREAK SPACE -> ' ' */
+ { 0xA1, 0x21 }, /* INVERTED EXCLAMATION MARK -> '!' */
+ { 0xA2, 0x63 }, /* CENT SIGN -> 'c' */
+ { 0xA3, 0x4C }, /* POUND SIGN -> 'L' */
+ { 0xA5, 0x59 }, /* YEN SIGN -> 'Y' */
+ { 0xA6, 0x7C }, /* BROKEN BAR -> '|' */
+ { 0xA7, 0x53 }, /* SECTION SIGN -> 'S' */
+ { 0xA8, 0x22 }, /* DIAERESIS -> '"' */
+ { 0xA9, 0x43 }, /* COPYRIGHT SIGN -> 'C' */
+ { 0xAA, 0x61 }, /* FEMININE ORDINAL INDICATOR -> 'a' */
+ { 0xAB, 0x3C }, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -> '<' */
+ { 0xAC, 0x21 }, /* NOT SIGN -> '!' */
+ { 0xAE, 0x52 }, /* REGISTERED SIGN -> 'R' */
+ { 0xAF, 0x2D }, /* MACRON -> '-' */
+ { 0xB0, 0x6F }, /* DEGREE SIGN -> 'o' */
+ { 0xB2, 0x32 }, /* SUPERSCRIPT TWO -> '2' */
+ { 0xB3, 0x33 }, /* SUPERSCRIPT THREE -> '3' */
+ { 0xB4, 0x27 }, /* ACUTE ACCENT -> ''' */
+ { 0xB5, 0x75 }, /* MICRO SIGN -> 'u' */
+ { 0xB6, 0x50 }, /* PILCROW SIGN -> 'P' */
+ { 0xB7, 0x2A }, /* MIDDLE DOT -> '*' */
+ { 0xB8, 0x2C }, /* CEDILLA -> ',' */
+ { 0xB9, 0x31 }, /* SUPERSCRIPT ONE -> '1' */
+ { 0xBA, 0x6F }, /* MASCULINE ORDINAL INDICATOR -> 'o' */
+ { 0xBB, 0x3E }, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -> '>' */
+ { 0xBF, 0x3F }, /* INVERTED QUESTION MARK -> '?' */
+ { 0xC0, 0x00 }, /* LATIN CAPITAL LETTER A WITH GRAVE -> ... */
+ { 0xC5, 0x41 }, /* LATIN CAPITAL LETTER A WITH RING ABOVE -> 'A' */
+ { 0xC6, 0x45 }, /* LATIN CAPITAL LETTER AE -> 'E' */
+ { 0xC7, 0x43 }, /* LATIN CAPITAL LETTER C WITH CEDILLA -> 'C' */
+ { 0xC8, 0x00 }, /* LATIN CAPITAL LETTER E WITH GRAVE -> ... */
+ { 0xCB, 0x45 }, /* LATIN CAPITAL LETTER E WITH DIAERESIS -> 'E' */
+ { 0xCC, 0x00 }, /* LATIN CAPITAL LETTER I WITH GRAVE -> ... */
+ { 0xCF, 0x49 }, /* LATIN CAPITAL LETTER I WITH DIAERESIS -> 'I' */
+ { 0xD0, 0x44 }, /* LATIN CAPITAL LETTER ETH -> 'D' */
+ { 0xD1, 0x4E }, /* LATIN CAPITAL LETTER N WITH TILDE -> 'N' */
+ { 0xD2, 0x00 }, /* LATIN CAPITAL LETTER O WITH GRAVE -> ... */
+ { 0xD6, 0x4F }, /* LATIN CAPITAL LETTER O WITH DIAERESIS -> 'O' */
+ { 0xD7, 0x78 }, /* MULTIPLICATION SIGN -> 'x' */
+ { 0xD8, 0x4F }, /* LATIN CAPITAL LETTER O WITH STROKE -> 'O' */
+ { 0xD9, 0x00 }, /* LATIN CAPITAL LETTER U WITH GRAVE -> ... */
+ { 0xDC, 0x55 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS -> 'U' */
+ { 0xDD, 0x59 }, /* LATIN CAPITAL LETTER Y WITH ACUTE -> 'Y' */
+ { 0xDF, 0x73 }, /* LATIN SMALL LETTER SHARP S -> 's' */
+ { 0xE0, 0x00 }, /* LATIN SMALL LETTER A WITH GRAVE -> ... */
+ { 0xE5, 0x61 }, /* LATIN SMALL LETTER A WITH RING ABOVE -> 'a' */
+ { 0xE6, 0x65 }, /* LATIN SMALL LETTER AE -> 'e' */
+ { 0xE7, 0x63 }, /* LATIN SMALL LETTER C WITH CEDILLA -> 'c' */
+ { 0xE8, 0x00 }, /* LATIN SMALL LETTER E WITH GRAVE -> ... */
+ { 0xEB, 0x65 }, /* LATIN SMALL LETTER E WITH DIAERESIS -> 'e' */
+ { 0xEC, 0x00 }, /* LATIN SMALL LETTER I WITH GRAVE -> ... */
+ { 0xEF, 0x69 }, /* LATIN SMALL LETTER I WITH DIAERESIS -> 'i' */
+ { 0xF0, 0x64 }, /* LATIN SMALL LETTER ETH -> 'd' */
+ { 0xF1, 0x6E }, /* LATIN SMALL LETTER N WITH TILDE -> 'n' */
+ { 0xF2, 0x00 }, /* LATIN SMALL LETTER O WITH GRAVE -> ... */
+ { 0xF6, 0x6F }, /* LATIN SMALL LETTER O WITH DIAERESIS -> 'o' */
+ { 0xF7, 0x2F }, /* DIVISION SIGN -> '/' */
+ { 0xF8, 0x6F }, /* LATIN SMALL LETTER O WITH STROKE -> 'o' */
+ { 0xF9, 0x00 }, /* LATIN SMALL LETTER U WITH GRAVE -> ... */
+ { 0xFC, 0x75 }, /* LATIN SMALL LETTER U WITH DIAERESIS -> 'u' */
+ { 0xFD, 0x79 }, /* LATIN SMALL LETTER Y WITH ACUTE -> 'y' */
+ { 0xFF, 0x79 }, /* LATIN SMALL LETTER Y WITH DIAERESIS -> 'y' */
+ /* Entries for page 0x01 */
+ { 0x00, 0x41 }, /* LATIN CAPITAL LETTER A WITH MACRON -> 'A' */
+ { 0x01, 0x61 }, /* LATIN SMALL LETTER A WITH MACRON -> 'a' */
+ { 0x02, 0x41 }, /* LATIN CAPITAL LETTER A WITH BREVE -> 'A' */
+ { 0x03, 0x61 }, /* LATIN SMALL LETTER A WITH BREVE -> 'a' */
+ { 0x04, 0x41 }, /* LATIN CAPITAL LETTER A WITH OGONEK -> 'A' */
+ { 0x05, 0x61 }, /* LATIN SMALL LETTER A WITH OGONEK -> 'a' */
+ { 0x06, 0x43 }, /* LATIN CAPITAL LETTER C WITH ACUTE -> 'C' */
+ { 0x07, 0x63 }, /* LATIN SMALL LETTER C WITH ACUTE -> 'c' */
+ { 0x08, 0x43 }, /* LATIN CAPITAL LETTER C WITH CIRCUMFLEX -> 'C' */
+ { 0x09, 0x63 }, /* LATIN SMALL LETTER C WITH CIRCUMFLEX -> 'c' */
+ { 0x0A, 0x43 }, /* LATIN CAPITAL LETTER C WITH DOT ABOVE -> 'C' */
+ { 0x0B, 0x63 }, /* LATIN SMALL LETTER C WITH DOT ABOVE -> 'c' */
+ { 0x0C, 0x43 }, /* LATIN CAPITAL LETTER C WITH CARON -> 'C' */
+ { 0x0D, 0x63 }, /* LATIN SMALL LETTER C WITH CARON -> 'c' */
+ { 0x0E, 0x44 }, /* LATIN CAPITAL LETTER D WITH CARON -> 'D' */
+ { 0x0F, 0x64 }, /* LATIN SMALL LETTER D WITH CARON -> 'd' */
+ { 0x10, 0x44 }, /* LATIN CAPITAL LETTER D WITH STROKE -> 'D' */
+ { 0x11, 0x64 }, /* LATIN SMALL LETTER D WITH STROKE -> 'd' */
+ { 0x12, 0x45 }, /* LATIN CAPITAL LETTER E WITH MACRON -> 'E' */
+ { 0x13, 0x65 }, /* LATIN SMALL LETTER E WITH MACRON -> 'e' */
+ { 0x14, 0x45 }, /* LATIN CAPITAL LETTER E WITH BREVE -> 'E' */
+ { 0x15, 0x65 }, /* LATIN SMALL LETTER E WITH BREVE -> 'e' */
+ { 0x16, 0x45 }, /* LATIN CAPITAL LETTER E WITH DOT ABOVE -> 'E' */
+ { 0x17, 0x65 }, /* LATIN SMALL LETTER E WITH DOT ABOVE -> 'e' */
+ { 0x18, 0x45 }, /* LATIN CAPITAL LETTER E WITH OGONEK -> 'E' */
+ { 0x19, 0x65 }, /* LATIN SMALL LETTER E WITH OGONEK -> 'e' */
+ { 0x1A, 0x45 }, /* LATIN CAPITAL LETTER E WITH CARON -> 'E' */
+ { 0x1B, 0x65 }, /* LATIN SMALL LETTER E WITH CARON -> 'e' */
+ { 0x1C, 0x47 }, /* LATIN CAPITAL LETTER G WITH CIRCUMFLEX -> 'G' */
+ { 0x1D, 0x67 }, /* LATIN SMALL LETTER G WITH CIRCUMFLEX -> 'g' */
+ { 0x1E, 0x47 }, /* LATIN CAPITAL LETTER G WITH BREVE -> 'G' */
+ { 0x1F, 0x67 }, /* LATIN SMALL LETTER G WITH BREVE -> 'g' */
+ { 0x20, 0x47 }, /* LATIN CAPITAL LETTER G WITH DOT ABOVE -> 'G' */
+ { 0x21, 0x67 }, /* LATIN SMALL LETTER G WITH DOT ABOVE -> 'g' */
+ { 0x22, 0x47 }, /* LATIN CAPITAL LETTER G WITH CEDILLA -> 'G' */
+ { 0x23, 0x67 }, /* LATIN SMALL LETTER G WITH CEDILLA -> 'g' */
+ { 0x24, 0x48 }, /* LATIN CAPITAL LETTER H WITH CIRCUMFLEX -> 'H' */
+ { 0x25, 0x68 }, /* LATIN SMALL LETTER H WITH CIRCUMFLEX -> 'h' */
+ { 0x26, 0x48 }, /* LATIN CAPITAL LETTER H WITH STROKE -> 'H' */
+ { 0x27, 0x68 }, /* LATIN SMALL LETTER H WITH STROKE -> 'h' */
+ { 0x28, 0x49 }, /* LATIN CAPITAL LETTER I WITH TILDE -> 'I' */
+ { 0x29, 0x69 }, /* LATIN SMALL LETTER I WITH TILDE -> 'i' */
+ { 0x2A, 0x49 }, /* LATIN CAPITAL LETTER I WITH MACRON -> 'I' */
+ { 0x2B, 0x69 }, /* LATIN SMALL LETTER I WITH MACRON -> 'i' */
+ { 0x2C, 0x49 }, /* LATIN CAPITAL LETTER I WITH BREVE -> 'I' */
+ { 0x2D, 0x69 }, /* LATIN SMALL LETTER I WITH BREVE -> 'i' */
+ { 0x2E, 0x49 }, /* LATIN CAPITAL LETTER I WITH OGONEK -> 'I' */
+ { 0x2F, 0x69 }, /* LATIN SMALL LETTER I WITH OGONEK -> 'i' */
+ { 0x30, 0x49 }, /* LATIN CAPITAL LETTER I WITH DOT ABOVE -> 'I' */
+ { 0x31, 0x69 }, /* LATIN SMALL LETTER DOTLESS I -> 'i' */
+ { 0x34, 0x4A }, /* LATIN CAPITAL LETTER J WITH CIRCUMFLEX -> 'J' */
+ { 0x35, 0x6A }, /* LATIN SMALL LETTER J WITH CIRCUMFLEX -> 'j' */
+ { 0x36, 0x4B }, /* LATIN CAPITAL LETTER K WITH CEDILLA -> 'K' */
+ { 0x37, 0x6B }, /* LATIN SMALL LETTER K WITH CEDILLA -> 'k' */
+ { 0x38, 0x6B }, /* LATIN SMALL LETTER KRA -> 'k' */
+ { 0x39, 0x4C }, /* LATIN CAPITAL LETTER L WITH ACUTE -> 'L' */
+ { 0x3A, 0x6C }, /* LATIN SMALL LETTER L WITH ACUTE -> 'l' */
+ { 0x3B, 0x4C }, /* LATIN CAPITAL LETTER L WITH CEDILLA -> 'L' */
+ { 0x3C, 0x6C }, /* LATIN SMALL LETTER L WITH CEDILLA -> 'l' */
+ { 0x3D, 0x4C }, /* LATIN CAPITAL LETTER L WITH CARON -> 'L' */
+ { 0x3E, 0x6C }, /* LATIN SMALL LETTER L WITH CARON -> 'l' */
+ { 0x3F, 0x4C }, /* LATIN CAPITAL LETTER L WITH MIDDLE DOT -> 'L' */
+ { 0x40, 0x6C }, /* LATIN SMALL LETTER L WITH MIDDLE DOT -> 'l' */
+ { 0x41, 0x4C }, /* LATIN CAPITAL LETTER L WITH STROKE -> 'L' */
+ { 0x42, 0x6C }, /* LATIN SMALL LETTER L WITH STROKE -> 'l' */
+ { 0x43, 0x4E }, /* LATIN CAPITAL LETTER N WITH ACUTE -> 'N' */
+ { 0x44, 0x6E }, /* LATIN SMALL LETTER N WITH ACUTE -> 'n' */
+ { 0x45, 0x4E }, /* LATIN CAPITAL LETTER N WITH CEDILLA -> 'N' */
+ { 0x46, 0x6E }, /* LATIN SMALL LETTER N WITH CEDILLA -> 'n' */
+ { 0x47, 0x4E }, /* LATIN CAPITAL LETTER N WITH CARON -> 'N' */
+ { 0x48, 0x6E }, /* LATIN SMALL LETTER N WITH CARON -> 'n' */
+ { 0x4C, 0x4F }, /* LATIN CAPITAL LETTER O WITH MACRON -> 'O' */
+ { 0x4D, 0x6F }, /* LATIN SMALL LETTER O WITH MACRON -> 'o' */
+ { 0x4E, 0x4F }, /* LATIN CAPITAL LETTER O WITH BREVE -> 'O' */
+ { 0x4F, 0x6F }, /* LATIN SMALL LETTER O WITH BREVE -> 'o' */
+ { 0x50, 0x4F }, /* LATIN CAPITAL LETTER O WITH DOUBLE ACUTE -> 'O' */
+ { 0x51, 0x6F }, /* LATIN SMALL LETTER O WITH DOUBLE ACUTE -> 'o' */
+ { 0x52, 0x45 }, /* LATIN CAPITAL LIGATURE OE -> 'E' */
+ { 0x53, 0x65 }, /* LATIN SMALL LIGATURE OE -> 'e' */
+ { 0x54, 0x52 }, /* LATIN CAPITAL LETTER R WITH ACUTE -> 'R' */
+ { 0x55, 0x72 }, /* LATIN SMALL LETTER R WITH ACUTE -> 'r' */
+ { 0x56, 0x52 }, /* LATIN CAPITAL LETTER R WITH CEDILLA -> 'R' */
+ { 0x57, 0x72 }, /* LATIN SMALL LETTER R WITH CEDILLA -> 'r' */
+ { 0x58, 0x52 }, /* LATIN CAPITAL LETTER R WITH CARON -> 'R' */
+ { 0x59, 0x72 }, /* LATIN SMALL LETTER R WITH CARON -> 'r' */
+ { 0x5A, 0x53 }, /* LATIN CAPITAL LETTER S WITH ACUTE -> 'S' */
+ { 0x5B, 0x73 }, /* LATIN SMALL LETTER S WITH ACUTE -> 's' */
+ { 0x5C, 0x53 }, /* LATIN CAPITAL LETTER S WITH CIRCUMFLEX -> 'S' */
+ { 0x5D, 0x73 }, /* LATIN SMALL LETTER S WITH CIRCUMFLEX -> 's' */
+ { 0x5E, 0x53 }, /* LATIN CAPITAL LETTER S WITH CEDILLA -> 'S' */
+ { 0x5F, 0x73 }, /* LATIN SMALL LETTER S WITH CEDILLA -> 's' */
+ { 0x60, 0x53 }, /* LATIN CAPITAL LETTER S WITH CARON -> 'S' */
+ { 0x61, 0x73 }, /* LATIN SMALL LETTER S WITH CARON -> 's' */
+ { 0x62, 0x54 }, /* LATIN CAPITAL LETTER T WITH CEDILLA -> 'T' */
+ { 0x63, 0x74 }, /* LATIN SMALL LETTER T WITH CEDILLA -> 't' */
+ { 0x64, 0x54 }, /* LATIN CAPITAL LETTER T WITH CARON -> 'T' */
+ { 0x65, 0x74 }, /* LATIN SMALL LETTER T WITH CARON -> 't' */
+ { 0x66, 0x54 }, /* LATIN CAPITAL LETTER T WITH STROKE -> 'T' */
+ { 0x67, 0x74 }, /* LATIN SMALL LETTER T WITH STROKE -> 't' */
+ { 0x68, 0x55 }, /* LATIN CAPITAL LETTER U WITH TILDE -> 'U' */
+ { 0x69, 0x75 }, /* LATIN SMALL LETTER U WITH TILDE -> 'u' */
+ { 0x6A, 0x55 }, /* LATIN CAPITAL LETTER U WITH MACRON -> 'U' */
+ { 0x6B, 0x75 }, /* LATIN SMALL LETTER U WITH MACRON -> 'u' */
+ { 0x6C, 0x55 }, /* LATIN CAPITAL LETTER U WITH BREVE -> 'U' */
+ { 0x6D, 0x75 }, /* LATIN SMALL LETTER U WITH BREVE -> 'u' */
+ { 0x6E, 0x55 }, /* LATIN CAPITAL LETTER U WITH RING ABOVE -> 'U' */
+ { 0x6F, 0x75 }, /* LATIN SMALL LETTER U WITH RING ABOVE -> 'u' */
+ { 0x70, 0x55 }, /* LATIN CAPITAL LETTER U WITH DOUBLE ACUTE -> 'U' */
+ { 0x71, 0x75 }, /* LATIN SMALL LETTER U WITH DOUBLE ACUTE -> 'u' */
+ { 0x72, 0x55 }, /* LATIN CAPITAL LETTER U WITH OGONEK -> 'U' */
+ { 0x73, 0x75 }, /* LATIN SMALL LETTER U WITH OGONEK -> 'u' */
+ { 0x74, 0x57 }, /* LATIN CAPITAL LETTER W WITH CIRCUMFLEX -> 'W' */
+ { 0x75, 0x77 }, /* LATIN SMALL LETTER W WITH CIRCUMFLEX -> 'w' */
+ { 0x76, 0x59 }, /* LATIN CAPITAL LETTER Y WITH CIRCUMFLEX -> 'Y' */
+ { 0x77, 0x79 }, /* LATIN SMALL LETTER Y WITH CIRCUMFLEX -> 'y' */
+ { 0x78, 0x59 }, /* LATIN CAPITAL LETTER Y WITH DIAERESIS -> 'Y' */
+ { 0x79, 0x5A }, /* LATIN CAPITAL LETTER Z WITH ACUTE -> 'Z' */
+ { 0x7A, 0x7A }, /* LATIN SMALL LETTER Z WITH ACUTE -> 'z' */
+ { 0x7B, 0x5A }, /* LATIN CAPITAL LETTER Z WITH DOT ABOVE -> 'Z' */
+ { 0x7C, 0x7A }, /* LATIN SMALL LETTER Z WITH DOT ABOVE -> 'z' */
+ { 0x7D, 0x5A }, /* LATIN CAPITAL LETTER Z WITH CARON -> 'Z' */
+ { 0x7E, 0x7A }, /* LATIN SMALL LETTER Z WITH CARON -> 'z' */
+ { 0x7F, 0x73 }, /* LATIN SMALL LETTER LONG S -> 's' */
+ { 0x80, 0x62 }, /* LATIN SMALL LETTER B WITH STROKE -> 'b' */
+ { 0x81, 0x42 }, /* LATIN CAPITAL LETTER B WITH HOOK -> 'B' */
+ { 0x82, 0x42 }, /* LATIN CAPITAL LETTER B WITH TOPBAR -> 'B' */
+ { 0x83, 0x62 }, /* LATIN SMALL LETTER B WITH TOPBAR -> 'b' */
+ { 0x84, 0x36 }, /* LATIN CAPITAL LETTER TONE SIX -> '6' */
+ { 0x85, 0x36 }, /* LATIN SMALL LETTER TONE SIX -> '6' */
+ { 0x86, 0x4F }, /* LATIN CAPITAL LETTER OPEN O -> 'O' */
+ { 0x87, 0x43 }, /* LATIN CAPITAL LETTER C WITH HOOK -> 'C' */
+ { 0x88, 0x63 }, /* LATIN SMALL LETTER C WITH HOOK -> 'c' */
+ { 0x89, 0x00 }, /* LATIN CAPITAL LETTER AFRICAN D -> ... */
+ { 0x8B, 0x44 }, /* LATIN CAPITAL LETTER D WITH TOPBAR -> 'D' */
+ { 0x8C, 0x64 }, /* LATIN SMALL LETTER D WITH TOPBAR -> 'd' */
+ { 0x8D, 0x64 }, /* LATIN SMALL LETTER TURNED DELTA -> 'd' */
+ { 0x8E, 0x33 }, /* LATIN CAPITAL LETTER REVERSED E -> '3' */
+ { 0x8F, 0x40 }, /* LATIN CAPITAL LETTER SCHWA -> '@' */
+ { 0x90, 0x45 }, /* LATIN CAPITAL LETTER OPEN E -> 'E' */
+ { 0x91, 0x46 }, /* LATIN CAPITAL LETTER F WITH HOOK -> 'F' */
+ { 0x92, 0x66 }, /* LATIN SMALL LETTER F WITH HOOK -> 'f' */
+ { 0x93, 0x47 }, /* LATIN CAPITAL LETTER G WITH HOOK -> 'G' */
+ { 0x94, 0x47 }, /* LATIN CAPITAL LETTER GAMMA -> 'G' */
+ { 0x96, 0x49 }, /* LATIN CAPITAL LETTER IOTA -> 'I' */
+ { 0x97, 0x49 }, /* LATIN CAPITAL LETTER I WITH STROKE -> 'I' */
+ { 0x98, 0x4B }, /* LATIN CAPITAL LETTER K WITH HOOK -> 'K' */
+ { 0x99, 0x6B }, /* LATIN SMALL LETTER K WITH HOOK -> 'k' */
+ { 0x9A, 0x6C }, /* LATIN SMALL LETTER L WITH BAR -> 'l' */
+ { 0x9B, 0x6C }, /* LATIN SMALL LETTER LAMBDA WITH STROKE -> 'l' */
+ { 0x9C, 0x57 }, /* LATIN CAPITAL LETTER TURNED M -> 'W' */
+ { 0x9D, 0x4E }, /* LATIN CAPITAL LETTER N WITH LEFT HOOK -> 'N' */
+ { 0x9E, 0x6E }, /* LATIN SMALL LETTER N WITH LONG RIGHT LEG -> 'n' */
+ { 0x9F, 0x4F }, /* LATIN CAPITAL LETTER O WITH MIDDLE TILDE -> 'O' */
+ { 0xA0, 0x4F }, /* LATIN CAPITAL LETTER O WITH HORN -> 'O' */
+ { 0xA1, 0x6F }, /* LATIN SMALL LETTER O WITH HORN -> 'o' */
+ { 0xA4, 0x50 }, /* LATIN CAPITAL LETTER P WITH HOOK -> 'P' */
+ { 0xA5, 0x70 }, /* LATIN SMALL LETTER P WITH HOOK -> 'p' */
+ { 0xA7, 0x32 }, /* LATIN CAPITAL LETTER TONE TWO -> '2' */
+ { 0xA8, 0x32 }, /* LATIN SMALL LETTER TONE TWO -> '2' */
+ { 0xAB, 0x74 }, /* LATIN SMALL LETTER T WITH PALATAL HOOK -> 't' */
+ { 0xAC, 0x54 }, /* LATIN CAPITAL LETTER T WITH HOOK -> 'T' */
+ { 0xAD, 0x74 }, /* LATIN SMALL LETTER T WITH HOOK -> 't' */
+ { 0xAE, 0x54 }, /* LATIN CAPITAL LETTER T WITH RETROFLEX HOOK -> 'T' */
+ { 0xAF, 0x55 }, /* LATIN CAPITAL LETTER U WITH HORN -> 'U' */
+ { 0xB0, 0x75 }, /* LATIN SMALL LETTER U WITH HORN -> 'u' */
+ { 0xB1, 0x59 }, /* LATIN CAPITAL LETTER UPSILON -> 'Y' */
+ { 0xB2, 0x56 }, /* LATIN CAPITAL LETTER V WITH HOOK -> 'V' */
+ { 0xB3, 0x59 }, /* LATIN CAPITAL LETTER Y WITH HOOK -> 'Y' */
+ { 0xB4, 0x79 }, /* LATIN SMALL LETTER Y WITH HOOK -> 'y' */
+ { 0xB5, 0x5A }, /* LATIN CAPITAL LETTER Z WITH STROKE -> 'Z' */
+ { 0xB6, 0x7A }, /* LATIN SMALL LETTER Z WITH STROKE -> 'z' */
+ { 0xBB, 0x32 }, /* LATIN LETTER TWO WITH STROKE -> '2' */
+ { 0xBC, 0x35 }, /* LATIN CAPITAL LETTER TONE FIVE -> '5' */
+ { 0xBD, 0x35 }, /* LATIN SMALL LETTER TONE FIVE -> '5' */
+ { 0xBF, 0x77 }, /* LATIN LETTER WYNN -> 'w' */
+ { 0xC0, 0x7C }, /* LATIN LETTER DENTAL CLICK -> '|' */
+ { 0xC3, 0x21 }, /* LATIN LETTER RETROFLEX CLICK -> '!' */
+ { 0xCD, 0x41 }, /* LATIN CAPITAL LETTER A WITH CARON -> 'A' */
+ { 0xCE, 0x61 }, /* LATIN SMALL LETTER A WITH CARON -> 'a' */
+ { 0xCF, 0x49 }, /* LATIN CAPITAL LETTER I WITH CARON -> 'I' */
+ { 0xD0, 0x69 }, /* LATIN SMALL LETTER I WITH CARON -> 'i' */
+ { 0xD1, 0x4F }, /* LATIN CAPITAL LETTER O WITH CARON -> 'O' */
+ { 0xD2, 0x6F }, /* LATIN SMALL LETTER O WITH CARON -> 'o' */
+ { 0xD3, 0x55 }, /* LATIN CAPITAL LETTER U WITH CARON -> 'U' */
+ { 0xD4, 0x75 }, /* LATIN SMALL LETTER U WITH CARON -> 'u' */
+ { 0xD5, 0x55 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON -> 'U' */
+ { 0xD6, 0x75 }, /* LATIN SMALL LETTER U WITH DIAERESIS AND MACRON -> 'u' */
+ { 0xD7, 0x55 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE -> 'U' */
+ { 0xD8, 0x75 }, /* LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE -> 'u' */
+ { 0xD9, 0x55 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON -> 'U' */
+ { 0xDA, 0x75 }, /* LATIN SMALL LETTER U WITH DIAERESIS AND CARON -> 'u' */
+ { 0xDB, 0x55 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE -> 'U' */
+ { 0xDC, 0x75 }, /* LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE -> 'u' */
+ { 0xDD, 0x40 }, /* LATIN SMALL LETTER TURNED E -> '@' */
+ { 0xDE, 0x41 }, /* LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON -> 'A' */
+ { 0xDF, 0x61 }, /* LATIN SMALL LETTER A WITH DIAERESIS AND MACRON -> 'a' */
+ { 0xE0, 0x41 }, /* LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON -> 'A' */
+ { 0xE1, 0x61 }, /* LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON -> 'a' */
+ { 0xE4, 0x47 }, /* LATIN CAPITAL LETTER G WITH STROKE -> 'G' */
+ { 0xE5, 0x67 }, /* LATIN SMALL LETTER G WITH STROKE -> 'g' */
+ { 0xE6, 0x47 }, /* LATIN CAPITAL LETTER G WITH CARON -> 'G' */
+ { 0xE7, 0x67 }, /* LATIN SMALL LETTER G WITH CARON -> 'g' */
+ { 0xE8, 0x4B }, /* LATIN CAPITAL LETTER K WITH CARON -> 'K' */
+ { 0xE9, 0x6B }, /* LATIN SMALL LETTER K WITH CARON -> 'k' */
+ { 0xEA, 0x4F }, /* LATIN CAPITAL LETTER O WITH OGONEK -> 'O' */
+ { 0xEB, 0x6F }, /* LATIN SMALL LETTER O WITH OGONEK -> 'o' */
+ { 0xEC, 0x4F }, /* LATIN CAPITAL LETTER O WITH OGONEK AND MACRON -> 'O' */
+ { 0xED, 0x6F }, /* LATIN SMALL LETTER O WITH OGONEK AND MACRON -> 'o' */
+ { 0xF0, 0x6A }, /* LATIN SMALL LETTER J WITH CARON -> 'j' */
+ { 0xF4, 0x47 }, /* LATIN CAPITAL LETTER G WITH ACUTE -> 'G' */
+ { 0xF5, 0x67 }, /* LATIN SMALL LETTER G WITH ACUTE -> 'g' */
+ { 0xF7, 0x57 }, /* LATIN CAPITAL LETTER WYNN -> 'W' */
+ { 0xF8, 0x4E }, /* LATIN CAPITAL LETTER N WITH GRAVE -> 'N' */
+ { 0xF9, 0x6E }, /* LATIN SMALL LETTER N WITH GRAVE -> 'n' */
+ { 0xFA, 0x41 }, /* LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE -> 'A' */
+ { 0xFB, 0x61 }, /* LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE -> 'a' */
+ { 0xFE, 0x4F }, /* LATIN CAPITAL LETTER O WITH STROKE AND ACUTE -> 'O' */
+ { 0xFF, 0x6F }, /* LATIN SMALL LETTER O WITH STROKE AND ACUTE -> 'o' */
+ /* Entries for page 0x02 */
+ { 0x00, 0x41 }, /* LATIN CAPITAL LETTER A WITH DOUBLE GRAVE -> 'A' */
+ { 0x01, 0x61 }, /* LATIN SMALL LETTER A WITH DOUBLE GRAVE -> 'a' */
+ { 0x02, 0x41 }, /* LATIN CAPITAL LETTER A WITH INVERTED BREVE -> 'A' */
+ { 0x03, 0x61 }, /* LATIN SMALL LETTER A WITH INVERTED BREVE -> 'a' */
+ { 0x04, 0x45 }, /* LATIN CAPITAL LETTER E WITH DOUBLE GRAVE -> 'E' */
+ { 0x05, 0x65 }, /* LATIN SMALL LETTER E WITH DOUBLE GRAVE -> 'e' */
+ { 0x06, 0x45 }, /* LATIN CAPITAL LETTER E WITH INVERTED BREVE -> 'E' */
+ { 0x07, 0x65 }, /* LATIN SMALL LETTER E WITH INVERTED BREVE -> 'e' */
+ { 0x08, 0x49 }, /* LATIN CAPITAL LETTER I WITH DOUBLE GRAVE -> 'I' */
+ { 0x09, 0x69 }, /* LATIN SMALL LETTER I WITH DOUBLE GRAVE -> 'i' */
+ { 0x0A, 0x49 }, /* LATIN CAPITAL LETTER I WITH INVERTED BREVE -> 'I' */
+ { 0x0B, 0x69 }, /* LATIN SMALL LETTER I WITH INVERTED BREVE -> 'i' */
+ { 0x0C, 0x4F }, /* LATIN CAPITAL LETTER O WITH DOUBLE GRAVE -> 'O' */
+ { 0x0D, 0x6F }, /* LATIN SMALL LETTER O WITH DOUBLE GRAVE -> 'o' */
+ { 0x0E, 0x4F }, /* LATIN CAPITAL LETTER O WITH INVERTED BREVE -> 'O' */
+ { 0x0F, 0x6F }, /* LATIN SMALL LETTER O WITH INVERTED BREVE -> 'o' */
+ { 0x10, 0x52 }, /* LATIN CAPITAL LETTER R WITH DOUBLE GRAVE -> 'R' */
+ { 0x11, 0x72 }, /* LATIN SMALL LETTER R WITH DOUBLE GRAVE -> 'r' */
+ { 0x12, 0x52 }, /* LATIN CAPITAL LETTER R WITH INVERTED BREVE -> 'R' */
+ { 0x13, 0x72 }, /* LATIN SMALL LETTER R WITH INVERTED BREVE -> 'r' */
+ { 0x14, 0x55 }, /* LATIN CAPITAL LETTER U WITH DOUBLE GRAVE -> 'U' */
+ { 0x15, 0x75 }, /* LATIN SMALL LETTER U WITH DOUBLE GRAVE -> 'u' */
+ { 0x16, 0x55 }, /* LATIN CAPITAL LETTER U WITH INVERTED BREVE -> 'U' */
+ { 0x17, 0x75 }, /* LATIN SMALL LETTER U WITH INVERTED BREVE -> 'u' */
+ { 0x18, 0x53 }, /* LATIN CAPITAL LETTER S WITH COMMA BELOW -> 'S' */
+ { 0x19, 0x73 }, /* LATIN SMALL LETTER S WITH COMMA BELOW -> 's' */
+ { 0x1A, 0x54 }, /* LATIN CAPITAL LETTER T WITH COMMA BELOW -> 'T' */
+ { 0x1B, 0x74 }, /* LATIN SMALL LETTER T WITH COMMA BELOW -> 't' */
+ { 0x1C, 0x59 }, /* LATIN CAPITAL LETTER YOGH -> 'Y' */
+ { 0x1D, 0x79 }, /* LATIN SMALL LETTER YOGH -> 'y' */
+ { 0x1E, 0x48 }, /* LATIN CAPITAL LETTER H WITH CARON -> 'H' */
+ { 0x1F, 0x68 }, /* LATIN SMALL LETTER H WITH CARON -> 'h' */
+ { 0x20, 0x4E }, /* LATIN CAPITAL LETTER N WITH LONG RIGHT LEG -> 'N' */
+ { 0x21, 0x64 }, /* LATIN SMALL LETTER D WITH CURL -> 'd' */
+ { 0x24, 0x5A }, /* LATIN CAPITAL LETTER Z WITH HOOK -> 'Z' */
+ { 0x25, 0x7A }, /* LATIN SMALL LETTER Z WITH HOOK -> 'z' */
+ { 0x26, 0x41 }, /* LATIN CAPITAL LETTER A WITH DOT ABOVE -> 'A' */
+ { 0x27, 0x61 }, /* LATIN SMALL LETTER A WITH DOT ABOVE -> 'a' */
+ { 0x28, 0x45 }, /* LATIN CAPITAL LETTER E WITH CEDILLA -> 'E' */
+ { 0x29, 0x65 }, /* LATIN SMALL LETTER E WITH CEDILLA -> 'e' */
+ { 0x2A, 0x4F }, /* LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON -> 'O' */
+ { 0x2B, 0x6F }, /* LATIN SMALL LETTER O WITH DIAERESIS AND MACRON -> 'o' */
+ { 0x2C, 0x4F }, /* LATIN CAPITAL LETTER O WITH TILDE AND MACRON -> 'O' */
+ { 0x2D, 0x6F }, /* LATIN SMALL LETTER O WITH TILDE AND MACRON -> 'o' */
+ { 0x2E, 0x4F }, /* LATIN CAPITAL LETTER O WITH DOT ABOVE -> 'O' */
+ { 0x2F, 0x6F }, /* LATIN SMALL LETTER O WITH DOT ABOVE -> 'o' */
+ { 0x30, 0x4F }, /* LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON -> 'O' */
+ { 0x31, 0x6F }, /* LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON -> 'o' */
+ { 0x32, 0x59 }, /* LATIN CAPITAL LETTER Y WITH MACRON -> 'Y' */
+ { 0x33, 0x79 }, /* LATIN SMALL LETTER Y WITH MACRON -> 'y' */
+ { 0x34, 0x6C }, /* LATIN SMALL LETTER L WITH CURL -> 'l' */
+ { 0x35, 0x6E }, /* LATIN SMALL LETTER N WITH CURL -> 'n' */
+ { 0x36, 0x74 }, /* LATIN SMALL LETTER T WITH CURL -> 't' */
+ { 0x37, 0x6A }, /* LATIN SMALL LETTER DOTLESS J -> 'j' */
+ { 0x3A, 0x41 }, /* LATIN CAPITAL LETTER A WITH STROKE -> 'A' */
+ { 0x3B, 0x43 }, /* LATIN CAPITAL LETTER C WITH STROKE -> 'C' */
+ { 0x3C, 0x63 }, /* LATIN SMALL LETTER C WITH STROKE -> 'c' */
+ { 0x3D, 0x4C }, /* LATIN CAPITAL LETTER L WITH BAR -> 'L' */
+ { 0x3E, 0x54 }, /* LATIN CAPITAL LETTER T WITH DIAGONAL STROKE -> 'T' */
+ { 0x3F, 0x73 }, /* LATIN SMALL LETTER S WITH SWASH TAIL -> 's' */
+ { 0x40, 0x7A }, /* LATIN SMALL LETTER Z WITH SWASH TAIL -> 'z' */
+ { 0x43, 0x42 }, /* LATIN CAPITAL LETTER B WITH STROKE -> 'B' */
+ { 0x44, 0x55 }, /* LATIN CAPITAL LETTER U BAR -> 'U' */
+ { 0x45, 0x5E }, /* LATIN CAPITAL LETTER TURNED V -> '^' */
+ { 0x46, 0x45 }, /* LATIN CAPITAL LETTER E WITH STROKE -> 'E' */
+ { 0x47, 0x65 }, /* LATIN SMALL LETTER E WITH STROKE -> 'e' */
+ { 0x48, 0x4A }, /* LATIN CAPITAL LETTER J WITH STROKE -> 'J' */
+ { 0x49, 0x6A }, /* LATIN SMALL LETTER J WITH STROKE -> 'j' */
+ { 0x4A, 0x71 }, /* LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL -> 'q' */
+ { 0x4B, 0x71 }, /* LATIN SMALL LETTER Q WITH HOOK TAIL -> 'q' */
+ { 0x4C, 0x52 }, /* LATIN CAPITAL LETTER R WITH STROKE -> 'R' */
+ { 0x4D, 0x72 }, /* LATIN SMALL LETTER R WITH STROKE -> 'r' */
+ { 0x4E, 0x59 }, /* LATIN CAPITAL LETTER Y WITH STROKE -> 'Y' */
+ { 0x4F, 0x79 }, /* LATIN SMALL LETTER Y WITH STROKE -> 'y' */
+ { 0x50, 0x00 }, /* LATIN SMALL LETTER TURNED A -> ... */
+ { 0x52, 0x61 }, /* LATIN SMALL LETTER TURNED ALPHA -> 'a' */
+ { 0x53, 0x62 }, /* LATIN SMALL LETTER B WITH HOOK -> 'b' */
+ { 0x54, 0x6F }, /* LATIN SMALL LETTER OPEN O -> 'o' */
+ { 0x55, 0x63 }, /* LATIN SMALL LETTER C WITH CURL -> 'c' */
+ { 0x56, 0x64 }, /* LATIN SMALL LETTER D WITH TAIL -> 'd' */
+ { 0x57, 0x64 }, /* LATIN SMALL LETTER D WITH HOOK -> 'd' */
+ { 0x58, 0x65 }, /* LATIN SMALL LETTER REVERSED E -> 'e' */
+ { 0x59, 0x40 }, /* LATIN SMALL LETTER SCHWA -> '@' */
+ { 0x5A, 0x40 }, /* LATIN SMALL LETTER SCHWA WITH HOOK -> '@' */
+ { 0x5B, 0x00 }, /* LATIN SMALL LETTER OPEN E -> ... */
+ { 0x5E, 0x65 }, /* LATIN SMALL LETTER CLOSED REVERSED OPEN E -> 'e' */
+ { 0x5F, 0x6A }, /* LATIN SMALL LETTER DOTLESS J WITH STROKE -> 'j' */
+ { 0x60, 0x00 }, /* LATIN SMALL LETTER G WITH HOOK -> ... */
+ { 0x63, 0x67 }, /* LATIN SMALL LETTER GAMMA -> 'g' */
+ { 0x64, 0x75 }, /* LATIN SMALL LETTER RAMS HORN -> 'u' */
+ { 0x65, 0x59 }, /* LATIN SMALL LETTER TURNED H -> 'Y' */
+ { 0x66, 0x68 }, /* LATIN SMALL LETTER H WITH HOOK -> 'h' */
+ { 0x67, 0x68 }, /* LATIN SMALL LETTER HENG WITH HOOK -> 'h' */
+ { 0x68, 0x69 }, /* LATIN SMALL LETTER I WITH STROKE -> 'i' */
+ { 0x69, 0x69 }, /* LATIN SMALL LETTER IOTA -> 'i' */
+ { 0x6A, 0x49 }, /* LATIN LETTER SMALL CAPITAL I -> 'I' */
+ { 0x6B, 0x00 }, /* LATIN SMALL LETTER L WITH MIDDLE TILDE -> ... */
+ { 0x6D, 0x6C }, /* LATIN SMALL LETTER L WITH RETROFLEX HOOK -> 'l' */
+ { 0x6F, 0x57 }, /* LATIN SMALL LETTER TURNED M -> 'W' */
+ { 0x70, 0x57 }, /* LATIN SMALL LETTER TURNED M WITH LONG LEG -> 'W' */
+ { 0x71, 0x6D }, /* LATIN SMALL LETTER M WITH HOOK -> 'm' */
+ { 0x72, 0x00 }, /* LATIN SMALL LETTER N WITH LEFT HOOK -> ... */
+ { 0x74, 0x6E }, /* LATIN LETTER SMALL CAPITAL N -> 'n' */
+ { 0x75, 0x6F }, /* LATIN SMALL LETTER BARRED O -> 'o' */
+ { 0x77, 0x4F }, /* LATIN SMALL LETTER CLOSED OMEGA -> 'O' */
+ { 0x78, 0x46 }, /* LATIN SMALL LETTER PHI -> 'F' */
+ { 0x79, 0x00 }, /* LATIN SMALL LETTER TURNED R -> ... */
+ { 0x7F, 0x72 }, /* LATIN SMALL LETTER REVERSED R WITH FISHHOOK -> 'r' */
+ { 0x80, 0x52 }, /* LATIN LETTER SMALL CAPITAL R -> 'R' */
+ { 0x81, 0x52 }, /* LATIN LETTER SMALL CAPITAL INVERTED R -> 'R' */
+ { 0x82, 0x73 }, /* LATIN SMALL LETTER S WITH HOOK -> 's' */
+ { 0x83, 0x53 }, /* LATIN SMALL LETTER ESH -> 'S' */
+ { 0x84, 0x6A }, /* LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK -> 'j' */
+ { 0x85, 0x53 }, /* LATIN SMALL LETTER SQUAT REVERSED ESH -> 'S' */
+ { 0x86, 0x53 }, /* LATIN SMALL LETTER ESH WITH CURL -> 'S' */
+ { 0x87, 0x74 }, /* LATIN SMALL LETTER TURNED T -> 't' */
+ { 0x88, 0x74 }, /* LATIN SMALL LETTER T WITH RETROFLEX HOOK -> 't' */
+ { 0x89, 0x75 }, /* LATIN SMALL LETTER U BAR -> 'u' */
+ { 0x8A, 0x55 }, /* LATIN SMALL LETTER UPSILON -> 'U' */
+ { 0x8B, 0x76 }, /* LATIN SMALL LETTER V WITH HOOK -> 'v' */
+ { 0x8C, 0x5E }, /* LATIN SMALL LETTER TURNED V -> '^' */
+ { 0x8D, 0x77 }, /* LATIN SMALL LETTER TURNED W -> 'w' */
+ { 0x8E, 0x79 }, /* LATIN SMALL LETTER TURNED Y -> 'y' */
+ { 0x8F, 0x59 }, /* LATIN LETTER SMALL CAPITAL Y -> 'Y' */
+ { 0x90, 0x7A }, /* LATIN SMALL LETTER Z WITH RETROFLEX HOOK -> 'z' */
+ { 0x91, 0x7A }, /* LATIN SMALL LETTER Z WITH CURL -> 'z' */
+ { 0x92, 0x5A }, /* LATIN SMALL LETTER EZH -> 'Z' */
+ { 0x93, 0x5A }, /* LATIN SMALL LETTER EZH WITH CURL -> 'Z' */
+ { 0x94, 0x00 }, /* LATIN LETTER GLOTTAL STOP -> ... */
+ { 0x96, 0x3F }, /* LATIN LETTER INVERTED GLOTTAL STOP -> '?' */
+ { 0x97, 0x43 }, /* LATIN LETTER STRETCHED C -> 'C' */
+ { 0x98, 0x40 }, /* LATIN LETTER BILABIAL CLICK -> '@' */
+ { 0x99, 0x42 }, /* LATIN LETTER SMALL CAPITAL B -> 'B' */
+ { 0x9A, 0x45 }, /* LATIN SMALL LETTER CLOSED OPEN E -> 'E' */
+ { 0x9B, 0x47 }, /* LATIN LETTER SMALL CAPITAL G WITH HOOK -> 'G' */
+ { 0x9C, 0x48 }, /* LATIN LETTER SMALL CAPITAL H -> 'H' */
+ { 0x9D, 0x6A }, /* LATIN SMALL LETTER J WITH CROSSED-TAIL -> 'j' */
+ { 0x9E, 0x6B }, /* LATIN SMALL LETTER TURNED K -> 'k' */
+ { 0x9F, 0x4C }, /* LATIN LETTER SMALL CAPITAL L -> 'L' */
+ { 0xA0, 0x71 }, /* LATIN SMALL LETTER Q WITH HOOK -> 'q' */
+ { 0xA1, 0x3F }, /* LATIN LETTER GLOTTAL STOP WITH STROKE -> '?' */
+ { 0xA2, 0x3F }, /* LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE -> '?' */
+ { 0xAE, 0x00 }, /* LATIN SMALL LETTER TURNED H WITH FISHHOOK -> ... */
+ { 0xB1, 0x68 }, /* MODIFIER LETTER SMALL H WITH HOOK -> 'h' */
+ { 0xB2, 0x6A }, /* MODIFIER LETTER SMALL J -> 'j' */
+ { 0xB3, 0x00 }, /* MODIFIER LETTER SMALL R -> ... */
+ { 0xB6, 0x72 }, /* MODIFIER LETTER SMALL CAPITAL INVERTED R -> 'r' */
+ { 0xB7, 0x77 }, /* MODIFIER LETTER SMALL W -> 'w' */
+ { 0xB8, 0x79 }, /* MODIFIER LETTER SMALL Y -> 'y' */
+ { 0xB9, 0x27 }, /* MODIFIER LETTER PRIME -> ''' */
+ { 0xBA, 0x22 }, /* MODIFIER LETTER DOUBLE PRIME -> '"' */
+ { 0xBB, 0x60 }, /* MODIFIER LETTER TURNED COMMA -> '`' */
+ { 0xBC, 0x27 }, /* MODIFIER LETTER APOSTROPHE -> ''' */
+ { 0xBD, 0x60 }, /* MODIFIER LETTER REVERSED COMMA -> '`' */
+ { 0xBE, 0x60 }, /* MODIFIER LETTER RIGHT HALF RING -> '`' */
+ { 0xBF, 0x27 }, /* MODIFIER LETTER LEFT HALF RING -> ''' */
+ { 0xC0, 0x3F }, /* MODIFIER LETTER GLOTTAL STOP -> '?' */
+ { 0xC1, 0x3F }, /* MODIFIER LETTER REVERSED GLOTTAL STOP -> '?' */
+ { 0xC2, 0x3C }, /* MODIFIER LETTER LEFT ARROWHEAD -> '<' */
+ { 0xC3, 0x3E }, /* MODIFIER LETTER RIGHT ARROWHEAD -> '>' */
+ { 0xC4, 0x5E }, /* MODIFIER LETTER UP ARROWHEAD -> '^' */
+ { 0xC5, 0x56 }, /* MODIFIER LETTER DOWN ARROWHEAD -> 'V' */
+ { 0xC6, 0x5E }, /* MODIFIER LETTER CIRCUMFLEX ACCENT -> '^' */
+ { 0xC7, 0x56 }, /* CARON -> 'V' */
+ { 0xC8, 0x27 }, /* MODIFIER LETTER VERTICAL LINE -> ''' */
+ { 0xC9, 0x2D }, /* MODIFIER LETTER MACRON -> '-' */
+ { 0xCA, 0x2F }, /* MODIFIER LETTER ACUTE ACCENT -> '/' */
+ { 0xCB, 0x5C }, /* MODIFIER LETTER GRAVE ACCENT -> '\' */
+ { 0xCC, 0x2C }, /* MODIFIER LETTER LOW VERTICAL LINE -> ',' */
+ { 0xCD, 0x5F }, /* MODIFIER LETTER LOW MACRON -> '_' */
+ { 0xCE, 0x5C }, /* MODIFIER LETTER LOW GRAVE ACCENT -> '\' */
+ { 0xCF, 0x2F }, /* MODIFIER LETTER LOW ACUTE ACCENT -> '/' */
+ { 0xD0, 0x3A }, /* MODIFIER LETTER TRIANGULAR COLON -> ':' */
+ { 0xD1, 0x2E }, /* MODIFIER LETTER HALF TRIANGULAR COLON -> '.' */
+ { 0xD2, 0x60 }, /* MODIFIER LETTER CENTRED RIGHT HALF RING -> '`' */
+ { 0xD3, 0x27 }, /* MODIFIER LETTER CENTRED LEFT HALF RING -> ''' */
+ { 0xD4, 0x5E }, /* MODIFIER LETTER UP TACK -> '^' */
+ { 0xD5, 0x56 }, /* MODIFIER LETTER DOWN TACK -> 'V' */
+ { 0xD6, 0x2B }, /* MODIFIER LETTER PLUS SIGN -> '+' */
+ { 0xD7, 0x2D }, /* MODIFIER LETTER MINUS SIGN -> '-' */
+ { 0xD8, 0x56 }, /* BREVE -> 'V' */
+ { 0xD9, 0x2E }, /* DOT ABOVE -> '.' */
+ { 0xDA, 0x40 }, /* RING ABOVE -> '@' */
+ { 0xDB, 0x2C }, /* OGONEK -> ',' */
+ { 0xDC, 0x7E }, /* SMALL TILDE -> '~' */
+ { 0xDD, 0x22 }, /* DOUBLE ACUTE ACCENT -> '"' */
+ { 0xDE, 0x52 }, /* MODIFIER LETTER RHOTIC HOOK -> 'R' */
+ { 0xDF, 0x58 }, /* MODIFIER LETTER CROSS ACCENT -> 'X' */
+ { 0xE0, 0x47 }, /* MODIFIER LETTER SMALL GAMMA -> 'G' */
+ { 0xE1, 0x6C }, /* MODIFIER LETTER SMALL L -> 'l' */
+ { 0xE2, 0x73 }, /* MODIFIER LETTER SMALL S -> 's' */
+ { 0xE3, 0x78 }, /* MODIFIER LETTER SMALL X -> 'x' */
+ { 0xE4, 0x3F }, /* MODIFIER LETTER SMALL REVERSED GLOTTAL STOP -> '?' */
+ { 0xEC, 0x56 }, /* MODIFIER LETTER VOICING -> 'V' */
+ { 0xED, 0x3D }, /* MODIFIER LETTER UNASPIRATED -> '=' */
+ { 0xEE, 0x22 }, /* MODIFIER LETTER DOUBLE APOSTROPHE -> '"' */
+ /* Entries for page 0x03 */
+ { 0x63, 0x61 }, /* COMBINING LATIN SMALL LETTER A -> 'a' */
+ { 0x64, 0x65 }, /* COMBINING LATIN SMALL LETTER E -> 'e' */
+ { 0x65, 0x69 }, /* COMBINING LATIN SMALL LETTER I -> 'i' */
+ { 0x66, 0x6F }, /* COMBINING LATIN SMALL LETTER O -> 'o' */
+ { 0x67, 0x75 }, /* COMBINING LATIN SMALL LETTER U -> 'u' */
+ { 0x68, 0x63 }, /* COMBINING LATIN SMALL LETTER C -> 'c' */
+ { 0x69, 0x64 }, /* COMBINING LATIN SMALL LETTER D -> 'd' */
+ { 0x6A, 0x68 }, /* COMBINING LATIN SMALL LETTER H -> 'h' */
+ { 0x6B, 0x6D }, /* COMBINING LATIN SMALL LETTER M -> 'm' */
+ { 0x6C, 0x72 }, /* COMBINING LATIN SMALL LETTER R -> 'r' */
+ { 0x6D, 0x74 }, /* COMBINING LATIN SMALL LETTER T -> 't' */
+ { 0x6E, 0x76 }, /* COMBINING LATIN SMALL LETTER V -> 'v' */
+ { 0x6F, 0x78 }, /* COMBINING LATIN SMALL LETTER X -> 'x' */
+ { 0x74, 0x27 }, /* GREEK NUMERAL SIGN -> ''' */
+ { 0x75, 0x2C }, /* GREEK LOWER NUMERAL SIGN -> ',' */
+ { 0x7E, 0x3F }, /* GREEK QUESTION MARK -> '?' */
+ { 0x86, 0x41 }, /* GREEK CAPITAL LETTER ALPHA WITH TONOS -> 'A' */
+ { 0x87, 0x3B }, /* GREEK ANO TELEIA -> ';' */
+ { 0x88, 0x45 }, /* GREEK CAPITAL LETTER EPSILON WITH TONOS -> 'E' */
+ { 0x89, 0x45 }, /* GREEK CAPITAL LETTER ETA WITH TONOS -> 'E' */
+ { 0x8A, 0x49 }, /* GREEK CAPITAL LETTER IOTA WITH TONOS -> 'I' */
+ { 0x8C, 0x4F }, /* GREEK CAPITAL LETTER OMICRON WITH TONOS -> 'O' */
+ { 0x8E, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH TONOS -> 'U' */
+ { 0x8F, 0x4F }, /* GREEK CAPITAL LETTER OMEGA WITH TONOS -> 'O' */
+ { 0x90, 0x49 }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS -> 'I' */
+ { 0x91, 0x41 }, /* GREEK CAPITAL LETTER ALPHA -> 'A' */
+ { 0x92, 0x42 }, /* GREEK CAPITAL LETTER BETA -> 'B' */
+ { 0x93, 0x47 }, /* GREEK CAPITAL LETTER GAMMA -> 'G' */
+ { 0x94, 0x44 }, /* GREEK CAPITAL LETTER DELTA -> 'D' */
+ { 0x95, 0x45 }, /* GREEK CAPITAL LETTER EPSILON -> 'E' */
+ { 0x96, 0x5A }, /* GREEK CAPITAL LETTER ZETA -> 'Z' */
+ { 0x97, 0x45 }, /* GREEK CAPITAL LETTER ETA -> 'E' */
+ { 0x99, 0x49 }, /* GREEK CAPITAL LETTER IOTA -> 'I' */
+ { 0x9A, 0x4B }, /* GREEK CAPITAL LETTER KAPPA -> 'K' */
+ { 0x9B, 0x4C }, /* GREEK CAPITAL LETTER LAMDA -> 'L' */
+ { 0x9C, 0x4D }, /* GREEK CAPITAL LETTER MU -> 'M' */
+ { 0x9D, 0x4E }, /* GREEK CAPITAL LETTER NU -> 'N' */
+ { 0x9F, 0x4F }, /* GREEK CAPITAL LETTER OMICRON -> 'O' */
+ { 0xA0, 0x50 }, /* GREEK CAPITAL LETTER PI -> 'P' */
+ { 0xA1, 0x52 }, /* GREEK CAPITAL LETTER RHO -> 'R' */
+ { 0xA3, 0x53 }, /* GREEK CAPITAL LETTER SIGMA -> 'S' */
+ { 0xA4, 0x54 }, /* GREEK CAPITAL LETTER TAU -> 'T' */
+ { 0xA5, 0x55 }, /* GREEK CAPITAL LETTER UPSILON -> 'U' */
+ { 0xA9, 0x4F }, /* GREEK CAPITAL LETTER OMEGA -> 'O' */
+ { 0xAA, 0x49 }, /* GREEK CAPITAL LETTER IOTA WITH DIALYTIKA -> 'I' */
+ { 0xAB, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA -> 'U' */
+ { 0xAC, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH TONOS -> 'a' */
+ { 0xAD, 0x65 }, /* GREEK SMALL LETTER EPSILON WITH TONOS -> 'e' */
+ { 0xAE, 0x65 }, /* GREEK SMALL LETTER ETA WITH TONOS -> 'e' */
+ { 0xAF, 0x69 }, /* GREEK SMALL LETTER IOTA WITH TONOS -> 'i' */
+ { 0xB0, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS -> 'u' */
+ { 0xB1, 0x61 }, /* GREEK SMALL LETTER ALPHA -> 'a' */
+ { 0xB2, 0x62 }, /* GREEK SMALL LETTER BETA -> 'b' */
+ { 0xB3, 0x67 }, /* GREEK SMALL LETTER GAMMA -> 'g' */
+ { 0xB4, 0x64 }, /* GREEK SMALL LETTER DELTA -> 'd' */
+ { 0xB5, 0x65 }, /* GREEK SMALL LETTER EPSILON -> 'e' */
+ { 0xB6, 0x7A }, /* GREEK SMALL LETTER ZETA -> 'z' */
+ { 0xB7, 0x65 }, /* GREEK SMALL LETTER ETA -> 'e' */
+ { 0xB9, 0x69 }, /* GREEK SMALL LETTER IOTA -> 'i' */
+ { 0xBA, 0x6B }, /* GREEK SMALL LETTER KAPPA -> 'k' */
+ { 0xBB, 0x6C }, /* GREEK SMALL LETTER LAMDA -> 'l' */
+ { 0xBC, 0x6D }, /* GREEK SMALL LETTER MU -> 'm' */
+ { 0xBD, 0x6E }, /* GREEK SMALL LETTER NU -> 'n' */
+ { 0xBE, 0x78 }, /* GREEK SMALL LETTER XI -> 'x' */
+ { 0xBF, 0x6F }, /* GREEK SMALL LETTER OMICRON -> 'o' */
+ { 0xC0, 0x70 }, /* GREEK SMALL LETTER PI -> 'p' */
+ { 0xC1, 0x72 }, /* GREEK SMALL LETTER RHO -> 'r' */
+ { 0xC2, 0x73 }, /* GREEK SMALL LETTER FINAL SIGMA -> 's' */
+ { 0xC3, 0x73 }, /* GREEK SMALL LETTER SIGMA -> 's' */
+ { 0xC4, 0x74 }, /* GREEK SMALL LETTER TAU -> 't' */
+ { 0xC5, 0x75 }, /* GREEK SMALL LETTER UPSILON -> 'u' */
+ { 0xC9, 0x6F }, /* GREEK SMALL LETTER OMEGA -> 'o' */
+ { 0xCA, 0x69 }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA -> 'i' */
+ { 0xCB, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA -> 'u' */
+ { 0xCC, 0x6F }, /* GREEK SMALL LETTER OMICRON WITH TONOS -> 'o' */
+ { 0xCD, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH TONOS -> 'u' */
+ { 0xCE, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH TONOS -> 'o' */
+ { 0xD0, 0x62 }, /* GREEK BETA SYMBOL -> 'b' */
+ { 0xD2, 0x00 }, /* GREEK UPSILON WITH HOOK SYMBOL -> ... */
+ { 0xD4, 0x55 }, /* GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL -> 'U' */
+ { 0xD6, 0x70 }, /* GREEK PI SYMBOL -> 'p' */
+ { 0xD7, 0x26 }, /* GREEK KAI SYMBOL -> '&' */
+ { 0xDC, 0x57 }, /* GREEK LETTER DIGAMMA -> 'W' */
+ { 0xDD, 0x77 }, /* GREEK SMALL LETTER DIGAMMA -> 'w' */
+ { 0xDE, 0x51 }, /* GREEK LETTER KOPPA -> 'Q' */
+ { 0xDF, 0x71 }, /* GREEK SMALL LETTER KOPPA -> 'q' */
+ { 0xE4, 0x46 }, /* COPTIC CAPITAL LETTER FEI -> 'F' */
+ { 0xE5, 0x66 }, /* COPTIC SMALL LETTER FEI -> 'f' */
+ { 0xE8, 0x48 }, /* COPTIC CAPITAL LETTER HORI -> 'H' */
+ { 0xE9, 0x68 }, /* COPTIC SMALL LETTER HORI -> 'h' */
+ { 0xEA, 0x47 }, /* COPTIC CAPITAL LETTER GANGIA -> 'G' */
+ { 0xEB, 0x67 }, /* COPTIC SMALL LETTER GANGIA -> 'g' */
+ { 0xF0, 0x6B }, /* GREEK KAPPA SYMBOL -> 'k' */
+ { 0xF1, 0x72 }, /* GREEK RHO SYMBOL -> 'r' */
+ { 0xF2, 0x63 }, /* GREEK LUNATE SIGMA SYMBOL -> 'c' */
+ { 0xF3, 0x6A }, /* GREEK LETTER YOT -> 'j' */
+ /* Entries for page 0x04 */
+ { 0x06, 0x49 }, /* CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I -> 'I' */
+ { 0x08, 0x4A }, /* CYRILLIC CAPITAL LETTER JE -> 'J' */
+ { 0x0D, 0x49 }, /* CYRILLIC CAPITAL LETTER I WITH GRAVE -> 'I' */
+ { 0x0E, 0x55 }, /* CYRILLIC CAPITAL LETTER SHORT U -> 'U' */
+ { 0x10, 0x41 }, /* CYRILLIC CAPITAL LETTER A -> 'A' */
+ { 0x11, 0x42 }, /* CYRILLIC CAPITAL LETTER BE -> 'B' */
+ { 0x12, 0x56 }, /* CYRILLIC CAPITAL LETTER VE -> 'V' */
+ { 0x13, 0x47 }, /* CYRILLIC CAPITAL LETTER GHE -> 'G' */
+ { 0x14, 0x44 }, /* CYRILLIC CAPITAL LETTER DE -> 'D' */
+ { 0x15, 0x45 }, /* CYRILLIC CAPITAL LETTER IE -> 'E' */
+ { 0x17, 0x5A }, /* CYRILLIC CAPITAL LETTER ZE -> 'Z' */
+ { 0x18, 0x49 }, /* CYRILLIC CAPITAL LETTER I -> 'I' */
+ { 0x19, 0x49 }, /* CYRILLIC CAPITAL LETTER SHORT I -> 'I' */
+ { 0x1A, 0x4B }, /* CYRILLIC CAPITAL LETTER KA -> 'K' */
+ { 0x1B, 0x4C }, /* CYRILLIC CAPITAL LETTER EL -> 'L' */
+ { 0x1C, 0x4D }, /* CYRILLIC CAPITAL LETTER EM -> 'M' */
+ { 0x1D, 0x4E }, /* CYRILLIC CAPITAL LETTER EN -> 'N' */
+ { 0x1E, 0x4F }, /* CYRILLIC CAPITAL LETTER O -> 'O' */
+ { 0x1F, 0x50 }, /* CYRILLIC CAPITAL LETTER PE -> 'P' */
+ { 0x20, 0x52 }, /* CYRILLIC CAPITAL LETTER ER -> 'R' */
+ { 0x21, 0x53 }, /* CYRILLIC CAPITAL LETTER ES -> 'S' */
+ { 0x22, 0x54 }, /* CYRILLIC CAPITAL LETTER TE -> 'T' */
+ { 0x23, 0x55 }, /* CYRILLIC CAPITAL LETTER U -> 'U' */
+ { 0x24, 0x46 }, /* CYRILLIC CAPITAL LETTER EF -> 'F' */
+ { 0x2A, 0x27 }, /* CYRILLIC CAPITAL LETTER HARD SIGN -> ''' */
+ { 0x2B, 0x59 }, /* CYRILLIC CAPITAL LETTER YERU -> 'Y' */
+ { 0x2C, 0x27 }, /* CYRILLIC CAPITAL LETTER SOFT SIGN -> ''' */
+ { 0x2D, 0x45 }, /* CYRILLIC CAPITAL LETTER E -> 'E' */
+ { 0x30, 0x61 }, /* CYRILLIC SMALL LETTER A -> 'a' */
+ { 0x31, 0x62 }, /* CYRILLIC SMALL LETTER BE -> 'b' */
+ { 0x32, 0x76 }, /* CYRILLIC SMALL LETTER VE -> 'v' */
+ { 0x33, 0x67 }, /* CYRILLIC SMALL LETTER GHE -> 'g' */
+ { 0x34, 0x64 }, /* CYRILLIC SMALL LETTER DE -> 'd' */
+ { 0x35, 0x65 }, /* CYRILLIC SMALL LETTER IE -> 'e' */
+ { 0x37, 0x7A }, /* CYRILLIC SMALL LETTER ZE -> 'z' */
+ { 0x38, 0x69 }, /* CYRILLIC SMALL LETTER I -> 'i' */
+ { 0x39, 0x69 }, /* CYRILLIC SMALL LETTER SHORT I -> 'i' */
+ { 0x3A, 0x6B }, /* CYRILLIC SMALL LETTER KA -> 'k' */
+ { 0x3B, 0x6C }, /* CYRILLIC SMALL LETTER EL -> 'l' */
+ { 0x3C, 0x6D }, /* CYRILLIC SMALL LETTER EM -> 'm' */
+ { 0x3D, 0x6E }, /* CYRILLIC SMALL LETTER EN -> 'n' */
+ { 0x3E, 0x6F }, /* CYRILLIC SMALL LETTER O -> 'o' */
+ { 0x3F, 0x70 }, /* CYRILLIC SMALL LETTER PE -> 'p' */
+ { 0x40, 0x72 }, /* CYRILLIC SMALL LETTER ER -> 'r' */
+ { 0x41, 0x73 }, /* CYRILLIC SMALL LETTER ES -> 's' */
+ { 0x42, 0x74 }, /* CYRILLIC SMALL LETTER TE -> 't' */
+ { 0x43, 0x75 }, /* CYRILLIC SMALL LETTER U -> 'u' */
+ { 0x44, 0x66 }, /* CYRILLIC SMALL LETTER EF -> 'f' */
+ { 0x4A, 0x27 }, /* CYRILLIC SMALL LETTER HARD SIGN -> ''' */
+ { 0x4B, 0x79 }, /* CYRILLIC SMALL LETTER YERU -> 'y' */
+ { 0x4C, 0x27 }, /* CYRILLIC SMALL LETTER SOFT SIGN -> ''' */
+ { 0x4D, 0x65 }, /* CYRILLIC SMALL LETTER E -> 'e' */
+ { 0x56, 0x69 }, /* CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I -> 'i' */
+ { 0x58, 0x6A }, /* CYRILLIC SMALL LETTER JE -> 'j' */
+ { 0x5D, 0x69 }, /* CYRILLIC SMALL LETTER I WITH GRAVE -> 'i' */
+ { 0x5E, 0x75 }, /* CYRILLIC SMALL LETTER SHORT U -> 'u' */
+ { 0x60, 0x4F }, /* CYRILLIC CAPITAL LETTER OMEGA -> 'O' */
+ { 0x61, 0x6F }, /* CYRILLIC SMALL LETTER OMEGA -> 'o' */
+ { 0x62, 0x45 }, /* CYRILLIC CAPITAL LETTER YAT -> 'E' */
+ { 0x63, 0x65 }, /* CYRILLIC SMALL LETTER YAT -> 'e' */
+ { 0x66, 0x45 }, /* CYRILLIC CAPITAL LETTER LITTLE YUS -> 'E' */
+ { 0x67, 0x65 }, /* CYRILLIC SMALL LETTER LITTLE YUS -> 'e' */
+ { 0x6A, 0x4F }, /* CYRILLIC CAPITAL LETTER BIG YUS -> 'O' */
+ { 0x6B, 0x6F }, /* CYRILLIC SMALL LETTER BIG YUS -> 'o' */
+ { 0x72, 0x46 }, /* CYRILLIC CAPITAL LETTER FITA -> 'F' */
+ { 0x73, 0x66 }, /* CYRILLIC SMALL LETTER FITA -> 'f' */
+ { 0x74, 0x59 }, /* CYRILLIC CAPITAL LETTER IZHITSA -> 'Y' */
+ { 0x75, 0x79 }, /* CYRILLIC SMALL LETTER IZHITSA -> 'y' */
+ { 0x76, 0x59 }, /* CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT -> 'Y' */
+ { 0x77, 0x79 }, /* CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT -> 'y' */
+ { 0x78, 0x75 }, /* CYRILLIC CAPITAL LETTER UK -> 'u' */
+ { 0x79, 0x75 }, /* CYRILLIC SMALL LETTER UK -> 'u' */
+ { 0x7A, 0x4F }, /* CYRILLIC CAPITAL LETTER ROUND OMEGA -> 'O' */
+ { 0x7B, 0x6F }, /* CYRILLIC SMALL LETTER ROUND OMEGA -> 'o' */
+ { 0x7C, 0x4F }, /* CYRILLIC CAPITAL LETTER OMEGA WITH TITLO -> 'O' */
+ { 0x7D, 0x6F }, /* CYRILLIC SMALL LETTER OMEGA WITH TITLO -> 'o' */
+ { 0x80, 0x51 }, /* CYRILLIC CAPITAL LETTER KOPPA -> 'Q' */
+ { 0x81, 0x71 }, /* CYRILLIC SMALL LETTER KOPPA -> 'q' */
+ { 0x8C, 0x22 }, /* CYRILLIC CAPITAL LETTER SEMISOFT SIGN -> '"' */
+ { 0x8D, 0x22 }, /* CYRILLIC SMALL LETTER SEMISOFT SIGN -> '"' */
+ { 0xAE, 0x55 }, /* CYRILLIC CAPITAL LETTER STRAIGHT U -> 'U' */
+ { 0xAF, 0x75 }, /* CYRILLIC SMALL LETTER STRAIGHT U -> 'u' */
+ { 0xBA, 0x48 }, /* CYRILLIC CAPITAL LETTER SHHA -> 'H' */
+ { 0xBB, 0x68 }, /* CYRILLIC SMALL LETTER SHHA -> 'h' */
+ { 0xC0, 0x60 }, /* CYRILLIC LETTER PALOCHKA -> '`' */
+ { 0xD0, 0x61 }, /* CYRILLIC CAPITAL LETTER A WITH BREVE -> 'a' */
+ { 0xD1, 0x61 }, /* CYRILLIC SMALL LETTER A WITH BREVE -> 'a' */
+ { 0xD2, 0x41 }, /* CYRILLIC CAPITAL LETTER A WITH DIAERESIS -> 'A' */
+ { 0xD3, 0x61 }, /* CYRILLIC SMALL LETTER A WITH DIAERESIS -> 'a' */
+ { 0xD8, 0x00 }, /* CYRILLIC CAPITAL LETTER SCHWA -> ... */
+ { 0xDB, 0x40 }, /* CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS -> '@' */
+ { 0xDE, 0x5A }, /* CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS -> 'Z' */
+ { 0xDF, 0x7A }, /* CYRILLIC SMALL LETTER ZE WITH DIAERESIS -> 'z' */
+ { 0xE2, 0x49 }, /* CYRILLIC CAPITAL LETTER I WITH MACRON -> 'I' */
+ { 0xE3, 0x69 }, /* CYRILLIC SMALL LETTER I WITH MACRON -> 'i' */
+ { 0xE4, 0x49 }, /* CYRILLIC CAPITAL LETTER I WITH DIAERESIS -> 'I' */
+ { 0xE5, 0x69 }, /* CYRILLIC SMALL LETTER I WITH DIAERESIS -> 'i' */
+ { 0xE6, 0x4F }, /* CYRILLIC CAPITAL LETTER O WITH DIAERESIS -> 'O' */
+ { 0xE7, 0x6F }, /* CYRILLIC SMALL LETTER O WITH DIAERESIS -> 'o' */
+ { 0xE8, 0x4F }, /* CYRILLIC CAPITAL LETTER BARRED O -> 'O' */
+ { 0xE9, 0x6F }, /* CYRILLIC SMALL LETTER BARRED O -> 'o' */
+ { 0xEA, 0x4F }, /* CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS -> 'O' */
+ { 0xEB, 0x6F }, /* CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS -> 'o' */
+ { 0xEC, 0x45 }, /* CYRILLIC CAPITAL LETTER E WITH DIAERESIS -> 'E' */
+ { 0xED, 0x65 }, /* CYRILLIC SMALL LETTER E WITH DIAERESIS -> 'e' */
+ { 0xEE, 0x55 }, /* CYRILLIC CAPITAL LETTER U WITH MACRON -> 'U' */
+ { 0xEF, 0x75 }, /* CYRILLIC SMALL LETTER U WITH MACRON -> 'u' */
+ { 0xF0, 0x55 }, /* CYRILLIC CAPITAL LETTER U WITH DIAERESIS -> 'U' */
+ { 0xF1, 0x75 }, /* CYRILLIC SMALL LETTER U WITH DIAERESIS -> 'u' */
+ { 0xF2, 0x55 }, /* CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE -> 'U' */
+ { 0xF3, 0x75 }, /* CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE -> 'u' */
+ { 0xF8, 0x59 }, /* CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS -> 'Y' */
+ { 0xF9, 0x79 }, /* CYRILLIC SMALL LETTER YERU WITH DIAERESIS -> 'y' */
+ /* Entries for page 0x05 */
+ { 0x31, 0x41 }, /* ARMENIAN CAPITAL LETTER AYB -> 'A' */
+ { 0x32, 0x42 }, /* ARMENIAN CAPITAL LETTER BEN -> 'B' */
+ { 0x33, 0x47 }, /* ARMENIAN CAPITAL LETTER GIM -> 'G' */
+ { 0x34, 0x44 }, /* ARMENIAN CAPITAL LETTER DA -> 'D' */
+ { 0x35, 0x45 }, /* ARMENIAN CAPITAL LETTER ECH -> 'E' */
+ { 0x36, 0x5A }, /* ARMENIAN CAPITAL LETTER ZA -> 'Z' */
+ { 0x37, 0x45 }, /* ARMENIAN CAPITAL LETTER EH -> 'E' */
+ { 0x38, 0x45 }, /* ARMENIAN CAPITAL LETTER ET -> 'E' */
+ { 0x3B, 0x49 }, /* ARMENIAN CAPITAL LETTER INI -> 'I' */
+ { 0x3C, 0x4C }, /* ARMENIAN CAPITAL LETTER LIWN -> 'L' */
+ { 0x3F, 0x4B }, /* ARMENIAN CAPITAL LETTER KEN -> 'K' */
+ { 0x40, 0x48 }, /* ARMENIAN CAPITAL LETTER HO -> 'H' */
+ { 0x44, 0x4D }, /* ARMENIAN CAPITAL LETTER MEN -> 'M' */
+ { 0x45, 0x59 }, /* ARMENIAN CAPITAL LETTER YI -> 'Y' */
+ { 0x46, 0x4E }, /* ARMENIAN CAPITAL LETTER NOW -> 'N' */
+ { 0x48, 0x4F }, /* ARMENIAN CAPITAL LETTER VO -> 'O' */
+ { 0x4A, 0x50 }, /* ARMENIAN CAPITAL LETTER PEH -> 'P' */
+ { 0x4B, 0x4A }, /* ARMENIAN CAPITAL LETTER JHEH -> 'J' */
+ { 0x4D, 0x53 }, /* ARMENIAN CAPITAL LETTER SEH -> 'S' */
+ { 0x4E, 0x56 }, /* ARMENIAN CAPITAL LETTER VEW -> 'V' */
+ { 0x4F, 0x54 }, /* ARMENIAN CAPITAL LETTER TIWN -> 'T' */
+ { 0x50, 0x52 }, /* ARMENIAN CAPITAL LETTER REH -> 'R' */
+ { 0x52, 0x57 }, /* ARMENIAN CAPITAL LETTER YIWN -> 'W' */
+ { 0x55, 0x4F }, /* ARMENIAN CAPITAL LETTER OH -> 'O' */
+ { 0x56, 0x46 }, /* ARMENIAN CAPITAL LETTER FEH -> 'F' */
+ { 0x59, 0x3C }, /* ARMENIAN MODIFIER LETTER LEFT HALF RING -> '<' */
+ { 0x5A, 0x27 }, /* ARMENIAN APOSTROPHE -> ''' */
+ { 0x5B, 0x2F }, /* ARMENIAN EMPHASIS MARK -> '/' */
+ { 0x5C, 0x21 }, /* ARMENIAN EXCLAMATION MARK -> '!' */
+ { 0x5D, 0x2C }, /* ARMENIAN COMMA -> ',' */
+ { 0x5E, 0x3F }, /* ARMENIAN QUESTION MARK -> '?' */
+ { 0x5F, 0x2E }, /* ARMENIAN ABBREVIATION MARK -> '.' */
+ { 0x61, 0x61 }, /* ARMENIAN SMALL LETTER AYB -> 'a' */
+ { 0x62, 0x62 }, /* ARMENIAN SMALL LETTER BEN -> 'b' */
+ { 0x63, 0x67 }, /* ARMENIAN SMALL LETTER GIM -> 'g' */
+ { 0x64, 0x64 }, /* ARMENIAN SMALL LETTER DA -> 'd' */
+ { 0x65, 0x65 }, /* ARMENIAN SMALL LETTER ECH -> 'e' */
+ { 0x66, 0x7A }, /* ARMENIAN SMALL LETTER ZA -> 'z' */
+ { 0x67, 0x65 }, /* ARMENIAN SMALL LETTER EH -> 'e' */
+ { 0x68, 0x65 }, /* ARMENIAN SMALL LETTER ET -> 'e' */
+ { 0x6B, 0x69 }, /* ARMENIAN SMALL LETTER INI -> 'i' */
+ { 0x6C, 0x6C }, /* ARMENIAN SMALL LETTER LIWN -> 'l' */
+ { 0x6F, 0x6B }, /* ARMENIAN SMALL LETTER KEN -> 'k' */
+ { 0x70, 0x68 }, /* ARMENIAN SMALL LETTER HO -> 'h' */
+ { 0x74, 0x6D }, /* ARMENIAN SMALL LETTER MEN -> 'm' */
+ { 0x75, 0x79 }, /* ARMENIAN SMALL LETTER YI -> 'y' */
+ { 0x76, 0x6E }, /* ARMENIAN SMALL LETTER NOW -> 'n' */
+ { 0x78, 0x6F }, /* ARMENIAN SMALL LETTER VO -> 'o' */
+ { 0x7A, 0x70 }, /* ARMENIAN SMALL LETTER PEH -> 'p' */
+ { 0x7B, 0x6A }, /* ARMENIAN SMALL LETTER JHEH -> 'j' */
+ { 0x7D, 0x73 }, /* ARMENIAN SMALL LETTER SEH -> 's' */
+ { 0x7E, 0x76 }, /* ARMENIAN SMALL LETTER VEW -> 'v' */
+ { 0x7F, 0x74 }, /* ARMENIAN SMALL LETTER TIWN -> 't' */
+ { 0x80, 0x72 }, /* ARMENIAN SMALL LETTER REH -> 'r' */
+ { 0x82, 0x77 }, /* ARMENIAN SMALL LETTER YIWN -> 'w' */
+ { 0x85, 0x6F }, /* ARMENIAN SMALL LETTER OH -> 'o' */
+ { 0x86, 0x66 }, /* ARMENIAN SMALL LETTER FEH -> 'f' */
+ { 0x89, 0x3A }, /* ARMENIAN FULL STOP -> ':' */
+ { 0x8A, 0x2D }, /* ARMENIAN HYPHEN -> '-' */
+ { 0xB1, 0x65 }, /* HEBREW POINT HATAF SEGOL -> 'e' */
+ { 0xB2, 0x61 }, /* HEBREW POINT HATAF PATAH -> 'a' */
+ { 0xB3, 0x6F }, /* HEBREW POINT HATAF QAMATS -> 'o' */
+ { 0xB4, 0x69 }, /* HEBREW POINT HIRIQ -> 'i' */
+ { 0xB5, 0x65 }, /* HEBREW POINT TSERE -> 'e' */
+ { 0xB6, 0x65 }, /* HEBREW POINT SEGOL -> 'e' */
+ { 0xB7, 0x61 }, /* HEBREW POINT PATAH -> 'a' */
+ { 0xB8, 0x61 }, /* HEBREW POINT QAMATS -> 'a' */
+ { 0xB9, 0x6F }, /* HEBREW POINT HOLAM -> 'o' */
+ { 0xBA, 0x6F }, /* HEBREW POINT HOLAM HASER FOR VAV -> 'o' */
+ { 0xBB, 0x75 }, /* HEBREW POINT QUBUTS -> 'u' */
+ { 0xBE, 0x2D }, /* HEBREW PUNCTUATION MAQAF -> '-' */
+ { 0xC0, 0x7C }, /* HEBREW PUNCTUATION PASEQ -> '|' */
+ { 0xC3, 0x2E }, /* HEBREW PUNCTUATION SOF PASUQ -> '.' */
+ { 0xC6, 0x6E }, /* HEBREW PUNCTUATION NUN HAFUKHA -> 'n' */
+ { 0xC7, 0x6F }, /* HEBREW POINT QAMATS QATAN -> 'o' */
+ { 0xD0, 0x41 }, /* HEBREW LETTER ALEF -> 'A' */
+ { 0xD1, 0x62 }, /* HEBREW LETTER BET -> 'b' */
+ { 0xD2, 0x67 }, /* HEBREW LETTER GIMEL -> 'g' */
+ { 0xD3, 0x64 }, /* HEBREW LETTER DALET -> 'd' */
+ { 0xD4, 0x68 }, /* HEBREW LETTER HE -> 'h' */
+ { 0xD5, 0x76 }, /* HEBREW LETTER VAV -> 'v' */
+ { 0xD6, 0x7A }, /* HEBREW LETTER ZAYIN -> 'z' */
+ { 0xD7, 0x48 }, /* HEBREW LETTER HET -> 'H' */
+ { 0xD8, 0x54 }, /* HEBREW LETTER TET -> 'T' */
+ { 0xD9, 0x79 }, /* HEBREW LETTER YOD -> 'y' */
+ { 0xDC, 0x6C }, /* HEBREW LETTER LAMED -> 'l' */
+ { 0xDD, 0x6D }, /* HEBREW LETTER FINAL MEM -> 'm' */
+ { 0xDE, 0x6D }, /* HEBREW LETTER MEM -> 'm' */
+ { 0xDF, 0x6E }, /* HEBREW LETTER FINAL NUN -> 'n' */
+ { 0xE0, 0x6E }, /* HEBREW LETTER NUN -> 'n' */
+ { 0xE1, 0x73 }, /* HEBREW LETTER SAMEKH -> 's' */
+ { 0xE2, 0x60 }, /* HEBREW LETTER AYIN -> '`' */
+ { 0xE3, 0x70 }, /* HEBREW LETTER FINAL PE -> 'p' */
+ { 0xE4, 0x70 }, /* HEBREW LETTER PE -> 'p' */
+ { 0xE7, 0x6B }, /* HEBREW LETTER QOF -> 'k' */
+ { 0xE8, 0x72 }, /* HEBREW LETTER RESH -> 'r' */
+ { 0xEA, 0x74 }, /* HEBREW LETTER TAV -> 't' */
+ { 0xF0, 0x56 }, /* HEBREW LIGATURE YIDDISH DOUBLE VAV -> 'V' */
+ { 0xF3, 0x27 }, /* HEBREW PUNCTUATION GERESH -> ''' */
+ { 0xF4, 0x22 }, /* HEBREW PUNCTUATION GERSHAYIM -> '"' */
+ /* Entries for page 0x06 */
+ { 0x0C, 0x2C }, /* ARABIC COMMA -> ',' */
+ { 0x1B, 0x3B }, /* ARABIC SEMICOLON -> ';' */
+ { 0x1F, 0x3F }, /* ARABIC QUESTION MARK -> '?' */
+ { 0x22, 0x61 }, /* ARABIC LETTER ALEF WITH MADDA ABOVE -> 'a' */
+ { 0x23, 0x27 }, /* ARABIC LETTER ALEF WITH HAMZA ABOVE -> ''' */
+ { 0x28, 0x62 }, /* ARABIC LETTER BEH -> 'b' */
+ { 0x29, 0x40 }, /* ARABIC LETTER TEH MARBUTA -> '@' */
+ { 0x2A, 0x74 }, /* ARABIC LETTER TEH -> 't' */
+ { 0x2C, 0x6A }, /* ARABIC LETTER JEEM -> 'j' */
+ { 0x2D, 0x48 }, /* ARABIC LETTER HAH -> 'H' */
+ { 0x2F, 0x64 }, /* ARABIC LETTER DAL -> 'd' */
+ { 0x31, 0x72 }, /* ARABIC LETTER REH -> 'r' */
+ { 0x32, 0x7A }, /* ARABIC LETTER ZAIN -> 'z' */
+ { 0x33, 0x73 }, /* ARABIC LETTER SEEN -> 's' */
+ { 0x35, 0x53 }, /* ARABIC LETTER SAD -> 'S' */
+ { 0x36, 0x44 }, /* ARABIC LETTER DAD -> 'D' */
+ { 0x37, 0x54 }, /* ARABIC LETTER TAH -> 'T' */
+ { 0x38, 0x5A }, /* ARABIC LETTER ZAH -> 'Z' */
+ { 0x39, 0x60 }, /* ARABIC LETTER AIN -> '`' */
+ { 0x3A, 0x47 }, /* ARABIC LETTER GHAIN -> 'G' */
+ { 0x41, 0x66 }, /* ARABIC LETTER FEH -> 'f' */
+ { 0x42, 0x71 }, /* ARABIC LETTER QAF -> 'q' */
+ { 0x43, 0x6B }, /* ARABIC LETTER KAF -> 'k' */
+ { 0x44, 0x6C }, /* ARABIC LETTER LAM -> 'l' */
+ { 0x45, 0x6D }, /* ARABIC LETTER MEEM -> 'm' */
+ { 0x46, 0x6E }, /* ARABIC LETTER NOON -> 'n' */
+ { 0x47, 0x68 }, /* ARABIC LETTER HEH -> 'h' */
+ { 0x48, 0x77 }, /* ARABIC LETTER WAW -> 'w' */
+ { 0x49, 0x7E }, /* ARABIC LETTER ALEF MAKSURA -> '~' */
+ { 0x4A, 0x79 }, /* ARABIC LETTER YEH -> 'y' */
+ { 0x4E, 0x61 }, /* ARABIC FATHA -> 'a' */
+ { 0x4F, 0x75 }, /* ARABIC DAMMA -> 'u' */
+ { 0x50, 0x69 }, /* ARABIC KASRA -> 'i' */
+ { 0x51, 0x57 }, /* ARABIC SHADDA -> 'W' */
+ { 0x54, 0x27 }, /* ARABIC HAMZA ABOVE -> ''' */
+ { 0x55, 0x27 }, /* ARABIC HAMZA BELOW -> ''' */
+ { 0x60, 0x30 }, /* ARABIC-INDIC DIGIT ZERO -> '0' */
+ { 0x61, 0x31 }, /* ARABIC-INDIC DIGIT ONE -> '1' */
+ { 0x62, 0x32 }, /* ARABIC-INDIC DIGIT TWO -> '2' */
+ { 0x63, 0x33 }, /* ARABIC-INDIC DIGIT THREE -> '3' */
+ { 0x64, 0x34 }, /* ARABIC-INDIC DIGIT FOUR -> '4' */
+ { 0x65, 0x35 }, /* ARABIC-INDIC DIGIT FIVE -> '5' */
+ { 0x66, 0x36 }, /* ARABIC-INDIC DIGIT SIX -> '6' */
+ { 0x67, 0x37 }, /* ARABIC-INDIC DIGIT SEVEN -> '7' */
+ { 0x68, 0x38 }, /* ARABIC-INDIC DIGIT EIGHT -> '8' */
+ { 0x69, 0x39 }, /* ARABIC-INDIC DIGIT NINE -> '9' */
+ { 0x6A, 0x25 }, /* ARABIC PERCENT SIGN -> '%' */
+ { 0x6B, 0x2E }, /* ARABIC DECIMAL SEPARATOR -> '.' */
+ { 0x6C, 0x2C }, /* ARABIC THOUSANDS SEPARATOR -> ',' */
+ { 0x6D, 0x2A }, /* ARABIC FIVE POINTED STAR -> '*' */
+ { 0x71, 0x00 }, /* ARABIC LETTER ALEF WASLA -> ... */
+ { 0x73, 0x27 }, /* ARABIC LETTER ALEF WITH WAVY HAMZA BELOW -> ''' */
+ { 0x75, 0x27 }, /* ARABIC LETTER HIGH HAMZA ALEF -> ''' */
+ { 0x7B, 0x62 }, /* ARABIC LETTER BEEH -> 'b' */
+ { 0x7C, 0x74 }, /* ARABIC LETTER TEH WITH RING -> 't' */
+ { 0x7D, 0x54 }, /* ARABIC LETTER TEH WITH THREE DOTS ABOVE DOWNWARDS -> 'T' */
+ { 0x7E, 0x70 }, /* ARABIC LETTER PEH -> 'p' */
+ { 0x82, 0x48 }, /* ARABIC LETTER HAH WITH TWO DOTS VERTICAL ABOVE -> 'H' */
+ { 0x85, 0x48 }, /* ARABIC LETTER HAH WITH THREE DOTS ABOVE -> 'H' */
+ { 0x89, 0x44 }, /* ARABIC LETTER DAL WITH RING -> 'D' */
+ { 0x8A, 0x44 }, /* ARABIC LETTER DAL WITH DOT BELOW -> 'D' */
+ { 0x8E, 0x64 }, /* ARABIC LETTER DUL -> 'd' */
+ { 0x8F, 0x44 }, /* ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARDS -> 'D' */
+ { 0x90, 0x44 }, /* ARABIC LETTER DAL WITH FOUR DOTS ABOVE -> 'D' */
+ { 0x92, 0x00 }, /* ARABIC LETTER REH WITH SMALL V -> ... */
+ { 0x97, 0x52 }, /* ARABIC LETTER REH WITH TWO DOTS ABOVE -> 'R' */
+ { 0x98, 0x6A }, /* ARABIC LETTER JEH -> 'j' */
+ { 0x99, 0x52 }, /* ARABIC LETTER REH WITH FOUR DOTS ABOVE -> 'R' */
+ { 0x9A, 0x00 }, /* ARABIC LETTER SEEN WITH DOT BELOW AND DOT ABOVE -> ... */
+ { 0x9E, 0x53 }, /* ARABIC LETTER SAD WITH THREE DOTS ABOVE -> 'S' */
+ { 0x9F, 0x54 }, /* ARABIC LETTER TAH WITH THREE DOTS ABOVE -> 'T' */
+ { 0xA1, 0x00 }, /* ARABIC LETTER DOTLESS FEH -> ... */
+ { 0xA3, 0x46 }, /* ARABIC LETTER FEH WITH DOT BELOW -> 'F' */
+ { 0xA4, 0x76 }, /* ARABIC LETTER VEH -> 'v' */
+ { 0xA5, 0x66 }, /* ARABIC LETTER FEH WITH THREE DOTS BELOW -> 'f' */
+ { 0xA7, 0x51 }, /* ARABIC LETTER QAF WITH DOT ABOVE -> 'Q' */
+ { 0xA8, 0x51 }, /* ARABIC LETTER QAF WITH THREE DOTS ABOVE -> 'Q' */
+ { 0xAA, 0x6B }, /* ARABIC LETTER SWASH KAF -> 'k' */
+ { 0xAB, 0x4B }, /* ARABIC LETTER KAF WITH RING -> 'K' */
+ { 0xAC, 0x4B }, /* ARABIC LETTER KAF WITH DOT ABOVE -> 'K' */
+ { 0xAE, 0x4B }, /* ARABIC LETTER KAF WITH THREE DOTS BELOW -> 'K' */
+ { 0xAF, 0x67 }, /* ARABIC LETTER GAF -> 'g' */
+ { 0xB0, 0x47 }, /* ARABIC LETTER GAF WITH RING -> 'G' */
+ { 0xB1, 0x4E }, /* ARABIC LETTER NGOEH -> 'N' */
+ { 0xB2, 0x00 }, /* ARABIC LETTER GAF WITH TWO DOTS BELOW -> ... */
+ { 0xB4, 0x47 }, /* ARABIC LETTER GAF WITH THREE DOTS ABOVE -> 'G' */
+ { 0xB5, 0x00 }, /* ARABIC LETTER LAM WITH SMALL V -> ... */
+ { 0xB8, 0x4C }, /* ARABIC LETTER LAM WITH THREE DOTS BELOW -> 'L' */
+ { 0xB9, 0x00 }, /* ARABIC LETTER NOON WITH DOT BELOW -> ... */
+ { 0xBD, 0x4E }, /* ARABIC LETTER NOON WITH THREE DOTS ABOVE -> 'N' */
+ { 0xBE, 0x68 }, /* ARABIC LETTER HEH DOACHASHMEE -> 'h' */
+ { 0xC1, 0x68 }, /* ARABIC LETTER HEH GOAL -> 'h' */
+ { 0xC2, 0x48 }, /* ARABIC LETTER HEH GOAL WITH HAMZA ABOVE -> 'H' */
+ { 0xC3, 0x40 }, /* ARABIC LETTER TEH MARBUTA GOAL -> '@' */
+ { 0xC4, 0x57 }, /* ARABIC LETTER WAW WITH RING -> 'W' */
+ { 0xC7, 0x75 }, /* ARABIC LETTER U -> 'u' */
+ { 0xCA, 0x57 }, /* ARABIC LETTER WAW WITH TWO DOTS ABOVE -> 'W' */
+ { 0xCB, 0x76 }, /* ARABIC LETTER VE -> 'v' */
+ { 0xCC, 0x79 }, /* ARABIC LETTER FARSI YEH -> 'y' */
+ { 0xCD, 0x59 }, /* ARABIC LETTER YEH WITH TAIL -> 'Y' */
+ { 0xCE, 0x59 }, /* ARABIC LETTER YEH WITH SMALL V -> 'Y' */
+ { 0xCF, 0x57 }, /* ARABIC LETTER WAW WITH DOT ABOVE -> 'W' */
+ { 0xD2, 0x79 }, /* ARABIC LETTER YEH BARREE -> 'y' */
+ { 0xD4, 0x2E }, /* ARABIC FULL STOP -> '.' */
+ { 0xDD, 0x40 }, /* ARABIC END OF AYAH -> '@' */
+ { 0xDE, 0x23 }, /* ARABIC START OF RUB EL HIZB -> '#' */
+ { 0xE9, 0x5E }, /* ARABIC PLACE OF SAJDAH -> '^' */
+ { 0xF0, 0x30 }, /* EXTENDED ARABIC-INDIC DIGIT ZERO -> '0' */
+ { 0xF1, 0x31 }, /* EXTENDED ARABIC-INDIC DIGIT ONE -> '1' */
+ { 0xF2, 0x32 }, /* EXTENDED ARABIC-INDIC DIGIT TWO -> '2' */
+ { 0xF3, 0x33 }, /* EXTENDED ARABIC-INDIC DIGIT THREE -> '3' */
+ { 0xF4, 0x34 }, /* EXTENDED ARABIC-INDIC DIGIT FOUR -> '4' */
+ { 0xF5, 0x35 }, /* EXTENDED ARABIC-INDIC DIGIT FIVE -> '5' */
+ { 0xF6, 0x36 }, /* EXTENDED ARABIC-INDIC DIGIT SIX -> '6' */
+ { 0xF7, 0x37 }, /* EXTENDED ARABIC-INDIC DIGIT SEVEN -> '7' */
+ { 0xF8, 0x38 }, /* EXTENDED ARABIC-INDIC DIGIT EIGHT -> '8' */
+ { 0xF9, 0x39 }, /* EXTENDED ARABIC-INDIC DIGIT NINE -> '9' */
+ { 0xFB, 0x44 }, /* ARABIC LETTER DAD WITH DOT BELOW -> 'D' */
+ { 0xFD, 0x26 }, /* ARABIC SIGN SINDHI AMPERSAND -> '&' */
+ /* Entries for page 0x07 */
+ { 0x01, 0x2F }, /* SYRIAC SUPRALINEAR FULL STOP -> '/' */
+ { 0x02, 0x2C }, /* SYRIAC SUBLINEAR FULL STOP -> ',' */
+ { 0x03, 0x21 }, /* SYRIAC SUPRALINEAR COLON -> '!' */
+ { 0x04, 0x21 }, /* SYRIAC SUBLINEAR COLON -> '!' */
+ { 0x05, 0x2D }, /* SYRIAC HORIZONTAL COLON -> '-' */
+ { 0x06, 0x2C }, /* SYRIAC COLON SKEWED LEFT -> ',' */
+ { 0x07, 0x2C }, /* SYRIAC COLON SKEWED RIGHT -> ',' */
+ { 0x08, 0x3B }, /* SYRIAC SUPRALINEAR COLON SKEWED LEFT -> ';' */
+ { 0x09, 0x3F }, /* SYRIAC SUBLINEAR COLON SKEWED RIGHT -> '?' */
+ { 0x0A, 0x7E }, /* SYRIAC CONTRACTION -> '~' */
+ { 0x0B, 0x7B }, /* SYRIAC HARKLEAN OBELUS -> '{' */
+ { 0x0C, 0x7D }, /* SYRIAC HARKLEAN METOBELUS -> '}' */
+ { 0x0D, 0x2A }, /* SYRIAC HARKLEAN ASTERISCUS -> '*' */
+ { 0x10, 0x27 }, /* SYRIAC LETTER ALAPH -> ''' */
+ { 0x12, 0x62 }, /* SYRIAC LETTER BETH -> 'b' */
+ { 0x13, 0x67 }, /* SYRIAC LETTER GAMAL -> 'g' */
+ { 0x14, 0x67 }, /* SYRIAC LETTER GAMAL GARSHUNI -> 'g' */
+ { 0x15, 0x64 }, /* SYRIAC LETTER DALATH -> 'd' */
+ { 0x16, 0x64 }, /* SYRIAC LETTER DOTLESS DALATH RISH -> 'd' */
+ { 0x17, 0x68 }, /* SYRIAC LETTER HE -> 'h' */
+ { 0x18, 0x77 }, /* SYRIAC LETTER WAW -> 'w' */
+ { 0x19, 0x7A }, /* SYRIAC LETTER ZAIN -> 'z' */
+ { 0x1A, 0x48 }, /* SYRIAC LETTER HETH -> 'H' */
+ { 0x1B, 0x74 }, /* SYRIAC LETTER TETH -> 't' */
+ { 0x1C, 0x74 }, /* SYRIAC LETTER TETH GARSHUNI -> 't' */
+ { 0x1D, 0x79 }, /* SYRIAC LETTER YUDH -> 'y' */
+ { 0x1F, 0x6B }, /* SYRIAC LETTER KAPH -> 'k' */
+ { 0x20, 0x6C }, /* SYRIAC LETTER LAMADH -> 'l' */
+ { 0x21, 0x6D }, /* SYRIAC LETTER MIM -> 'm' */
+ { 0x22, 0x6E }, /* SYRIAC LETTER NUN -> 'n' */
+ { 0x23, 0x73 }, /* SYRIAC LETTER SEMKATH -> 's' */
+ { 0x24, 0x73 }, /* SYRIAC LETTER FINAL SEMKATH -> 's' */
+ { 0x25, 0x60 }, /* SYRIAC LETTER E -> '`' */
+ { 0x26, 0x70 }, /* SYRIAC LETTER PE -> 'p' */
+ { 0x27, 0x70 }, /* SYRIAC LETTER REVERSED PE -> 'p' */
+ { 0x28, 0x53 }, /* SYRIAC LETTER SADHE -> 'S' */
+ { 0x29, 0x71 }, /* SYRIAC LETTER QAPH -> 'q' */
+ { 0x2A, 0x72 }, /* SYRIAC LETTER RISH -> 'r' */
+ { 0x2C, 0x74 }, /* SYRIAC LETTER TAW -> 't' */
+ { 0x30, 0x00 }, /* SYRIAC PTHAHA ABOVE -> ... */
+ { 0x32, 0x61 }, /* SYRIAC PTHAHA DOTTED -> 'a' */
+ { 0x33, 0x00 }, /* SYRIAC ZQAPHA ABOVE -> ... */
+ { 0x35, 0x41 }, /* SYRIAC ZQAPHA DOTTED -> 'A' */
+ { 0x36, 0x00 }, /* SYRIAC RBASA ABOVE -> ... */
+ { 0x38, 0x65 }, /* SYRIAC DOTTED ZLAMA HORIZONTAL -> 'e' */
+ { 0x39, 0x45 }, /* SYRIAC DOTTED ZLAMA ANGULAR -> 'E' */
+ { 0x3A, 0x69 }, /* SYRIAC HBASA ABOVE -> 'i' */
+ { 0x3B, 0x69 }, /* SYRIAC HBASA BELOW -> 'i' */
+ { 0x3C, 0x00 }, /* SYRIAC HBASA-ESASA DOTTED -> ... */
+ { 0x3E, 0x75 }, /* SYRIAC ESASA BELOW -> 'u' */
+ { 0x3F, 0x6F }, /* SYRIAC RWAHA -> 'o' */
+ { 0x41, 0x60 }, /* SYRIAC QUSHSHAYA -> '`' */
+ { 0x42, 0x27 }, /* SYRIAC RUKKAKHA -> ''' */
+ { 0x45, 0x58 }, /* SYRIAC THREE DOTS ABOVE -> 'X' */
+ { 0x46, 0x51 }, /* SYRIAC THREE DOTS BELOW -> 'Q' */
+ { 0x47, 0x40 }, /* SYRIAC OBLIQUE LINE ABOVE -> '@' */
+ { 0x48, 0x40 }, /* SYRIAC OBLIQUE LINE BELOW -> '@' */
+ { 0x49, 0x7C }, /* SYRIAC MUSIC -> '|' */
+ { 0x4A, 0x2B }, /* SYRIAC BARREKH -> '+' */
+ { 0x80, 0x68 }, /* THAANA LETTER HAA -> 'h' */
+ { 0x82, 0x6E }, /* THAANA LETTER NOONU -> 'n' */
+ { 0x83, 0x72 }, /* THAANA LETTER RAA -> 'r' */
+ { 0x84, 0x62 }, /* THAANA LETTER BAA -> 'b' */
+ { 0x85, 0x4C }, /* THAANA LETTER LHAVIYANI -> 'L' */
+ { 0x86, 0x6B }, /* THAANA LETTER KAAFU -> 'k' */
+ { 0x87, 0x27 }, /* THAANA LETTER ALIFU -> ''' */
+ { 0x88, 0x76 }, /* THAANA LETTER VAAVU -> 'v' */
+ { 0x89, 0x6D }, /* THAANA LETTER MEEMU -> 'm' */
+ { 0x8A, 0x66 }, /* THAANA LETTER FAAFU -> 'f' */
+ { 0x8D, 0x6C }, /* THAANA LETTER LAAMU -> 'l' */
+ { 0x8E, 0x67 }, /* THAANA LETTER GAAFU -> 'g' */
+ { 0x90, 0x73 }, /* THAANA LETTER SEENU -> 's' */
+ { 0x91, 0x64 }, /* THAANA LETTER DAVIYANI -> 'd' */
+ { 0x92, 0x7A }, /* THAANA LETTER ZAVIYANI -> 'z' */
+ { 0x93, 0x74 }, /* THAANA LETTER TAVIYANI -> 't' */
+ { 0x94, 0x79 }, /* THAANA LETTER YAA -> 'y' */
+ { 0x95, 0x70 }, /* THAANA LETTER PAVIYANI -> 'p' */
+ { 0x96, 0x6A }, /* THAANA LETTER JAVIYANI -> 'j' */
+ { 0x9C, 0x7A }, /* THAANA LETTER ZAA -> 'z' */
+ { 0x9E, 0x73 }, /* THAANA LETTER SAADHU -> 's' */
+ { 0x9F, 0x64 }, /* THAANA LETTER DAADHU -> 'd' */
+ { 0xA0, 0x74 }, /* THAANA LETTER TO -> 't' */
+ { 0xA1, 0x7A }, /* THAANA LETTER ZO -> 'z' */
+ { 0xA2, 0x60 }, /* THAANA LETTER AINU -> '`' */
+ { 0xA4, 0x71 }, /* THAANA LETTER QAAFU -> 'q' */
+ { 0xA5, 0x77 }, /* THAANA LETTER WAAVU -> 'w' */
+ { 0xA6, 0x61 }, /* THAANA ABAFILI -> 'a' */
+ { 0xA8, 0x69 }, /* THAANA IBIFILI -> 'i' */
+ { 0xAA, 0x75 }, /* THAANA UBUFILI -> 'u' */
+ { 0xAC, 0x65 }, /* THAANA EBEFILI -> 'e' */
+ { 0xAE, 0x6F }, /* THAANA OBOFILI -> 'o' */
+ /* Entries for page 0x09 */
+ { 0x01, 0x4E }, /* DEVANAGARI SIGN CANDRABINDU -> 'N' */
+ { 0x02, 0x4E }, /* DEVANAGARI SIGN ANUSVARA -> 'N' */
+ { 0x03, 0x48 }, /* DEVANAGARI SIGN VISARGA -> 'H' */
+ { 0x05, 0x61 }, /* DEVANAGARI LETTER A -> 'a' */
+ { 0x07, 0x69 }, /* DEVANAGARI LETTER I -> 'i' */
+ { 0x09, 0x75 }, /* DEVANAGARI LETTER U -> 'u' */
+ { 0x0B, 0x52 }, /* DEVANAGARI LETTER VOCALIC R -> 'R' */
+ { 0x0C, 0x4C }, /* DEVANAGARI LETTER VOCALIC L -> 'L' */
+ { 0x0E, 0x65 }, /* DEVANAGARI LETTER SHORT E -> 'e' */
+ { 0x0F, 0x65 }, /* DEVANAGARI LETTER E -> 'e' */
+ { 0x12, 0x6F }, /* DEVANAGARI LETTER SHORT O -> 'o' */
+ { 0x13, 0x6F }, /* DEVANAGARI LETTER O -> 'o' */
+ { 0x15, 0x6B }, /* DEVANAGARI LETTER KA -> 'k' */
+ { 0x17, 0x67 }, /* DEVANAGARI LETTER GA -> 'g' */
+ { 0x1A, 0x63 }, /* DEVANAGARI LETTER CA -> 'c' */
+ { 0x1C, 0x6A }, /* DEVANAGARI LETTER JA -> 'j' */
+ { 0x24, 0x74 }, /* DEVANAGARI LETTER TA -> 't' */
+ { 0x26, 0x64 }, /* DEVANAGARI LETTER DA -> 'd' */
+ { 0x28, 0x6E }, /* DEVANAGARI LETTER NA -> 'n' */
+ { 0x2A, 0x70 }, /* DEVANAGARI LETTER PA -> 'p' */
+ { 0x2C, 0x62 }, /* DEVANAGARI LETTER BA -> 'b' */
+ { 0x2E, 0x6D }, /* DEVANAGARI LETTER MA -> 'm' */
+ { 0x2F, 0x79 }, /* DEVANAGARI LETTER YA -> 'y' */
+ { 0x30, 0x72 }, /* DEVANAGARI LETTER RA -> 'r' */
+ { 0x32, 0x6C }, /* DEVANAGARI LETTER LA -> 'l' */
+ { 0x33, 0x6C }, /* DEVANAGARI LETTER LLA -> 'l' */
+ { 0x35, 0x76 }, /* DEVANAGARI LETTER VA -> 'v' */
+ { 0x38, 0x73 }, /* DEVANAGARI LETTER SA -> 's' */
+ { 0x39, 0x68 }, /* DEVANAGARI LETTER HA -> 'h' */
+ { 0x3C, 0x27 }, /* DEVANAGARI SIGN NUKTA -> ''' */
+ { 0x3D, 0x27 }, /* DEVANAGARI SIGN AVAGRAHA -> ''' */
+ { 0x3F, 0x69 }, /* DEVANAGARI VOWEL SIGN I -> 'i' */
+ { 0x41, 0x75 }, /* DEVANAGARI VOWEL SIGN U -> 'u' */
+ { 0x43, 0x52 }, /* DEVANAGARI VOWEL SIGN VOCALIC R -> 'R' */
+ { 0x46, 0x65 }, /* DEVANAGARI VOWEL SIGN SHORT E -> 'e' */
+ { 0x47, 0x65 }, /* DEVANAGARI VOWEL SIGN E -> 'e' */
+ { 0x4A, 0x6F }, /* DEVANAGARI VOWEL SIGN SHORT O -> 'o' */
+ { 0x4B, 0x6F }, /* DEVANAGARI VOWEL SIGN O -> 'o' */
+ { 0x51, 0x27 }, /* DEVANAGARI STRESS SIGN UDATTA -> ''' */
+ { 0x52, 0x27 }, /* DEVANAGARI STRESS SIGN ANUDATTA -> ''' */
+ { 0x53, 0x60 }, /* DEVANAGARI GRAVE ACCENT -> '`' */
+ { 0x54, 0x27 }, /* DEVANAGARI ACUTE ACCENT -> ''' */
+ { 0x58, 0x71 }, /* DEVANAGARI LETTER QA -> 'q' */
+ { 0x5B, 0x7A }, /* DEVANAGARI LETTER ZA -> 'z' */
+ { 0x5E, 0x66 }, /* DEVANAGARI LETTER FA -> 'f' */
+ { 0x62, 0x4C }, /* DEVANAGARI VOWEL SIGN VOCALIC L -> 'L' */
+ { 0x66, 0x30 }, /* DEVANAGARI DIGIT ZERO -> '0' */
+ { 0x67, 0x31 }, /* DEVANAGARI DIGIT ONE -> '1' */
+ { 0x68, 0x32 }, /* DEVANAGARI DIGIT TWO -> '2' */
+ { 0x69, 0x33 }, /* DEVANAGARI DIGIT THREE -> '3' */
+ { 0x6A, 0x34 }, /* DEVANAGARI DIGIT FOUR -> '4' */
+ { 0x6B, 0x35 }, /* DEVANAGARI DIGIT FIVE -> '5' */
+ { 0x6C, 0x36 }, /* DEVANAGARI DIGIT SIX -> '6' */
+ { 0x6D, 0x37 }, /* DEVANAGARI DIGIT SEVEN -> '7' */
+ { 0x6E, 0x38 }, /* DEVANAGARI DIGIT EIGHT -> '8' */
+ { 0x6F, 0x39 }, /* DEVANAGARI DIGIT NINE -> '9' */
+ { 0x70, 0x2E }, /* DEVANAGARI ABBREVIATION SIGN -> '.' */
+ { 0x81, 0x4E }, /* BENGALI SIGN CANDRABINDU -> 'N' */
+ { 0x82, 0x4E }, /* BENGALI SIGN ANUSVARA -> 'N' */
+ { 0x83, 0x48 }, /* BENGALI SIGN VISARGA -> 'H' */
+ { 0x85, 0x61 }, /* BENGALI LETTER A -> 'a' */
+ { 0x87, 0x69 }, /* BENGALI LETTER I -> 'i' */
+ { 0x89, 0x75 }, /* BENGALI LETTER U -> 'u' */
+ { 0x8B, 0x52 }, /* BENGALI LETTER VOCALIC R -> 'R' */
+ { 0x8F, 0x65 }, /* BENGALI LETTER E -> 'e' */
+ { 0x93, 0x6F }, /* BENGALI LETTER O -> 'o' */
+ { 0x95, 0x6B }, /* BENGALI LETTER KA -> 'k' */
+ { 0x97, 0x67 }, /* BENGALI LETTER GA -> 'g' */
+ { 0x9A, 0x63 }, /* BENGALI LETTER CA -> 'c' */
+ { 0x9C, 0x6A }, /* BENGALI LETTER JA -> 'j' */
+ { 0xA4, 0x74 }, /* BENGALI LETTER TA -> 't' */
+ { 0xA6, 0x64 }, /* BENGALI LETTER DA -> 'd' */
+ { 0xA8, 0x6E }, /* BENGALI LETTER NA -> 'n' */
+ { 0xAA, 0x70 }, /* BENGALI LETTER PA -> 'p' */
+ { 0xAC, 0x62 }, /* BENGALI LETTER BA -> 'b' */
+ { 0xAE, 0x6D }, /* BENGALI LETTER MA -> 'm' */
+ { 0xAF, 0x79 }, /* BENGALI LETTER YA -> 'y' */
+ { 0xB0, 0x72 }, /* BENGALI LETTER RA -> 'r' */
+ { 0xB2, 0x6C }, /* BENGALI LETTER LA -> 'l' */
+ { 0xB8, 0x73 }, /* BENGALI LETTER SA -> 's' */
+ { 0xB9, 0x68 }, /* BENGALI LETTER HA -> 'h' */
+ { 0xBC, 0x27 }, /* BENGALI SIGN NUKTA -> ''' */
+ { 0xBF, 0x69 }, /* BENGALI VOWEL SIGN I -> 'i' */
+ { 0xC1, 0x75 }, /* BENGALI VOWEL SIGN U -> 'u' */
+ { 0xC3, 0x52 }, /* BENGALI VOWEL SIGN VOCALIC R -> 'R' */
+ { 0xC7, 0x65 }, /* BENGALI VOWEL SIGN E -> 'e' */
+ { 0xCB, 0x6F }, /* BENGALI VOWEL SIGN O -> 'o' */
+ { 0xD7, 0x2B }, /* BENGALI AU LENGTH MARK -> '+' */
+ { 0xE2, 0x4C }, /* BENGALI VOWEL SIGN VOCALIC L -> 'L' */
+ { 0xE6, 0x30 }, /* BENGALI DIGIT ZERO -> '0' */
+ { 0xE7, 0x31 }, /* BENGALI DIGIT ONE -> '1' */
+ { 0xE8, 0x32 }, /* BENGALI DIGIT TWO -> '2' */
+ { 0xE9, 0x33 }, /* BENGALI DIGIT THREE -> '3' */
+ { 0xEA, 0x34 }, /* BENGALI DIGIT FOUR -> '4' */
+ { 0xEB, 0x35 }, /* BENGALI DIGIT FIVE -> '5' */
+ { 0xEC, 0x36 }, /* BENGALI DIGIT SIX -> '6' */
+ { 0xED, 0x37 }, /* BENGALI DIGIT SEVEN -> '7' */
+ { 0xEE, 0x38 }, /* BENGALI DIGIT EIGHT -> '8' */
+ { 0xEF, 0x39 }, /* BENGALI DIGIT NINE -> '9' */
+ /* Entries for page 0x0A */
+ { 0x02, 0x4E }, /* GURMUKHI SIGN BINDI -> 'N' */
+ { 0x05, 0x61 }, /* GURMUKHI LETTER A -> 'a' */
+ { 0x07, 0x69 }, /* GURMUKHI LETTER I -> 'i' */
+ { 0x09, 0x75 }, /* GURMUKHI LETTER U -> 'u' */
+ { 0x15, 0x6B }, /* GURMUKHI LETTER KA -> 'k' */
+ { 0x17, 0x67 }, /* GURMUKHI LETTER GA -> 'g' */
+ { 0x1A, 0x63 }, /* GURMUKHI LETTER CA -> 'c' */
+ { 0x1C, 0x6A }, /* GURMUKHI LETTER JA -> 'j' */
+ { 0x24, 0x74 }, /* GURMUKHI LETTER TA -> 't' */
+ { 0x26, 0x64 }, /* GURMUKHI LETTER DA -> 'd' */
+ { 0x28, 0x6E }, /* GURMUKHI LETTER NA -> 'n' */
+ { 0x2A, 0x70 }, /* GURMUKHI LETTER PA -> 'p' */
+ { 0x2C, 0x62 }, /* GURMUKHI LETTER BA -> 'b' */
+ { 0x2E, 0x6D }, /* GURMUKHI LETTER MA -> 'm' */
+ { 0x2F, 0x79 }, /* GURMUKHI LETTER YA -> 'y' */
+ { 0x30, 0x72 }, /* GURMUKHI LETTER RA -> 'r' */
+ { 0x32, 0x6C }, /* GURMUKHI LETTER LA -> 'l' */
+ { 0x35, 0x76 }, /* GURMUKHI LETTER VA -> 'v' */
+ { 0x38, 0x73 }, /* GURMUKHI LETTER SA -> 's' */
+ { 0x39, 0x68 }, /* GURMUKHI LETTER HA -> 'h' */
+ { 0x3C, 0x27 }, /* GURMUKHI SIGN NUKTA -> ''' */
+ { 0x3F, 0x69 }, /* GURMUKHI VOWEL SIGN I -> 'i' */
+ { 0x41, 0x75 }, /* GURMUKHI VOWEL SIGN U -> 'u' */
+ { 0x5B, 0x7A }, /* GURMUKHI LETTER ZA -> 'z' */
+ { 0x5E, 0x66 }, /* GURMUKHI LETTER FA -> 'f' */
+ { 0x66, 0x30 }, /* GURMUKHI DIGIT ZERO -> '0' */
+ { 0x67, 0x31 }, /* GURMUKHI DIGIT ONE -> '1' */
+ { 0x68, 0x32 }, /* GURMUKHI DIGIT TWO -> '2' */
+ { 0x69, 0x33 }, /* GURMUKHI DIGIT THREE -> '3' */
+ { 0x6A, 0x34 }, /* GURMUKHI DIGIT FOUR -> '4' */
+ { 0x6B, 0x35 }, /* GURMUKHI DIGIT FIVE -> '5' */
+ { 0x6C, 0x36 }, /* GURMUKHI DIGIT SIX -> '6' */
+ { 0x6D, 0x37 }, /* GURMUKHI DIGIT SEVEN -> '7' */
+ { 0x6E, 0x38 }, /* GURMUKHI DIGIT EIGHT -> '8' */
+ { 0x6F, 0x39 }, /* GURMUKHI DIGIT NINE -> '9' */
+ { 0x70, 0x4E }, /* GURMUKHI TIPPI -> 'N' */
+ { 0x71, 0x48 }, /* GURMUKHI ADDAK -> 'H' */
+ { 0x81, 0x4E }, /* GUJARATI SIGN CANDRABINDU -> 'N' */
+ { 0x82, 0x4E }, /* GUJARATI SIGN ANUSVARA -> 'N' */
+ { 0x83, 0x48 }, /* GUJARATI SIGN VISARGA -> 'H' */
+ { 0x85, 0x61 }, /* GUJARATI LETTER A -> 'a' */
+ { 0x87, 0x69 }, /* GUJARATI LETTER I -> 'i' */
+ { 0x89, 0x75 }, /* GUJARATI LETTER U -> 'u' */
+ { 0x8B, 0x52 }, /* GUJARATI LETTER VOCALIC R -> 'R' */
+ { 0x8F, 0x65 }, /* GUJARATI LETTER E -> 'e' */
+ { 0x93, 0x6F }, /* GUJARATI LETTER O -> 'o' */
+ { 0x95, 0x6B }, /* GUJARATI LETTER KA -> 'k' */
+ { 0x97, 0x67 }, /* GUJARATI LETTER GA -> 'g' */
+ { 0x9A, 0x63 }, /* GUJARATI LETTER CA -> 'c' */
+ { 0x9C, 0x6A }, /* GUJARATI LETTER JA -> 'j' */
+ { 0xA4, 0x74 }, /* GUJARATI LETTER TA -> 't' */
+ { 0xA6, 0x64 }, /* GUJARATI LETTER DA -> 'd' */
+ { 0xA8, 0x6E }, /* GUJARATI LETTER NA -> 'n' */
+ { 0xAA, 0x70 }, /* GUJARATI LETTER PA -> 'p' */
+ { 0xAC, 0x62 }, /* GUJARATI LETTER BA -> 'b' */
+ { 0xAE, 0x6D }, /* GUJARATI LETTER MA -> 'm' */
+ { 0xB0, 0x72 }, /* GUJARATI LETTER RA -> 'r' */
+ { 0xB2, 0x6C }, /* GUJARATI LETTER LA -> 'l' */
+ { 0xB5, 0x76 }, /* GUJARATI LETTER VA -> 'v' */
+ { 0xB8, 0x73 }, /* GUJARATI LETTER SA -> 's' */
+ { 0xB9, 0x68 }, /* GUJARATI LETTER HA -> 'h' */
+ { 0xBC, 0x27 }, /* GUJARATI SIGN NUKTA -> ''' */
+ { 0xBD, 0x27 }, /* GUJARATI SIGN AVAGRAHA -> ''' */
+ { 0xBF, 0x69 }, /* GUJARATI VOWEL SIGN I -> 'i' */
+ { 0xC1, 0x75 }, /* GUJARATI VOWEL SIGN U -> 'u' */
+ { 0xC3, 0x52 }, /* GUJARATI VOWEL SIGN VOCALIC R -> 'R' */
+ { 0xC7, 0x65 }, /* GUJARATI VOWEL SIGN E -> 'e' */
+ { 0xCB, 0x6F }, /* GUJARATI VOWEL SIGN O -> 'o' */
+ { 0xE6, 0x30 }, /* GUJARATI DIGIT ZERO -> '0' */
+ { 0xE7, 0x31 }, /* GUJARATI DIGIT ONE -> '1' */
+ { 0xE8, 0x32 }, /* GUJARATI DIGIT TWO -> '2' */
+ { 0xE9, 0x33 }, /* GUJARATI DIGIT THREE -> '3' */
+ { 0xEA, 0x34 }, /* GUJARATI DIGIT FOUR -> '4' */
+ { 0xEB, 0x35 }, /* GUJARATI DIGIT FIVE -> '5' */
+ { 0xEC, 0x36 }, /* GUJARATI DIGIT SIX -> '6' */
+ { 0xED, 0x37 }, /* GUJARATI DIGIT SEVEN -> '7' */
+ { 0xEE, 0x38 }, /* GUJARATI DIGIT EIGHT -> '8' */
+ { 0xEF, 0x39 }, /* GUJARATI DIGIT NINE -> '9' */
+ /* Entries for page 0x0B */
+ { 0x01, 0x4E }, /* ORIYA SIGN CANDRABINDU -> 'N' */
+ { 0x02, 0x4E }, /* ORIYA SIGN ANUSVARA -> 'N' */
+ { 0x03, 0x48 }, /* ORIYA SIGN VISARGA -> 'H' */
+ { 0x05, 0x61 }, /* ORIYA LETTER A -> 'a' */
+ { 0x07, 0x69 }, /* ORIYA LETTER I -> 'i' */
+ { 0x09, 0x75 }, /* ORIYA LETTER U -> 'u' */
+ { 0x0B, 0x52 }, /* ORIYA LETTER VOCALIC R -> 'R' */
+ { 0x0C, 0x4C }, /* ORIYA LETTER VOCALIC L -> 'L' */
+ { 0x0F, 0x65 }, /* ORIYA LETTER E -> 'e' */
+ { 0x13, 0x6F }, /* ORIYA LETTER O -> 'o' */
+ { 0x15, 0x6B }, /* ORIYA LETTER KA -> 'k' */
+ { 0x17, 0x67 }, /* ORIYA LETTER GA -> 'g' */
+ { 0x1A, 0x63 }, /* ORIYA LETTER CA -> 'c' */
+ { 0x1C, 0x6A }, /* ORIYA LETTER JA -> 'j' */
+ { 0x24, 0x74 }, /* ORIYA LETTER TA -> 't' */
+ { 0x26, 0x64 }, /* ORIYA LETTER DA -> 'd' */
+ { 0x28, 0x6E }, /* ORIYA LETTER NA -> 'n' */
+ { 0x2A, 0x70 }, /* ORIYA LETTER PA -> 'p' */
+ { 0x2C, 0x62 }, /* ORIYA LETTER BA -> 'b' */
+ { 0x2E, 0x6D }, /* ORIYA LETTER MA -> 'm' */
+ { 0x2F, 0x79 }, /* ORIYA LETTER YA -> 'y' */
+ { 0x30, 0x72 }, /* ORIYA LETTER RA -> 'r' */
+ { 0x32, 0x6C }, /* ORIYA LETTER LA -> 'l' */
+ { 0x38, 0x73 }, /* ORIYA LETTER SA -> 's' */
+ { 0x39, 0x68 }, /* ORIYA LETTER HA -> 'h' */
+ { 0x3C, 0x27 }, /* ORIYA SIGN NUKTA -> ''' */
+ { 0x3D, 0x27 }, /* ORIYA SIGN AVAGRAHA -> ''' */
+ { 0x3F, 0x69 }, /* ORIYA VOWEL SIGN I -> 'i' */
+ { 0x41, 0x75 }, /* ORIYA VOWEL SIGN U -> 'u' */
+ { 0x43, 0x52 }, /* ORIYA VOWEL SIGN VOCALIC R -> 'R' */
+ { 0x47, 0x65 }, /* ORIYA VOWEL SIGN E -> 'e' */
+ { 0x4B, 0x6F }, /* ORIYA VOWEL SIGN O -> 'o' */
+ { 0x56, 0x2B }, /* ORIYA AI LENGTH MARK -> '+' */
+ { 0x57, 0x2B }, /* ORIYA AU LENGTH MARK -> '+' */
+ { 0x66, 0x30 }, /* ORIYA DIGIT ZERO -> '0' */
+ { 0x67, 0x31 }, /* ORIYA DIGIT ONE -> '1' */
+ { 0x68, 0x32 }, /* ORIYA DIGIT TWO -> '2' */
+ { 0x69, 0x33 }, /* ORIYA DIGIT THREE -> '3' */
+ { 0x6A, 0x34 }, /* ORIYA DIGIT FOUR -> '4' */
+ { 0x6B, 0x35 }, /* ORIYA DIGIT FIVE -> '5' */
+ { 0x6C, 0x36 }, /* ORIYA DIGIT SIX -> '6' */
+ { 0x6D, 0x37 }, /* ORIYA DIGIT SEVEN -> '7' */
+ { 0x6E, 0x38 }, /* ORIYA DIGIT EIGHT -> '8' */
+ { 0x6F, 0x39 }, /* ORIYA DIGIT NINE -> '9' */
+ { 0x82, 0x4E }, /* TAMIL SIGN ANUSVARA -> 'N' */
+ { 0x83, 0x48 }, /* TAMIL SIGN VISARGA -> 'H' */
+ { 0x85, 0x61 }, /* TAMIL LETTER A -> 'a' */
+ { 0x87, 0x69 }, /* TAMIL LETTER I -> 'i' */
+ { 0x89, 0x75 }, /* TAMIL LETTER U -> 'u' */
+ { 0x8E, 0x65 }, /* TAMIL LETTER E -> 'e' */
+ { 0x92, 0x6F }, /* TAMIL LETTER O -> 'o' */
+ { 0x95, 0x6B }, /* TAMIL LETTER KA -> 'k' */
+ { 0x9A, 0x63 }, /* TAMIL LETTER CA -> 'c' */
+ { 0x9C, 0x6A }, /* TAMIL LETTER JA -> 'j' */
+ { 0xA4, 0x74 }, /* TAMIL LETTER TA -> 't' */
+ { 0xA8, 0x6E }, /* TAMIL LETTER NA -> 'n' */
+ { 0xAA, 0x70 }, /* TAMIL LETTER PA -> 'p' */
+ { 0xAE, 0x6D }, /* TAMIL LETTER MA -> 'm' */
+ { 0xAF, 0x79 }, /* TAMIL LETTER YA -> 'y' */
+ { 0xB0, 0x72 }, /* TAMIL LETTER RA -> 'r' */
+ { 0xB2, 0x6C }, /* TAMIL LETTER LA -> 'l' */
+ { 0xB5, 0x76 }, /* TAMIL LETTER VA -> 'v' */
+ { 0xB8, 0x73 }, /* TAMIL LETTER SA -> 's' */
+ { 0xB9, 0x68 }, /* TAMIL LETTER HA -> 'h' */
+ { 0xBF, 0x69 }, /* TAMIL VOWEL SIGN I -> 'i' */
+ { 0xC1, 0x75 }, /* TAMIL VOWEL SIGN U -> 'u' */
+ { 0xC6, 0x65 }, /* TAMIL VOWEL SIGN E -> 'e' */
+ { 0xCA, 0x6F }, /* TAMIL VOWEL SIGN O -> 'o' */
+ { 0xD7, 0x2B }, /* TAMIL AU LENGTH MARK -> '+' */
+ { 0xE6, 0x30 }, /* TAMIL DIGIT ZERO -> '0' */
+ { 0xE7, 0x31 }, /* TAMIL DIGIT ONE -> '1' */
+ { 0xE8, 0x32 }, /* TAMIL DIGIT TWO -> '2' */
+ { 0xE9, 0x33 }, /* TAMIL DIGIT THREE -> '3' */
+ { 0xEA, 0x34 }, /* TAMIL DIGIT FOUR -> '4' */
+ { 0xEB, 0x35 }, /* TAMIL DIGIT FIVE -> '5' */
+ { 0xEC, 0x36 }, /* TAMIL DIGIT SIX -> '6' */
+ { 0xED, 0x37 }, /* TAMIL DIGIT SEVEN -> '7' */
+ { 0xEE, 0x38 }, /* TAMIL DIGIT EIGHT -> '8' */
+ { 0xEF, 0x39 }, /* TAMIL DIGIT NINE -> '9' */
+ /* Entries for page 0x0C */
+ { 0x01, 0x4E }, /* TELUGU SIGN CANDRABINDU -> 'N' */
+ { 0x02, 0x4E }, /* TELUGU SIGN ANUSVARA -> 'N' */
+ { 0x03, 0x48 }, /* TELUGU SIGN VISARGA -> 'H' */
+ { 0x05, 0x61 }, /* TELUGU LETTER A -> 'a' */
+ { 0x07, 0x69 }, /* TELUGU LETTER I -> 'i' */
+ { 0x09, 0x75 }, /* TELUGU LETTER U -> 'u' */
+ { 0x0B, 0x52 }, /* TELUGU LETTER VOCALIC R -> 'R' */
+ { 0x0C, 0x4C }, /* TELUGU LETTER VOCALIC L -> 'L' */
+ { 0x0E, 0x65 }, /* TELUGU LETTER E -> 'e' */
+ { 0x12, 0x6F }, /* TELUGU LETTER O -> 'o' */
+ { 0x15, 0x6B }, /* TELUGU LETTER KA -> 'k' */
+ { 0x17, 0x67 }, /* TELUGU LETTER GA -> 'g' */
+ { 0x1A, 0x63 }, /* TELUGU LETTER CA -> 'c' */
+ { 0x1C, 0x6A }, /* TELUGU LETTER JA -> 'j' */
+ { 0x24, 0x74 }, /* TELUGU LETTER TA -> 't' */
+ { 0x26, 0x64 }, /* TELUGU LETTER DA -> 'd' */
+ { 0x28, 0x6E }, /* TELUGU LETTER NA -> 'n' */
+ { 0x2A, 0x70 }, /* TELUGU LETTER PA -> 'p' */
+ { 0x2C, 0x62 }, /* TELUGU LETTER BA -> 'b' */
+ { 0x2E, 0x6D }, /* TELUGU LETTER MA -> 'm' */
+ { 0x2F, 0x79 }, /* TELUGU LETTER YA -> 'y' */
+ { 0x30, 0x72 }, /* TELUGU LETTER RA -> 'r' */
+ { 0x32, 0x6C }, /* TELUGU LETTER LA -> 'l' */
+ { 0x35, 0x76 }, /* TELUGU LETTER VA -> 'v' */
+ { 0x38, 0x73 }, /* TELUGU LETTER SA -> 's' */
+ { 0x39, 0x68 }, /* TELUGU LETTER HA -> 'h' */
+ { 0x3F, 0x69 }, /* TELUGU VOWEL SIGN I -> 'i' */
+ { 0x41, 0x75 }, /* TELUGU VOWEL SIGN U -> 'u' */
+ { 0x43, 0x52 }, /* TELUGU VOWEL SIGN VOCALIC R -> 'R' */
+ { 0x46, 0x65 }, /* TELUGU VOWEL SIGN E -> 'e' */
+ { 0x4A, 0x6F }, /* TELUGU VOWEL SIGN O -> 'o' */
+ { 0x55, 0x2B }, /* TELUGU LENGTH MARK -> '+' */
+ { 0x56, 0x2B }, /* TELUGU AI LENGTH MARK -> '+' */
+ { 0x66, 0x30 }, /* TELUGU DIGIT ZERO -> '0' */
+ { 0x67, 0x31 }, /* TELUGU DIGIT ONE -> '1' */
+ { 0x68, 0x32 }, /* TELUGU DIGIT TWO -> '2' */
+ { 0x69, 0x33 }, /* TELUGU DIGIT THREE -> '3' */
+ { 0x6A, 0x34 }, /* TELUGU DIGIT FOUR -> '4' */
+ { 0x6B, 0x35 }, /* TELUGU DIGIT FIVE -> '5' */
+ { 0x6C, 0x36 }, /* TELUGU DIGIT SIX -> '6' */
+ { 0x6D, 0x37 }, /* TELUGU DIGIT SEVEN -> '7' */
+ { 0x6E, 0x38 }, /* TELUGU DIGIT EIGHT -> '8' */
+ { 0x6F, 0x39 }, /* TELUGU DIGIT NINE -> '9' */
+ { 0x82, 0x4E }, /* KANNADA SIGN ANUSVARA -> 'N' */
+ { 0x83, 0x48 }, /* KANNADA SIGN VISARGA -> 'H' */
+ { 0x85, 0x61 }, /* KANNADA LETTER A -> 'a' */
+ { 0x87, 0x69 }, /* KANNADA LETTER I -> 'i' */
+ { 0x89, 0x75 }, /* KANNADA LETTER U -> 'u' */
+ { 0x8B, 0x52 }, /* KANNADA LETTER VOCALIC R -> 'R' */
+ { 0x8C, 0x4C }, /* KANNADA LETTER VOCALIC L -> 'L' */
+ { 0x8E, 0x65 }, /* KANNADA LETTER E -> 'e' */
+ { 0x92, 0x6F }, /* KANNADA LETTER O -> 'o' */
+ { 0x95, 0x6B }, /* KANNADA LETTER KA -> 'k' */
+ { 0x97, 0x67 }, /* KANNADA LETTER GA -> 'g' */
+ { 0x9A, 0x63 }, /* KANNADA LETTER CA -> 'c' */
+ { 0x9C, 0x6A }, /* KANNADA LETTER JA -> 'j' */
+ { 0xA4, 0x74 }, /* KANNADA LETTER TA -> 't' */
+ { 0xA6, 0x64 }, /* KANNADA LETTER DA -> 'd' */
+ { 0xA8, 0x6E }, /* KANNADA LETTER NA -> 'n' */
+ { 0xAA, 0x70 }, /* KANNADA LETTER PA -> 'p' */
+ { 0xAC, 0x62 }, /* KANNADA LETTER BA -> 'b' */
+ { 0xAE, 0x6D }, /* KANNADA LETTER MA -> 'm' */
+ { 0xAF, 0x79 }, /* KANNADA LETTER YA -> 'y' */
+ { 0xB0, 0x72 }, /* KANNADA LETTER RA -> 'r' */
+ { 0xB2, 0x6C }, /* KANNADA LETTER LA -> 'l' */
+ { 0xB5, 0x76 }, /* KANNADA LETTER VA -> 'v' */
+ { 0xB8, 0x73 }, /* KANNADA LETTER SA -> 's' */
+ { 0xB9, 0x68 }, /* KANNADA LETTER HA -> 'h' */
+ { 0xBF, 0x69 }, /* KANNADA VOWEL SIGN I -> 'i' */
+ { 0xC1, 0x75 }, /* KANNADA VOWEL SIGN U -> 'u' */
+ { 0xC3, 0x52 }, /* KANNADA VOWEL SIGN VOCALIC R -> 'R' */
+ { 0xC6, 0x65 }, /* KANNADA VOWEL SIGN E -> 'e' */
+ { 0xCA, 0x6F }, /* KANNADA VOWEL SIGN O -> 'o' */
+ { 0xD5, 0x2B }, /* KANNADA LENGTH MARK -> '+' */
+ { 0xD6, 0x2B }, /* KANNADA AI LENGTH MARK -> '+' */
+ { 0xE6, 0x30 }, /* KANNADA DIGIT ZERO -> '0' */
+ { 0xE7, 0x31 }, /* KANNADA DIGIT ONE -> '1' */
+ { 0xE8, 0x32 }, /* KANNADA DIGIT TWO -> '2' */
+ { 0xE9, 0x33 }, /* KANNADA DIGIT THREE -> '3' */
+ { 0xEA, 0x34 }, /* KANNADA DIGIT FOUR -> '4' */
+ { 0xEB, 0x35 }, /* KANNADA DIGIT FIVE -> '5' */
+ { 0xEC, 0x36 }, /* KANNADA DIGIT SIX -> '6' */
+ { 0xED, 0x37 }, /* KANNADA DIGIT SEVEN -> '7' */
+ { 0xEE, 0x38 }, /* KANNADA DIGIT EIGHT -> '8' */
+ { 0xEF, 0x39 }, /* KANNADA DIGIT NINE -> '9' */
+ /* Entries for page 0x0D */
+ { 0x02, 0x4E }, /* MALAYALAM SIGN ANUSVARA -> 'N' */
+ { 0x03, 0x48 }, /* MALAYALAM SIGN VISARGA -> 'H' */
+ { 0x05, 0x61 }, /* MALAYALAM LETTER A -> 'a' */
+ { 0x07, 0x69 }, /* MALAYALAM LETTER I -> 'i' */
+ { 0x09, 0x75 }, /* MALAYALAM LETTER U -> 'u' */
+ { 0x0B, 0x52 }, /* MALAYALAM LETTER VOCALIC R -> 'R' */
+ { 0x0C, 0x4C }, /* MALAYALAM LETTER VOCALIC L -> 'L' */
+ { 0x0E, 0x65 }, /* MALAYALAM LETTER E -> 'e' */
+ { 0x12, 0x6F }, /* MALAYALAM LETTER O -> 'o' */
+ { 0x15, 0x6B }, /* MALAYALAM LETTER KA -> 'k' */
+ { 0x17, 0x67 }, /* MALAYALAM LETTER GA -> 'g' */
+ { 0x1A, 0x63 }, /* MALAYALAM LETTER CA -> 'c' */
+ { 0x1C, 0x6A }, /* MALAYALAM LETTER JA -> 'j' */
+ { 0x24, 0x74 }, /* MALAYALAM LETTER TA -> 't' */
+ { 0x26, 0x64 }, /* MALAYALAM LETTER DA -> 'd' */
+ { 0x28, 0x6E }, /* MALAYALAM LETTER NA -> 'n' */
+ { 0x2A, 0x70 }, /* MALAYALAM LETTER PA -> 'p' */
+ { 0x2C, 0x62 }, /* MALAYALAM LETTER BA -> 'b' */
+ { 0x2E, 0x6D }, /* MALAYALAM LETTER MA -> 'm' */
+ { 0x2F, 0x79 }, /* MALAYALAM LETTER YA -> 'y' */
+ { 0x30, 0x72 }, /* MALAYALAM LETTER RA -> 'r' */
+ { 0x32, 0x6C }, /* MALAYALAM LETTER LA -> 'l' */
+ { 0x35, 0x76 }, /* MALAYALAM LETTER VA -> 'v' */
+ { 0x38, 0x73 }, /* MALAYALAM LETTER SA -> 's' */
+ { 0x39, 0x68 }, /* MALAYALAM LETTER HA -> 'h' */
+ { 0x3F, 0x69 }, /* MALAYALAM VOWEL SIGN I -> 'i' */
+ { 0x41, 0x75 }, /* MALAYALAM VOWEL SIGN U -> 'u' */
+ { 0x43, 0x52 }, /* MALAYALAM VOWEL SIGN VOCALIC R -> 'R' */
+ { 0x46, 0x65 }, /* MALAYALAM VOWEL SIGN E -> 'e' */
+ { 0x4A, 0x6F }, /* MALAYALAM VOWEL SIGN O -> 'o' */
+ { 0x57, 0x2B }, /* MALAYALAM AU LENGTH MARK -> '+' */
+ { 0x66, 0x30 }, /* MALAYALAM DIGIT ZERO -> '0' */
+ { 0x67, 0x31 }, /* MALAYALAM DIGIT ONE -> '1' */
+ { 0x68, 0x32 }, /* MALAYALAM DIGIT TWO -> '2' */
+ { 0x69, 0x33 }, /* MALAYALAM DIGIT THREE -> '3' */
+ { 0x6A, 0x34 }, /* MALAYALAM DIGIT FOUR -> '4' */
+ { 0x6B, 0x35 }, /* MALAYALAM DIGIT FIVE -> '5' */
+ { 0x6C, 0x36 }, /* MALAYALAM DIGIT SIX -> '6' */
+ { 0x6D, 0x37 }, /* MALAYALAM DIGIT SEVEN -> '7' */
+ { 0x6E, 0x38 }, /* MALAYALAM DIGIT EIGHT -> '8' */
+ { 0x6F, 0x39 }, /* MALAYALAM DIGIT NINE -> '9' */
+ { 0x82, 0x4E }, /* SINHALA SIGN ANUSVARAYA -> 'N' */
+ { 0x83, 0x48 }, /* SINHALA SIGN VISARGAYA -> 'H' */
+ { 0x85, 0x61 }, /* SINHALA LETTER AYANNA -> 'a' */
+ { 0x89, 0x69 }, /* SINHALA LETTER IYANNA -> 'i' */
+ { 0x8B, 0x75 }, /* SINHALA LETTER UYANNA -> 'u' */
+ { 0x8D, 0x52 }, /* SINHALA LETTER IRUYANNA -> 'R' */
+ { 0x8F, 0x4C }, /* SINHALA LETTER ILUYANNA -> 'L' */
+ { 0x91, 0x65 }, /* SINHALA LETTER EYANNA -> 'e' */
+ { 0x94, 0x6F }, /* SINHALA LETTER OYANNA -> 'o' */
+ { 0x9A, 0x6B }, /* SINHALA LETTER ALPAPRAANA KAYANNA -> 'k' */
+ { 0x9C, 0x67 }, /* SINHALA LETTER ALPAPRAANA GAYANNA -> 'g' */
+ { 0xA0, 0x63 }, /* SINHALA LETTER ALPAPRAANA CAYANNA -> 'c' */
+ { 0xA2, 0x6A }, /* SINHALA LETTER ALPAPRAANA JAYANNA -> 'j' */
+ { 0xAD, 0x74 }, /* SINHALA LETTER ALPAPRAANA TAYANNA -> 't' */
+ { 0xAF, 0x64 }, /* SINHALA LETTER ALPAPRAANA DAYANNA -> 'd' */
+ { 0xB1, 0x6E }, /* SINHALA LETTER DANTAJA NAYANNA -> 'n' */
+ { 0xB4, 0x70 }, /* SINHALA LETTER ALPAPRAANA PAYANNA -> 'p' */
+ { 0xB6, 0x62 }, /* SINHALA LETTER ALPAPRAANA BAYANNA -> 'b' */
+ { 0xB8, 0x6D }, /* SINHALA LETTER MAYANNA -> 'm' */
+ { 0xBA, 0x79 }, /* SINHALA LETTER YAYANNA -> 'y' */
+ { 0xBB, 0x72 }, /* SINHALA LETTER RAYANNA -> 'r' */
+ { 0xBD, 0x6C }, /* SINHALA LETTER DANTAJA LAYANNA -> 'l' */
+ { 0xC0, 0x76 }, /* SINHALA LETTER VAYANNA -> 'v' */
+ { 0xC3, 0x73 }, /* SINHALA LETTER DANTAJA SAYANNA -> 's' */
+ { 0xC4, 0x68 }, /* SINHALA LETTER HAYANNA -> 'h' */
+ { 0xC6, 0x66 }, /* SINHALA LETTER FAYANNA -> 'f' */
+ { 0xD2, 0x69 }, /* SINHALA VOWEL SIGN KETTI IS-PILLA -> 'i' */
+ { 0xD4, 0x75 }, /* SINHALA VOWEL SIGN KETTI PAA-PILLA -> 'u' */
+ { 0xD8, 0x52 }, /* SINHALA VOWEL SIGN GAETTA-PILLA -> 'R' */
+ { 0xD9, 0x65 }, /* SINHALA VOWEL SIGN KOMBUVA -> 'e' */
+ { 0xDC, 0x6F }, /* SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA -> 'o' */
+ { 0xDF, 0x4C }, /* SINHALA VOWEL SIGN GAYANUKITTA -> 'L' */
+ /* Entries for page 0x0E */
+ { 0x01, 0x6B }, /* THAI CHARACTER KO KAI -> 'k' */
+ { 0x0D, 0x79 }, /* THAI CHARACTER YO YING -> 'y' */
+ { 0x0E, 0x64 }, /* THAI CHARACTER DO CHADA -> 'd' */
+ { 0x0F, 0x74 }, /* THAI CHARACTER TO PATAK -> 't' */
+ { 0x13, 0x6E }, /* THAI CHARACTER NO NEN -> 'n' */
+ { 0x14, 0x64 }, /* THAI CHARACTER DO DEK -> 'd' */
+ { 0x15, 0x74 }, /* THAI CHARACTER TO TAO -> 't' */
+ { 0x19, 0x6E }, /* THAI CHARACTER NO NU -> 'n' */
+ { 0x1A, 0x62 }, /* THAI CHARACTER BO BAIMAI -> 'b' */
+ { 0x1B, 0x70 }, /* THAI CHARACTER PO PLA -> 'p' */
+ { 0x1D, 0x66 }, /* THAI CHARACTER FO FA -> 'f' */
+ { 0x1F, 0x66 }, /* THAI CHARACTER FO FAN -> 'f' */
+ { 0x21, 0x6D }, /* THAI CHARACTER MO MA -> 'm' */
+ { 0x22, 0x79 }, /* THAI CHARACTER YO YAK -> 'y' */
+ { 0x23, 0x72 }, /* THAI CHARACTER RO RUA -> 'r' */
+ { 0x24, 0x52 }, /* THAI CHARACTER RU -> 'R' */
+ { 0x25, 0x6C }, /* THAI CHARACTER LO LING -> 'l' */
+ { 0x26, 0x4C }, /* THAI CHARACTER LU -> 'L' */
+ { 0x27, 0x77 }, /* THAI CHARACTER WO WAEN -> 'w' */
+ { 0x28, 0x00 }, /* THAI CHARACTER SO SALA -> ... */
+ { 0x2A, 0x73 }, /* THAI CHARACTER SO SUA -> 's' */
+ { 0x2B, 0x68 }, /* THAI CHARACTER HO HIP -> 'h' */
+ { 0x2C, 0x6C }, /* THAI CHARACTER LO CHULA -> 'l' */
+ { 0x2D, 0x60 }, /* THAI CHARACTER O ANG -> '`' */
+ { 0x2E, 0x68 }, /* THAI CHARACTER HO NOKHUK -> 'h' */
+ { 0x2F, 0x7E }, /* THAI CHARACTER PAIYANNOI -> '~' */
+ { 0x30, 0x61 }, /* THAI CHARACTER SARA A -> 'a' */
+ { 0x31, 0x61 }, /* THAI CHARACTER MAI HAN-AKAT -> 'a' */
+ { 0x34, 0x69 }, /* THAI CHARACTER SARA I -> 'i' */
+ { 0x38, 0x75 }, /* THAI CHARACTER SARA U -> 'u' */
+ { 0x3A, 0x27 }, /* THAI CHARACTER PHINTHU -> ''' */
+ { 0x40, 0x65 }, /* THAI CHARACTER SARA E -> 'e' */
+ { 0x42, 0x6F }, /* THAI CHARACTER SARA O -> 'o' */
+ { 0x46, 0x2B }, /* THAI CHARACTER MAIYAMOK -> '+' */
+ { 0x4D, 0x4D }, /* THAI CHARACTER NIKHAHIT -> 'M' */
+ { 0x50, 0x30 }, /* THAI DIGIT ZERO -> '0' */
+ { 0x51, 0x31 }, /* THAI DIGIT ONE -> '1' */
+ { 0x52, 0x32 }, /* THAI DIGIT TWO -> '2' */
+ { 0x53, 0x33 }, /* THAI DIGIT THREE -> '3' */
+ { 0x54, 0x34 }, /* THAI DIGIT FOUR -> '4' */
+ { 0x55, 0x35 }, /* THAI DIGIT FIVE -> '5' */
+ { 0x56, 0x36 }, /* THAI DIGIT SIX -> '6' */
+ { 0x57, 0x37 }, /* THAI DIGIT SEVEN -> '7' */
+ { 0x58, 0x38 }, /* THAI DIGIT EIGHT -> '8' */
+ { 0x59, 0x39 }, /* THAI DIGIT NINE -> '9' */
+ { 0x81, 0x6B }, /* LAO LETTER KO -> 'k' */
+ { 0x8A, 0x73 }, /* LAO LETTER SO TAM -> 's' */
+ { 0x94, 0x64 }, /* LAO LETTER DO -> 'd' */
+ { 0x95, 0x68 }, /* LAO LETTER TO -> 'h' */
+ { 0x99, 0x6E }, /* LAO LETTER NO -> 'n' */
+ { 0x9A, 0x62 }, /* LAO LETTER BO -> 'b' */
+ { 0x9B, 0x70 }, /* LAO LETTER PO -> 'p' */
+ { 0x9D, 0x66 }, /* LAO LETTER FO TAM -> 'f' */
+ { 0x9F, 0x66 }, /* LAO LETTER FO SUNG -> 'f' */
+ { 0xA1, 0x6D }, /* LAO LETTER MO -> 'm' */
+ { 0xA2, 0x79 }, /* LAO LETTER YO -> 'y' */
+ { 0xA3, 0x72 }, /* LAO LETTER LO LING -> 'r' */
+ { 0xA5, 0x6C }, /* LAO LETTER LO LOOT -> 'l' */
+ { 0xA7, 0x77 }, /* LAO LETTER WO -> 'w' */
+ { 0xAA, 0x73 }, /* LAO LETTER SO SUNG -> 's' */
+ { 0xAB, 0x68 }, /* LAO LETTER HO SUNG -> 'h' */
+ { 0xAD, 0x60 }, /* LAO LETTER O -> '`' */
+ { 0xAF, 0x7E }, /* LAO ELLIPSIS -> '~' */
+ { 0xB0, 0x61 }, /* LAO VOWEL SIGN A -> 'a' */
+ { 0xB4, 0x69 }, /* LAO VOWEL SIGN I -> 'i' */
+ { 0xB6, 0x79 }, /* LAO VOWEL SIGN Y -> 'y' */
+ { 0xB8, 0x75 }, /* LAO VOWEL SIGN U -> 'u' */
+ { 0xBB, 0x6F }, /* LAO VOWEL SIGN MAI KON -> 'o' */
+ { 0xBC, 0x6C }, /* LAO SEMIVOWEL SIGN LO -> 'l' */
+ { 0xC0, 0x65 }, /* LAO VOWEL SIGN E -> 'e' */
+ { 0xC2, 0x6F }, /* LAO VOWEL SIGN O -> 'o' */
+ { 0xC6, 0x2B }, /* LAO KO LA -> '+' */
+ { 0xCD, 0x4D }, /* LAO NIGGAHITA -> 'M' */
+ { 0xD0, 0x30 }, /* LAO DIGIT ZERO -> '0' */
+ { 0xD1, 0x31 }, /* LAO DIGIT ONE -> '1' */
+ { 0xD2, 0x32 }, /* LAO DIGIT TWO -> '2' */
+ { 0xD3, 0x33 }, /* LAO DIGIT THREE -> '3' */
+ { 0xD4, 0x34 }, /* LAO DIGIT FOUR -> '4' */
+ { 0xD5, 0x35 }, /* LAO DIGIT FIVE -> '5' */
+ { 0xD6, 0x36 }, /* LAO DIGIT SIX -> '6' */
+ { 0xD7, 0x37 }, /* LAO DIGIT SEVEN -> '7' */
+ { 0xD8, 0x38 }, /* LAO DIGIT EIGHT -> '8' */
+ { 0xD9, 0x39 }, /* LAO DIGIT NINE -> '9' */
+ /* Entries for page 0x0F */
+ { 0x0B, 0x2D }, /* TIBETAN MARK INTERSYLLABIC TSHEG -> '-' */
+ { 0x20, 0x30 }, /* TIBETAN DIGIT ZERO -> '0' */
+ { 0x21, 0x31 }, /* TIBETAN DIGIT ONE -> '1' */
+ { 0x22, 0x32 }, /* TIBETAN DIGIT TWO -> '2' */
+ { 0x23, 0x33 }, /* TIBETAN DIGIT THREE -> '3' */
+ { 0x24, 0x34 }, /* TIBETAN DIGIT FOUR -> '4' */
+ { 0x25, 0x35 }, /* TIBETAN DIGIT FIVE -> '5' */
+ { 0x26, 0x36 }, /* TIBETAN DIGIT SIX -> '6' */
+ { 0x27, 0x37 }, /* TIBETAN DIGIT SEVEN -> '7' */
+ { 0x28, 0x38 }, /* TIBETAN DIGIT EIGHT -> '8' */
+ { 0x29, 0x39 }, /* TIBETAN DIGIT NINE -> '9' */
+ { 0x34, 0x2B }, /* TIBETAN MARK BSDUS RTAGS -> '+' */
+ { 0x35, 0x2A }, /* TIBETAN MARK NGAS BZUNG NYI ZLA -> '*' */
+ { 0x36, 0x5E }, /* TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN -> '^' */
+ { 0x37, 0x5F }, /* TIBETAN MARK NGAS BZUNG SGOR RTAGS -> '_' */
+ { 0x39, 0x7E }, /* TIBETAN MARK TSA -PHRU -> '~' */
+ { 0x3B, 0x5D }, /* TIBETAN MARK GUG RTAGS GYAS -> ']' */
+ { 0x40, 0x6B }, /* TIBETAN LETTER KA -> 'k' */
+ { 0x42, 0x67 }, /* TIBETAN LETTER GA -> 'g' */
+ { 0x45, 0x63 }, /* TIBETAN LETTER CA -> 'c' */
+ { 0x47, 0x6A }, /* TIBETAN LETTER JA -> 'j' */
+ { 0x4F, 0x74 }, /* TIBETAN LETTER TA -> 't' */
+ { 0x51, 0x64 }, /* TIBETAN LETTER DA -> 'd' */
+ { 0x53, 0x6E }, /* TIBETAN LETTER NA -> 'n' */
+ { 0x54, 0x70 }, /* TIBETAN LETTER PA -> 'p' */
+ { 0x56, 0x62 }, /* TIBETAN LETTER BA -> 'b' */
+ { 0x58, 0x6D }, /* TIBETAN LETTER MA -> 'm' */
+ { 0x5D, 0x77 }, /* TIBETAN LETTER WA -> 'w' */
+ { 0x5F, 0x7A }, /* TIBETAN LETTER ZA -> 'z' */
+ { 0x60, 0x27 }, /* TIBETAN LETTER -A -> ''' */
+ { 0x61, 0x79 }, /* TIBETAN LETTER YA -> 'y' */
+ { 0x62, 0x72 }, /* TIBETAN LETTER RA -> 'r' */
+ { 0x63, 0x6C }, /* TIBETAN LETTER LA -> 'l' */
+ { 0x66, 0x73 }, /* TIBETAN LETTER SA -> 's' */
+ { 0x67, 0x68 }, /* TIBETAN LETTER HA -> 'h' */
+ { 0x68, 0x61 }, /* TIBETAN LETTER A -> 'a' */
+ { 0x6A, 0x72 }, /* TIBETAN LETTER FIXED-FORM RA -> 'r' */
+ { 0x72, 0x69 }, /* TIBETAN VOWEL SIGN I -> 'i' */
+ { 0x74, 0x75 }, /* TIBETAN VOWEL SIGN U -> 'u' */
+ { 0x76, 0x52 }, /* TIBETAN VOWEL SIGN VOCALIC R -> 'R' */
+ { 0x78, 0x4C }, /* TIBETAN VOWEL SIGN VOCALIC L -> 'L' */
+ { 0x7A, 0x65 }, /* TIBETAN VOWEL SIGN E -> 'e' */
+ { 0x7C, 0x6F }, /* TIBETAN VOWEL SIGN O -> 'o' */
+ { 0x7E, 0x4D }, /* TIBETAN SIGN RJES SU NGA RO -> 'M' */
+ { 0x7F, 0x48 }, /* TIBETAN SIGN RNAM BCAD -> 'H' */
+ { 0x80, 0x69 }, /* TIBETAN VOWEL SIGN REVERSED I -> 'i' */
+ { 0x90, 0x6B }, /* TIBETAN SUBJOINED LETTER KA -> 'k' */
+ { 0x92, 0x67 }, /* TIBETAN SUBJOINED LETTER GA -> 'g' */
+ { 0x95, 0x63 }, /* TIBETAN SUBJOINED LETTER CA -> 'c' */
+ { 0x97, 0x6A }, /* TIBETAN SUBJOINED LETTER JA -> 'j' */
+ { 0x9F, 0x74 }, /* TIBETAN SUBJOINED LETTER TA -> 't' */
+ { 0xA1, 0x64 }, /* TIBETAN SUBJOINED LETTER DA -> 'd' */
+ { 0xA3, 0x6E }, /* TIBETAN SUBJOINED LETTER NA -> 'n' */
+ { 0xA4, 0x70 }, /* TIBETAN SUBJOINED LETTER PA -> 'p' */
+ { 0xA6, 0x62 }, /* TIBETAN SUBJOINED LETTER BA -> 'b' */
+ { 0xA8, 0x6D }, /* TIBETAN SUBJOINED LETTER MA -> 'm' */
+ { 0xAD, 0x77 }, /* TIBETAN SUBJOINED LETTER WA -> 'w' */
+ { 0xAF, 0x7A }, /* TIBETAN SUBJOINED LETTER ZA -> 'z' */
+ { 0xB0, 0x27 }, /* TIBETAN SUBJOINED LETTER -A -> ''' */
+ { 0xB1, 0x79 }, /* TIBETAN SUBJOINED LETTER YA -> 'y' */
+ { 0xB2, 0x72 }, /* TIBETAN SUBJOINED LETTER RA -> 'r' */
+ { 0xB3, 0x6C }, /* TIBETAN SUBJOINED LETTER LA -> 'l' */
+ { 0xB6, 0x73 }, /* TIBETAN SUBJOINED LETTER SA -> 's' */
+ { 0xB7, 0x68 }, /* TIBETAN SUBJOINED LETTER HA -> 'h' */
+ { 0xB8, 0x61 }, /* TIBETAN SUBJOINED LETTER A -> 'a' */
+ { 0xBA, 0x77 }, /* TIBETAN SUBJOINED LETTER FIXED-FORM WA -> 'w' */
+ { 0xBB, 0x79 }, /* TIBETAN SUBJOINED LETTER FIXED-FORM YA -> 'y' */
+ { 0xBC, 0x72 }, /* TIBETAN SUBJOINED LETTER FIXED-FORM RA -> 'r' */
+ { 0xBE, 0x58 }, /* TIBETAN KU RU KHA -> 'X' */
+ /* Entries for page 0x10 */
+ { 0x00, 0x6B }, /* MYANMAR LETTER KA -> 'k' */
+ { 0x02, 0x67 }, /* MYANMAR LETTER GA -> 'g' */
+ { 0x05, 0x63 }, /* MYANMAR LETTER CA -> 'c' */
+ { 0x07, 0x6A }, /* MYANMAR LETTER JA -> 'j' */
+ { 0x12, 0x64 }, /* MYANMAR LETTER DA -> 'd' */
+ { 0x14, 0x6E }, /* MYANMAR LETTER NA -> 'n' */
+ { 0x15, 0x70 }, /* MYANMAR LETTER PA -> 'p' */
+ { 0x17, 0x62 }, /* MYANMAR LETTER BA -> 'b' */
+ { 0x19, 0x6D }, /* MYANMAR LETTER MA -> 'm' */
+ { 0x1A, 0x79 }, /* MYANMAR LETTER YA -> 'y' */
+ { 0x1B, 0x72 }, /* MYANMAR LETTER RA -> 'r' */
+ { 0x1C, 0x6C }, /* MYANMAR LETTER LA -> 'l' */
+ { 0x1D, 0x77 }, /* MYANMAR LETTER WA -> 'w' */
+ { 0x1E, 0x73 }, /* MYANMAR LETTER SA -> 's' */
+ { 0x1F, 0x68 }, /* MYANMAR LETTER HA -> 'h' */
+ { 0x21, 0x61 }, /* MYANMAR LETTER A -> 'a' */
+ { 0x23, 0x69 }, /* MYANMAR LETTER I -> 'i' */
+ { 0x25, 0x75 }, /* MYANMAR LETTER U -> 'u' */
+ { 0x27, 0x65 }, /* MYANMAR LETTER E -> 'e' */
+ { 0x29, 0x6F }, /* MYANMAR LETTER O -> 'o' */
+ { 0x2D, 0x69 }, /* MYANMAR VOWEL SIGN I -> 'i' */
+ { 0x2F, 0x75 }, /* MYANMAR VOWEL SIGN U -> 'u' */
+ { 0x31, 0x65 }, /* MYANMAR VOWEL SIGN E -> 'e' */
+ { 0x36, 0x4E }, /* MYANMAR SIGN ANUSVARA -> 'N' */
+ { 0x37, 0x27 }, /* MYANMAR SIGN DOT BELOW -> ''' */
+ { 0x38, 0x3A }, /* MYANMAR SIGN VISARGA -> ':' */
+ { 0x40, 0x30 }, /* MYANMAR DIGIT ZERO -> '0' */
+ { 0x41, 0x31 }, /* MYANMAR DIGIT ONE -> '1' */
+ { 0x42, 0x32 }, /* MYANMAR DIGIT TWO -> '2' */
+ { 0x43, 0x33 }, /* MYANMAR DIGIT THREE -> '3' */
+ { 0x44, 0x34 }, /* MYANMAR DIGIT FOUR -> '4' */
+ { 0x45, 0x35 }, /* MYANMAR DIGIT FIVE -> '5' */
+ { 0x46, 0x36 }, /* MYANMAR DIGIT SIX -> '6' */
+ { 0x47, 0x37 }, /* MYANMAR DIGIT SEVEN -> '7' */
+ { 0x48, 0x38 }, /* MYANMAR DIGIT EIGHT -> '8' */
+ { 0x49, 0x39 }, /* MYANMAR DIGIT NINE -> '9' */
+ { 0x52, 0x52 }, /* MYANMAR LETTER VOCALIC R -> 'R' */
+ { 0x54, 0x4C }, /* MYANMAR LETTER VOCALIC L -> 'L' */
+ { 0x56, 0x52 }, /* MYANMAR VOWEL SIGN VOCALIC R -> 'R' */
+ { 0x58, 0x4C }, /* MYANMAR VOWEL SIGN VOCALIC L -> 'L' */
+ { 0xA0, 0x41 }, /* GEORGIAN CAPITAL LETTER AN -> 'A' */
+ { 0xA1, 0x42 }, /* GEORGIAN CAPITAL LETTER BAN -> 'B' */
+ { 0xA2, 0x47 }, /* GEORGIAN CAPITAL LETTER GAN -> 'G' */
+ { 0xA3, 0x44 }, /* GEORGIAN CAPITAL LETTER DON -> 'D' */
+ { 0xA4, 0x45 }, /* GEORGIAN CAPITAL LETTER EN -> 'E' */
+ { 0xA5, 0x56 }, /* GEORGIAN CAPITAL LETTER VIN -> 'V' */
+ { 0xA6, 0x5A }, /* GEORGIAN CAPITAL LETTER ZEN -> 'Z' */
+ { 0xA8, 0x49 }, /* GEORGIAN CAPITAL LETTER IN -> 'I' */
+ { 0xA9, 0x4B }, /* GEORGIAN CAPITAL LETTER KAN -> 'K' */
+ { 0xAA, 0x4C }, /* GEORGIAN CAPITAL LETTER LAS -> 'L' */
+ { 0xAB, 0x4D }, /* GEORGIAN CAPITAL LETTER MAN -> 'M' */
+ { 0xAC, 0x4E }, /* GEORGIAN CAPITAL LETTER NAR -> 'N' */
+ { 0xAD, 0x4F }, /* GEORGIAN CAPITAL LETTER ON -> 'O' */
+ { 0xAE, 0x50 }, /* GEORGIAN CAPITAL LETTER PAR -> 'P' */
+ { 0xB0, 0x52 }, /* GEORGIAN CAPITAL LETTER RAE -> 'R' */
+ { 0xB1, 0x53 }, /* GEORGIAN CAPITAL LETTER SAN -> 'S' */
+ { 0xB2, 0x54 }, /* GEORGIAN CAPITAL LETTER TAR -> 'T' */
+ { 0xB3, 0x55 }, /* GEORGIAN CAPITAL LETTER UN -> 'U' */
+ { 0xB7, 0x51 }, /* GEORGIAN CAPITAL LETTER QAR -> 'Q' */
+ { 0xBC, 0x43 }, /* GEORGIAN CAPITAL LETTER CIL -> 'C' */
+ { 0xBE, 0x58 }, /* GEORGIAN CAPITAL LETTER XAN -> 'X' */
+ { 0xBF, 0x4A }, /* GEORGIAN CAPITAL LETTER JHAN -> 'J' */
+ { 0xC0, 0x48 }, /* GEORGIAN CAPITAL LETTER HAE -> 'H' */
+ { 0xC1, 0x45 }, /* GEORGIAN CAPITAL LETTER HE -> 'E' */
+ { 0xC2, 0x59 }, /* GEORGIAN CAPITAL LETTER HIE -> 'Y' */
+ { 0xC3, 0x57 }, /* GEORGIAN CAPITAL LETTER WE -> 'W' */
+ { 0xD0, 0x61 }, /* GEORGIAN LETTER AN -> 'a' */
+ { 0xD1, 0x62 }, /* GEORGIAN LETTER BAN -> 'b' */
+ { 0xD2, 0x67 }, /* GEORGIAN LETTER GAN -> 'g' */
+ { 0xD3, 0x64 }, /* GEORGIAN LETTER DON -> 'd' */
+ { 0xD4, 0x65 }, /* GEORGIAN LETTER EN -> 'e' */
+ { 0xD5, 0x76 }, /* GEORGIAN LETTER VIN -> 'v' */
+ { 0xD6, 0x7A }, /* GEORGIAN LETTER ZEN -> 'z' */
+ { 0xD8, 0x69 }, /* GEORGIAN LETTER IN -> 'i' */
+ { 0xD9, 0x6B }, /* GEORGIAN LETTER KAN -> 'k' */
+ { 0xDA, 0x6C }, /* GEORGIAN LETTER LAS -> 'l' */
+ { 0xDB, 0x6D }, /* GEORGIAN LETTER MAN -> 'm' */
+ { 0xDC, 0x6E }, /* GEORGIAN LETTER NAR -> 'n' */
+ { 0xDD, 0x6F }, /* GEORGIAN LETTER ON -> 'o' */
+ { 0xDE, 0x70 }, /* GEORGIAN LETTER PAR -> 'p' */
+ { 0xE0, 0x72 }, /* GEORGIAN LETTER RAE -> 'r' */
+ { 0xE1, 0x73 }, /* GEORGIAN LETTER SAN -> 's' */
+ { 0xE2, 0x74 }, /* GEORGIAN LETTER TAR -> 't' */
+ { 0xE3, 0x75 }, /* GEORGIAN LETTER UN -> 'u' */
+ { 0xE7, 0x71 }, /* GEORGIAN LETTER QAR -> 'q' */
+ { 0xEC, 0x63 }, /* GEORGIAN LETTER CIL -> 'c' */
+ { 0xEE, 0x78 }, /* GEORGIAN LETTER XAN -> 'x' */
+ { 0xEF, 0x6A }, /* GEORGIAN LETTER JHAN -> 'j' */
+ { 0xF0, 0x68 }, /* GEORGIAN LETTER HAE -> 'h' */
+ { 0xF1, 0x65 }, /* GEORGIAN LETTER HE -> 'e' */
+ { 0xF2, 0x79 }, /* GEORGIAN LETTER HIE -> 'y' */
+ { 0xF3, 0x77 }, /* GEORGIAN LETTER WE -> 'w' */
+ { 0xF6, 0x66 }, /* GEORGIAN LETTER FI -> 'f' */
+ /* Entries for page 0x11 */
+ { 0x00, 0x67 }, /* HANGUL CHOSEONG KIYEOK -> 'g' */
+ { 0x02, 0x6E }, /* HANGUL CHOSEONG NIEUN -> 'n' */
+ { 0x03, 0x64 }, /* HANGUL CHOSEONG TIKEUT -> 'd' */
+ { 0x05, 0x72 }, /* HANGUL CHOSEONG RIEUL -> 'r' */
+ { 0x06, 0x6D }, /* HANGUL CHOSEONG MIEUM -> 'm' */
+ { 0x07, 0x62 }, /* HANGUL CHOSEONG PIEUP -> 'b' */
+ { 0x09, 0x73 }, /* HANGUL CHOSEONG SIOS -> 's' */
+ { 0x0C, 0x6A }, /* HANGUL CHOSEONG CIEUC -> 'j' */
+ { 0x0E, 0x63 }, /* HANGUL CHOSEONG CHIEUCH -> 'c' */
+ { 0x0F, 0x6B }, /* HANGUL CHOSEONG KHIEUKH -> 'k' */
+ { 0x10, 0x74 }, /* HANGUL CHOSEONG THIEUTH -> 't' */
+ { 0x11, 0x70 }, /* HANGUL CHOSEONG PHIEUPH -> 'p' */
+ { 0x12, 0x68 }, /* HANGUL CHOSEONG HIEUH -> 'h' */
+ { 0x35, 0x73 }, /* HANGUL CHOSEONG SIOS-IEUNG -> 's' */
+ { 0x40, 0x5A }, /* HANGUL CHOSEONG PANSIOS -> 'Z' */
+ { 0x41, 0x67 }, /* HANGUL CHOSEONG IEUNG-KIYEOK -> 'g' */
+ { 0x42, 0x64 }, /* HANGUL CHOSEONG IEUNG-TIKEUT -> 'd' */
+ { 0x43, 0x6D }, /* HANGUL CHOSEONG IEUNG-MIEUM -> 'm' */
+ { 0x44, 0x62 }, /* HANGUL CHOSEONG IEUNG-PIEUP -> 'b' */
+ { 0x45, 0x73 }, /* HANGUL CHOSEONG IEUNG-SIOS -> 's' */
+ { 0x46, 0x5A }, /* HANGUL CHOSEONG IEUNG-PANSIOS -> 'Z' */
+ { 0x48, 0x6A }, /* HANGUL CHOSEONG IEUNG-CIEUC -> 'j' */
+ { 0x49, 0x63 }, /* HANGUL CHOSEONG IEUNG-CHIEUCH -> 'c' */
+ { 0x4A, 0x74 }, /* HANGUL CHOSEONG IEUNG-THIEUTH -> 't' */
+ { 0x4B, 0x70 }, /* HANGUL CHOSEONG IEUNG-PHIEUPH -> 'p' */
+ { 0x4C, 0x4E }, /* HANGUL CHOSEONG YESIEUNG -> 'N' */
+ { 0x4D, 0x6A }, /* HANGUL CHOSEONG CIEUC-IEUNG -> 'j' */
+ { 0x59, 0x51 }, /* HANGUL CHOSEONG YEORINHIEUH -> 'Q' */
+ { 0x61, 0x61 }, /* HANGUL JUNGSEONG A -> 'a' */
+ { 0x66, 0x65 }, /* HANGUL JUNGSEONG E -> 'e' */
+ { 0x69, 0x6F }, /* HANGUL JUNGSEONG O -> 'o' */
+ { 0x6E, 0x75 }, /* HANGUL JUNGSEONG U -> 'u' */
+ { 0x75, 0x69 }, /* HANGUL JUNGSEONG I -> 'i' */
+ { 0x9E, 0x55 }, /* HANGUL JUNGSEONG ARAEA -> 'U' */
+ { 0xA8, 0x67 }, /* HANGUL JONGSEONG KIYEOK -> 'g' */
+ { 0xAB, 0x6E }, /* HANGUL JONGSEONG NIEUN -> 'n' */
+ { 0xAE, 0x64 }, /* HANGUL JONGSEONG TIKEUT -> 'd' */
+ { 0xAF, 0x6C }, /* HANGUL JONGSEONG RIEUL -> 'l' */
+ { 0xB7, 0x6D }, /* HANGUL JONGSEONG MIEUM -> 'm' */
+ { 0xB8, 0x62 }, /* HANGUL JONGSEONG PIEUP -> 'b' */
+ { 0xBA, 0x73 }, /* HANGUL JONGSEONG SIOS -> 's' */
+ { 0xBD, 0x6A }, /* HANGUL JONGSEONG CIEUC -> 'j' */
+ { 0xBE, 0x63 }, /* HANGUL JONGSEONG CHIEUCH -> 'c' */
+ { 0xBF, 0x6B }, /* HANGUL JONGSEONG KHIEUKH -> 'k' */
+ { 0xC0, 0x74 }, /* HANGUL JONGSEONG THIEUTH -> 't' */
+ { 0xC1, 0x70 }, /* HANGUL JONGSEONG PHIEUPH -> 'p' */
+ { 0xC2, 0x68 }, /* HANGUL JONGSEONG HIEUH -> 'h' */
+ { 0xEB, 0x5A }, /* HANGUL JONGSEONG PANSIOS -> 'Z' */
+ { 0xEC, 0x67 }, /* HANGUL JONGSEONG IEUNG-KIYEOK -> 'g' */
+ { 0xF0, 0x4E }, /* HANGUL JONGSEONG YESIEUNG -> 'N' */
+ { 0xF9, 0x51 }, /* HANGUL JONGSEONG YEORINHIEUH -> 'Q' */
+ /* Entries for page 0x13 */
+ { 0x61, 0x20 }, /* ETHIOPIC WORDSPACE -> ' ' */
+ { 0x62, 0x2E }, /* ETHIOPIC FULL STOP -> '.' */
+ { 0x63, 0x2C }, /* ETHIOPIC COMMA -> ',' */
+ { 0x64, 0x3B }, /* ETHIOPIC SEMICOLON -> ';' */
+ { 0x65, 0x3A }, /* ETHIOPIC COLON -> ':' */
+ { 0x67, 0x3F }, /* ETHIOPIC QUESTION MARK -> '?' */
+ { 0x69, 0x31 }, /* ETHIOPIC DIGIT ONE -> '1' */
+ { 0x6A, 0x32 }, /* ETHIOPIC DIGIT TWO -> '2' */
+ { 0x6B, 0x33 }, /* ETHIOPIC DIGIT THREE -> '3' */
+ { 0x6C, 0x34 }, /* ETHIOPIC DIGIT FOUR -> '4' */
+ { 0x6D, 0x35 }, /* ETHIOPIC DIGIT FIVE -> '5' */
+ { 0x6E, 0x36 }, /* ETHIOPIC DIGIT SIX -> '6' */
+ { 0x6F, 0x37 }, /* ETHIOPIC DIGIT SEVEN -> '7' */
+ { 0x70, 0x38 }, /* ETHIOPIC DIGIT EIGHT -> '8' */
+ { 0x71, 0x39 }, /* ETHIOPIC DIGIT NINE -> '9' */
+ { 0xA0, 0x61 }, /* CHEROKEE LETTER A -> 'a' */
+ { 0xA1, 0x65 }, /* CHEROKEE LETTER E -> 'e' */
+ { 0xA2, 0x69 }, /* CHEROKEE LETTER I -> 'i' */
+ { 0xA3, 0x6F }, /* CHEROKEE LETTER O -> 'o' */
+ { 0xA4, 0x75 }, /* CHEROKEE LETTER U -> 'u' */
+ { 0xA5, 0x76 }, /* CHEROKEE LETTER V -> 'v' */
+ { 0xCD, 0x73 }, /* CHEROKEE LETTER S -> 's' */
+ /* Entries for page 0x14 */
+ { 0x01, 0x65 }, /* CANADIAN SYLLABICS E -> 'e' */
+ { 0x03, 0x69 }, /* CANADIAN SYLLABICS I -> 'i' */
+ { 0x05, 0x6F }, /* CANADIAN SYLLABICS O -> 'o' */
+ { 0x09, 0x69 }, /* CANADIAN SYLLABICS CARRIER I -> 'i' */
+ { 0x0A, 0x61 }, /* CANADIAN SYLLABICS A -> 'a' */
+ { 0x1D, 0x77 }, /* CANADIAN SYLLABICS Y-CREE W -> 'w' */
+ { 0x1E, 0x27 }, /* CANADIAN SYLLABICS GLOTTAL STOP -> ''' */
+ { 0x1F, 0x74 }, /* CANADIAN SYLLABICS FINAL ACUTE -> 't' */
+ { 0x20, 0x6B }, /* CANADIAN SYLLABICS FINAL GRAVE -> 'k' */
+ { 0x22, 0x73 }, /* CANADIAN SYLLABICS FINAL TOP HALF RING -> 's' */
+ { 0x23, 0x6E }, /* CANADIAN SYLLABICS FINAL RIGHT HALF RING -> 'n' */
+ { 0x24, 0x77 }, /* CANADIAN SYLLABICS FINAL RING -> 'w' */
+ { 0x25, 0x6E }, /* CANADIAN SYLLABICS FINAL DOUBLE ACUTE -> 'n' */
+ { 0x27, 0x77 }, /* CANADIAN SYLLABICS FINAL MIDDLE DOT -> 'w' */
+ { 0x28, 0x63 }, /* CANADIAN SYLLABICS FINAL SHORT HORIZONTAL STROKE -> 'c' */
+ { 0x29, 0x3F }, /* CANADIAN SYLLABICS FINAL PLUS -> '?' */
+ { 0x2A, 0x6C }, /* CANADIAN SYLLABICS FINAL DOWN TACK -> 'l' */
+ { 0x49, 0x70 }, /* CANADIAN SYLLABICS P -> 'p' */
+ { 0x4A, 0x70 }, /* CANADIAN SYLLABICS WEST-CREE P -> 'p' */
+ { 0x4B, 0x68 }, /* CANADIAN SYLLABICS CARRIER H -> 'h' */
+ { 0x66, 0x74 }, /* CANADIAN SYLLABICS T -> 't' */
+ { 0x83, 0x6B }, /* CANADIAN SYLLABICS K -> 'k' */
+ { 0xA1, 0x63 }, /* CANADIAN SYLLABICS C -> 'c' */
+ { 0xBB, 0x6D }, /* CANADIAN SYLLABICS M -> 'm' */
+ { 0xBC, 0x6D }, /* CANADIAN SYLLABICS WEST-CREE M -> 'm' */
+ { 0xBE, 0x6D }, /* CANADIAN SYLLABICS ATHAPASCAN M -> 'm' */
+ { 0xBF, 0x6D }, /* CANADIAN SYLLABICS SAYISI M -> 'm' */
+ { 0xD0, 0x6E }, /* CANADIAN SYLLABICS N -> 'n' */
+ { 0xEA, 0x00 }, /* CANADIAN SYLLABICS L -> ... */
+ { 0xEC, 0x6C }, /* CANADIAN SYLLABICS MEDIAL L -> 'l' */
+ /* Entries for page 0x15 */
+ { 0x05, 0x73 }, /* CANADIAN SYLLABICS S -> 's' */
+ { 0x06, 0x73 }, /* CANADIAN SYLLABICS ATHAPASCAN S -> 's' */
+ { 0x08, 0x73 }, /* CANADIAN SYLLABICS BLACKFOOT S -> 's' */
+ { 0x3E, 0x00 }, /* CANADIAN SYLLABICS Y -> ... */
+ { 0x40, 0x79 }, /* CANADIAN SYLLABICS WEST-CREE Y -> 'y' */
+ { 0x50, 0x00 }, /* CANADIAN SYLLABICS R -> ... */
+ { 0x52, 0x72 }, /* CANADIAN SYLLABICS MEDIAL R -> 'r' */
+ { 0x5D, 0x66 }, /* CANADIAN SYLLABICS F -> 'f' */
+ { 0x7B, 0x68 }, /* CANADIAN SYLLABICS NUNAVIK H -> 'h' */
+ { 0x7C, 0x68 }, /* CANADIAN SYLLABICS NUNAVUT H -> 'h' */
+ { 0x85, 0x71 }, /* CANADIAN SYLLABICS Q -> 'q' */
+ { 0xAF, 0x62 }, /* CANADIAN SYLLABICS AIVILIK B -> 'b' */
+ { 0xB0, 0x65 }, /* CANADIAN SYLLABICS BLACKFOOT E -> 'e' */
+ { 0xB1, 0x69 }, /* CANADIAN SYLLABICS BLACKFOOT I -> 'i' */
+ { 0xB2, 0x6F }, /* CANADIAN SYLLABICS BLACKFOOT O -> 'o' */
+ { 0xB3, 0x61 }, /* CANADIAN SYLLABICS BLACKFOOT A -> 'a' */
+ { 0xEE, 0x70 }, /* CANADIAN SYLLABICS CARRIER P -> 'p' */
+ /* Entries for page 0x16 */
+ { 0x46, 0x7A }, /* CANADIAN SYLLABICS CARRIER Z -> 'z' */
+ { 0x47, 0x7A }, /* CANADIAN SYLLABICS CARRIER INITIAL Z -> 'z' */
+ { 0x6D, 0x58 }, /* CANADIAN SYLLABICS CHI SIGN -> 'X' */
+ { 0x6E, 0x2E }, /* CANADIAN SYLLABICS FULL STOP -> '.' */
+ { 0x80, 0x20 }, /* OGHAM SPACE MARK -> ' ' */
+ { 0x81, 0x62 }, /* OGHAM LETTER BEITH -> 'b' */
+ { 0x82, 0x6C }, /* OGHAM LETTER LUIS -> 'l' */
+ { 0x83, 0x66 }, /* OGHAM LETTER FEARN -> 'f' */
+ { 0x84, 0x73 }, /* OGHAM LETTER SAIL -> 's' */
+ { 0x85, 0x6E }, /* OGHAM LETTER NION -> 'n' */
+ { 0x86, 0x68 }, /* OGHAM LETTER UATH -> 'h' */
+ { 0x87, 0x64 }, /* OGHAM LETTER DAIR -> 'd' */
+ { 0x88, 0x74 }, /* OGHAM LETTER TINNE -> 't' */
+ { 0x89, 0x63 }, /* OGHAM LETTER COLL -> 'c' */
+ { 0x8A, 0x71 }, /* OGHAM LETTER CEIRT -> 'q' */
+ { 0x8B, 0x6D }, /* OGHAM LETTER MUIN -> 'm' */
+ { 0x8C, 0x67 }, /* OGHAM LETTER GORT -> 'g' */
+ { 0x8E, 0x7A }, /* OGHAM LETTER STRAIF -> 'z' */
+ { 0x8F, 0x72 }, /* OGHAM LETTER RUIS -> 'r' */
+ { 0x90, 0x61 }, /* OGHAM LETTER AILM -> 'a' */
+ { 0x91, 0x6F }, /* OGHAM LETTER ONN -> 'o' */
+ { 0x92, 0x75 }, /* OGHAM LETTER UR -> 'u' */
+ { 0x93, 0x65 }, /* OGHAM LETTER EADHADH -> 'e' */
+ { 0x94, 0x69 }, /* OGHAM LETTER IODHADH -> 'i' */
+ { 0x98, 0x70 }, /* OGHAM LETTER IFIN -> 'p' */
+ { 0x99, 0x78 }, /* OGHAM LETTER EAMHANCHOLL -> 'x' */
+ { 0x9A, 0x70 }, /* OGHAM LETTER PEITH -> 'p' */
+ { 0x9B, 0x3C }, /* OGHAM FEATHER MARK -> '<' */
+ { 0x9C, 0x3E }, /* OGHAM REVERSED FEATHER MARK -> '>' */
+ { 0xA0, 0x66 }, /* RUNIC LETTER FEHU FEOH FE F -> 'f' */
+ { 0xA1, 0x76 }, /* RUNIC LETTER V -> 'v' */
+ { 0xA2, 0x75 }, /* RUNIC LETTER URUZ UR U -> 'u' */
+ { 0xA4, 0x79 }, /* RUNIC LETTER Y -> 'y' */
+ { 0xA5, 0x77 }, /* RUNIC LETTER W -> 'w' */
+ { 0xA8, 0x61 }, /* RUNIC LETTER ANSUZ A -> 'a' */
+ { 0xA9, 0x6F }, /* RUNIC LETTER OS O -> 'o' */
+ { 0xAC, 0x00 }, /* RUNIC LETTER LONG-BRANCH-OSS O -> ... */
+ { 0xAE, 0x6F }, /* RUNIC LETTER O -> 'o' */
+ { 0xB1, 0x72 }, /* RUNIC LETTER RAIDO RAD REID R -> 'r' */
+ { 0xB2, 0x6B }, /* RUNIC LETTER KAUNA -> 'k' */
+ { 0xB3, 0x63 }, /* RUNIC LETTER CEN -> 'c' */
+ { 0xB4, 0x6B }, /* RUNIC LETTER KAUN K -> 'k' */
+ { 0xB5, 0x67 }, /* RUNIC LETTER G -> 'g' */
+ { 0xB7, 0x67 }, /* RUNIC LETTER GEBO GYFU G -> 'g' */
+ { 0xB8, 0x67 }, /* RUNIC LETTER GAR -> 'g' */
+ { 0xB9, 0x77 }, /* RUNIC LETTER WUNJO WYNN W -> 'w' */
+ { 0xBA, 0x00 }, /* RUNIC LETTER HAGLAZ H -> ... */
+ { 0xBD, 0x68 }, /* RUNIC LETTER SHORT-TWIG-HAGALL H -> 'h' */
+ { 0xBE, 0x00 }, /* RUNIC LETTER NAUDIZ NYD NAUD N -> ... */
+ { 0xC0, 0x6E }, /* RUNIC LETTER DOTTED-N -> 'n' */
+ { 0xC1, 0x69 }, /* RUNIC LETTER ISAZ IS ISS I -> 'i' */
+ { 0xC2, 0x65 }, /* RUNIC LETTER E -> 'e' */
+ { 0xC3, 0x6A }, /* RUNIC LETTER JERAN J -> 'j' */
+ { 0xC4, 0x67 }, /* RUNIC LETTER GER -> 'g' */
+ { 0xC6, 0x61 }, /* RUNIC LETTER SHORT-TWIG-AR A -> 'a' */
+ { 0xC8, 0x70 }, /* RUNIC LETTER PERTHO PEORTH P -> 'p' */
+ { 0xC9, 0x7A }, /* RUNIC LETTER ALGIZ EOLHX -> 'z' */
+ { 0xCA, 0x00 }, /* RUNIC LETTER SOWILO S -> ... */
+ { 0xCC, 0x73 }, /* RUNIC LETTER SHORT-TWIG-SOL S -> 's' */
+ { 0xCD, 0x63 }, /* RUNIC LETTER C -> 'c' */
+ { 0xCE, 0x7A }, /* RUNIC LETTER Z -> 'z' */
+ { 0xCF, 0x74 }, /* RUNIC LETTER TIWAZ TIR TYR T -> 't' */
+ { 0xD0, 0x74 }, /* RUNIC LETTER SHORT-TWIG-TYR T -> 't' */
+ { 0xD1, 0x64 }, /* RUNIC LETTER D -> 'd' */
+ { 0xD2, 0x62 }, /* RUNIC LETTER BERKANAN BEORC BJARKAN B -> 'b' */
+ { 0xD3, 0x62 }, /* RUNIC LETTER SHORT-TWIG-BJARKAN B -> 'b' */
+ { 0xD4, 0x70 }, /* RUNIC LETTER DOTTED-P -> 'p' */
+ { 0xD5, 0x70 }, /* RUNIC LETTER OPEN-P -> 'p' */
+ { 0xD6, 0x65 }, /* RUNIC LETTER EHWAZ EH E -> 'e' */
+ { 0xD7, 0x00 }, /* RUNIC LETTER MANNAZ MAN M -> ... */
+ { 0xD9, 0x6D }, /* RUNIC LETTER SHORT-TWIG-MADR M -> 'm' */
+ { 0xDA, 0x6C }, /* RUNIC LETTER LAUKAZ LAGU LOGR L -> 'l' */
+ { 0xDB, 0x6C }, /* RUNIC LETTER DOTTED-L -> 'l' */
+ { 0xDE, 0x64 }, /* RUNIC LETTER DAGAZ DAEG D -> 'd' */
+ { 0xDF, 0x6F }, /* RUNIC LETTER OTHALAN ETHEL O -> 'o' */
+ { 0xE5, 0x73 }, /* RUNIC LETTER STAN -> 's' */
+ { 0xE9, 0x71 }, /* RUNIC LETTER Q -> 'q' */
+ { 0xEA, 0x78 }, /* RUNIC LETTER X -> 'x' */
+ { 0xEB, 0x2E }, /* RUNIC SINGLE PUNCTUATION -> '.' */
+ { 0xEC, 0x3A }, /* RUNIC MULTIPLE PUNCTUATION -> ':' */
+ { 0xED, 0x2B }, /* RUNIC CROSS PUNCTUATION -> '+' */
+ /* Entries for page 0x17 */
+ { 0x80, 0x6B }, /* KHMER LETTER KA -> 'k' */
+ { 0x82, 0x67 }, /* KHMER LETTER KO -> 'g' */
+ { 0x85, 0x63 }, /* KHMER LETTER CA -> 'c' */
+ { 0x87, 0x6A }, /* KHMER LETTER CO -> 'j' */
+ { 0x8A, 0x74 }, /* KHMER LETTER DA -> 't' */
+ { 0x8C, 0x64 }, /* KHMER LETTER DO -> 'd' */
+ { 0x8F, 0x74 }, /* KHMER LETTER TA -> 't' */
+ { 0x91, 0x64 }, /* KHMER LETTER TO -> 'd' */
+ { 0x93, 0x6E }, /* KHMER LETTER NO -> 'n' */
+ { 0x94, 0x70 }, /* KHMER LETTER BA -> 'p' */
+ { 0x96, 0x62 }, /* KHMER LETTER PO -> 'b' */
+ { 0x98, 0x6D }, /* KHMER LETTER MO -> 'm' */
+ { 0x99, 0x79 }, /* KHMER LETTER YO -> 'y' */
+ { 0x9A, 0x72 }, /* KHMER LETTER RO -> 'r' */
+ { 0x9B, 0x6C }, /* KHMER LETTER LO -> 'l' */
+ { 0x9C, 0x76 }, /* KHMER LETTER VO -> 'v' */
+ { 0x9F, 0x73 }, /* KHMER LETTER SA -> 's' */
+ { 0xA0, 0x68 }, /* KHMER LETTER HA -> 'h' */
+ { 0xA1, 0x6C }, /* KHMER LETTER LA -> 'l' */
+ { 0xA2, 0x71 }, /* KHMER LETTER QA -> 'q' */
+ { 0xA3, 0x61 }, /* KHMER INDEPENDENT VOWEL QAQ -> 'a' */
+ { 0xA5, 0x69 }, /* KHMER INDEPENDENT VOWEL QI -> 'i' */
+ { 0xA7, 0x75 }, /* KHMER INDEPENDENT VOWEL QU -> 'u' */
+ { 0xAF, 0x65 }, /* KHMER INDEPENDENT VOWEL QE -> 'e' */
+ { 0xB4, 0x61 }, /* KHMER VOWEL INHERENT AQ -> 'a' */
+ { 0xB7, 0x69 }, /* KHMER VOWEL SIGN I -> 'i' */
+ { 0xB9, 0x79 }, /* KHMER VOWEL SIGN Y -> 'y' */
+ { 0xBB, 0x75 }, /* KHMER VOWEL SIGN U -> 'u' */
+ { 0xC1, 0x65 }, /* KHMER VOWEL SIGN E -> 'e' */
+ { 0xC6, 0x4D }, /* KHMER SIGN NIKAHIT -> 'M' */
+ { 0xC7, 0x48 }, /* KHMER SIGN REAHMUK -> 'H' */
+ { 0xCC, 0x72 }, /* KHMER SIGN ROBAT -> 'r' */
+ { 0xCE, 0x21 }, /* KHMER SIGN KAKABAT -> '!' */
+ { 0xD4, 0x2E }, /* KHMER SIGN KHAN -> '.' */
+ { 0xD6, 0x3A }, /* KHMER SIGN CAMNUC PII KUUH -> ':' */
+ { 0xD7, 0x2B }, /* KHMER SIGN LEK TOO -> '+' */
+ { 0xDC, 0x27 }, /* KHMER SIGN AVAKRAHASANYA -> ''' */
+ { 0xE0, 0x30 }, /* KHMER DIGIT ZERO -> '0' */
+ { 0xE1, 0x31 }, /* KHMER DIGIT ONE -> '1' */
+ { 0xE2, 0x32 }, /* KHMER DIGIT TWO -> '2' */
+ { 0xE3, 0x33 }, /* KHMER DIGIT THREE -> '3' */
+ { 0xE4, 0x34 }, /* KHMER DIGIT FOUR -> '4' */
+ { 0xE5, 0x35 }, /* KHMER DIGIT FIVE -> '5' */
+ { 0xE6, 0x36 }, /* KHMER DIGIT SIX -> '6' */
+ { 0xE7, 0x37 }, /* KHMER DIGIT SEVEN -> '7' */
+ { 0xE8, 0x38 }, /* KHMER DIGIT EIGHT -> '8' */
+ { 0xE9, 0x39 }, /* KHMER DIGIT NINE -> '9' */
+ /* Entries for page 0x18 */
+ { 0x07, 0x2D }, /* MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER -> '-' */
+ { 0x10, 0x30 }, /* MONGOLIAN DIGIT ZERO -> '0' */
+ { 0x11, 0x31 }, /* MONGOLIAN DIGIT ONE -> '1' */
+ { 0x12, 0x32 }, /* MONGOLIAN DIGIT TWO -> '2' */
+ { 0x13, 0x33 }, /* MONGOLIAN DIGIT THREE -> '3' */
+ { 0x14, 0x34 }, /* MONGOLIAN DIGIT FOUR -> '4' */
+ { 0x15, 0x35 }, /* MONGOLIAN DIGIT FIVE -> '5' */
+ { 0x16, 0x36 }, /* MONGOLIAN DIGIT SIX -> '6' */
+ { 0x17, 0x37 }, /* MONGOLIAN DIGIT SEVEN -> '7' */
+ { 0x18, 0x38 }, /* MONGOLIAN DIGIT EIGHT -> '8' */
+ { 0x19, 0x39 }, /* MONGOLIAN DIGIT NINE -> '9' */
+ { 0x20, 0x61 }, /* MONGOLIAN LETTER A -> 'a' */
+ { 0x21, 0x65 }, /* MONGOLIAN LETTER E -> 'e' */
+ { 0x22, 0x69 }, /* MONGOLIAN LETTER I -> 'i' */
+ { 0x23, 0x6F }, /* MONGOLIAN LETTER O -> 'o' */
+ { 0x24, 0x75 }, /* MONGOLIAN LETTER U -> 'u' */
+ { 0x25, 0x4F }, /* MONGOLIAN LETTER OE -> 'O' */
+ { 0x26, 0x55 }, /* MONGOLIAN LETTER UE -> 'U' */
+ { 0x28, 0x6E }, /* MONGOLIAN LETTER NA -> 'n' */
+ { 0x2A, 0x62 }, /* MONGOLIAN LETTER BA -> 'b' */
+ { 0x2B, 0x70 }, /* MONGOLIAN LETTER PA -> 'p' */
+ { 0x2C, 0x71 }, /* MONGOLIAN LETTER QA -> 'q' */
+ { 0x2D, 0x67 }, /* MONGOLIAN LETTER GA -> 'g' */
+ { 0x2E, 0x6D }, /* MONGOLIAN LETTER MA -> 'm' */
+ { 0x2F, 0x6C }, /* MONGOLIAN LETTER LA -> 'l' */
+ { 0x30, 0x73 }, /* MONGOLIAN LETTER SA -> 's' */
+ { 0x32, 0x74 }, /* MONGOLIAN LETTER TA -> 't' */
+ { 0x33, 0x64 }, /* MONGOLIAN LETTER DA -> 'd' */
+ { 0x35, 0x6A }, /* MONGOLIAN LETTER JA -> 'j' */
+ { 0x36, 0x79 }, /* MONGOLIAN LETTER YA -> 'y' */
+ { 0x37, 0x72 }, /* MONGOLIAN LETTER RA -> 'r' */
+ { 0x38, 0x77 }, /* MONGOLIAN LETTER WA -> 'w' */
+ { 0x39, 0x66 }, /* MONGOLIAN LETTER FA -> 'f' */
+ { 0x3A, 0x6B }, /* MONGOLIAN LETTER KA -> 'k' */
+ { 0x3D, 0x7A }, /* MONGOLIAN LETTER ZA -> 'z' */
+ { 0x3E, 0x68 }, /* MONGOLIAN LETTER HAA -> 'h' */
+ { 0x43, 0x2D }, /* MONGOLIAN LETTER TODO LONG VOWEL SIGN -> '-' */
+ { 0x44, 0x65 }, /* MONGOLIAN LETTER TODO E -> 'e' */
+ { 0x45, 0x69 }, /* MONGOLIAN LETTER TODO I -> 'i' */
+ { 0x46, 0x6F }, /* MONGOLIAN LETTER TODO O -> 'o' */
+ { 0x47, 0x75 }, /* MONGOLIAN LETTER TODO U -> 'u' */
+ { 0x48, 0x4F }, /* MONGOLIAN LETTER TODO OE -> 'O' */
+ { 0x49, 0x55 }, /* MONGOLIAN LETTER TODO UE -> 'U' */
+ { 0x4B, 0x62 }, /* MONGOLIAN LETTER TODO BA -> 'b' */
+ { 0x4C, 0x70 }, /* MONGOLIAN LETTER TODO PA -> 'p' */
+ { 0x4D, 0x71 }, /* MONGOLIAN LETTER TODO QA -> 'q' */
+ { 0x4E, 0x67 }, /* MONGOLIAN LETTER TODO GA -> 'g' */
+ { 0x4F, 0x6D }, /* MONGOLIAN LETTER TODO MA -> 'm' */
+ { 0x50, 0x74 }, /* MONGOLIAN LETTER TODO TA -> 't' */
+ { 0x51, 0x64 }, /* MONGOLIAN LETTER TODO DA -> 'd' */
+ { 0x53, 0x6A }, /* MONGOLIAN LETTER TODO JA -> 'j' */
+ { 0x55, 0x79 }, /* MONGOLIAN LETTER TODO YA -> 'y' */
+ { 0x56, 0x77 }, /* MONGOLIAN LETTER TODO WA -> 'w' */
+ { 0x57, 0x6B }, /* MONGOLIAN LETTER TODO KA -> 'k' */
+ { 0x58, 0x67 }, /* MONGOLIAN LETTER TODO GAA -> 'g' */
+ { 0x59, 0x68 }, /* MONGOLIAN LETTER TODO HAA -> 'h' */
+ { 0x5D, 0x65 }, /* MONGOLIAN LETTER SIBE E -> 'e' */
+ { 0x5E, 0x69 }, /* MONGOLIAN LETTER SIBE I -> 'i' */
+ { 0x60, 0x55 }, /* MONGOLIAN LETTER SIBE UE -> 'U' */
+ { 0x61, 0x75 }, /* MONGOLIAN LETTER SIBE U -> 'u' */
+ { 0x63, 0x6B }, /* MONGOLIAN LETTER SIBE KA -> 'k' */
+ { 0x64, 0x67 }, /* MONGOLIAN LETTER SIBE GA -> 'g' */
+ { 0x65, 0x68 }, /* MONGOLIAN LETTER SIBE HA -> 'h' */
+ { 0x66, 0x70 }, /* MONGOLIAN LETTER SIBE PA -> 'p' */
+ { 0x68, 0x74 }, /* MONGOLIAN LETTER SIBE TA -> 't' */
+ { 0x69, 0x64 }, /* MONGOLIAN LETTER SIBE DA -> 'd' */
+ { 0x6A, 0x6A }, /* MONGOLIAN LETTER SIBE JA -> 'j' */
+ { 0x6B, 0x66 }, /* MONGOLIAN LETTER SIBE FA -> 'f' */
+ { 0x6C, 0x67 }, /* MONGOLIAN LETTER SIBE GAA -> 'g' */
+ { 0x6D, 0x68 }, /* MONGOLIAN LETTER SIBE HAA -> 'h' */
+ { 0x6F, 0x7A }, /* MONGOLIAN LETTER SIBE ZA -> 'z' */
+ { 0x70, 0x72 }, /* MONGOLIAN LETTER SIBE RAA -> 'r' */
+ { 0x73, 0x69 }, /* MONGOLIAN LETTER MANCHU I -> 'i' */
+ { 0x74, 0x6B }, /* MONGOLIAN LETTER MANCHU KA -> 'k' */
+ { 0x75, 0x72 }, /* MONGOLIAN LETTER MANCHU RA -> 'r' */
+ { 0x76, 0x66 }, /* MONGOLIAN LETTER MANCHU FA -> 'f' */
+ { 0x81, 0x48 }, /* MONGOLIAN LETTER ALI GALI VISARGA ONE -> 'H' */
+ { 0x82, 0x58 }, /* MONGOLIAN LETTER ALI GALI DAMARU -> 'X' */
+ { 0x83, 0x57 }, /* MONGOLIAN LETTER ALI GALI UBADAMA -> 'W' */
+ { 0x84, 0x4D }, /* MONGOLIAN LETTER ALI GALI INVERTED UBADAMA -> 'M' */
+ { 0x87, 0x61 }, /* MONGOLIAN LETTER ALI GALI A -> 'a' */
+ { 0x88, 0x69 }, /* MONGOLIAN LETTER ALI GALI I -> 'i' */
+ { 0x89, 0x6B }, /* MONGOLIAN LETTER ALI GALI KA -> 'k' */
+ { 0x8B, 0x63 }, /* MONGOLIAN LETTER ALI GALI CA -> 'c' */
+ { 0x90, 0x74 }, /* MONGOLIAN LETTER ALI GALI TA -> 't' */
+ { 0x91, 0x64 }, /* MONGOLIAN LETTER ALI GALI DA -> 'd' */
+ { 0x92, 0x70 }, /* MONGOLIAN LETTER ALI GALI PA -> 'p' */
+ { 0x96, 0x7A }, /* MONGOLIAN LETTER ALI GALI ZA -> 'z' */
+ { 0x97, 0x61 }, /* MONGOLIAN LETTER ALI GALI AH -> 'a' */
+ { 0x98, 0x74 }, /* MONGOLIAN LETTER TODO ALI GALI TA -> 't' */
+ { 0x9C, 0x63 }, /* MONGOLIAN LETTER MANCHU ALI GALI CA -> 'c' */
+ { 0xA0, 0x74 }, /* MONGOLIAN LETTER MANCHU ALI GALI TA -> 't' */
+ { 0xA5, 0x7A }, /* MONGOLIAN LETTER MANCHU ALI GALI ZA -> 'z' */
+ { 0xA6, 0x75 }, /* MONGOLIAN LETTER ALI GALI HALF U -> 'u' */
+ { 0xA7, 0x79 }, /* MONGOLIAN LETTER ALI GALI HALF YA -> 'y' */
+ { 0xA9, 0x27 }, /* MONGOLIAN LETTER ALI GALI DAGALGA -> ''' */
+ /* Entries for page 0x1D */
+ { 0x00, 0x41 }, /* LATIN LETTER SMALL CAPITAL A -> 'A' */
+ { 0x03, 0x42 }, /* LATIN LETTER SMALL CAPITAL BARRED B -> 'B' */
+ { 0x04, 0x43 }, /* LATIN LETTER SMALL CAPITAL C -> 'C' */
+ { 0x05, 0x44 }, /* LATIN LETTER SMALL CAPITAL D -> 'D' */
+ { 0x06, 0x44 }, /* LATIN LETTER SMALL CAPITAL ETH -> 'D' */
+ { 0x07, 0x45 }, /* LATIN LETTER SMALL CAPITAL E -> 'E' */
+ { 0x08, 0x65 }, /* LATIN SMALL LETTER TURNED OPEN E -> 'e' */
+ { 0x09, 0x69 }, /* LATIN SMALL LETTER TURNED I -> 'i' */
+ { 0x0A, 0x4A }, /* LATIN LETTER SMALL CAPITAL J -> 'J' */
+ { 0x0B, 0x4B }, /* LATIN LETTER SMALL CAPITAL K -> 'K' */
+ { 0x0C, 0x4C }, /* LATIN LETTER SMALL CAPITAL L WITH STROKE -> 'L' */
+ { 0x0D, 0x4D }, /* LATIN LETTER SMALL CAPITAL M -> 'M' */
+ { 0x0E, 0x4E }, /* LATIN LETTER SMALL CAPITAL REVERSED N -> 'N' */
+ { 0x0F, 0x4F }, /* LATIN LETTER SMALL CAPITAL O -> 'O' */
+ { 0x11, 0x4F }, /* LATIN SMALL LETTER SIDEWAYS O -> 'O' */
+ { 0x13, 0x4F }, /* LATIN SMALL LETTER SIDEWAYS O WITH STROKE -> 'O' */
+ { 0x18, 0x50 }, /* LATIN LETTER SMALL CAPITAL P -> 'P' */
+ { 0x19, 0x52 }, /* LATIN LETTER SMALL CAPITAL REVERSED R -> 'R' */
+ { 0x1A, 0x52 }, /* LATIN LETTER SMALL CAPITAL TURNED R -> 'R' */
+ { 0x1B, 0x54 }, /* LATIN LETTER SMALL CAPITAL T -> 'T' */
+ { 0x1C, 0x55 }, /* LATIN LETTER SMALL CAPITAL U -> 'U' */
+ { 0x1D, 0x75 }, /* LATIN SMALL LETTER SIDEWAYS U -> 'u' */
+ { 0x1E, 0x75 }, /* LATIN SMALL LETTER SIDEWAYS DIAERESIZED U -> 'u' */
+ { 0x1F, 0x6D }, /* LATIN SMALL LETTER SIDEWAYS TURNED M -> 'm' */
+ { 0x20, 0x56 }, /* LATIN LETTER SMALL CAPITAL V -> 'V' */
+ { 0x21, 0x57 }, /* LATIN LETTER SMALL CAPITAL W -> 'W' */
+ { 0x22, 0x5A }, /* LATIN LETTER SMALL CAPITAL Z -> 'Z' */
+ { 0x2C, 0x41 }, /* MODIFIER LETTER CAPITAL A -> 'A' */
+ { 0x2E, 0x42 }, /* MODIFIER LETTER CAPITAL B -> 'B' */
+ { 0x2F, 0x42 }, /* MODIFIER LETTER CAPITAL BARRED B -> 'B' */
+ { 0x30, 0x44 }, /* MODIFIER LETTER CAPITAL D -> 'D' */
+ { 0x31, 0x45 }, /* MODIFIER LETTER CAPITAL E -> 'E' */
+ { 0x32, 0x45 }, /* MODIFIER LETTER CAPITAL REVERSED E -> 'E' */
+ { 0x33, 0x47 }, /* MODIFIER LETTER CAPITAL G -> 'G' */
+ { 0x34, 0x48 }, /* MODIFIER LETTER CAPITAL H -> 'H' */
+ { 0x35, 0x49 }, /* MODIFIER LETTER CAPITAL I -> 'I' */
+ { 0x36, 0x4A }, /* MODIFIER LETTER CAPITAL J -> 'J' */
+ { 0x37, 0x4B }, /* MODIFIER LETTER CAPITAL K -> 'K' */
+ { 0x38, 0x4C }, /* MODIFIER LETTER CAPITAL L -> 'L' */
+ { 0x39, 0x4D }, /* MODIFIER LETTER CAPITAL M -> 'M' */
+ { 0x3A, 0x4E }, /* MODIFIER LETTER CAPITAL N -> 'N' */
+ { 0x3B, 0x4E }, /* MODIFIER LETTER CAPITAL REVERSED N -> 'N' */
+ { 0x3C, 0x4F }, /* MODIFIER LETTER CAPITAL O -> 'O' */
+ { 0x3E, 0x50 }, /* MODIFIER LETTER CAPITAL P -> 'P' */
+ { 0x3F, 0x52 }, /* MODIFIER LETTER CAPITAL R -> 'R' */
+ { 0x40, 0x54 }, /* MODIFIER LETTER CAPITAL T -> 'T' */
+ { 0x41, 0x55 }, /* MODIFIER LETTER CAPITAL U -> 'U' */
+ { 0x42, 0x57 }, /* MODIFIER LETTER CAPITAL W -> 'W' */
+ { 0x43, 0x00 }, /* MODIFIER LETTER SMALL A -> ... */
+ { 0x45, 0x61 }, /* MODIFIER LETTER SMALL ALPHA -> 'a' */
+ { 0x47, 0x62 }, /* MODIFIER LETTER SMALL B -> 'b' */
+ { 0x48, 0x64 }, /* MODIFIER LETTER SMALL D -> 'd' */
+ { 0x49, 0x65 }, /* MODIFIER LETTER SMALL E -> 'e' */
+ { 0x4B, 0x65 }, /* MODIFIER LETTER SMALL OPEN E -> 'e' */
+ { 0x4C, 0x65 }, /* MODIFIER LETTER SMALL TURNED OPEN E -> 'e' */
+ { 0x4D, 0x67 }, /* MODIFIER LETTER SMALL G -> 'g' */
+ { 0x4E, 0x69 }, /* MODIFIER LETTER SMALL TURNED I -> 'i' */
+ { 0x4F, 0x6B }, /* MODIFIER LETTER SMALL K -> 'k' */
+ { 0x50, 0x6D }, /* MODIFIER LETTER SMALL M -> 'm' */
+ { 0x52, 0x6F }, /* MODIFIER LETTER SMALL O -> 'o' */
+ { 0x56, 0x70 }, /* MODIFIER LETTER SMALL P -> 'p' */
+ { 0x57, 0x74 }, /* MODIFIER LETTER SMALL T -> 't' */
+ { 0x58, 0x75 }, /* MODIFIER LETTER SMALL U -> 'u' */
+ { 0x59, 0x75 }, /* MODIFIER LETTER SMALL SIDEWAYS U -> 'u' */
+ { 0x5A, 0x6D }, /* MODIFIER LETTER SMALL TURNED M -> 'm' */
+ { 0x5B, 0x76 }, /* MODIFIER LETTER SMALL V -> 'v' */
+ { 0x5D, 0x62 }, /* MODIFIER LETTER SMALL BETA -> 'b' */
+ { 0x5E, 0x67 }, /* MODIFIER LETTER SMALL GREEK GAMMA -> 'g' */
+ { 0x5F, 0x64 }, /* MODIFIER LETTER SMALL DELTA -> 'd' */
+ { 0x60, 0x66 }, /* MODIFIER LETTER SMALL GREEK PHI -> 'f' */
+ { 0x62, 0x69 }, /* LATIN SUBSCRIPT SMALL LETTER I -> 'i' */
+ { 0x63, 0x72 }, /* LATIN SUBSCRIPT SMALL LETTER R -> 'r' */
+ { 0x64, 0x75 }, /* LATIN SUBSCRIPT SMALL LETTER U -> 'u' */
+ { 0x65, 0x76 }, /* LATIN SUBSCRIPT SMALL LETTER V -> 'v' */
+ { 0x66, 0x62 }, /* GREEK SUBSCRIPT SMALL LETTER BETA -> 'b' */
+ { 0x67, 0x67 }, /* GREEK SUBSCRIPT SMALL LETTER GAMMA -> 'g' */
+ { 0x68, 0x72 }, /* GREEK SUBSCRIPT SMALL LETTER RHO -> 'r' */
+ { 0x69, 0x66 }, /* GREEK SUBSCRIPT SMALL LETTER PHI -> 'f' */
+ { 0x6C, 0x62 }, /* LATIN SMALL LETTER B WITH MIDDLE TILDE -> 'b' */
+ { 0x6D, 0x64 }, /* LATIN SMALL LETTER D WITH MIDDLE TILDE -> 'd' */
+ { 0x6E, 0x66 }, /* LATIN SMALL LETTER F WITH MIDDLE TILDE -> 'f' */
+ { 0x6F, 0x6D }, /* LATIN SMALL LETTER M WITH MIDDLE TILDE -> 'm' */
+ { 0x70, 0x6E }, /* LATIN SMALL LETTER N WITH MIDDLE TILDE -> 'n' */
+ { 0x71, 0x70 }, /* LATIN SMALL LETTER P WITH MIDDLE TILDE -> 'p' */
+ { 0x72, 0x72 }, /* LATIN SMALL LETTER R WITH MIDDLE TILDE -> 'r' */
+ { 0x73, 0x72 }, /* LATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TILDE -> 'r' */
+ { 0x74, 0x73 }, /* LATIN SMALL LETTER S WITH MIDDLE TILDE -> 's' */
+ { 0x75, 0x74 }, /* LATIN SMALL LETTER T WITH MIDDLE TILDE -> 't' */
+ { 0x76, 0x7A }, /* LATIN SMALL LETTER Z WITH MIDDLE TILDE -> 'z' */
+ { 0x77, 0x67 }, /* LATIN SMALL LETTER TURNED G -> 'g' */
+ { 0x7D, 0x70 }, /* LATIN SMALL LETTER P WITH STROKE -> 'p' */
+ { 0x80, 0x62 }, /* LATIN SMALL LETTER B WITH PALATAL HOOK -> 'b' */
+ { 0x81, 0x64 }, /* LATIN SMALL LETTER D WITH PALATAL HOOK -> 'd' */
+ { 0x82, 0x66 }, /* LATIN SMALL LETTER F WITH PALATAL HOOK -> 'f' */
+ { 0x83, 0x67 }, /* LATIN SMALL LETTER G WITH PALATAL HOOK -> 'g' */
+ { 0x84, 0x6B }, /* LATIN SMALL LETTER K WITH PALATAL HOOK -> 'k' */
+ { 0x85, 0x6C }, /* LATIN SMALL LETTER L WITH PALATAL HOOK -> 'l' */
+ { 0x86, 0x6D }, /* LATIN SMALL LETTER M WITH PALATAL HOOK -> 'm' */
+ { 0x87, 0x6E }, /* LATIN SMALL LETTER N WITH PALATAL HOOK -> 'n' */
+ { 0x88, 0x70 }, /* LATIN SMALL LETTER P WITH PALATAL HOOK -> 'p' */
+ { 0x89, 0x72 }, /* LATIN SMALL LETTER R WITH PALATAL HOOK -> 'r' */
+ { 0x8A, 0x73 }, /* LATIN SMALL LETTER S WITH PALATAL HOOK -> 's' */
+ { 0x8C, 0x76 }, /* LATIN SMALL LETTER V WITH PALATAL HOOK -> 'v' */
+ { 0x8D, 0x78 }, /* LATIN SMALL LETTER X WITH PALATAL HOOK -> 'x' */
+ { 0x8E, 0x7A }, /* LATIN SMALL LETTER Z WITH PALATAL HOOK -> 'z' */
+ /* Entries for page 0x1E */
+ { 0x00, 0x41 }, /* LATIN CAPITAL LETTER A WITH RING BELOW -> 'A' */
+ { 0x01, 0x61 }, /* LATIN SMALL LETTER A WITH RING BELOW -> 'a' */
+ { 0x02, 0x42 }, /* LATIN CAPITAL LETTER B WITH DOT ABOVE -> 'B' */
+ { 0x03, 0x62 }, /* LATIN SMALL LETTER B WITH DOT ABOVE -> 'b' */
+ { 0x04, 0x42 }, /* LATIN CAPITAL LETTER B WITH DOT BELOW -> 'B' */
+ { 0x05, 0x62 }, /* LATIN SMALL LETTER B WITH DOT BELOW -> 'b' */
+ { 0x06, 0x42 }, /* LATIN CAPITAL LETTER B WITH LINE BELOW -> 'B' */
+ { 0x07, 0x62 }, /* LATIN SMALL LETTER B WITH LINE BELOW -> 'b' */
+ { 0x08, 0x43 }, /* LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE -> 'C' */
+ { 0x09, 0x63 }, /* LATIN SMALL LETTER C WITH CEDILLA AND ACUTE -> 'c' */
+ { 0x0A, 0x44 }, /* LATIN CAPITAL LETTER D WITH DOT ABOVE -> 'D' */
+ { 0x0B, 0x64 }, /* LATIN SMALL LETTER D WITH DOT ABOVE -> 'd' */
+ { 0x0C, 0x44 }, /* LATIN CAPITAL LETTER D WITH DOT BELOW -> 'D' */
+ { 0x0D, 0x64 }, /* LATIN SMALL LETTER D WITH DOT BELOW -> 'd' */
+ { 0x0E, 0x44 }, /* LATIN CAPITAL LETTER D WITH LINE BELOW -> 'D' */
+ { 0x0F, 0x64 }, /* LATIN SMALL LETTER D WITH LINE BELOW -> 'd' */
+ { 0x10, 0x44 }, /* LATIN CAPITAL LETTER D WITH CEDILLA -> 'D' */
+ { 0x11, 0x64 }, /* LATIN SMALL LETTER D WITH CEDILLA -> 'd' */
+ { 0x12, 0x44 }, /* LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW -> 'D' */
+ { 0x13, 0x64 }, /* LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW -> 'd' */
+ { 0x14, 0x45 }, /* LATIN CAPITAL LETTER E WITH MACRON AND GRAVE -> 'E' */
+ { 0x15, 0x65 }, /* LATIN SMALL LETTER E WITH MACRON AND GRAVE -> 'e' */
+ { 0x16, 0x45 }, /* LATIN CAPITAL LETTER E WITH MACRON AND ACUTE -> 'E' */
+ { 0x17, 0x65 }, /* LATIN SMALL LETTER E WITH MACRON AND ACUTE -> 'e' */
+ { 0x18, 0x45 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW -> 'E' */
+ { 0x19, 0x65 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW -> 'e' */
+ { 0x1A, 0x45 }, /* LATIN CAPITAL LETTER E WITH TILDE BELOW -> 'E' */
+ { 0x1B, 0x65 }, /* LATIN SMALL LETTER E WITH TILDE BELOW -> 'e' */
+ { 0x1C, 0x45 }, /* LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE -> 'E' */
+ { 0x1D, 0x65 }, /* LATIN SMALL LETTER E WITH CEDILLA AND BREVE -> 'e' */
+ { 0x1E, 0x46 }, /* LATIN CAPITAL LETTER F WITH DOT ABOVE -> 'F' */
+ { 0x1F, 0x66 }, /* LATIN SMALL LETTER F WITH DOT ABOVE -> 'f' */
+ { 0x20, 0x47 }, /* LATIN CAPITAL LETTER G WITH MACRON -> 'G' */
+ { 0x21, 0x67 }, /* LATIN SMALL LETTER G WITH MACRON -> 'g' */
+ { 0x22, 0x48 }, /* LATIN CAPITAL LETTER H WITH DOT ABOVE -> 'H' */
+ { 0x23, 0x68 }, /* LATIN SMALL LETTER H WITH DOT ABOVE -> 'h' */
+ { 0x24, 0x48 }, /* LATIN CAPITAL LETTER H WITH DOT BELOW -> 'H' */
+ { 0x25, 0x68 }, /* LATIN SMALL LETTER H WITH DOT BELOW -> 'h' */
+ { 0x26, 0x48 }, /* LATIN CAPITAL LETTER H WITH DIAERESIS -> 'H' */
+ { 0x27, 0x68 }, /* LATIN SMALL LETTER H WITH DIAERESIS -> 'h' */
+ { 0x28, 0x48 }, /* LATIN CAPITAL LETTER H WITH CEDILLA -> 'H' */
+ { 0x29, 0x68 }, /* LATIN SMALL LETTER H WITH CEDILLA -> 'h' */
+ { 0x2A, 0x48 }, /* LATIN CAPITAL LETTER H WITH BREVE BELOW -> 'H' */
+ { 0x2B, 0x68 }, /* LATIN SMALL LETTER H WITH BREVE BELOW -> 'h' */
+ { 0x2C, 0x49 }, /* LATIN CAPITAL LETTER I WITH TILDE BELOW -> 'I' */
+ { 0x2D, 0x69 }, /* LATIN SMALL LETTER I WITH TILDE BELOW -> 'i' */
+ { 0x2E, 0x49 }, /* LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE -> 'I' */
+ { 0x2F, 0x69 }, /* LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE -> 'i' */
+ { 0x30, 0x4B }, /* LATIN CAPITAL LETTER K WITH ACUTE -> 'K' */
+ { 0x31, 0x6B }, /* LATIN SMALL LETTER K WITH ACUTE -> 'k' */
+ { 0x32, 0x4B }, /* LATIN CAPITAL LETTER K WITH DOT BELOW -> 'K' */
+ { 0x33, 0x6B }, /* LATIN SMALL LETTER K WITH DOT BELOW -> 'k' */
+ { 0x34, 0x4B }, /* LATIN CAPITAL LETTER K WITH LINE BELOW -> 'K' */
+ { 0x35, 0x6B }, /* LATIN SMALL LETTER K WITH LINE BELOW -> 'k' */
+ { 0x36, 0x4C }, /* LATIN CAPITAL LETTER L WITH DOT BELOW -> 'L' */
+ { 0x37, 0x6C }, /* LATIN SMALL LETTER L WITH DOT BELOW -> 'l' */
+ { 0x38, 0x4C }, /* LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON -> 'L' */
+ { 0x39, 0x6C }, /* LATIN SMALL LETTER L WITH DOT BELOW AND MACRON -> 'l' */
+ { 0x3A, 0x4C }, /* LATIN CAPITAL LETTER L WITH LINE BELOW -> 'L' */
+ { 0x3B, 0x6C }, /* LATIN SMALL LETTER L WITH LINE BELOW -> 'l' */
+ { 0x3C, 0x4C }, /* LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW -> 'L' */
+ { 0x3D, 0x6C }, /* LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW -> 'l' */
+ { 0x3E, 0x4D }, /* LATIN CAPITAL LETTER M WITH ACUTE -> 'M' */
+ { 0x3F, 0x6D }, /* LATIN SMALL LETTER M WITH ACUTE -> 'm' */
+ { 0x40, 0x4D }, /* LATIN CAPITAL LETTER M WITH DOT ABOVE -> 'M' */
+ { 0x41, 0x6D }, /* LATIN SMALL LETTER M WITH DOT ABOVE -> 'm' */
+ { 0x42, 0x4D }, /* LATIN CAPITAL LETTER M WITH DOT BELOW -> 'M' */
+ { 0x43, 0x6D }, /* LATIN SMALL LETTER M WITH DOT BELOW -> 'm' */
+ { 0x44, 0x4E }, /* LATIN CAPITAL LETTER N WITH DOT ABOVE -> 'N' */
+ { 0x45, 0x6E }, /* LATIN SMALL LETTER N WITH DOT ABOVE -> 'n' */
+ { 0x46, 0x4E }, /* LATIN CAPITAL LETTER N WITH DOT BELOW -> 'N' */
+ { 0x47, 0x6E }, /* LATIN SMALL LETTER N WITH DOT BELOW -> 'n' */
+ { 0x48, 0x4E }, /* LATIN CAPITAL LETTER N WITH LINE BELOW -> 'N' */
+ { 0x49, 0x6E }, /* LATIN SMALL LETTER N WITH LINE BELOW -> 'n' */
+ { 0x4A, 0x4E }, /* LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW -> 'N' */
+ { 0x4B, 0x6E }, /* LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW -> 'n' */
+ { 0x4C, 0x4F }, /* LATIN CAPITAL LETTER O WITH TILDE AND ACUTE -> 'O' */
+ { 0x4D, 0x6F }, /* LATIN SMALL LETTER O WITH TILDE AND ACUTE -> 'o' */
+ { 0x4E, 0x4F }, /* LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS -> 'O' */
+ { 0x4F, 0x6F }, /* LATIN SMALL LETTER O WITH TILDE AND DIAERESIS -> 'o' */
+ { 0x50, 0x4F }, /* LATIN CAPITAL LETTER O WITH MACRON AND GRAVE -> 'O' */
+ { 0x51, 0x6F }, /* LATIN SMALL LETTER O WITH MACRON AND GRAVE -> 'o' */
+ { 0x52, 0x4F }, /* LATIN CAPITAL LETTER O WITH MACRON AND ACUTE -> 'O' */
+ { 0x53, 0x6F }, /* LATIN SMALL LETTER O WITH MACRON AND ACUTE -> 'o' */
+ { 0x54, 0x50 }, /* LATIN CAPITAL LETTER P WITH ACUTE -> 'P' */
+ { 0x55, 0x70 }, /* LATIN SMALL LETTER P WITH ACUTE -> 'p' */
+ { 0x56, 0x50 }, /* LATIN CAPITAL LETTER P WITH DOT ABOVE -> 'P' */
+ { 0x57, 0x70 }, /* LATIN SMALL LETTER P WITH DOT ABOVE -> 'p' */
+ { 0x58, 0x52 }, /* LATIN CAPITAL LETTER R WITH DOT ABOVE -> 'R' */
+ { 0x59, 0x72 }, /* LATIN SMALL LETTER R WITH DOT ABOVE -> 'r' */
+ { 0x5A, 0x52 }, /* LATIN CAPITAL LETTER R WITH DOT BELOW -> 'R' */
+ { 0x5B, 0x72 }, /* LATIN SMALL LETTER R WITH DOT BELOW -> 'r' */
+ { 0x5C, 0x52 }, /* LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON -> 'R' */
+ { 0x5D, 0x72 }, /* LATIN SMALL LETTER R WITH DOT BELOW AND MACRON -> 'r' */
+ { 0x5E, 0x52 }, /* LATIN CAPITAL LETTER R WITH LINE BELOW -> 'R' */
+ { 0x5F, 0x72 }, /* LATIN SMALL LETTER R WITH LINE BELOW -> 'r' */
+ { 0x60, 0x53 }, /* LATIN CAPITAL LETTER S WITH DOT ABOVE -> 'S' */
+ { 0x61, 0x73 }, /* LATIN SMALL LETTER S WITH DOT ABOVE -> 's' */
+ { 0x62, 0x53 }, /* LATIN CAPITAL LETTER S WITH DOT BELOW -> 'S' */
+ { 0x63, 0x73 }, /* LATIN SMALL LETTER S WITH DOT BELOW -> 's' */
+ { 0x64, 0x53 }, /* LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE -> 'S' */
+ { 0x65, 0x73 }, /* LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE -> 's' */
+ { 0x66, 0x53 }, /* LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE -> 'S' */
+ { 0x67, 0x73 }, /* LATIN SMALL LETTER S WITH CARON AND DOT ABOVE -> 's' */
+ { 0x68, 0x53 }, /* LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE -> 'S' */
+ { 0x69, 0x73 }, /* LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE -> 's' */
+ { 0x6A, 0x54 }, /* LATIN CAPITAL LETTER T WITH DOT ABOVE -> 'T' */
+ { 0x6B, 0x74 }, /* LATIN SMALL LETTER T WITH DOT ABOVE -> 't' */
+ { 0x6C, 0x54 }, /* LATIN CAPITAL LETTER T WITH DOT BELOW -> 'T' */
+ { 0x6D, 0x74 }, /* LATIN SMALL LETTER T WITH DOT BELOW -> 't' */
+ { 0x6E, 0x54 }, /* LATIN CAPITAL LETTER T WITH LINE BELOW -> 'T' */
+ { 0x6F, 0x74 }, /* LATIN SMALL LETTER T WITH LINE BELOW -> 't' */
+ { 0x70, 0x54 }, /* LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW -> 'T' */
+ { 0x71, 0x74 }, /* LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW -> 't' */
+ { 0x72, 0x55 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS BELOW -> 'U' */
+ { 0x73, 0x75 }, /* LATIN SMALL LETTER U WITH DIAERESIS BELOW -> 'u' */
+ { 0x74, 0x55 }, /* LATIN CAPITAL LETTER U WITH TILDE BELOW -> 'U' */
+ { 0x75, 0x75 }, /* LATIN SMALL LETTER U WITH TILDE BELOW -> 'u' */
+ { 0x76, 0x55 }, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW -> 'U' */
+ { 0x77, 0x75 }, /* LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW -> 'u' */
+ { 0x78, 0x55 }, /* LATIN CAPITAL LETTER U WITH TILDE AND ACUTE -> 'U' */
+ { 0x79, 0x75 }, /* LATIN SMALL LETTER U WITH TILDE AND ACUTE -> 'u' */
+ { 0x7A, 0x55 }, /* LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS -> 'U' */
+ { 0x7B, 0x75 }, /* LATIN SMALL LETTER U WITH MACRON AND DIAERESIS -> 'u' */
+ { 0x7C, 0x56 }, /* LATIN CAPITAL LETTER V WITH TILDE -> 'V' */
+ { 0x7D, 0x76 }, /* LATIN SMALL LETTER V WITH TILDE -> 'v' */
+ { 0x7E, 0x56 }, /* LATIN CAPITAL LETTER V WITH DOT BELOW -> 'V' */
+ { 0x7F, 0x76 }, /* LATIN SMALL LETTER V WITH DOT BELOW -> 'v' */
+ { 0x80, 0x57 }, /* LATIN CAPITAL LETTER W WITH GRAVE -> 'W' */
+ { 0x81, 0x77 }, /* LATIN SMALL LETTER W WITH GRAVE -> 'w' */
+ { 0x82, 0x57 }, /* LATIN CAPITAL LETTER W WITH ACUTE -> 'W' */
+ { 0x83, 0x77 }, /* LATIN SMALL LETTER W WITH ACUTE -> 'w' */
+ { 0x84, 0x57 }, /* LATIN CAPITAL LETTER W WITH DIAERESIS -> 'W' */
+ { 0x85, 0x77 }, /* LATIN SMALL LETTER W WITH DIAERESIS -> 'w' */
+ { 0x86, 0x57 }, /* LATIN CAPITAL LETTER W WITH DOT ABOVE -> 'W' */
+ { 0x87, 0x77 }, /* LATIN SMALL LETTER W WITH DOT ABOVE -> 'w' */
+ { 0x88, 0x57 }, /* LATIN CAPITAL LETTER W WITH DOT BELOW -> 'W' */
+ { 0x89, 0x77 }, /* LATIN SMALL LETTER W WITH DOT BELOW -> 'w' */
+ { 0x8A, 0x58 }, /* LATIN CAPITAL LETTER X WITH DOT ABOVE -> 'X' */
+ { 0x8B, 0x78 }, /* LATIN SMALL LETTER X WITH DOT ABOVE -> 'x' */
+ { 0x8C, 0x58 }, /* LATIN CAPITAL LETTER X WITH DIAERESIS -> 'X' */
+ { 0x8D, 0x78 }, /* LATIN SMALL LETTER X WITH DIAERESIS -> 'x' */
+ { 0x8E, 0x59 }, /* LATIN CAPITAL LETTER Y WITH DOT ABOVE -> 'Y' */
+ { 0x8F, 0x79 }, /* LATIN SMALL LETTER Y WITH DOT ABOVE -> 'y' */
+ { 0x90, 0x5A }, /* LATIN CAPITAL LETTER Z WITH CIRCUMFLEX -> 'Z' */
+ { 0x91, 0x7A }, /* LATIN SMALL LETTER Z WITH CIRCUMFLEX -> 'z' */
+ { 0x92, 0x5A }, /* LATIN CAPITAL LETTER Z WITH DOT BELOW -> 'Z' */
+ { 0x93, 0x7A }, /* LATIN SMALL LETTER Z WITH DOT BELOW -> 'z' */
+ { 0x94, 0x5A }, /* LATIN CAPITAL LETTER Z WITH LINE BELOW -> 'Z' */
+ { 0x95, 0x7A }, /* LATIN SMALL LETTER Z WITH LINE BELOW -> 'z' */
+ { 0x96, 0x68 }, /* LATIN SMALL LETTER H WITH LINE BELOW -> 'h' */
+ { 0x97, 0x74 }, /* LATIN SMALL LETTER T WITH DIAERESIS -> 't' */
+ { 0x98, 0x77 }, /* LATIN SMALL LETTER W WITH RING ABOVE -> 'w' */
+ { 0x99, 0x79 }, /* LATIN SMALL LETTER Y WITH RING ABOVE -> 'y' */
+ { 0x9A, 0x61 }, /* LATIN SMALL LETTER A WITH RIGHT HALF RING -> 'a' */
+ { 0x9B, 0x53 }, /* LATIN SMALL LETTER LONG S WITH DOT ABOVE -> 'S' */
+ { 0xA0, 0x41 }, /* LATIN CAPITAL LETTER A WITH DOT BELOW -> 'A' */
+ { 0xA1, 0x61 }, /* LATIN SMALL LETTER A WITH DOT BELOW -> 'a' */
+ { 0xA2, 0x41 }, /* LATIN CAPITAL LETTER A WITH HOOK ABOVE -> 'A' */
+ { 0xA3, 0x61 }, /* LATIN SMALL LETTER A WITH HOOK ABOVE -> 'a' */
+ { 0xA4, 0x41 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE -> 'A' */
+ { 0xA5, 0x61 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE -> 'a' */
+ { 0xA6, 0x41 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE -> 'A' */
+ { 0xA7, 0x61 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE -> 'a' */
+ { 0xA8, 0x41 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE -> 'A' */
+ { 0xA9, 0x61 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE -> 'a' */
+ { 0xAA, 0x41 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE -> 'A' */
+ { 0xAB, 0x61 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE -> 'a' */
+ { 0xAC, 0x41 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW -> 'A' */
+ { 0xAD, 0x61 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW -> 'a' */
+ { 0xAE, 0x41 }, /* LATIN CAPITAL LETTER A WITH BREVE AND ACUTE -> 'A' */
+ { 0xAF, 0x61 }, /* LATIN SMALL LETTER A WITH BREVE AND ACUTE -> 'a' */
+ { 0xB0, 0x41 }, /* LATIN CAPITAL LETTER A WITH BREVE AND GRAVE -> 'A' */
+ { 0xB1, 0x61 }, /* LATIN SMALL LETTER A WITH BREVE AND GRAVE -> 'a' */
+ { 0xB2, 0x41 }, /* LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE -> 'A' */
+ { 0xB3, 0x61 }, /* LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE -> 'a' */
+ { 0xB4, 0x41 }, /* LATIN CAPITAL LETTER A WITH BREVE AND TILDE -> 'A' */
+ { 0xB5, 0x61 }, /* LATIN SMALL LETTER A WITH BREVE AND TILDE -> 'a' */
+ { 0xB6, 0x41 }, /* LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW -> 'A' */
+ { 0xB7, 0x61 }, /* LATIN SMALL LETTER A WITH BREVE AND DOT BELOW -> 'a' */
+ { 0xB8, 0x45 }, /* LATIN CAPITAL LETTER E WITH DOT BELOW -> 'E' */
+ { 0xB9, 0x65 }, /* LATIN SMALL LETTER E WITH DOT BELOW -> 'e' */
+ { 0xBA, 0x45 }, /* LATIN CAPITAL LETTER E WITH HOOK ABOVE -> 'E' */
+ { 0xBB, 0x65 }, /* LATIN SMALL LETTER E WITH HOOK ABOVE -> 'e' */
+ { 0xBC, 0x45 }, /* LATIN CAPITAL LETTER E WITH TILDE -> 'E' */
+ { 0xBD, 0x65 }, /* LATIN SMALL LETTER E WITH TILDE -> 'e' */
+ { 0xBE, 0x45 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE -> 'E' */
+ { 0xBF, 0x65 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE -> 'e' */
+ { 0xC0, 0x45 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE -> 'E' */
+ { 0xC1, 0x65 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE -> 'e' */
+ { 0xC2, 0x45 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE -> 'E' */
+ { 0xC3, 0x65 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE -> 'e' */
+ { 0xC4, 0x45 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE -> 'E' */
+ { 0xC5, 0x65 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE -> 'e' */
+ { 0xC6, 0x45 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW -> 'E' */
+ { 0xC7, 0x65 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW -> 'e' */
+ { 0xC8, 0x49 }, /* LATIN CAPITAL LETTER I WITH HOOK ABOVE -> 'I' */
+ { 0xC9, 0x69 }, /* LATIN SMALL LETTER I WITH HOOK ABOVE -> 'i' */
+ { 0xCA, 0x49 }, /* LATIN CAPITAL LETTER I WITH DOT BELOW -> 'I' */
+ { 0xCB, 0x69 }, /* LATIN SMALL LETTER I WITH DOT BELOW -> 'i' */
+ { 0xCC, 0x4F }, /* LATIN CAPITAL LETTER O WITH DOT BELOW -> 'O' */
+ { 0xCD, 0x6F }, /* LATIN SMALL LETTER O WITH DOT BELOW -> 'o' */
+ { 0xCE, 0x4F }, /* LATIN CAPITAL LETTER O WITH HOOK ABOVE -> 'O' */
+ { 0xCF, 0x6F }, /* LATIN SMALL LETTER O WITH HOOK ABOVE -> 'o' */
+ { 0xD0, 0x4F }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE -> 'O' */
+ { 0xD1, 0x6F }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE -> 'o' */
+ { 0xD2, 0x4F }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE -> 'O' */
+ { 0xD3, 0x6F }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE -> 'o' */
+ { 0xD4, 0x4F }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE -> 'O' */
+ { 0xD5, 0x6F }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE -> 'o' */
+ { 0xD6, 0x4F }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE -> 'O' */
+ { 0xD7, 0x6F }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE -> 'o' */
+ { 0xD8, 0x4F }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW -> 'O' */
+ { 0xD9, 0x6F }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW -> 'o' */
+ { 0xDA, 0x4F }, /* LATIN CAPITAL LETTER O WITH HORN AND ACUTE -> 'O' */
+ { 0xDB, 0x6F }, /* LATIN SMALL LETTER O WITH HORN AND ACUTE -> 'o' */
+ { 0xDC, 0x4F }, /* LATIN CAPITAL LETTER O WITH HORN AND GRAVE -> 'O' */
+ { 0xDD, 0x6F }, /* LATIN SMALL LETTER O WITH HORN AND GRAVE -> 'o' */
+ { 0xDE, 0x4F }, /* LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE -> 'O' */
+ { 0xDF, 0x6F }, /* LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE -> 'o' */
+ { 0xE0, 0x4F }, /* LATIN CAPITAL LETTER O WITH HORN AND TILDE -> 'O' */
+ { 0xE1, 0x6F }, /* LATIN SMALL LETTER O WITH HORN AND TILDE -> 'o' */
+ { 0xE2, 0x4F }, /* LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW -> 'O' */
+ { 0xE3, 0x6F }, /* LATIN SMALL LETTER O WITH HORN AND DOT BELOW -> 'o' */
+ { 0xE4, 0x55 }, /* LATIN CAPITAL LETTER U WITH DOT BELOW -> 'U' */
+ { 0xE5, 0x75 }, /* LATIN SMALL LETTER U WITH DOT BELOW -> 'u' */
+ { 0xE6, 0x55 }, /* LATIN CAPITAL LETTER U WITH HOOK ABOVE -> 'U' */
+ { 0xE7, 0x75 }, /* LATIN SMALL LETTER U WITH HOOK ABOVE -> 'u' */
+ { 0xE8, 0x55 }, /* LATIN CAPITAL LETTER U WITH HORN AND ACUTE -> 'U' */
+ { 0xE9, 0x75 }, /* LATIN SMALL LETTER U WITH HORN AND ACUTE -> 'u' */
+ { 0xEA, 0x55 }, /* LATIN CAPITAL LETTER U WITH HORN AND GRAVE -> 'U' */
+ { 0xEB, 0x75 }, /* LATIN SMALL LETTER U WITH HORN AND GRAVE -> 'u' */
+ { 0xEC, 0x55 }, /* LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE -> 'U' */
+ { 0xED, 0x75 }, /* LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE -> 'u' */
+ { 0xEE, 0x55 }, /* LATIN CAPITAL LETTER U WITH HORN AND TILDE -> 'U' */
+ { 0xEF, 0x75 }, /* LATIN SMALL LETTER U WITH HORN AND TILDE -> 'u' */
+ { 0xF0, 0x55 }, /* LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW -> 'U' */
+ { 0xF1, 0x75 }, /* LATIN SMALL LETTER U WITH HORN AND DOT BELOW -> 'u' */
+ { 0xF2, 0x59 }, /* LATIN CAPITAL LETTER Y WITH GRAVE -> 'Y' */
+ { 0xF3, 0x79 }, /* LATIN SMALL LETTER Y WITH GRAVE -> 'y' */
+ { 0xF4, 0x59 }, /* LATIN CAPITAL LETTER Y WITH DOT BELOW -> 'Y' */
+ { 0xF5, 0x79 }, /* LATIN SMALL LETTER Y WITH DOT BELOW -> 'y' */
+ { 0xF6, 0x59 }, /* LATIN CAPITAL LETTER Y WITH HOOK ABOVE -> 'Y' */
+ { 0xF7, 0x79 }, /* LATIN SMALL LETTER Y WITH HOOK ABOVE -> 'y' */
+ { 0xF8, 0x59 }, /* LATIN CAPITAL LETTER Y WITH TILDE -> 'Y' */
+ { 0xF9, 0x79 }, /* LATIN SMALL LETTER Y WITH TILDE -> 'y' */
+ /* Entries for page 0x1F */
+ { 0x00, 0x00 }, /* GREEK SMALL LETTER ALPHA WITH PSILI -> ... */
+ { 0x07, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI -> 'a' */
+ { 0x08, 0x00 }, /* GREEK CAPITAL LETTER ALPHA WITH PSILI -> ... */
+ { 0x0F, 0x41 }, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI -> 'A' */
+ { 0x10, 0x00 }, /* GREEK SMALL LETTER EPSILON WITH PSILI -> ... */
+ { 0x15, 0x65 }, /* GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA -> 'e' */
+ { 0x18, 0x00 }, /* GREEK CAPITAL LETTER EPSILON WITH PSILI -> ... */
+ { 0x1D, 0x45 }, /* GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA -> 'E' */
+ { 0x20, 0x00 }, /* GREEK SMALL LETTER ETA WITH PSILI -> ... */
+ { 0x27, 0x65 }, /* GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI -> 'e' */
+ { 0x28, 0x00 }, /* GREEK CAPITAL LETTER ETA WITH PSILI -> ... */
+ { 0x2F, 0x45 }, /* GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI -> 'E' */
+ { 0x30, 0x00 }, /* GREEK SMALL LETTER IOTA WITH PSILI -> ... */
+ { 0x37, 0x69 }, /* GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI -> 'i' */
+ { 0x38, 0x00 }, /* GREEK CAPITAL LETTER IOTA WITH PSILI -> ... */
+ { 0x3F, 0x49 }, /* GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI -> 'I' */
+ { 0x40, 0x00 }, /* GREEK SMALL LETTER OMICRON WITH PSILI -> ... */
+ { 0x45, 0x6F }, /* GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA -> 'o' */
+ { 0x48, 0x00 }, /* GREEK CAPITAL LETTER OMICRON WITH PSILI -> ... */
+ { 0x4D, 0x4F }, /* GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA -> 'O' */
+ { 0x50, 0x00 }, /* GREEK SMALL LETTER UPSILON WITH PSILI -> ... */
+ { 0x57, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI -> 'u' */
+ { 0x59, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH DASIA -> 'U' */
+ { 0x5B, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA -> 'U' */
+ { 0x5D, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA -> 'U' */
+ { 0x5F, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI -> 'U' */
+ { 0x60, 0x00 }, /* GREEK SMALL LETTER OMEGA WITH PSILI -> ... */
+ { 0x67, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI -> 'o' */
+ { 0x68, 0x00 }, /* GREEK CAPITAL LETTER OMEGA WITH PSILI -> ... */
+ { 0x6F, 0x4F }, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI -> 'O' */
+ { 0x70, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH VARIA -> 'a' */
+ { 0x71, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH OXIA -> 'a' */
+ { 0x72, 0x00 }, /* GREEK SMALL LETTER EPSILON WITH VARIA -> ... */
+ { 0x75, 0x65 }, /* GREEK SMALL LETTER ETA WITH OXIA -> 'e' */
+ { 0x76, 0x69 }, /* GREEK SMALL LETTER IOTA WITH VARIA -> 'i' */
+ { 0x77, 0x69 }, /* GREEK SMALL LETTER IOTA WITH OXIA -> 'i' */
+ { 0x78, 0x6F }, /* GREEK SMALL LETTER OMICRON WITH VARIA -> 'o' */
+ { 0x79, 0x6F }, /* GREEK SMALL LETTER OMICRON WITH OXIA -> 'o' */
+ { 0x7A, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH VARIA -> 'u' */
+ { 0x7B, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH OXIA -> 'u' */
+ { 0x7C, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH VARIA -> 'o' */
+ { 0x7D, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH OXIA -> 'o' */
+ { 0x80, 0x00 }, /* GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI -> ... */
+ { 0x87, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI -> 'a' */
+ { 0x88, 0x00 }, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI -> ... */
+ { 0x8F, 0x41 }, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI -> 'A' */
+ { 0x90, 0x00 }, /* GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI -> ... */
+ { 0x97, 0x65 }, /* GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI -> 'e' */
+ { 0x98, 0x00 }, /* GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI -> ... */
+ { 0x9F, 0x45 }, /* GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI -> 'E' */
+ { 0xA0, 0x00 }, /* GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI -> ... */
+ { 0xA7, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI -> 'o' */
+ { 0xA8, 0x00 }, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI -> ... */
+ { 0xAF, 0x4F }, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI -> 'O' */
+ { 0xB0, 0x00 }, /* GREEK SMALL LETTER ALPHA WITH VRACHY -> ... */
+ { 0xB4, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI -> 'a' */
+ { 0xB6, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI -> 'a' */
+ { 0xB7, 0x61 }, /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI -> 'a' */
+ { 0xB8, 0x00 }, /* GREEK CAPITAL LETTER ALPHA WITH VRACHY -> ... */
+ { 0xBC, 0x41 }, /* GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI -> 'A' */
+ { 0xBD, 0x27 }, /* GREEK KORONIS -> ''' */
+ { 0xBE, 0x69 }, /* GREEK PROSGEGRAMMENI -> 'i' */
+ { 0xBF, 0x27 }, /* GREEK PSILI -> ''' */
+ { 0xC0, 0x7E }, /* GREEK PERISPOMENI -> '~' */
+ { 0xC2, 0x00 }, /* GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI -> ... */
+ { 0xC4, 0x65 }, /* GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI -> 'e' */
+ { 0xC6, 0x65 }, /* GREEK SMALL LETTER ETA WITH PERISPOMENI -> 'e' */
+ { 0xC7, 0x65 }, /* GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI -> 'e' */
+ { 0xC8, 0x00 }, /* GREEK CAPITAL LETTER EPSILON WITH VARIA -> ... */
+ { 0xCC, 0x45 }, /* GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI -> 'E' */
+ { 0xD0, 0x00 }, /* GREEK SMALL LETTER IOTA WITH VRACHY -> ... */
+ { 0xD3, 0x69 }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA -> 'i' */
+ { 0xD6, 0x69 }, /* GREEK SMALL LETTER IOTA WITH PERISPOMENI -> 'i' */
+ { 0xD7, 0x69 }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI -> 'i' */
+ { 0xD8, 0x00 }, /* GREEK CAPITAL LETTER IOTA WITH VRACHY -> ... */
+ { 0xDB, 0x49 }, /* GREEK CAPITAL LETTER IOTA WITH OXIA -> 'I' */
+ { 0xE0, 0x00 }, /* GREEK SMALL LETTER UPSILON WITH VRACHY -> ... */
+ { 0xE3, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA -> 'u' */
+ { 0xE4, 0x52 }, /* GREEK SMALL LETTER RHO WITH PSILI -> 'R' */
+ { 0xE5, 0x52 }, /* GREEK SMALL LETTER RHO WITH DASIA -> 'R' */
+ { 0xE6, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH PERISPOMENI -> 'u' */
+ { 0xE7, 0x75 }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI -> 'u' */
+ { 0xE8, 0x00 }, /* GREEK CAPITAL LETTER UPSILON WITH VRACHY -> ... */
+ { 0xEB, 0x55 }, /* GREEK CAPITAL LETTER UPSILON WITH OXIA -> 'U' */
+ { 0xEC, 0x52 }, /* GREEK CAPITAL LETTER RHO WITH DASIA -> 'R' */
+ { 0xEF, 0x60 }, /* GREEK VARIA -> '`' */
+ { 0xF2, 0x00 }, /* GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI -> ... */
+ { 0xF4, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI -> 'o' */
+ { 0xF6, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI -> 'o' */
+ { 0xF7, 0x6F }, /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI -> 'o' */
+ { 0xF8, 0x00 }, /* GREEK CAPITAL LETTER OMICRON WITH VARIA -> ... */
+ { 0xFC, 0x4F }, /* GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI -> 'O' */
+ { 0xFD, 0x27 }, /* GREEK OXIA -> ''' */
+ { 0xFE, 0x60 }, /* GREEK DASIA -> '`' */
+ /* Entries for page 0x20 */
+ { 0x00, 0x00 }, /* EN QUAD -> ... */
+ { 0x0B, 0x20 }, /* ZERO WIDTH SPACE -> ' ' */
+ { 0x10, 0x00 }, /* HYPHEN -> ... */
+ { 0x15, 0x2D }, /* HORIZONTAL BAR -> '-' */
+ { 0x17, 0x5F }, /* DOUBLE LOW LINE -> '_' */
+ { 0x18, 0x27 }, /* LEFT SINGLE QUOTATION MARK -> ''' */
+ { 0x19, 0x27 }, /* RIGHT SINGLE QUOTATION MARK -> ''' */
+ { 0x1A, 0x2C }, /* SINGLE LOW-9 QUOTATION MARK -> ',' */
+ { 0x1B, 0x27 }, /* SINGLE HIGH-REVERSED-9 QUOTATION MARK -> ''' */
+ { 0x1C, 0x00 }, /* LEFT DOUBLE QUOTATION MARK -> ... */
+ { 0x1F, 0x22 }, /* DOUBLE HIGH-REVERSED-9 QUOTATION MARK -> '"' */
+ { 0x20, 0x2B }, /* DAGGER -> '+' */
+ { 0x22, 0x2A }, /* BULLET -> '*' */
+ { 0x23, 0x3E }, /* TRIANGULAR BULLET -> '>' */
+ { 0x24, 0x2E }, /* ONE DOT LEADER -> '.' */
+ { 0x26, 0x2E }, /* HORIZONTAL ELLIPSIS -> '.' */
+ { 0x27, 0x2E }, /* HYPHENATION POINT -> '.' */
+ { 0x2F, 0x20 }, /* NARROW NO-BREAK SPACE -> ' ' */
+ { 0x32, 0x27 }, /* PRIME -> ''' */
+ { 0x33, 0x22 }, /* DOUBLE PRIME -> '"' */
+ { 0x35, 0x60 }, /* REVERSED PRIME -> '`' */
+ { 0x38, 0x5E }, /* CARET -> '^' */
+ { 0x39, 0x3C }, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK -> '<' */
+ { 0x3A, 0x3E }, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -> '>' */
+ { 0x3B, 0x2A }, /* REFERENCE MARK -> '*' */
+ { 0x3C, 0x21 }, /* DOUBLE EXCLAMATION MARK -> '!' */
+ { 0x3D, 0x3F }, /* INTERROBANG -> '?' */
+ { 0x3E, 0x2D }, /* OVERLINE -> '-' */
+ { 0x3F, 0x5F }, /* UNDERTIE -> '_' */
+ { 0x40, 0x2D }, /* CHARACTER TIE -> '-' */
+ { 0x41, 0x5E }, /* CARET INSERTION POINT -> '^' */
+ { 0x42, 0x2A }, /* ASTERISM -> '*' */
+ { 0x43, 0x2D }, /* HYPHEN BULLET -> '-' */
+ { 0x44, 0x2F }, /* FRACTION SLASH -> '/' */
+ { 0x47, 0x3F }, /* DOUBLE QUESTION MARK -> '?' */
+ { 0x48, 0x3F }, /* QUESTION EXCLAMATION MARK -> '?' */
+ { 0x49, 0x21 }, /* EXCLAMATION QUESTION MARK -> '!' */
+ { 0x4A, 0x26 }, /* TIRONIAN SIGN ET -> '&' */
+ { 0x4B, 0x50 }, /* REVERSED PILCROW SIGN -> 'P' */
+ { 0x4C, 0x3C }, /* BLACK LEFTWARDS BULLET -> '<' */
+ { 0x4D, 0x3E }, /* BLACK RIGHTWARDS BULLET -> '>' */
+ { 0x4E, 0x2A }, /* LOW ASTERISK -> '*' */
+ { 0x4F, 0x3B }, /* REVERSED SEMICOLON -> ';' */
+ { 0x51, 0x2A }, /* TWO ASTERISKS ALIGNED VERTICALLY -> '*' */
+ { 0x52, 0x2D }, /* COMMERCIAL MINUS SIGN -> '-' */
+ { 0x53, 0x7E }, /* SWUNG DASH -> '~' */
+ { 0x55, 0x2A }, /* FLOWER PUNCTUATION MARK -> '*' */
+ { 0x5B, 0x3A }, /* FOUR DOT MARK -> ':' */
+ { 0x5F, 0x20 }, /* MEDIUM MATHEMATICAL SPACE -> ' ' */
+ { 0x70, 0x30 }, /* SUPERSCRIPT ZERO -> '0' */
+ { 0x71, 0x69 }, /* SUPERSCRIPT LATIN SMALL LETTER I -> 'i' */
+ { 0x74, 0x34 }, /* SUPERSCRIPT FOUR -> '4' */
+ { 0x75, 0x35 }, /* SUPERSCRIPT FIVE -> '5' */
+ { 0x76, 0x36 }, /* SUPERSCRIPT SIX -> '6' */
+ { 0x77, 0x37 }, /* SUPERSCRIPT SEVEN -> '7' */
+ { 0x78, 0x38 }, /* SUPERSCRIPT EIGHT -> '8' */
+ { 0x79, 0x39 }, /* SUPERSCRIPT NINE -> '9' */
+ { 0x7A, 0x2B }, /* SUPERSCRIPT PLUS SIGN -> '+' */
+ { 0x7B, 0x2D }, /* SUPERSCRIPT MINUS -> '-' */
+ { 0x7C, 0x3D }, /* SUPERSCRIPT EQUALS SIGN -> '=' */
+ { 0x7D, 0x28 }, /* SUPERSCRIPT LEFT PARENTHESIS -> '(' */
+ { 0x7E, 0x29 }, /* SUPERSCRIPT RIGHT PARENTHESIS -> ')' */
+ { 0x7F, 0x6E }, /* SUPERSCRIPT LATIN SMALL LETTER N -> 'n' */
+ { 0x80, 0x30 }, /* SUBSCRIPT ZERO -> '0' */
+ { 0x81, 0x31 }, /* SUBSCRIPT ONE -> '1' */
+ { 0x82, 0x32 }, /* SUBSCRIPT TWO -> '2' */
+ { 0x83, 0x33 }, /* SUBSCRIPT THREE -> '3' */
+ { 0x84, 0x34 }, /* SUBSCRIPT FOUR -> '4' */
+ { 0x85, 0x35 }, /* SUBSCRIPT FIVE -> '5' */
+ { 0x86, 0x36 }, /* SUBSCRIPT SIX -> '6' */
+ { 0x87, 0x37 }, /* SUBSCRIPT SEVEN -> '7' */
+ { 0x88, 0x38 }, /* SUBSCRIPT EIGHT -> '8' */
+ { 0x89, 0x39 }, /* SUBSCRIPT NINE -> '9' */
+ { 0x8A, 0x2B }, /* SUBSCRIPT PLUS SIGN -> '+' */
+ { 0x8B, 0x2D }, /* SUBSCRIPT MINUS -> '-' */
+ { 0x8C, 0x3D }, /* SUBSCRIPT EQUALS SIGN -> '=' */
+ { 0x8D, 0x28 }, /* SUBSCRIPT LEFT PARENTHESIS -> '(' */
+ { 0x8E, 0x29 }, /* SUBSCRIPT RIGHT PARENTHESIS -> ')' */
+ { 0x90, 0x61 }, /* LATIN SUBSCRIPT SMALL LETTER A -> 'a' */
+ { 0x91, 0x65 }, /* LATIN SUBSCRIPT SMALL LETTER E -> 'e' */
+ { 0x92, 0x6F }, /* LATIN SUBSCRIPT SMALL LETTER O -> 'o' */
+ { 0x93, 0x78 }, /* LATIN SUBSCRIPT SMALL LETTER X -> 'x' */
+ { 0x95, 0x68 }, /* LATIN SUBSCRIPT SMALL LETTER H -> 'h' */
+ { 0x96, 0x6B }, /* LATIN SUBSCRIPT SMALL LETTER K -> 'k' */
+ { 0x97, 0x6C }, /* LATIN SUBSCRIPT SMALL LETTER L -> 'l' */
+ { 0x98, 0x6D }, /* LATIN SUBSCRIPT SMALL LETTER M -> 'm' */
+ { 0x99, 0x6E }, /* LATIN SUBSCRIPT SMALL LETTER N -> 'n' */
+ { 0x9A, 0x70 }, /* LATIN SUBSCRIPT SMALL LETTER P -> 'p' */
+ { 0x9B, 0x73 }, /* LATIN SUBSCRIPT SMALL LETTER S -> 's' */
+ { 0x9C, 0x74 }, /* LATIN SUBSCRIPT SMALL LETTER T -> 't' */
+ { 0xA4, 0x4C }, /* LIRA SIGN -> 'L' */
+ { 0xA6, 0x4E }, /* NAIRA SIGN -> 'N' */
+ { 0xA9, 0x57 }, /* WON SIGN -> 'W' */
+ { 0xAB, 0x44 }, /* DONG SIGN -> 'D' */
+ { 0xAC, 0x45 }, /* EURO SIGN -> 'E' */
+ { 0xAD, 0x4B }, /* KIP SIGN -> 'K' */
+ { 0xAE, 0x54 }, /* TUGRIK SIGN -> 'T' */
+ { 0xB1, 0x50 }, /* PESO SIGN -> 'P' */
+ { 0xB2, 0x47 }, /* GUARANI SIGN -> 'G' */
+ { 0xB3, 0x41 }, /* AUSTRAL SIGN -> 'A' */
+ { 0xB6, 0x4C }, /* LIVRE TOURNOIS SIGN -> 'L' */
+ { 0xB8, 0x54 }, /* TENGE SIGN -> 'T' */
+ { 0xBA, 0x4C }, /* TURKISH LIRA SIGN -> 'L' */
+ { 0xBB, 0x4D }, /* NORDIC MARK SIGN -> 'M' */
+ { 0xBC, 0x6D }, /* MANAT SIGN -> 'm' */
+ { 0xBD, 0x52 }, /* RUBLE SIGN -> 'R' */
+ { 0xBE, 0x6C }, /* LARI SIGN -> 'l' */
+ /* Entries for page 0x21 */
+ { 0x02, 0x43 }, /* DOUBLE-STRUCK CAPITAL C -> 'C' */
+ { 0x03, 0x43 }, /* DEGREE CELSIUS -> 'C' */
+ { 0x09, 0x46 }, /* DEGREE FAHRENHEIT -> 'F' */
+ { 0x0A, 0x67 }, /* SCRIPT SMALL G -> 'g' */
+ { 0x0B, 0x00 }, /* SCRIPT CAPITAL H -> ... */
+ { 0x0D, 0x48 }, /* DOUBLE-STRUCK CAPITAL H -> 'H' */
+ { 0x0E, 0x68 }, /* PLANCK CONSTANT -> 'h' */
+ { 0x10, 0x49 }, /* SCRIPT CAPITAL I -> 'I' */
+ { 0x11, 0x49 }, /* BLACK-LETTER CAPITAL I -> 'I' */
+ { 0x12, 0x4C }, /* SCRIPT CAPITAL L -> 'L' */
+ { 0x13, 0x6C }, /* SCRIPT SMALL L -> 'l' */
+ { 0x15, 0x4E }, /* DOUBLE-STRUCK CAPITAL N -> 'N' */
+ { 0x19, 0x50 }, /* DOUBLE-STRUCK CAPITAL P -> 'P' */
+ { 0x1A, 0x51 }, /* DOUBLE-STRUCK CAPITAL Q -> 'Q' */
+ { 0x1B, 0x00 }, /* SCRIPT CAPITAL R -> ... */
+ { 0x1D, 0x52 }, /* DOUBLE-STRUCK CAPITAL R -> 'R' */
+ { 0x22, 0x54 }, /* TRADE MARK SIGN -> 'T' */
+ { 0x24, 0x5A }, /* DOUBLE-STRUCK CAPITAL Z -> 'Z' */
+ { 0x28, 0x5A }, /* BLACK-LETTER CAPITAL Z -> 'Z' */
+ { 0x2A, 0x4B }, /* KELVIN SIGN -> 'K' */
+ { 0x2B, 0x41 }, /* ANGSTROM SIGN -> 'A' */
+ { 0x2C, 0x42 }, /* SCRIPT CAPITAL B -> 'B' */
+ { 0x2D, 0x43 }, /* BLACK-LETTER CAPITAL C -> 'C' */
+ { 0x2E, 0x65 }, /* ESTIMATED SYMBOL -> 'e' */
+ { 0x2F, 0x65 }, /* SCRIPT SMALL E -> 'e' */
+ { 0x30, 0x45 }, /* SCRIPT CAPITAL E -> 'E' */
+ { 0x31, 0x46 }, /* SCRIPT CAPITAL F -> 'F' */
+ { 0x32, 0x46 }, /* TURNED CAPITAL F -> 'F' */
+ { 0x33, 0x4D }, /* SCRIPT CAPITAL M -> 'M' */
+ { 0x34, 0x6F }, /* SCRIPT SMALL O -> 'o' */
+ { 0x39, 0x69 }, /* INFORMATION SOURCE -> 'i' */
+ { 0x45, 0x44 }, /* DOUBLE-STRUCK ITALIC CAPITAL D -> 'D' */
+ { 0x46, 0x64 }, /* DOUBLE-STRUCK ITALIC SMALL D -> 'd' */
+ { 0x47, 0x65 }, /* DOUBLE-STRUCK ITALIC SMALL E -> 'e' */
+ { 0x48, 0x69 }, /* DOUBLE-STRUCK ITALIC SMALL I -> 'i' */
+ { 0x49, 0x6A }, /* DOUBLE-STRUCK ITALIC SMALL J -> 'j' */
+ { 0x4E, 0x46 }, /* TURNED SMALL F -> 'F' */
+ { 0x60, 0x49 }, /* ROMAN NUMERAL ONE -> 'I' */
+ { 0x64, 0x56 }, /* ROMAN NUMERAL FIVE -> 'V' */
+ { 0x69, 0x58 }, /* ROMAN NUMERAL TEN -> 'X' */
+ { 0x6C, 0x4C }, /* ROMAN NUMERAL FIFTY -> 'L' */
+ { 0x6D, 0x43 }, /* ROMAN NUMERAL ONE HUNDRED -> 'C' */
+ { 0x6E, 0x44 }, /* ROMAN NUMERAL FIVE HUNDRED -> 'D' */
+ { 0x6F, 0x4D }, /* ROMAN NUMERAL ONE THOUSAND -> 'M' */
+ { 0x70, 0x69 }, /* SMALL ROMAN NUMERAL ONE -> 'i' */
+ { 0x74, 0x76 }, /* SMALL ROMAN NUMERAL FIVE -> 'v' */
+ { 0x79, 0x78 }, /* SMALL ROMAN NUMERAL TEN -> 'x' */
+ { 0x7C, 0x6C }, /* SMALL ROMAN NUMERAL FIFTY -> 'l' */
+ { 0x7D, 0x63 }, /* SMALL ROMAN NUMERAL ONE HUNDRED -> 'c' */
+ { 0x7E, 0x64 }, /* SMALL ROMAN NUMERAL FIVE HUNDRED -> 'd' */
+ { 0x7F, 0x6D }, /* SMALL ROMAN NUMERAL ONE THOUSAND -> 'm' */
+ { 0x83, 0x29 }, /* ROMAN NUMERAL REVERSED ONE HUNDRED -> ')' */
+ { 0x90, 0x3C }, /* LEFTWARDS ARROW -> '<' */
+ { 0x91, 0x5E }, /* UPWARDS ARROW -> '^' */
+ { 0x92, 0x3E }, /* RIGHTWARDS ARROW -> '>' */
+ { 0x93, 0x76 }, /* DOWNWARDS ARROW -> 'v' */
+ { 0x94, 0x2D }, /* LEFT RIGHT ARROW -> '-' */
+ { 0x95, 0x7C }, /* UP DOWN ARROW -> '|' */
+ { 0x96, 0x5C }, /* NORTH WEST ARROW -> '\' */
+ { 0x97, 0x2F }, /* NORTH EAST ARROW -> '/' */
+ { 0x98, 0x5C }, /* SOUTH EAST ARROW -> '\' */
+ { 0x99, 0x2F }, /* SOUTH WEST ARROW -> '/' */
+ { 0x9A, 0x21 }, /* LEFTWARDS ARROW WITH STROKE -> '!' */
+ { 0x9B, 0x21 }, /* RIGHTWARDS ARROW WITH STROKE -> '!' */
+ { 0x9C, 0x7E }, /* LEFTWARDS WAVE ARROW -> '~' */
+ { 0x9D, 0x7E }, /* RIGHTWARDS WAVE ARROW -> '~' */
+ { 0x9E, 0x2D }, /* LEFTWARDS TWO HEADED ARROW -> '-' */
+ { 0x9F, 0x7C }, /* UPWARDS TWO HEADED ARROW -> '|' */
+ { 0xA0, 0x2D }, /* RIGHTWARDS TWO HEADED ARROW -> '-' */
+ { 0xA1, 0x7C }, /* DOWNWARDS TWO HEADED ARROW -> '|' */
+ { 0xA2, 0x00 }, /* LEFTWARDS ARROW WITH TAIL -> ... */
+ { 0xA4, 0x2D }, /* LEFTWARDS ARROW FROM BAR -> '-' */
+ { 0xA5, 0x7C }, /* UPWARDS ARROW FROM BAR -> '|' */
+ { 0xA6, 0x2D }, /* RIGHTWARDS ARROW FROM BAR -> '-' */
+ { 0xA7, 0x7C }, /* DOWNWARDS ARROW FROM BAR -> '|' */
+ { 0xA8, 0x7C }, /* UP DOWN ARROW WITH BASE -> '|' */
+ { 0xA9, 0x00 }, /* LEFTWARDS ARROW WITH HOOK -> ... */
+ { 0xAD, 0x2D }, /* LEFT RIGHT WAVE ARROW -> '-' */
+ { 0xAE, 0x21 }, /* LEFT RIGHT ARROW WITH STROKE -> '!' */
+ { 0xAF, 0x00 }, /* DOWNWARDS ZIGZAG ARROW -> ... */
+ { 0xB5, 0x7C }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS -> '|' */
+ { 0xB6, 0x5E }, /* ANTICLOCKWISE TOP SEMICIRCLE ARROW -> '^' */
+ { 0xB7, 0x56 }, /* CLOCKWISE TOP SEMICIRCLE ARROW -> 'V' */
+ { 0xB8, 0x5C }, /* NORTH WEST ARROW TO LONG BAR -> '\' */
+ { 0xB9, 0x3D }, /* LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR -> '=' */
+ { 0xBA, 0x56 }, /* ANTICLOCKWISE OPEN CIRCLE ARROW -> 'V' */
+ { 0xBB, 0x5E }, /* CLOCKWISE OPEN CIRCLE ARROW -> '^' */
+ { 0xBC, 0x2D }, /* LEFTWARDS HARPOON WITH BARB UPWARDS -> '-' */
+ { 0xBD, 0x2D }, /* LEFTWARDS HARPOON WITH BARB DOWNWARDS -> '-' */
+ { 0xBE, 0x7C }, /* UPWARDS HARPOON WITH BARB RIGHTWARDS -> '|' */
+ { 0xBF, 0x7C }, /* UPWARDS HARPOON WITH BARB LEFTWARDS -> '|' */
+ { 0xC0, 0x2D }, /* RIGHTWARDS HARPOON WITH BARB UPWARDS -> '-' */
+ { 0xC1, 0x2D }, /* RIGHTWARDS HARPOON WITH BARB DOWNWARDS -> '-' */
+ { 0xC2, 0x7C }, /* DOWNWARDS HARPOON WITH BARB RIGHTWARDS -> '|' */
+ { 0xC3, 0x7C }, /* DOWNWARDS HARPOON WITH BARB LEFTWARDS -> '|' */
+ { 0xC4, 0x3D }, /* RIGHTWARDS ARROW OVER LEFTWARDS ARROW -> '=' */
+ { 0xC5, 0x7C }, /* UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW -> '|' */
+ { 0xC6, 0x3D }, /* LEFTWARDS ARROW OVER RIGHTWARDS ARROW -> '=' */
+ { 0xC7, 0x3D }, /* LEFTWARDS PAIRED ARROWS -> '=' */
+ { 0xC8, 0x7C }, /* UPWARDS PAIRED ARROWS -> '|' */
+ { 0xC9, 0x3D }, /* RIGHTWARDS PAIRED ARROWS -> '=' */
+ { 0xCA, 0x7C }, /* DOWNWARDS PAIRED ARROWS -> '|' */
+ { 0xCB, 0x3D }, /* LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON -> '=' */
+ { 0xCC, 0x3D }, /* RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON -> '=' */
+ { 0xCD, 0x00 }, /* LEFTWARDS DOUBLE ARROW WITH STROKE -> ... */
+ { 0xCF, 0x21 }, /* RIGHTWARDS DOUBLE ARROW WITH STROKE -> '!' */
+ { 0xD0, 0x3C }, /* LEFTWARDS DOUBLE ARROW -> '<' */
+ { 0xD1, 0x5E }, /* UPWARDS DOUBLE ARROW -> '^' */
+ { 0xD2, 0x3E }, /* RIGHTWARDS DOUBLE ARROW -> '>' */
+ { 0xD3, 0x76 }, /* DOWNWARDS DOUBLE ARROW -> 'v' */
+ { 0xD4, 0x3D }, /* LEFT RIGHT DOUBLE ARROW -> '=' */
+ { 0xD5, 0x7C }, /* UP DOWN DOUBLE ARROW -> '|' */
+ { 0xD6, 0x5C }, /* NORTH WEST DOUBLE ARROW -> '\' */
+ { 0xD7, 0x2F }, /* NORTH EAST DOUBLE ARROW -> '/' */
+ { 0xD8, 0x5C }, /* SOUTH EAST DOUBLE ARROW -> '\' */
+ { 0xD9, 0x2F }, /* SOUTH WEST DOUBLE ARROW -> '/' */
+ { 0xDA, 0x3D }, /* LEFTWARDS TRIPLE ARROW -> '=' */
+ { 0xDB, 0x3D }, /* RIGHTWARDS TRIPLE ARROW -> '=' */
+ { 0xDC, 0x7E }, /* LEFTWARDS SQUIGGLE ARROW -> '~' */
+ { 0xDD, 0x7E }, /* RIGHTWARDS SQUIGGLE ARROW -> '~' */
+ { 0xDE, 0x7C }, /* UPWARDS ARROW WITH DOUBLE STROKE -> '|' */
+ { 0xDF, 0x7C }, /* DOWNWARDS ARROW WITH DOUBLE STROKE -> '|' */
+ { 0xE0, 0x2D }, /* LEFTWARDS DASHED ARROW -> '-' */
+ { 0xE1, 0x7C }, /* UPWARDS DASHED ARROW -> '|' */
+ { 0xE2, 0x2D }, /* RIGHTWARDS DASHED ARROW -> '-' */
+ { 0xE3, 0x7C }, /* DOWNWARDS DASHED ARROW -> '|' */
+ { 0xE4, 0x00 }, /* LEFTWARDS ARROW TO BAR -> ... */
+ { 0xE6, 0x2D }, /* LEFTWARDS WHITE ARROW -> '-' */
+ { 0xE7, 0x7C }, /* UPWARDS WHITE ARROW -> '|' */
+ { 0xE8, 0x2D }, /* RIGHTWARDS WHITE ARROW -> '-' */
+ { 0xE9, 0x00 }, /* DOWNWARDS WHITE ARROW -> ... */
+ { 0xEF, 0x7C }, /* UPWARDS WHITE DOUBLE ARROW ON PEDESTAL -> '|' */
+ { 0xF0, 0x2D }, /* RIGHTWARDS WHITE ARROW FROM WALL -> '-' */
+ { 0xF1, 0x5C }, /* NORTH WEST ARROW TO CORNER -> '\' */
+ { 0xF2, 0x5C }, /* SOUTH EAST ARROW TO CORNER -> '\' */
+ { 0xF3, 0x7C }, /* UP DOWN WHITE ARROW -> '|' */
+ /* Entries for page 0x22 */
+ { 0x04, 0x21 }, /* THERE DOES NOT EXIST -> '!' */
+ { 0x09, 0x21 }, /* NOT AN ELEMENT OF -> '!' */
+ { 0x0C, 0x21 }, /* DOES NOT CONTAIN AS MEMBER -> '!' */
+ { 0x12, 0x2D }, /* MINUS SIGN -> '-' */
+ { 0x15, 0x2F }, /* DIVISION SLASH -> '/' */
+ { 0x16, 0x5C }, /* SET MINUS -> '\' */
+ { 0x17, 0x2A }, /* ASTERISK OPERATOR -> '*' */
+ { 0x18, 0x6F }, /* RING OPERATOR -> 'o' */
+ { 0x19, 0x2E }, /* BULLET OPERATOR -> '.' */
+ { 0x23, 0x7C }, /* DIVIDES -> '|' */
+ { 0x24, 0x21 }, /* DOES NOT DIVIDE -> '!' */
+ { 0x26, 0x21 }, /* NOT PARALLEL TO -> '!' */
+ { 0x36, 0x3A }, /* RATIO -> ':' */
+ { 0x3C, 0x7E }, /* TILDE OPERATOR -> '~' */
+ { 0x41, 0x23 }, /* NOT TILDE -> '#' */
+ { 0x44, 0x23 }, /* NOT ASYMPTOTICALLY EQUAL TO -> '#' */
+ { 0x49, 0x23 }, /* NOT ALMOST EQUAL TO -> '#' */
+ { 0x60, 0x23 }, /* NOT EQUAL TO -> '#' */
+ { 0x62, 0x23 }, /* NOT IDENTICAL TO -> '#' */
+ { 0x64, 0x3C }, /* LESS-THAN OR EQUAL TO -> '<' */
+ { 0x65, 0x3E }, /* GREATER-THAN OR EQUAL TO -> '>' */
+ { 0x68, 0x23 }, /* LESS-THAN BUT NOT EQUAL TO -> '#' */
+ { 0x69, 0x23 }, /* GREATER-THAN BUT NOT EQUAL TO -> '#' */
+ { 0x6D, 0x23 }, /* NOT EQUIVALENT TO -> '#' */
+ { 0x6E, 0x21 }, /* NOT LESS-THAN -> '!' */
+ { 0x6F, 0x21 }, /* NOT GREATER-THAN -> '!' */
+ { 0x80, 0x21 }, /* DOES NOT PRECEDE -> '!' */
+ { 0x81, 0x21 }, /* DOES NOT SUCCEED -> '!' */
+ { 0x84, 0x21 }, /* NOT A SUBSET OF -> '!' */
+ { 0x85, 0x21 }, /* NOT A SUPERSET OF -> '!' */
+ { 0x8A, 0x23 }, /* SUBSET OF WITH NOT EQUAL TO -> '#' */
+ { 0x8B, 0x23 }, /* SUPERSET OF WITH NOT EQUAL TO -> '#' */
+ { 0x9B, 0x2A }, /* CIRCLED ASTERISK OPERATOR -> '*' */
+ { 0xC6, 0x2A }, /* STAR OPERATOR -> '*' */
+ /* Entries for page 0x23 */
+ { 0x03, 0x5E }, /* UP ARROWHEAD -> '^' */
+ { 0x29, 0x3C }, /* LEFT-POINTING ANGLE BRACKET -> '<' */
+ { 0x5F, 0x2A }, /* APL FUNCTIONAL SYMBOL CIRCLE STAR -> '*' */
+ { 0x63, 0x2A }, /* APL FUNCTIONAL SYMBOL STAR DIAERESIS -> '*' */
+ /* Entries for page 0x24 */
+ { 0x60, 0x31 }, /* CIRCLED DIGIT ONE -> '1' */
+ { 0x61, 0x32 }, /* CIRCLED DIGIT TWO -> '2' */
+ { 0x62, 0x33 }, /* CIRCLED DIGIT THREE -> '3' */
+ { 0x63, 0x34 }, /* CIRCLED DIGIT FOUR -> '4' */
+ { 0x64, 0x35 }, /* CIRCLED DIGIT FIVE -> '5' */
+ { 0x65, 0x36 }, /* CIRCLED DIGIT SIX -> '6' */
+ { 0x66, 0x37 }, /* CIRCLED DIGIT SEVEN -> '7' */
+ { 0x67, 0x38 }, /* CIRCLED DIGIT EIGHT -> '8' */
+ { 0x68, 0x39 }, /* CIRCLED DIGIT NINE -> '9' */
+ { 0xB6, 0x41 }, /* CIRCLED LATIN CAPITAL LETTER A -> 'A' */
+ { 0xB7, 0x42 }, /* CIRCLED LATIN CAPITAL LETTER B -> 'B' */
+ { 0xB8, 0x43 }, /* CIRCLED LATIN CAPITAL LETTER C -> 'C' */
+ { 0xB9, 0x44 }, /* CIRCLED LATIN CAPITAL LETTER D -> 'D' */
+ { 0xBA, 0x45 }, /* CIRCLED LATIN CAPITAL LETTER E -> 'E' */
+ { 0xBB, 0x46 }, /* CIRCLED LATIN CAPITAL LETTER F -> 'F' */
+ { 0xBC, 0x47 }, /* CIRCLED LATIN CAPITAL LETTER G -> 'G' */
+ { 0xBD, 0x48 }, /* CIRCLED LATIN CAPITAL LETTER H -> 'H' */
+ { 0xBE, 0x49 }, /* CIRCLED LATIN CAPITAL LETTER I -> 'I' */
+ { 0xBF, 0x4A }, /* CIRCLED LATIN CAPITAL LETTER J -> 'J' */
+ { 0xC0, 0x4B }, /* CIRCLED LATIN CAPITAL LETTER K -> 'K' */
+ { 0xC1, 0x4C }, /* CIRCLED LATIN CAPITAL LETTER L -> 'L' */
+ { 0xC2, 0x4D }, /* CIRCLED LATIN CAPITAL LETTER M -> 'M' */
+ { 0xC3, 0x4E }, /* CIRCLED LATIN CAPITAL LETTER N -> 'N' */
+ { 0xC4, 0x4F }, /* CIRCLED LATIN CAPITAL LETTER O -> 'O' */
+ { 0xC5, 0x50 }, /* CIRCLED LATIN CAPITAL LETTER P -> 'P' */
+ { 0xC6, 0x51 }, /* CIRCLED LATIN CAPITAL LETTER Q -> 'Q' */
+ { 0xC7, 0x52 }, /* CIRCLED LATIN CAPITAL LETTER R -> 'R' */
+ { 0xC8, 0x53 }, /* CIRCLED LATIN CAPITAL LETTER S -> 'S' */
+ { 0xC9, 0x54 }, /* CIRCLED LATIN CAPITAL LETTER T -> 'T' */
+ { 0xCA, 0x55 }, /* CIRCLED LATIN CAPITAL LETTER U -> 'U' */
+ { 0xCB, 0x56 }, /* CIRCLED LATIN CAPITAL LETTER V -> 'V' */
+ { 0xCC, 0x57 }, /* CIRCLED LATIN CAPITAL LETTER W -> 'W' */
+ { 0xCD, 0x58 }, /* CIRCLED LATIN CAPITAL LETTER X -> 'X' */
+ { 0xCE, 0x59 }, /* CIRCLED LATIN CAPITAL LETTER Y -> 'Y' */
+ { 0xCF, 0x5A }, /* CIRCLED LATIN CAPITAL LETTER Z -> 'Z' */
+ { 0xD0, 0x61 }, /* CIRCLED LATIN SMALL LETTER A -> 'a' */
+ { 0xD1, 0x62 }, /* CIRCLED LATIN SMALL LETTER B -> 'b' */
+ { 0xD2, 0x63 }, /* CIRCLED LATIN SMALL LETTER C -> 'c' */
+ { 0xD3, 0x64 }, /* CIRCLED LATIN SMALL LETTER D -> 'd' */
+ { 0xD4, 0x65 }, /* CIRCLED LATIN SMALL LETTER E -> 'e' */
+ { 0xD5, 0x66 }, /* CIRCLED LATIN SMALL LETTER F -> 'f' */
+ { 0xD6, 0x67 }, /* CIRCLED LATIN SMALL LETTER G -> 'g' */
+ { 0xD7, 0x68 }, /* CIRCLED LATIN SMALL LETTER H -> 'h' */
+ { 0xD8, 0x69 }, /* CIRCLED LATIN SMALL LETTER I -> 'i' */
+ { 0xD9, 0x6A }, /* CIRCLED LATIN SMALL LETTER J -> 'j' */
+ { 0xDA, 0x6B }, /* CIRCLED LATIN SMALL LETTER K -> 'k' */
+ { 0xDB, 0x6C }, /* CIRCLED LATIN SMALL LETTER L -> 'l' */
+ { 0xDC, 0x6D }, /* CIRCLED LATIN SMALL LETTER M -> 'm' */
+ { 0xDD, 0x6E }, /* CIRCLED LATIN SMALL LETTER N -> 'n' */
+ { 0xDE, 0x6F }, /* CIRCLED LATIN SMALL LETTER O -> 'o' */
+ { 0xDF, 0x70 }, /* CIRCLED LATIN SMALL LETTER P -> 'p' */
+ { 0xE0, 0x71 }, /* CIRCLED LATIN SMALL LETTER Q -> 'q' */
+ { 0xE1, 0x72 }, /* CIRCLED LATIN SMALL LETTER R -> 'r' */
+ { 0xE2, 0x73 }, /* CIRCLED LATIN SMALL LETTER S -> 's' */
+ { 0xE3, 0x74 }, /* CIRCLED LATIN SMALL LETTER T -> 't' */
+ { 0xE4, 0x75 }, /* CIRCLED LATIN SMALL LETTER U -> 'u' */
+ { 0xE5, 0x76 }, /* CIRCLED LATIN SMALL LETTER V -> 'v' */
+ { 0xE6, 0x77 }, /* CIRCLED LATIN SMALL LETTER W -> 'w' */
+ { 0xE7, 0x78 }, /* CIRCLED LATIN SMALL LETTER X -> 'x' */
+ { 0xE8, 0x79 }, /* CIRCLED LATIN SMALL LETTER Y -> 'y' */
+ { 0xE9, 0x7A }, /* CIRCLED LATIN SMALL LETTER Z -> 'z' */
+ { 0xEA, 0x30 }, /* CIRCLED DIGIT ZERO -> '0' */
+ { 0xF5, 0x31 }, /* DOUBLE CIRCLED DIGIT ONE -> '1' */
+ { 0xF6, 0x32 }, /* DOUBLE CIRCLED DIGIT TWO -> '2' */
+ { 0xF7, 0x33 }, /* DOUBLE CIRCLED DIGIT THREE -> '3' */
+ { 0xF8, 0x34 }, /* DOUBLE CIRCLED DIGIT FOUR -> '4' */
+ { 0xF9, 0x35 }, /* DOUBLE CIRCLED DIGIT FIVE -> '5' */
+ { 0xFA, 0x36 }, /* DOUBLE CIRCLED DIGIT SIX -> '6' */
+ { 0xFB, 0x37 }, /* DOUBLE CIRCLED DIGIT SEVEN -> '7' */
+ { 0xFC, 0x38 }, /* DOUBLE CIRCLED DIGIT EIGHT -> '8' */
+ { 0xFD, 0x39 }, /* DOUBLE CIRCLED DIGIT NINE -> '9' */
+ { 0xFF, 0x30 }, /* NEGATIVE CIRCLED DIGIT ZERO -> '0' */
+ /* Entries for page 0x25 */
+ { 0x00, 0x2D }, /* BOX DRAWINGS LIGHT HORIZONTAL -> '-' */
+ { 0x01, 0x2D }, /* BOX DRAWINGS HEAVY HORIZONTAL -> '-' */
+ { 0x02, 0x7C }, /* BOX DRAWINGS LIGHT VERTICAL -> '|' */
+ { 0x03, 0x7C }, /* BOX DRAWINGS HEAVY VERTICAL -> '|' */
+ { 0x04, 0x2D }, /* BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL -> '-' */
+ { 0x05, 0x2D }, /* BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL -> '-' */
+ { 0x06, 0x7C }, /* BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL -> '|' */
+ { 0x07, 0x7C }, /* BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL -> '|' */
+ { 0x08, 0x2D }, /* BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL -> '-' */
+ { 0x09, 0x2D }, /* BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL -> '-' */
+ { 0x0A, 0x7C }, /* BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL -> '|' */
+ { 0x0B, 0x7C }, /* BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL -> '|' */
+ { 0x0C, 0x00 }, /* BOX DRAWINGS LIGHT DOWN AND RIGHT -> ... */
+ { 0x4B, 0x2B }, /* BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL -> '+' */
+ { 0x4C, 0x2D }, /* BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL -> '-' */
+ { 0x4D, 0x2D }, /* BOX DRAWINGS HEAVY DOUBLE DASH HORIZONTAL -> '-' */
+ { 0x4E, 0x7C }, /* BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL -> '|' */
+ { 0x4F, 0x7C }, /* BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL -> '|' */
+ { 0x50, 0x2D }, /* BOX DRAWINGS DOUBLE HORIZONTAL -> '-' */
+ { 0x51, 0x7C }, /* BOX DRAWINGS DOUBLE VERTICAL -> '|' */
+ { 0x52, 0x00 }, /* BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE -> ... */
+ { 0x70, 0x2B }, /* BOX DRAWINGS LIGHT ARC UP AND RIGHT -> '+' */
+ { 0x71, 0x2F }, /* BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT -> '/' */
+ { 0x72, 0x5C }, /* BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT -> '\' */
+ { 0x73, 0x58 }, /* BOX DRAWINGS LIGHT DIAGONAL CROSS -> 'X' */
+ { 0x74, 0x2D }, /* BOX DRAWINGS LIGHT LEFT -> '-' */
+ { 0x75, 0x7C }, /* BOX DRAWINGS LIGHT UP -> '|' */
+ { 0x76, 0x2D }, /* BOX DRAWINGS LIGHT RIGHT -> '-' */
+ { 0x77, 0x7C }, /* BOX DRAWINGS LIGHT DOWN -> '|' */
+ { 0x78, 0x2D }, /* BOX DRAWINGS HEAVY LEFT -> '-' */
+ { 0x79, 0x7C }, /* BOX DRAWINGS HEAVY UP -> '|' */
+ { 0x7A, 0x2D }, /* BOX DRAWINGS HEAVY RIGHT -> '-' */
+ { 0x7B, 0x7C }, /* BOX DRAWINGS HEAVY DOWN -> '|' */
+ { 0x7C, 0x2D }, /* BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT -> '-' */
+ { 0x7D, 0x7C }, /* BOX DRAWINGS LIGHT UP AND HEAVY DOWN -> '|' */
+ { 0x7E, 0x2D }, /* BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT -> '-' */
+ { 0x7F, 0x7C }, /* BOX DRAWINGS HEAVY UP AND LIGHT DOWN -> '|' */
+ { 0x80, 0x00 }, /* UPPER HALF BLOCK -> ... */
+ { 0x93, 0x23 }, /* DARK SHADE -> '#' */
+ { 0x94, 0x2D }, /* UPPER ONE EIGHTH BLOCK -> '-' */
+ { 0x95, 0x7C }, /* RIGHT ONE EIGHTH BLOCK -> '|' */
+ { 0x96, 0x00 }, /* QUADRANT LOWER LEFT -> ... */
+ { 0xB1, 0x23 }, /* WHITE PARALLELOGRAM -> '#' */
+ { 0xB2, 0x00 }, /* BLACK UP-POINTING TRIANGLE -> ... */
+ { 0xB5, 0x5E }, /* WHITE UP-POINTING SMALL TRIANGLE -> '^' */
+ { 0xB6, 0x00 }, /* BLACK RIGHT-POINTING TRIANGLE -> ... */
+ { 0xBB, 0x3E }, /* WHITE RIGHT-POINTING POINTER -> '>' */
+ { 0xBC, 0x00 }, /* BLACK DOWN-POINTING TRIANGLE -> ... */
+ { 0xBF, 0x56 }, /* WHITE DOWN-POINTING SMALL TRIANGLE -> 'V' */
+ { 0xC0, 0x00 }, /* BLACK LEFT-POINTING TRIANGLE -> ... */
+ { 0xC5, 0x3C }, /* WHITE LEFT-POINTING POINTER -> '<' */
+ { 0xC6, 0x00 }, /* BLACK DIAMOND -> ... */
+ { 0xE6, 0x2A }, /* WHITE BULLET -> '*' */
+ { 0xE7, 0x00 }, /* SQUARE WITH LEFT HALF BLACK -> ... */
+ { 0xEB, 0x23 }, /* WHITE SQUARE WITH VERTICAL BISECTING LINE -> '#' */
+ { 0xEC, 0x00 }, /* WHITE UP-POINTING TRIANGLE WITH DOT -> ... */
+ { 0xEE, 0x5E }, /* UP-POINTING TRIANGLE WITH RIGHT HALF BLACK -> '^' */
+ { 0xEF, 0x4F }, /* LARGE CIRCLE -> 'O' */
+ { 0xF0, 0x00 }, /* WHITE SQUARE WITH UPPER LEFT QUADRANT -> ... */
+ { 0xF7, 0x23 }, /* WHITE CIRCLE WITH UPPER RIGHT QUADRANT -> '#' */
+ /* Entries for page 0x26 */
+ { 0x05, 0x2A }, /* BLACK STAR -> '*' */
+ { 0x06, 0x2A }, /* WHITE STAR -> '*' */
+ { 0x2A, 0x2A }, /* STAR AND CRESCENT -> '*' */
+ { 0x6F, 0x23 }, /* MUSIC SHARP SIGN -> '#' */
+ { 0x98, 0x2A }, /* FLOWER -> '*' */
+ { 0x9D, 0x2A }, /* OUTLINED WHITE STAR -> '*' */
+ /* Entries for page 0x27 */
+ { 0x13, 0x76 }, /* CHECK MARK -> 'v' */
+ { 0x14, 0x56 }, /* HEAVY CHECK MARK -> 'V' */
+ { 0x15, 0x78 }, /* MULTIPLICATION X -> 'x' */
+ { 0x16, 0x58 }, /* HEAVY MULTIPLICATION X -> 'X' */
+ { 0x17, 0x78 }, /* BALLOT X -> 'x' */
+ { 0x18, 0x58 }, /* HEAVY BALLOT X -> 'X' */
+ { 0x21, 0x00 }, /* STAR OF DAVID -> ... */
+ { 0x46, 0x2A }, /* HEAVY CHEVRON SNOWFLAKE -> '*' */
+ { 0x49, 0x00 }, /* BALLOON-SPOKED ASTERISK -> ... */
+ { 0x4B, 0x2A }, /* HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK -> '*' */
+ { 0x58, 0x7C }, /* LIGHT VERTICAL BAR -> '|' */
+ { 0x5C, 0x27 }, /* HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT -> ''' */
+ { 0x5D, 0x22 }, /* HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT -> '"' */
+ { 0x5E, 0x22 }, /* HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT -> '"' */
+ { 0x5F, 0x2C }, /* HEAVY LOW SINGLE COMMA QUOTATION MARK ORNAMENT -> ',' */
+ { 0x62, 0x21 }, /* HEAVY EXCLAMATION MARK ORNAMENT -> '!' */
+ { 0xE6, 0x5B }, /* MATHEMATICAL LEFT WHITE SQUARE BRACKET -> '[' */
+ { 0xE8, 0x3C }, /* MATHEMATICAL LEFT ANGLE BRACKET -> '<' */
+ /* Entries for page 0x28 */
+ { 0x00, 0x20 }, /* BRAILLE PATTERN BLANK -> ' ' */
+ { 0x01, 0x61 }, /* BRAILLE PATTERN DOTS-1 -> 'a' */
+ { 0x02, 0x31 }, /* BRAILLE PATTERN DOTS-2 -> '1' */
+ { 0x03, 0x62 }, /* BRAILLE PATTERN DOTS-12 -> 'b' */
+ { 0x04, 0x27 }, /* BRAILLE PATTERN DOTS-3 -> ''' */
+ { 0x05, 0x6B }, /* BRAILLE PATTERN DOTS-13 -> 'k' */
+ { 0x06, 0x32 }, /* BRAILLE PATTERN DOTS-23 -> '2' */
+ { 0x07, 0x6C }, /* BRAILLE PATTERN DOTS-123 -> 'l' */
+ { 0x08, 0x40 }, /* BRAILLE PATTERN DOTS-4 -> '@' */
+ { 0x09, 0x63 }, /* BRAILLE PATTERN DOTS-14 -> 'c' */
+ { 0x0A, 0x69 }, /* BRAILLE PATTERN DOTS-24 -> 'i' */
+ { 0x0B, 0x66 }, /* BRAILLE PATTERN DOTS-124 -> 'f' */
+ { 0x0C, 0x2F }, /* BRAILLE PATTERN DOTS-34 -> '/' */
+ { 0x0D, 0x6D }, /* BRAILLE PATTERN DOTS-134 -> 'm' */
+ { 0x0E, 0x73 }, /* BRAILLE PATTERN DOTS-234 -> 's' */
+ { 0x0F, 0x70 }, /* BRAILLE PATTERN DOTS-1234 -> 'p' */
+ { 0x10, 0x22 }, /* BRAILLE PATTERN DOTS-5 -> '"' */
+ { 0x11, 0x65 }, /* BRAILLE PATTERN DOTS-15 -> 'e' */
+ { 0x12, 0x33 }, /* BRAILLE PATTERN DOTS-25 -> '3' */
+ { 0x13, 0x68 }, /* BRAILLE PATTERN DOTS-125 -> 'h' */
+ { 0x14, 0x39 }, /* BRAILLE PATTERN DOTS-35 -> '9' */
+ { 0x15, 0x6F }, /* BRAILLE PATTERN DOTS-135 -> 'o' */
+ { 0x16, 0x36 }, /* BRAILLE PATTERN DOTS-235 -> '6' */
+ { 0x17, 0x72 }, /* BRAILLE PATTERN DOTS-1235 -> 'r' */
+ { 0x18, 0x5E }, /* BRAILLE PATTERN DOTS-45 -> '^' */
+ { 0x19, 0x64 }, /* BRAILLE PATTERN DOTS-145 -> 'd' */
+ { 0x1A, 0x6A }, /* BRAILLE PATTERN DOTS-245 -> 'j' */
+ { 0x1B, 0x67 }, /* BRAILLE PATTERN DOTS-1245 -> 'g' */
+ { 0x1C, 0x3E }, /* BRAILLE PATTERN DOTS-345 -> '>' */
+ { 0x1D, 0x6E }, /* BRAILLE PATTERN DOTS-1345 -> 'n' */
+ { 0x1E, 0x74 }, /* BRAILLE PATTERN DOTS-2345 -> 't' */
+ { 0x1F, 0x71 }, /* BRAILLE PATTERN DOTS-12345 -> 'q' */
+ { 0x20, 0x2C }, /* BRAILLE PATTERN DOTS-6 -> ',' */
+ { 0x21, 0x2A }, /* BRAILLE PATTERN DOTS-16 -> '*' */
+ { 0x22, 0x35 }, /* BRAILLE PATTERN DOTS-26 -> '5' */
+ { 0x23, 0x3C }, /* BRAILLE PATTERN DOTS-126 -> '<' */
+ { 0x24, 0x2D }, /* BRAILLE PATTERN DOTS-36 -> '-' */
+ { 0x25, 0x75 }, /* BRAILLE PATTERN DOTS-136 -> 'u' */
+ { 0x26, 0x38 }, /* BRAILLE PATTERN DOTS-236 -> '8' */
+ { 0x27, 0x76 }, /* BRAILLE PATTERN DOTS-1236 -> 'v' */
+ { 0x28, 0x2E }, /* BRAILLE PATTERN DOTS-46 -> '.' */
+ { 0x29, 0x25 }, /* BRAILLE PATTERN DOTS-146 -> '%' */
+ { 0x2A, 0x5B }, /* BRAILLE PATTERN DOTS-246 -> '[' */
+ { 0x2B, 0x24 }, /* BRAILLE PATTERN DOTS-1246 -> '$' */
+ { 0x2C, 0x2B }, /* BRAILLE PATTERN DOTS-346 -> '+' */
+ { 0x2D, 0x78 }, /* BRAILLE PATTERN DOTS-1346 -> 'x' */
+ { 0x2E, 0x21 }, /* BRAILLE PATTERN DOTS-2346 -> '!' */
+ { 0x2F, 0x26 }, /* BRAILLE PATTERN DOTS-12346 -> '&' */
+ { 0x30, 0x3B }, /* BRAILLE PATTERN DOTS-56 -> ';' */
+ { 0x31, 0x3A }, /* BRAILLE PATTERN DOTS-156 -> ':' */
+ { 0x32, 0x34 }, /* BRAILLE PATTERN DOTS-256 -> '4' */
+ { 0x33, 0x5C }, /* BRAILLE PATTERN DOTS-1256 -> '\' */
+ { 0x34, 0x30 }, /* BRAILLE PATTERN DOTS-356 -> '0' */
+ { 0x35, 0x7A }, /* BRAILLE PATTERN DOTS-1356 -> 'z' */
+ { 0x36, 0x37 }, /* BRAILLE PATTERN DOTS-2356 -> '7' */
+ { 0x37, 0x28 }, /* BRAILLE PATTERN DOTS-12356 -> '(' */
+ { 0x38, 0x5F }, /* BRAILLE PATTERN DOTS-456 -> '_' */
+ { 0x39, 0x3F }, /* BRAILLE PATTERN DOTS-1456 -> '?' */
+ { 0x3A, 0x77 }, /* BRAILLE PATTERN DOTS-2456 -> 'w' */
+ { 0x3B, 0x5D }, /* BRAILLE PATTERN DOTS-12456 -> ']' */
+ { 0x3C, 0x23 }, /* BRAILLE PATTERN DOTS-3456 -> '#' */
+ { 0x3D, 0x79 }, /* BRAILLE PATTERN DOTS-13456 -> 'y' */
+ { 0x3E, 0x29 }, /* BRAILLE PATTERN DOTS-23456 -> ')' */
+ { 0x3F, 0x3D }, /* BRAILLE PATTERN DOTS-123456 -> '=' */
+ /* Entries for page 0x29 */
+ { 0x83, 0x7B }, /* LEFT WHITE CURLY BRACKET -> '{' */
+ /* Entries for page 0x2C */
+ { 0x60, 0x4C }, /* LATIN CAPITAL LETTER L WITH DOUBLE BAR -> 'L' */
+ { 0x61, 0x6C }, /* LATIN SMALL LETTER L WITH DOUBLE BAR -> 'l' */
+ { 0x62, 0x4C }, /* LATIN CAPITAL LETTER L WITH MIDDLE TILDE -> 'L' */
+ { 0x63, 0x50 }, /* LATIN CAPITAL LETTER P WITH STROKE -> 'P' */
+ { 0x64, 0x52 }, /* LATIN CAPITAL LETTER R WITH TAIL -> 'R' */
+ { 0x65, 0x61 }, /* LATIN SMALL LETTER A WITH STROKE -> 'a' */
+ { 0x66, 0x74 }, /* LATIN SMALL LETTER T WITH DIAGONAL STROKE -> 't' */
+ { 0x67, 0x48 }, /* LATIN CAPITAL LETTER H WITH DESCENDER -> 'H' */
+ { 0x68, 0x68 }, /* LATIN SMALL LETTER H WITH DESCENDER -> 'h' */
+ { 0x69, 0x4B }, /* LATIN CAPITAL LETTER K WITH DESCENDER -> 'K' */
+ { 0x6A, 0x6B }, /* LATIN SMALL LETTER K WITH DESCENDER -> 'k' */
+ { 0x6B, 0x5A }, /* LATIN CAPITAL LETTER Z WITH DESCENDER -> 'Z' */
+ { 0x6C, 0x7A }, /* LATIN SMALL LETTER Z WITH DESCENDER -> 'z' */
+ { 0x6E, 0x4D }, /* LATIN CAPITAL LETTER M WITH HOOK -> 'M' */
+ { 0x6F, 0x41 }, /* LATIN CAPITAL LETTER TURNED A -> 'A' */
+ /* Entries for page 0x2E */
+ { 0x00, 0x72 }, /* RIGHT ANGLE SUBSTITUTION MARKER -> 'r' */
+ { 0x06, 0x54 }, /* RAISED INTERPOLATION MARKER -> 'T' */
+ { 0x09, 0x73 }, /* LEFT TRANSPOSITION BRACKET -> 's' */
+ { 0x0C, 0x5C }, /* LEFT RAISED OMISSION BRACKET -> '\' */
+ { 0x0D, 0x2F }, /* RIGHT RAISED OMISSION BRACKET -> '/' */
+ { 0x12, 0x3E }, /* HYPODIASTOLE -> '>' */
+ { 0x13, 0x25 }, /* DOTTED OBELOS -> '%' */
+ { 0x16, 0x3E }, /* DOTTED RIGHT-POINTING ANGLE -> '>' */
+ { 0x17, 0x3D }, /* DOUBLE OBLIQUE HYPHEN -> '=' */
+ { 0x19, 0x2F }, /* PALM BRANCH -> '/' */
+ { 0x1A, 0x2D }, /* HYPHEN WITH DIAERESIS -> '-' */
+ { 0x1B, 0x7E }, /* TILDE WITH RING ABOVE -> '~' */
+ { 0x1C, 0x5C }, /* LEFT LOW PARAPHRASE BRACKET -> '\' */
+ { 0x1D, 0x2F }, /* RIGHT LOW PARAPHRASE BRACKET -> '/' */
+ { 0x1E, 0x7E }, /* TILDE WITH DOT ABOVE -> '~' */
+ { 0x1F, 0x7E }, /* TILDE WITH DOT BELOW -> '~' */
+ { 0x2E, 0x3F }, /* REVERSED QUESTION MARK -> '?' */
+ { 0x2F, 0x27 }, /* VERTICAL TILDE -> ''' */
+ { 0x30, 0x6F }, /* RING POINT -> 'o' */
+ { 0x31, 0x2E }, /* WORD SEPARATOR MIDDLE DOT -> '.' */
+ { 0x32, 0x2C }, /* TURNED COMMA -> ',' */
+ { 0x33, 0x2E }, /* RAISED DOT -> '.' */
+ { 0x34, 0x2C }, /* RAISED COMMA -> ',' */
+ { 0x35, 0x3B }, /* TURNED SEMICOLON -> ';' */
+ { 0x3C, 0x78 }, /* STENOGRAPHIC FULL STOP -> 'x' */
+ { 0x3D, 0x7C }, /* VERTICAL SIX DOTS -> '|' */
+ { 0x40, 0x3D }, /* DOUBLE HYPHEN -> '=' */
+ { 0x41, 0x2C }, /* REVERSED COMMA -> ',' */
+ { 0x42, 0x22 }, /* DOUBLE LOW-REVERSED-9 QUOTATION MARK -> '"' */
+ /* Entries for page 0x30 */
+ { 0x00, 0x20 }, /* IDEOGRAPHIC SPACE -> ' ' */
+ { 0x03, 0x22 }, /* DITTO MARK -> '"' */
+ { 0x05, 0x22 }, /* IDEOGRAPHIC ITERATION MARK -> '"' */
+ { 0x06, 0x2F }, /* IDEOGRAPHIC CLOSING MARK -> '/' */
+ { 0x07, 0x30 }, /* IDEOGRAPHIC NUMBER ZERO -> '0' */
+ { 0x08, 0x3C }, /* LEFT ANGLE BRACKET -> '<' */
+ { 0x0C, 0x5B }, /* LEFT CORNER BRACKET -> '[' */
+ { 0x0E, 0x7B }, /* LEFT WHITE CORNER BRACKET -> '{' */
+ { 0x12, 0x40 }, /* POSTAL MARK -> '@' */
+ { 0x14, 0x5B }, /* LEFT TORTOISE SHELL BRACKET -> '[' */
+ { 0x20, 0x40 }, /* POSTAL MARK FACE -> '@' */
+ { 0x21, 0x31 }, /* HANGZHOU NUMERAL ONE -> '1' */
+ { 0x22, 0x32 }, /* HANGZHOU NUMERAL TWO -> '2' */
+ { 0x23, 0x33 }, /* HANGZHOU NUMERAL THREE -> '3' */
+ { 0x24, 0x34 }, /* HANGZHOU NUMERAL FOUR -> '4' */
+ { 0x25, 0x35 }, /* HANGZHOU NUMERAL FIVE -> '5' */
+ { 0x26, 0x36 }, /* HANGZHOU NUMERAL SIX -> '6' */
+ { 0x27, 0x37 }, /* HANGZHOU NUMERAL SEVEN -> '7' */
+ { 0x28, 0x38 }, /* HANGZHOU NUMERAL EIGHT -> '8' */
+ { 0x29, 0x39 }, /* HANGZHOU NUMERAL NINE -> '9' */
+ { 0x30, 0x7E }, /* WAVY DASH -> '~' */
+ { 0x31, 0x00 }, /* VERTICAL KANA REPEAT MARK -> ... */
+ { 0x34, 0x2B }, /* VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF -> '+' */
+ { 0x36, 0x40 }, /* CIRCLED POSTAL MARK -> '@' */
+ { 0x41, 0x61 }, /* HIRAGANA LETTER SMALL A -> 'a' */
+ { 0x42, 0x61 }, /* HIRAGANA LETTER A -> 'a' */
+ { 0x43, 0x69 }, /* HIRAGANA LETTER SMALL I -> 'i' */
+ { 0x44, 0x69 }, /* HIRAGANA LETTER I -> 'i' */
+ { 0x45, 0x75 }, /* HIRAGANA LETTER SMALL U -> 'u' */
+ { 0x46, 0x75 }, /* HIRAGANA LETTER U -> 'u' */
+ { 0x47, 0x65 }, /* HIRAGANA LETTER SMALL E -> 'e' */
+ { 0x48, 0x65 }, /* HIRAGANA LETTER E -> 'e' */
+ { 0x49, 0x6F }, /* HIRAGANA LETTER SMALL O -> 'o' */
+ { 0x4A, 0x6F }, /* HIRAGANA LETTER O -> 'o' */
+ { 0x93, 0x6E }, /* HIRAGANA LETTER N -> 'n' */
+ { 0x9D, 0x22 }, /* HIRAGANA ITERATION MARK -> '"' */
+ { 0x9E, 0x22 }, /* HIRAGANA VOICED ITERATION MARK -> '"' */
+ { 0xA0, 0x3D }, /* KATAKANA-HIRAGANA DOUBLE HYPHEN -> '=' */
+ { 0xA1, 0x61 }, /* KATAKANA LETTER SMALL A -> 'a' */
+ { 0xA2, 0x61 }, /* KATAKANA LETTER A -> 'a' */
+ { 0xA3, 0x69 }, /* KATAKANA LETTER SMALL I -> 'i' */
+ { 0xA4, 0x69 }, /* KATAKANA LETTER I -> 'i' */
+ { 0xA5, 0x75 }, /* KATAKANA LETTER SMALL U -> 'u' */
+ { 0xA6, 0x75 }, /* KATAKANA LETTER U -> 'u' */
+ { 0xA7, 0x65 }, /* KATAKANA LETTER SMALL E -> 'e' */
+ { 0xA8, 0x65 }, /* KATAKANA LETTER E -> 'e' */
+ { 0xA9, 0x6F }, /* KATAKANA LETTER SMALL O -> 'o' */
+ { 0xAA, 0x6F }, /* KATAKANA LETTER O -> 'o' */
+ { 0xF3, 0x6E }, /* KATAKANA LETTER N -> 'n' */
+ { 0xFB, 0x2A }, /* KATAKANA MIDDLE DOT -> '*' */
+ { 0xFC, 0x2D }, /* KATAKANA-HIRAGANA PROLONGED SOUND MARK -> '-' */
+ { 0xFD, 0x22 }, /* KATAKANA ITERATION MARK -> '"' */
+ { 0xFE, 0x22 }, /* KATAKANA VOICED ITERATION MARK -> '"' */
+ /* Entries for page 0x31 */
+ { 0x05, 0x42 }, /* BOPOMOFO LETTER B -> 'B' */
+ { 0x06, 0x50 }, /* BOPOMOFO LETTER P -> 'P' */
+ { 0x07, 0x4D }, /* BOPOMOFO LETTER M -> 'M' */
+ { 0x08, 0x46 }, /* BOPOMOFO LETTER F -> 'F' */
+ { 0x09, 0x44 }, /* BOPOMOFO LETTER D -> 'D' */
+ { 0x0A, 0x54 }, /* BOPOMOFO LETTER T -> 'T' */
+ { 0x0B, 0x4E }, /* BOPOMOFO LETTER N -> 'N' */
+ { 0x0C, 0x4C }, /* BOPOMOFO LETTER L -> 'L' */
+ { 0x0D, 0x47 }, /* BOPOMOFO LETTER G -> 'G' */
+ { 0x0E, 0x4B }, /* BOPOMOFO LETTER K -> 'K' */
+ { 0x0F, 0x48 }, /* BOPOMOFO LETTER H -> 'H' */
+ { 0x10, 0x4A }, /* BOPOMOFO LETTER J -> 'J' */
+ { 0x11, 0x51 }, /* BOPOMOFO LETTER Q -> 'Q' */
+ { 0x12, 0x58 }, /* BOPOMOFO LETTER X -> 'X' */
+ { 0x16, 0x52 }, /* BOPOMOFO LETTER R -> 'R' */
+ { 0x17, 0x5A }, /* BOPOMOFO LETTER Z -> 'Z' */
+ { 0x18, 0x43 }, /* BOPOMOFO LETTER C -> 'C' */
+ { 0x19, 0x53 }, /* BOPOMOFO LETTER S -> 'S' */
+ { 0x1A, 0x41 }, /* BOPOMOFO LETTER A -> 'A' */
+ { 0x1B, 0x4F }, /* BOPOMOFO LETTER O -> 'O' */
+ { 0x1C, 0x45 }, /* BOPOMOFO LETTER E -> 'E' */
+ { 0x27, 0x49 }, /* BOPOMOFO LETTER I -> 'I' */
+ { 0x28, 0x55 }, /* BOPOMOFO LETTER U -> 'U' */
+ { 0x2A, 0x56 }, /* BOPOMOFO LETTER V -> 'V' */
+ { 0x31, 0x67 }, /* HANGUL LETTER KIYEOK -> 'g' */
+ { 0x34, 0x6E }, /* HANGUL LETTER NIEUN -> 'n' */
+ { 0x37, 0x64 }, /* HANGUL LETTER TIKEUT -> 'd' */
+ { 0x39, 0x72 }, /* HANGUL LETTER RIEUL -> 'r' */
+ { 0x41, 0x6D }, /* HANGUL LETTER MIEUM -> 'm' */
+ { 0x42, 0x62 }, /* HANGUL LETTER PIEUP -> 'b' */
+ { 0x45, 0x73 }, /* HANGUL LETTER SIOS -> 's' */
+ { 0x48, 0x6A }, /* HANGUL LETTER CIEUC -> 'j' */
+ { 0x4A, 0x63 }, /* HANGUL LETTER CHIEUCH -> 'c' */
+ { 0x4B, 0x6B }, /* HANGUL LETTER KHIEUKH -> 'k' */
+ { 0x4C, 0x74 }, /* HANGUL LETTER THIEUTH -> 't' */
+ { 0x4D, 0x70 }, /* HANGUL LETTER PHIEUPH -> 'p' */
+ { 0x4E, 0x68 }, /* HANGUL LETTER HIEUH -> 'h' */
+ { 0x4F, 0x61 }, /* HANGUL LETTER A -> 'a' */
+ { 0x54, 0x65 }, /* HANGUL LETTER E -> 'e' */
+ { 0x57, 0x6F }, /* HANGUL LETTER O -> 'o' */
+ { 0x5C, 0x75 }, /* HANGUL LETTER U -> 'u' */
+ { 0x63, 0x69 }, /* HANGUL LETTER I -> 'i' */
+ { 0x7F, 0x5A }, /* HANGUL LETTER PANSIOS -> 'Z' */
+ { 0x81, 0x4E }, /* HANGUL LETTER YESIEUNG -> 'N' */
+ { 0x86, 0x51 }, /* HANGUL LETTER YEORINHIEUH -> 'Q' */
+ { 0x8D, 0x55 }, /* HANGUL LETTER ARAEA -> 'U' */
+ { 0xB4, 0x50 }, /* BOPOMOFO FINAL LETTER P -> 'P' */
+ { 0xB5, 0x54 }, /* BOPOMOFO FINAL LETTER T -> 'T' */
+ { 0xB6, 0x4B }, /* BOPOMOFO FINAL LETTER K -> 'K' */
+ { 0xB7, 0x48 }, /* BOPOMOFO FINAL LETTER H -> 'H' */
+ /* Entries for page 0x32 */
+ { 0xD0, 0x61 }, /* CIRCLED KATAKANA A -> 'a' */
+ { 0xD1, 0x69 }, /* CIRCLED KATAKANA I -> 'i' */
+ { 0xD2, 0x75 }, /* CIRCLED KATAKANA U -> 'u' */
+ { 0xD3, 0x75 }, /* CIRCLED KATAKANA E -> 'u' */
+ { 0xD4, 0x6F }, /* CIRCLED KATAKANA O -> 'o' */
+ /* Entries for page 0xA0 */
+ { 0x02, 0x69 }, /* YI SYLLABLE I -> 'i' */
+ { 0x0A, 0x61 }, /* YI SYLLABLE A -> 'a' */
+ { 0x11, 0x6F }, /* YI SYLLABLE O -> 'o' */
+ { 0x14, 0x65 }, /* YI SYLLABLE E -> 'e' */
+ /* Entries for page 0xC5 */
+ { 0x44, 0x61 }, /* HANGUL SYLLABLE A -> 'a' */
+ { 0xD0, 0x65 }, /* HANGUL SYLLABLE E -> 'e' */
+ /* Entries for page 0xC6 */
+ { 0x24, 0x6F }, /* HANGUL SYLLABLE O -> 'o' */
+ { 0xB0, 0x75 }, /* HANGUL SYLLABLE U -> 'u' */
+ /* Entries for page 0xC7 */
+ { 0x74, 0x69 }, /* HANGUL SYLLABLE I -> 'i' */
+ /* Entries for page 0xFB */
+ { 0x1D, 0x69 }, /* HEBREW LETTER YOD WITH HIRIQ -> 'i' */
+ { 0x20, 0x60 }, /* HEBREW LETTER ALTERNATIVE AYIN -> '`' */
+ { 0x21, 0x41 }, /* HEBREW LETTER WIDE ALEF -> 'A' */
+ { 0x22, 0x64 }, /* HEBREW LETTER WIDE DALET -> 'd' */
+ { 0x23, 0x68 }, /* HEBREW LETTER WIDE HE -> 'h' */
+ { 0x25, 0x6C }, /* HEBREW LETTER WIDE LAMED -> 'l' */
+ { 0x26, 0x6D }, /* HEBREW LETTER WIDE FINAL MEM -> 'm' */
+ { 0x27, 0x72 }, /* HEBREW LETTER WIDE RESH -> 'r' */
+ { 0x28, 0x74 }, /* HEBREW LETTER WIDE TAV -> 't' */
+ { 0x29, 0x2B }, /* HEBREW LETTER ALTERNATIVE PLUS SIGN -> '+' */
+ { 0x2B, 0x53 }, /* HEBREW LETTER SHIN WITH SIN DOT -> 'S' */
+ { 0x2D, 0x53 }, /* HEBREW LETTER SHIN WITH DAGESH AND SIN DOT -> 'S' */
+ { 0x2E, 0x61 }, /* HEBREW LETTER ALEF WITH PATAH -> 'a' */
+ { 0x2F, 0x61 }, /* HEBREW LETTER ALEF WITH QAMATS -> 'a' */
+ { 0x30, 0x41 }, /* HEBREW LETTER ALEF WITH MAPIQ -> 'A' */
+ { 0x31, 0x62 }, /* HEBREW LETTER BET WITH DAGESH -> 'b' */
+ { 0x32, 0x67 }, /* HEBREW LETTER GIMEL WITH DAGESH -> 'g' */
+ { 0x33, 0x64 }, /* HEBREW LETTER DALET WITH DAGESH -> 'd' */
+ { 0x34, 0x68 }, /* HEBREW LETTER HE WITH MAPIQ -> 'h' */
+ { 0x35, 0x76 }, /* HEBREW LETTER VAV WITH DAGESH -> 'v' */
+ { 0x36, 0x7A }, /* HEBREW LETTER ZAYIN WITH DAGESH -> 'z' */
+ { 0x38, 0x74 }, /* HEBREW LETTER TET WITH DAGESH -> 't' */
+ { 0x39, 0x79 }, /* HEBREW LETTER YOD WITH DAGESH -> 'y' */
+ { 0x3C, 0x6C }, /* HEBREW LETTER LAMED WITH DAGESH -> 'l' */
+ { 0x3E, 0x6D }, /* HEBREW LETTER MEM WITH DAGESH -> 'm' */
+ { 0x40, 0x6E }, /* HEBREW LETTER NUN WITH DAGESH -> 'n' */
+ { 0x41, 0x73 }, /* HEBREW LETTER SAMEKH WITH DAGESH -> 's' */
+ { 0x43, 0x70 }, /* HEBREW LETTER FINAL PE WITH DAGESH -> 'p' */
+ { 0x44, 0x70 }, /* HEBREW LETTER PE WITH DAGESH -> 'p' */
+ { 0x47, 0x6B }, /* HEBREW LETTER QOF WITH DAGESH -> 'k' */
+ { 0x48, 0x72 }, /* HEBREW LETTER RESH WITH DAGESH -> 'r' */
+ { 0x4A, 0x74 }, /* HEBREW LETTER TAV WITH DAGESH -> 't' */
+ { 0x4B, 0x6F }, /* HEBREW LETTER VAV WITH HOLAM -> 'o' */
+ { 0x4C, 0x76 }, /* HEBREW LETTER BET WITH RAFE -> 'v' */
+ { 0x4E, 0x66 }, /* HEBREW LETTER PE WITH RAFE -> 'f' */
+ /* Entries for page 0xFE */
+ { 0x23, 0x7E }, /* COMBINING DOUBLE TILDE RIGHT HALF -> '~' */
+ { 0x32, 0x2D }, /* PRESENTATION FORM FOR VERTICAL EN DASH -> '-' */
+ { 0x33, 0x5F }, /* PRESENTATION FORM FOR VERTICAL LOW LINE -> '_' */
+ { 0x34, 0x5F }, /* PRESENTATION FORM FOR VERTICAL WAVY LOW LINE -> '_' */
+ { 0x35, 0x28 }, /* PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS -> '(' */
+ { 0x37, 0x7B }, /* PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET -> '{' */
+ { 0x39, 0x5B }, /* PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET -> '[' */
+ { 0x3F, 0x3C }, /* PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET -> '<' */
+ { 0x41, 0x5B }, /* PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET -> '[' */
+ { 0x43, 0x7B }, /* PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET -> '{' */
+ { 0x44, 0x7D }, /* PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET -> '}' */
+ { 0x50, 0x2C }, /* SMALL COMMA -> ',' */
+ { 0x51, 0x2C }, /* SMALL IDEOGRAPHIC COMMA -> ',' */
+ { 0x52, 0x2E }, /* SMALL FULL STOP -> '.' */
+ { 0x54, 0x3B }, /* SMALL SEMICOLON -> ';' */
+ { 0x55, 0x3A }, /* SMALL COLON -> ':' */
+ { 0x56, 0x3F }, /* SMALL QUESTION MARK -> '?' */
+ { 0x57, 0x21 }, /* SMALL EXCLAMATION MARK -> '!' */
+ { 0x58, 0x2D }, /* SMALL EM DASH -> '-' */
+ { 0x59, 0x28 }, /* SMALL LEFT PARENTHESIS -> '(' */
+ { 0x5A, 0x29 }, /* SMALL RIGHT PARENTHESIS -> ')' */
+ { 0x5B, 0x7B }, /* SMALL LEFT CURLY BRACKET -> '{' */
+ { 0x5C, 0x7D }, /* SMALL RIGHT CURLY BRACKET -> '}' */
+ { 0x5D, 0x7B }, /* SMALL LEFT TORTOISE SHELL BRACKET -> '{' */
+ { 0x5E, 0x7D }, /* SMALL RIGHT TORTOISE SHELL BRACKET -> '}' */
+ { 0x5F, 0x23 }, /* SMALL NUMBER SIGN -> '#' */
+ { 0x60, 0x26 }, /* SMALL AMPERSAND -> '&' */
+ { 0x61, 0x2A }, /* SMALL ASTERISK -> '*' */
+ { 0x62, 0x2B }, /* SMALL PLUS SIGN -> '+' */
+ { 0x63, 0x2D }, /* SMALL HYPHEN-MINUS -> '-' */
+ { 0x64, 0x3C }, /* SMALL LESS-THAN SIGN -> '<' */
+ { 0x65, 0x3E }, /* SMALL GREATER-THAN SIGN -> '>' */
+ { 0x66, 0x3D }, /* SMALL EQUALS SIGN -> '=' */
+ { 0x68, 0x5C }, /* SMALL REVERSE SOLIDUS -> '\' */
+ { 0x69, 0x24 }, /* SMALL DOLLAR SIGN -> '$' */
+ { 0x6A, 0x25 }, /* SMALL PERCENT SIGN -> '%' */
+ { 0x6B, 0x40 }, /* SMALL COMMERCIAL AT -> '@' */
+ /* Entries for page 0xFF */
+ { 0x61, 0x2E }, /* HALFWIDTH IDEOGRAPHIC FULL STOP -> '.' */
+ { 0x62, 0x5B }, /* HALFWIDTH LEFT CORNER BRACKET -> '[' */
+ { 0x63, 0x5D }, /* HALFWIDTH RIGHT CORNER BRACKET -> ']' */
+ { 0x64, 0x2C }, /* HALFWIDTH IDEOGRAPHIC COMMA -> ',' */
+ { 0x65, 0x2A }, /* HALFWIDTH KATAKANA MIDDLE DOT -> '*' */
+ { 0x67, 0x61 }, /* HALFWIDTH KATAKANA LETTER SMALL A -> 'a' */
+ { 0x68, 0x69 }, /* HALFWIDTH KATAKANA LETTER SMALL I -> 'i' */
+ { 0x69, 0x75 }, /* HALFWIDTH KATAKANA LETTER SMALL U -> 'u' */
+ { 0x6A, 0x65 }, /* HALFWIDTH KATAKANA LETTER SMALL E -> 'e' */
+ { 0x6B, 0x6F }, /* HALFWIDTH KATAKANA LETTER SMALL O -> 'o' */
+ { 0x70, 0x2B }, /* HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK -> '+' */
+ { 0x71, 0x61 }, /* HALFWIDTH KATAKANA LETTER A -> 'a' */
+ { 0x72, 0x69 }, /* HALFWIDTH KATAKANA LETTER I -> 'i' */
+ { 0x73, 0x75 }, /* HALFWIDTH KATAKANA LETTER U -> 'u' */
+ { 0x74, 0x65 }, /* HALFWIDTH KATAKANA LETTER E -> 'e' */
+ { 0x75, 0x6F }, /* HALFWIDTH KATAKANA LETTER O -> 'o' */
+ { 0x9D, 0x6E }, /* HALFWIDTH KATAKANA LETTER N -> 'n' */
+ { 0x9E, 0x3A }, /* HALFWIDTH KATAKANA VOICED SOUND MARK -> ':' */
+ { 0x9F, 0x3B }, /* HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK -> ';' */
+ { 0xA1, 0x67 }, /* HALFWIDTH HANGUL LETTER KIYEOK -> 'g' */
+ { 0xA4, 0x6E }, /* HALFWIDTH HANGUL LETTER NIEUN -> 'n' */
+ { 0xA7, 0x64 }, /* HALFWIDTH HANGUL LETTER TIKEUT -> 'd' */
+ { 0xA9, 0x72 }, /* HALFWIDTH HANGUL LETTER RIEUL -> 'r' */
+ { 0xB1, 0x6D }, /* HALFWIDTH HANGUL LETTER MIEUM -> 'm' */
+ { 0xB2, 0x62 }, /* HALFWIDTH HANGUL LETTER PIEUP -> 'b' */
+ { 0xB5, 0x73 }, /* HALFWIDTH HANGUL LETTER SIOS -> 's' */
+ { 0xB8, 0x6A }, /* HALFWIDTH HANGUL LETTER CIEUC -> 'j' */
+ { 0xBA, 0x63 }, /* HALFWIDTH HANGUL LETTER CHIEUCH -> 'c' */
+ { 0xBB, 0x6B }, /* HALFWIDTH HANGUL LETTER KHIEUKH -> 'k' */
+ { 0xBC, 0x74 }, /* HALFWIDTH HANGUL LETTER THIEUTH -> 't' */
+ { 0xBD, 0x70 }, /* HALFWIDTH HANGUL LETTER PHIEUPH -> 'p' */
+ { 0xBE, 0x68 }, /* HALFWIDTH HANGUL LETTER HIEUH -> 'h' */
+ { 0xC2, 0x61 }, /* HALFWIDTH HANGUL LETTER A -> 'a' */
+ { 0xC7, 0x65 }, /* HALFWIDTH HANGUL LETTER E -> 'e' */
+ { 0xCC, 0x6F }, /* HALFWIDTH HANGUL LETTER O -> 'o' */
+ { 0xD3, 0x75 }, /* HALFWIDTH HANGUL LETTER U -> 'u' */
+ { 0xDC, 0x69 }, /* HALFWIDTH HANGUL LETTER I -> 'i' */
+ { 0xE2, 0x21 }, /* FULLWIDTH NOT SIGN -> '!' */
+ { 0xE3, 0x2D }, /* FULLWIDTH MACRON -> '-' */
+ { 0xE4, 0x7C }, /* FULLWIDTH BROKEN BAR -> '|' */
+ { 0xE8, 0x7C }, /* HALFWIDTH FORMS LIGHT VERTICAL -> '|' */
+ { 0xE9, 0x3C }, /* HALFWIDTH LEFTWARDS ARROW -> '<' */
+ { 0xEA, 0x5E }, /* HALFWIDTH UPWARDS ARROW -> '^' */
+ { 0xEB, 0x3E }, /* HALFWIDTH RIGHTWARDS ARROW -> '>' */
+ { 0xEC, 0x76 }, /* HALFWIDTH DOWNWARDS ARROW -> 'v' */
+ { 0xED, 0x23 }, /* HALFWIDTH BLACK SQUARE -> '#' */
+ { 0xEE, 0x4F }, /* HALFWIDTH WHITE CIRCLE -> 'O' */
+ { 0xF9, 0x7B }, /* INTERLINEAR ANNOTATION ANCHOR -> '{' */
+ { 0xFA, 0x7C }, /* INTERLINEAR ANNOTATION SEPARATOR -> '|' */
+ { 0xFB, 0x7D }, /* INTERLINEAR ANNOTATION TERMINATOR -> '}' */
+};
+
+#define UCS_PAGE_ENTRY_RANGE_MARKER 0
diff --git a/drivers/tty/vt/ucs_recompose_table.h_shipped b/drivers/tty/vt/ucs_recompose_table.h_shipped
new file mode 100644
index 000000000000..bd91edde5d19
--- /dev/null
+++ b/drivers/tty/vt/ucs_recompose_table.h_shipped
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ucs_recompose_table.h - Unicode character recomposition
+ *
+ * Auto-generated by gen_ucs_recompose_table.py
+ *
+ * Unicode Version: 16.0.0
+ *
+ * This file contains a table with most commonly used Latin, Greek, and
+ * Cyrillic recomposition pairs only (71 entries). To generate a table with
+ * all possible recomposition pairs from the Unicode BMP (1000 entries)
+ * instead, run:
+ *
+ * python gen_ucs_recompose_table.py --full
+ */
+
+/*
+ * Table of most commonly used Latin, Greek, and Cyrillic recomposition pairs only
+ * Sorted by base character and then combining mark for binary search
+ */
+static const struct ucs_recomposition ucs_recomposition_table[] = {
+ { 0x0041, 0x0300, 0x00C0 }, /* LATIN CAPITAL LETTER A + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER A WITH GRAVE */
+ { 0x0041, 0x0301, 0x00C1 }, /* LATIN CAPITAL LETTER A + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER A WITH ACUTE */
+ { 0x0041, 0x0302, 0x00C2 }, /* LATIN CAPITAL LETTER A + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
+ { 0x0041, 0x0303, 0x00C3 }, /* LATIN CAPITAL LETTER A + COMBINING TILDE = LATIN CAPITAL LETTER A WITH TILDE */
+ { 0x0041, 0x0308, 0x00C4 }, /* LATIN CAPITAL LETTER A + COMBINING DIAERESIS = LATIN CAPITAL LETTER A WITH DIAERESIS */
+ { 0x0041, 0x030A, 0x00C5 }, /* LATIN CAPITAL LETTER A + COMBINING RING ABOVE = LATIN CAPITAL LETTER A WITH RING ABOVE */
+ { 0x0043, 0x0327, 0x00C7 }, /* LATIN CAPITAL LETTER C + COMBINING CEDILLA = LATIN CAPITAL LETTER C WITH CEDILLA */
+ { 0x0045, 0x0300, 0x00C8 }, /* LATIN CAPITAL LETTER E + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER E WITH GRAVE */
+ { 0x0045, 0x0301, 0x00C9 }, /* LATIN CAPITAL LETTER E + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER E WITH ACUTE */
+ { 0x0045, 0x0302, 0x00CA }, /* LATIN CAPITAL LETTER E + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
+ { 0x0045, 0x0308, 0x00CB }, /* LATIN CAPITAL LETTER E + COMBINING DIAERESIS = LATIN CAPITAL LETTER E WITH DIAERESIS */
+ { 0x0049, 0x0300, 0x00CC }, /* LATIN CAPITAL LETTER I + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER I WITH GRAVE */
+ { 0x0049, 0x0301, 0x00CD }, /* LATIN CAPITAL LETTER I + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER I WITH ACUTE */
+ { 0x0049, 0x0302, 0x00CE }, /* LATIN CAPITAL LETTER I + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
+ { 0x0049, 0x0308, 0x00CF }, /* LATIN CAPITAL LETTER I + COMBINING DIAERESIS = LATIN CAPITAL LETTER I WITH DIAERESIS */
+ { 0x004E, 0x0303, 0x00D1 }, /* LATIN CAPITAL LETTER N + COMBINING TILDE = LATIN CAPITAL LETTER N WITH TILDE */
+ { 0x004F, 0x0300, 0x00D2 }, /* LATIN CAPITAL LETTER O + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER O WITH GRAVE */
+ { 0x004F, 0x0301, 0x00D3 }, /* LATIN CAPITAL LETTER O + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER O WITH ACUTE */
+ { 0x004F, 0x0302, 0x00D4 }, /* LATIN CAPITAL LETTER O + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
+ { 0x004F, 0x0303, 0x00D5 }, /* LATIN CAPITAL LETTER O + COMBINING TILDE = LATIN CAPITAL LETTER O WITH TILDE */
+ { 0x004F, 0x0308, 0x00D6 }, /* LATIN CAPITAL LETTER O + COMBINING DIAERESIS = LATIN CAPITAL LETTER O WITH DIAERESIS */
+ { 0x0055, 0x0300, 0x00D9 }, /* LATIN CAPITAL LETTER U + COMBINING GRAVE ACCENT = LATIN CAPITAL LETTER U WITH GRAVE */
+ { 0x0055, 0x0301, 0x00DA }, /* LATIN CAPITAL LETTER U + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER U WITH ACUTE */
+ { 0x0055, 0x0302, 0x00DB }, /* LATIN CAPITAL LETTER U + COMBINING CIRCUMFLEX ACCENT = LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
+ { 0x0055, 0x0308, 0x00DC }, /* LATIN CAPITAL LETTER U + COMBINING DIAERESIS = LATIN CAPITAL LETTER U WITH DIAERESIS */
+ { 0x0059, 0x0301, 0x00DD }, /* LATIN CAPITAL LETTER Y + COMBINING ACUTE ACCENT = LATIN CAPITAL LETTER Y WITH ACUTE */
+ { 0x0061, 0x0300, 0x00E0 }, /* LATIN SMALL LETTER A + COMBINING GRAVE ACCENT = LATIN SMALL LETTER A WITH GRAVE */
+ { 0x0061, 0x0301, 0x00E1 }, /* LATIN SMALL LETTER A + COMBINING ACUTE ACCENT = LATIN SMALL LETTER A WITH ACUTE */
+ { 0x0061, 0x0302, 0x00E2 }, /* LATIN SMALL LETTER A + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER A WITH CIRCUMFLEX */
+ { 0x0061, 0x0303, 0x00E3 }, /* LATIN SMALL LETTER A + COMBINING TILDE = LATIN SMALL LETTER A WITH TILDE */
+ { 0x0061, 0x0308, 0x00E4 }, /* LATIN SMALL LETTER A + COMBINING DIAERESIS = LATIN SMALL LETTER A WITH DIAERESIS */
+ { 0x0061, 0x030A, 0x00E5 }, /* LATIN SMALL LETTER A + COMBINING RING ABOVE = LATIN SMALL LETTER A WITH RING ABOVE */
+ { 0x0063, 0x0327, 0x00E7 }, /* LATIN SMALL LETTER C + COMBINING CEDILLA = LATIN SMALL LETTER C WITH CEDILLA */
+ { 0x0065, 0x0300, 0x00E8 }, /* LATIN SMALL LETTER E + COMBINING GRAVE ACCENT = LATIN SMALL LETTER E WITH GRAVE */
+ { 0x0065, 0x0301, 0x00E9 }, /* LATIN SMALL LETTER E + COMBINING ACUTE ACCENT = LATIN SMALL LETTER E WITH ACUTE */
+ { 0x0065, 0x0302, 0x00EA }, /* LATIN SMALL LETTER E + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER E WITH CIRCUMFLEX */
+ { 0x0065, 0x0308, 0x00EB }, /* LATIN SMALL LETTER E + COMBINING DIAERESIS = LATIN SMALL LETTER E WITH DIAERESIS */
+ { 0x0069, 0x0300, 0x00EC }, /* LATIN SMALL LETTER I + COMBINING GRAVE ACCENT = LATIN SMALL LETTER I WITH GRAVE */
+ { 0x0069, 0x0301, 0x00ED }, /* LATIN SMALL LETTER I + COMBINING ACUTE ACCENT = LATIN SMALL LETTER I WITH ACUTE */
+ { 0x0069, 0x0302, 0x00EE }, /* LATIN SMALL LETTER I + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER I WITH CIRCUMFLEX */
+ { 0x0069, 0x0308, 0x00EF }, /* LATIN SMALL LETTER I + COMBINING DIAERESIS = LATIN SMALL LETTER I WITH DIAERESIS */
+ { 0x006E, 0x0303, 0x00F1 }, /* LATIN SMALL LETTER N + COMBINING TILDE = LATIN SMALL LETTER N WITH TILDE */
+ { 0x006F, 0x0300, 0x00F2 }, /* LATIN SMALL LETTER O + COMBINING GRAVE ACCENT = LATIN SMALL LETTER O WITH GRAVE */
+ { 0x006F, 0x0301, 0x00F3 }, /* LATIN SMALL LETTER O + COMBINING ACUTE ACCENT = LATIN SMALL LETTER O WITH ACUTE */
+ { 0x006F, 0x0302, 0x00F4 }, /* LATIN SMALL LETTER O + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER O WITH CIRCUMFLEX */
+ { 0x006F, 0x0303, 0x00F5 }, /* LATIN SMALL LETTER O + COMBINING TILDE = LATIN SMALL LETTER O WITH TILDE */
+ { 0x006F, 0x0308, 0x00F6 }, /* LATIN SMALL LETTER O + COMBINING DIAERESIS = LATIN SMALL LETTER O WITH DIAERESIS */
+ { 0x0075, 0x0300, 0x00F9 }, /* LATIN SMALL LETTER U + COMBINING GRAVE ACCENT = LATIN SMALL LETTER U WITH GRAVE */
+ { 0x0075, 0x0301, 0x00FA }, /* LATIN SMALL LETTER U + COMBINING ACUTE ACCENT = LATIN SMALL LETTER U WITH ACUTE */
+ { 0x0075, 0x0302, 0x00FB }, /* LATIN SMALL LETTER U + COMBINING CIRCUMFLEX ACCENT = LATIN SMALL LETTER U WITH CIRCUMFLEX */
+ { 0x0075, 0x0308, 0x00FC }, /* LATIN SMALL LETTER U + COMBINING DIAERESIS = LATIN SMALL LETTER U WITH DIAERESIS */
+ { 0x0079, 0x0301, 0x00FD }, /* LATIN SMALL LETTER Y + COMBINING ACUTE ACCENT = LATIN SMALL LETTER Y WITH ACUTE */
+ { 0x0079, 0x0308, 0x00FF }, /* LATIN SMALL LETTER Y + COMBINING DIAERESIS = LATIN SMALL LETTER Y WITH DIAERESIS */
+ { 0x0391, 0x0301, 0x0386 }, /* GREEK CAPITAL LETTER ALPHA + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER ALPHA WITH TONOS */
+ { 0x0395, 0x0301, 0x0388 }, /* GREEK CAPITAL LETTER EPSILON + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER EPSILON WITH TONOS */
+ { 0x0397, 0x0301, 0x0389 }, /* GREEK CAPITAL LETTER ETA + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER ETA WITH TONOS */
+ { 0x0399, 0x0301, 0x038A }, /* GREEK CAPITAL LETTER IOTA + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER IOTA WITH TONOS */
+ { 0x039F, 0x0301, 0x038C }, /* GREEK CAPITAL LETTER OMICRON + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER OMICRON WITH TONOS */
+ { 0x03A5, 0x0301, 0x038E }, /* GREEK CAPITAL LETTER UPSILON + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER UPSILON WITH TONOS */
+ { 0x03A9, 0x0301, 0x038F }, /* GREEK CAPITAL LETTER OMEGA + COMBINING ACUTE ACCENT = GREEK CAPITAL LETTER OMEGA WITH TONOS */
+ { 0x03B1, 0x0301, 0x03AC }, /* GREEK SMALL LETTER ALPHA + COMBINING ACUTE ACCENT = GREEK SMALL LETTER ALPHA WITH TONOS */
+ { 0x03B5, 0x0301, 0x03AD }, /* GREEK SMALL LETTER EPSILON + COMBINING ACUTE ACCENT = GREEK SMALL LETTER EPSILON WITH TONOS */
+ { 0x03B7, 0x0301, 0x03AE }, /* GREEK SMALL LETTER ETA + COMBINING ACUTE ACCENT = GREEK SMALL LETTER ETA WITH TONOS */
+ { 0x03B9, 0x0301, 0x03AF }, /* GREEK SMALL LETTER IOTA + COMBINING ACUTE ACCENT = GREEK SMALL LETTER IOTA WITH TONOS */
+ { 0x03BF, 0x0301, 0x03CC }, /* GREEK SMALL LETTER OMICRON + COMBINING ACUTE ACCENT = GREEK SMALL LETTER OMICRON WITH TONOS */
+ { 0x03C5, 0x0301, 0x03CD }, /* GREEK SMALL LETTER UPSILON + COMBINING ACUTE ACCENT = GREEK SMALL LETTER UPSILON WITH TONOS */
+ { 0x03C9, 0x0301, 0x03CE }, /* GREEK SMALL LETTER OMEGA + COMBINING ACUTE ACCENT = GREEK SMALL LETTER OMEGA WITH TONOS */
+ { 0x0418, 0x0306, 0x0419 }, /* CYRILLIC CAPITAL LETTER I + COMBINING BREVE = CYRILLIC CAPITAL LETTER SHORT I */
+ { 0x0423, 0x0306, 0x040E }, /* CYRILLIC CAPITAL LETTER U + COMBINING BREVE = CYRILLIC CAPITAL LETTER SHORT U */
+ { 0x0438, 0x0306, 0x0439 }, /* CYRILLIC SMALL LETTER I + COMBINING BREVE = CYRILLIC SMALL LETTER SHORT I */
+ { 0x0443, 0x0306, 0x045E }, /* CYRILLIC SMALL LETTER U + COMBINING BREVE = CYRILLIC SMALL LETTER SHORT U */
+};
+
+/*
+ * Boundary values for quick rejection
+ * These are calculated by analyzing the table during generation
+ */
+#define UCS_RECOMPOSE_MIN_BASE 0x0041
+#define UCS_RECOMPOSE_MAX_BASE 0x0443
+#define UCS_RECOMPOSE_MIN_MARK 0x0300
+#define UCS_RECOMPOSE_MAX_MARK 0x0327
diff --git a/drivers/tty/vt/ucs_width_table.h_shipped b/drivers/tty/vt/ucs_width_table.h_shipped
new file mode 100644
index 000000000000..6fcb8f1d577d
--- /dev/null
+++ b/drivers/tty/vt/ucs_width_table.h_shipped
@@ -0,0 +1,453 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ucs_width_table.h - Unicode character width
+ *
+ * Auto-generated by gen_ucs_width_table.py
+ *
+ * Unicode Version: 16.0.0
+ */
+
+/* Zero-width character ranges (BMP - Basic Multilingual Plane, U+0000 to U+FFFF) */
+static const struct ucs_interval16 ucs_zero_width_bmp_ranges[] = {
+ { 0x00AD, 0x00AD }, /* SOFT HYPHEN */
+ { 0x0300, 0x036F }, /* COMBINING GRAVE ACCENT - COMBINING LATIN SMALL LETTER X */
+ { 0x0483, 0x0489 }, /* COMBINING CYRILLIC TITLO - COMBINING CYRILLIC MILLIONS SIGN */
+ { 0x0591, 0x05BD }, /* HEBREW ACCENT ETNAHTA - HEBREW POINT METEG */
+ { 0x05BF, 0x05BF }, /* HEBREW POINT RAFE */
+ { 0x05C1, 0x05C2 }, /* HEBREW POINT SHIN DOT - HEBREW POINT SIN DOT */
+ { 0x05C4, 0x05C5 }, /* HEBREW MARK UPPER DOT - HEBREW MARK LOWER DOT */
+ { 0x05C7, 0x05C7 }, /* HEBREW POINT QAMATS QATAN */
+ { 0x0600, 0x0605 }, /* ARABIC NUMBER SIGN - ARABIC NUMBER MARK ABOVE */
+ { 0x0610, 0x061A }, /* ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM - ARABIC SMALL KASRA */
+ { 0x061C, 0x061C }, /* ARABIC LETTER MARK */
+ { 0x064B, 0x065F }, /* ARABIC FATHATAN - ARABIC WAVY HAMZA BELOW */
+ { 0x0670, 0x0670 }, /* ARABIC LETTER SUPERSCRIPT ALEF */
+ { 0x06D6, 0x06DD }, /* ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA - ARABIC END OF AYAH */
+ { 0x06DF, 0x06E4 }, /* ARABIC SMALL HIGH ROUNDED ZERO - ARABIC SMALL HIGH MADDA */
+ { 0x06E7, 0x06E8 }, /* ARABIC SMALL HIGH YEH - ARABIC SMALL HIGH NOON */
+ { 0x06EA, 0x06ED }, /* ARABIC EMPTY CENTRE LOW STOP - ARABIC SMALL LOW MEEM */
+ { 0x070F, 0x070F }, /* SYRIAC ABBREVIATION MARK */
+ { 0x0711, 0x0711 }, /* SYRIAC LETTER SUPERSCRIPT ALAPH */
+ { 0x0730, 0x074A }, /* SYRIAC PTHAHA ABOVE - SYRIAC BARREKH */
+ { 0x07A6, 0x07B0 }, /* THAANA ABAFILI - THAANA SUKUN */
+ { 0x07EB, 0x07F3 }, /* NKO COMBINING SHORT HIGH TONE - NKO COMBINING DOUBLE DOT ABOVE */
+ { 0x07FD, 0x07FD }, /* NKO DANTAYALAN */
+ { 0x0816, 0x0819 }, /* SAMARITAN MARK IN - SAMARITAN MARK DAGESH */
+ { 0x081B, 0x0823 }, /* SAMARITAN MARK EPENTHETIC YUT - SAMARITAN VOWEL SIGN A */
+ { 0x0825, 0x0827 }, /* SAMARITAN VOWEL SIGN SHORT A - SAMARITAN VOWEL SIGN U */
+ { 0x0829, 0x082D }, /* SAMARITAN VOWEL SIGN LONG I - SAMARITAN MARK NEQUDAA */
+ { 0x0859, 0x085B }, /* MANDAIC AFFRICATION MARK - MANDAIC GEMINATION MARK */
+ { 0x0890, 0x0891 }, /* ARABIC POUND MARK ABOVE - ARABIC PIASTRE MARK ABOVE */
+ { 0x0897, 0x089F }, /* ARABIC PEPET - ARABIC HALF MADDA OVER MADDA */
+ { 0x08CA, 0x0903 }, /* ARABIC SMALL HIGH FARSI YEH - DEVANAGARI SIGN VISARGA */
+ { 0x093A, 0x093C }, /* DEVANAGARI VOWEL SIGN OE - DEVANAGARI SIGN NUKTA */
+ { 0x093E, 0x094F }, /* DEVANAGARI VOWEL SIGN AA - DEVANAGARI VOWEL SIGN AW */
+ { 0x0951, 0x0957 }, /* DEVANAGARI STRESS SIGN UDATTA - DEVANAGARI VOWEL SIGN UUE */
+ { 0x0962, 0x0963 }, /* DEVANAGARI VOWEL SIGN VOCALIC L - DEVANAGARI VOWEL SIGN VOCALIC LL */
+ { 0x0981, 0x0983 }, /* BENGALI SIGN CANDRABINDU - BENGALI SIGN VISARGA */
+ { 0x09BC, 0x09BC }, /* BENGALI SIGN NUKTA */
+ { 0x09BE, 0x09C4 }, /* BENGALI VOWEL SIGN AA - BENGALI VOWEL SIGN VOCALIC RR */
+ { 0x09C7, 0x09C8 }, /* BENGALI VOWEL SIGN E - BENGALI VOWEL SIGN AI */
+ { 0x09CB, 0x09CD }, /* BENGALI VOWEL SIGN O - BENGALI SIGN VIRAMA */
+ { 0x09D7, 0x09D7 }, /* BENGALI AU LENGTH MARK */
+ { 0x09E2, 0x09E3 }, /* BENGALI VOWEL SIGN VOCALIC L - BENGALI VOWEL SIGN VOCALIC LL */
+ { 0x09FE, 0x09FE }, /* BENGALI SANDHI MARK */
+ { 0x0A01, 0x0A03 }, /* GURMUKHI SIGN ADAK BINDI - GURMUKHI SIGN VISARGA */
+ { 0x0A3C, 0x0A3C }, /* GURMUKHI SIGN NUKTA */
+ { 0x0A3E, 0x0A42 }, /* GURMUKHI VOWEL SIGN AA - GURMUKHI VOWEL SIGN UU */
+ { 0x0A47, 0x0A48 }, /* GURMUKHI VOWEL SIGN EE - GURMUKHI VOWEL SIGN AI */
+ { 0x0A4B, 0x0A4D }, /* GURMUKHI VOWEL SIGN OO - GURMUKHI SIGN VIRAMA */
+ { 0x0A51, 0x0A51 }, /* GURMUKHI SIGN UDAAT */
+ { 0x0A70, 0x0A71 }, /* GURMUKHI TIPPI - GURMUKHI ADDAK */
+ { 0x0A75, 0x0A75 }, /* GURMUKHI SIGN YAKASH */
+ { 0x0A81, 0x0A83 }, /* GUJARATI SIGN CANDRABINDU - GUJARATI SIGN VISARGA */
+ { 0x0ABC, 0x0ABC }, /* GUJARATI SIGN NUKTA */
+ { 0x0ABE, 0x0AC5 }, /* GUJARATI VOWEL SIGN AA - GUJARATI VOWEL SIGN CANDRA E */
+ { 0x0AC7, 0x0AC9 }, /* GUJARATI VOWEL SIGN E - GUJARATI VOWEL SIGN CANDRA O */
+ { 0x0ACB, 0x0ACD }, /* GUJARATI VOWEL SIGN O - GUJARATI SIGN VIRAMA */
+ { 0x0AE2, 0x0AE3 }, /* GUJARATI VOWEL SIGN VOCALIC L - GUJARATI VOWEL SIGN VOCALIC LL */
+ { 0x0AFA, 0x0AFF }, /* GUJARATI SIGN SUKUN - GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE */
+ { 0x0B01, 0x0B03 }, /* ORIYA SIGN CANDRABINDU - ORIYA SIGN VISARGA */
+ { 0x0B3C, 0x0B3C }, /* ORIYA SIGN NUKTA */
+ { 0x0B3E, 0x0B44 }, /* ORIYA VOWEL SIGN AA - ORIYA VOWEL SIGN VOCALIC RR */
+ { 0x0B47, 0x0B48 }, /* ORIYA VOWEL SIGN E - ORIYA VOWEL SIGN AI */
+ { 0x0B4B, 0x0B4D }, /* ORIYA VOWEL SIGN O - ORIYA SIGN VIRAMA */
+ { 0x0B55, 0x0B57 }, /* ORIYA SIGN OVERLINE - ORIYA AU LENGTH MARK */
+ { 0x0B62, 0x0B63 }, /* ORIYA VOWEL SIGN VOCALIC L - ORIYA VOWEL SIGN VOCALIC LL */
+ { 0x0B82, 0x0B82 }, /* TAMIL SIGN ANUSVARA */
+ { 0x0BBE, 0x0BC2 }, /* TAMIL VOWEL SIGN AA - TAMIL VOWEL SIGN UU */
+ { 0x0BC6, 0x0BC8 }, /* TAMIL VOWEL SIGN E - TAMIL VOWEL SIGN AI */
+ { 0x0BCA, 0x0BCD }, /* TAMIL VOWEL SIGN O - TAMIL SIGN VIRAMA */
+ { 0x0BD7, 0x0BD7 }, /* TAMIL AU LENGTH MARK */
+ { 0x0C00, 0x0C04 }, /* TELUGU SIGN COMBINING CANDRABINDU ABOVE - TELUGU SIGN COMBINING ANUSVARA ABOVE */
+ { 0x0C3C, 0x0C3C }, /* TELUGU SIGN NUKTA */
+ { 0x0C3E, 0x0C44 }, /* TELUGU VOWEL SIGN AA - TELUGU VOWEL SIGN VOCALIC RR */
+ { 0x0C46, 0x0C48 }, /* TELUGU VOWEL SIGN E - TELUGU VOWEL SIGN AI */
+ { 0x0C4A, 0x0C4D }, /* TELUGU VOWEL SIGN O - TELUGU SIGN VIRAMA */
+ { 0x0C55, 0x0C56 }, /* TELUGU LENGTH MARK - TELUGU AI LENGTH MARK */
+ { 0x0C62, 0x0C63 }, /* TELUGU VOWEL SIGN VOCALIC L - TELUGU VOWEL SIGN VOCALIC LL */
+ { 0x0C81, 0x0C83 }, /* KANNADA SIGN CANDRABINDU - KANNADA SIGN VISARGA */
+ { 0x0CBC, 0x0CBC }, /* KANNADA SIGN NUKTA */
+ { 0x0CBE, 0x0CC4 }, /* KANNADA VOWEL SIGN AA - KANNADA VOWEL SIGN VOCALIC RR */
+ { 0x0CC6, 0x0CC8 }, /* KANNADA VOWEL SIGN E - KANNADA VOWEL SIGN AI */
+ { 0x0CCA, 0x0CCD }, /* KANNADA VOWEL SIGN O - KANNADA SIGN VIRAMA */
+ { 0x0CD5, 0x0CD6 }, /* KANNADA LENGTH MARK - KANNADA AI LENGTH MARK */
+ { 0x0CE2, 0x0CE3 }, /* KANNADA VOWEL SIGN VOCALIC L - KANNADA VOWEL SIGN VOCALIC LL */
+ { 0x0CF3, 0x0CF3 }, /* KANNADA SIGN COMBINING ANUSVARA ABOVE RIGHT */
+ { 0x0D00, 0x0D03 }, /* MALAYALAM SIGN COMBINING ANUSVARA ABOVE - MALAYALAM SIGN VISARGA */
+ { 0x0D3B, 0x0D3C }, /* MALAYALAM SIGN VERTICAL BAR VIRAMA - MALAYALAM SIGN CIRCULAR VIRAMA */
+ { 0x0D3E, 0x0D44 }, /* MALAYALAM VOWEL SIGN AA - MALAYALAM VOWEL SIGN VOCALIC RR */
+ { 0x0D46, 0x0D48 }, /* MALAYALAM VOWEL SIGN E - MALAYALAM VOWEL SIGN AI */
+ { 0x0D4A, 0x0D4D }, /* MALAYALAM VOWEL SIGN O - MALAYALAM SIGN VIRAMA */
+ { 0x0D57, 0x0D57 }, /* MALAYALAM AU LENGTH MARK */
+ { 0x0D62, 0x0D63 }, /* MALAYALAM VOWEL SIGN VOCALIC L - MALAYALAM VOWEL SIGN VOCALIC LL */
+ { 0x0D81, 0x0D83 }, /* SINHALA SIGN CANDRABINDU - SINHALA SIGN VISARGAYA */
+ { 0x0DCA, 0x0DCA }, /* SINHALA SIGN AL-LAKUNA */
+ { 0x0DCF, 0x0DD4 }, /* SINHALA VOWEL SIGN AELA-PILLA - SINHALA VOWEL SIGN KETTI PAA-PILLA */
+ { 0x0DD6, 0x0DD6 }, /* SINHALA VOWEL SIGN DIGA PAA-PILLA */
+ { 0x0DD8, 0x0DDF }, /* SINHALA VOWEL SIGN GAETTA-PILLA - SINHALA VOWEL SIGN GAYANUKITTA */
+ { 0x0DF2, 0x0DF3 }, /* SINHALA VOWEL SIGN DIGA GAETTA-PILLA - SINHALA VOWEL SIGN DIGA GAYANUKITTA */
+ { 0x0E31, 0x0E31 }, /* THAI CHARACTER MAI HAN-AKAT */
+ { 0x0E34, 0x0E3A }, /* THAI CHARACTER SARA I - THAI CHARACTER PHINTHU */
+ { 0x0E47, 0x0E4E }, /* THAI CHARACTER MAITAIKHU - THAI CHARACTER YAMAKKAN */
+ { 0x0EB1, 0x0EB1 }, /* LAO VOWEL SIGN MAI KAN */
+ { 0x0EB4, 0x0EBC }, /* LAO VOWEL SIGN I - LAO SEMIVOWEL SIGN LO */
+ { 0x0EC8, 0x0ECE }, /* LAO TONE MAI EK - LAO YAMAKKAN */
+ { 0x0F18, 0x0F19 }, /* TIBETAN ASTROLOGICAL SIGN -KHYUD PA - TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS */
+ { 0x0F35, 0x0F35 }, /* TIBETAN MARK NGAS BZUNG NYI ZLA */
+ { 0x0F37, 0x0F37 }, /* TIBETAN MARK NGAS BZUNG SGOR RTAGS */
+ { 0x0F39, 0x0F39 }, /* TIBETAN MARK TSA -PHRU */
+ { 0x0F3E, 0x0F3F }, /* TIBETAN SIGN YAR TSHES - TIBETAN SIGN MAR TSHES */
+ { 0x0F71, 0x0F84 }, /* TIBETAN VOWEL SIGN AA - TIBETAN MARK HALANTA */
+ { 0x0F86, 0x0F87 }, /* TIBETAN SIGN LCI RTAGS - TIBETAN SIGN YANG RTAGS */
+ { 0x0F8D, 0x0F97 }, /* TIBETAN SUBJOINED SIGN LCE TSA CAN - TIBETAN SUBJOINED LETTER JA */
+ { 0x0F99, 0x0FBC }, /* TIBETAN SUBJOINED LETTER NYA - TIBETAN SUBJOINED LETTER FIXED-FORM RA */
+ { 0x0FC6, 0x0FC6 }, /* TIBETAN SYMBOL PADMA GDAN */
+ { 0x102B, 0x103E }, /* MYANMAR VOWEL SIGN TALL AA - MYANMAR CONSONANT SIGN MEDIAL HA */
+ { 0x1056, 0x1059 }, /* MYANMAR VOWEL SIGN VOCALIC R - MYANMAR VOWEL SIGN VOCALIC LL */
+ { 0x105E, 0x1060 }, /* MYANMAR CONSONANT SIGN MON MEDIAL NA - MYANMAR CONSONANT SIGN MON MEDIAL LA */
+ { 0x1062, 0x1064 }, /* MYANMAR VOWEL SIGN SGAW KAREN EU - MYANMAR TONE MARK SGAW KAREN KE PHO */
+ { 0x1067, 0x106D }, /* MYANMAR VOWEL SIGN WESTERN PWO KAREN EU - MYANMAR SIGN WESTERN PWO KAREN TONE-5 */
+ { 0x1071, 0x1074 }, /* MYANMAR VOWEL SIGN GEBA KAREN I - MYANMAR VOWEL SIGN KAYAH EE */
+ { 0x1082, 0x108D }, /* MYANMAR CONSONANT SIGN SHAN MEDIAL WA - MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE */
+ { 0x108F, 0x108F }, /* MYANMAR SIGN RUMAI PALAUNG TONE-5 */
+ { 0x109A, 0x109D }, /* MYANMAR SIGN KHAMTI TONE-1 - MYANMAR VOWEL SIGN AITON AI */
+ { 0x135D, 0x135F }, /* ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK - ETHIOPIC COMBINING GEMINATION MARK */
+ { 0x1712, 0x1715 }, /* TAGALOG VOWEL SIGN I - TAGALOG SIGN PAMUDPOD */
+ { 0x1732, 0x1734 }, /* HANUNOO VOWEL SIGN I - HANUNOO SIGN PAMUDPOD */
+ { 0x1752, 0x1753 }, /* BUHID VOWEL SIGN I - BUHID VOWEL SIGN U */
+ { 0x1772, 0x1773 }, /* TAGBANWA VOWEL SIGN I - TAGBANWA VOWEL SIGN U */
+ { 0x17B4, 0x17D3 }, /* KHMER VOWEL INHERENT AQ - KHMER SIGN BATHAMASAT */
+ { 0x17DD, 0x17DD }, /* KHMER SIGN ATTHACAN */
+ { 0x180B, 0x180F }, /* MONGOLIAN FREE VARIATION SELECTOR ONE - MONGOLIAN FREE VARIATION SELECTOR FOUR */
+ { 0x1885, 0x1886 }, /* MONGOLIAN LETTER ALI GALI BALUDA - MONGOLIAN LETTER ALI GALI THREE BALUDA */
+ { 0x18A9, 0x18A9 }, /* MONGOLIAN LETTER ALI GALI DAGALGA */
+ { 0x1920, 0x192B }, /* LIMBU VOWEL SIGN A - LIMBU SUBJOINED LETTER WA */
+ { 0x1930, 0x193B }, /* LIMBU SMALL LETTER KA - LIMBU SIGN SA-I */
+ { 0x1A17, 0x1A1B }, /* BUGINESE VOWEL SIGN I - BUGINESE VOWEL SIGN AE */
+ { 0x1A55, 0x1A5E }, /* TAI THAM CONSONANT SIGN MEDIAL RA - TAI THAM CONSONANT SIGN SA */
+ { 0x1A60, 0x1A7C }, /* TAI THAM SIGN SAKOT - TAI THAM SIGN KHUEN-LUE KARAN */
+ { 0x1A7F, 0x1A7F }, /* TAI THAM COMBINING CRYPTOGRAMMIC DOT */
+ { 0x1AB0, 0x1ACE }, /* COMBINING DOUBLED CIRCUMFLEX ACCENT - COMBINING LATIN SMALL LETTER INSULAR T */
+ { 0x1B00, 0x1B04 }, /* BALINESE SIGN ULU RICEM - BALINESE SIGN BISAH */
+ { 0x1B34, 0x1B44 }, /* BALINESE SIGN REREKAN - BALINESE ADEG ADEG */
+ { 0x1B6B, 0x1B73 }, /* BALINESE MUSICAL SYMBOL COMBINING TEGEH - BALINESE MUSICAL SYMBOL COMBINING GONG */
+ { 0x1B80, 0x1B82 }, /* SUNDANESE SIGN PANYECEK - SUNDANESE SIGN PANGWISAD */
+ { 0x1BA1, 0x1BAD }, /* SUNDANESE CONSONANT SIGN PAMINGKAL - SUNDANESE CONSONANT SIGN PASANGAN WA */
+ { 0x1BE6, 0x1BF3 }, /* BATAK SIGN TOMPI - BATAK PANONGONAN */
+ { 0x1C24, 0x1C37 }, /* LEPCHA SUBJOINED LETTER YA - LEPCHA SIGN NUKTA */
+ { 0x1CD0, 0x1CD2 }, /* VEDIC TONE KARSHANA - VEDIC TONE PRENKHA */
+ { 0x1CD4, 0x1CE8 }, /* VEDIC SIGN YAJURVEDIC MIDLINE SVARITA - VEDIC SIGN VISARGA ANUDATTA WITH TAIL */
+ { 0x1CED, 0x1CED }, /* VEDIC SIGN TIRYAK */
+ { 0x1CF4, 0x1CF4 }, /* VEDIC TONE CANDRA ABOVE */
+ { 0x1CF7, 0x1CF9 }, /* VEDIC SIGN ATIKRAMA - VEDIC TONE DOUBLE RING ABOVE */
+ { 0x1DC0, 0x1DFF }, /* COMBINING DOTTED GRAVE ACCENT - COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW */
+ { 0x200B, 0x200F }, /* ZERO WIDTH SPACE - RIGHT-TO-LEFT MARK */
+ { 0x202A, 0x202E }, /* LEFT-TO-RIGHT EMBEDDING - RIGHT-TO-LEFT OVERRIDE */
+ { 0x2060, 0x2064 }, /* WORD JOINER - INVISIBLE PLUS */
+ { 0x2066, 0x206F }, /* LEFT-TO-RIGHT ISOLATE - NOMINAL DIGIT SHAPES */
+ { 0x20D0, 0x20F0 }, /* COMBINING LEFT HARPOON ABOVE - COMBINING ASTERISK ABOVE */
+ { 0x2640, 0x2640 }, /* FEMALE SIGN */
+ { 0x2642, 0x2642 }, /* MALE SIGN */
+ { 0x26A7, 0x26A7 }, /* MALE WITH STROKE AND MALE AND FEMALE SIGN */
+ { 0x2CEF, 0x2CF1 }, /* COPTIC COMBINING NI ABOVE - COPTIC COMBINING SPIRITUS LENIS */
+ { 0x2D7F, 0x2D7F }, /* TIFINAGH CONSONANT JOINER */
+ { 0x2DE0, 0x2DFF }, /* COMBINING CYRILLIC LETTER BE - COMBINING CYRILLIC LETTER IOTIFIED BIG YUS */
+ { 0x302A, 0x302F }, /* IDEOGRAPHIC LEVEL TONE MARK - HANGUL DOUBLE DOT TONE MARK */
+ { 0x3099, 0x309A }, /* COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK - COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */
+ { 0xA66F, 0xA672 }, /* COMBINING CYRILLIC VZMET - COMBINING CYRILLIC THOUSAND MILLIONS SIGN */
+ { 0xA674, 0xA67D }, /* COMBINING CYRILLIC LETTER UKRAINIAN IE - COMBINING CYRILLIC PAYEROK */
+ { 0xA69E, 0xA69F }, /* COMBINING CYRILLIC LETTER EF - COMBINING CYRILLIC LETTER IOTIFIED E */
+ { 0xA6F0, 0xA6F1 }, /* BAMUM COMBINING MARK KOQNDON - BAMUM COMBINING MARK TUKWENTIS */
+ { 0xA802, 0xA802 }, /* SYLOTI NAGRI SIGN DVISVARA */
+ { 0xA806, 0xA806 }, /* SYLOTI NAGRI SIGN HASANTA */
+ { 0xA80B, 0xA80B }, /* SYLOTI NAGRI SIGN ANUSVARA */
+ { 0xA823, 0xA827 }, /* SYLOTI NAGRI VOWEL SIGN A - SYLOTI NAGRI VOWEL SIGN OO */
+ { 0xA82C, 0xA82C }, /* SYLOTI NAGRI SIGN ALTERNATE HASANTA */
+ { 0xA880, 0xA881 }, /* SAURASHTRA SIGN ANUSVARA - SAURASHTRA SIGN VISARGA */
+ { 0xA8B4, 0xA8C5 }, /* SAURASHTRA CONSONANT SIGN HAARU - SAURASHTRA SIGN CANDRABINDU */
+ { 0xA8E0, 0xA8F1 }, /* COMBINING DEVANAGARI DIGIT ZERO - COMBINING DEVANAGARI SIGN AVAGRAHA */
+ { 0xA8FF, 0xA8FF }, /* DEVANAGARI VOWEL SIGN AY */
+ { 0xA926, 0xA92D }, /* KAYAH LI VOWEL UE - KAYAH LI TONE CALYA PLOPHU */
+ { 0xA947, 0xA953 }, /* REJANG VOWEL SIGN I - REJANG VIRAMA */
+ { 0xA980, 0xA983 }, /* JAVANESE SIGN PANYANGGA - JAVANESE SIGN WIGNYAN */
+ { 0xA9B3, 0xA9C0 }, /* JAVANESE SIGN CECAK TELU - JAVANESE PANGKON */
+ { 0xA9E5, 0xA9E5 }, /* MYANMAR SIGN SHAN SAW */
+ { 0xAA29, 0xAA36 }, /* CHAM VOWEL SIGN AA - CHAM CONSONANT SIGN WA */
+ { 0xAA43, 0xAA43 }, /* CHAM CONSONANT SIGN FINAL NG */
+ { 0xAA4C, 0xAA4D }, /* CHAM CONSONANT SIGN FINAL M - CHAM CONSONANT SIGN FINAL H */
+ { 0xAA7B, 0xAA7D }, /* MYANMAR SIGN PAO KAREN TONE - MYANMAR SIGN TAI LAING TONE-5 */
+ { 0xAAB0, 0xAAB0 }, /* TAI VIET MAI KANG */
+ { 0xAAB2, 0xAAB4 }, /* TAI VIET VOWEL I - TAI VIET VOWEL U */
+ { 0xAAB7, 0xAAB8 }, /* TAI VIET MAI KHIT - TAI VIET VOWEL IA */
+ { 0xAABE, 0xAABF }, /* TAI VIET VOWEL AM - TAI VIET TONE MAI EK */
+ { 0xAAC1, 0xAAC1 }, /* TAI VIET TONE MAI THO */
+ { 0xAAEB, 0xAAEF }, /* MEETEI MAYEK VOWEL SIGN II - MEETEI MAYEK VOWEL SIGN AAU */
+ { 0xAAF5, 0xAAF6 }, /* MEETEI MAYEK VOWEL SIGN VISARGA - MEETEI MAYEK VIRAMA */
+ { 0xABE3, 0xABEA }, /* MEETEI MAYEK VOWEL SIGN ONAP - MEETEI MAYEK VOWEL SIGN NUNG */
+ { 0xABEC, 0xABED }, /* MEETEI MAYEK LUM IYEK - MEETEI MAYEK APUN IYEK */
+ { 0xFB1E, 0xFB1E }, /* HEBREW POINT JUDEO-SPANISH VARIKA */
+ { 0xFE00, 0xFE0F }, /* VARIATION SELECTOR-1 - VARIATION SELECTOR-16 */
+ { 0xFE20, 0xFE2F }, /* COMBINING LIGATURE LEFT HALF - COMBINING CYRILLIC TITLO RIGHT HALF */
+ { 0xFEFF, 0xFEFF }, /* ZERO WIDTH NO-BREAK SPACE */
+ { 0xFFF9, 0xFFFB }, /* INTERLINEAR ANNOTATION ANCHOR - INTERLINEAR ANNOTATION TERMINATOR */
+};
+
+/* Zero-width character ranges (non-BMP, U+10000 and above) */
+static const struct ucs_interval32 ucs_zero_width_non_bmp_ranges[] = {
+ { 0x101FD, 0x101FD }, /* PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE */
+ { 0x102E0, 0x102E0 }, /* COPTIC EPACT THOUSANDS MARK */
+ { 0x10376, 0x1037A }, /* COMBINING OLD PERMIC LETTER AN - COMBINING OLD PERMIC LETTER SII */
+ { 0x10A01, 0x10A03 }, /* KHAROSHTHI VOWEL SIGN I - KHAROSHTHI VOWEL SIGN VOCALIC R */
+ { 0x10A05, 0x10A06 }, /* KHAROSHTHI VOWEL SIGN E - KHAROSHTHI VOWEL SIGN O */
+ { 0x10A0C, 0x10A0F }, /* KHAROSHTHI VOWEL LENGTH MARK - KHAROSHTHI SIGN VISARGA */
+ { 0x10A38, 0x10A3A }, /* KHAROSHTHI SIGN BAR ABOVE - KHAROSHTHI SIGN DOT BELOW */
+ { 0x10A3F, 0x10A3F }, /* KHAROSHTHI VIRAMA */
+ { 0x10AE5, 0x10AE6 }, /* MANICHAEAN ABBREVIATION MARK ABOVE - MANICHAEAN ABBREVIATION MARK BELOW */
+ { 0x10D24, 0x10D27 }, /* HANIFI ROHINGYA SIGN HARBAHAY - HANIFI ROHINGYA SIGN TASSI */
+ { 0x10D69, 0x10D6D }, /* GARAY VOWEL SIGN E - GARAY CONSONANT NASALIZATION MARK */
+ { 0x10EAB, 0x10EAC }, /* YEZIDI COMBINING HAMZA MARK - YEZIDI COMBINING MADDA MARK */
+ { 0x10EFC, 0x10EFF }, /* ARABIC COMBINING ALEF OVERLAY - ARABIC SMALL LOW WORD MADDA */
+ { 0x10F46, 0x10F50 }, /* SOGDIAN COMBINING DOT BELOW - SOGDIAN COMBINING STROKE BELOW */
+ { 0x10F82, 0x10F85 }, /* OLD UYGHUR COMBINING DOT ABOVE - OLD UYGHUR COMBINING TWO DOTS BELOW */
+ { 0x11000, 0x11002 }, /* BRAHMI SIGN CANDRABINDU - BRAHMI SIGN VISARGA */
+ { 0x11038, 0x11046 }, /* BRAHMI VOWEL SIGN AA - BRAHMI VIRAMA */
+ { 0x11070, 0x11070 }, /* BRAHMI SIGN OLD TAMIL VIRAMA */
+ { 0x11073, 0x11074 }, /* BRAHMI VOWEL SIGN OLD TAMIL SHORT E - BRAHMI VOWEL SIGN OLD TAMIL SHORT O */
+ { 0x1107F, 0x11082 }, /* BRAHMI NUMBER JOINER - KAITHI SIGN VISARGA */
+ { 0x110B0, 0x110BA }, /* KAITHI VOWEL SIGN AA - KAITHI SIGN NUKTA */
+ { 0x110BD, 0x110BD }, /* KAITHI NUMBER SIGN */
+ { 0x110C2, 0x110C2 }, /* KAITHI VOWEL SIGN VOCALIC R */
+ { 0x110CD, 0x110CD }, /* KAITHI NUMBER SIGN ABOVE */
+ { 0x11100, 0x11102 }, /* CHAKMA SIGN CANDRABINDU - CHAKMA SIGN VISARGA */
+ { 0x11127, 0x11134 }, /* CHAKMA VOWEL SIGN A - CHAKMA MAAYYAA */
+ { 0x11145, 0x11146 }, /* CHAKMA VOWEL SIGN AA - CHAKMA VOWEL SIGN EI */
+ { 0x11173, 0x11173 }, /* MAHAJANI SIGN NUKTA */
+ { 0x11180, 0x11182 }, /* SHARADA SIGN CANDRABINDU - SHARADA SIGN VISARGA */
+ { 0x111B3, 0x111C0 }, /* SHARADA VOWEL SIGN AA - SHARADA SIGN VIRAMA */
+ { 0x111C9, 0x111CC }, /* SHARADA SANDHI MARK - SHARADA EXTRA SHORT VOWEL MARK */
+ { 0x111CE, 0x111CF }, /* SHARADA VOWEL SIGN PRISHTHAMATRA E - SHARADA SIGN INVERTED CANDRABINDU */
+ { 0x1122C, 0x11237 }, /* KHOJKI VOWEL SIGN AA - KHOJKI SIGN SHADDA */
+ { 0x1123E, 0x1123E }, /* KHOJKI SIGN SUKUN */
+ { 0x11241, 0x11241 }, /* KHOJKI VOWEL SIGN VOCALIC R */
+ { 0x112DF, 0x112EA }, /* KHUDAWADI SIGN ANUSVARA - KHUDAWADI SIGN VIRAMA */
+ { 0x11300, 0x11303 }, /* GRANTHA SIGN COMBINING ANUSVARA ABOVE - GRANTHA SIGN VISARGA */
+ { 0x1133B, 0x1133C }, /* COMBINING BINDU BELOW - GRANTHA SIGN NUKTA */
+ { 0x1133E, 0x11344 }, /* GRANTHA VOWEL SIGN AA - GRANTHA VOWEL SIGN VOCALIC RR */
+ { 0x11347, 0x11348 }, /* GRANTHA VOWEL SIGN EE - GRANTHA VOWEL SIGN AI */
+ { 0x1134B, 0x1134D }, /* GRANTHA VOWEL SIGN OO - GRANTHA SIGN VIRAMA */
+ { 0x11357, 0x11357 }, /* GRANTHA AU LENGTH MARK */
+ { 0x11362, 0x11363 }, /* GRANTHA VOWEL SIGN VOCALIC L - GRANTHA VOWEL SIGN VOCALIC LL */
+ { 0x11366, 0x1136C }, /* COMBINING GRANTHA DIGIT ZERO - COMBINING GRANTHA DIGIT SIX */
+ { 0x11370, 0x11374 }, /* COMBINING GRANTHA LETTER A - COMBINING GRANTHA LETTER PA */
+ { 0x113B8, 0x113C0 }, /* TULU-TIGALARI VOWEL SIGN AA - TULU-TIGALARI VOWEL SIGN VOCALIC LL */
+ { 0x113C2, 0x113C2 }, /* TULU-TIGALARI VOWEL SIGN EE */
+ { 0x113C5, 0x113C5 }, /* TULU-TIGALARI VOWEL SIGN AI */
+ { 0x113C7, 0x113CA }, /* TULU-TIGALARI VOWEL SIGN OO - TULU-TIGALARI SIGN CANDRA ANUNASIKA */
+ { 0x113CC, 0x113D0 }, /* TULU-TIGALARI SIGN ANUSVARA - TULU-TIGALARI CONJOINER */
+ { 0x113D2, 0x113D2 }, /* TULU-TIGALARI GEMINATION MARK */
+ { 0x113E1, 0x113E2 }, /* TULU-TIGALARI VEDIC TONE SVARITA - TULU-TIGALARI VEDIC TONE ANUDATTA */
+ { 0x11435, 0x11446 }, /* NEWA VOWEL SIGN AA - NEWA SIGN NUKTA */
+ { 0x1145E, 0x1145E }, /* NEWA SANDHI MARK */
+ { 0x114B0, 0x114C3 }, /* TIRHUTA VOWEL SIGN AA - TIRHUTA SIGN NUKTA */
+ { 0x115AF, 0x115B5 }, /* SIDDHAM VOWEL SIGN AA - SIDDHAM VOWEL SIGN VOCALIC RR */
+ { 0x115B8, 0x115C0 }, /* SIDDHAM VOWEL SIGN E - SIDDHAM SIGN NUKTA */
+ { 0x115DC, 0x115DD }, /* SIDDHAM VOWEL SIGN ALTERNATE U - SIDDHAM VOWEL SIGN ALTERNATE UU */
+ { 0x11630, 0x11640 }, /* MODI VOWEL SIGN AA - MODI SIGN ARDHACANDRA */
+ { 0x116AB, 0x116B7 }, /* TAKRI SIGN ANUSVARA - TAKRI SIGN NUKTA */
+ { 0x1171D, 0x1172B }, /* AHOM CONSONANT SIGN MEDIAL LA - AHOM SIGN KILLER */
+ { 0x1182C, 0x1183A }, /* DOGRA VOWEL SIGN AA - DOGRA SIGN NUKTA */
+ { 0x11930, 0x11935 }, /* DIVES AKURU VOWEL SIGN AA - DIVES AKURU VOWEL SIGN E */
+ { 0x11937, 0x11938 }, /* DIVES AKURU VOWEL SIGN AI - DIVES AKURU VOWEL SIGN O */
+ { 0x1193B, 0x1193E }, /* DIVES AKURU SIGN ANUSVARA - DIVES AKURU VIRAMA */
+ { 0x11940, 0x11940 }, /* DIVES AKURU MEDIAL YA */
+ { 0x11942, 0x11943 }, /* DIVES AKURU MEDIAL RA - DIVES AKURU SIGN NUKTA */
+ { 0x119D1, 0x119D7 }, /* NANDINAGARI VOWEL SIGN AA - NANDINAGARI VOWEL SIGN VOCALIC RR */
+ { 0x119DA, 0x119E0 }, /* NANDINAGARI VOWEL SIGN E - NANDINAGARI SIGN VIRAMA */
+ { 0x119E4, 0x119E4 }, /* NANDINAGARI VOWEL SIGN PRISHTHAMATRA E */
+ { 0x11A01, 0x11A0A }, /* ZANABAZAR SQUARE VOWEL SIGN I - ZANABAZAR SQUARE VOWEL LENGTH MARK */
+ { 0x11A33, 0x11A39 }, /* ZANABAZAR SQUARE FINAL CONSONANT MARK - ZANABAZAR SQUARE SIGN VISARGA */
+ { 0x11A3B, 0x11A3E }, /* ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA - ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA */
+ { 0x11A47, 0x11A47 }, /* ZANABAZAR SQUARE SUBJOINER */
+ { 0x11A51, 0x11A5B }, /* SOYOMBO VOWEL SIGN I - SOYOMBO VOWEL LENGTH MARK */
+ { 0x11A8A, 0x11A99 }, /* SOYOMBO FINAL CONSONANT SIGN G - SOYOMBO SUBJOINER */
+ { 0x11C2F, 0x11C36 }, /* BHAIKSUKI VOWEL SIGN AA - BHAIKSUKI VOWEL SIGN VOCALIC L */
+ { 0x11C38, 0x11C3F }, /* BHAIKSUKI VOWEL SIGN E - BHAIKSUKI SIGN VIRAMA */
+ { 0x11C92, 0x11CA7 }, /* MARCHEN SUBJOINED LETTER KA - MARCHEN SUBJOINED LETTER ZA */
+ { 0x11CA9, 0x11CB6 }, /* MARCHEN SUBJOINED LETTER YA - MARCHEN SIGN CANDRABINDU */
+ { 0x11D31, 0x11D36 }, /* MASARAM GONDI VOWEL SIGN AA - MASARAM GONDI VOWEL SIGN VOCALIC R */
+ { 0x11D3A, 0x11D3A }, /* MASARAM GONDI VOWEL SIGN E */
+ { 0x11D3C, 0x11D3D }, /* MASARAM GONDI VOWEL SIGN AI - MASARAM GONDI VOWEL SIGN O */
+ { 0x11D3F, 0x11D45 }, /* MASARAM GONDI VOWEL SIGN AU - MASARAM GONDI VIRAMA */
+ { 0x11D47, 0x11D47 }, /* MASARAM GONDI RA-KARA */
+ { 0x11D8A, 0x11D8E }, /* GUNJALA GONDI VOWEL SIGN AA - GUNJALA GONDI VOWEL SIGN UU */
+ { 0x11D90, 0x11D91 }, /* GUNJALA GONDI VOWEL SIGN EE - GUNJALA GONDI VOWEL SIGN AI */
+ { 0x11D93, 0x11D97 }, /* GUNJALA GONDI VOWEL SIGN OO - GUNJALA GONDI VIRAMA */
+ { 0x11EF3, 0x11EF6 }, /* MAKASAR VOWEL SIGN I - MAKASAR VOWEL SIGN O */
+ { 0x11F00, 0x11F01 }, /* KAWI SIGN CANDRABINDU - KAWI SIGN ANUSVARA */
+ { 0x11F03, 0x11F03 }, /* KAWI SIGN VISARGA */
+ { 0x11F34, 0x11F3A }, /* KAWI VOWEL SIGN AA - KAWI VOWEL SIGN VOCALIC R */
+ { 0x11F3E, 0x11F42 }, /* KAWI VOWEL SIGN E - KAWI CONJOINER */
+ { 0x11F5A, 0x11F5A }, /* KAWI SIGN NUKTA */
+ { 0x13430, 0x13440 }, /* EGYPTIAN HIEROGLYPH VERTICAL JOINER - EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY */
+ { 0x13447, 0x13455 }, /* EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START - EGYPTIAN HIEROGLYPH MODIFIER DAMAGED */
+ { 0x1611E, 0x1612F }, /* GURUNG KHEMA VOWEL SIGN AA - GURUNG KHEMA SIGN THOLHOMA */
+ { 0x16AF0, 0x16AF4 }, /* BASSA VAH COMBINING HIGH TONE - BASSA VAH COMBINING HIGH-LOW TONE */
+ { 0x16B30, 0x16B36 }, /* PAHAWH HMONG MARK CIM TUB - PAHAWH HMONG MARK CIM TAUM */
+ { 0x16F4F, 0x16F4F }, /* MIAO SIGN CONSONANT MODIFIER BAR */
+ { 0x16F51, 0x16F87 }, /* MIAO SIGN ASPIRATION - MIAO VOWEL SIGN UI */
+ { 0x16F8F, 0x16F92 }, /* MIAO TONE RIGHT - MIAO TONE BELOW */
+ { 0x16FE4, 0x16FE4 }, /* KHITAN SMALL SCRIPT FILLER */
+ { 0x16FF0, 0x16FF1 }, /* VIETNAMESE ALTERNATE READING MARK CA - VIETNAMESE ALTERNATE READING MARK NHAY */
+ { 0x1BC9D, 0x1BC9E }, /* DUPLOYAN THICK LETTER SELECTOR - DUPLOYAN DOUBLE MARK */
+ { 0x1BCA0, 0x1BCA3 }, /* SHORTHAND FORMAT LETTER OVERLAP - SHORTHAND FORMAT UP STEP */
+ { 0x1CF00, 0x1CF2D }, /* ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT - ZNAMENNY COMBINING MARK KRYZH ON LEFT */
+ { 0x1CF30, 0x1CF46 }, /* ZNAMENNY COMBINING TONAL RANGE MARK MRACHNO - ZNAMENNY PRIZNAK MODIFIER ROG */
+ { 0x1D165, 0x1D169 }, /* MUSICAL SYMBOL COMBINING STEM - MUSICAL SYMBOL COMBINING TREMOLO-3 */
+ { 0x1D16D, 0x1D182 }, /* MUSICAL SYMBOL COMBINING AUGMENTATION DOT - MUSICAL SYMBOL COMBINING LOURE */
+ { 0x1D185, 0x1D18B }, /* MUSICAL SYMBOL COMBINING DOIT - MUSICAL SYMBOL COMBINING TRIPLE TONGUE */
+ { 0x1D1AA, 0x1D1AD }, /* MUSICAL SYMBOL COMBINING DOWN BOW - MUSICAL SYMBOL COMBINING SNAP PIZZICATO */
+ { 0x1D242, 0x1D244 }, /* COMBINING GREEK MUSICAL TRISEME - COMBINING GREEK MUSICAL PENTASEME */
+ { 0x1DA00, 0x1DA36 }, /* SIGNWRITING HEAD RIM - SIGNWRITING AIR SUCKING IN */
+ { 0x1DA3B, 0x1DA6C }, /* SIGNWRITING MOUTH CLOSED NEUTRAL - SIGNWRITING EXCITEMENT */
+ { 0x1DA75, 0x1DA75 }, /* SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS */
+ { 0x1DA84, 0x1DA84 }, /* SIGNWRITING LOCATION HEAD NECK */
+ { 0x1DA9B, 0x1DA9F }, /* SIGNWRITING FILL MODIFIER-2 - SIGNWRITING FILL MODIFIER-6 */
+ { 0x1DAA1, 0x1DAAF }, /* SIGNWRITING ROTATION MODIFIER-2 - SIGNWRITING ROTATION MODIFIER-16 */
+ { 0x1E000, 0x1E006 }, /* COMBINING GLAGOLITIC LETTER AZU - COMBINING GLAGOLITIC LETTER ZHIVETE */
+ { 0x1E008, 0x1E018 }, /* COMBINING GLAGOLITIC LETTER ZEMLJA - COMBINING GLAGOLITIC LETTER HERU */
+ { 0x1E01B, 0x1E021 }, /* COMBINING GLAGOLITIC LETTER SHTA - COMBINING GLAGOLITIC LETTER YATI */
+ { 0x1E023, 0x1E024 }, /* COMBINING GLAGOLITIC LETTER YU - COMBINING GLAGOLITIC LETTER SMALL YUS */
+ { 0x1E026, 0x1E02A }, /* COMBINING GLAGOLITIC LETTER YO - COMBINING GLAGOLITIC LETTER FITA */
+ { 0x1E08F, 0x1E08F }, /* COMBINING CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */
+ { 0x1E130, 0x1E136 }, /* NYIAKENG PUACHUE HMONG TONE-B - NYIAKENG PUACHUE HMONG TONE-D */
+ { 0x1E2AE, 0x1E2AE }, /* TOTO SIGN RISING TONE */
+ { 0x1E2EC, 0x1E2EF }, /* WANCHO TONE TUP - WANCHO TONE KOINI */
+ { 0x1E4EC, 0x1E4EF }, /* NAG MUNDARI SIGN MUHOR - NAG MUNDARI SIGN SUTUH */
+ { 0x1E5EE, 0x1E5EF }, /* OL ONAL SIGN MU - OL ONAL SIGN IKIR */
+ { 0x1E8D0, 0x1E8D6 }, /* MENDE KIKAKUI COMBINING NUMBER TEENS - MENDE KIKAKUI COMBINING NUMBER MILLIONS */
+ { 0x1E944, 0x1E94A }, /* ADLAM ALIF LENGTHENER - ADLAM NUKTA */
+ { 0x1F3FB, 0x1F3FF }, /* EMOJI MODIFIER FITZPATRICK TYPE-1-2 - EMOJI MODIFIER FITZPATRICK TYPE-6 */
+ { 0x1F9B0, 0x1F9B3 }, /* EMOJI COMPONENT RED HAIR - EMOJI COMPONENT WHITE HAIR */
+ { 0xE0001, 0xE0001 }, /* LANGUAGE TAG */
+ { 0xE0020, 0xE007F }, /* TAG SPACE - CANCEL TAG */
+ { 0xE0100, 0xE01EF }, /* VARIATION SELECTOR-17 - VARIATION SELECTOR-256 */
+};
+
+/* Double-width character ranges (BMP - Basic Multilingual Plane, U+0000 to U+FFFF) */
+static const struct ucs_interval16 ucs_double_width_bmp_ranges[] = {
+ { 0x1100, 0x115F }, /* HANGUL CHOSEONG KIYEOK - HANGUL CHOSEONG FILLER */
+ { 0x231A, 0x231B }, /* WATCH - HOURGLASS */
+ { 0x2329, 0x232A }, /* LEFT-POINTING ANGLE BRACKET - RIGHT-POINTING ANGLE BRACKET */
+ { 0x23E9, 0x23EC }, /* BLACK RIGHT-POINTING DOUBLE TRIANGLE - BLACK DOWN-POINTING DOUBLE TRIANGLE */
+ { 0x23F0, 0x23F0 }, /* ALARM CLOCK */
+ { 0x23F3, 0x23F3 }, /* HOURGLASS WITH FLOWING SAND */
+ { 0x25FD, 0x25FE }, /* WHITE MEDIUM SMALL SQUARE - BLACK MEDIUM SMALL SQUARE */
+ { 0x2614, 0x2615 }, /* UMBRELLA WITH RAIN DROPS - HOT BEVERAGE */
+ { 0x2630, 0x2637 }, /* TRIGRAM FOR HEAVEN - TRIGRAM FOR EARTH */
+ { 0x2648, 0x2653 }, /* ARIES - PISCES */
+ { 0x267F, 0x267F }, /* WHEELCHAIR SYMBOL */
+ { 0x268A, 0x268F }, /* MONOGRAM FOR YANG - DIGRAM FOR GREATER YIN */
+ { 0x2693, 0x2693 }, /* ANCHOR */
+ { 0x26A1, 0x26A1 }, /* HIGH VOLTAGE SIGN */
+ { 0x26AA, 0x26AB }, /* MEDIUM WHITE CIRCLE - MEDIUM BLACK CIRCLE */
+ { 0x26BD, 0x26BE }, /* SOCCER BALL - BASEBALL */
+ { 0x26C4, 0x26C5 }, /* SNOWMAN WITHOUT SNOW - SUN BEHIND CLOUD */
+ { 0x26CE, 0x26CE }, /* OPHIUCHUS */
+ { 0x26D4, 0x26D4 }, /* NO ENTRY */
+ { 0x26EA, 0x26EA }, /* CHURCH */
+ { 0x26F2, 0x26F3 }, /* FOUNTAIN - FLAG IN HOLE */
+ { 0x26F5, 0x26F5 }, /* SAILBOAT */
+ { 0x26FA, 0x26FA }, /* TENT */
+ { 0x26FD, 0x26FD }, /* FUEL PUMP */
+ { 0x2705, 0x2705 }, /* WHITE HEAVY CHECK MARK */
+ { 0x270A, 0x270B }, /* RAISED FIST - RAISED HAND */
+ { 0x2728, 0x2728 }, /* SPARKLES */
+ { 0x274C, 0x274C }, /* CROSS MARK */
+ { 0x274E, 0x274E }, /* NEGATIVE SQUARED CROSS MARK */
+ { 0x2753, 0x2755 }, /* BLACK QUESTION MARK ORNAMENT - WHITE EXCLAMATION MARK ORNAMENT */
+ { 0x2757, 0x2757 }, /* HEAVY EXCLAMATION MARK SYMBOL */
+ { 0x2795, 0x2797 }, /* HEAVY PLUS SIGN - HEAVY DIVISION SIGN */
+ { 0x27B0, 0x27B0 }, /* CURLY LOOP */
+ { 0x27BF, 0x27BF }, /* DOUBLE CURLY LOOP */
+ { 0x2B1B, 0x2B1C }, /* BLACK LARGE SQUARE - WHITE LARGE SQUARE */
+ { 0x2B50, 0x2B50 }, /* WHITE MEDIUM STAR */
+ { 0x2B55, 0x2B55 }, /* HEAVY LARGE CIRCLE */
+ { 0x2E80, 0x2E99 }, /* CJK RADICAL REPEAT - CJK RADICAL RAP */
+ { 0x2E9B, 0x2EF3 }, /* CJK RADICAL CHOKE - CJK RADICAL C-SIMPLIFIED TURTLE */
+ { 0x2F00, 0x2FD5 }, /* KANGXI RADICAL ONE - KANGXI RADICAL FLUTE */
+ { 0x2FF0, 0x3029 }, /* IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT - HANGZHOU NUMERAL NINE */
+ { 0x3030, 0x303E }, /* WAVY DASH - IDEOGRAPHIC VARIATION INDICATOR */
+ { 0x3041, 0x3096 }, /* HIRAGANA LETTER SMALL A - HIRAGANA LETTER SMALL KE */
+ { 0x309B, 0x30FF }, /* KATAKANA-HIRAGANA VOICED SOUND MARK - KATAKANA DIGRAPH KOTO */
+ { 0x3105, 0x312F }, /* BOPOMOFO LETTER B - BOPOMOFO LETTER NN */
+ { 0x3131, 0x318E }, /* HANGUL LETTER KIYEOK - HANGUL LETTER ARAEAE */
+ { 0x3190, 0x31E5 }, /* IDEOGRAPHIC ANNOTATION LINKING MARK - CJK STROKE SZP */
+ { 0x31EF, 0x321E }, /* IDEOGRAPHIC DESCRIPTION CHARACTER SUBTRACTION - PARENTHESIZED KOREAN CHARACTER O HU */
+ { 0x3220, 0x3247 }, /* PARENTHESIZED IDEOGRAPH ONE - CIRCLED IDEOGRAPH KOTO */
+ { 0x3250, 0xA48C }, /* PARTNERSHIP SIGN - YI SYLLABLE YYR */
+ { 0xA490, 0xA4C6 }, /* YI RADICAL QOT - YI RADICAL KE */
+ { 0xA960, 0xA97C }, /* HANGUL CHOSEONG TIKEUT-MIEUM - HANGUL CHOSEONG SSANGYEORINHIEUH */
+ { 0xAC00, 0xD7A3 }, /* HANGUL SYLLABLE GA - HANGUL SYLLABLE HIH */
+ { 0xF900, 0xFAFF }, /* U+F900 - U+FAFF */
+ { 0xFE10, 0xFE19 }, /* PRESENTATION FORM FOR VERTICAL COMMA - PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS */
+ { 0xFE30, 0xFE52 }, /* PRESENTATION FORM FOR VERTICAL TWO DOT LEADER - SMALL FULL STOP */
+ { 0xFE54, 0xFE66 }, /* SMALL SEMICOLON - SMALL EQUALS SIGN */
+ { 0xFE68, 0xFE6B }, /* SMALL REVERSE SOLIDUS - SMALL COMMERCIAL AT */
+ { 0xFF01, 0xFF60 }, /* FULLWIDTH EXCLAMATION MARK - FULLWIDTH RIGHT WHITE PARENTHESIS */
+ { 0xFFE0, 0xFFE6 }, /* FULLWIDTH CENT SIGN - FULLWIDTH WON SIGN */
+};
+
+/* Double-width character ranges (non-BMP, U+10000 and above) */
+static const struct ucs_interval32 ucs_double_width_non_bmp_ranges[] = {
+ { 0x16FE0, 0x16FE3 }, /* TANGUT ITERATION MARK - OLD CHINESE ITERATION MARK */
+ { 0x17000, 0x187F7 }, /* U+17000 - U+187F7 */
+ { 0x18800, 0x18CD5 }, /* TANGUT COMPONENT-001 - KHITAN SMALL SCRIPT CHARACTER-18CD5 */
+ { 0x18CFF, 0x18D08 }, /* U+18CFF - U+18D08 */
+ { 0x1AFF0, 0x1AFF3 }, /* KATAKANA LETTER MINNAN TONE-2 - KATAKANA LETTER MINNAN TONE-5 */
+ { 0x1AFF5, 0x1AFFB }, /* KATAKANA LETTER MINNAN TONE-7 - KATAKANA LETTER MINNAN NASALIZED TONE-5 */
+ { 0x1AFFD, 0x1AFFE }, /* KATAKANA LETTER MINNAN NASALIZED TONE-7 - KATAKANA LETTER MINNAN NASALIZED TONE-8 */
+ { 0x1B000, 0x1B122 }, /* KATAKANA LETTER ARCHAIC E - KATAKANA LETTER ARCHAIC WU */
+ { 0x1B132, 0x1B132 }, /* HIRAGANA LETTER SMALL KO */
+ { 0x1B150, 0x1B152 }, /* HIRAGANA LETTER SMALL WI - HIRAGANA LETTER SMALL WO */
+ { 0x1B155, 0x1B155 }, /* KATAKANA LETTER SMALL KO */
+ { 0x1B164, 0x1B167 }, /* KATAKANA LETTER SMALL WI - KATAKANA LETTER SMALL N */
+ { 0x1B170, 0x1B2FB }, /* NUSHU CHARACTER-1B170 - NUSHU CHARACTER-1B2FB */
+ { 0x1D300, 0x1D356 }, /* MONOGRAM FOR EARTH - TETRAGRAM FOR FOSTERING */
+ { 0x1D360, 0x1D376 }, /* COUNTING ROD UNIT DIGIT ONE - IDEOGRAPHIC TALLY MARK FIVE */
+ { 0x1F000, 0x1F02F }, /* U+1F000 - U+1F02F */
+ { 0x1F0A0, 0x1F0FF }, /* U+1F0A0 - U+1F0FF */
+ { 0x1F18E, 0x1F18E }, /* NEGATIVE SQUARED AB */
+ { 0x1F191, 0x1F19A }, /* SQUARED CL - SQUARED VS */
+ { 0x1F200, 0x1F202 }, /* SQUARE HIRAGANA HOKA - SQUARED KATAKANA SA */
+ { 0x1F210, 0x1F23B }, /* SQUARED CJK UNIFIED IDEOGRAPH-624B - SQUARED CJK UNIFIED IDEOGRAPH-914D */
+ { 0x1F240, 0x1F248 }, /* TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C - TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 */
+ { 0x1F250, 0x1F251 }, /* CIRCLED IDEOGRAPH ADVANTAGE - CIRCLED IDEOGRAPH ACCEPT */
+ { 0x1F260, 0x1F265 }, /* ROUNDED SYMBOL FOR FU - ROUNDED SYMBOL FOR CAI */
+ { 0x1F300, 0x1F3FA }, /* CYCLONE - AMPHORA */
+ { 0x1F400, 0x1F64F }, /* RAT - PERSON WITH FOLDED HANDS */
+ { 0x1F680, 0x1F9AF }, /* ROCKET - PROBING CANE */
+ { 0x1F9B4, 0x1FAFF }, /* U+1F9B4 - U+1FAFF */
+ { 0x20000, 0x2FFFD }, /* U+20000 - U+2FFFD */
+ { 0x30000, 0x3FFFD }, /* U+30000 - U+3FFFD */
+};
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index be5564ed8c01..62049ceb34de 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -104,7 +104,6 @@
#include <linux/uaccess.h>
#include <linux/kdb.h>
#include <linux/ctype.h>
-#include <linux/bsearch.h>
#include <linux/gcd.h>
#define MAX_NR_CON_DRIVER 16
@@ -444,6 +443,15 @@ static void vc_uniscr_scroll(struct vc_data *vc, unsigned int top,
}
}
+static u32 vc_uniscr_getc(struct vc_data *vc, int relative_pos)
+{
+ int pos = vc->state.x + vc->vc_need_wrap + relative_pos;
+
+ if (vc->vc_uni_lines && in_range(pos, 0, vc->vc_cols))
+ return vc->vc_uni_lines[vc->state.y][pos];
+ return 0;
+}
+
static void vc_uniscr_copy_area(u32 **dst_lines,
unsigned int dst_cols,
unsigned int dst_rows,
@@ -1862,6 +1870,14 @@ int mouse_reporting(void)
return vc_cons[fg_console].d->vc_report_mouse;
}
+/* invoked via ioctl(TIOCLINUX) */
+static int get_bracketed_paste(struct tty_struct *tty)
+{
+ struct vc_data *vc = tty->driver_data;
+
+ return vc->vc_bracketed_paste;
+}
+
enum {
CSI_DEC_hl_CURSOR_KEYS = 1, /* CKM: cursor keys send ^[Ox/^[[x */
CSI_DEC_hl_132_COLUMNS = 3, /* COLM: 80/132 mode switch */
@@ -1872,6 +1888,7 @@ enum {
CSI_DEC_hl_MOUSE_X10 = 9,
CSI_DEC_hl_SHOW_CURSOR = 25, /* TCEM */
CSI_DEC_hl_MOUSE_VT200 = 1000,
+ CSI_DEC_hl_BRACKETED_PASTE = 2004,
};
/* console_lock is held */
@@ -1924,6 +1941,9 @@ static void csi_DEC_hl(struct vc_data *vc, bool on_off)
case CSI_DEC_hl_MOUSE_VT200:
vc->vc_report_mouse = on_off ? 2 : 0;
break;
+ case CSI_DEC_hl_BRACKETED_PASTE:
+ vc->vc_bracketed_paste = on_off;
+ break;
}
}
@@ -2149,6 +2169,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
vc->state.charset = 0;
vc->vc_need_wrap = 0;
vc->vc_report_mouse = 0;
+ vc->vc_bracketed_paste = 0;
vc->vc_utf = default_utf8;
vc->vc_utf_count = 0;
@@ -2712,43 +2733,6 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c)
}
}
-/* is_double_width() is based on the wcwidth() implementation by
- * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
- * Latest version: https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
- */
-struct interval {
- uint32_t first;
- uint32_t last;
-};
-
-static int ucs_cmp(const void *key, const void *elt)
-{
- uint32_t ucs = *(uint32_t *)key;
- struct interval e = *(struct interval *) elt;
-
- if (ucs > e.last)
- return 1;
- else if (ucs < e.first)
- return -1;
- return 0;
-}
-
-static int is_double_width(uint32_t ucs)
-{
- static const struct interval double_width[] = {
- { 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E },
- { 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF },
- { 0xFE10, 0xFE19 }, { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 },
- { 0xFFE0, 0xFFE6 }, { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD }
- };
- if (ucs < double_width[0].first ||
- ucs > double_width[ARRAY_SIZE(double_width) - 1].last)
- return 0;
-
- return bsearch(&ucs, double_width, ARRAY_SIZE(double_width),
- sizeof(struct interval), ucs_cmp) != NULL;
-}
-
struct vc_draw_region {
unsigned long from, to;
int x;
@@ -2817,7 +2801,7 @@ static int vc_translate_unicode(struct vc_data *vc, int c, bool *rescan)
if ((c & 0xc0) == 0x80) {
/* Unexpected continuation byte? */
if (!vc->vc_utf_count)
- return 0xfffd;
+ goto bad_sequence;
vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
vc->vc_npar++;
@@ -2829,17 +2813,17 @@ static int vc_translate_unicode(struct vc_data *vc, int c, bool *rescan)
/* Reject overlong sequences */
if (c <= utf8_length_changes[vc->vc_npar - 1] ||
c > utf8_length_changes[vc->vc_npar])
- return 0xfffd;
+ goto bad_sequence;
return vc_sanitize_unicode(c);
}
/* Single ASCII byte or first byte of a sequence received */
if (vc->vc_utf_count) {
- /* Continuation byte expected */
+ /* A continuation byte was expected */
*rescan = true;
vc->vc_utf_count = 0;
- return 0xfffd;
+ goto bad_sequence;
}
/* Nothing to do if an ASCII byte was received */
@@ -2858,11 +2842,14 @@ static int vc_translate_unicode(struct vc_data *vc, int c, bool *rescan)
vc->vc_utf_count = 3;
vc->vc_utf_char = (c & 0x07);
} else {
- return 0xfffd;
+ goto bad_sequence;
}
need_more_bytes:
return -1;
+
+bad_sequence:
+ return 0xfffd;
}
static int vc_translate(struct vc_data *vc, int *c, bool *rescan)
@@ -2940,54 +2927,143 @@ static bool vc_is_control(struct vc_data *vc, int tc, int c)
return false;
}
+static void vc_con_rewind(struct vc_data *vc)
+{
+ if (vc->state.x && !vc->vc_need_wrap) {
+ vc->vc_pos -= 2;
+ vc->state.x--;
+ }
+ vc->vc_need_wrap = 0;
+}
+
+#define UCS_ZWS 0x200b /* Zero Width Space */
+#define UCS_VS16 0xfe0f /* Variation Selector 16 */
+#define UCS_REPLACEMENT 0xfffd /* Replacement Character */
+
+static int vc_process_ucs(struct vc_data *vc, int *c, int *tc)
+{
+ u32 prev_c, curr_c = *c;
+
+ if (ucs_is_double_width(curr_c)) {
+ /*
+ * The Unicode screen memory is allocated only when
+ * required. This is one such case as we need to remember
+ * which displayed characters are double-width.
+ */
+ vc_uniscr_check(vc);
+ return 2;
+ }
+
+ if (!ucs_is_zero_width(curr_c))
+ return 1;
+
+ /* From here curr_c is known to be zero-width. */
+
+ if (ucs_is_double_width(vc_uniscr_getc(vc, -2))) {
+ /*
+ * Let's merge this zero-width code point with the preceding
+ * double-width code point by replacing the existing
+ * zero-width space padding. To do so we rewind one column
+ * and pretend this has a width of 1.
+ * We give the legacy display the same initial space padding.
+ */
+ vc_con_rewind(vc);
+ *tc = ' ';
+ return 1;
+ }
+
+ /* From here the preceding character, if any, must be single-width. */
+ prev_c = vc_uniscr_getc(vc, -1);
+
+ if (curr_c == UCS_VS16 && prev_c != 0) {
+ /*
+ * VS16 (U+FE0F) is special. It typically turns the preceding
+ * single-width character into a double-width one. Let it
+ * have a width of 1 effectively making the combination with
+ * the preceding character double-width.
+ */
+ *tc = ' ';
+ return 1;
+ }
+
+ /* try recomposition */
+ prev_c = ucs_recompose(prev_c, curr_c);
+ if (prev_c != 0) {
+ vc_con_rewind(vc);
+ *tc = *c = prev_c;
+ return 1;
+ }
+
+ /* Otherwise zero-width code points are ignored. */
+ return 0;
+}
+
+static int vc_get_glyph(struct vc_data *vc, int tc)
+{
+ int glyph = conv_uni_to_pc(vc, tc);
+ u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+
+ if (!(glyph & ~charmask))
+ return glyph;
+
+ if (glyph == -1)
+ return -1; /* nothing to display */
+
+ /* Glyph not found */
+ if ((!vc->vc_utf || vc->vc_disp_ctrl || tc < 128) && !(tc & ~charmask)) {
+ /*
+ * In legacy mode use the glyph we get by a 1:1 mapping.
+ * This would make absolutely no sense with Unicode in mind, but do this for
+ * ASCII characters since a font may lack Unicode mapping info and we don't
+ * want to end up with having question marks only.
+ */
+ return tc;
+ }
+
+ /*
+ * The Unicode screen memory is allocated only when required.
+ * This is one such case: we're about to "cheat" with the displayed
+ * character meaning the simple screen buffer won't hold the original
+ * information, whereas the Unicode screen buffer always does.
+ */
+ vc_uniscr_check(vc);
+
+ /* Try getting a simpler fallback character. */
+ tc = ucs_get_fallback(tc);
+ if (tc)
+ return vc_get_glyph(vc, tc);
+
+ /* Display U+FFFD (Unicode Replacement Character). */
+ return conv_uni_to_pc(vc, UCS_REPLACEMENT);
+}
+
static int vc_con_write_normal(struct vc_data *vc, int tc, int c,
struct vc_draw_region *draw)
{
int next_c;
unsigned char vc_attr = vc->vc_attr;
- u16 himask = vc->vc_hi_font_mask, charmask = himask ? 0x1ff : 0xff;
+ u16 himask = vc->vc_hi_font_mask;
u8 width = 1;
bool inverse = false;
if (vc->vc_utf && !vc->vc_disp_ctrl) {
- if (is_double_width(c))
- width = 2;
+ width = vc_process_ucs(vc, &c, &tc);
+ if (!width)
+ goto out;
}
/* Now try to find out how to display it */
- tc = conv_uni_to_pc(vc, tc);
- if (tc & ~charmask) {
- if (tc == -1 || tc == -2)
- return -1; /* nothing to display */
-
- /* Glyph not found */
- if ((!vc->vc_utf || vc->vc_disp_ctrl || c < 128) &&
- !(c & ~charmask)) {
- /*
- * In legacy mode use the glyph we get by a 1:1
- * mapping.
- * This would make absolutely no sense with Unicode in
- * mind, but do this for ASCII characters since a font
- * may lack Unicode mapping info and we don't want to
- * end up with having question marks only.
- */
- tc = c;
- } else {
- /*
- * Display U+FFFD. If it's not found, display an inverse
- * question mark.
- */
- tc = conv_uni_to_pc(vc, 0xfffd);
- if (tc < 0) {
- inverse = true;
- tc = conv_uni_to_pc(vc, '?');
- if (tc < 0)
- tc = '?';
-
- vc_attr = vc_invert_attr(vc);
- con_flush(vc, draw);
- }
- }
+ tc = vc_get_glyph(vc, tc);
+ if (tc == -1)
+ return -1; /* nothing to display */
+ if (tc < 0) {
+ inverse = true;
+ tc = conv_uni_to_pc(vc, '?');
+ if (tc < 0)
+ tc = '?';
+
+ vc_attr = vc_invert_attr(vc);
+ con_flush(vc, draw);
}
next_c = c;
@@ -3028,8 +3104,14 @@ static int vc_con_write_normal(struct vc_data *vc, int tc, int c,
tc = conv_uni_to_pc(vc, ' ');
if (tc < 0)
tc = ' ';
- next_c = ' ';
+ /*
+ * Store a zero-width space in the Unicode screen given that
+ * the previous code point is semantically double width.
+ */
+ next_c = UCS_ZWS;
}
+
+out:
notify_write(vc, c);
if (inverse)
@@ -3414,6 +3496,8 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
break;
case TIOCL_BLANKEDSCREEN:
return console_blanked;
+ case TIOCL_GETBRACKETEDPASTE:
+ return get_bracketed_paste(tty);
default:
return -EINVAL;
}
@@ -4501,7 +4585,7 @@ void do_blank_screen(int entering_gfx)
}
hide_cursor(vc);
- del_timer_sync(&console_timer);
+ timer_delete_sync(&console_timer);
blank_timer_expired = 0;
save_screen(vc);
@@ -4566,6 +4650,7 @@ void do_unblank_screen(int leaving_gfx)
set_palette(vc);
set_cursor(vc);
vt_event_post(VT_EVENT_UNBLANK, vc->vc_num, vc->vc_num);
+ notify_update(vc);
}
EXPORT_SYMBOL(do_unblank_screen);
@@ -4606,7 +4691,7 @@ void poke_blanked_console(void)
/* This isn't perfectly race free, but a race here would be mostly harmless,
* at worst, we'll do a spurious blank and it's unlikely
*/
- del_timer(&console_timer);
+ timer_delete(&console_timer);
blank_timer_expired = 0;
if (ignore_poke || !vc_cons[fg_console].d || vc_cons[fg_console].d->vc_mode == KD_GRAPHICS)
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index 4b91072f3a4e..61342e06970a 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -951,6 +951,22 @@ int vt_ioctl(struct tty_struct *tty,
(unsigned short __user *)arg);
case VT_WAITEVENT:
return vt_event_wait_ioctl((struct vt_event __user *)arg);
+
+ case VT_GETCONSIZECSRPOS:
+ {
+ struct vt_consizecsrpos concsr;
+
+ console_lock();
+ concsr.con_cols = vc->vc_cols;
+ concsr.con_rows = vc->vc_rows;
+ concsr.csr_col = vc->state.x;
+ concsr.csr_row = vc->state.y;
+ console_unlock();
+ if (copy_to_user(up, &concsr, sizeof(concsr)))
+ return -EFAULT;
+ return 0;
+ }
+
default:
return -ENOIOCTLCMD;
}
@@ -1103,8 +1119,6 @@ long vt_compat_ioctl(struct tty_struct *tty,
case VT_WAITACTIVE:
case VT_RELDISP:
case VT_DISALLOCATE:
- case VT_RESIZE:
- case VT_RESIZEX:
return vt_ioctl(tty, cmd, arg);
/*