mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 12:44:11 +08:00
TTY/Serial driver changes for 5.12-rc1
Here is the big set of tty/serial driver changes for 5.12-rc1. Nothing huge, just lots of good cleanups and additions: - Your n_tty line discipline cleanups - vt core cleanups and reworks to make the code more "modern" - stm32 driver additions - tty led support added to the tty core and led layer - minor serial driver fixups and additions All of these have been in linux-next for a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYCqgqw8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ymJYQCgnxHmkhzJ2VarTDR3cWm1gu0NU7AAoNe5wWUh 4TQbhB9LSNo78HnIVze0 =Chcg -----END PGP SIGNATURE----- Merge tag 'tty-5.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty/serial driver updates from Greg KH: "Here is the big set of tty/serial driver changes for 5.12-rc1. Nothing huge, just lots of good cleanups and additions: - n_tty line discipline cleanups - vt core cleanups and reworks to make the code more "modern" - stm32 driver additions - tty led support added to the tty core and led layer - minor serial driver fixups and additions All of these have been in linux-next for a while with no reported issues" * tag 'tty-5.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (54 commits) serial: core: Remove BUG_ON(in_interrupt()) check vt_ioctl: Remove in_interrupt() check dt-bindings: serial: imx: Switch to my personal address vt: keyboard, use new API for keyboard_tasklet serial: stm32: improve platform_get_irq condition handling in init_port serial: ifx6x60: Remove driver for deprecated platform tty: fix up iterate_tty_read() EOVERFLOW handling tty: fix up hung_up_tty_read() conversion tty: fix up hung_up_tty_write() conversion tty: teach the n_tty ICANON case about the new "cookie continuations" too tty: teach n_tty line discipline about the new "cookie continuations" tty: clean up legacy leftovers from n_tty line discipline tty: implement read_iter tty: convert tty_ldisc_ops 'read()' function to take a kernel pointer serial: remove sirf prima/atlas driver serial: mxs-auart: Remove <asm/cacheflush.h> serial: mxs-auart: Remove serial_mxs_probe_dt() serial: fsl_lpuart: Use of_device_get_match_data() dt-bindings: serial: renesas,hscif: Add r8a779a0 support tty: serial: Drop unused efm32 serial driver ...
This commit is contained in:
commit
e4286926ab
6
Documentation/ABI/testing/sysfs-class-led-trigger-tty
Normal file
6
Documentation/ABI/testing/sysfs-class-led-trigger-tty
Normal file
@ -0,0 +1,6 @@
|
||||
What: /sys/class/leds/<led>/ttyname
|
||||
Date: Dec 2020
|
||||
KernelVersion: 5.10
|
||||
Contact: linux-leds@vger.kernel.org
|
||||
Description:
|
||||
Specifies the tty device name of the triggering tty
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Freescale i.MX Universal Asynchronous Receiver/Transmitter (UART)
|
||||
|
||||
maintainers:
|
||||
- Fabio Estevam <fabio.estevam@nxp.com>
|
||||
- Fabio Estevam <festevam@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "serial.yaml"
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Freescale MXS Application UART (AUART)
|
||||
|
||||
maintainers:
|
||||
- Fabio Estevam <fabio.estevam@nxp.com>
|
||||
- Fabio Estevam <festevam@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "serial.yaml"
|
||||
|
@ -51,6 +51,7 @@ properties:
|
||||
- renesas,hscif-r8a77980 # R-Car V3H
|
||||
- renesas,hscif-r8a77990 # R-Car E3
|
||||
- renesas,hscif-r8a77995 # R-Car D3
|
||||
- renesas,hscif-r8a779a0 # R-Car V3U
|
||||
- const: renesas,rcar-gen3-hscif # R-Car Gen3 and RZ/G2
|
||||
- const: renesas,hscif # generic HSCIF compatible UART
|
||||
|
||||
|
@ -1,34 +0,0 @@
|
||||
* CSR SiRFprimaII/atlasVI Universal Synchronous Asynchronous Receiver/Transmitter *
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "sirf,prima2-uart", "sirf, prima2-usp-uart",
|
||||
"sirf,atlas7-uart" or "sirf,atlas7-usp-uart".
|
||||
- reg : Offset and length of the register set for the device
|
||||
- interrupts : Should contain uart interrupt
|
||||
- fifosize : Should define hardware rx/tx fifo size
|
||||
- clocks : Should contain uart clock number
|
||||
|
||||
Optional properties:
|
||||
- uart-has-rtscts: we have hardware flow controller pins in hardware
|
||||
- rts-gpios: RTS pin for USP-based UART if uart-has-rtscts is true
|
||||
- cts-gpios: CTS pin for USP-based UART if uart-has-rtscts is true
|
||||
|
||||
Example:
|
||||
|
||||
uart0: uart@b0050000 {
|
||||
cell-index = <0>;
|
||||
compatible = "sirf,prima2-uart";
|
||||
reg = <0xb0050000 0x1000>;
|
||||
interrupts = <17>;
|
||||
fifosize = <128>;
|
||||
clocks = <&clks 13>;
|
||||
};
|
||||
|
||||
On the board-specific dts, we can put rts-gpios and cts-gpios like
|
||||
|
||||
usp@b0090000 {
|
||||
compatible = "sirf,prima2-usp-uart";
|
||||
uart-has-rtscts;
|
||||
rts-gpios = <&gpio 15 0>;
|
||||
cts-gpios = <&gpio 46 0>;
|
||||
};
|
@ -50,11 +50,14 @@ properties:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
cts-gpios:
|
||||
maxItems: 1
|
||||
|
||||
rts-gpios:
|
||||
maxItems: 1
|
||||
# cts-gpios and rts-gpios properties can be used instead of 'uart-has-rtscts'
|
||||
# or 'st,hw-flow-ctrl' (deprecated) for making use of any gpio pins for flow
|
||||
# control instead of dedicated pins.
|
||||
#
|
||||
# It should be noted that both cts-gpios/rts-gpios and 'uart-has-rtscts' or
|
||||
# 'st,hw-flow-ctrl' (deprecated) properties cannot co-exist in a design.
|
||||
cts-gpios: true
|
||||
rts-gpios: true
|
||||
|
||||
wakeup-source: true
|
||||
|
||||
|
@ -68,7 +68,6 @@ There are debugfs parameters provided for serial communication.
|
||||
* tty_status: Prints the bit-mask tty status information
|
||||
|
||||
- 0x01 - tty->warned is on.
|
||||
- 0x02 - tty->low_latency is on.
|
||||
- 0x04 - tty->packed is on.
|
||||
- 0x08 - tty->flow_stopped is on.
|
||||
- 0x10 - tty->hw_stopped is on.
|
||||
|
@ -152,7 +152,7 @@ static int spk_ttyio_initialise_ldisc(struct spk_synth *synth)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tty = tty_kopen(dev);
|
||||
tty = tty_kopen_exclusive(dev);
|
||||
if (IS_ERR(tty))
|
||||
return PTR_ERR(tty);
|
||||
|
||||
|
@ -801,7 +801,8 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file *file,
|
||||
* We don't provide read/write/poll interface for user space.
|
||||
*/
|
||||
static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file,
|
||||
unsigned char __user *buf, size_t nr)
|
||||
unsigned char *buf, size_t nr,
|
||||
void **cookie, unsigned long offset)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -818,29 +819,28 @@ static __poll_t hci_uart_tty_poll(struct tty_struct *tty,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct tty_ldisc_ops hci_uart_ldisc = {
|
||||
.owner = THIS_MODULE,
|
||||
.magic = TTY_LDISC_MAGIC,
|
||||
.name = "n_hci",
|
||||
.open = hci_uart_tty_open,
|
||||
.close = hci_uart_tty_close,
|
||||
.read = hci_uart_tty_read,
|
||||
.write = hci_uart_tty_write,
|
||||
.ioctl = hci_uart_tty_ioctl,
|
||||
.compat_ioctl = hci_uart_tty_ioctl,
|
||||
.poll = hci_uart_tty_poll,
|
||||
.receive_buf = hci_uart_tty_receive,
|
||||
.write_wakeup = hci_uart_tty_wakeup,
|
||||
};
|
||||
|
||||
static int __init hci_uart_init(void)
|
||||
{
|
||||
static struct tty_ldisc_ops hci_uart_ldisc;
|
||||
int err;
|
||||
|
||||
BT_INFO("HCI UART driver ver %s", VERSION);
|
||||
|
||||
/* Register the tty discipline */
|
||||
|
||||
memset(&hci_uart_ldisc, 0, sizeof(hci_uart_ldisc));
|
||||
hci_uart_ldisc.magic = TTY_LDISC_MAGIC;
|
||||
hci_uart_ldisc.name = "n_hci";
|
||||
hci_uart_ldisc.open = hci_uart_tty_open;
|
||||
hci_uart_ldisc.close = hci_uart_tty_close;
|
||||
hci_uart_ldisc.read = hci_uart_tty_read;
|
||||
hci_uart_ldisc.write = hci_uart_tty_write;
|
||||
hci_uart_ldisc.ioctl = hci_uart_tty_ioctl;
|
||||
hci_uart_ldisc.compat_ioctl = hci_uart_tty_ioctl;
|
||||
hci_uart_ldisc.poll = hci_uart_tty_poll;
|
||||
hci_uart_ldisc.receive_buf = hci_uart_tty_receive;
|
||||
hci_uart_ldisc.write_wakeup = hci_uart_tty_wakeup;
|
||||
hci_uart_ldisc.owner = THIS_MODULE;
|
||||
|
||||
err = tty_register_ldisc(N_HCI, &hci_uart_ldisc);
|
||||
if (err) {
|
||||
BT_ERR("HCI line discipline registration failed. (%d)", err);
|
||||
|
@ -2494,8 +2494,6 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
|
||||
printk("%s(%d):mgslpc_open(%s), old ref count = %d\n",
|
||||
__FILE__, __LINE__, tty->driver->name, port->count);
|
||||
|
||||
port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
spin_lock_irqsave(&info->netlock, flags);
|
||||
if (info->netcount) {
|
||||
retval = -EBUSY;
|
||||
|
@ -156,7 +156,9 @@ out:
|
||||
* returning 0 characters.
|
||||
*/
|
||||
|
||||
static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char __user * buf, size_t nr)
|
||||
static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file,
|
||||
unsigned char *kbuf, size_t nr,
|
||||
void **cookie, unsigned long offset)
|
||||
{
|
||||
struct serport *serport = (struct serport*) tty->disc_data;
|
||||
struct serio *serio;
|
||||
|
@ -144,4 +144,13 @@ config LEDS_TRIGGER_AUDIO
|
||||
the audio mute and mic-mute changes.
|
||||
If unsure, say N
|
||||
|
||||
config LEDS_TRIGGER_TTY
|
||||
tristate "LED Trigger for TTY devices"
|
||||
depends on TTY
|
||||
help
|
||||
This allows LEDs to be controlled by activity on ttys which includes
|
||||
serial devices like /dev/ttyS0.
|
||||
|
||||
When build as a module this driver will be called ledtrig-tty.
|
||||
|
||||
endif # LEDS_TRIGGERS
|
||||
|
@ -15,3 +15,4 @@ obj-$(CONFIG_LEDS_TRIGGER_PANIC) += ledtrig-panic.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_PATTERN) += ledtrig-pattern.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_AUDIO) += ledtrig-audio.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_TTY) += ledtrig-tty.o
|
||||
|
183
drivers/leds/trigger/ledtrig-tty.c
Normal file
183
drivers/leds/trigger/ledtrig-tty.c
Normal file
@ -0,0 +1,183 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tty.h>
|
||||
#include <uapi/linux/serial.h>
|
||||
|
||||
struct ledtrig_tty_data {
|
||||
struct led_classdev *led_cdev;
|
||||
struct delayed_work dwork;
|
||||
struct mutex mutex;
|
||||
const char *ttyname;
|
||||
struct tty_struct *tty;
|
||||
int rx, tx;
|
||||
};
|
||||
|
||||
static void ledtrig_tty_restart(struct ledtrig_tty_data *trigger_data)
|
||||
{
|
||||
schedule_delayed_work(&trigger_data->dwork, 0);
|
||||
}
|
||||
|
||||
static ssize_t ttyname_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev);
|
||||
ssize_t len = 0;
|
||||
|
||||
mutex_lock(&trigger_data->mutex);
|
||||
|
||||
if (trigger_data->ttyname)
|
||||
len = sprintf(buf, "%s\n", trigger_data->ttyname);
|
||||
|
||||
mutex_unlock(&trigger_data->mutex);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t ttyname_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev);
|
||||
char *ttyname;
|
||||
ssize_t ret = size;
|
||||
bool running;
|
||||
|
||||
if (size > 0 && buf[size - 1] == '\n')
|
||||
size -= 1;
|
||||
|
||||
if (size) {
|
||||
ttyname = kmemdup_nul(buf, size, GFP_KERNEL);
|
||||
if (!ttyname) {
|
||||
ret = -ENOMEM;
|
||||
goto out_unlock;
|
||||
}
|
||||
} else {
|
||||
ttyname = NULL;
|
||||
}
|
||||
|
||||
mutex_lock(&trigger_data->mutex);
|
||||
|
||||
running = trigger_data->ttyname != NULL;
|
||||
|
||||
kfree(trigger_data->ttyname);
|
||||
tty_kref_put(trigger_data->tty);
|
||||
trigger_data->tty = NULL;
|
||||
|
||||
trigger_data->ttyname = ttyname;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&trigger_data->mutex);
|
||||
|
||||
if (ttyname && !running)
|
||||
ledtrig_tty_restart(trigger_data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
static DEVICE_ATTR_RW(ttyname);
|
||||
|
||||
static void ledtrig_tty_work(struct work_struct *work)
|
||||
{
|
||||
struct ledtrig_tty_data *trigger_data =
|
||||
container_of(work, struct ledtrig_tty_data, dwork.work);
|
||||
struct serial_icounter_struct icount;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&trigger_data->mutex);
|
||||
|
||||
if (!trigger_data->ttyname) {
|
||||
/* exit without rescheduling */
|
||||
mutex_unlock(&trigger_data->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
/* try to get the tty corresponding to $ttyname */
|
||||
if (!trigger_data->tty) {
|
||||
dev_t devno;
|
||||
struct tty_struct *tty;
|
||||
int ret;
|
||||
|
||||
ret = tty_dev_name_to_number(trigger_data->ttyname, &devno);
|
||||
if (ret < 0)
|
||||
/*
|
||||
* A device with this name might appear later, so keep
|
||||
* retrying.
|
||||
*/
|
||||
goto out;
|
||||
|
||||
tty = tty_kopen_shared(devno);
|
||||
if (IS_ERR(tty) || !tty)
|
||||
/* What to do? retry or abort */
|
||||
goto out;
|
||||
|
||||
trigger_data->tty = tty;
|
||||
}
|
||||
|
||||
ret = tty_get_icount(trigger_data->tty, &icount);
|
||||
if (ret) {
|
||||
dev_info(trigger_data->tty->dev, "Failed to get icount, stopped polling\n");
|
||||
mutex_unlock(&trigger_data->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (icount.rx != trigger_data->rx ||
|
||||
icount.tx != trigger_data->tx) {
|
||||
led_set_brightness(trigger_data->led_cdev, LED_ON);
|
||||
|
||||
trigger_data->rx = icount.rx;
|
||||
trigger_data->tx = icount.tx;
|
||||
} else {
|
||||
led_set_brightness(trigger_data->led_cdev, LED_OFF);
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&trigger_data->mutex);
|
||||
schedule_delayed_work(&trigger_data->dwork, msecs_to_jiffies(100));
|
||||
}
|
||||
|
||||
static struct attribute *ledtrig_tty_attrs[] = {
|
||||
&dev_attr_ttyname.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ledtrig_tty);
|
||||
|
||||
static int ledtrig_tty_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct ledtrig_tty_data *trigger_data;
|
||||
|
||||
trigger_data = kzalloc(sizeof(*trigger_data), GFP_KERNEL);
|
||||
if (!trigger_data)
|
||||
return -ENOMEM;
|
||||
|
||||
led_set_trigger_data(led_cdev, trigger_data);
|
||||
|
||||
INIT_DELAYED_WORK(&trigger_data->dwork, ledtrig_tty_work);
|
||||
trigger_data->led_cdev = led_cdev;
|
||||
mutex_init(&trigger_data->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ledtrig_tty_deactivate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct ledtrig_tty_data *trigger_data = led_get_trigger_data(led_cdev);
|
||||
|
||||
cancel_delayed_work_sync(&trigger_data->dwork);
|
||||
|
||||
kfree(trigger_data);
|
||||
}
|
||||
|
||||
static struct led_trigger ledtrig_tty = {
|
||||
.name = "tty",
|
||||
.activate = ledtrig_tty_activate,
|
||||
.deactivate = ledtrig_tty_deactivate,
|
||||
.groups = ledtrig_tty_groups,
|
||||
};
|
||||
module_led_trigger(ledtrig_tty);
|
||||
|
||||
MODULE_AUTHOR("Uwe Kleine-König <u.kleine-koenig@pengutronix.de>");
|
||||
MODULE_DESCRIPTION("UART LED trigger");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -89,8 +89,7 @@ static inline void update_tty_status(struct ser_device *ser)
|
||||
ser->tty_status =
|
||||
ser->tty->stopped << 5 |
|
||||
ser->tty->flow_stopped << 3 |
|
||||
ser->tty->packet << 2 |
|
||||
ser->tty->port->low_latency << 1;
|
||||
ser->tty->packet << 2;
|
||||
}
|
||||
static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty)
|
||||
{
|
||||
|
@ -259,7 +259,8 @@ static int ppp_asynctty_hangup(struct tty_struct *tty)
|
||||
*/
|
||||
static ssize_t
|
||||
ppp_asynctty_read(struct tty_struct *tty, struct file *file,
|
||||
unsigned char __user *buf, size_t count)
|
||||
unsigned char *buf, size_t count,
|
||||
void **cookie, unsigned long offset)
|
||||
{
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
@ -257,7 +257,8 @@ static int ppp_sync_hangup(struct tty_struct *tty)
|
||||
*/
|
||||
static ssize_t
|
||||
ppp_sync_read(struct tty_struct *tty, struct file *file,
|
||||
unsigned char __user *buf, size_t count)
|
||||
unsigned char *buf, size_t count,
|
||||
void **cookie, unsigned long offset)
|
||||
{
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
@ -914,7 +914,6 @@ static int tty3215_open(struct tty_struct *tty, struct file * filp)
|
||||
|
||||
tty_port_tty_set(&raw->port, tty);
|
||||
|
||||
raw->port.low_latency = 0; /* don't use bottom half for pushing chars */
|
||||
/*
|
||||
* Start up 3215 device
|
||||
*/
|
||||
|
@ -65,7 +65,6 @@ sclp_tty_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
tty_port_tty_set(&sclp_port, tty);
|
||||
tty->driver_data = NULL;
|
||||
sclp_port.low_latency = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -560,7 +560,6 @@ sclp_vt220_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
if (tty->count == 1) {
|
||||
tty_port_tty_set(&sclp_vt220_port, tty);
|
||||
sclp_vt220_port.low_latency = 0;
|
||||
if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
|
||||
tty->winsize.ws_row = 24;
|
||||
tty->winsize.ws_col = 80;
|
||||
|
@ -967,7 +967,6 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
|
||||
tty->driver_data = tp;
|
||||
tty->winsize.ws_row = tp->view.rows - 2;
|
||||
tty->winsize.ws_col = tp->view.cols;
|
||||
tp->port.low_latency = 0;
|
||||
tp->inattr = TF_INPUT;
|
||||
goto port_install;
|
||||
}
|
||||
@ -996,7 +995,6 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
|
||||
return rc;
|
||||
}
|
||||
|
||||
tp->port.low_latency = 0;
|
||||
tty->winsize.ws_row = tp->view.rows - 2;
|
||||
tty->winsize.ws_col = tp->view.cols;
|
||||
|
||||
|
@ -998,7 +998,6 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss)
|
||||
state->custom_divisor = ss->custom_divisor;
|
||||
port->close_delay = ss->close_delay * HZ/100;
|
||||
port->closing_wait = ss->closing_wait * HZ/100;
|
||||
port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
check_and_exit:
|
||||
if (tty_port_initialized(port)) {
|
||||
@ -1386,8 +1385,6 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
|
||||
tty->driver_data = info;
|
||||
tty->port = port;
|
||||
|
||||
port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
retval = startup(tty, info);
|
||||
if (retval) {
|
||||
return retval;
|
||||
|
@ -605,7 +605,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
|
||||
hvcsd->todo_mask |= HVCS_QUICK_READ;
|
||||
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
/* This is synch because tty->low_latency == 1 */
|
||||
/* This is synch -- FIXME :js: it is not! */
|
||||
if(got)
|
||||
tty_flip_buffer_push(&hvcsd->port);
|
||||
|
||||
@ -825,9 +825,6 @@ static int hvcs_remove(struct vio_dev *dev)
|
||||
unsigned long flags;
|
||||
struct tty_struct *tty;
|
||||
|
||||
if (!hvcsd)
|
||||
return -ENODEV;
|
||||
|
||||
/* By this time the vty-server won't be getting any more interrupts */
|
||||
|
||||
spin_lock_irqsave(&hvcsd->lock, flags);
|
||||
|
@ -101,7 +101,6 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
|
||||
|
||||
tty->port.tty = linux_tty;
|
||||
linux_tty->driver_data = tty;
|
||||
tty->port.low_latency = 1;
|
||||
|
||||
if (tty->tty_type == TTYTYPE_MODEM)
|
||||
ipwireless_ppp_open(tty->network);
|
||||
|
@ -1273,7 +1273,6 @@ static int mxser_set_serial_info(struct tty_struct *tty,
|
||||
(ss->flags & ASYNC_FLAGS));
|
||||
port->close_delay = ss->close_delay * HZ / 100;
|
||||
port->closing_wait = ss->closing_wait * HZ / 100;
|
||||
port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
|
||||
(ss->baud_base != info->baud_base ||
|
||||
ss->custom_divisor !=
|
||||
|
@ -2559,7 +2559,8 @@ static void gsmld_write_wakeup(struct tty_struct *tty)
|
||||
*/
|
||||
|
||||
static ssize_t gsmld_read(struct tty_struct *tty, struct file *file,
|
||||
unsigned char __user *buf, size_t nr)
|
||||
unsigned char *buf, size_t nr,
|
||||
void **cookie, unsigned long offset)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
@ -416,13 +416,19 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
|
||||
* Returns the number of bytes returned or error code.
|
||||
*/
|
||||
static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
|
||||
__u8 __user *buf, size_t nr)
|
||||
__u8 *kbuf, size_t nr,
|
||||
void **cookie, unsigned long offset)
|
||||
{
|
||||
struct n_hdlc *n_hdlc = tty->disc_data;
|
||||
int ret = 0;
|
||||
struct n_hdlc_buf *rbuf;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
/* Is this a repeated call for an rbuf we already found earlier? */
|
||||
rbuf = *cookie;
|
||||
if (rbuf)
|
||||
goto have_rbuf;
|
||||
|
||||
add_wait_queue(&tty->read_wait, &wait);
|
||||
|
||||
for (;;) {
|
||||
@ -436,25 +442,8 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
|
||||
if (rbuf) {
|
||||
if (rbuf->count > nr) {
|
||||
/* too large for caller's buffer */
|
||||
ret = -EOVERFLOW;
|
||||
} else {
|
||||
__set_current_state(TASK_RUNNING);
|
||||
if (copy_to_user(buf, rbuf->buf, rbuf->count))
|
||||
ret = -EFAULT;
|
||||
else
|
||||
ret = rbuf->count;
|
||||
}
|
||||
|
||||
if (n_hdlc->rx_free_buf_list.count >
|
||||
DEFAULT_RX_BUF_COUNT)
|
||||
kfree(rbuf);
|
||||
else
|
||||
n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, rbuf);
|
||||
if (rbuf)
|
||||
break;
|
||||
}
|
||||
|
||||
/* no data */
|
||||
if (tty_io_nonblock(tty, file)) {
|
||||
@ -473,6 +462,39 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
|
||||
remove_wait_queue(&tty->read_wait, &wait);
|
||||
__set_current_state(TASK_RUNNING);
|
||||
|
||||
if (!rbuf)
|
||||
return ret;
|
||||
*cookie = rbuf;
|
||||
|
||||
have_rbuf:
|
||||
/* Have we used it up entirely? */
|
||||
if (offset >= rbuf->count)
|
||||
goto done_with_rbuf;
|
||||
|
||||
/* More data to go, but can't copy any more? EOVERFLOW */
|
||||
ret = -EOVERFLOW;
|
||||
if (!nr)
|
||||
goto done_with_rbuf;
|
||||
|
||||
/* Copy as much data as possible */
|
||||
ret = rbuf->count - offset;
|
||||
if (ret > nr)
|
||||
ret = nr;
|
||||
memcpy(kbuf, rbuf->buf+offset, ret);
|
||||
offset += ret;
|
||||
|
||||
/* If we still have data left, we leave the rbuf in the cookie */
|
||||
if (offset < rbuf->count)
|
||||
return ret;
|
||||
|
||||
done_with_rbuf:
|
||||
*cookie = NULL;
|
||||
|
||||
if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT)
|
||||
kfree(rbuf);
|
||||
else
|
||||
n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, rbuf);
|
||||
|
||||
return ret;
|
||||
|
||||
} /* end of n_hdlc_tty_read() */
|
||||
|
@ -20,7 +20,8 @@ static void n_null_close(struct tty_struct *tty)
|
||||
}
|
||||
|
||||
static ssize_t n_null_read(struct tty_struct *tty, struct file *file,
|
||||
unsigned char __user * buf, size_t nr)
|
||||
unsigned char *buf, size_t nr,
|
||||
void **cookie, unsigned long offset)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ static void remove_client_block(struct r3964_info *pInfo,
|
||||
static int r3964_open(struct tty_struct *tty);
|
||||
static void r3964_close(struct tty_struct *tty);
|
||||
static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
|
||||
unsigned char __user * buf, size_t nr);
|
||||
void *cookie, unsigned char *buf, size_t nr);
|
||||
static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
|
||||
const unsigned char *buf, size_t nr);
|
||||
static int r3964_ioctl(struct tty_struct *tty, struct file *file,
|
||||
@ -1058,7 +1058,8 @@ static void r3964_close(struct tty_struct *tty)
|
||||
}
|
||||
|
||||
static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
|
||||
unsigned char __user * buf, size_t nr)
|
||||
unsigned char *kbuf, size_t nr,
|
||||
void **cookie, unsigned long offset)
|
||||
{
|
||||
struct r3964_info *pInfo = tty->disc_data;
|
||||
struct r3964_client_info *pClient;
|
||||
@ -1109,10 +1110,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
|
||||
kfree(pMsg);
|
||||
TRACE_M("r3964_read - msg kfree %p", pMsg);
|
||||
|
||||
if (copy_to_user(buf, &theMsg, ret)) {
|
||||
ret = -EFAULT;
|
||||
goto unlock;
|
||||
}
|
||||
memcpy(kbuf, &theMsg, ret);
|
||||
|
||||
TRACE_PS("read - return %d", ret);
|
||||
goto unlock;
|
||||
|
@ -118,7 +118,9 @@ static void n_tracerouter_close(struct tty_struct *tty)
|
||||
* -EINVAL
|
||||
*/
|
||||
static ssize_t n_tracerouter_read(struct tty_struct *tty, struct file *file,
|
||||
unsigned char __user *buf, size_t nr) {
|
||||
unsigned char *buf, size_t nr,
|
||||
void **cookie, unsigned long offset)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,9 @@ static void n_tracesink_close(struct tty_struct *tty)
|
||||
* -EINVAL
|
||||
*/
|
||||
static ssize_t n_tracesink_read(struct tty_struct *tty, struct file *file,
|
||||
unsigned char __user *buf, size_t nr) {
|
||||
unsigned char *buf, size_t nr,
|
||||
void **cookie, unsigned long offset)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -164,29 +164,24 @@ static void zero_buffer(struct tty_struct *tty, u8 *buffer, int size)
|
||||
memset(buffer, 0x00, size);
|
||||
}
|
||||
|
||||
static int tty_copy_to_user(struct tty_struct *tty, void __user *to,
|
||||
size_t tail, size_t n)
|
||||
static void tty_copy(struct tty_struct *tty, void *to, size_t tail, size_t n)
|
||||
{
|
||||
struct n_tty_data *ldata = tty->disc_data;
|
||||
size_t size = N_TTY_BUF_SIZE - tail;
|
||||
void *from = read_buf_addr(ldata, tail);
|
||||
int uncopied;
|
||||
|
||||
if (n > size) {
|
||||
tty_audit_add_data(tty, from, size);
|
||||
uncopied = copy_to_user(to, from, size);
|
||||
zero_buffer(tty, from, size - uncopied);
|
||||
if (uncopied)
|
||||
return uncopied;
|
||||
memcpy(to, from, size);
|
||||
zero_buffer(tty, from, size);
|
||||
to += size;
|
||||
n -= size;
|
||||
from = ldata->read_buf;
|
||||
}
|
||||
|
||||
tty_audit_add_data(tty, from, n);
|
||||
uncopied = copy_to_user(to, from, n);
|
||||
zero_buffer(tty, from, n - uncopied);
|
||||
return uncopied;
|
||||
memcpy(to, from, n);
|
||||
zero_buffer(tty, from, n);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1894,8 +1889,10 @@ static void n_tty_close(struct tty_struct *tty)
|
||||
if (tty->link)
|
||||
n_tty_packet_mode_flush(tty);
|
||||
|
||||
down_write(&tty->termios_rwsem);
|
||||
vfree(ldata);
|
||||
tty->disc_data = NULL;
|
||||
up_write(&tty->termios_rwsem);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1944,42 +1941,38 @@ static inline int input_available_p(struct tty_struct *tty, int poll)
|
||||
/**
|
||||
* copy_from_read_buf - copy read data directly
|
||||
* @tty: terminal device
|
||||
* @b: user data
|
||||
* @kbp: data
|
||||
* @nr: size of data
|
||||
*
|
||||
* Helper function to speed up n_tty_read. It is only called when
|
||||
* ICANON is off; it copies characters straight from the tty queue to
|
||||
* user space directly. It can be profitably called twice; once to
|
||||
* drain the space from the tail pointer to the (physical) end of the
|
||||
* buffer, and once to drain the space from the (physical) beginning of
|
||||
* the buffer to head pointer.
|
||||
* ICANON is off; it copies characters straight from the tty queue.
|
||||
*
|
||||
* Called under the ldata->atomic_read_lock sem
|
||||
*
|
||||
* Returns true if it successfully copied data, but there is still
|
||||
* more data to be had.
|
||||
*
|
||||
* n_tty_read()/consumer path:
|
||||
* caller holds non-exclusive termios_rwsem
|
||||
* read_tail published
|
||||
*/
|
||||
|
||||
static int copy_from_read_buf(struct tty_struct *tty,
|
||||
unsigned char __user **b,
|
||||
static bool copy_from_read_buf(struct tty_struct *tty,
|
||||
unsigned char **kbp,
|
||||
size_t *nr)
|
||||
|
||||
{
|
||||
struct n_tty_data *ldata = tty->disc_data;
|
||||
int retval;
|
||||
size_t n;
|
||||
bool is_eof;
|
||||
size_t head = smp_load_acquire(&ldata->commit_head);
|
||||
size_t tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
|
||||
|
||||
retval = 0;
|
||||
n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail);
|
||||
n = min(*nr, n);
|
||||
if (n) {
|
||||
unsigned char *from = read_buf_addr(ldata, tail);
|
||||
retval = copy_to_user(*b, from, n);
|
||||
n -= retval;
|
||||
memcpy(*kbp, from, n);
|
||||
is_eof = n == 1 && *from == EOF_CHAR(tty);
|
||||
tty_audit_add_data(tty, from, n);
|
||||
zero_buffer(tty, from, n);
|
||||
@ -1987,22 +1980,25 @@ static int copy_from_read_buf(struct tty_struct *tty,
|
||||
/* Turn single EOF into zero-length read */
|
||||
if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
|
||||
(head == ldata->read_tail))
|
||||
n = 0;
|
||||
*b += n;
|
||||
return false;
|
||||
*kbp += n;
|
||||
*nr -= n;
|
||||
|
||||
/* If we have more to copy, let the caller know */
|
||||
return head != ldata->read_tail;
|
||||
}
|
||||
return retval;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* canon_copy_from_read_buf - copy read data in canonical mode
|
||||
* @tty: terminal device
|
||||
* @b: user data
|
||||
* @kbp: data
|
||||
* @nr: size of data
|
||||
*
|
||||
* Helper function for n_tty_read. It is only called when ICANON is on;
|
||||
* it copies one line of input up to and including the line-delimiting
|
||||
* character into the user-space buffer.
|
||||
* character into the result buffer.
|
||||
*
|
||||
* NB: When termios is changed from non-canonical to canonical mode and
|
||||
* the read buffer contains data, n_tty_set_termios() simulates an EOF
|
||||
@ -2017,21 +2013,22 @@ static int copy_from_read_buf(struct tty_struct *tty,
|
||||
* read_tail published
|
||||
*/
|
||||
|
||||
static int canon_copy_from_read_buf(struct tty_struct *tty,
|
||||
unsigned char __user **b,
|
||||
size_t *nr)
|
||||
static bool canon_copy_from_read_buf(struct tty_struct *tty,
|
||||
unsigned char **kbp,
|
||||
size_t *nr)
|
||||
{
|
||||
struct n_tty_data *ldata = tty->disc_data;
|
||||
size_t n, size, more, c;
|
||||
size_t eol;
|
||||
size_t tail;
|
||||
int ret, found = 0;
|
||||
size_t tail, canon_head;
|
||||
int found = 0;
|
||||
|
||||
/* N.B. avoid overrun if nr == 0 */
|
||||
if (!*nr)
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
n = min(*nr + 1, smp_load_acquire(&ldata->canon_head) - ldata->read_tail);
|
||||
canon_head = smp_load_acquire(&ldata->canon_head);
|
||||
n = min(*nr + 1, canon_head - ldata->read_tail);
|
||||
|
||||
tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
|
||||
size = min_t(size_t, tail + n, N_TTY_BUF_SIZE);
|
||||
@ -2061,10 +2058,8 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
|
||||
n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu tail:%zu more:%zu\n",
|
||||
__func__, eol, found, n, c, tail, more);
|
||||
|
||||
ret = tty_copy_to_user(tty, *b, tail, n);
|
||||
if (ret)
|
||||
return -EFAULT;
|
||||
*b += n;
|
||||
tty_copy(tty, *kbp, tail, n);
|
||||
*kbp += n;
|
||||
*nr -= n;
|
||||
|
||||
if (found)
|
||||
@ -2077,8 +2072,11 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
|
||||
else
|
||||
ldata->push = 0;
|
||||
tty_audit_push();
|
||||
return false;
|
||||
}
|
||||
return 0;
|
||||
|
||||
/* No EOL found - do a continuation retry if there is more data */
|
||||
return ldata->read_tail != canon_head;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2129,10 +2127,11 @@ static int job_control(struct tty_struct *tty, struct file *file)
|
||||
*/
|
||||
|
||||
static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
||||
unsigned char __user *buf, size_t nr)
|
||||
unsigned char *kbuf, size_t nr,
|
||||
void **cookie, unsigned long offset)
|
||||
{
|
||||
struct n_tty_data *ldata = tty->disc_data;
|
||||
unsigned char __user *b = buf;
|
||||
unsigned char *kb = kbuf;
|
||||
DEFINE_WAIT_FUNC(wait, woken_wake_function);
|
||||
int c;
|
||||
int minimum, time;
|
||||
@ -2141,6 +2140,30 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
||||
int packet;
|
||||
size_t 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 (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;
|
||||
}
|
||||
|
||||
c = job_control(tty, file);
|
||||
if (c < 0)
|
||||
return c;
|
||||
@ -2178,17 +2201,13 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
||||
/* First test for status change. */
|
||||
if (packet && tty->link->ctrl_status) {
|
||||
unsigned char cs;
|
||||
if (b != buf)
|
||||
if (kb != kbuf)
|
||||
break;
|
||||
spin_lock_irq(&tty->link->ctrl_lock);
|
||||
cs = tty->link->ctrl_status;
|
||||
tty->link->ctrl_status = 0;
|
||||
spin_unlock_irq(&tty->link->ctrl_lock);
|
||||
if (put_user(cs, b)) {
|
||||
retval = -EFAULT;
|
||||
break;
|
||||
}
|
||||
b++;
|
||||
*kb++ = cs;
|
||||
nr--;
|
||||
break;
|
||||
}
|
||||
@ -2231,33 +2250,35 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
||||
}
|
||||
|
||||
if (ldata->icanon && !L_EXTPROC(tty)) {
|
||||
retval = canon_copy_from_read_buf(tty, &b, &nr);
|
||||
if (retval)
|
||||
break;
|
||||
if (canon_copy_from_read_buf(tty, &kb, &nr))
|
||||
goto more_to_be_read;
|
||||
} else {
|
||||
int uncopied;
|
||||
|
||||
/* Deal with packet mode. */
|
||||
if (packet && b == buf) {
|
||||
if (put_user(TIOCPKT_DATA, b)) {
|
||||
retval = -EFAULT;
|
||||
break;
|
||||
}
|
||||
b++;
|
||||
if (packet && kb == kbuf) {
|
||||
*kb++ = TIOCPKT_DATA;
|
||||
nr--;
|
||||
}
|
||||
|
||||
uncopied = copy_from_read_buf(tty, &b, &nr);
|
||||
uncopied += copy_from_read_buf(tty, &b, &nr);
|
||||
if (uncopied) {
|
||||
retval = -EFAULT;
|
||||
break;
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
n_tty_check_unthrottle(tty);
|
||||
|
||||
if (b - buf >= minimum)
|
||||
if (kb - kbuf >= minimum)
|
||||
break;
|
||||
if (time)
|
||||
timeout = time;
|
||||
@ -2269,8 +2290,8 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
||||
remove_wait_queue(&tty->read_wait, &wait);
|
||||
mutex_unlock(&ldata->atomic_read_lock);
|
||||
|
||||
if (b - buf)
|
||||
retval = b - buf;
|
||||
if (kb - kbuf)
|
||||
retval = kb - kbuf;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -45,7 +45,6 @@ static DEFINE_MUTEX(devpts_mutex);
|
||||
|
||||
static void pty_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
BUG_ON(!tty);
|
||||
if (tty->driver->subtype == PTY_TYPE_MASTER)
|
||||
WARN_ON(tty->count > 1);
|
||||
else {
|
||||
@ -67,7 +66,8 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
|
||||
wake_up_interruptible(&tty->link->read_wait);
|
||||
wake_up_interruptible(&tty->link->write_wait);
|
||||
if (tty->driver->subtype == PTY_TYPE_MASTER) {
|
||||
set_bit(TTY_OTHER_CLOSED, &tty->flags);
|
||||
struct file *f;
|
||||
|
||||
#ifdef CONFIG_UNIX98_PTYS
|
||||
if (tty->driver == ptm_driver) {
|
||||
mutex_lock(&devpts_mutex);
|
||||
@ -76,7 +76,17 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
|
||||
mutex_unlock(&devpts_mutex);
|
||||
}
|
||||
#endif
|
||||
tty_vhangup(tty->link);
|
||||
|
||||
/*
|
||||
* This hack is required because a program can open a
|
||||
* pty and redirect a console to it, but if the pty is
|
||||
* closed and the console is not released, then the
|
||||
* slave side will never close. So release the
|
||||
* redirect when the master closes.
|
||||
*/
|
||||
f = tty_release_redirect(tty->link);
|
||||
if (f)
|
||||
fput(f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,16 +26,17 @@ static void tegra_uart_handle_break(struct uart_port *p)
|
||||
{
|
||||
unsigned int status, tmout = 10000;
|
||||
|
||||
do {
|
||||
while (1) {
|
||||
status = p->serial_in(p, UART_LSR);
|
||||
if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
|
||||
status = p->serial_in(p, UART_RX);
|
||||
else
|
||||
if (!(status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)))
|
||||
break;
|
||||
|
||||
p->serial_in(p, UART_RX);
|
||||
|
||||
if (--tmout == 0)
|
||||
break;
|
||||
udelay(1);
|
||||
} while (1);
|
||||
}
|
||||
}
|
||||
|
||||
static int tegra_uart_probe(struct platform_device *pdev)
|
||||
|
@ -276,28 +276,6 @@ config SERIAL_SAMSUNG_CONSOLE
|
||||
your boot loader about how to pass options to the kernel at
|
||||
boot time.)
|
||||
|
||||
config SERIAL_SIRFSOC
|
||||
tristate "SiRF SoC Platform Serial port support"
|
||||
depends on ARCH_SIRF
|
||||
select SERIAL_CORE
|
||||
help
|
||||
Support for the on-chip UART on the CSR SiRFprimaII series,
|
||||
providing /dev/ttySiRF0, 1 and 2 (note, some machines may not
|
||||
provide all of these ports, depending on how the serial port
|
||||
pins are configured).
|
||||
|
||||
config SERIAL_SIRFSOC_CONSOLE
|
||||
bool "Support for console on SiRF SoC serial port"
|
||||
depends on SERIAL_SIRFSOC=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
help
|
||||
Even if you say Y here, the currently visible virtual console
|
||||
(/dev/tty0) will still be used as the system console by default, but
|
||||
you can alter that using a kernel command line option such as
|
||||
"console=ttySiRFx". (Try "man bootparam" or see the documentation of
|
||||
your boot loader about how to pass options to the kernel at
|
||||
boot time.)
|
||||
|
||||
config SERIAL_TEGRA
|
||||
tristate "NVIDIA Tegra20/30 SoC serial controller"
|
||||
depends on ARCH_TEGRA && TEGRA20_APB_DMA
|
||||
@ -1204,13 +1182,6 @@ config SERIAL_ALTERA_UART_CONSOLE
|
||||
help
|
||||
Enable a Altera UART port to be the system console.
|
||||
|
||||
config SERIAL_IFX6X60
|
||||
tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)"
|
||||
depends on GPIOLIB || COMPILE_TEST
|
||||
depends on SPI && HAS_DMA
|
||||
help
|
||||
Support for the IFX6x60 modem devices on Intel MID platforms.
|
||||
|
||||
config SERIAL_PCH_UART
|
||||
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART"
|
||||
depends on PCI && (X86_32 || MIPS || COMPILE_TEST)
|
||||
@ -1295,14 +1266,6 @@ config SERIAL_AR933X_NR_UARTS
|
||||
Set this to the number of serial ports you want the driver
|
||||
to support.
|
||||
|
||||
config SERIAL_EFM32_UART
|
||||
tristate "EFM32 UART/USART port"
|
||||
depends on ARM && (ARCH_EFM32 || COMPILE_TEST)
|
||||
select SERIAL_CORE
|
||||
help
|
||||
This driver support the USART and UART ports on
|
||||
Energy Micro's efm32 SoCs.
|
||||
|
||||
config SERIAL_MPS2_UART_CONSOLE
|
||||
bool "MPS2 UART console support"
|
||||
depends on SERIAL_MPS2_UART
|
||||
@ -1316,11 +1279,6 @@ config SERIAL_MPS2_UART
|
||||
help
|
||||
This driver support the UART ports on ARM MPS2.
|
||||
|
||||
config SERIAL_EFM32_UART_CONSOLE
|
||||
bool "EFM32 UART/USART console support"
|
||||
depends on SERIAL_EFM32_UART=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
|
||||
config SERIAL_ARC
|
||||
tristate "ARC UART driver support"
|
||||
select SERIAL_CORE
|
||||
|
@ -64,16 +64,13 @@ obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
|
||||
obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
|
||||
obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
|
||||
obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
|
||||
obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o
|
||||
obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o
|
||||
obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o
|
||||
obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o
|
||||
obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
|
||||
obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
|
||||
obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o
|
||||
obj-$(CONFIG_SERIAL_TEGRA_TCU) += tegra-tcu.o
|
||||
obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o
|
||||
obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
|
||||
obj-$(CONFIG_SERIAL_ARC) += arc_uart.o
|
||||
obj-$(CONFIG_SERIAL_RP2) += rp2.o
|
||||
obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o
|
||||
|
@ -499,8 +499,7 @@ static void cpm_uart_set_termios(struct uart_port *port,
|
||||
pr_debug("CPM uart[%d]:set_termios\n", port->line);
|
||||
|
||||
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
|
||||
if (baud < HW_BUF_SPD_THRESHOLD ||
|
||||
(pinfo->port.state && pinfo->port.state->port.low_latency))
|
||||
if (baud < HW_BUF_SPD_THRESHOLD || port->flags & UPF_LOW_LATENCY)
|
||||
pinfo->rx_fifosize = 1;
|
||||
else
|
||||
pinfo->rx_fifosize = RX_BUF_SIZE;
|
||||
@ -1107,6 +1106,32 @@ static void cpm_put_poll_char(struct uart_port *port,
|
||||
ch[0] = (char)c;
|
||||
cpm_uart_early_write(pinfo, ch, 1, false);
|
||||
}
|
||||
|
||||
static struct uart_port *udbg_port;
|
||||
|
||||
static void udbg_cpm_putc(char c)
|
||||
{
|
||||
if (c == '\n')
|
||||
cpm_put_poll_char(udbg_port, '\r');
|
||||
cpm_put_poll_char(udbg_port, c);
|
||||
}
|
||||
|
||||
static int udbg_cpm_getc_poll(void)
|
||||
{
|
||||
int c = cpm_get_poll_char(udbg_port);
|
||||
|
||||
return c == NO_POLL_CHAR ? -1 : c;
|
||||
}
|
||||
|
||||
static int udbg_cpm_getc(void)
|
||||
{
|
||||
int c;
|
||||
|
||||
while ((c = udbg_cpm_getc_poll()) == -1)
|
||||
cpu_relax();
|
||||
return c;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_CONSOLE_POLL */
|
||||
|
||||
static const struct uart_ops cpm_uart_pops = {
|
||||
@ -1237,7 +1262,10 @@ static int cpm_uart_init_port(struct device_node *np,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
|
||||
udbg_putc = NULL;
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
if (!udbg_port)
|
||||
#endif
|
||||
udbg_putc = NULL;
|
||||
#endif
|
||||
|
||||
return cpm_uart_request_port(&pinfo->port);
|
||||
@ -1358,6 +1386,15 @@ static int __init cpm_uart_console_setup(struct console *co, char *options)
|
||||
uart_set_options(port, co, baud, parity, bits, flow);
|
||||
cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX);
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
if (!udbg_port) {
|
||||
udbg_port = &pinfo->port;
|
||||
udbg_putc = udbg_cpm_putc;
|
||||
udbg_getc = udbg_cpm_getc;
|
||||
udbg_getc_poll = udbg_cpm_getc_poll;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,852 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <linux/platform_data/efm32-uart.h>
|
||||
|
||||
#define DRIVER_NAME "efm32-uart"
|
||||
#define DEV_NAME "ttyefm"
|
||||
|
||||
#define UARTn_CTRL 0x00
|
||||
#define UARTn_CTRL_SYNC 0x0001
|
||||
#define UARTn_CTRL_TXBIL 0x1000
|
||||
|
||||
#define UARTn_FRAME 0x04
|
||||
#define UARTn_FRAME_DATABITS__MASK 0x000f
|
||||
#define UARTn_FRAME_DATABITS(n) ((n) - 3)
|
||||
#define UARTn_FRAME_PARITY__MASK 0x0300
|
||||
#define UARTn_FRAME_PARITY_NONE 0x0000
|
||||
#define UARTn_FRAME_PARITY_EVEN 0x0200
|
||||
#define UARTn_FRAME_PARITY_ODD 0x0300
|
||||
#define UARTn_FRAME_STOPBITS_HALF 0x0000
|
||||
#define UARTn_FRAME_STOPBITS_ONE 0x1000
|
||||
#define UARTn_FRAME_STOPBITS_TWO 0x3000
|
||||
|
||||
#define UARTn_CMD 0x0c
|
||||
#define UARTn_CMD_RXEN 0x0001
|
||||
#define UARTn_CMD_RXDIS 0x0002
|
||||
#define UARTn_CMD_TXEN 0x0004
|
||||
#define UARTn_CMD_TXDIS 0x0008
|
||||
|
||||
#define UARTn_STATUS 0x10
|
||||
#define UARTn_STATUS_TXENS 0x0002
|
||||
#define UARTn_STATUS_TXC 0x0020
|
||||
#define UARTn_STATUS_TXBL 0x0040
|
||||
#define UARTn_STATUS_RXDATAV 0x0080
|
||||
|
||||
#define UARTn_CLKDIV 0x14
|
||||
|
||||
#define UARTn_RXDATAX 0x18
|
||||
#define UARTn_RXDATAX_RXDATA__MASK 0x01ff
|
||||
#define UARTn_RXDATAX_PERR 0x4000
|
||||
#define UARTn_RXDATAX_FERR 0x8000
|
||||
/*
|
||||
* This is a software only flag used for ignore_status_mask and
|
||||
* read_status_mask! It's used for breaks that the hardware doesn't report
|
||||
* explicitly.
|
||||
*/
|
||||
#define SW_UARTn_RXDATAX_BERR 0x2000
|
||||
|
||||
#define UARTn_TXDATA 0x34
|
||||
|
||||
#define UARTn_IF 0x40
|
||||
#define UARTn_IF_TXC 0x0001
|
||||
#define UARTn_IF_TXBL 0x0002
|
||||
#define UARTn_IF_RXDATAV 0x0004
|
||||
#define UARTn_IF_RXOF 0x0010
|
||||
|
||||
#define UARTn_IFS 0x44
|
||||
#define UARTn_IFC 0x48
|
||||
#define UARTn_IEN 0x4c
|
||||
|
||||
#define UARTn_ROUTE 0x54
|
||||
#define UARTn_ROUTE_LOCATION__MASK 0x0700
|
||||
#define UARTn_ROUTE_LOCATION(n) (((n) << 8) & UARTn_ROUTE_LOCATION__MASK)
|
||||
#define UARTn_ROUTE_RXPEN 0x0001
|
||||
#define UARTn_ROUTE_TXPEN 0x0002
|
||||
|
||||
struct efm32_uart_port {
|
||||
struct uart_port port;
|
||||
unsigned int txirq;
|
||||
struct clk *clk;
|
||||
struct efm32_uart_pdata pdata;
|
||||
};
|
||||
#define to_efm_port(_port) container_of(_port, struct efm32_uart_port, port)
|
||||
#define efm_debug(efm_port, format, arg...) \
|
||||
dev_dbg(efm_port->port.dev, format, ##arg)
|
||||
|
||||
static void efm32_uart_write32(struct efm32_uart_port *efm_port,
|
||||
u32 value, unsigned offset)
|
||||
{
|
||||
writel_relaxed(value, efm_port->port.membase + offset);
|
||||
}
|
||||
|
||||
static u32 efm32_uart_read32(struct efm32_uart_port *efm_port,
|
||||
unsigned offset)
|
||||
{
|
||||
return readl_relaxed(efm_port->port.membase + offset);
|
||||
}
|
||||
|
||||
static unsigned int efm32_uart_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
|
||||
|
||||
if (status & UARTn_STATUS_TXC)
|
||||
return TIOCSER_TEMT;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void efm32_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
/* sorry, neither handshaking lines nor loop functionallity */
|
||||
}
|
||||
|
||||
static unsigned int efm32_uart_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
/* sorry, no handshaking lines available */
|
||||
return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR;
|
||||
}
|
||||
|
||||
static void efm32_uart_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
u32 ien = efm32_uart_read32(efm_port, UARTn_IEN);
|
||||
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD);
|
||||
ien &= ~(UARTn_IF_TXC | UARTn_IF_TXBL);
|
||||
efm32_uart_write32(efm_port, ien, UARTn_IEN);
|
||||
}
|
||||
|
||||
static void efm32_uart_tx_chars(struct efm32_uart_port *efm_port)
|
||||
{
|
||||
struct uart_port *port = &efm_port->port;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
|
||||
while (efm32_uart_read32(efm_port, UARTn_STATUS) &
|
||||
UARTn_STATUS_TXBL) {
|
||||
if (port->x_char) {
|
||||
port->icount.tx++;
|
||||
efm32_uart_write32(efm_port, port->x_char,
|
||||
UARTn_TXDATA);
|
||||
port->x_char = 0;
|
||||
continue;
|
||||
}
|
||||
if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
|
||||
port->icount.tx++;
|
||||
efm32_uart_write32(efm_port, xmit->buf[xmit->tail],
|
||||
UARTn_TXDATA);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (!port->x_char && uart_circ_empty(xmit) &&
|
||||
efm32_uart_read32(efm_port, UARTn_STATUS) &
|
||||
UARTn_STATUS_TXC)
|
||||
efm32_uart_stop_tx(port);
|
||||
}
|
||||
|
||||
static void efm32_uart_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
u32 ien;
|
||||
|
||||
efm32_uart_write32(efm_port,
|
||||
UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IFC);
|
||||
ien = efm32_uart_read32(efm_port, UARTn_IEN);
|
||||
efm32_uart_write32(efm_port,
|
||||
ien | UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IEN);
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD);
|
||||
|
||||
efm32_uart_tx_chars(efm_port);
|
||||
}
|
||||
|
||||
static void efm32_uart_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_RXDIS, UARTn_CMD);
|
||||
}
|
||||
|
||||
static void efm32_uart_break_ctl(struct uart_port *port, int ctl)
|
||||
{
|
||||
/* not possible without fiddling with gpios */
|
||||
}
|
||||
|
||||
static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port)
|
||||
{
|
||||
struct uart_port *port = &efm_port->port;
|
||||
|
||||
while (efm32_uart_read32(efm_port, UARTn_STATUS) &
|
||||
UARTn_STATUS_RXDATAV) {
|
||||
u32 rxdata = efm32_uart_read32(efm_port, UARTn_RXDATAX);
|
||||
int flag = 0;
|
||||
|
||||
/*
|
||||
* This is a reserved bit and I only saw it read as 0. But to be
|
||||
* sure not to be confused too much by new devices adhere to the
|
||||
* warning in the reference manual that reserved bits might
|
||||
* read as 1 in the future.
|
||||
*/
|
||||
rxdata &= ~SW_UARTn_RXDATAX_BERR;
|
||||
|
||||
port->icount.rx++;
|
||||
|
||||
if ((rxdata & UARTn_RXDATAX_FERR) &&
|
||||
!(rxdata & UARTn_RXDATAX_RXDATA__MASK)) {
|
||||
rxdata |= SW_UARTn_RXDATAX_BERR;
|
||||
port->icount.brk++;
|
||||
if (uart_handle_break(port))
|
||||
continue;
|
||||
} else if (rxdata & UARTn_RXDATAX_PERR)
|
||||
port->icount.parity++;
|
||||
else if (rxdata & UARTn_RXDATAX_FERR)
|
||||
port->icount.frame++;
|
||||
|
||||
rxdata &= port->read_status_mask;
|
||||
|
||||
if (rxdata & SW_UARTn_RXDATAX_BERR)
|
||||
flag = TTY_BREAK;
|
||||
else if (rxdata & UARTn_RXDATAX_PERR)
|
||||
flag = TTY_PARITY;
|
||||
else if (rxdata & UARTn_RXDATAX_FERR)
|
||||
flag = TTY_FRAME;
|
||||
else if (uart_handle_sysrq_char(port,
|
||||
rxdata & UARTn_RXDATAX_RXDATA__MASK))
|
||||
continue;
|
||||
|
||||
if ((rxdata & port->ignore_status_mask) == 0)
|
||||
tty_insert_flip_char(&port->state->port,
|
||||
rxdata & UARTn_RXDATAX_RXDATA__MASK, flag);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t efm32_uart_rxirq(int irq, void *data)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = data;
|
||||
u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF);
|
||||
int handled = IRQ_NONE;
|
||||
struct uart_port *port = &efm_port->port;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
||||
spin_lock(&port->lock);
|
||||
|
||||
if (irqflag & UARTn_IF_RXDATAV) {
|
||||
efm32_uart_write32(efm_port, UARTn_IF_RXDATAV, UARTn_IFC);
|
||||
efm32_uart_rx_chars(efm_port);
|
||||
|
||||
handled = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (irqflag & UARTn_IF_RXOF) {
|
||||
efm32_uart_write32(efm_port, UARTn_IF_RXOF, UARTn_IFC);
|
||||
port->icount.overrun++;
|
||||
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
|
||||
|
||||
handled = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
spin_unlock(&port->lock);
|
||||
|
||||
tty_flip_buffer_push(tport);
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
static irqreturn_t efm32_uart_txirq(int irq, void *data)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = data;
|
||||
u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF);
|
||||
|
||||
/* TXBL doesn't need to be cleared */
|
||||
if (irqflag & UARTn_IF_TXC)
|
||||
efm32_uart_write32(efm_port, UARTn_IF_TXC, UARTn_IFC);
|
||||
|
||||
if (irqflag & (UARTn_IF_TXC | UARTn_IF_TXBL)) {
|
||||
efm32_uart_tx_chars(efm_port);
|
||||
return IRQ_HANDLED;
|
||||
} else
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static int efm32_uart_startup(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
int ret;
|
||||
|
||||
ret = clk_enable(efm_port->clk);
|
||||
if (ret) {
|
||||
efm_debug(efm_port, "failed to enable clk\n");
|
||||
goto err_clk_enable;
|
||||
}
|
||||
port->uartclk = clk_get_rate(efm_port->clk);
|
||||
|
||||
/* Enable pins at configured location */
|
||||
efm32_uart_write32(efm_port,
|
||||
UARTn_ROUTE_LOCATION(efm_port->pdata.location) |
|
||||
UARTn_ROUTE_RXPEN | UARTn_ROUTE_TXPEN,
|
||||
UARTn_ROUTE);
|
||||
|
||||
ret = request_irq(port->irq, efm32_uart_rxirq, 0,
|
||||
DRIVER_NAME, efm_port);
|
||||
if (ret) {
|
||||
efm_debug(efm_port, "failed to register rxirq\n");
|
||||
goto err_request_irq_rx;
|
||||
}
|
||||
|
||||
/* disable all irqs */
|
||||
efm32_uart_write32(efm_port, 0, UARTn_IEN);
|
||||
|
||||
ret = request_irq(efm_port->txirq, efm32_uart_txirq, 0,
|
||||
DRIVER_NAME, efm_port);
|
||||
if (ret) {
|
||||
efm_debug(efm_port, "failed to register txirq\n");
|
||||
free_irq(port->irq, efm_port);
|
||||
err_request_irq_rx:
|
||||
|
||||
clk_disable(efm_port->clk);
|
||||
} else {
|
||||
efm32_uart_write32(efm_port,
|
||||
UARTn_IF_RXDATAV | UARTn_IF_RXOF, UARTn_IEN);
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_RXEN, UARTn_CMD);
|
||||
}
|
||||
|
||||
err_clk_enable:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void efm32_uart_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
|
||||
efm32_uart_write32(efm_port, 0, UARTn_IEN);
|
||||
free_irq(port->irq, efm_port);
|
||||
|
||||
clk_disable(efm_port->clk);
|
||||
}
|
||||
|
||||
static void efm32_uart_set_termios(struct uart_port *port,
|
||||
struct ktermios *new, struct ktermios *old)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
unsigned long flags;
|
||||
unsigned baud;
|
||||
u32 clkdiv;
|
||||
u32 frame = 0;
|
||||
|
||||
/* no modem control lines */
|
||||
new->c_cflag &= ~(CRTSCTS | CMSPAR);
|
||||
|
||||
baud = uart_get_baud_rate(port, new, old,
|
||||
DIV_ROUND_CLOSEST(port->uartclk, 16 * 8192),
|
||||
DIV_ROUND_CLOSEST(port->uartclk, 16));
|
||||
|
||||
switch (new->c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
frame |= UARTn_FRAME_DATABITS(5);
|
||||
break;
|
||||
case CS6:
|
||||
frame |= UARTn_FRAME_DATABITS(6);
|
||||
break;
|
||||
case CS7:
|
||||
frame |= UARTn_FRAME_DATABITS(7);
|
||||
break;
|
||||
case CS8:
|
||||
frame |= UARTn_FRAME_DATABITS(8);
|
||||
break;
|
||||
}
|
||||
|
||||
if (new->c_cflag & CSTOPB)
|
||||
/* the receiver only verifies the first stop bit */
|
||||
frame |= UARTn_FRAME_STOPBITS_TWO;
|
||||
else
|
||||
frame |= UARTn_FRAME_STOPBITS_ONE;
|
||||
|
||||
if (new->c_cflag & PARENB) {
|
||||
if (new->c_cflag & PARODD)
|
||||
frame |= UARTn_FRAME_PARITY_ODD;
|
||||
else
|
||||
frame |= UARTn_FRAME_PARITY_EVEN;
|
||||
} else
|
||||
frame |= UARTn_FRAME_PARITY_NONE;
|
||||
|
||||
/*
|
||||
* the 6 lowest bits of CLKDIV are dc, bit 6 has value 0.25.
|
||||
* port->uartclk <= 14e6, so 4 * port->uartclk doesn't overflow.
|
||||
*/
|
||||
clkdiv = (DIV_ROUND_CLOSEST(4 * port->uartclk, 16 * baud) - 4) << 6;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
efm32_uart_write32(efm_port,
|
||||
UARTn_CMD_TXDIS | UARTn_CMD_RXDIS, UARTn_CMD);
|
||||
|
||||
port->read_status_mask = UARTn_RXDATAX_RXDATA__MASK;
|
||||
if (new->c_iflag & INPCK)
|
||||
port->read_status_mask |=
|
||||
UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR;
|
||||
if (new->c_iflag & (IGNBRK | BRKINT | PARMRK))
|
||||
port->read_status_mask |= SW_UARTn_RXDATAX_BERR;
|
||||
|
||||
port->ignore_status_mask = 0;
|
||||
if (new->c_iflag & IGNPAR)
|
||||
port->ignore_status_mask |=
|
||||
UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR;
|
||||
if (new->c_iflag & IGNBRK)
|
||||
port->ignore_status_mask |= SW_UARTn_RXDATAX_BERR;
|
||||
|
||||
uart_update_timeout(port, new->c_cflag, baud);
|
||||
|
||||
efm32_uart_write32(efm_port, UARTn_CTRL_TXBIL, UARTn_CTRL);
|
||||
efm32_uart_write32(efm_port, frame, UARTn_FRAME);
|
||||
efm32_uart_write32(efm_port, clkdiv, UARTn_CLKDIV);
|
||||
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_TXEN | UARTn_CMD_RXEN,
|
||||
UARTn_CMD);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static const char *efm32_uart_type(struct uart_port *port)
|
||||
{
|
||||
return port->type == PORT_EFMUART ? "efm32-uart" : NULL;
|
||||
}
|
||||
|
||||
static void efm32_uart_release_port(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
|
||||
clk_unprepare(efm_port->clk);
|
||||
clk_put(efm_port->clk);
|
||||
iounmap(port->membase);
|
||||
}
|
||||
|
||||
static int efm32_uart_request_port(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
int ret;
|
||||
|
||||
port->membase = ioremap(port->mapbase, 60);
|
||||
if (!efm_port->port.membase) {
|
||||
ret = -ENOMEM;
|
||||
efm_debug(efm_port, "failed to remap\n");
|
||||
goto err_ioremap;
|
||||
}
|
||||
|
||||
efm_port->clk = clk_get(port->dev, NULL);
|
||||
if (IS_ERR(efm_port->clk)) {
|
||||
ret = PTR_ERR(efm_port->clk);
|
||||
efm_debug(efm_port, "failed to get clock\n");
|
||||
goto err_clk_get;
|
||||
}
|
||||
|
||||
ret = clk_prepare(efm_port->clk);
|
||||
if (ret) {
|
||||
clk_put(efm_port->clk);
|
||||
err_clk_get:
|
||||
|
||||
iounmap(port->membase);
|
||||
err_ioremap:
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void efm32_uart_config_port(struct uart_port *port, int type)
|
||||
{
|
||||
if (type & UART_CONFIG_TYPE &&
|
||||
!efm32_uart_request_port(port))
|
||||
port->type = PORT_EFMUART;
|
||||
}
|
||||
|
||||
static int efm32_uart_verify_port(struct uart_port *port,
|
||||
struct serial_struct *serinfo)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (serinfo->type != PORT_UNKNOWN && serinfo->type != PORT_EFMUART)
|
||||
ret = -EINVAL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct uart_ops efm32_uart_pops = {
|
||||
.tx_empty = efm32_uart_tx_empty,
|
||||
.set_mctrl = efm32_uart_set_mctrl,
|
||||
.get_mctrl = efm32_uart_get_mctrl,
|
||||
.stop_tx = efm32_uart_stop_tx,
|
||||
.start_tx = efm32_uart_start_tx,
|
||||
.stop_rx = efm32_uart_stop_rx,
|
||||
.break_ctl = efm32_uart_break_ctl,
|
||||
.startup = efm32_uart_startup,
|
||||
.shutdown = efm32_uart_shutdown,
|
||||
.set_termios = efm32_uart_set_termios,
|
||||
.type = efm32_uart_type,
|
||||
.release_port = efm32_uart_release_port,
|
||||
.request_port = efm32_uart_request_port,
|
||||
.config_port = efm32_uart_config_port,
|
||||
.verify_port = efm32_uart_verify_port,
|
||||
};
|
||||
|
||||
static struct efm32_uart_port *efm32_uart_ports[5];
|
||||
|
||||
#ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE
|
||||
static void efm32_uart_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
unsigned int timeout = 0x400;
|
||||
u32 status;
|
||||
|
||||
while (1) {
|
||||
status = efm32_uart_read32(efm_port, UARTn_STATUS);
|
||||
|
||||
if (status & UARTn_STATUS_TXBL)
|
||||
break;
|
||||
if (!timeout--)
|
||||
return;
|
||||
}
|
||||
efm32_uart_write32(efm_port, ch, UARTn_TXDATA);
|
||||
}
|
||||
|
||||
static void efm32_uart_console_write(struct console *co, const char *s,
|
||||
unsigned int count)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = efm32_uart_ports[co->index];
|
||||
u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
|
||||
unsigned int timeout = 0x400;
|
||||
|
||||
if (!(status & UARTn_STATUS_TXENS))
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD);
|
||||
|
||||
uart_console_write(&efm_port->port, s, count,
|
||||
efm32_uart_console_putchar);
|
||||
|
||||
/* Wait for the transmitter to become empty */
|
||||
while (1) {
|
||||
u32 status = efm32_uart_read32(efm_port, UARTn_STATUS);
|
||||
if (status & UARTn_STATUS_TXC)
|
||||
break;
|
||||
if (!timeout--)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(status & UARTn_STATUS_TXENS))
|
||||
efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD);
|
||||
}
|
||||
|
||||
static void efm32_uart_console_get_options(struct efm32_uart_port *efm_port,
|
||||
int *baud, int *parity, int *bits)
|
||||
{
|
||||
u32 ctrl = efm32_uart_read32(efm_port, UARTn_CTRL);
|
||||
u32 route, clkdiv, frame;
|
||||
|
||||
if (ctrl & UARTn_CTRL_SYNC)
|
||||
/* not operating in async mode */
|
||||
return;
|
||||
|
||||
route = efm32_uart_read32(efm_port, UARTn_ROUTE);
|
||||
if (!(route & UARTn_ROUTE_TXPEN))
|
||||
/* tx pin not routed */
|
||||
return;
|
||||
|
||||
clkdiv = efm32_uart_read32(efm_port, UARTn_CLKDIV);
|
||||
|
||||
*baud = DIV_ROUND_CLOSEST(4 * efm_port->port.uartclk,
|
||||
16 * (4 + (clkdiv >> 6)));
|
||||
|
||||
frame = efm32_uart_read32(efm_port, UARTn_FRAME);
|
||||
switch (frame & UARTn_FRAME_PARITY__MASK) {
|
||||
case UARTn_FRAME_PARITY_ODD:
|
||||
*parity = 'o';
|
||||
break;
|
||||
case UARTn_FRAME_PARITY_EVEN:
|
||||
*parity = 'e';
|
||||
break;
|
||||
default:
|
||||
*parity = 'n';
|
||||
}
|
||||
|
||||
*bits = (frame & UARTn_FRAME_DATABITS__MASK) -
|
||||
UARTn_FRAME_DATABITS(4) + 4;
|
||||
|
||||
efm_debug(efm_port, "get_opts: options=%d%c%d\n",
|
||||
*baud, *parity, *bits);
|
||||
}
|
||||
|
||||
static int efm32_uart_console_setup(struct console *co, char *options)
|
||||
{
|
||||
struct efm32_uart_port *efm_port;
|
||||
int baud = 115200;
|
||||
int bits = 8;
|
||||
int parity = 'n';
|
||||
int flow = 'n';
|
||||
int ret;
|
||||
|
||||
if (co->index < 0 || co->index >= ARRAY_SIZE(efm32_uart_ports)) {
|
||||
unsigned i;
|
||||
for (i = 0; i < ARRAY_SIZE(efm32_uart_ports); ++i) {
|
||||
if (efm32_uart_ports[i]) {
|
||||
pr_warn("efm32-console: fall back to console index %u (from %hhi)\n",
|
||||
i, co->index);
|
||||
co->index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
efm_port = efm32_uart_ports[co->index];
|
||||
if (!efm_port) {
|
||||
pr_warn("efm32-console: No port at %d\n", co->index);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = clk_prepare(efm_port->clk);
|
||||
if (ret) {
|
||||
dev_warn(efm_port->port.dev,
|
||||
"console: clk_prepare failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
efm_port->port.uartclk = clk_get_rate(efm_port->clk);
|
||||
|
||||
if (options)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
else
|
||||
efm32_uart_console_get_options(efm_port,
|
||||
&baud, &parity, &bits);
|
||||
|
||||
return uart_set_options(&efm_port->port, co, baud, parity, bits, flow);
|
||||
}
|
||||
|
||||
static struct uart_driver efm32_uart_reg;
|
||||
|
||||
static struct console efm32_uart_console = {
|
||||
.name = DEV_NAME,
|
||||
.write = efm32_uart_console_write,
|
||||
.device = uart_console_device,
|
||||
.setup = efm32_uart_console_setup,
|
||||
.flags = CON_PRINTBUFFER,
|
||||
.index = -1,
|
||||
.data = &efm32_uart_reg,
|
||||
};
|
||||
|
||||
#else
|
||||
#define efm32_uart_console (*(struct console *)NULL)
|
||||
#endif /* ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE / else */
|
||||
|
||||
static struct uart_driver efm32_uart_reg = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = DRIVER_NAME,
|
||||
.dev_name = DEV_NAME,
|
||||
.nr = ARRAY_SIZE(efm32_uart_ports),
|
||||
.cons = &efm32_uart_console,
|
||||
};
|
||||
|
||||
static int efm32_uart_probe_dt(struct platform_device *pdev,
|
||||
struct efm32_uart_port *efm_port)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
u32 location;
|
||||
int ret;
|
||||
|
||||
if (!np)
|
||||
return 1;
|
||||
|
||||
ret = of_property_read_u32(np, "energymicro,location", &location);
|
||||
|
||||
if (ret)
|
||||
/* fall back to wrongly namespaced property */
|
||||
ret = of_property_read_u32(np, "efm32,location", &location);
|
||||
|
||||
if (ret)
|
||||
/* fall back to old and (wrongly) generic property "location" */
|
||||
ret = of_property_read_u32(np, "location", &location);
|
||||
|
||||
if (!ret) {
|
||||
if (location > 5) {
|
||||
dev_err(&pdev->dev, "invalid location\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
efm_debug(efm_port, "using location %u\n", location);
|
||||
efm_port->pdata.location = location;
|
||||
} else {
|
||||
efm_debug(efm_port, "fall back to location 0\n");
|
||||
}
|
||||
|
||||
ret = of_alias_get_id(np, "serial");
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to get alias id: %d\n", ret);
|
||||
return ret;
|
||||
} else {
|
||||
efm_port->port.line = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int efm32_uart_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct efm32_uart_port *efm_port;
|
||||
struct resource *res;
|
||||
unsigned int line;
|
||||
int ret;
|
||||
|
||||
efm_port = kzalloc(sizeof(*efm_port), GFP_KERNEL);
|
||||
if (!efm_port) {
|
||||
dev_dbg(&pdev->dev, "failed to allocate private data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENODEV;
|
||||
dev_dbg(&pdev->dev, "failed to determine base address\n");
|
||||
goto err_get_base;
|
||||
}
|
||||
|
||||
if (resource_size(res) < 60) {
|
||||
ret = -EINVAL;
|
||||
dev_dbg(&pdev->dev, "memory resource too small\n");
|
||||
goto err_too_small;
|
||||
}
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret <= 0) {
|
||||
dev_dbg(&pdev->dev, "failed to get rx irq\n");
|
||||
goto err_get_rxirq;
|
||||
}
|
||||
|
||||
efm_port->port.irq = ret;
|
||||
|
||||
ret = platform_get_irq(pdev, 1);
|
||||
if (ret <= 0)
|
||||
ret = efm_port->port.irq + 1;
|
||||
|
||||
efm_port->txirq = ret;
|
||||
|
||||
efm_port->port.dev = &pdev->dev;
|
||||
efm_port->port.mapbase = res->start;
|
||||
efm_port->port.type = PORT_EFMUART;
|
||||
efm_port->port.iotype = UPIO_MEM32;
|
||||
efm_port->port.fifosize = 2;
|
||||
efm_port->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_EFM32_UART_CONSOLE);
|
||||
efm_port->port.ops = &efm32_uart_pops;
|
||||
efm_port->port.flags = UPF_BOOT_AUTOCONF;
|
||||
|
||||
ret = efm32_uart_probe_dt(pdev, efm_port);
|
||||
if (ret > 0) {
|
||||
/* not created by device tree */
|
||||
const struct efm32_uart_pdata *pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
efm_port->port.line = pdev->id;
|
||||
|
||||
if (pdata)
|
||||
efm_port->pdata = *pdata;
|
||||
} else if (ret < 0)
|
||||
goto err_probe_dt;
|
||||
|
||||
line = efm_port->port.line;
|
||||
|
||||
if (line >= 0 && line < ARRAY_SIZE(efm32_uart_ports))
|
||||
efm32_uart_ports[line] = efm_port;
|
||||
|
||||
ret = uart_add_one_port(&efm32_uart_reg, &efm_port->port);
|
||||
if (ret) {
|
||||
dev_dbg(&pdev->dev, "failed to add port: %d\n", ret);
|
||||
|
||||
if (line >= 0 && line < ARRAY_SIZE(efm32_uart_ports))
|
||||
efm32_uart_ports[line] = NULL;
|
||||
err_probe_dt:
|
||||
err_get_rxirq:
|
||||
err_too_small:
|
||||
err_get_base:
|
||||
kfree(efm_port);
|
||||
} else {
|
||||
platform_set_drvdata(pdev, efm_port);
|
||||
dev_dbg(&pdev->dev, "\\o/\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int efm32_uart_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = platform_get_drvdata(pdev);
|
||||
unsigned int line = efm_port->port.line;
|
||||
|
||||
uart_remove_one_port(&efm32_uart_reg, &efm_port->port);
|
||||
|
||||
if (line >= 0 && line < ARRAY_SIZE(efm32_uart_ports))
|
||||
efm32_uart_ports[line] = NULL;
|
||||
|
||||
kfree(efm_port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id efm32_uart_dt_ids[] = {
|
||||
{
|
||||
.compatible = "energymicro,efm32-uart",
|
||||
}, {
|
||||
/* doesn't follow the "vendor,device" scheme, don't use */
|
||||
.compatible = "efm32,uart",
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, efm32_uart_dt_ids);
|
||||
|
||||
static struct platform_driver efm32_uart_driver = {
|
||||
.probe = efm32_uart_probe,
|
||||
.remove = efm32_uart_remove,
|
||||
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = efm32_uart_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init efm32_uart_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = uart_register_driver(&efm32_uart_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = platform_driver_register(&efm32_uart_driver);
|
||||
if (ret)
|
||||
uart_unregister_driver(&efm32_uart_reg);
|
||||
|
||||
pr_info("EFM32 UART/USART driver\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(efm32_uart_init);
|
||||
|
||||
static void __exit efm32_uart_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&efm32_uart_driver);
|
||||
uart_unregister_driver(&efm32_uart_reg);
|
||||
}
|
||||
module_exit(efm32_uart_exit);
|
||||
|
||||
MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
|
||||
MODULE_DESCRIPTION("EFM32 UART/USART driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:" DRIVER_NAME);
|
@ -2580,9 +2580,7 @@ static struct uart_driver lpuart_reg = {
|
||||
|
||||
static int lpuart_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *of_id = of_match_device(lpuart_dt_ids,
|
||||
&pdev->dev);
|
||||
const struct lpuart_soc_data *sdata = of_id->data;
|
||||
const struct lpuart_soc_data *sdata = of_device_get_match_data(&pdev->dev);
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct lpuart_port *sport;
|
||||
struct resource *res;
|
||||
|
@ -118,7 +118,7 @@ MODULE_DEVICE_TABLE(pci, icom_pci_table);
|
||||
static LIST_HEAD(icom_adapter_head);
|
||||
|
||||
/* spinlock for adapter initialization and changing adapter operations */
|
||||
static spinlock_t icom_lock;
|
||||
static DEFINE_SPINLOCK(icom_lock);
|
||||
|
||||
#ifdef ICOM_TRACE
|
||||
static inline void trace(struct icom_port *icom_port, char *trace_pt,
|
||||
@ -1616,8 +1616,6 @@ static int __init icom_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
spin_lock_init(&icom_lock);
|
||||
|
||||
ret = uart_register_driver(&icom_uart_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,118 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/****************************************************************************
|
||||
*
|
||||
* Driver for the IFX spi modem.
|
||||
*
|
||||
* Copyright (C) 2009, 2010 Intel Corp
|
||||
* Jim Stanley <jim.stanley@intel.com>
|
||||
*
|
||||
*****************************************************************************/
|
||||
#ifndef _IFX6X60_H
|
||||
#define _IFX6X60_H
|
||||
|
||||
struct gpio_desc;
|
||||
|
||||
#define DRVNAME "ifx6x60"
|
||||
#define TTYNAME "ttyIFX"
|
||||
|
||||
#define IFX_SPI_MAX_MINORS 1
|
||||
#define IFX_SPI_TRANSFER_SIZE 2048
|
||||
#define IFX_SPI_FIFO_SIZE 4096
|
||||
|
||||
#define IFX_SPI_HEADER_OVERHEAD 4
|
||||
#define IFX_RESET_TIMEOUT msecs_to_jiffies(50)
|
||||
|
||||
/* device flags bitfield definitions */
|
||||
#define IFX_SPI_STATE_PRESENT 0
|
||||
#define IFX_SPI_STATE_IO_IN_PROGRESS 1
|
||||
#define IFX_SPI_STATE_IO_READY 2
|
||||
#define IFX_SPI_STATE_TIMER_PENDING 3
|
||||
#define IFX_SPI_STATE_IO_AVAILABLE 4
|
||||
|
||||
/* flow control bitfields */
|
||||
#define IFX_SPI_DCD 0
|
||||
#define IFX_SPI_CTS 1
|
||||
#define IFX_SPI_DSR 2
|
||||
#define IFX_SPI_RI 3
|
||||
#define IFX_SPI_DTR 4
|
||||
#define IFX_SPI_RTS 5
|
||||
#define IFX_SPI_TX_FC 6
|
||||
#define IFX_SPI_RX_FC 7
|
||||
#define IFX_SPI_UPDATE 8
|
||||
|
||||
#define IFX_SPI_PAYLOAD_SIZE (IFX_SPI_TRANSFER_SIZE - \
|
||||
IFX_SPI_HEADER_OVERHEAD)
|
||||
|
||||
#define IFX_SPI_IRQ_TYPE DETECT_EDGE_RISING
|
||||
#define IFX_SPI_GPIO_TARGET 0
|
||||
#define IFX_SPI_GPIO0 0x105
|
||||
|
||||
#define IFX_SPI_STATUS_TIMEOUT (2000*HZ)
|
||||
|
||||
/* values for bits in power status byte */
|
||||
#define IFX_SPI_POWER_DATA_PENDING 1
|
||||
#define IFX_SPI_POWER_SRDY 2
|
||||
|
||||
struct ifx_spi_device {
|
||||
/* Our SPI device */
|
||||
struct spi_device *spi_dev;
|
||||
|
||||
/* Port specific data */
|
||||
struct kfifo tx_fifo;
|
||||
spinlock_t fifo_lock;
|
||||
unsigned long signal_state;
|
||||
|
||||
/* TTY Layer logic */
|
||||
struct tty_port tty_port;
|
||||
struct device *tty_dev;
|
||||
int minor;
|
||||
|
||||
/* Low level I/O work */
|
||||
struct tasklet_struct io_work_tasklet;
|
||||
unsigned long flags;
|
||||
dma_addr_t rx_dma;
|
||||
dma_addr_t tx_dma;
|
||||
|
||||
int modem; /* Modem type */
|
||||
int use_dma; /* provide dma-able addrs in SPI msg */
|
||||
long max_hz; /* max SPI frequency */
|
||||
|
||||
spinlock_t write_lock;
|
||||
int write_pending;
|
||||
spinlock_t power_lock;
|
||||
unsigned char power_status;
|
||||
|
||||
unsigned char *rx_buffer;
|
||||
unsigned char *tx_buffer;
|
||||
dma_addr_t rx_bus;
|
||||
dma_addr_t tx_bus;
|
||||
unsigned char spi_more;
|
||||
unsigned char spi_slave_cts;
|
||||
|
||||
struct timer_list spi_timer;
|
||||
|
||||
struct spi_message spi_msg;
|
||||
struct spi_transfer spi_xfer;
|
||||
|
||||
struct {
|
||||
/* gpio lines */
|
||||
struct gpio_desc *srdy; /* slave-ready gpio */
|
||||
struct gpio_desc *mrdy; /* master-ready gpio */
|
||||
struct gpio_desc *reset; /* modem-reset gpio */
|
||||
struct gpio_desc *po; /* modem-on gpio */
|
||||
struct gpio_desc *reset_out; /* modem-in-reset gpio */
|
||||
struct gpio_desc *pmu_reset; /* PMU reset gpio */
|
||||
/* state/stats */
|
||||
int unack_srdy_int_nb;
|
||||
} gpio;
|
||||
|
||||
/* modem reset */
|
||||
unsigned long mdm_reset_state;
|
||||
#define MR_START 0
|
||||
#define MR_INPROGRESS 1
|
||||
#define MR_COMPLETE 2
|
||||
wait_queue_head_t mdm_reset_wait;
|
||||
void (*swap_buf)(unsigned char *buf, int len, void *end);
|
||||
};
|
||||
|
||||
#endif /* _IFX6X60_H */
|
@ -2248,7 +2248,7 @@ static int imx_uart_probe(struct platform_device *pdev)
|
||||
sport->port.dev = &pdev->dev;
|
||||
sport->port.mapbase = res->start;
|
||||
sport->port.membase = base;
|
||||
sport->port.type = PORT_IMX,
|
||||
sport->port.type = PORT_IMX;
|
||||
sport->port.iotype = UPIO_MEM;
|
||||
sport->port.irq = rxirq;
|
||||
sport->port.fifosize = 32;
|
||||
|
@ -876,7 +876,7 @@ static int lqasc_probe(struct platform_device *pdev)
|
||||
port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
|
||||
port->ops = &lqasc_pops;
|
||||
port->fifosize = 16;
|
||||
port->type = PORT_LTQ_ASC,
|
||||
port->type = PORT_LTQ_ASC;
|
||||
port->line = line;
|
||||
port->dev = &pdev->dev;
|
||||
/* unused, just to be backward-compatible */
|
||||
|
@ -521,9 +521,6 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
MAX3100_STATUS_PE | MAX3100_STATUS_FE |
|
||||
MAX3100_STATUS_OE;
|
||||
|
||||
/* we are sending char from a workqueue so enable */
|
||||
s->port.state->port.low_latency = 1;
|
||||
|
||||
if (s->poll_time > 0)
|
||||
del_timer_sync(&s->timer);
|
||||
|
||||
|
@ -34,8 +34,6 @@
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/irq.h>
|
||||
@ -1535,34 +1533,6 @@ disable_clk_ahb:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns 1 if pdev isn't a device instatiated by dt, 0 if it
|
||||
* could successfully get all information from dt or a negative errno.
|
||||
*/
|
||||
static int serial_mxs_probe_dt(struct mxs_auart_port *s,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int ret;
|
||||
|
||||
if (!np)
|
||||
/* no device tree device */
|
||||
return 1;
|
||||
|
||||
ret = of_alias_get_id(np, "serial");
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to get alias id: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
s->port.line = ret;
|
||||
|
||||
if (of_get_property(np, "uart-has-rtscts", NULL) ||
|
||||
of_get_property(np, "fsl,uart-has-rtscts", NULL) /* deprecated */)
|
||||
set_bit(MXS_AUART_RTSCTS, &s->flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
@ -1631,6 +1601,7 @@ static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s)
|
||||
|
||||
static int mxs_auart_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct mxs_auart_port *s;
|
||||
u32 version;
|
||||
int ret, irq;
|
||||
@ -1643,11 +1614,17 @@ static int mxs_auart_probe(struct platform_device *pdev)
|
||||
s->port.dev = &pdev->dev;
|
||||
s->dev = &pdev->dev;
|
||||
|
||||
ret = serial_mxs_probe_dt(s, pdev);
|
||||
if (ret > 0)
|
||||
s->port.line = pdev->id < 0 ? 0 : pdev->id;
|
||||
else if (ret < 0)
|
||||
ret = of_alias_get_id(np, "serial");
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to get alias id: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
s->port.line = ret;
|
||||
|
||||
if (of_get_property(np, "uart-has-rtscts", NULL) ||
|
||||
of_get_property(np, "fsl,uart-has-rtscts", NULL) /* deprecated */)
|
||||
set_bit(MXS_AUART_RTSCTS, &s->flags);
|
||||
|
||||
if (s->port.line >= ARRAY_SIZE(auart_port)) {
|
||||
dev_err(&pdev->dev, "serial%d out of range\n", s->port.line);
|
||||
return -EINVAL;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/console.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
@ -62,6 +63,9 @@
|
||||
#define OWL_UART_STAT_TRFL_MASK GENMASK(16, 11)
|
||||
#define OWL_UART_STAT_UTBB BIT(17)
|
||||
|
||||
#define OWL_UART_POLL_USEC 5
|
||||
#define OWL_UART_TIMEOUT_USEC 10000
|
||||
|
||||
static struct uart_driver owl_uart_driver;
|
||||
|
||||
struct owl_uart_info {
|
||||
@ -461,6 +465,36 @@ static void owl_uart_config_port(struct uart_port *port, int flags)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
|
||||
static int owl_uart_poll_get_char(struct uart_port *port)
|
||||
{
|
||||
if (owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_RFEM)
|
||||
return NO_POLL_CHAR;
|
||||
|
||||
return owl_uart_read(port, OWL_UART_RXDAT);
|
||||
}
|
||||
|
||||
static void owl_uart_poll_put_char(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
/* Wait while FIFO is full or timeout */
|
||||
ret = readl_poll_timeout_atomic(port->membase + OWL_UART_STAT, reg,
|
||||
!(reg & OWL_UART_STAT_TFFU),
|
||||
OWL_UART_POLL_USEC,
|
||||
OWL_UART_TIMEOUT_USEC);
|
||||
if (ret == -ETIMEDOUT) {
|
||||
dev_err(port->dev, "Timeout waiting while UART TX FULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
owl_uart_write(port, ch, OWL_UART_TXDAT);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_CONSOLE_POLL */
|
||||
|
||||
static const struct uart_ops owl_uart_ops = {
|
||||
.set_mctrl = owl_uart_set_mctrl,
|
||||
.get_mctrl = owl_uart_get_mctrl,
|
||||
@ -476,6 +510,10 @@ static const struct uart_ops owl_uart_ops = {
|
||||
.request_port = owl_uart_request_port,
|
||||
.release_port = owl_uart_release_port,
|
||||
.verify_port = owl_uart_verify_port,
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_get_char = owl_uart_poll_get_char,
|
||||
.poll_put_char = owl_uart_poll_put_char,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_OWL_CONSOLE
|
||||
|
@ -975,7 +975,6 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
|
||||
port->closing_wait = closing_wait;
|
||||
if (new_info->xmit_fifo_size)
|
||||
uport->fifosize = new_info->xmit_fifo_size;
|
||||
port->low_latency = (uport->flags & UPF_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
check_and_exit:
|
||||
retval = 0;
|
||||
@ -1795,8 +1794,6 @@ static int uart_port_activate(struct tty_port *port, struct tty_struct *tty)
|
||||
if (!uport || uport->flags & UPF_DEAD)
|
||||
return -ENXIO;
|
||||
|
||||
port->low_latency = (uport->flags & UPF_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
/*
|
||||
* Start up the serial port.
|
||||
*/
|
||||
@ -2851,6 +2848,8 @@ static const struct attribute_group tty_dev_attr_group = {
|
||||
* @drv: pointer to the uart low level driver structure for this port
|
||||
* @uport: uart port structure to use for this port.
|
||||
*
|
||||
* Context: task context, might sleep
|
||||
*
|
||||
* This allows the driver to register its own uart_port structure
|
||||
* with the core driver. The main purpose is to allow the low
|
||||
* level uart drivers to expand uart_port, rather than having yet
|
||||
@ -2864,8 +2863,6 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
struct device *tty_dev;
|
||||
int num_groups;
|
||||
|
||||
BUG_ON(in_interrupt());
|
||||
|
||||
if (uport->line >= drv->nr)
|
||||
return -EINVAL;
|
||||
|
||||
@ -2954,6 +2951,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
* @drv: pointer to the uart low level driver structure for this port
|
||||
* @uport: uart port structure for this port
|
||||
*
|
||||
* Context: task context, might sleep
|
||||
*
|
||||
* This unhooks (and hangs up) the specified port structure from the
|
||||
* core driver. No further calls will be made to the low-level code
|
||||
* for this port.
|
||||
@ -2966,8 +2965,6 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
struct tty_struct *tty;
|
||||
int ret = 0;
|
||||
|
||||
BUG_ON(in_interrupt());
|
||||
|
||||
mutex_lock(&port_mutex);
|
||||
|
||||
/*
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,447 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Drivers for CSR SiRFprimaII onboard UARTs.
|
||||
*
|
||||
* Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
|
||||
*/
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/hrtimer.h>
|
||||
struct sirfsoc_uart_param {
|
||||
const char *uart_name;
|
||||
const char *port_name;
|
||||
};
|
||||
|
||||
struct sirfsoc_register {
|
||||
/* hardware uart specific */
|
||||
u32 sirfsoc_line_ctrl;
|
||||
u32 sirfsoc_divisor;
|
||||
/* uart - usp common */
|
||||
u32 sirfsoc_tx_rx_en;
|
||||
u32 sirfsoc_int_en_reg;
|
||||
u32 sirfsoc_int_st_reg;
|
||||
u32 sirfsoc_int_en_clr_reg;
|
||||
u32 sirfsoc_tx_dma_io_ctrl;
|
||||
u32 sirfsoc_tx_dma_io_len;
|
||||
u32 sirfsoc_tx_fifo_ctrl;
|
||||
u32 sirfsoc_tx_fifo_level_chk;
|
||||
u32 sirfsoc_tx_fifo_op;
|
||||
u32 sirfsoc_tx_fifo_status;
|
||||
u32 sirfsoc_tx_fifo_data;
|
||||
u32 sirfsoc_rx_dma_io_ctrl;
|
||||
u32 sirfsoc_rx_dma_io_len;
|
||||
u32 sirfsoc_rx_fifo_ctrl;
|
||||
u32 sirfsoc_rx_fifo_level_chk;
|
||||
u32 sirfsoc_rx_fifo_op;
|
||||
u32 sirfsoc_rx_fifo_status;
|
||||
u32 sirfsoc_rx_fifo_data;
|
||||
u32 sirfsoc_afc_ctrl;
|
||||
u32 sirfsoc_swh_dma_io;
|
||||
/* hardware usp specific */
|
||||
u32 sirfsoc_mode1;
|
||||
u32 sirfsoc_mode2;
|
||||
u32 sirfsoc_tx_frame_ctrl;
|
||||
u32 sirfsoc_rx_frame_ctrl;
|
||||
u32 sirfsoc_async_param_reg;
|
||||
};
|
||||
|
||||
typedef u32 (*fifo_full_mask)(struct uart_port *port);
|
||||
typedef u32 (*fifo_empty_mask)(struct uart_port *port);
|
||||
|
||||
struct sirfsoc_fifo_status {
|
||||
fifo_full_mask ff_full;
|
||||
fifo_empty_mask ff_empty;
|
||||
};
|
||||
|
||||
struct sirfsoc_int_en {
|
||||
u32 sirfsoc_rx_done_en;
|
||||
u32 sirfsoc_tx_done_en;
|
||||
u32 sirfsoc_rx_oflow_en;
|
||||
u32 sirfsoc_tx_allout_en;
|
||||
u32 sirfsoc_rx_io_dma_en;
|
||||
u32 sirfsoc_tx_io_dma_en;
|
||||
u32 sirfsoc_rxfifo_full_en;
|
||||
u32 sirfsoc_txfifo_empty_en;
|
||||
u32 sirfsoc_rxfifo_thd_en;
|
||||
u32 sirfsoc_txfifo_thd_en;
|
||||
u32 sirfsoc_frm_err_en;
|
||||
u32 sirfsoc_rxd_brk_en;
|
||||
u32 sirfsoc_rx_timeout_en;
|
||||
u32 sirfsoc_parity_err_en;
|
||||
u32 sirfsoc_cts_en;
|
||||
u32 sirfsoc_rts_en;
|
||||
};
|
||||
|
||||
struct sirfsoc_int_status {
|
||||
u32 sirfsoc_rx_done;
|
||||
u32 sirfsoc_tx_done;
|
||||
u32 sirfsoc_rx_oflow;
|
||||
u32 sirfsoc_tx_allout;
|
||||
u32 sirfsoc_rx_io_dma;
|
||||
u32 sirfsoc_tx_io_dma;
|
||||
u32 sirfsoc_rxfifo_full;
|
||||
u32 sirfsoc_txfifo_empty;
|
||||
u32 sirfsoc_rxfifo_thd;
|
||||
u32 sirfsoc_txfifo_thd;
|
||||
u32 sirfsoc_frm_err;
|
||||
u32 sirfsoc_rxd_brk;
|
||||
u32 sirfsoc_rx_timeout;
|
||||
u32 sirfsoc_parity_err;
|
||||
u32 sirfsoc_cts;
|
||||
u32 sirfsoc_rts;
|
||||
};
|
||||
|
||||
enum sirfsoc_uart_type {
|
||||
SIRF_REAL_UART,
|
||||
SIRF_USP_UART,
|
||||
};
|
||||
|
||||
struct sirfsoc_uart_register {
|
||||
struct sirfsoc_register uart_reg;
|
||||
struct sirfsoc_int_en uart_int_en;
|
||||
struct sirfsoc_int_status uart_int_st;
|
||||
struct sirfsoc_fifo_status fifo_status;
|
||||
struct sirfsoc_uart_param uart_param;
|
||||
enum sirfsoc_uart_type uart_type;
|
||||
};
|
||||
|
||||
static u32 uart_usp_ff_full_mask(struct uart_port *port)
|
||||
{
|
||||
u32 full_bit;
|
||||
|
||||
full_bit = ilog2(port->fifosize);
|
||||
return (1 << full_bit);
|
||||
}
|
||||
|
||||
static u32 uart_usp_ff_empty_mask(struct uart_port *port)
|
||||
{
|
||||
u32 empty_bit;
|
||||
|
||||
empty_bit = ilog2(port->fifosize) + 1;
|
||||
return (1 << empty_bit);
|
||||
}
|
||||
|
||||
static struct sirfsoc_uart_register sirfsoc_usp = {
|
||||
.uart_reg = {
|
||||
.sirfsoc_mode1 = 0x0000,
|
||||
.sirfsoc_mode2 = 0x0004,
|
||||
.sirfsoc_tx_frame_ctrl = 0x0008,
|
||||
.sirfsoc_rx_frame_ctrl = 0x000c,
|
||||
.sirfsoc_tx_rx_en = 0x0010,
|
||||
.sirfsoc_int_en_reg = 0x0014,
|
||||
.sirfsoc_int_st_reg = 0x0018,
|
||||
.sirfsoc_async_param_reg = 0x0024,
|
||||
.sirfsoc_tx_dma_io_ctrl = 0x0100,
|
||||
.sirfsoc_tx_dma_io_len = 0x0104,
|
||||
.sirfsoc_tx_fifo_ctrl = 0x0108,
|
||||
.sirfsoc_tx_fifo_level_chk = 0x010c,
|
||||
.sirfsoc_tx_fifo_op = 0x0110,
|
||||
.sirfsoc_tx_fifo_status = 0x0114,
|
||||
.sirfsoc_tx_fifo_data = 0x0118,
|
||||
.sirfsoc_rx_dma_io_ctrl = 0x0120,
|
||||
.sirfsoc_rx_dma_io_len = 0x0124,
|
||||
.sirfsoc_rx_fifo_ctrl = 0x0128,
|
||||
.sirfsoc_rx_fifo_level_chk = 0x012c,
|
||||
.sirfsoc_rx_fifo_op = 0x0130,
|
||||
.sirfsoc_rx_fifo_status = 0x0134,
|
||||
.sirfsoc_rx_fifo_data = 0x0138,
|
||||
.sirfsoc_int_en_clr_reg = 0x140,
|
||||
},
|
||||
.uart_int_en = {
|
||||
.sirfsoc_rx_done_en = BIT(0),
|
||||
.sirfsoc_tx_done_en = BIT(1),
|
||||
.sirfsoc_rx_oflow_en = BIT(2),
|
||||
.sirfsoc_tx_allout_en = BIT(3),
|
||||
.sirfsoc_rx_io_dma_en = BIT(4),
|
||||
.sirfsoc_tx_io_dma_en = BIT(5),
|
||||
.sirfsoc_rxfifo_full_en = BIT(6),
|
||||
.sirfsoc_txfifo_empty_en = BIT(7),
|
||||
.sirfsoc_rxfifo_thd_en = BIT(8),
|
||||
.sirfsoc_txfifo_thd_en = BIT(9),
|
||||
.sirfsoc_frm_err_en = BIT(10),
|
||||
.sirfsoc_rx_timeout_en = BIT(11),
|
||||
.sirfsoc_rxd_brk_en = BIT(15),
|
||||
},
|
||||
.uart_int_st = {
|
||||
.sirfsoc_rx_done = BIT(0),
|
||||
.sirfsoc_tx_done = BIT(1),
|
||||
.sirfsoc_rx_oflow = BIT(2),
|
||||
.sirfsoc_tx_allout = BIT(3),
|
||||
.sirfsoc_rx_io_dma = BIT(4),
|
||||
.sirfsoc_tx_io_dma = BIT(5),
|
||||
.sirfsoc_rxfifo_full = BIT(6),
|
||||
.sirfsoc_txfifo_empty = BIT(7),
|
||||
.sirfsoc_rxfifo_thd = BIT(8),
|
||||
.sirfsoc_txfifo_thd = BIT(9),
|
||||
.sirfsoc_frm_err = BIT(10),
|
||||
.sirfsoc_rx_timeout = BIT(11),
|
||||
.sirfsoc_rxd_brk = BIT(15),
|
||||
},
|
||||
.fifo_status = {
|
||||
.ff_full = uart_usp_ff_full_mask,
|
||||
.ff_empty = uart_usp_ff_empty_mask,
|
||||
},
|
||||
.uart_param = {
|
||||
.uart_name = "ttySiRF",
|
||||
.port_name = "sirfsoc-uart",
|
||||
},
|
||||
};
|
||||
|
||||
static struct sirfsoc_uart_register sirfsoc_uart = {
|
||||
.uart_reg = {
|
||||
.sirfsoc_line_ctrl = 0x0040,
|
||||
.sirfsoc_tx_rx_en = 0x004c,
|
||||
.sirfsoc_divisor = 0x0050,
|
||||
.sirfsoc_int_en_reg = 0x0054,
|
||||
.sirfsoc_int_st_reg = 0x0058,
|
||||
.sirfsoc_int_en_clr_reg = 0x0060,
|
||||
.sirfsoc_tx_dma_io_ctrl = 0x0100,
|
||||
.sirfsoc_tx_dma_io_len = 0x0104,
|
||||
.sirfsoc_tx_fifo_ctrl = 0x0108,
|
||||
.sirfsoc_tx_fifo_level_chk = 0x010c,
|
||||
.sirfsoc_tx_fifo_op = 0x0110,
|
||||
.sirfsoc_tx_fifo_status = 0x0114,
|
||||
.sirfsoc_tx_fifo_data = 0x0118,
|
||||
.sirfsoc_rx_dma_io_ctrl = 0x0120,
|
||||
.sirfsoc_rx_dma_io_len = 0x0124,
|
||||
.sirfsoc_rx_fifo_ctrl = 0x0128,
|
||||
.sirfsoc_rx_fifo_level_chk = 0x012c,
|
||||
.sirfsoc_rx_fifo_op = 0x0130,
|
||||
.sirfsoc_rx_fifo_status = 0x0134,
|
||||
.sirfsoc_rx_fifo_data = 0x0138,
|
||||
.sirfsoc_afc_ctrl = 0x0140,
|
||||
.sirfsoc_swh_dma_io = 0x0148,
|
||||
},
|
||||
.uart_int_en = {
|
||||
.sirfsoc_rx_done_en = BIT(0),
|
||||
.sirfsoc_tx_done_en = BIT(1),
|
||||
.sirfsoc_rx_oflow_en = BIT(2),
|
||||
.sirfsoc_tx_allout_en = BIT(3),
|
||||
.sirfsoc_rx_io_dma_en = BIT(4),
|
||||
.sirfsoc_tx_io_dma_en = BIT(5),
|
||||
.sirfsoc_rxfifo_full_en = BIT(6),
|
||||
.sirfsoc_txfifo_empty_en = BIT(7),
|
||||
.sirfsoc_rxfifo_thd_en = BIT(8),
|
||||
.sirfsoc_txfifo_thd_en = BIT(9),
|
||||
.sirfsoc_frm_err_en = BIT(10),
|
||||
.sirfsoc_rxd_brk_en = BIT(11),
|
||||
.sirfsoc_rx_timeout_en = BIT(12),
|
||||
.sirfsoc_parity_err_en = BIT(13),
|
||||
.sirfsoc_cts_en = BIT(14),
|
||||
.sirfsoc_rts_en = BIT(15),
|
||||
},
|
||||
.uart_int_st = {
|
||||
.sirfsoc_rx_done = BIT(0),
|
||||
.sirfsoc_tx_done = BIT(1),
|
||||
.sirfsoc_rx_oflow = BIT(2),
|
||||
.sirfsoc_tx_allout = BIT(3),
|
||||
.sirfsoc_rx_io_dma = BIT(4),
|
||||
.sirfsoc_tx_io_dma = BIT(5),
|
||||
.sirfsoc_rxfifo_full = BIT(6),
|
||||
.sirfsoc_txfifo_empty = BIT(7),
|
||||
.sirfsoc_rxfifo_thd = BIT(8),
|
||||
.sirfsoc_txfifo_thd = BIT(9),
|
||||
.sirfsoc_frm_err = BIT(10),
|
||||
.sirfsoc_rxd_brk = BIT(11),
|
||||
.sirfsoc_rx_timeout = BIT(12),
|
||||
.sirfsoc_parity_err = BIT(13),
|
||||
.sirfsoc_cts = BIT(14),
|
||||
.sirfsoc_rts = BIT(15),
|
||||
},
|
||||
.fifo_status = {
|
||||
.ff_full = uart_usp_ff_full_mask,
|
||||
.ff_empty = uart_usp_ff_empty_mask,
|
||||
},
|
||||
.uart_param = {
|
||||
.uart_name = "ttySiRF",
|
||||
.port_name = "sirfsoc_uart",
|
||||
},
|
||||
};
|
||||
/* uart io ctrl */
|
||||
#define SIRFUART_DATA_BIT_LEN_MASK 0x3
|
||||
#define SIRFUART_DATA_BIT_LEN_5 BIT(0)
|
||||
#define SIRFUART_DATA_BIT_LEN_6 1
|
||||
#define SIRFUART_DATA_BIT_LEN_7 2
|
||||
#define SIRFUART_DATA_BIT_LEN_8 3
|
||||
#define SIRFUART_STOP_BIT_LEN_1 0
|
||||
#define SIRFUART_STOP_BIT_LEN_2 BIT(2)
|
||||
#define SIRFUART_PARITY_EN BIT(3)
|
||||
#define SIRFUART_EVEN_BIT BIT(4)
|
||||
#define SIRFUART_STICK_BIT_MASK (7 << 3)
|
||||
#define SIRFUART_STICK_BIT_NONE (0 << 3)
|
||||
#define SIRFUART_STICK_BIT_EVEN BIT(3)
|
||||
#define SIRFUART_STICK_BIT_ODD (3 << 3)
|
||||
#define SIRFUART_STICK_BIT_MARK (5 << 3)
|
||||
#define SIRFUART_STICK_BIT_SPACE (7 << 3)
|
||||
#define SIRFUART_SET_BREAK BIT(6)
|
||||
#define SIRFUART_LOOP_BACK BIT(7)
|
||||
#define SIRFUART_PARITY_MASK (7 << 3)
|
||||
#define SIRFUART_DUMMY_READ BIT(16)
|
||||
#define SIRFUART_AFC_CTRL_RX_THD 0x70
|
||||
#define SIRFUART_AFC_RX_EN BIT(8)
|
||||
#define SIRFUART_AFC_TX_EN BIT(9)
|
||||
#define SIRFUART_AFC_CTS_CTRL BIT(10)
|
||||
#define SIRFUART_AFC_RTS_CTRL BIT(11)
|
||||
#define SIRFUART_AFC_CTS_STATUS BIT(12)
|
||||
#define SIRFUART_AFC_RTS_STATUS BIT(13)
|
||||
/* UART FIFO Register */
|
||||
#define SIRFUART_FIFO_STOP 0x0
|
||||
#define SIRFUART_FIFO_RESET BIT(0)
|
||||
#define SIRFUART_FIFO_START BIT(1)
|
||||
|
||||
#define SIRFUART_RX_EN BIT(0)
|
||||
#define SIRFUART_TX_EN BIT(1)
|
||||
|
||||
#define SIRFUART_IO_MODE BIT(0)
|
||||
#define SIRFUART_DMA_MODE 0x0
|
||||
#define SIRFUART_RX_DMA_FLUSH 0x4
|
||||
|
||||
#define SIRFUART_CLEAR_RX_ADDR_EN 0x2
|
||||
/* Baud Rate Calculation */
|
||||
#define SIRF_USP_MIN_SAMPLE_DIV 0x1
|
||||
#define SIRF_MIN_SAMPLE_DIV 0xf
|
||||
#define SIRF_MAX_SAMPLE_DIV 0x3f
|
||||
#define SIRF_IOCLK_DIV_MAX 0xffff
|
||||
#define SIRF_SAMPLE_DIV_SHIFT 16
|
||||
#define SIRF_IOCLK_DIV_MASK 0xffff
|
||||
#define SIRF_SAMPLE_DIV_MASK 0x3f0000
|
||||
#define SIRF_BAUD_RATE_SUPPORT_NR 18
|
||||
|
||||
/* USP SPEC */
|
||||
#define SIRFSOC_USP_ENDIAN_CTRL_LSBF BIT(4)
|
||||
#define SIRFSOC_USP_EN BIT(5)
|
||||
#define SIRFSOC_USP_MODE2_RXD_DELAY_OFFSET 0
|
||||
#define SIRFSOC_USP_MODE2_TXD_DELAY_OFFSET 8
|
||||
#define SIRFSOC_USP_MODE2_CLK_DIVISOR_MASK 0x3ff
|
||||
#define SIRFSOC_USP_MODE2_CLK_DIVISOR_OFFSET 21
|
||||
#define SIRFSOC_USP_TX_DATA_LEN_OFFSET 0
|
||||
#define SIRFSOC_USP_TX_SYNC_LEN_OFFSET 8
|
||||
#define SIRFSOC_USP_TX_FRAME_LEN_OFFSET 16
|
||||
#define SIRFSOC_USP_TX_SHIFTER_LEN_OFFSET 24
|
||||
#define SIRFSOC_USP_TX_CLK_DIVISOR_OFFSET 30
|
||||
#define SIRFSOC_USP_RX_DATA_LEN_OFFSET 0
|
||||
#define SIRFSOC_USP_RX_FRAME_LEN_OFFSET 8
|
||||
#define SIRFSOC_USP_RX_SHIFTER_LEN_OFFSET 16
|
||||
#define SIRFSOC_USP_RX_CLK_DIVISOR_OFFSET 24
|
||||
#define SIRFSOC_USP_ASYNC_DIV2_MASK 0x3f
|
||||
#define SIRFSOC_USP_ASYNC_DIV2_OFFSET 16
|
||||
#define SIRFSOC_USP_LOOP_BACK_CTRL BIT(2)
|
||||
#define SIRFSOC_USP_FRADDR_CLR_EN BIT(1)
|
||||
/* USP-UART Common */
|
||||
#define SIRFSOC_UART_RX_TIMEOUT(br, to) (((br) * (((to) + 999) / 1000)) / 1000)
|
||||
#define SIRFUART_RECV_TIMEOUT_VALUE(x) \
|
||||
(((x) > 0xFFFF) ? 0xFFFF : ((x) & 0xFFFF))
|
||||
#define SIRFUART_USP_RECV_TIMEOUT(x) (x & 0xFFFF)
|
||||
#define SIRFUART_UART_RECV_TIMEOUT(x) ((x & 0xFFFF) << 16)
|
||||
|
||||
#define SIRFUART_FIFO_THD(port) (port->fifosize >> 1)
|
||||
#define SIRFUART_ERR_INT_STAT(unit_st, uart_type) \
|
||||
(uint_st->sirfsoc_rx_oflow | \
|
||||
uint_st->sirfsoc_frm_err | \
|
||||
uint_st->sirfsoc_rxd_brk | \
|
||||
((uart_type != SIRF_REAL_UART) ? \
|
||||
0 : uint_st->sirfsoc_parity_err))
|
||||
#define SIRFUART_RX_IO_INT_EN(uint_en, uart_type) \
|
||||
(uint_en->sirfsoc_rx_done_en |\
|
||||
uint_en->sirfsoc_rxfifo_thd_en |\
|
||||
uint_en->sirfsoc_rxfifo_full_en |\
|
||||
uint_en->sirfsoc_frm_err_en |\
|
||||
uint_en->sirfsoc_rx_oflow_en |\
|
||||
uint_en->sirfsoc_rxd_brk_en |\
|
||||
((uart_type != SIRF_REAL_UART) ? \
|
||||
0 : uint_en->sirfsoc_parity_err_en))
|
||||
#define SIRFUART_RX_IO_INT_ST(uint_st) \
|
||||
(uint_st->sirfsoc_rxfifo_thd |\
|
||||
uint_st->sirfsoc_rxfifo_full|\
|
||||
uint_st->sirfsoc_rx_done |\
|
||||
uint_st->sirfsoc_rx_timeout)
|
||||
#define SIRFUART_CTS_INT_ST(uint_st) (uint_st->sirfsoc_cts)
|
||||
#define SIRFUART_RX_DMA_INT_EN(uint_en, uart_type) \
|
||||
(uint_en->sirfsoc_frm_err_en |\
|
||||
uint_en->sirfsoc_rx_oflow_en |\
|
||||
uint_en->sirfsoc_rxd_brk_en |\
|
||||
((uart_type != SIRF_REAL_UART) ? \
|
||||
0 : uint_en->sirfsoc_parity_err_en))
|
||||
/* Generic Definitions */
|
||||
#define SIRFSOC_UART_NAME "ttySiRF"
|
||||
#define SIRFSOC_UART_MAJOR 0
|
||||
#define SIRFSOC_UART_MINOR 0
|
||||
#define SIRFUART_PORT_NAME "sirfsoc-uart"
|
||||
#define SIRFUART_MAP_SIZE 0x200
|
||||
#define SIRFSOC_UART_NR 11
|
||||
#define SIRFSOC_PORT_TYPE 0xa5
|
||||
|
||||
/* Uart Common Use Macro*/
|
||||
#define SIRFSOC_RX_DMA_BUF_SIZE (1024 * 32)
|
||||
#define BYTES_TO_ALIGN(dma_addr) ((unsigned long)(dma_addr) & 0x3)
|
||||
/* Uart Fifo Level Chk */
|
||||
#define SIRFUART_TX_FIFO_SC_OFFSET 0
|
||||
#define SIRFUART_TX_FIFO_LC_OFFSET 10
|
||||
#define SIRFUART_TX_FIFO_HC_OFFSET 20
|
||||
#define SIRFUART_TX_FIFO_CHK_SC(line, value) ((((line) == 1) ? (value & 0x3) :\
|
||||
(value & 0x1f)) << SIRFUART_TX_FIFO_SC_OFFSET)
|
||||
#define SIRFUART_TX_FIFO_CHK_LC(line, value) ((((line) == 1) ? (value & 0x3) :\
|
||||
(value & 0x1f)) << SIRFUART_TX_FIFO_LC_OFFSET)
|
||||
#define SIRFUART_TX_FIFO_CHK_HC(line, value) ((((line) == 1) ? (value & 0x3) :\
|
||||
(value & 0x1f)) << SIRFUART_TX_FIFO_HC_OFFSET)
|
||||
|
||||
#define SIRFUART_RX_FIFO_CHK_SC SIRFUART_TX_FIFO_CHK_SC
|
||||
#define SIRFUART_RX_FIFO_CHK_LC SIRFUART_TX_FIFO_CHK_LC
|
||||
#define SIRFUART_RX_FIFO_CHK_HC SIRFUART_TX_FIFO_CHK_HC
|
||||
#define SIRFUART_RX_FIFO_MASK 0x7f
|
||||
/* Indicate how many buffers used */
|
||||
|
||||
/* For Fast Baud Rate Calculation */
|
||||
struct sirfsoc_baudrate_to_regv {
|
||||
unsigned int baud_rate;
|
||||
unsigned int reg_val;
|
||||
};
|
||||
|
||||
enum sirfsoc_tx_state {
|
||||
TX_DMA_IDLE,
|
||||
TX_DMA_RUNNING,
|
||||
TX_DMA_PAUSE,
|
||||
};
|
||||
|
||||
struct sirfsoc_rx_buffer {
|
||||
struct circ_buf xmit;
|
||||
dma_cookie_t cookie;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
dma_addr_t dma_addr;
|
||||
};
|
||||
|
||||
struct sirfsoc_uart_port {
|
||||
bool hw_flow_ctrl;
|
||||
bool ms_enabled;
|
||||
|
||||
struct uart_port port;
|
||||
struct clk *clk;
|
||||
/* for SiRFatlas7, there are SET/CLR for UART_INT_EN */
|
||||
bool is_atlas7;
|
||||
struct sirfsoc_uart_register *uart_reg;
|
||||
struct dma_chan *rx_dma_chan;
|
||||
struct dma_chan *tx_dma_chan;
|
||||
dma_addr_t tx_dma_addr;
|
||||
struct dma_async_tx_descriptor *tx_dma_desc;
|
||||
unsigned long transfer_size;
|
||||
enum sirfsoc_tx_state tx_dma_state;
|
||||
unsigned int cts_gpio;
|
||||
unsigned int rts_gpio;
|
||||
|
||||
struct sirfsoc_rx_buffer rx_dma_items;
|
||||
struct hrtimer hrt;
|
||||
bool is_hrt_enabled;
|
||||
unsigned long rx_period_time;
|
||||
unsigned long rx_last_pos;
|
||||
unsigned long pio_fetch_cnt;
|
||||
};
|
||||
|
||||
/* Register Access Control */
|
||||
#define portaddr(port, reg) ((port)->membase + (reg))
|
||||
#define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
|
||||
#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
|
||||
|
||||
/* UART Port Mask */
|
||||
#define SIRFUART_FIFOLEVEL_MASK(port) ((port->fifosize - 1) & 0xFFF)
|
||||
#define SIRFUART_FIFOFULL_MASK(port) (port->fifosize & 0xFFF)
|
||||
#define SIRFUART_FIFOEMPTY_MASK(port) ((port->fifosize & 0xFFF) << 1)
|
File diff suppressed because it is too large
Load Diff
@ -672,7 +672,6 @@ static int open(struct tty_struct *tty, struct file *filp)
|
||||
DBGINFO(("%s open, old ref count = %d\n", info->device_name, info->port.count));
|
||||
|
||||
mutex_lock(&info->port.mutex);
|
||||
info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
spin_lock_irqsave(&info->netlock, flags);
|
||||
if (info->netcount) {
|
||||
|
@ -142,7 +142,7 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */
|
||||
/* Mutex to protect creating and releasing a tty */
|
||||
DEFINE_MUTEX(tty_mutex);
|
||||
|
||||
static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
|
||||
static ssize_t tty_read(struct kiocb *, struct iov_iter *);
|
||||
static ssize_t tty_write(struct kiocb *, struct iov_iter *);
|
||||
static __poll_t tty_poll(struct file *, poll_table *);
|
||||
static int tty_open(struct inode *, struct file *);
|
||||
@ -429,8 +429,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
|
||||
EXPORT_SYMBOL_GPL(tty_find_polling_driver);
|
||||
#endif
|
||||
|
||||
static ssize_t hung_up_tty_read(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
static ssize_t hung_up_tty_read(struct kiocb *iocb, struct iov_iter *to)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -473,8 +472,9 @@ static void tty_show_fdinfo(struct seq_file *m, struct file *file)
|
||||
|
||||
static const struct file_operations tty_fops = {
|
||||
.llseek = no_llseek,
|
||||
.read = tty_read,
|
||||
.read_iter = tty_read,
|
||||
.write_iter = tty_write,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.splice_write = iter_file_splice_write,
|
||||
.poll = tty_poll,
|
||||
.unlocked_ioctl = tty_ioctl,
|
||||
@ -487,8 +487,9 @@ static const struct file_operations tty_fops = {
|
||||
|
||||
static const struct file_operations console_fops = {
|
||||
.llseek = no_llseek,
|
||||
.read = tty_read,
|
||||
.read_iter = tty_read,
|
||||
.write_iter = redirected_tty_write,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.splice_write = iter_file_splice_write,
|
||||
.poll = tty_poll,
|
||||
.unlocked_ioctl = tty_ioctl,
|
||||
@ -500,7 +501,7 @@ static const struct file_operations console_fops = {
|
||||
|
||||
static const struct file_operations hung_up_tty_fops = {
|
||||
.llseek = no_llseek,
|
||||
.read = hung_up_tty_read,
|
||||
.read_iter = hung_up_tty_read,
|
||||
.write_iter = hung_up_tty_write,
|
||||
.poll = hung_up_tty_poll,
|
||||
.unlocked_ioctl = hung_up_tty_ioctl,
|
||||
@ -538,6 +539,29 @@ void tty_wakeup(struct tty_struct *tty)
|
||||
|
||||
EXPORT_SYMBOL_GPL(tty_wakeup);
|
||||
|
||||
/**
|
||||
* tty_release_redirect - Release a redirect on a pty if present
|
||||
* @tty: tty device
|
||||
*
|
||||
* This is available to the pty code so if the master closes, if the
|
||||
* slave is a redirect it can release the redirect. It returns the
|
||||
* filp for the redirect, which must be fput when the operations on
|
||||
* the tty are completed.
|
||||
*/
|
||||
struct file *tty_release_redirect(struct tty_struct *tty)
|
||||
{
|
||||
struct file *f = NULL;
|
||||
|
||||
spin_lock(&redirect_lock);
|
||||
if (redirect && file_tty(redirect) == tty) {
|
||||
f = redirect;
|
||||
redirect = NULL;
|
||||
}
|
||||
spin_unlock(&redirect_lock);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* __tty_hangup - actual handler for hangup events
|
||||
* @tty: tty device
|
||||
@ -564,7 +588,7 @@ EXPORT_SYMBOL_GPL(tty_wakeup);
|
||||
static void __tty_hangup(struct tty_struct *tty, int exit_session)
|
||||
{
|
||||
struct file *cons_filp = NULL;
|
||||
struct file *filp, *f = NULL;
|
||||
struct file *filp, *f;
|
||||
struct tty_file_private *priv;
|
||||
int closecount = 0, n;
|
||||
int refs;
|
||||
@ -572,13 +596,7 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
|
||||
spin_lock(&redirect_lock);
|
||||
if (redirect && file_tty(redirect) == tty) {
|
||||
f = redirect;
|
||||
redirect = NULL;
|
||||
}
|
||||
spin_unlock(&redirect_lock);
|
||||
f = tty_release_redirect(tty);
|
||||
|
||||
tty_lock(tty);
|
||||
|
||||
@ -829,6 +847,72 @@ static void tty_update_time(struct timespec64 *time)
|
||||
time->tv_sec = sec;
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate on the ldisc ->read() function until we've gotten all
|
||||
* the data the ldisc has for us.
|
||||
*
|
||||
* The "cookie" is something that the ldisc read function can fill
|
||||
* in to let us know that there is more data to be had.
|
||||
*
|
||||
* We promise to continue to call the ldisc until it stops returning
|
||||
* data or clears the cookie. The cookie may be something that the
|
||||
* ldisc maintains state for and needs to free.
|
||||
*/
|
||||
static int iterate_tty_read(struct tty_ldisc *ld, struct tty_struct *tty,
|
||||
struct file *file, struct iov_iter *to)
|
||||
{
|
||||
int retval = 0;
|
||||
void *cookie = NULL;
|
||||
unsigned long offset = 0;
|
||||
char kernel_buf[64];
|
||||
size_t count = iov_iter_count(to);
|
||||
|
||||
do {
|
||||
int size, copied;
|
||||
|
||||
size = count > sizeof(kernel_buf) ? sizeof(kernel_buf) : count;
|
||||
size = ld->ops->read(tty, file, kernel_buf, size, &cookie, offset);
|
||||
if (!size)
|
||||
break;
|
||||
|
||||
if (size < 0) {
|
||||
/* Did we have an earlier error (ie -EFAULT)? */
|
||||
if (retval)
|
||||
break;
|
||||
retval = size;
|
||||
|
||||
/*
|
||||
* -EOVERFLOW means we didn't have enough space
|
||||
* for a whole packet, and we shouldn't return
|
||||
* a partial result.
|
||||
*/
|
||||
if (retval == -EOVERFLOW)
|
||||
offset = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
copied = copy_to_iter(kernel_buf, size, to);
|
||||
offset += copied;
|
||||
count -= copied;
|
||||
|
||||
/*
|
||||
* If the user copy failed, we still need to do another ->read()
|
||||
* call if we had a cookie to let the ldisc clear up.
|
||||
*
|
||||
* But make sure size is zeroed.
|
||||
*/
|
||||
if (unlikely(copied != size)) {
|
||||
count = 0;
|
||||
retval = -EFAULT;
|
||||
}
|
||||
} while (cookie);
|
||||
|
||||
/* We always clear tty buffer in case they contained passwords */
|
||||
memzero_explicit(kernel_buf, sizeof(kernel_buf));
|
||||
return offset ? offset : retval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tty_read - read method for tty device files
|
||||
* @file: pointer to tty file
|
||||
@ -844,10 +928,10 @@ static void tty_update_time(struct timespec64 *time)
|
||||
* read calls may be outstanding in parallel.
|
||||
*/
|
||||
|
||||
static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
|
||||
loff_t *ppos)
|
||||
static ssize_t tty_read(struct kiocb *iocb, struct iov_iter *to)
|
||||
{
|
||||
int i;
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct tty_struct *tty = file_tty(file);
|
||||
struct tty_ldisc *ld;
|
||||
@ -861,11 +945,10 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
|
||||
situation */
|
||||
ld = tty_ldisc_ref_wait(tty);
|
||||
if (!ld)
|
||||
return hung_up_tty_read(file, buf, count, ppos);
|
||||
return hung_up_tty_read(iocb, to);
|
||||
i = -EIO;
|
||||
if (ld->ops->read)
|
||||
i = ld->ops->read(tty, file, buf, count);
|
||||
else
|
||||
i = -EIO;
|
||||
i = iterate_tty_read(ld, tty, file, to);
|
||||
tty_ldisc_deref(ld);
|
||||
|
||||
if (i > 0)
|
||||
@ -1889,22 +1972,7 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
|
||||
return driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_kopen - open a tty device for kernel
|
||||
* @device: dev_t of device to open
|
||||
*
|
||||
* Opens tty exclusively for kernel. Performs the driver lookup,
|
||||
* makes sure it's not already opened and performs the first-time
|
||||
* tty initialization.
|
||||
*
|
||||
* Returns the locked initialized &tty_struct
|
||||
*
|
||||
* Claims the global tty_mutex to serialize:
|
||||
* - concurrent first-time tty initialization
|
||||
* - concurrent tty driver removal w/ lookup
|
||||
* - concurrent tty removal from driver table
|
||||
*/
|
||||
struct tty_struct *tty_kopen(dev_t device)
|
||||
static struct tty_struct *tty_kopen(dev_t device, int shared)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
struct tty_driver *driver;
|
||||
@ -1919,7 +1987,7 @@ struct tty_struct *tty_kopen(dev_t device)
|
||||
|
||||
/* check whether we're reopening an existing tty */
|
||||
tty = tty_driver_lookup_tty(driver, NULL, index);
|
||||
if (IS_ERR(tty))
|
||||
if (IS_ERR(tty) || shared)
|
||||
goto out;
|
||||
|
||||
if (tty) {
|
||||
@ -1937,7 +2005,42 @@ out:
|
||||
tty_driver_kref_put(driver);
|
||||
return tty;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_kopen);
|
||||
|
||||
/**
|
||||
* tty_kopen_exclusive - open a tty device for kernel
|
||||
* @device: dev_t of device to open
|
||||
*
|
||||
* Opens tty exclusively for kernel. Performs the driver lookup,
|
||||
* makes sure it's not already opened and performs the first-time
|
||||
* tty initialization.
|
||||
*
|
||||
* Returns the locked initialized &tty_struct
|
||||
*
|
||||
* Claims the global tty_mutex to serialize:
|
||||
* - concurrent first-time tty initialization
|
||||
* - concurrent tty driver removal w/ lookup
|
||||
* - concurrent tty removal from driver table
|
||||
*/
|
||||
struct tty_struct *tty_kopen_exclusive(dev_t device)
|
||||
{
|
||||
return tty_kopen(device, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_kopen_exclusive);
|
||||
|
||||
/**
|
||||
* tty_kopen_shared - open a tty device for shared in-kernel use
|
||||
* @device: dev_t of device to open
|
||||
*
|
||||
* Opens an already existing tty for in-kernel use. Compared to
|
||||
* tty_kopen_exclusive() above it doesn't ensure to be the only user.
|
||||
*
|
||||
* Locking is identical to tty_kopen() above.
|
||||
*/
|
||||
struct tty_struct *tty_kopen_shared(dev_t device)
|
||||
{
|
||||
return tty_kopen(device, 1);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_kopen_shared);
|
||||
|
||||
/**
|
||||
* tty_open_by_driver - open a tty device
|
||||
@ -2488,15 +2591,36 @@ static int tty_tiocmset(struct tty_struct *tty, unsigned int cmd,
|
||||
return tty->ops->tiocmset(tty, set, clear);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_get_icount - get tty statistics
|
||||
* @tty: tty device
|
||||
* @icount: output parameter
|
||||
*
|
||||
* Gets a copy of the tty's icount statistics.
|
||||
*
|
||||
* Locking: none (up to the driver)
|
||||
*/
|
||||
int tty_get_icount(struct tty_struct *tty,
|
||||
struct serial_icounter_struct *icount)
|
||||
{
|
||||
memset(icount, 0, sizeof(*icount));
|
||||
|
||||
if (tty->ops->get_icount)
|
||||
return tty->ops->get_icount(tty, icount);
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_get_icount);
|
||||
|
||||
static int tty_tiocgicount(struct tty_struct *tty, void __user *arg)
|
||||
{
|
||||
int retval = -EINVAL;
|
||||
struct serial_icounter_struct icount;
|
||||
memset(&icount, 0, sizeof(icount));
|
||||
if (tty->ops->get_icount)
|
||||
retval = tty->ops->get_icount(tty, &icount);
|
||||
int retval;
|
||||
|
||||
retval = tty_get_icount(tty, &icount);
|
||||
if (retval != 0)
|
||||
return retval;
|
||||
|
||||
if (copy_to_user(arg, &icount, sizeof(icount)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
@ -2887,7 +3011,7 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
|
||||
|
||||
static int this_tty(const void *t, struct file *file, unsigned fd)
|
||||
{
|
||||
if (likely(file->f_op->read != tty_read))
|
||||
if (likely(file->f_op->read_iter != tty_read))
|
||||
return 0;
|
||||
return file_tty(file) != t ? 0 : fd + 1;
|
||||
}
|
||||
|
@ -681,9 +681,6 @@ static int vcc_remove(struct vio_dev *vdev)
|
||||
{
|
||||
struct vcc_port *port = dev_get_drvdata(&vdev->dev);
|
||||
|
||||
if (!port)
|
||||
return -ENODEV;
|
||||
|
||||
del_timer_sync(&port->rx_timer);
|
||||
del_timer_sync(&port->tx_timer);
|
||||
|
||||
@ -695,12 +692,9 @@ static int vcc_remove(struct vio_dev *vdev)
|
||||
tty_vhangup(port->tty);
|
||||
|
||||
/* Get exclusive reference to VCC, ensures that there are no other
|
||||
* clients to this port
|
||||
* clients to this port. This cannot fail.
|
||||
*/
|
||||
port = vcc_get(port->index, true);
|
||||
|
||||
if (WARN_ON(!port))
|
||||
return -ENODEV;
|
||||
vcc_get(port->index, true);
|
||||
|
||||
tty_unregister_device(vcc_tty_driver, port->index);
|
||||
|
||||
|
@ -495,7 +495,7 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
|
||||
|
||||
p2[unicode & 0x3f] = fontpos;
|
||||
|
||||
p->sum += (fontpos << 20) + unicode;
|
||||
p->sum += (fontpos << 20U) + unicode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <linux/keyboard.h>
|
||||
#include <linux/kd.h>
|
||||
|
||||
u_short plain_map[NR_KEYS] = {
|
||||
unsigned short plain_map[NR_KEYS] = {
|
||||
0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
|
||||
0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf07f, 0xf009,
|
||||
0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
|
||||
@ -25,7 +25,7 @@ u_short plain_map[NR_KEYS] = {
|
||||
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
|
||||
};
|
||||
|
||||
u_short shift_map[NR_KEYS] = {
|
||||
static unsigned short shift_map[NR_KEYS] = {
|
||||
0xf200, 0xf01b, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e,
|
||||
0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07f, 0xf009,
|
||||
0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49,
|
||||
@ -44,7 +44,7 @@ u_short shift_map[NR_KEYS] = {
|
||||
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
|
||||
};
|
||||
|
||||
u_short altgr_map[NR_KEYS] = {
|
||||
static unsigned short altgr_map[NR_KEYS] = {
|
||||
0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
|
||||
0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200,
|
||||
0xfb71, 0xfb77, 0xf918, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
|
||||
@ -63,7 +63,7 @@ u_short altgr_map[NR_KEYS] = {
|
||||
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
|
||||
};
|
||||
|
||||
u_short ctrl_map[NR_KEYS] = {
|
||||
static unsigned short ctrl_map[NR_KEYS] = {
|
||||
0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e,
|
||||
0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200,
|
||||
0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
|
||||
@ -82,7 +82,7 @@ u_short ctrl_map[NR_KEYS] = {
|
||||
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
|
||||
};
|
||||
|
||||
u_short shift_ctrl_map[NR_KEYS] = {
|
||||
static unsigned short shift_ctrl_map[NR_KEYS] = {
|
||||
0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
|
||||
0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200,
|
||||
0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
|
||||
@ -101,7 +101,7 @@ u_short shift_ctrl_map[NR_KEYS] = {
|
||||
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
|
||||
};
|
||||
|
||||
u_short alt_map[NR_KEYS] = {
|
||||
static unsigned short alt_map[NR_KEYS] = {
|
||||
0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836,
|
||||
0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf87f, 0xf809,
|
||||
0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869,
|
||||
@ -120,7 +120,7 @@ u_short alt_map[NR_KEYS] = {
|
||||
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
|
||||
};
|
||||
|
||||
u_short ctrl_alt_map[NR_KEYS] = {
|
||||
static unsigned short ctrl_alt_map[NR_KEYS] = {
|
||||
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
|
||||
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
|
||||
0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809,
|
||||
@ -224,40 +224,40 @@ char *func_table[MAX_NR_FUNC] = {
|
||||
};
|
||||
|
||||
struct kbdiacruc accent_table[MAX_DIACR] = {
|
||||
{'`', 'A', 0300}, {'`', 'a', 0340},
|
||||
{'\'', 'A', 0301}, {'\'', 'a', 0341},
|
||||
{'^', 'A', 0302}, {'^', 'a', 0342},
|
||||
{'~', 'A', 0303}, {'~', 'a', 0343},
|
||||
{'"', 'A', 0304}, {'"', 'a', 0344},
|
||||
{'O', 'A', 0305}, {'o', 'a', 0345},
|
||||
{'0', 'A', 0305}, {'0', 'a', 0345},
|
||||
{'A', 'A', 0305}, {'a', 'a', 0345},
|
||||
{'A', 'E', 0306}, {'a', 'e', 0346},
|
||||
{',', 'C', 0307}, {',', 'c', 0347},
|
||||
{'`', 'E', 0310}, {'`', 'e', 0350},
|
||||
{'\'', 'E', 0311}, {'\'', 'e', 0351},
|
||||
{'^', 'E', 0312}, {'^', 'e', 0352},
|
||||
{'"', 'E', 0313}, {'"', 'e', 0353},
|
||||
{'`', 'I', 0314}, {'`', 'i', 0354},
|
||||
{'\'', 'I', 0315}, {'\'', 'i', 0355},
|
||||
{'^', 'I', 0316}, {'^', 'i', 0356},
|
||||
{'"', 'I', 0317}, {'"', 'i', 0357},
|
||||
{'-', 'D', 0320}, {'-', 'd', 0360},
|
||||
{'~', 'N', 0321}, {'~', 'n', 0361},
|
||||
{'`', 'O', 0322}, {'`', 'o', 0362},
|
||||
{'\'', 'O', 0323}, {'\'', 'o', 0363},
|
||||
{'^', 'O', 0324}, {'^', 'o', 0364},
|
||||
{'~', 'O', 0325}, {'~', 'o', 0365},
|
||||
{'"', 'O', 0326}, {'"', 'o', 0366},
|
||||
{'/', 'O', 0330}, {'/', 'o', 0370},
|
||||
{'`', 'U', 0331}, {'`', 'u', 0371},
|
||||
{'\'', 'U', 0332}, {'\'', 'u', 0372},
|
||||
{'^', 'U', 0333}, {'^', 'u', 0373},
|
||||
{'"', 'U', 0334}, {'"', 'u', 0374},
|
||||
{'\'', 'Y', 0335}, {'\'', 'y', 0375},
|
||||
{'T', 'H', 0336}, {'t', 'h', 0376},
|
||||
{'s', 's', 0337}, {'"', 'y', 0377},
|
||||
{'s', 'z', 0337}, {'i', 'j', 0377},
|
||||
{'`', 'A', 0x00c0}, {'`', 'a', 0x00e0},
|
||||
{'\'', 'A', 0x00c1}, {'\'', 'a', 0x00e1},
|
||||
{'^', 'A', 0x00c2}, {'^', 'a', 0x00e2},
|
||||
{'~', 'A', 0x00c3}, {'~', 'a', 0x00e3},
|
||||
{'"', 'A', 0x00c4}, {'"', 'a', 0x00e4},
|
||||
{'O', 'A', 0x00c5}, {'o', 'a', 0x00e5},
|
||||
{'0', 'A', 0x00c5}, {'0', 'a', 0x00e5},
|
||||
{'A', 'A', 0x00c5}, {'a', 'a', 0x00e5},
|
||||
{'A', 'E', 0x00c6}, {'a', 'e', 0x00e6},
|
||||
{',', 'C', 0x00c7}, {',', 'c', 0x00e7},
|
||||
{'`', 'E', 0x00c8}, {'`', 'e', 0x00e8},
|
||||
{'\'', 'E', 0x00c9}, {'\'', 'e', 0x00e9},
|
||||
{'^', 'E', 0x00ca}, {'^', 'e', 0x00ea},
|
||||
{'"', 'E', 0x00cb}, {'"', 'e', 0x00eb},
|
||||
{'`', 'I', 0x00cc}, {'`', 'i', 0x00ec},
|
||||
{'\'', 'I', 0x00cd}, {'\'', 'i', 0x00ed},
|
||||
{'^', 'I', 0x00ce}, {'^', 'i', 0x00ee},
|
||||
{'"', 'I', 0x00cf}, {'"', 'i', 0x00ef},
|
||||
{'-', 'D', 0x00d0}, {'-', 'd', 0x00f0},
|
||||
{'~', 'N', 0x00d1}, {'~', 'n', 0x00f1},
|
||||
{'`', 'O', 0x00d2}, {'`', 'o', 0x00f2},
|
||||
{'\'', 'O', 0x00d3}, {'\'', 'o', 0x00f3},
|
||||
{'^', 'O', 0x00d4}, {'^', 'o', 0x00f4},
|
||||
{'~', 'O', 0x00d5}, {'~', 'o', 0x00f5},
|
||||
{'"', 'O', 0x00d6}, {'"', 'o', 0x00f6},
|
||||
{'/', 'O', 0x00d8}, {'/', 'o', 0x00f8},
|
||||
{'`', 'U', 0x00d9}, {'`', 'u', 0x00f9},
|
||||
{'\'', 'U', 0x00da}, {'\'', 'u', 0x00fa},
|
||||
{'^', 'U', 0x00db}, {'^', 'u', 0x00fb},
|
||||
{'"', 'U', 0x00dc}, {'"', 'u', 0x00fc},
|
||||
{'\'', 'Y', 0x00dd}, {'\'', 'y', 0x00fd},
|
||||
{'T', 'H', 0x00de}, {'t', 'h', 0x00fe},
|
||||
{'s', 's', 0x00df}, {'"', 'y', 0x00ff},
|
||||
{'s', 'z', 0x00df}, {'i', 'j', 0x00ff},
|
||||
};
|
||||
|
||||
unsigned int accent_table_size = 68;
|
||||
|
@ -131,6 +131,9 @@ static const unsigned char max_vals[] = {
|
||||
|
||||
static const int NR_TYPES = ARRAY_SIZE(max_vals);
|
||||
|
||||
static void kbd_bh(struct tasklet_struct *unused);
|
||||
static DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh);
|
||||
|
||||
static struct input_handler kbd_handler;
|
||||
static DEFINE_SPINLOCK(kbd_event_lock);
|
||||
static DEFINE_SPINLOCK(led_lock);
|
||||
@ -372,6 +375,12 @@ static void to_utf8(struct vc_data *vc, uint c)
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: review locking for vt.c callers */
|
||||
static void set_leds(void)
|
||||
{
|
||||
tasklet_schedule(&keyboard_tasklet);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called after returning from RAW mode or when changing consoles - recompute
|
||||
* shift_down[] and shift_state from key_down[] maybe called when keymap is
|
||||
@ -401,9 +410,12 @@ static void do_compute_shiftstate(void)
|
||||
}
|
||||
|
||||
/* We still have to export this method to vt.c */
|
||||
void compute_shiftstate(void)
|
||||
void vt_set_leds_compute_shiftstate(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
set_leds();
|
||||
|
||||
spin_lock_irqsave(&kbd_event_lock, flags);
|
||||
do_compute_shiftstate();
|
||||
spin_unlock_irqrestore(&kbd_event_lock, flags);
|
||||
@ -1233,7 +1245,7 @@ void vt_kbd_con_stop(int console)
|
||||
* handle the scenario when keyboard handler is not registered yet
|
||||
* but we already getting updates from the VT to update led state.
|
||||
*/
|
||||
static void kbd_bh(unsigned long dummy)
|
||||
static void kbd_bh(struct tasklet_struct *unused)
|
||||
{
|
||||
unsigned int leds;
|
||||
unsigned long flags;
|
||||
@ -1249,8 +1261,6 @@ static void kbd_bh(unsigned long dummy)
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_TASKLET_DISABLED_OLD(keyboard_tasklet, kbd_bh);
|
||||
|
||||
#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
|
||||
defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
|
||||
defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
|
||||
|
@ -1036,8 +1036,7 @@ void redraw_screen(struct vc_data *vc, int is_switch)
|
||||
}
|
||||
set_cursor(vc);
|
||||
if (is_switch) {
|
||||
set_leds();
|
||||
compute_shiftstate();
|
||||
vt_set_leds_compute_shiftstate();
|
||||
notify_update(vc);
|
||||
}
|
||||
}
|
||||
@ -4584,16 +4583,8 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
|
||||
|
||||
if (op->data && font.charcount > op->charcount)
|
||||
rc = -ENOSPC;
|
||||
if (!(op->flags & KD_FONT_FLAG_OLD)) {
|
||||
if (font.width > op->width || font.height > op->height)
|
||||
rc = -ENOSPC;
|
||||
} else {
|
||||
if (font.width != 8)
|
||||
rc = -EIO;
|
||||
else if ((op->height && font.height > op->height) ||
|
||||
font.height > 32)
|
||||
rc = -ENOSPC;
|
||||
}
|
||||
if (font.width > op->width || font.height > op->height)
|
||||
rc = -ENOSPC;
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
@ -4621,7 +4612,7 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op)
|
||||
return -EINVAL;
|
||||
if (op->charcount > 512)
|
||||
return -EINVAL;
|
||||
if (op->width <= 0 || op->width > 32 || op->height > 32)
|
||||
if (op->width <= 0 || op->width > 32 || !op->height || op->height > 32)
|
||||
return -EINVAL;
|
||||
size = (op->width+7)/8 * 32 * op->charcount;
|
||||
if (size > max_font_size)
|
||||
@ -4631,31 +4622,6 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op)
|
||||
if (IS_ERR(font.data))
|
||||
return PTR_ERR(font.data);
|
||||
|
||||
if (!op->height) { /* Need to guess font height [compat] */
|
||||
int h, i;
|
||||
u8 *charmap = font.data;
|
||||
|
||||
/*
|
||||
* If from KDFONTOP ioctl, don't allow things which can be done
|
||||
* in userland,so that we can get rid of this soon
|
||||
*/
|
||||
if (!(op->flags & KD_FONT_FLAG_OLD)) {
|
||||
kfree(font.data);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (h = 32; h > 0; h--)
|
||||
for (i = 0; i < op->charcount; i++)
|
||||
if (charmap[32*i+h-1])
|
||||
goto nonzero;
|
||||
|
||||
kfree(font.data);
|
||||
return -EINVAL;
|
||||
|
||||
nonzero:
|
||||
op->height = h;
|
||||
}
|
||||
|
||||
font.charcount = op->charcount;
|
||||
font.width = op->width;
|
||||
font.height = op->height;
|
||||
|
@ -484,70 +484,6 @@ static int vt_k_ioctl(struct tty_struct *tty, unsigned int cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int do_fontx_ioctl(struct vc_data *vc, int cmd,
|
||||
struct consolefontdesc __user *user_cfd,
|
||||
struct console_font_op *op)
|
||||
{
|
||||
struct consolefontdesc cfdarg;
|
||||
int i;
|
||||
|
||||
if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc)))
|
||||
return -EFAULT;
|
||||
|
||||
switch (cmd) {
|
||||
case PIO_FONTX:
|
||||
op->op = KD_FONT_OP_SET;
|
||||
op->flags = KD_FONT_FLAG_OLD;
|
||||
op->width = 8;
|
||||
op->height = cfdarg.charheight;
|
||||
op->charcount = cfdarg.charcount;
|
||||
op->data = cfdarg.chardata;
|
||||
return con_font_op(vc, op);
|
||||
|
||||
case GIO_FONTX:
|
||||
op->op = KD_FONT_OP_GET;
|
||||
op->flags = KD_FONT_FLAG_OLD;
|
||||
op->width = 8;
|
||||
op->height = cfdarg.charheight;
|
||||
op->charcount = cfdarg.charcount;
|
||||
op->data = cfdarg.chardata;
|
||||
i = con_font_op(vc, op);
|
||||
if (i)
|
||||
return i;
|
||||
cfdarg.charheight = op->height;
|
||||
cfdarg.charcount = op->charcount;
|
||||
if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vt_io_fontreset(struct vc_data *vc, struct console_font_op *op)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (__is_defined(BROKEN_GRAPHICS_PROGRAMS)) {
|
||||
/*
|
||||
* With BROKEN_GRAPHICS_PROGRAMS defined, the default font is
|
||||
* not saved.
|
||||
*/
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
op->op = KD_FONT_OP_SET_DEFAULT;
|
||||
op->data = NULL;
|
||||
ret = con_font_op(vc, op);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
console_lock();
|
||||
con_set_default_unimap(vc);
|
||||
console_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud,
|
||||
bool perm, struct vc_data *vc)
|
||||
{
|
||||
@ -572,29 +508,7 @@ static inline int do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud,
|
||||
static int vt_io_ioctl(struct vc_data *vc, unsigned int cmd, void __user *up,
|
||||
bool perm)
|
||||
{
|
||||
struct console_font_op op; /* used in multiple places here */
|
||||
|
||||
switch (cmd) {
|
||||
case PIO_FONT:
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
op.op = KD_FONT_OP_SET;
|
||||
op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */
|
||||
op.width = 8;
|
||||
op.height = 0;
|
||||
op.charcount = 256;
|
||||
op.data = up;
|
||||
return con_font_op(vc, &op);
|
||||
|
||||
case GIO_FONT:
|
||||
op.op = KD_FONT_OP_GET;
|
||||
op.flags = KD_FONT_FLAG_OLD;
|
||||
op.width = 8;
|
||||
op.height = 32;
|
||||
op.charcount = 256;
|
||||
op.data = up;
|
||||
return con_font_op(vc, &op);
|
||||
|
||||
case PIO_CMAP:
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
@ -603,20 +517,6 @@ static int vt_io_ioctl(struct vc_data *vc, unsigned int cmd, void __user *up,
|
||||
case GIO_CMAP:
|
||||
return con_get_cmap(up);
|
||||
|
||||
case PIO_FONTX:
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
|
||||
fallthrough;
|
||||
case GIO_FONTX:
|
||||
return do_fontx_ioctl(vc, cmd, up, &op);
|
||||
|
||||
case PIO_FONTRESET:
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
|
||||
return vt_io_fontreset(vc, &op);
|
||||
|
||||
case PIO_SCRNMAP:
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
@ -1030,8 +930,7 @@ void reset_vc(struct vc_data *vc)
|
||||
put_pid(vc->vt_pid);
|
||||
vc->vt_pid = NULL;
|
||||
vc->vt_newvt = -1;
|
||||
if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */
|
||||
reset_palette(vc);
|
||||
reset_palette(vc);
|
||||
}
|
||||
|
||||
void vc_SAK(struct work_struct *work)
|
||||
@ -1059,54 +958,6 @@ void vc_SAK(struct work_struct *work)
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
struct compat_consolefontdesc {
|
||||
unsigned short charcount; /* characters in font (256 or 512) */
|
||||
unsigned short charheight; /* scan lines per character (1-32) */
|
||||
compat_caddr_t chardata; /* font data in expanded form */
|
||||
};
|
||||
|
||||
static inline int
|
||||
compat_fontx_ioctl(struct vc_data *vc, int cmd,
|
||||
struct compat_consolefontdesc __user *user_cfd,
|
||||
int perm, struct console_font_op *op)
|
||||
{
|
||||
struct compat_consolefontdesc cfdarg;
|
||||
int i;
|
||||
|
||||
if (copy_from_user(&cfdarg, user_cfd, sizeof(struct compat_consolefontdesc)))
|
||||
return -EFAULT;
|
||||
|
||||
switch (cmd) {
|
||||
case PIO_FONTX:
|
||||
if (!perm)
|
||||
return -EPERM;
|
||||
op->op = KD_FONT_OP_SET;
|
||||
op->flags = KD_FONT_FLAG_OLD;
|
||||
op->width = 8;
|
||||
op->height = cfdarg.charheight;
|
||||
op->charcount = cfdarg.charcount;
|
||||
op->data = compat_ptr(cfdarg.chardata);
|
||||
return con_font_op(vc, op);
|
||||
|
||||
case GIO_FONTX:
|
||||
op->op = KD_FONT_OP_GET;
|
||||
op->flags = KD_FONT_FLAG_OLD;
|
||||
op->width = 8;
|
||||
op->height = cfdarg.charheight;
|
||||
op->charcount = cfdarg.charcount;
|
||||
op->data = compat_ptr(cfdarg.chardata);
|
||||
i = con_font_op(vc, op);
|
||||
if (i)
|
||||
return i;
|
||||
cfdarg.charheight = op->height;
|
||||
cfdarg.charcount = op->charcount;
|
||||
if (copy_to_user(user_cfd, &cfdarg, sizeof(struct compat_consolefontdesc)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
struct compat_console_font_op {
|
||||
compat_uint_t op; /* operation code KD_FONT_OP_* */
|
||||
compat_uint_t flags; /* KD_FONT_FLAG_* */
|
||||
@ -1183,9 +1034,6 @@ long vt_compat_ioctl(struct tty_struct *tty,
|
||||
/*
|
||||
* these need special handlers for incompatible data structures
|
||||
*/
|
||||
case PIO_FONTX:
|
||||
case GIO_FONTX:
|
||||
return compat_fontx_ioctl(vc, cmd, up, perm, &op);
|
||||
|
||||
case KDFONTOP:
|
||||
return compat_kdfontop_ioctl(up, perm, &op, vc);
|
||||
|
@ -90,7 +90,6 @@ static unsigned int vga_video_num_lines; /* Number of text lines */
|
||||
static bool vga_can_do_color; /* Do we support colors? */
|
||||
static unsigned int vga_default_font_height __read_mostly; /* Height of default screen font */
|
||||
static unsigned char vga_video_type __read_mostly; /* Card type */
|
||||
static bool vga_font_is_default = true;
|
||||
static int vga_vesa_blanked;
|
||||
static bool vga_palette_blanked;
|
||||
static bool vga_is_gfx;
|
||||
@ -878,7 +877,6 @@ static int vgacon_do_font_op(struct vgastate *state, char *arg, int set,
|
||||
beg = 0x0a;
|
||||
}
|
||||
|
||||
#ifdef BROKEN_GRAPHICS_PROGRAMS
|
||||
/*
|
||||
* All fonts are loaded in slot 0 (0:1 for 512 ch)
|
||||
*/
|
||||
@ -886,24 +884,7 @@ static int vgacon_do_font_op(struct vgastate *state, char *arg, int set,
|
||||
if (!arg)
|
||||
return -EINVAL; /* Return to default font not supported */
|
||||
|
||||
vga_font_is_default = false;
|
||||
font_select = ch512 ? 0x04 : 0x00;
|
||||
#else
|
||||
/*
|
||||
* The default font is kept in slot 0 and is never touched.
|
||||
* A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
|
||||
*/
|
||||
|
||||
if (set) {
|
||||
vga_font_is_default = !arg;
|
||||
if (!arg)
|
||||
ch512 = false; /* Default font is always 256 */
|
||||
font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
|
||||
}
|
||||
|
||||
if (!vga_font_is_default)
|
||||
charmap += 4 * cmapsz;
|
||||
#endif
|
||||
|
||||
raw_spin_lock_irq(&vga_lock);
|
||||
/* First, the Sequencer */
|
||||
|
@ -6,8 +6,6 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/keyboard.h>
|
||||
|
||||
extern struct tasklet_struct keyboard_tasklet;
|
||||
|
||||
extern char *func_table[MAX_NR_FUNC];
|
||||
|
||||
/*
|
||||
@ -71,12 +69,6 @@ extern void (*kbd_ledfunc)(unsigned int led);
|
||||
extern int set_console(int nr);
|
||||
extern void schedule_console_callback(void);
|
||||
|
||||
/* FIXME: review locking for vt.c callers */
|
||||
static inline void set_leds(void)
|
||||
{
|
||||
tasklet_schedule(&keyboard_tasklet);
|
||||
}
|
||||
|
||||
static inline int vc_kbd_mode(struct kbd_struct * kbd, int flag)
|
||||
{
|
||||
return ((kbd->modeflags >> flag) & 1);
|
||||
@ -135,7 +127,7 @@ static inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag)
|
||||
|
||||
struct console;
|
||||
|
||||
void compute_shiftstate(void);
|
||||
void vt_set_leds_compute_shiftstate(void);
|
||||
|
||||
/* defkeymap.c */
|
||||
|
||||
|
@ -1,8 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _LINUX_KD_H
|
||||
#define _LINUX_KD_H
|
||||
|
||||
#include <uapi/linux/kd.h>
|
||||
|
||||
#define KD_FONT_FLAG_OLD 0x80000000 /* Invoked via old interface [compat] */
|
||||
#endif /* _LINUX_KD_H */
|
@ -1,19 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
*
|
||||
*
|
||||
*/
|
||||
#ifndef __LINUX_PLATFORM_DATA_EFM32_UART_H__
|
||||
#define __LINUX_PLATFORM_DATA_EFM32_UART_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/**
|
||||
* struct efm32_uart_pdata
|
||||
* @location: pinmux location for the I/O pins (to be written to the ROUTE
|
||||
* register)
|
||||
*/
|
||||
struct efm32_uart_pdata {
|
||||
u8 location;
|
||||
};
|
||||
#endif /* ifndef __LINUX_PLATFORM_DATA_EFM32_UART_H__ */
|
@ -1,15 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef LINUX_IFX_MODEM_H
|
||||
#define LINUX_IFX_MODEM_H
|
||||
|
||||
struct ifx_modem_platform_data {
|
||||
unsigned short tx_pwr; /* modem power threshold */
|
||||
unsigned char modem_type; /* Modem type */
|
||||
unsigned long max_hz; /* max SPI frequency */
|
||||
unsigned short use_dma:1; /* spi protocol driver supplies
|
||||
dma-able addrs */
|
||||
};
|
||||
#define IFX_MODEM_6160 1
|
||||
#define IFX_MODEM_6260 2
|
||||
|
||||
#endif
|
@ -240,8 +240,7 @@ struct tty_port {
|
||||
wait_queue_head_t delta_msr_wait; /* Modem status change */
|
||||
unsigned long flags; /* User TTY flags ASYNC_ */
|
||||
unsigned long iflags; /* Internal flags TTY_PORT_ */
|
||||
unsigned char console:1, /* port is a console */
|
||||
low_latency:1; /* optional: tune for latency */
|
||||
unsigned char console:1; /* port is a console */
|
||||
struct mutex mutex; /* Locking */
|
||||
struct mutex buf_mutex; /* Buffer alloc lock */
|
||||
unsigned char *xmit_buf; /* Optional buffer */
|
||||
@ -416,12 +415,14 @@ extern struct tty_struct *get_current_tty(void);
|
||||
/* tty_io.c */
|
||||
extern int __init tty_init(void);
|
||||
extern const char *tty_name(const struct tty_struct *tty);
|
||||
extern struct tty_struct *tty_kopen(dev_t device);
|
||||
extern struct tty_struct *tty_kopen_exclusive(dev_t device);
|
||||
extern struct tty_struct *tty_kopen_shared(dev_t device);
|
||||
extern void tty_kclose(struct tty_struct *tty);
|
||||
extern int tty_dev_name_to_number(const char *name, dev_t *number);
|
||||
extern int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout);
|
||||
extern void tty_ldisc_unlock(struct tty_struct *tty);
|
||||
extern ssize_t redirected_tty_write(struct kiocb *, struct iov_iter *);
|
||||
extern struct file *tty_release_redirect(struct tty_struct *tty);
|
||||
#else
|
||||
static inline void tty_kref_put(struct tty_struct *tty)
|
||||
{ }
|
||||
@ -442,7 +443,7 @@ static inline int __init tty_init(void)
|
||||
{ return 0; }
|
||||
static inline const char *tty_name(const struct tty_struct *tty)
|
||||
{ return "(none)"; }
|
||||
static inline struct tty_struct *tty_kopen(dev_t device)
|
||||
static inline struct tty_struct *tty_kopen_exclusive(dev_t device)
|
||||
{ return ERR_PTR(-ENODEV); }
|
||||
static inline void tty_kclose(struct tty_struct *tty)
|
||||
{ }
|
||||
@ -500,6 +501,8 @@ extern void tty_unthrottle(struct tty_struct *tty);
|
||||
extern int tty_throttle_safe(struct tty_struct *tty);
|
||||
extern int tty_unthrottle_safe(struct tty_struct *tty);
|
||||
extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws);
|
||||
extern int tty_get_icount(struct tty_struct *tty,
|
||||
struct serial_icounter_struct *icount);
|
||||
extern int is_current_pgrp_orphaned(void);
|
||||
extern void tty_hangup(struct tty_struct *tty);
|
||||
extern void tty_vhangup(struct tty_struct *tty);
|
||||
|
@ -185,7 +185,8 @@ struct tty_ldisc_ops {
|
||||
void (*close)(struct tty_struct *);
|
||||
void (*flush_buffer)(struct tty_struct *tty);
|
||||
ssize_t (*read)(struct tty_struct *tty, struct file *file,
|
||||
unsigned char __user *buf, size_t nr);
|
||||
unsigned char *buf, size_t nr,
|
||||
void **cookie, unsigned long offset);
|
||||
ssize_t (*write)(struct tty_struct *tty, struct file *file,
|
||||
const unsigned char *buf, size_t nr);
|
||||
int (*ioctl)(struct tty_struct *tty, struct file *file,
|
||||
|
@ -16,18 +16,6 @@
|
||||
#include <linux/consolemap.h>
|
||||
#include <linux/notifier.h>
|
||||
|
||||
/*
|
||||
* Presently, a lot of graphics programs do not restore the contents of
|
||||
* the higher font pages. Defining this flag will avoid use of them, but
|
||||
* will lose support for PIO_FONTRESET. Note that many font operations are
|
||||
* not likely to work with these programs anyway; they need to be
|
||||
* fixed. The linux/Documentation directory includes a code snippet
|
||||
* to save and restore the text font.
|
||||
*/
|
||||
#ifdef CONFIG_VGA_CONSOLE
|
||||
#define BROKEN_GRAPHICS_PROGRAMS 1
|
||||
#endif
|
||||
|
||||
void kd_mksound(unsigned int hz, unsigned int ticks);
|
||||
int kbd_rate(struct kbd_repeat *rep);
|
||||
|
||||
|
@ -208,9 +208,6 @@
|
||||
/* Atheros AR933X SoC */
|
||||
#define PORT_AR933X 99
|
||||
|
||||
/* Energy Micro efm32 SoC */
|
||||
#define PORT_EFMUART 100
|
||||
|
||||
/* ARC (Synopsys) on-chip UART */
|
||||
#define PORT_ARC 101
|
||||
|
||||
|
@ -5,19 +5,4 @@
|
||||
#include <linux/types.h>
|
||||
#include <asm/termios.h>
|
||||
|
||||
#define NFF 5
|
||||
|
||||
struct termiox
|
||||
{
|
||||
__u16 x_hflag;
|
||||
__u16 x_cflag;
|
||||
__u16 x_rflag[NFF];
|
||||
__u16 x_sflag;
|
||||
};
|
||||
|
||||
#define RTSXOFF 0x0001 /* RTS flow control on input */
|
||||
#define CTSXON 0x0002 /* CTS flow control on output */
|
||||
#define DTRXOFF 0x0004 /* DTR flow control on input */
|
||||
#define DSRXON 0x0008 /* DCD flow control on output */
|
||||
|
||||
#endif
|
||||
|
@ -292,7 +292,8 @@ static int nci_uart_tty_ioctl(struct tty_struct *tty, struct file *file,
|
||||
|
||||
/* We don't provide read/write/poll interface for user space. */
|
||||
static ssize_t nci_uart_tty_read(struct tty_struct *tty, struct file *file,
|
||||
unsigned char __user *buf, size_t nr)
|
||||
unsigned char *buf, size_t nr,
|
||||
void **cookie, unsigned long offset)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user