TTY / Serial driver updates for 7.3-rc1

Here is the "big" set of tty and serial driver updates for 7.3-rc1.  Not
 really all that much happened this development cycle for this subsystem,
 changes in here are:
   - removal of the ipwireless driver as it's no longer used or needed
   - new 8250_mxpcie driver added
   - qcom serial driver updates and additions
   - vt mode validation addition
   - lots of other small serial driver updates and additions
 
 All of these have been in linux-next for weeks with no reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCao2mTw8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+yk34ACdFfyDYJ0n1JcdskTxdNMBSPRkj7UAoJtMC/2y
 jxCfyfkM18YIuwZD6CvO
 =MlfE
 -----END PGP SIGNATURE-----

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

Pull TTY / serial driver updates from Greg KH:
 "Here is the "big" set of tty and serial driver updates for 7.3-rc1.

  Not really all that much happened this development cycle for this
  subsystem, changes in here are:

   - removal of the ipwireless driver as it's no longer used or needed

   - new 8250_mxpcie driver added

   - qcom serial driver updates and additions

   - vt mode validation addition

   - lots of other small serial driver updates and additions

  All of these have been in linux-next for weeks with no reported issues"

* tag 'tty-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (97 commits)
  serial: imx: serialize imx_uart_ports[] lifetime
  tty: clear cdev pointer after cdev_add() failure
  tty: skip cdev_del() when no cdev is registered
  serial: core: clear freed pointers on uart_register_driver() failure
  serial: core: do fallible allocations before the console can be registered
  serial: 8250_mxpcie: implement rx_trig_bytes callbacks via MUEx50 RTL
  serial: 8250_mxpcie: introduce per-port private data structure
  serial: 8250: allow UART drivers to override rx_trig_bytes handling
  serial: 8250_mxpcie: add break support for RS485 using MUEx50 features
  serial: 8250: allow low-level drivers to override break control
  serial: 8250_mxpcie: support serial interface mode switching
  serial: 8250_mxpcie: speed up TX using memory-mapped FIFO window
  serial: 8250_mxpcie: speed up RX using memory-mapped FIFO window
  serial: 8250_mxpcie: add custom handle_irq callback
  serial: 8250_mxpcie: offload XON/XOFF flow control to MUEx50 hardware
  serial: 8250_mxpcie: enable automatic RTS/CTS flow control
  serial: 8250_mxpcie: enable enhanced mode and program FIFO trigger levels
  serial: 8250: add Moxa MUEx50 UART port type
  serial: 8250: split Moxa PCIe serial board support out of 8250_pci
  serial: qcom-geni: Use geni_se_set_perf_level() for baud rate perf level
  ...
This commit is contained in:
Linus Torvalds 2026-08-25 10:59:12 -07:00
commit 70f5376dbd
81 changed files with 2061 additions and 4726 deletions

View File

@ -23,7 +23,8 @@ allOf:
then:
properties:
compatible:
const: aspeed,ast2500-vuart
contains:
const: aspeed,ast2500-vuart
- if:
properties:
compatible:
@ -188,6 +189,11 @@ properties:
- loongson,ls2k2000-uart
- const: loongson,ls2k1500-uart
- const: ns16550a
- items:
- enum:
- aspeed,ast2600-vuart
- aspeed,ast2700-vuart
- const: aspeed,ast2500-vuart
reg:
maxItems: 1

View File

@ -9,6 +9,13 @@ title: Maxim MAX310X Advanced Universal Asynchronous Receiver-Transmitter (UART)
maintainers:
- Hugo Villeneuve <hvilleneuve@dimonoff.com>
description:
The MAX310X is a family of SPI/I2C UARTs with one (max3107, max3108),
two (max3109) or four (max14830) channels. Single-channel parts are
described as a serial node with RS-485 properties on the chip node;
multi-channel parts use one "serial@N" child node per channel, each
carrying its own serial/RS-485 properties.
properties:
compatible:
enum:
@ -49,8 +56,55 @@ required:
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
- $ref: /schemas/serial/serial.yaml#
- $ref: /schemas/serial/rs485.yaml#
- if:
properties:
compatible:
contains:
enum:
- maxim,max3107
- maxim,max3108
then:
allOf:
- $ref: /schemas/serial/serial.yaml#
- $ref: /schemas/serial/rs485.yaml#
- if:
properties:
compatible:
contains:
enum:
- maxim,max3109
- maxim,max14830
then:
properties:
"#address-cells":
const: 1
"#size-cells":
const: 0
patternProperties:
"^serial@[0-3]$":
type: object
description: A single UART channel of the chip.
allOf:
- $ref: /schemas/serial/serial.yaml#
- $ref: /schemas/serial/rs485.yaml#
properties:
reg:
description: UART channel number on the chip.
maximum: 3
required:
- reg
unevaluatedProperties: false
- if:
properties:
compatible:
contains:
const: maxim,max3109
then:
patternProperties:
"^serial@[23]$": false
unevaluatedProperties: false
@ -70,5 +124,39 @@ examples:
interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
gpio-controller;
#gpio-cells = <2>;
rs485-rts-active-low;
linux,rs485-enabled-at-boot-time;
};
};
- |
#include <dt-bindings/interrupt-controller/irq.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
serial@0 {
compatible = "maxim,max14830";
reg = <0>;
spi-max-frequency = <26000000>;
clocks = <&xtal4m>;
clock-names = "xtal";
interrupt-parent = <&gpio3>;
interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
gpio-controller;
#gpio-cells = <2>;
#address-cells = <1>;
#size-cells = <0>;
serial@0 {
reg = <0>;
rs485-rts-active-low;
linux,rs485-enabled-at-boot-time;
};
serial@2 {
reg = <2>;
rs485-rts-active-low;
};
};
};

View File

@ -54,6 +54,7 @@ properties:
- anlogic,dr1v90-uart
- brcm,bcm11351-dw-apb-uart
- brcm,bcm21664-dw-apb-uart
- google,lga-uart
- rockchip,px30-uart
- rockchip,rk1808-uart
- rockchip,rk3036-uart
@ -72,6 +73,7 @@ properties:
- rockchip,rk3576-uart
- rockchip,rk3588-uart
- rockchip,rv1103b-uart
- rockchip,rv1106-uart
- rockchip,rv1108-uart
- rockchip,rv1126-uart
- sophgo,sg2044-uart

View File

@ -13785,12 +13785,6 @@ F: include/net/ip_vs.h
F: include/uapi/linux/ip_vs.h
F: net/netfilter/ipvs/
IPWIRELESS DRIVER
M: Jiri Kosina <jikos@kernel.org>
M: David Sterba <dsterba@suse.com>
S: Odd Fixes
F: drivers/tty/ipwireless/
IRON DEVICE AUDIO CODEC DRIVERS
M: Kiseok Jo <kiseok.jo@irondevice.com>
L: linux-sound@vger.kernel.org

View File

@ -20,6 +20,7 @@ aliases {
mmc2 = &mmc2;
serial0 = &uart0;
serial1 = &uart1;
serial2 = &uart2;
};
backlight_lcd0: backlight {

View File

@ -20,6 +20,7 @@ / {
aliases {
serial0 = &uart0;
serial2 = &uart2;
};
chosen {

View File

@ -21,6 +21,8 @@ / {
aliases {
serial0 = &uart0;
serial1 = &uart1;
serial2 = &uart2;
ethernet0 = &gmac0;
ethernet1 = &gmac1;
};

View File

@ -16,6 +16,8 @@ / {
aliases {
serial0 = &uart0;
serial1 = &uart1;
serial2 = &uart2;
};
chosen {

View File

@ -13,6 +13,7 @@
/ {
aliases {
serial0 = &uart0;
serial1 = &uart1;
mmc0 = &mmc0;
mmc1 = &mmc1;
};

View File

@ -9,6 +9,10 @@ / {
model = "Google Hayato rev1";
chassis-type = "convertible";
compatible = "google,hayato-rev1", "google,hayato", "mediatek,mt8192";
aliases {
serial1 = &uart1;
};
};
&keyboard_controller {

View File

@ -19,6 +19,7 @@ / {
aliases {
serial0 = &uart0;
serial1 = &uart1;
};
chosen {

View File

@ -24,6 +24,8 @@ aliases {
mmc0 = &mmc0;
mmc1 = &mmc1;
serial0 = &uart0;
serial1 = &uart1;
serial2 = &uart2;
};
chosen {

View File

@ -33,6 +33,8 @@ aliases {
mmc0 = &mmc0;
mmc1 = &mmc1;
serial0 = &uart0;
serial1 = &uart1;
serial2 = &uart2;
};
backlight_lcm1: backlight-lcm1 {

View File

@ -17,6 +17,8 @@ aliases {
i2c5 = &i2c5;
i2c6 = &i2c6;
serial0 = &uart0;
serial1 = &uart1;
serial2 = &uart2;
};
chosen {

View File

@ -31,6 +31,8 @@ aliases {
rtc0 = &rv3028;
rtc1 = &mt6359rtc;
serial0 = &uart0;
serial1 = &uart1;
serial2 = &uart2;
};
backlight_lcd0: backlight-lcd0 {

View File

@ -22,6 +22,7 @@ aliases {
mmc0 = &mmc0;
mmc1 = &mmc1;
serial0 = &uart0;
serial1 = &uart1;
};
chosen {

View File

@ -571,7 +571,6 @@ CONFIG_PPDEV=m
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_VIRTIO=m
CONFIG_NVRAM=y
CONFIG_IPWIRELESS=m
CONFIG_I2C_CHARDEV=m
CONFIG_I2C_HYDRA=m
CONFIG_I2C_MPC=m

View File

@ -291,15 +291,6 @@ config GOLDFISH_TTY_EARLY_CONSOLE
default y if GOLDFISH_TTY=y
select SERIAL_EARLYCON
config IPWIRELESS
tristate "IPWireless 3G UMTS PCMCIA card support"
depends on PCMCIA && NETDEVICES && HAS_IOPORT
select PPP
help
This is a driver for 3G UMTS PCMCIA card from IPWireless company. In
some countries (for example Czech Republic, T-Mobile ISP) this card
is shipped for service called UMTS 4G.
config N_GSM
tristate "GSM MUX line discipline support (EXPERIMENTAL)"
depends on NET

View File

@ -26,5 +26,3 @@ obj-$(CONFIG_GOLDFISH_TTY) += goldfish.o
obj-$(CONFIG_MIPS_EJTAG_FDC_TTY) += mips_ejtag_fdc.o
obj-$(CONFIG_VCC) += vcc.o
obj-$(CONFIG_RPMSG_TTY) += rpmsg_tty.o
obj-y += ipwireless/

View File

@ -443,23 +443,23 @@ static int rs_startup(struct tty_struct *tty, struct serial_state *info)
struct tty_port *port = &info->tport;
unsigned long flags;
int retval=0;
unsigned long page;
void *buffer;
page = get_zeroed_page(GFP_KERNEL);
if (!page)
buffer = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
local_irq_save(flags);
if (tty_port_initialized(port)) {
free_page(page);
kfree(buffer);
goto errout;
}
if (info->xmit.buf)
free_page(page);
kfree(buffer);
else
info->xmit.buf = (unsigned char *) page;
info->xmit.buf = buffer;
#ifdef SERIAL_DEBUG_OPEN
printk("starting up ttys%d ...", info->line);
@ -537,7 +537,7 @@ static void rs_shutdown(struct tty_struct *tty, struct serial_state *info)
*/
free_irq(IRQ_AMIGA_VERTB, info);
free_page((unsigned long)info->xmit.buf);
kfree(info->xmit.buf);
info->xmit.buf = NULL;
info->IER = 0;

View File

@ -17,6 +17,7 @@
#include <linux/mm.h>
#include <linux/dma-mapping.h>
#include <linux/serial_core.h>
#include <linux/wordpart.h>
/* Goldfish tty register's offsets */
#define GOLDFISH_TTY_REG_BYTES_READY 0x04
@ -37,7 +38,6 @@ struct goldfish_tty {
spinlock_t lock;
void __iomem *base;
u32 irq;
int opencount;
struct console console;
u32 version;
struct device *dev;
@ -49,15 +49,23 @@ static u32 goldfish_tty_line_count = 8;
static u32 goldfish_tty_current_line_count;
static struct goldfish_tty *goldfish_ttys;
static inline void gf_write_addr(unsigned long addr, void __iomem *portl, void __iomem *porth)
{
gf_iowrite32(lower_32_bits(addr), portl);
#ifdef CONFIG_64BIT
gf_iowrite32(upper_32_bits(addr), porth);
#endif
}
static void do_rw_io(struct goldfish_tty *qtty, unsigned long address,
size_t count, bool is_write)
{
unsigned long irq_flags;
void __iomem *base = qtty->base;
spin_lock_irqsave(&qtty->lock, irq_flags);
gf_write_ptr((void *)address, base + GOLDFISH_TTY_REG_DATA_PTR,
base + GOLDFISH_TTY_REG_DATA_PTR_HIGH);
guard(spinlock_irqsave)(&qtty->lock);
gf_write_addr(address, base + GOLDFISH_TTY_REG_DATA_PTR,
base + GOLDFISH_TTY_REG_DATA_PTR_HIGH);
gf_iowrite32(count, base + GOLDFISH_TTY_REG_DATA_LEN);
if (is_write)
@ -66,8 +74,6 @@ static void do_rw_io(struct goldfish_tty *qtty, unsigned long address,
else
gf_iowrite32(GOLDFISH_TTY_CMD_READ_BUFFER,
base + GOLDFISH_TTY_REG_CMD);
spin_unlock_irqrestore(&qtty->lock, irq_flags);
}
static void goldfish_tty_rw(struct goldfish_tty *qtty, unsigned long addr,
@ -409,7 +415,7 @@ static void goldfish_tty_remove(struct platform_device *pdev)
{
struct goldfish_tty *qtty = platform_get_drvdata(pdev);
mutex_lock(&goldfish_tty_lock);
guard(mutex)(&goldfish_tty_lock);
unregister_console(&qtty->console);
tty_unregister_device(goldfish_tty_driver, qtty->console.index);
@ -420,7 +426,6 @@ static void goldfish_tty_remove(struct platform_device *pdev)
goldfish_tty_current_line_count--;
if (goldfish_tty_current_line_count == 0)
goldfish_tty_delete_driver();
mutex_unlock(&goldfish_tty_lock);
}
#ifdef CONFIG_GOLDFISH_TTY_EARLY_CONSOLE

View File

@ -79,7 +79,7 @@ config HVC_UDBG
config HVC_DCC
bool "ARM JTAG DCC console"
depends on ARM || ARM64
depends on (ARM && (CPU_V6 || CPU_V6K || CPU_V7)) || ARM64
select HVC_DRIVER
select SERIAL_CORE_CONSOLE
help

View File

@ -1,9 +0,0 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the IPWireless driver
#
obj-$(CONFIG_IPWIRELESS) += ipwireless.o
ipwireless-y := hardware.o main.o network.o tty.o

File diff suppressed because it is too large Load Diff

View File

@ -1,63 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* IPWireless 3G PCMCIA Network Driver
*
* Original code
* by Stephen Blackheath <stephen@blacksapphire.com>,
* Ben Martel <benm@symmetric.co.nz>
*
* Copyrighted as follows:
* Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
*
* Various driver changes and rewrites, port to new kernels
* Copyright (C) 2006-2007 Jiri Kosina
*
* Misc code cleanups and updates
* Copyright (C) 2007 David Sterba
*/
#ifndef _IPWIRELESS_CS_HARDWARE_H_
#define _IPWIRELESS_CS_HARDWARE_H_
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#define IPW_CONTROL_LINE_CTS 0x0001
#define IPW_CONTROL_LINE_DCD 0x0002
#define IPW_CONTROL_LINE_DSR 0x0004
#define IPW_CONTROL_LINE_RI 0x0008
#define IPW_CONTROL_LINE_DTR 0x0010
#define IPW_CONTROL_LINE_RTS 0x0020
struct ipw_hardware;
struct ipw_network;
struct ipw_hardware *ipwireless_hardware_create(void);
void ipwireless_hardware_free(struct ipw_hardware *hw);
irqreturn_t ipwireless_interrupt(int irq, void *dev_id);
int ipwireless_set_DTR(struct ipw_hardware *hw, unsigned int channel_idx,
int state);
int ipwireless_set_RTS(struct ipw_hardware *hw, unsigned int channel_idx,
int state);
int ipwireless_send_packet(struct ipw_hardware *hw,
unsigned int channel_idx,
const unsigned char *data,
unsigned int length,
void (*packet_sent_callback) (void *cb,
unsigned int length),
void *sent_cb_data);
void ipwireless_associate_network(struct ipw_hardware *hw,
struct ipw_network *net);
void ipwireless_stop_interrupts(struct ipw_hardware *hw);
void ipwireless_init_hardware_v1(struct ipw_hardware *hw,
unsigned int base_port,
void __iomem *attr_memory,
void __iomem *common_memory,
int is_v2_card,
void (*reboot_cb) (void *data),
void *reboot_cb_data);
void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw);
void ipwireless_sleep(unsigned int tenths);
#endif

View File

@ -1,356 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* IPWireless 3G PCMCIA Network Driver
*
* Original code
* by Stephen Blackheath <stephen@blacksapphire.com>,
* Ben Martel <benm@symmetric.co.nz>
*
* Copyrighted as follows:
* Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
*
* Various driver changes and rewrites, port to new kernels
* Copyright (C) 2006-2007 Jiri Kosina
*
* Misc code cleanups and updates
* Copyright (C) 2007 David Sterba
*/
#include "hardware.h"
#include "network.h"
#include "main.h"
#include "tty.h"
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/device_id.h>
#include <pcmcia/ss.h>
#include <pcmcia/ds.h>
static const struct pcmcia_device_id ipw_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0100),
PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0200),
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, ipw_ids);
static void ipwireless_detach(struct pcmcia_device *link);
/*
* Module params
*/
/* Debug mode: more verbose, print sent/recv bytes */
int ipwireless_debug;
int ipwireless_loopback;
int ipwireless_out_queue = 10;
module_param_named(debug, ipwireless_debug, int, 0);
module_param_named(loopback, ipwireless_loopback, int, 0);
module_param_named(out_queue, ipwireless_out_queue, int, 0);
MODULE_PARM_DESC(debug, "switch on debug messages [0]");
MODULE_PARM_DESC(loopback,
"debug: enable ras_raw channel [0]");
MODULE_PARM_DESC(out_queue, "debug: set size of outgoing PPP queue [10]");
/* Executes in process context. */
static void signalled_reboot_work(struct work_struct *work_reboot)
{
struct ipw_dev *ipw = container_of(work_reboot, struct ipw_dev,
work_reboot);
struct pcmcia_device *link = ipw->link;
pcmcia_reset_card(link->socket);
}
static void signalled_reboot_callback(void *callback_data)
{
struct ipw_dev *ipw = (struct ipw_dev *) callback_data;
/* Delegate to process context. */
schedule_work(&ipw->work_reboot);
}
static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data)
{
struct ipw_dev *ipw = priv_data;
int ret;
p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
/* 0x40 causes it to generate level mode interrupts. */
/* 0x04 enables IREQ pin. */
p_dev->config_index |= 0x44;
p_dev->io_lines = 16;
ret = pcmcia_request_io(p_dev);
if (ret)
return ret;
if (!request_region(p_dev->resource[0]->start,
resource_size(p_dev->resource[0]),
IPWIRELESS_PCCARD_NAME)) {
ret = -EBUSY;
goto exit;
}
p_dev->resource[2]->flags |=
WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE;
ret = pcmcia_request_window(p_dev, p_dev->resource[2], 0);
if (ret != 0)
goto exit1;
ret = pcmcia_map_mem_page(p_dev, p_dev->resource[2], p_dev->card_addr);
if (ret != 0)
goto exit1;
ipw->is_v2_card = resource_size(p_dev->resource[2]) == 0x100;
ipw->common_memory = ioremap(p_dev->resource[2]->start,
resource_size(p_dev->resource[2]));
if (!ipw->common_memory) {
ret = -ENOMEM;
goto exit1;
}
if (!request_mem_region(p_dev->resource[2]->start,
resource_size(p_dev->resource[2]),
IPWIRELESS_PCCARD_NAME)) {
ret = -EBUSY;
goto exit2;
}
p_dev->resource[3]->flags |= WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM |
WIN_ENABLE;
p_dev->resource[3]->end = 0; /* this used to be 0x1000 */
ret = pcmcia_request_window(p_dev, p_dev->resource[3], 0);
if (ret != 0)
goto exit3;
ret = pcmcia_map_mem_page(p_dev, p_dev->resource[3], 0);
if (ret != 0)
goto exit3;
ipw->attr_memory = ioremap(p_dev->resource[3]->start,
resource_size(p_dev->resource[3]));
if (!ipw->attr_memory) {
ret = -ENOMEM;
goto exit3;
}
if (!request_mem_region(p_dev->resource[3]->start,
resource_size(p_dev->resource[3]),
IPWIRELESS_PCCARD_NAME)) {
ret = -EBUSY;
goto exit4;
}
return 0;
exit4:
iounmap(ipw->attr_memory);
exit3:
release_mem_region(p_dev->resource[2]->start,
resource_size(p_dev->resource[2]));
exit2:
iounmap(ipw->common_memory);
exit1:
release_region(p_dev->resource[0]->start,
resource_size(p_dev->resource[0]));
exit:
pcmcia_disable_device(p_dev);
return ret;
}
static int config_ipwireless(struct ipw_dev *ipw)
{
struct pcmcia_device *link = ipw->link;
int ret = 0;
ipw->is_v2_card = 0;
link->config_flags |= CONF_AUTO_SET_IO | CONF_AUTO_SET_IOMEM |
CONF_ENABLE_IRQ;
ret = pcmcia_loop_config(link, ipwireless_probe, ipw);
if (ret != 0)
return ret;
INIT_WORK(&ipw->work_reboot, signalled_reboot_work);
ipwireless_init_hardware_v1(ipw->hardware, link->resource[0]->start,
ipw->attr_memory, ipw->common_memory,
ipw->is_v2_card, signalled_reboot_callback,
ipw);
ret = pcmcia_request_irq(link, ipwireless_interrupt);
if (ret != 0)
goto exit;
printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n",
ipw->is_v2_card ? "V2/V3" : "V1");
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
": I/O ports %pR, irq %d\n", link->resource[0],
(unsigned int) link->irq);
if (ipw->attr_memory && ipw->common_memory)
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
": attr memory %pR, common memory %pR\n",
link->resource[3],
link->resource[2]);
ipw->network = ipwireless_network_create(ipw->hardware);
if (!ipw->network)
goto exit;
ipw->tty = ipwireless_tty_create(ipw->hardware, ipw->network);
if (!ipw->tty)
goto exit;
ipwireless_init_hardware_v2_v3(ipw->hardware);
/*
* Do the RequestConfiguration last, because it enables interrupts.
* Then we don't get any interrupts before we're ready for them.
*/
ret = pcmcia_enable_device(link);
if (ret != 0)
goto exit;
return 0;
exit:
if (ipw->common_memory) {
release_mem_region(link->resource[2]->start,
resource_size(link->resource[2]));
iounmap(ipw->common_memory);
}
if (ipw->attr_memory) {
release_mem_region(link->resource[3]->start,
resource_size(link->resource[3]));
iounmap(ipw->attr_memory);
}
pcmcia_disable_device(link);
return -1;
}
static void release_ipwireless(struct ipw_dev *ipw)
{
release_region(ipw->link->resource[0]->start,
resource_size(ipw->link->resource[0]));
if (ipw->common_memory) {
release_mem_region(ipw->link->resource[2]->start,
resource_size(ipw->link->resource[2]));
iounmap(ipw->common_memory);
}
if (ipw->attr_memory) {
release_mem_region(ipw->link->resource[3]->start,
resource_size(ipw->link->resource[3]));
iounmap(ipw->attr_memory);
}
pcmcia_disable_device(ipw->link);
}
/*
* ipwireless_attach() creates an "instance" of the driver, allocating
* local data structures for one device (one interface). The device
* is registered with Card Services.
*
* The pcmcia_device structure is initialized, but we don't actually
* configure the card at this point -- we wait until we receive a
* card insertion event.
*/
static int ipwireless_attach(struct pcmcia_device *link)
{
struct ipw_dev *ipw;
int ret;
ipw = kzalloc_obj(struct ipw_dev);
if (!ipw)
return -ENOMEM;
ipw->link = link;
link->priv = ipw;
ipw->hardware = ipwireless_hardware_create();
if (!ipw->hardware) {
kfree(ipw);
return -ENOMEM;
}
/* RegisterClient will call config_ipwireless */
ret = config_ipwireless(ipw);
if (ret != 0) {
ipwireless_detach(link);
return ret;
}
return 0;
}
/*
* This deletes a driver "instance". The device is de-registered with
* Card Services. If it has been released, all local data structures
* are freed. Otherwise, the structures will be freed when the device
* is released.
*/
static void ipwireless_detach(struct pcmcia_device *link)
{
struct ipw_dev *ipw = link->priv;
release_ipwireless(ipw);
if (ipw->tty != NULL)
ipwireless_tty_free(ipw->tty);
if (ipw->network != NULL)
ipwireless_network_free(ipw->network);
if (ipw->hardware != NULL)
ipwireless_hardware_free(ipw->hardware);
kfree(ipw);
}
static struct pcmcia_driver me = {
.owner = THIS_MODULE,
.probe = ipwireless_attach,
.remove = ipwireless_detach,
.name = IPWIRELESS_PCCARD_NAME,
.id_table = ipw_ids
};
/*
* Module insertion : initialisation of the module.
* Register the card with cardmgr...
*/
static int __init init_ipwireless(void)
{
int ret;
ret = ipwireless_tty_init();
if (ret != 0)
return ret;
ret = pcmcia_register_driver(&me);
if (ret != 0)
ipwireless_tty_release();
return ret;
}
/*
* Module removal
*/
static void __exit exit_ipwireless(void)
{
pcmcia_unregister_driver(&me);
ipwireless_tty_release();
}
module_init(init_ipwireless);
module_exit(exit_ipwireless);
MODULE_AUTHOR(IPWIRELESS_PCMCIA_AUTHOR);
MODULE_DESCRIPTION(IPWIRELESS_PCCARD_NAME " " IPWIRELESS_PCMCIA_VERSION);
MODULE_LICENSE("GPL");

View File

@ -1,66 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* IPWireless 3G PCMCIA Network Driver
*
* Original code
* by Stephen Blackheath <stephen@blacksapphire.com>,
* Ben Martel <benm@symmetric.co.nz>
*
* Copyrighted as follows:
* Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
*
* Various driver changes and rewrites, port to new kernels
* Copyright (C) 2006-2007 Jiri Kosina
*
* Misc code cleanups and updates
* Copyright (C) 2007 David Sterba
*/
#ifndef _IPWIRELESS_CS_H_
#define _IPWIRELESS_CS_H_
#include <linux/sched.h>
#include <linux/types.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#include "hardware.h"
#define IPWIRELESS_PCCARD_NAME "ipwireless"
#define IPWIRELESS_PCMCIA_VERSION "1.1"
#define IPWIRELESS_PCMCIA_AUTHOR \
"Stephen Blackheath, Ben Martel, Jiri Kosina and David Sterba"
#define IPWIRELESS_TX_QUEUE_SIZE 262144
#define IPWIRELESS_RX_QUEUE_SIZE 262144
#define IPWIRELESS_STATE_DEBUG
struct ipw_hardware;
struct ipw_network;
struct ipw_tty;
struct ipw_dev {
struct pcmcia_device *link;
int is_v2_card;
void __iomem *attr_memory;
void __iomem *common_memory;
/* Hardware context */
struct ipw_hardware *hardware;
/* Network layer context */
struct ipw_network *network;
/* TTY device context */
struct ipw_tty *tty;
struct work_struct work_reboot;
};
/* Module parametres */
extern int ipwireless_debug;
extern int ipwireless_loopback;
extern int ipwireless_out_queue;
#endif

View File

@ -1,517 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* IPWireless 3G PCMCIA Network Driver
*
* Original code
* by Stephen Blackheath <stephen@blacksapphire.com>,
* Ben Martel <benm@symmetric.co.nz>
*
* Copyrighted as follows:
* Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
*
* Various driver changes and rewrites, port to new kernels
* Copyright (C) 2006-2007 Jiri Kosina
*
* Misc code cleanups and updates
* Copyright (C) 2007 David Sterba
*/
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/netdevice.h>
#include <linux/ppp_channel.h>
#include <linux/ppp_defs.h>
#include <linux/slab.h>
#include <linux/ppp-ioctl.h>
#include <linux/skbuff.h>
#include "network.h"
#include "hardware.h"
#include "main.h"
#include "tty.h"
#define MAX_ASSOCIATED_TTYS 2
#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
struct ipw_network {
/* Hardware context, used for calls to hardware layer. */
struct ipw_hardware *hardware;
/* Context for kernel 'generic_ppp' functionality */
struct ppp_channel *ppp_channel;
/* tty context connected with IPW console */
struct ipw_tty *associated_ttys[NO_OF_IPW_CHANNELS][MAX_ASSOCIATED_TTYS];
/* True if ppp needs waking up once we're ready to xmit */
int ppp_blocked;
/* Number of packets queued up in hardware module. */
int outgoing_packets_queued;
/* Spinlock to avoid interrupts during shutdown */
spinlock_t lock;
struct mutex close_lock;
/* PPP ioctl data, not actually used anywere */
unsigned int flags;
unsigned int rbits;
u32 xaccm[8];
u32 raccm;
int mru;
int shutting_down;
unsigned int ras_control_lines;
struct work_struct work_go_online;
struct work_struct work_go_offline;
};
static void notify_packet_sent(void *callback_data, unsigned int packet_length)
{
struct ipw_network *network = callback_data;
unsigned long flags;
spin_lock_irqsave(&network->lock, flags);
network->outgoing_packets_queued--;
if (network->ppp_channel != NULL) {
if (network->ppp_blocked) {
network->ppp_blocked = 0;
spin_unlock_irqrestore(&network->lock, flags);
ppp_output_wakeup(network->ppp_channel);
if (ipwireless_debug)
printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
": ppp unblocked\n");
} else
spin_unlock_irqrestore(&network->lock, flags);
} else
spin_unlock_irqrestore(&network->lock, flags);
}
/*
* Called by the ppp system when it has a packet to send to the hardware.
*/
static int ipwireless_ppp_start_xmit(struct ppp_channel *ppp_channel,
struct sk_buff *skb)
{
struct ipw_network *network = ppp_channel->private;
unsigned long flags;
spin_lock_irqsave(&network->lock, flags);
if (network->outgoing_packets_queued < ipwireless_out_queue) {
unsigned char *buf;
static unsigned char header[] = {
PPP_ALLSTATIONS, /* 0xff */
PPP_UI, /* 0x03 */
};
int ret;
network->outgoing_packets_queued++;
spin_unlock_irqrestore(&network->lock, flags);
/*
* If we have the requested amount of headroom in the skb we
* were handed, then we can add the header efficiently.
*/
if (skb_headroom(skb) >= 2) {
memcpy(skb_push(skb, 2), header, 2);
ret = ipwireless_send_packet(network->hardware,
IPW_CHANNEL_RAS, skb->data,
skb->len,
notify_packet_sent,
network);
if (ret < 0) {
skb_pull(skb, 2);
return 0;
}
} else {
/* Otherwise (rarely) we do it inefficiently. */
buf = kmalloc(skb->len + 2, GFP_ATOMIC);
if (!buf)
return 0;
memcpy(buf + 2, skb->data, skb->len);
memcpy(buf, header, 2);
ret = ipwireless_send_packet(network->hardware,
IPW_CHANNEL_RAS, buf,
skb->len + 2,
notify_packet_sent,
network);
kfree(buf);
if (ret < 0)
return 0;
}
kfree_skb(skb);
return 1;
} else {
/*
* Otherwise reject the packet, and flag that the ppp system
* needs to be unblocked once we are ready to send.
*/
network->ppp_blocked = 1;
spin_unlock_irqrestore(&network->lock, flags);
if (ipwireless_debug)
printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": ppp blocked\n");
return 0;
}
}
/* Handle an ioctl call that has come in via ppp. (copy of ppp_async_ioctl() */
static int ipwireless_ppp_ioctl(struct ppp_channel *ppp_channel,
unsigned int cmd, unsigned long arg)
{
struct ipw_network *network = ppp_channel->private;
int err, val;
u32 accm[8];
int __user *user_arg = (int __user *) arg;
err = -EFAULT;
switch (cmd) {
case PPPIOCGFLAGS:
val = network->flags | network->rbits;
if (put_user(val, user_arg))
break;
err = 0;
break;
case PPPIOCSFLAGS:
if (get_user(val, user_arg))
break;
network->flags = val & ~SC_RCV_BITS;
network->rbits = val & SC_RCV_BITS;
err = 0;
break;
case PPPIOCGASYNCMAP:
if (put_user(network->xaccm[0], user_arg))
break;
err = 0;
break;
case PPPIOCSASYNCMAP:
if (get_user(network->xaccm[0], user_arg))
break;
err = 0;
break;
case PPPIOCGRASYNCMAP:
if (put_user(network->raccm, user_arg))
break;
err = 0;
break;
case PPPIOCSRASYNCMAP:
if (get_user(network->raccm, user_arg))
break;
err = 0;
break;
case PPPIOCGXASYNCMAP:
if (copy_to_user((void __user *) arg, network->xaccm,
sizeof(network->xaccm)))
break;
err = 0;
break;
case PPPIOCSXASYNCMAP:
if (copy_from_user(accm, (void __user *) arg, sizeof(accm)))
break;
accm[2] &= ~0x40000000U; /* can't escape 0x5e */
accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */
memcpy(network->xaccm, accm, sizeof(network->xaccm));
err = 0;
break;
case PPPIOCGMRU:
if (put_user(network->mru, user_arg))
break;
err = 0;
break;
case PPPIOCSMRU:
if (get_user(val, user_arg))
break;
if (val < PPP_MRU)
val = PPP_MRU;
network->mru = val;
err = 0;
break;
default:
err = -ENOTTY;
}
return err;
}
static const struct ppp_channel_ops ipwireless_ppp_channel_ops = {
.start_xmit = ipwireless_ppp_start_xmit,
.ioctl = ipwireless_ppp_ioctl
};
static void do_go_online(struct work_struct *work_go_online)
{
struct ipw_network *network =
container_of(work_go_online, struct ipw_network,
work_go_online);
unsigned long flags;
spin_lock_irqsave(&network->lock, flags);
if (!network->ppp_channel) {
struct ppp_channel *channel;
spin_unlock_irqrestore(&network->lock, flags);
channel = kzalloc_obj(struct ppp_channel);
if (!channel) {
printk(KERN_ERR IPWIRELESS_PCCARD_NAME
": unable to allocate PPP channel\n");
return;
}
channel->private = network;
channel->mtu = 16384; /* Wild guess */
channel->hdrlen = 2;
channel->ops = &ipwireless_ppp_channel_ops;
network->flags = 0;
network->rbits = 0;
network->mru = PPP_MRU;
memset(network->xaccm, 0, sizeof(network->xaccm));
network->xaccm[0] = ~0U;
network->xaccm[3] = 0x60000000U;
network->raccm = ~0U;
if (ppp_register_channel(channel) < 0) {
printk(KERN_ERR IPWIRELESS_PCCARD_NAME
": unable to register PPP channel\n");
kfree(channel);
return;
}
spin_lock_irqsave(&network->lock, flags);
network->ppp_channel = channel;
}
spin_unlock_irqrestore(&network->lock, flags);
}
static void do_go_offline(struct work_struct *work_go_offline)
{
struct ipw_network *network =
container_of(work_go_offline, struct ipw_network,
work_go_offline);
unsigned long flags;
mutex_lock(&network->close_lock);
spin_lock_irqsave(&network->lock, flags);
if (network->ppp_channel != NULL) {
struct ppp_channel *channel = network->ppp_channel;
network->ppp_channel = NULL;
spin_unlock_irqrestore(&network->lock, flags);
mutex_unlock(&network->close_lock);
ppp_unregister_channel(channel);
} else {
spin_unlock_irqrestore(&network->lock, flags);
mutex_unlock(&network->close_lock);
}
}
void ipwireless_network_notify_control_line_change(struct ipw_network *network,
unsigned int channel_idx,
unsigned int control_lines,
unsigned int changed_mask)
{
int i;
if (channel_idx == IPW_CHANNEL_RAS)
network->ras_control_lines = control_lines;
for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) {
struct ipw_tty *tty =
network->associated_ttys[channel_idx][i];
/*
* If it's associated with a tty (other than the RAS channel
* when we're online), then send the data to that tty. The RAS
* channel's data is handled above - it always goes through
* ppp_generic.
*/
if (tty)
ipwireless_tty_notify_control_line_change(tty,
channel_idx,
control_lines,
changed_mask);
}
}
/*
* Some versions of firmware stuff packets with 0xff 0x03 (PPP: ALLSTATIONS, UI)
* bytes, which are required on sent packet, but not always present on received
* packets
*/
static struct sk_buff *ipw_packet_received_skb(unsigned char *data,
unsigned int length)
{
struct sk_buff *skb;
if (length > 2 && data[0] == PPP_ALLSTATIONS && data[1] == PPP_UI) {
length -= 2;
data += 2;
}
skb = dev_alloc_skb(length + 4);
if (skb == NULL)
return NULL;
skb_reserve(skb, 2);
skb_put_data(skb, data, length);
return skb;
}
void ipwireless_network_packet_received(struct ipw_network *network,
unsigned int channel_idx,
unsigned char *data,
unsigned int length)
{
int i;
unsigned long flags;
for (i = 0; i < MAX_ASSOCIATED_TTYS; i++) {
struct ipw_tty *tty = network->associated_ttys[channel_idx][i];
if (!tty)
continue;
/*
* If it's associated with a tty (other than the RAS channel
* when we're online), then send the data to that tty. The RAS
* channel's data is handled above - it always goes through
* ppp_generic.
*/
if (channel_idx == IPW_CHANNEL_RAS
&& (network->ras_control_lines &
IPW_CONTROL_LINE_DCD) != 0
&& ipwireless_tty_is_modem(tty)) {
/*
* If data came in on the RAS channel and this tty is
* the modem tty, and we are online, then we send it to
* the PPP layer.
*/
mutex_lock(&network->close_lock);
spin_lock_irqsave(&network->lock, flags);
if (network->ppp_channel != NULL) {
struct sk_buff *skb;
spin_unlock_irqrestore(&network->lock,
flags);
/* Send the data to the ppp_generic module. */
skb = ipw_packet_received_skb(data, length);
if (skb)
ppp_input(network->ppp_channel, skb);
} else
spin_unlock_irqrestore(&network->lock,
flags);
mutex_unlock(&network->close_lock);
}
/* Otherwise we send it out the tty. */
else
ipwireless_tty_received(tty, data, length);
}
}
struct ipw_network *ipwireless_network_create(struct ipw_hardware *hw)
{
struct ipw_network *network =
kzalloc_obj(struct ipw_network);
if (!network)
return NULL;
spin_lock_init(&network->lock);
mutex_init(&network->close_lock);
network->hardware = hw;
INIT_WORK(&network->work_go_online, do_go_online);
INIT_WORK(&network->work_go_offline, do_go_offline);
ipwireless_associate_network(hw, network);
return network;
}
void ipwireless_network_free(struct ipw_network *network)
{
network->shutting_down = 1;
ipwireless_ppp_close(network);
flush_work(&network->work_go_online);
flush_work(&network->work_go_offline);
ipwireless_stop_interrupts(network->hardware);
ipwireless_associate_network(network->hardware, NULL);
kfree(network);
}
void ipwireless_associate_network_tty(struct ipw_network *network,
unsigned int channel_idx,
struct ipw_tty *tty)
{
int i;
for (i = 0; i < MAX_ASSOCIATED_TTYS; i++)
if (network->associated_ttys[channel_idx][i] == NULL) {
network->associated_ttys[channel_idx][i] = tty;
break;
}
}
void ipwireless_disassociate_network_ttys(struct ipw_network *network,
unsigned int channel_idx)
{
int i;
for (i = 0; i < MAX_ASSOCIATED_TTYS; i++)
network->associated_ttys[channel_idx][i] = NULL;
}
void ipwireless_ppp_open(struct ipw_network *network)
{
if (ipwireless_debug)
printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": online\n");
schedule_work(&network->work_go_online);
}
void ipwireless_ppp_close(struct ipw_network *network)
{
/* Disconnect from the wireless network. */
if (ipwireless_debug)
printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME ": offline\n");
schedule_work(&network->work_go_offline);
}
int ipwireless_ppp_channel_index(struct ipw_network *network)
{
int ret = -1;
unsigned long flags;
spin_lock_irqsave(&network->lock, flags);
if (network->ppp_channel != NULL)
ret = ppp_channel_index(network->ppp_channel);
spin_unlock_irqrestore(&network->lock, flags);
return ret;
}
int ipwireless_ppp_unit_number(struct ipw_network *network)
{
int ret = -1;
unsigned long flags;
spin_lock_irqsave(&network->lock, flags);
if (network->ppp_channel != NULL)
ret = ppp_unit_number(network->ppp_channel);
spin_unlock_irqrestore(&network->lock, flags);
return ret;
}
int ipwireless_ppp_mru(const struct ipw_network *network)
{
return network->mru;
}

View File

@ -1,54 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* IPWireless 3G PCMCIA Network Driver
*
* Original code
* by Stephen Blackheath <stephen@blacksapphire.com>,
* Ben Martel <benm@symmetric.co.nz>
*
* Copyrighted as follows:
* Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
*
* Various driver changes and rewrites, port to new kernels
* Copyright (C) 2006-2007 Jiri Kosina
*
* Misc code cleanups and updates
* Copyright (C) 2007 David Sterba
*/
#ifndef _IPWIRELESS_CS_NETWORK_H_
#define _IPWIRELESS_CS_NETWORK_H_
#include <linux/types.h>
struct ipw_network;
struct ipw_tty;
struct ipw_hardware;
/* Definitions of the different channels on the PCMCIA UE */
#define IPW_CHANNEL_RAS 0
#define IPW_CHANNEL_DIALLER 1
#define IPW_CHANNEL_CONSOLE 2
#define NO_OF_IPW_CHANNELS 5
void ipwireless_network_notify_control_line_change(struct ipw_network *net,
unsigned int channel_idx, unsigned int control_lines,
unsigned int control_mask);
void ipwireless_network_packet_received(struct ipw_network *net,
unsigned int channel_idx, unsigned char *data,
unsigned int length);
struct ipw_network *ipwireless_network_create(struct ipw_hardware *hw);
void ipwireless_network_free(struct ipw_network *net);
void ipwireless_associate_network_tty(struct ipw_network *net,
unsigned int channel_idx, struct ipw_tty *tty);
void ipwireless_disassociate_network_ttys(struct ipw_network *net,
unsigned int channel_idx);
void ipwireless_ppp_open(struct ipw_network *net);
void ipwireless_ppp_close(struct ipw_network *net);
int ipwireless_ppp_channel_index(struct ipw_network *net);
int ipwireless_ppp_unit_number(struct ipw_network *net);
int ipwireless_ppp_mru(const struct ipw_network *net);
#endif

View File

@ -1,109 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* IPWireless 3G PCMCIA Network Driver
*
* Original code
* by Stephen Blackheath <stephen@blacksapphire.com>,
* Ben Martel <benm@symmetric.co.nz>
*
* Copyrighted as follows:
* Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
*
* Various driver changes and rewrites, port to new kernels
* Copyright (C) 2006-2007 Jiri Kosina
*
* Misc code cleanups and updates
* Copyright (C) 2007 David Sterba
*/
#ifndef _IPWIRELESS_CS_SETUP_PROTOCOL_H_
#define _IPWIRELESS_CS_SETUP_PROTOCOL_H_
/* Version of the setup protocol and transport protocols */
#define TL_SETUP_VERSION 1
#define TL_SETUP_VERSION_QRY_TMO 1000
#define TL_SETUP_MAX_VERSION_QRY 30
/* Message numbers 0-9 are obsoleted and must not be reused! */
#define TL_SETUP_SIGNO_GET_VERSION_QRY 10
#define TL_SETUP_SIGNO_GET_VERSION_RSP 11
#define TL_SETUP_SIGNO_CONFIG_MSG 12
#define TL_SETUP_SIGNO_CONFIG_DONE_MSG 13
#define TL_SETUP_SIGNO_OPEN_MSG 14
#define TL_SETUP_SIGNO_CLOSE_MSG 15
#define TL_SETUP_SIGNO_INFO_MSG 20
#define TL_SETUP_SIGNO_INFO_MSG_ACK 21
#define TL_SETUP_SIGNO_REBOOT_MSG 22
#define TL_SETUP_SIGNO_REBOOT_MSG_ACK 23
/* Synchronous start-messages */
struct tl_setup_get_version_qry {
unsigned char sig_no; /* TL_SETUP_SIGNO_GET_VERSION_QRY */
} __attribute__ ((__packed__));
struct tl_setup_get_version_rsp {
unsigned char sig_no; /* TL_SETUP_SIGNO_GET_VERSION_RSP */
unsigned char version; /* TL_SETUP_VERSION */
} __attribute__ ((__packed__));
struct tl_setup_config_msg {
unsigned char sig_no; /* TL_SETUP_SIGNO_CONFIG_MSG */
unsigned char port_no;
unsigned char prio_data;
unsigned char prio_ctrl;
} __attribute__ ((__packed__));
struct tl_setup_config_done_msg {
unsigned char sig_no; /* TL_SETUP_SIGNO_CONFIG_DONE_MSG */
} __attribute__ ((__packed__));
/* Asynchronous messages */
struct tl_setup_open_msg {
unsigned char sig_no; /* TL_SETUP_SIGNO_OPEN_MSG */
unsigned char port_no;
} __attribute__ ((__packed__));
struct tl_setup_close_msg {
unsigned char sig_no; /* TL_SETUP_SIGNO_CLOSE_MSG */
unsigned char port_no;
} __attribute__ ((__packed__));
/* Driver type - for use in tl_setup_info_msg.driver_type */
#define COMM_DRIVER 0
#define NDISWAN_DRIVER 1
#define NDISWAN_DRIVER_MAJOR_VERSION 2
#define NDISWAN_DRIVER_MINOR_VERSION 0
/*
* It should not matter when this message comes over as we just store the
* results and send the ACK.
*/
struct tl_setup_info_msg {
unsigned char sig_no; /* TL_SETUP_SIGNO_INFO_MSG */
unsigned char driver_type;
unsigned char major_version;
unsigned char minor_version;
} __attribute__ ((__packed__));
struct tl_setup_info_msgAck {
unsigned char sig_no; /* TL_SETUP_SIGNO_INFO_MSG_ACK */
} __attribute__ ((__packed__));
struct TlSetupRebootMsgAck {
unsigned char sig_no; /* TL_SETUP_SIGNO_REBOOT_MSG_ACK */
} __attribute__ ((__packed__));
/* Define a union of all the msgs that the driver can receive from the card.*/
union ipw_setup_rx_msg {
unsigned char sig_no;
struct tl_setup_get_version_rsp version_rsp_msg;
struct tl_setup_open_msg open_msg;
struct tl_setup_close_msg close_msg;
struct tl_setup_info_msg InfoMsg;
struct tl_setup_info_msgAck info_msg_ack;
} __attribute__ ((__packed__));
#endif /* _IPWIRELESS_CS_SETUP_PROTOCOL_H_ */

View File

@ -1,627 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* IPWireless 3G PCMCIA Network Driver
*
* Original code
* by Stephen Blackheath <stephen@blacksapphire.com>,
* Ben Martel <benm@symmetric.co.nz>
*
* Copyrighted as follows:
* Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
*
* Various driver changes and rewrites, port to new kernels
* Copyright (C) 2006-2007 Jiri Kosina
*
* Misc code cleanups and updates
* Copyright (C) 2007 David Sterba
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/ppp_defs.h>
#include <linux/if.h>
#include <linux/ppp-ioctl.h>
#include <linux/sched.h>
#include <linux/serial.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/uaccess.h>
#include "tty.h"
#include "network.h"
#include "hardware.h"
#include "main.h"
#define IPWIRELESS_PCMCIA_START (0)
#define IPWIRELESS_PCMCIA_MINORS (24)
#define IPWIRELESS_PCMCIA_MINOR_RANGE (8)
#define TTYTYPE_MODEM (0)
#define TTYTYPE_MONITOR (1)
#define TTYTYPE_RAS_RAW (2)
struct ipw_tty {
struct tty_port port;
int index;
struct ipw_hardware *hardware;
unsigned int channel_idx;
unsigned int secondary_channel_idx;
int tty_type;
struct ipw_network *network;
unsigned int control_lines;
struct mutex ipw_tty_mutex;
int tx_bytes_queued;
};
static struct ipw_tty *ttys[IPWIRELESS_PCMCIA_MINORS];
static struct tty_driver *ipw_tty_driver;
static char *tty_type_name(int tty_type)
{
static char *channel_names[] = {
"modem",
"monitor",
"RAS-raw"
};
return channel_names[tty_type];
}
static struct ipw_tty *get_tty(int index)
{
/*
* The 'ras_raw' channel is only available when 'loopback' mode
* is enabled.
* Number of minor starts with 16 (_RANGE * _RAS_RAW).
*/
if (!ipwireless_loopback && index >=
IPWIRELESS_PCMCIA_MINOR_RANGE * TTYTYPE_RAS_RAW)
return NULL;
return ttys[index];
}
static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
{
struct ipw_tty *tty = get_tty(linux_tty->index);
if (!tty)
return -ENODEV;
mutex_lock(&tty->ipw_tty_mutex);
if (tty->port.count == 0)
tty->tx_bytes_queued = 0;
tty->port.count++;
tty->port.tty = linux_tty;
linux_tty->driver_data = tty;
if (tty->tty_type == TTYTYPE_MODEM)
ipwireless_ppp_open(tty->network);
mutex_unlock(&tty->ipw_tty_mutex);
return 0;
}
static void do_ipw_close(struct ipw_tty *tty)
{
tty->port.count--;
if (tty->port.count == 0) {
struct tty_struct *linux_tty = tty->port.tty;
if (linux_tty != NULL) {
tty->port.tty = NULL;
linux_tty->driver_data = NULL;
if (tty->tty_type == TTYTYPE_MODEM)
ipwireless_ppp_close(tty->network);
}
}
}
static void ipw_hangup(struct tty_struct *linux_tty)
{
struct ipw_tty *tty = linux_tty->driver_data;
if (!tty)
return;
mutex_lock(&tty->ipw_tty_mutex);
if (tty->port.count == 0) {
mutex_unlock(&tty->ipw_tty_mutex);
return;
}
do_ipw_close(tty);
mutex_unlock(&tty->ipw_tty_mutex);
}
static void ipw_close(struct tty_struct *linux_tty, struct file *filp)
{
ipw_hangup(linux_tty);
}
/* Take data received from hardware, and send it out the tty */
void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
unsigned int length)
{
int work = 0;
mutex_lock(&tty->ipw_tty_mutex);
if (!tty->port.count) {
mutex_unlock(&tty->ipw_tty_mutex);
return;
}
mutex_unlock(&tty->ipw_tty_mutex);
work = tty_insert_flip_string(&tty->port, data, length);
if (work != length)
printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
": %d chars not inserted to flip buffer!\n",
length - work);
if (work)
tty_flip_buffer_push(&tty->port);
}
static void ipw_write_packet_sent_callback(void *callback_data,
unsigned int packet_length)
{
struct ipw_tty *tty = callback_data;
/*
* Packet has been sent, so we subtract the number of bytes from our
* tally of outstanding TX bytes.
*/
tty->tx_bytes_queued -= packet_length;
}
static ssize_t ipw_write(struct tty_struct *linux_tty, const u8 *buf,
size_t count)
{
struct ipw_tty *tty = linux_tty->driver_data;
int room, ret;
if (!tty)
return -ENODEV;
mutex_lock(&tty->ipw_tty_mutex);
if (!tty->port.count) {
mutex_unlock(&tty->ipw_tty_mutex);
return -EINVAL;
}
room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
if (room < 0)
room = 0;
/* Don't allow caller to write any more than we have room for */
if (count > room)
count = room;
if (count == 0) {
mutex_unlock(&tty->ipw_tty_mutex);
return 0;
}
ret = ipwireless_send_packet(tty->hardware, IPW_CHANNEL_RAS,
buf, count,
ipw_write_packet_sent_callback, tty);
if (ret < 0) {
mutex_unlock(&tty->ipw_tty_mutex);
return 0;
}
tty->tx_bytes_queued += count;
mutex_unlock(&tty->ipw_tty_mutex);
return count;
}
static unsigned int ipw_write_room(struct tty_struct *linux_tty)
{
struct ipw_tty *tty = linux_tty->driver_data;
int room;
/* FIXME: Exactly how is the tty object locked here .. */
if (!tty)
return 0;
if (!tty->port.count)
return 0;
room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
if (room < 0)
room = 0;
return room;
}
static int ipwireless_get_serial_info(struct tty_struct *linux_tty,
struct serial_struct *ss)
{
struct ipw_tty *tty = linux_tty->driver_data;
if (!tty)
return -ENODEV;
if (!tty->port.count)
return -EINVAL;
ss->type = PORT_UNKNOWN;
ss->line = tty->index;
ss->baud_base = 115200;
return 0;
}
static int ipwireless_set_serial_info(struct tty_struct *linux_tty,
struct serial_struct *ss)
{
return 0; /* Keeps the PCMCIA scripts happy. */
}
static unsigned int ipw_chars_in_buffer(struct tty_struct *linux_tty)
{
struct ipw_tty *tty = linux_tty->driver_data;
if (!tty)
return 0;
if (!tty->port.count)
return 0;
return tty->tx_bytes_queued;
}
static int get_control_lines(struct ipw_tty *tty)
{
unsigned int my = tty->control_lines;
unsigned int out = 0;
if (my & IPW_CONTROL_LINE_RTS)
out |= TIOCM_RTS;
if (my & IPW_CONTROL_LINE_DTR)
out |= TIOCM_DTR;
if (my & IPW_CONTROL_LINE_CTS)
out |= TIOCM_CTS;
if (my & IPW_CONTROL_LINE_DSR)
out |= TIOCM_DSR;
if (my & IPW_CONTROL_LINE_DCD)
out |= TIOCM_CD;
return out;
}
static int set_control_lines(struct ipw_tty *tty, unsigned int set,
unsigned int clear)
{
int ret;
if (set & TIOCM_RTS) {
ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 1);
if (ret)
return ret;
if (tty->secondary_channel_idx != -1) {
ret = ipwireless_set_RTS(tty->hardware,
tty->secondary_channel_idx, 1);
if (ret)
return ret;
}
}
if (set & TIOCM_DTR) {
ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 1);
if (ret)
return ret;
if (tty->secondary_channel_idx != -1) {
ret = ipwireless_set_DTR(tty->hardware,
tty->secondary_channel_idx, 1);
if (ret)
return ret;
}
}
if (clear & TIOCM_RTS) {
ret = ipwireless_set_RTS(tty->hardware, tty->channel_idx, 0);
if (tty->secondary_channel_idx != -1) {
ret = ipwireless_set_RTS(tty->hardware,
tty->secondary_channel_idx, 0);
if (ret)
return ret;
}
}
if (clear & TIOCM_DTR) {
ret = ipwireless_set_DTR(tty->hardware, tty->channel_idx, 0);
if (tty->secondary_channel_idx != -1) {
ret = ipwireless_set_DTR(tty->hardware,
tty->secondary_channel_idx, 0);
if (ret)
return ret;
}
}
return 0;
}
static int ipw_tiocmget(struct tty_struct *linux_tty)
{
struct ipw_tty *tty = linux_tty->driver_data;
/* FIXME: Exactly how is the tty object locked here .. */
if (!tty)
return -ENODEV;
if (!tty->port.count)
return -EINVAL;
return get_control_lines(tty);
}
static int
ipw_tiocmset(struct tty_struct *linux_tty,
unsigned int set, unsigned int clear)
{
struct ipw_tty *tty = linux_tty->driver_data;
/* FIXME: Exactly how is the tty object locked here .. */
if (!tty)
return -ENODEV;
if (!tty->port.count)
return -EINVAL;
return set_control_lines(tty, set, clear);
}
static int ipw_ioctl(struct tty_struct *linux_tty,
unsigned int cmd, unsigned long arg)
{
struct ipw_tty *tty = linux_tty->driver_data;
if (!tty)
return -ENODEV;
if (!tty->port.count)
return -EINVAL;
/* FIXME: Exactly how is the tty object locked here .. */
if (tty->tty_type == TTYTYPE_MODEM) {
switch (cmd) {
case PPPIOCGCHAN:
{
int chan = ipwireless_ppp_channel_index(
tty->network);
if (chan < 0)
return -ENODEV;
if (put_user(chan, (int __user *) arg))
return -EFAULT;
}
return 0;
case PPPIOCGUNIT:
{
int unit = ipwireless_ppp_unit_number(
tty->network);
if (unit < 0)
return -ENODEV;
if (put_user(unit, (int __user *) arg))
return -EFAULT;
}
return 0;
case FIONREAD:
{
int val = 0;
if (put_user(val, (int __user *) arg))
return -EFAULT;
}
return 0;
case TCFLSH:
return tty_perform_flush(linux_tty, arg);
}
}
return -ENOIOCTLCMD;
}
static int add_tty(int j,
struct ipw_hardware *hardware,
struct ipw_network *network, int channel_idx,
int secondary_channel_idx, int tty_type)
{
ttys[j] = kzalloc_obj(struct ipw_tty);
if (!ttys[j])
return -ENOMEM;
ttys[j]->index = j;
ttys[j]->hardware = hardware;
ttys[j]->channel_idx = channel_idx;
ttys[j]->secondary_channel_idx = secondary_channel_idx;
ttys[j]->network = network;
ttys[j]->tty_type = tty_type;
mutex_init(&ttys[j]->ipw_tty_mutex);
tty_port_init(&ttys[j]->port);
tty_port_register_device(&ttys[j]->port, ipw_tty_driver, j, NULL);
ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
if (secondary_channel_idx != -1)
ipwireless_associate_network_tty(network,
secondary_channel_idx,
ttys[j]);
/* check if we provide raw device (if loopback is enabled) */
if (get_tty(j))
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
": registering %s device ttyIPWp%d\n",
tty_type_name(tty_type), j);
return 0;
}
struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hardware,
struct ipw_network *network)
{
int i, j;
for (i = 0; i < IPWIRELESS_PCMCIA_MINOR_RANGE; i++) {
int allfree = 1;
for (j = i; j < IPWIRELESS_PCMCIA_MINORS;
j += IPWIRELESS_PCMCIA_MINOR_RANGE)
if (ttys[j] != NULL) {
allfree = 0;
break;
}
if (allfree) {
j = i;
if (add_tty(j, hardware, network,
IPW_CHANNEL_DIALLER, IPW_CHANNEL_RAS,
TTYTYPE_MODEM))
return NULL;
j += IPWIRELESS_PCMCIA_MINOR_RANGE;
if (add_tty(j, hardware, network,
IPW_CHANNEL_DIALLER, -1,
TTYTYPE_MONITOR))
return NULL;
j += IPWIRELESS_PCMCIA_MINOR_RANGE;
if (add_tty(j, hardware, network,
IPW_CHANNEL_RAS, -1,
TTYTYPE_RAS_RAW))
return NULL;
return ttys[i];
}
}
return NULL;
}
/*
* Must be called before ipwireless_network_free().
*/
void ipwireless_tty_free(struct ipw_tty *tty)
{
int j;
struct ipw_network *network = ttys[tty->index]->network;
for (j = tty->index; j < IPWIRELESS_PCMCIA_MINORS;
j += IPWIRELESS_PCMCIA_MINOR_RANGE) {
struct ipw_tty *ttyj = ttys[j];
if (ttyj) {
mutex_lock(&ttyj->ipw_tty_mutex);
if (get_tty(j))
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
": deregistering %s device ttyIPWp%d\n",
tty_type_name(ttyj->tty_type), j);
if (ttyj->port.tty != NULL) {
mutex_unlock(&ttyj->ipw_tty_mutex);
tty_vhangup(ttyj->port.tty);
/* FIXME: Exactly how is the tty object locked here
against a parallel ioctl etc */
/* FIXME2: hangup does not mean all processes
* are gone */
mutex_lock(&ttyj->ipw_tty_mutex);
}
while (ttyj->port.count)
do_ipw_close(ttyj);
ipwireless_disassociate_network_ttys(network,
ttyj->channel_idx);
tty_unregister_device(ipw_tty_driver, j);
tty_port_destroy(&ttyj->port);
ttys[j] = NULL;
mutex_unlock(&ttyj->ipw_tty_mutex);
kfree(ttyj);
}
}
}
static const struct tty_operations tty_ops = {
.open = ipw_open,
.close = ipw_close,
.hangup = ipw_hangup,
.write = ipw_write,
.write_room = ipw_write_room,
.ioctl = ipw_ioctl,
.chars_in_buffer = ipw_chars_in_buffer,
.tiocmget = ipw_tiocmget,
.tiocmset = ipw_tiocmset,
.set_serial = ipwireless_set_serial_info,
.get_serial = ipwireless_get_serial_info,
};
int ipwireless_tty_init(void)
{
int result;
ipw_tty_driver = tty_alloc_driver(IPWIRELESS_PCMCIA_MINORS,
TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV);
if (IS_ERR(ipw_tty_driver))
return PTR_ERR(ipw_tty_driver);
ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME;
ipw_tty_driver->name = "ttyIPWp";
ipw_tty_driver->major = 0;
ipw_tty_driver->minor_start = IPWIRELESS_PCMCIA_START;
ipw_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
ipw_tty_driver->subtype = SERIAL_TYPE_NORMAL;
ipw_tty_driver->init_termios = tty_std_termios;
ipw_tty_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
ipw_tty_driver->init_termios.c_ispeed = 9600;
ipw_tty_driver->init_termios.c_ospeed = 9600;
tty_set_operations(ipw_tty_driver, &tty_ops);
result = tty_register_driver(ipw_tty_driver);
if (result) {
printk(KERN_ERR IPWIRELESS_PCCARD_NAME
": failed to register tty driver\n");
tty_driver_kref_put(ipw_tty_driver);
return result;
}
return 0;
}
void ipwireless_tty_release(void)
{
tty_unregister_driver(ipw_tty_driver);
tty_driver_kref_put(ipw_tty_driver);
}
int ipwireless_tty_is_modem(struct ipw_tty *tty)
{
return tty->tty_type == TTYTYPE_MODEM;
}
void
ipwireless_tty_notify_control_line_change(struct ipw_tty *tty,
unsigned int channel_idx,
unsigned int control_lines,
unsigned int changed_mask)
{
unsigned int old_control_lines = tty->control_lines;
tty->control_lines = (tty->control_lines & ~changed_mask)
| (control_lines & changed_mask);
/*
* If DCD is de-asserted, we close the tty so pppd can tell that we
* have gone offline.
*/
if ((old_control_lines & IPW_CONTROL_LINE_DCD)
&& !(tty->control_lines & IPW_CONTROL_LINE_DCD)
&& tty->port.tty) {
tty_hangup(tty->port.tty);
}
}

View File

@ -1,46 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* IPWireless 3G PCMCIA Network Driver
*
* Original code
* by Stephen Blackheath <stephen@blacksapphire.com>,
* Ben Martel <benm@symmetric.co.nz>
*
* Copyrighted as follows:
* Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
*
* Various driver changes and rewrites, port to new kernels
* Copyright (C) 2006-2007 Jiri Kosina
*
* Misc code cleanups and updates
* Copyright (C) 2007 David Sterba
*/
#ifndef _IPWIRELESS_CS_TTY_H_
#define _IPWIRELESS_CS_TTY_H_
#include <linux/types.h>
#include <linux/sched.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
struct ipw_tty;
struct ipw_network;
struct ipw_hardware;
int ipwireless_tty_init(void);
void ipwireless_tty_release(void);
struct ipw_tty *ipwireless_tty_create(struct ipw_hardware *hw,
struct ipw_network *net);
void ipwireless_tty_free(struct ipw_tty *tty);
void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
unsigned int length);
int ipwireless_tty_is_modem(struct ipw_tty *tty);
void ipwireless_tty_notify_control_line_change(struct ipw_tty *tty,
unsigned int channel_idx,
unsigned int control_lines,
unsigned int changed_mask);
#endif

View File

@ -651,11 +651,11 @@ static int acpi_serdev_do_lookup(struct acpi_device *adev,
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list,
acpi_serdev_parse_resource, lookup);
acpi_dev_free_resource_list(&resource_list);
if (ret < 0)
return -EINVAL;
acpi_dev_free_resource_list(&resource_list);
return 0;
}

View File

@ -177,7 +177,9 @@ static unsigned int __maybe_unused serial_icr_read(struct uart_8250_port *up,
void serial8250_clear_fifos(struct uart_8250_port *p);
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p);
void serial8250_fifo_wait_for_lsr_thre(struct uart_8250_port *up, unsigned int count);
void serial8250_fifo_wait_for_lsr_thre(struct uart_8250_port *up,
struct nbcon_write_context *wctxt,
unsigned int count);
void serial8250_rpm_get(struct uart_8250_port *p);
void serial8250_rpm_put(struct uart_8250_port *p);
@ -334,6 +336,13 @@ int fintek_8250_probe(struct uart_8250_port *uart);
static inline int fintek_8250_probe(struct uart_8250_port *uart) { return 0; }
#endif
#if IS_REACHABLE(CONFIG_SERIAL_8250_HUB6)
bool hub6_match_port(const struct uart_port *port1, const struct uart_port *port2);
#else
static inline bool hub6_match_port(const struct uart_port *port1, const struct uart_port *port2)
{ return false; }
#endif
#ifdef CONFIG_ARCH_OMAP1
#include <linux/soc/ti/omap1-soc.h>
static inline int is_omap1_8250(struct uart_8250_port *pt)

View File

@ -1099,10 +1099,8 @@ static int brcmuart_probe(struct platform_device *pdev)
}
ret = devm_request_irq(dev, dma_irq, brcmuart_isr,
IRQF_SHARED, "uart DMA irq", &new_port->port);
if (ret) {
dev_err_probe(dev, ret, "unable to register IRQ handler\n");
if (ret)
goto err1;
}
}
platform_set_drvdata(pdev, priv);
brcmuart_init_debugfs(priv, dev_name(&pdev->dev));

View File

@ -390,12 +390,34 @@ void __init serial8250_register_ports(struct uart_driver *drv, struct device *de
#ifdef CONFIG_SERIAL_8250_CONSOLE
static void univ8250_console_write(struct console *co, const char *s,
unsigned int count)
static void univ8250_console_write_atomic(struct console *co,
struct nbcon_write_context *wctxt)
{
struct uart_8250_port *up = &serial8250_ports[co->index];
serial8250_console_write(up, s, count);
serial8250_console_write(up, wctxt, true);
}
static void univ8250_console_write_thread(struct console *co,
struct nbcon_write_context *wctxt)
{
struct uart_8250_port *up = &serial8250_ports[co->index];
serial8250_console_write(up, wctxt, false);
}
static void univ8250_console_device_lock(struct console *co, unsigned long *flags)
{
struct uart_port *up = &serial8250_ports[co->index].port;
__uart_port_lock_irqsave(up, flags);
}
static void univ8250_console_device_unlock(struct console *co, unsigned long flags)
{
struct uart_port *up = &serial8250_ports[co->index].port;
__uart_port_unlock_irqrestore(up, flags);
}
static int univ8250_console_setup(struct console *co, char *options)
@ -496,12 +518,15 @@ static int univ8250_console_match(struct console *co, char *name, int idx,
static struct console univ8250_console = {
.name = "ttyS",
.write = univ8250_console_write,
.write_atomic = univ8250_console_write_atomic,
.write_thread = univ8250_console_write_thread,
.device_lock = univ8250_console_device_lock,
.device_unlock = univ8250_console_device_unlock,
.device = uart_console_device,
.setup = univ8250_console_setup,
.exit = univ8250_console_exit,
.match = univ8250_console_match,
.flags = CON_PRINTBUFFER | CON_ANYTIME,
.flags = CON_PRINTBUFFER | CON_ANYTIME | CON_NBCON,
.index = -1,
.data = &serial8250_reg,
};
@ -584,13 +609,19 @@ void serial8250_suspend_port(int line)
struct uart_8250_port *up = &serial8250_ports[line];
struct uart_port *port = &up->port;
if (!console_suspend_enabled && uart_console(port) &&
port->type != PORT_8250) {
unsigned char canary = 0xa5;
if (uart_console(port)) {
/* No irq_work may be queued when suspending */
scoped_guard(uart_port_lock_irq, port)
up->console_msr_work_allow = false;
irq_work_sync(&up->console_msr_work);
serial_out(up, UART_SCR, canary);
if (serial_in(up, UART_SCR) == canary)
up->canary = canary;
if (!console_suspend_enabled && port->type != PORT_8250) {
unsigned char canary = 0xa5;
serial_out(up, UART_SCR, canary);
if (serial_in(up, UART_SCR) == canary)
up->canary = canary;
}
}
uart_suspend_port(&serial8250_reg, port);
@ -620,6 +651,18 @@ void serial8250_resume_port(int line)
port->uartclk = 921600*16;
}
uart_resume_port(&serial8250_reg, port);
if (uart_console(port)) {
guard(uart_port_lock_irq)(port);
/* irq_work allowed again */
up->console_msr_work_allow = true;
/* Handle any pending MSR changes */
if (up->msr_saved_flags)
serial8250_modem_status(up);
}
}
EXPORT_SYMBOL(serial8250_resume_port);
@ -802,10 +845,16 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
uart->port.get_divisor = up->port.get_divisor;
if (up->port.set_divisor)
uart->port.set_divisor = up->port.set_divisor;
if (up->port.get_rxtrig)
uart->port.get_rxtrig = up->port.get_rxtrig;
if (up->port.set_rxtrig)
uart->port.set_rxtrig = up->port.set_rxtrig;
if (up->port.startup)
uart->port.startup = up->port.startup;
if (up->port.shutdown)
uart->port.shutdown = up->port.shutdown;
if (up->port.break_ctl)
uart->port.break_ctl = up->port.break_ctl;
if (up->port.pm)
uart->port.pm = up->port.pm;
if (up->port.handle_break)

View File

@ -156,7 +156,7 @@ static int dw8250_idle_enter(struct uart_port *p)
*
* FIXME: frame_time delay is too long with very low baudrates.
*/
serial8250_fifo_wait_for_lsr_thre(up, p->fifosize);
serial8250_fifo_wait_for_lsr_thre(up, NULL, p->fifosize);
ndelay(p->frame_time);
serial_port_out(p, UART_MCR, up->mcr | UART_MCR_LOOP);

View File

@ -23,6 +23,7 @@
* console=uart8250,mmio32,0xff5e0000,115200n8
*/
#include <linux/align.h>
#include <linux/tty.h>
#include <linux/init.h>
#include <linux/console.h>
@ -177,6 +178,23 @@ OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup);
OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup);
OF_EARLYCON_DECLARE(uart, "snps,dw-apb-uart", early_serial8250_setup);
static int __init early_serial8250_xscale_setup(struct earlycon_device *device,
const char *options)
{
/*
* Adjust for BE32 register accesses: drop any hardcoded
* address for the big endian byte target, add it explicitly
* if running on BE32.
*/
device->port.membase = PTR_ALIGN_DOWN(device->port.membase, 4);
if (IS_ENABLED(CONFIG_CPU_ENDIAN_BE32))
device->port.membase += 3;
device->port.regshift = 2;
return early_serial8250_setup(device, options);
}
OF_EARLYCON_DECLARE(uart, "intel,xscale-uart", early_serial8250_xscale_setup);
static int __init early_serial8250_rs2_setup(struct earlycon_device *device,
const char *options)
{
@ -184,7 +202,6 @@ static int __init early_serial8250_rs2_setup(struct earlycon_device *device,
return early_serial8250_setup(device, options);
}
OF_EARLYCON_DECLARE(uart, "intel,xscale-uart", early_serial8250_rs2_setup);
OF_EARLYCON_DECLARE(uart, "mrvl,mmp-uart", early_serial8250_rs2_setup);
OF_EARLYCON_DECLARE(uart, "mrvl,pxa-uart", early_serial8250_rs2_setup);

View File

@ -1140,22 +1140,15 @@ static void setup_gpio(struct pci_dev *pcidev, u8 __iomem *p)
static struct platform_device *__xr17v35x_register_gpio(struct pci_dev *pcidev,
const struct software_node *node)
{
struct platform_device *pdev;
struct platform_device_info pdevinfo = {
.name = "gpio_exar",
.id = PLATFORM_DEVID_AUTO,
.parent = &pcidev->dev,
.fwnode = dev_fwnode(&pcidev->dev),
.swnode = node,
};
pdev = platform_device_alloc("gpio_exar", PLATFORM_DEVID_AUTO);
if (!pdev)
return NULL;
pdev->dev.parent = &pcidev->dev;
device_set_node(&pdev->dev, dev_fwnode(&pcidev->dev));
if (device_add_software_node(&pdev->dev, node) < 0 ||
platform_device_add(pdev) < 0) {
platform_device_put(pdev);
return NULL;
}
return pdev;
return platform_device_register_full(&pdevinfo);
}
static void __xr17v35x_unregister_gpio(struct platform_device *pdev)
@ -1642,14 +1635,14 @@ static const struct exar8250_board pbn_exar_XR17V8358 = {
.exit = pci_xr17v35x_exit,
};
#define CTI_EXAR_DEVICE(devid, bd) { \
PCI_DEVICE_SUB( \
PCI_VENDOR_ID_EXAR, \
PCI_DEVICE_ID_EXAR_##devid, \
PCI_SUBVENDOR_ID_CONNECT_TECH, \
PCI_ANY_ID), 0, 0, \
(kernel_ulong_t)&bd \
}
#define CTI_EXAR_DEVICE(devid, bd) { \
PCI_DEVICE_SUB( \
PCI_VENDOR_ID_EXAR, \
PCI_DEVICE_ID_EXAR_##devid, \
PCI_SUBVENDOR_ID_CONNECT_TECH, \
PCI_ANY_ID), \
.driver_data = (kernel_ulong_t)&bd \
}
#define EXAR_DEVICE(vend, devid, bd) { PCI_DEVICE_DATA(vend, devid, &bd) }
@ -1658,18 +1651,18 @@ static const struct exar8250_board pbn_exar_XR17V8358 = {
PCI_VENDOR_ID_EXAR, \
PCI_DEVICE_ID_EXAR_##devid, \
PCI_SUBVENDOR_ID_IBM, \
PCI_SUBDEVICE_ID_IBM_##sdevid), 0, 0, \
(kernel_ulong_t)&bd \
}
PCI_SUBDEVICE_ID_IBM_##sdevid), \
.driver_data = (kernel_ulong_t)&bd \
}
#define USR_DEVICE(devid, sdevid, bd) { \
PCI_DEVICE_SUB( \
PCI_VENDOR_ID_USR, \
PCI_DEVICE_ID_EXAR_##devid, \
PCI_VENDOR_ID_EXAR, \
PCI_SUBDEVICE_ID_USR_##sdevid), 0, 0, \
(kernel_ulong_t)&bd \
}
PCI_SUBDEVICE_ID_USR_##sdevid), \
.driver_data = (kernel_ulong_t)&bd \
}
static const struct pci_device_id exar_pci_tbl[] = {
EXAR_DEVICE(ACCESSIO, COM_2S, pbn_exar_XR17C15x),
@ -1726,7 +1719,7 @@ static const struct pci_device_id exar_pci_tbl[] = {
EXAR_DEVICE(COMMTECH, 4224PCI335, pbn_fastcom335_4),
EXAR_DEVICE(COMMTECH, 2324PCI335, pbn_fastcom335_4),
EXAR_DEVICE(COMMTECH, 2328PCI335, pbn_fastcom335_8),
{ 0, }
{ }
};
MODULE_DEVICE_TABLE(pci, exar_pci_tbl);

View File

@ -7,6 +7,8 @@
#include <linux/init.h>
#include <linux/serial_8250.h>
#include "8250.h"
#define HUB6(card, port) \
{ \
.iobase = 0x302, \
@ -41,6 +43,12 @@ static struct platform_device hub6_device = {
},
};
bool hub6_match_port(const struct uart_port *port1, const struct uart_port *port2)
{
return port1->iobase == port2->iobase && port1->hub6 == port2->hub6;
}
EXPORT_SYMBOL_GPL(hub6_match_port);
static int __init hub6_init(void)
{
return platform_device_register(&hub6_device);

View File

@ -8,6 +8,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/pinctrl/consumer.h>
@ -521,7 +522,7 @@ static int mtk8250_probe(struct platform_device *pdev)
struct uart_8250_port uart = {};
struct mtk8250_data *data;
struct resource *regs;
int irq, err;
int irq, err, line;
struct fwnode_handle *fwnode = dev_fwnode(&pdev->dev);
irq = platform_get_irq(pdev, 0);
@ -575,6 +576,10 @@ static int mtk8250_probe(struct platform_device *pdev)
#endif
if (is_of_node(fwnode)) {
line = of_alias_get_id(pdev->dev.of_node, "serial");
if (line >= 0)
uart.port.line = line;
/* Disable Rate Fix function */
writel(0x0, uart.port.membase +
(MTK_UART_RATE_FIX << uart.port.regshift));

View File

@ -0,0 +1,627 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Moxa PCIe multiport serial device driver
*
* Copyright (C) 2025 Moxa Inc. (support@moxa.com)
* Author: Crescent Hsieh <crescentcy.hsieh@moxa.com>
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/dev_printk.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/tty_flip.h>
#include <linux/types.h>
#include <linux/8250_pci.h>
#include <linux/serial_8250.h>
#include "8250.h"
#define PCI_DEVICE_ID_MOXA_CP102E 0x1024
#define PCI_DEVICE_ID_MOXA_CP102EL 0x1025
#define PCI_DEVICE_ID_MOXA_CP102N 0x1027
#define PCI_DEVICE_ID_MOXA_CP104EL_A 0x1045
#define PCI_DEVICE_ID_MOXA_CP104N 0x1046
#define PCI_DEVICE_ID_MOXA_CP112N 0x1121
#define PCI_DEVICE_ID_MOXA_CP114EL 0x1144
#define PCI_DEVICE_ID_MOXA_CP114N 0x1145
#define PCI_DEVICE_ID_MOXA_CP116E_A_A 0x1160
#define PCI_DEVICE_ID_MOXA_CP116E_A_B 0x1161
#define PCI_DEVICE_ID_MOXA_CP118EL_A 0x1182
#define PCI_DEVICE_ID_MOXA_CP118E_A_I 0x1183
#define PCI_DEVICE_ID_MOXA_CP132EL 0x1322
#define PCI_DEVICE_ID_MOXA_CP132N 0x1323
#define PCI_DEVICE_ID_MOXA_CP134EL_A 0x1342
#define PCI_DEVICE_ID_MOXA_CP134N 0x1343
#define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381
#define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683
/* Bits in PCI device ID encoding board capabilities */
#define MOXA_DEV_ID_IFACE_MASK GENMASK(11, 8) /* Supported serial interface */
#define MOXA_DEV_ID_NPORTS_MASK GENMASK(7, 4) /* Number of UART ports */
/* UART */
#define MOXA_PUART_BASE_BAUD 921600
#define MOXA_PUART_OFFSET 0x200
#define MOXA_PUART_TX_TRIG_DEFAULT 0
#define MOXA_PUART_RX_TRIG_DEFAULT 96
#define MOXA_PUART_RX_FLOW_LOW_DEFAULT 16
#define MOXA_PUART_RX_FLOW_HIGH_DEFAULT 110
/* Special Function Register (SFR) */
#define MOXA_PUART_SFR 0x07
#define MOXA_PUART_SFR_FORCE_TX BIT(0)
#define MOXA_PUART_SFR_950 BIT(5)
/* Enhanced Function Register (EFR) */
#define MOXA_PUART_EFR 0x0A
#define MOXA_PUART_EFR_ENHANCED BIT(4)
#define MOXA_PUART_EFR_AUTO_RTS BIT(6)
#define MOXA_PUART_EFR_AUTO_CTS BIT(7)
#define MOXA_PUART_EFR_RX_FLOW_MASK GENMASK(1, 0)
#define MOXA_PUART_EFR_RX_FLOW_DISABLED 0x0
#define MOXA_PUART_EFR_RX_FLOW_XON2_XOFF2 0x1
#define MOXA_PUART_EFR_RX_FLOW_XON1_XOFF1 0x2
#define MOXA_PUART_EFR_RX_FLOW_COPY_TX 0x3
#define MOXA_PUART_EFR_TX_FLOW_MASK GENMASK(3, 2)
#define MOXA_PUART_EFR_TX_FLOW_DISABLED 0x0
#define MOXA_PUART_EFR_TX_FLOW_XON2_XOFF2 0x1
#define MOXA_PUART_EFR_TX_FLOW_XON1_XOFF1 0x2
#define MOXA_PUART_EFR_TX_FLOW_RESERVED 0x3
#define MOXA_PUART_XON1 0x0B
#define MOXA_PUART_XON2 0x0C
#define MOXA_PUART_XOFF1 0x0D
#define MOXA_PUART_XOFF2 0x0E
#define MOXA_PUART_TTL 0x10 /* Tx Interrupt Trigger Level */
#define MOXA_PUART_RTL 0x11 /* Rx Interrupt Trigger Level */
#define MOXA_PUART_FCL 0x12 /* Flow Control Low Trigger Level */
#define MOXA_PUART_FCH 0x13 /* Flow Control High Trigger Level */
#define MOXA_PUART_RX_FIFO_CNT 0x15 /* Rx FIFO Data Counter */
#define MOXA_PUART_TX_FIFO_CNT 0x16 /* Tx FIFO Data Counter */
#define MOXA_PUART_RX_FIFO_MEM 0x100 /* Memory Space to Rx FIFO Data Register */
#define MOXA_PUART_TX_FIFO_MEM 0x100 /* Memory Space to Tx FIFO Data Register */
#define MOXA_GPIO_DIRECTION 0x09
#define MOXA_GPIO_OUTPUT 0x0A
#define MOXA_GPIO_PIN2 BIT(2)
#define MOXA_UIR_OFFSET 0x04
#define MOXA_UIR_RS232 0x00
#define MOXA_UIR_RS422 0x01
#define MOXA_UIR_RS485_4W 0x0B
#define MOXA_UIR_RS485_2W 0x0F
#define MOXA_EVEN_RS_MASK GENMASK(3, 0)
#define MOXA_ODD_RS_MASK GENMASK(7, 4)
struct mxpcie8250_port {
int line;
u8 rx_trig_level;
};
struct mxpcie8250 {
unsigned int supp_rs;
unsigned int num_ports;
void __iomem *bar1_base; /* UART registers (MMIO) */
void __iomem *bar2_base; /* UIR / GPIO / CPLD (IO) */
struct mxpcie8250_port port[] __counted_by(num_ports);
};
enum {
MOXA_SUPP_RS232 = BIT(0),
MOXA_SUPP_RS422 = BIT(1),
MOXA_SUPP_RS485 = BIT(2),
};
static const struct serial_rs485 mxpcie8250_rs485_supported = {
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX | SER_RS485_MODE_RS422,
};
static bool mxpcie8250_is_mini_pcie(unsigned short device)
{
if (device == PCI_DEVICE_ID_MOXA_CP102N ||
device == PCI_DEVICE_ID_MOXA_CP104N ||
device == PCI_DEVICE_ID_MOXA_CP112N ||
device == PCI_DEVICE_ID_MOXA_CP114N ||
device == PCI_DEVICE_ID_MOXA_CP132N ||
device == PCI_DEVICE_ID_MOXA_CP134N)
return true;
return false;
}
static unsigned int mxpcie8250_get_supp_rs(unsigned short device)
{
switch (device & MOXA_DEV_ID_IFACE_MASK) {
case 0x0000:
case 0x0600:
return MOXA_SUPP_RS232;
case 0x0100:
return MOXA_SUPP_RS232 | MOXA_SUPP_RS422 | MOXA_SUPP_RS485;
case 0x0300:
return MOXA_SUPP_RS422 | MOXA_SUPP_RS485;
default:
return 0;
}
}
static unsigned short mxpcie8250_get_nports(unsigned short device)
{
switch (device) {
case PCI_DEVICE_ID_MOXA_CP116E_A_A:
case PCI_DEVICE_ID_MOXA_CP116E_A_B:
return 8;
default:
return FIELD_GET(MOXA_DEV_ID_NPORTS_MASK, device);
}
}
static void mxpcie8250_set_interface(struct mxpcie8250 *priv,
unsigned int port_idx,
u8 mode)
{
void __iomem *uir_addr = priv->bar2_base + MOXA_UIR_OFFSET + port_idx / 2;
u8 cval;
cval = ioread8(uir_addr);
if (port_idx % 2)
FIELD_MODIFY(MOXA_ODD_RS_MASK, &cval, mode);
else
FIELD_MODIFY(MOXA_EVEN_RS_MASK, &cval, mode);
iowrite8(cval, uir_addr);
}
/*
* Moxa PCIe multiport serial boards support switching serial interfaces
* via the ioctl() command "TIOCSRS485". Supported modes and corresponding
* flags in "serial_rs485":
*
* RS232 = (no flags set)
* RS422 = SER_RS485_ENABLED | SER_RS485_MODE_RS422
* RS485_2W (half-duplex) = SER_RS485_ENABLED
* RS485_4W (full-duplex) = SER_RS485_ENABLED | SER_RS485_RX_DURING_TX
*/
static int mxpcie8250_rs485_config(struct uart_port *port,
struct ktermios *termios,
struct serial_rs485 *rs485)
{
struct mxpcie8250 *priv = dev_get_drvdata(port->dev);
u8 mode = MOXA_UIR_RS232;
if (rs485->flags & SER_RS485_ENABLED) {
if (rs485->flags & SER_RS485_MODE_RS422)
mode = MOXA_UIR_RS422;
else if (rs485->flags & SER_RS485_RX_DURING_TX)
mode = MOXA_UIR_RS485_4W;
else
mode = MOXA_UIR_RS485_2W;
} else if (!(priv->supp_rs & MOXA_SUPP_RS232)) {
return -ENODEV;
}
mxpcie8250_set_interface(priv, port->port_id, mode);
return 0;
}
static void mxpcie8250_set_termios(struct uart_port *port,
struct ktermios *new,
const struct ktermios *old)
{
struct uart_8250_port *up = up_to_u8250p(port);
struct tty_struct *tty = port->state->port.tty;
unsigned int cflag = tty->termios.c_cflag;
u8 efr, val;
serial8250_do_set_termios(port, new, old);
up->port.status &= ~(UPSTAT_AUTORTS | UPSTAT_AUTOCTS | UPSTAT_AUTOXOFF);
efr = serial_in(up, MOXA_PUART_EFR);
efr &= ~(MOXA_PUART_EFR_AUTO_RTS | MOXA_PUART_EFR_AUTO_CTS);
if (cflag & CRTSCTS) {
efr |= (MOXA_PUART_EFR_AUTO_RTS | MOXA_PUART_EFR_AUTO_CTS);
up->port.status |= (UPSTAT_AUTORTS | UPSTAT_AUTOCTS);
}
/* Set on-chip software flow control character */
serial_out(up, MOXA_PUART_XON1, START_CHAR(tty));
serial_out(up, MOXA_PUART_XON2, START_CHAR(tty));
serial_out(up, MOXA_PUART_XOFF1, STOP_CHAR(tty));
serial_out(up, MOXA_PUART_XOFF2, STOP_CHAR(tty));
val = I_IXON(tty) ? MOXA_PUART_EFR_RX_FLOW_XON1_XOFF1 : MOXA_PUART_EFR_RX_FLOW_DISABLED;
FIELD_MODIFY(MOXA_PUART_EFR_RX_FLOW_MASK, &efr, val);
val = I_IXOFF(tty) ? MOXA_PUART_EFR_TX_FLOW_XON1_XOFF1 : MOXA_PUART_EFR_TX_FLOW_DISABLED;
FIELD_MODIFY(MOXA_PUART_EFR_TX_FLOW_MASK, &efr, val);
if (I_IXOFF(tty))
up->port.status |= UPSTAT_AUTOXOFF;
serial_out(up, MOXA_PUART_EFR, efr);
}
static int mxpcie8250_get_rxtrig(struct uart_port *port)
{
return serial_port_in(port, MOXA_PUART_RTL);
}
static int mxpcie8250_set_rxtrig(struct uart_port *port, unsigned char bytes)
{
struct mxpcie8250 *priv = dev_get_drvdata(port->dev);
if (bytes > port->fifosize)
return -EINVAL;
serial_port_out(port, MOXA_PUART_RTL, bytes);
priv->port[port->port_id].rx_trig_level = bytes;
return 0;
}
static int mxpcie8250_startup(struct uart_port *port)
{
struct mxpcie8250 *priv = dev_get_drvdata(port->dev);
struct uart_8250_port *up = up_to_u8250p(port);
int ret;
ret = serial8250_do_startup(port);
if (ret)
return ret;
/*
* The TX FIFO write pointer (w_ptr) and read pointer (r_ptr)
* are driven by different clocks: w_ptr uses the PCIe clock
* and r_ptr uses the UART clock. When TX FIFO flush is requested,
* w_ptr may be cleared before r_ptr, so the UART can still observe
* pending TX data.
*
* It is recommended to clear the FIFOs at least 5 times to ensure
* both pointers are reset.
*/
for (unsigned int i = 0; i < 5; ++i)
serial_out(up, UART_FCR, UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
serial_out(up, MOXA_PUART_EFR, MOXA_PUART_EFR_ENHANCED);
serial_out(up, MOXA_PUART_SFR, MOXA_PUART_SFR_950);
serial_out(up, MOXA_PUART_TTL, MOXA_PUART_TX_TRIG_DEFAULT);
serial_out(up, MOXA_PUART_RTL, priv->port[port->port_id].rx_trig_level);
serial_out(up, MOXA_PUART_FCL, MOXA_PUART_RX_FLOW_LOW_DEFAULT);
serial_out(up, MOXA_PUART_FCH, MOXA_PUART_RX_FLOW_HIGH_DEFAULT);
return 0;
}
static void mxpcie8250_shutdown(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
serial_out(up, MOXA_PUART_EFR, 0);
serial_out(up, MOXA_PUART_SFR, 0);
serial8250_do_shutdown(port);
}
static void mxpcie8250_throttle(struct uart_port *port)
{
guard(uart_port_lock_irqsave)(port);
port->ops->stop_rx(port);
}
static void mxpcie8250_unthrottle(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
guard(uart_port_lock_irqsave)(port);
up->ier |= UART_IER_RLSI | UART_IER_RDI;
port->read_status_mask |= UART_LSR_DR;
serial_out(up, UART_IER, up->ier);
}
static void mxpcie8250_rx_chars(struct uart_8250_port *up)
{
struct uart_port *port = &up->port;
struct tty_port *tport = &port->state->port;
unsigned int count;
u8 *buf;
count = serial_in(up, MOXA_PUART_RX_FIFO_CNT);
count = min(count, port->fifosize);
count = tty_prepare_flip_string(tport, &buf, count);
if (!count)
return;
for (unsigned int i = 0; i < count; ++i)
buf[i] = serial_in(up, MOXA_PUART_RX_FIFO_MEM + i);
port->icount.rx += count;
tty_flip_buffer_push(tport);
}
static bool mxpcie8250_should_rx(struct uart_8250_port *up, u16 lsr)
{
struct uart_port *port = &up->port;
if (!(lsr & (UART_LSR_DR | UART_LSR_BI)))
return false;
if (!(port->status & (UPSTAT_AUTOCTS | UPSTAT_AUTORTS)))
return true;
if (lsr & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
return true;
if (port->read_status_mask & UART_LSR_DR)
return true;
return false;
}
static void mxpcie8250_tx_chars(struct uart_8250_port *up)
{
struct uart_port *port = &up->port;
unsigned int offset = 0;
unsigned char c;
uart_port_tx_limited(port, c, port->fifosize - serial_in(up, MOXA_PUART_TX_FIFO_CNT),
true,
serial_out(up, MOXA_PUART_TX_FIFO_MEM + offset++, c),
({}));
}
static int mxpcie8250_handle_irq(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
u16 lsr;
u8 iir;
iir = serial_in(up, UART_IIR);
if (iir & UART_IIR_NO_INT)
return 0;
guard(uart_port_lock_check_sysrq_irqsave)(port);
lsr = serial_lsr_in(up);
if (mxpcie8250_should_rx(up, lsr)) {
if (!(lsr & UART_LSR_BRK_ERROR_BITS))
mxpcie8250_rx_chars(up);
else
lsr = serial8250_rx_chars(up, lsr);
}
serial8250_modem_status(up);
if ((lsr & UART_LSR_THRE) && (up->ier & UART_IER_THRI))
mxpcie8250_tx_chars(up);
return 1;
}
static void mxpcie8250_software_break_ctl(struct uart_port *port, int break_state)
{
struct uart_8250_port *up = up_to_u8250p(port);
struct tty_struct *tty = port->state->port.tty;
unsigned int baud, quot;
u8 sfr, tx_byte = 0x01;
guard(uart_port_lock_irqsave)(port);
if (break_state == -1) {
serial_out(up, UART_LCR, up->lcr | UART_LCR_DLAB);
serial_dl_write(up, 0);
serial_out(up, UART_LCR, up->lcr);
serial_out(up, MOXA_PUART_TX_FIFO_MEM, tx_byte);
sfr = serial_in(up, MOXA_PUART_SFR);
serial_out(up, MOXA_PUART_SFR, sfr | MOXA_PUART_SFR_FORCE_TX);
up->lcr |= UART_LCR_SBC;
serial_out(up, UART_LCR, up->lcr);
} else {
up->lcr &= ~UART_LCR_SBC;
serial_out(up, UART_LCR, up->lcr);
sfr = serial_in(up, MOXA_PUART_SFR);
serial_out(up, MOXA_PUART_SFR, sfr & ~MOXA_PUART_SFR_FORCE_TX);
serial_out(up, UART_FCR, UART_FCR_CLEAR_XMIT);
baud = tty_get_baud_rate(tty);
quot = uart_get_divisor(port, baud);
serial8250_do_set_divisor(port, baud, quot);
serial_out(up, UART_LCR, up->lcr);
}
}
static void mxpcie8250_break_ctl(struct uart_port *port, int break_state)
{
if (port->rs485.flags & SER_RS485_ENABLED &&
!(port->rs485.flags & SER_RS485_MODE_RS422))
mxpcie8250_software_break_ctl(port, break_state);
else
serial8250_do_break_ctl(port, break_state);
}
static void mxpcie8250_init_board(struct pci_dev *pdev, struct mxpcie8250 *priv)
{
void __iomem *bar2_base = priv->bar2_base;
unsigned short device = pdev->device;
u8 cval;
/* Initial terminator */
if (device == PCI_DEVICE_ID_MOXA_CP114EL ||
device == PCI_DEVICE_ID_MOXA_CP118EL_A) {
iowrite8(0xff, bar2_base + MOXA_GPIO_DIRECTION);
iowrite8(0x00, bar2_base + MOXA_GPIO_OUTPUT);
}
/*
* Enable hardware buffer to prevent break signal output when system boots up.
* This hardware buffer is only supported on Mini PCIe series.
*/
if (mxpcie8250_is_mini_pcie(device)) {
/* Set GPIO direction */
cval = ioread8(bar2_base + MOXA_GPIO_DIRECTION);
cval |= MOXA_GPIO_PIN2;
iowrite8(cval, bar2_base + MOXA_GPIO_DIRECTION);
/* Enable low GPIO */
cval = ioread8(bar2_base + MOXA_GPIO_OUTPUT);
cval &= ~MOXA_GPIO_PIN2;
iowrite8(cval, bar2_base + MOXA_GPIO_OUTPUT);
}
}
static void mxpcie8250_setup_port(struct pci_dev *pdev,
struct mxpcie8250 *priv,
struct uart_8250_port *up,
int idx)
{
unsigned short device = pdev->device;
int offset = idx * MOXA_PUART_OFFSET;
u8 init_mode = MOXA_UIR_RS232;
if (priv->supp_rs & MOXA_SUPP_RS485) {
up->port.rs485_config = mxpcie8250_rs485_config;
up->port.rs485_supported = mxpcie8250_rs485_supported;
}
if (!(priv->supp_rs & MOXA_SUPP_RS232)) {
init_mode = MOXA_UIR_RS422;
up->port.rs485.flags = SER_RS485_ENABLED | SER_RS485_MODE_RS422;
}
mxpcie8250_set_interface(priv, idx, init_mode);
if (idx == 3 &&
(device == PCI_DEVICE_ID_MOXA_CP104EL_A ||
device == PCI_DEVICE_ID_MOXA_CP114EL ||
device == PCI_DEVICE_ID_MOXA_CP134EL_A))
offset = 7 * MOXA_PUART_OFFSET;
up->port.mapbase = pci_resource_start(pdev, FL_BASE1) + offset;
up->port.membase = pcim_iomap_table(pdev)[FL_BASE1] + offset;
}
static int mxpcie8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct device *dev = &pdev->dev;
struct uart_8250_port up = {};
struct mxpcie8250 *priv;
unsigned short device = pdev->device;
unsigned int num_ports;
int ret;
ret = pcim_enable_device(pdev);
if (ret)
return ret;
num_ports = mxpcie8250_get_nports(device);
priv = devm_kzalloc(dev, struct_size(priv, port, num_ports), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->num_ports = num_ports;
priv->supp_rs = mxpcie8250_get_supp_rs(device);
priv->bar1_base = pcim_iomap(pdev, FL_BASE1, 0);
if (!priv->bar1_base)
return -ENOMEM;
priv->bar2_base = pcim_iomap(pdev, FL_BASE2, 0);
if (!priv->bar2_base)
return -ENOMEM;
mxpcie8250_init_board(pdev, priv);
up.port.dev = dev;
up.port.irq = pdev->irq;
up.port.uartclk = MOXA_PUART_BASE_BAUD * 16;
up.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
up.port.type = PORT_MUEX50;
up.port.iotype = UPIO_MEM;
up.port.iobase = 0;
up.port.regshift = 0;
up.port.set_termios = mxpcie8250_set_termios;
up.port.get_rxtrig = mxpcie8250_get_rxtrig;
up.port.set_rxtrig = mxpcie8250_set_rxtrig;
up.port.startup = mxpcie8250_startup;
up.port.shutdown = mxpcie8250_shutdown;
up.port.throttle = mxpcie8250_throttle;
up.port.unthrottle = mxpcie8250_unthrottle;
up.port.handle_irq = mxpcie8250_handle_irq;
up.port.break_ctl = mxpcie8250_break_ctl;
for (unsigned int i = 0; i < num_ports; i++) {
mxpcie8250_setup_port(pdev, priv, &up, i);
dev_dbg(dev, "Setup PCI port: port %lx, irq %d, type %d\n",
up.port.iobase, up.port.irq, up.port.iotype);
priv->port[i].line = serial8250_register_8250_port(&up);
if (priv->port[i].line < 0) {
dev_err(dev,
"Couldn't register serial port %lx, irq %d, type %d, error %d\n",
up.port.iobase, up.port.irq,
up.port.iotype, priv->port[i].line);
break;
}
priv->port[i].rx_trig_level = MOXA_PUART_RX_TRIG_DEFAULT;
}
pci_set_drvdata(pdev, priv);
return 0;
}
static void mxpcie8250_remove(struct pci_dev *pdev)
{
struct mxpcie8250 *priv = pci_get_drvdata(pdev);
for (unsigned int i = 0; i < priv->num_ports; i++)
serial8250_unregister_port(priv->port[i].line);
}
static const struct pci_device_id mxpcie8250_pci_ids[] = {
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102E) },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102EL) },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102N) },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL_A) },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104N) },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP112N) },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114EL) },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114N) },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_A) },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_B) },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL_A) },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118E_A_I) },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132EL) },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132N) },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134EL_A) },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134N) },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP138E_A) },
{ PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL_A) },
{ }
};
MODULE_DEVICE_TABLE(pci, mxpcie8250_pci_ids);
static struct pci_driver mxpcie8250_pci_driver = {
.name = "8250_mxpcie",
.id_table = mxpcie8250_pci_ids,
.probe = mxpcie8250_probe,
.remove = mxpcie8250_remove,
};
module_pci_driver(mxpcie8250_pci_driver);
MODULE_AUTHOR("Moxa Inc.");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Moxa PCIe Multiport Serial Device Driver");

View File

@ -5,6 +5,7 @@
* Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp.
*/
#include <linux/align.h>
#include <linux/bits.h>
#include <linux/console.h>
#include <linux/math.h>
@ -156,6 +157,17 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
if (ret)
goto err_pmruntime;
if (IS_ENABLED(CONFIG_CPU_XSCALE) && type == PORT_XSCALE) {
/*
* Adjust for BE32 register accesses: drop any hardcoded
* address for the big endian byte target, add it explicitly
* if running on BE32.
*/
port->mapbase = PTR_ALIGN_DOWN(port->mapbase, 4);
if (IS_ENABLED(CONFIG_CPU_ENDIAN_BE32))
port->mapbase += 3;
}
/* Get clk rate through clk driver if present */
if (!port->uartclk) {
struct clk *bus_clk;

View File

@ -76,25 +76,6 @@
#define PCI_DEVICE_ID_WCHIC_CH384_4S 0x3470
#define PCI_DEVICE_ID_WCHIC_CH384_8S 0x3853
#define PCI_DEVICE_ID_MOXA_CP102E 0x1024
#define PCI_DEVICE_ID_MOXA_CP102EL 0x1025
#define PCI_DEVICE_ID_MOXA_CP102N 0x1027
#define PCI_DEVICE_ID_MOXA_CP104EL_A 0x1045
#define PCI_DEVICE_ID_MOXA_CP104N 0x1046
#define PCI_DEVICE_ID_MOXA_CP112N 0x1121
#define PCI_DEVICE_ID_MOXA_CP114EL 0x1144
#define PCI_DEVICE_ID_MOXA_CP114N 0x1145
#define PCI_DEVICE_ID_MOXA_CP116E_A_A 0x1160
#define PCI_DEVICE_ID_MOXA_CP116E_A_B 0x1161
#define PCI_DEVICE_ID_MOXA_CP118EL_A 0x1182
#define PCI_DEVICE_ID_MOXA_CP118E_A_I 0x1183
#define PCI_DEVICE_ID_MOXA_CP132EL 0x1322
#define PCI_DEVICE_ID_MOXA_CP132N 0x1323
#define PCI_DEVICE_ID_MOXA_CP134EL_A 0x1342
#define PCI_DEVICE_ID_MOXA_CP134N 0x1343
#define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381
#define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683
#define PCI_DEVICE_ID_ADDIDATA_CPCI7500 0x7003
#define PCI_DEVICE_ID_ADDIDATA_CPCI7500_NG 0x7024
#define PCI_DEVICE_ID_ADDIDATA_CPCI7420_NG 0x7025
@ -2002,138 +1983,6 @@ pci_sunix_setup(struct serial_private *priv,
return setup_port(priv, port, bar, offset, 0);
}
#define MOXA_PUART_GPIO_EN 0x09
#define MOXA_PUART_GPIO_OUT 0x0A
#define MOXA_GPIO_PIN2 BIT(2)
#define MOXA_RS232 0x00
#define MOXA_RS422 0x01
#define MOXA_RS485_4W 0x0B
#define MOXA_RS485_2W 0x0F
#define MOXA_UIR_OFFSET 0x04
#define MOXA_EVEN_RS_MASK GENMASK(3, 0)
#define MOXA_ODD_RS_MASK GENMASK(7, 4)
enum {
MOXA_SUPP_RS232 = BIT(0),
MOXA_SUPP_RS422 = BIT(1),
MOXA_SUPP_RS485 = BIT(2),
};
static unsigned short moxa_get_nports(unsigned short device)
{
switch (device) {
case PCI_DEVICE_ID_MOXA_CP116E_A_A:
case PCI_DEVICE_ID_MOXA_CP116E_A_B:
return 8;
}
return FIELD_GET(0x00F0, device);
}
static bool pci_moxa_is_mini_pcie(unsigned short device)
{
if (device == PCI_DEVICE_ID_MOXA_CP102N ||
device == PCI_DEVICE_ID_MOXA_CP104N ||
device == PCI_DEVICE_ID_MOXA_CP112N ||
device == PCI_DEVICE_ID_MOXA_CP114N ||
device == PCI_DEVICE_ID_MOXA_CP132N ||
device == PCI_DEVICE_ID_MOXA_CP134N)
return true;
return false;
}
static unsigned int pci_moxa_supported_rs(struct pci_dev *dev)
{
switch (dev->device & 0x0F00) {
case 0x0000:
case 0x0600:
return MOXA_SUPP_RS232;
case 0x0100:
return MOXA_SUPP_RS232 | MOXA_SUPP_RS422 | MOXA_SUPP_RS485;
case 0x0300:
return MOXA_SUPP_RS422 | MOXA_SUPP_RS485;
}
return 0;
}
static int pci_moxa_set_interface(const struct pci_dev *dev,
unsigned int port_idx,
u8 mode)
{
resource_size_t iobar_addr = pci_resource_start(dev, 2);
resource_size_t UIR_addr = iobar_addr + MOXA_UIR_OFFSET + port_idx / 2;
u8 val;
val = inb(UIR_addr);
if (port_idx % 2) {
val &= ~MOXA_ODD_RS_MASK;
val |= FIELD_PREP(MOXA_ODD_RS_MASK, mode);
} else {
val &= ~MOXA_EVEN_RS_MASK;
val |= FIELD_PREP(MOXA_EVEN_RS_MASK, mode);
}
outb(val, UIR_addr);
return 0;
}
static int pci_moxa_init(struct pci_dev *dev)
{
unsigned short device = dev->device;
resource_size_t iobar_addr = pci_resource_start(dev, 2);
unsigned int i, num_ports = moxa_get_nports(device);
u8 val, init_mode = MOXA_RS232;
if (!IS_ENABLED(CONFIG_HAS_IOPORT))
return serial_8250_warn_need_ioport(dev);
if (!(pci_moxa_supported_rs(dev) & MOXA_SUPP_RS232)) {
init_mode = MOXA_RS422;
}
for (i = 0; i < num_ports; ++i)
pci_moxa_set_interface(dev, i, init_mode);
/*
* Enable hardware buffer to prevent break signal output when system boots up.
* This hardware buffer is only supported on Mini PCIe series.
*/
if (pci_moxa_is_mini_pcie(device)) {
/* Set GPIO direction */
val = inb(iobar_addr + MOXA_PUART_GPIO_EN);
val |= MOXA_GPIO_PIN2;
outb(val, iobar_addr + MOXA_PUART_GPIO_EN);
/* Enable low GPIO */
val = inb(iobar_addr + MOXA_PUART_GPIO_OUT);
val &= ~MOXA_GPIO_PIN2;
outb(val, iobar_addr + MOXA_PUART_GPIO_OUT);
}
return num_ports;
}
static int
pci_moxa_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_8250_port *port, int idx)
{
unsigned int bar = FL_GET_BASE(board->flags);
int offset;
if (!IS_ENABLED(CONFIG_HAS_IOPORT))
return serial_8250_warn_need_ioport(priv->dev);
if (board->num_ports == 4 && idx == 3)
offset = 7 * board->uart_offset;
else
offset = idx * board->uart_offset;
return setup_port(priv, port, bar, offset, 0);
}
#define SB_OPTR_IMR0 0x0c /* Interrupt mask register, p0 to p7 */
static int pci_systembase_init(struct pci_dev *dev)
{
@ -2996,17 +2845,6 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
.setup = pci_fintek_setup,
.init = pci_fintek_init,
},
/*
* MOXA
*/
{
.vendor = PCI_VENDOR_ID_MOXA,
.device = PCI_ANY_ID,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.init = pci_moxa_init,
.setup = pci_moxa_setup,
},
{
.vendor = 0x1c29,
.device = 0x1204,
@ -3225,9 +3063,6 @@ enum pci_board_num_t {
pbn_titan_2_4000000,
pbn_titan_4_4000000,
pbn_titan_8_4000000,
pbn_moxa_2,
pbn_moxa_4,
pbn_moxa_8,
};
/*
@ -4005,24 +3840,6 @@ static struct pciserial_board pci_boards[] = {
.uart_offset = 0x200,
.first_offset = 0x1000,
},
[pbn_moxa_2] = {
.flags = FL_BASE1,
.num_ports = 2,
.base_baud = 921600,
.uart_offset = 0x200,
},
[pbn_moxa_4] = {
.flags = FL_BASE1,
.num_ports = 4,
.base_baud = 921600,
.uart_offset = 0x200,
},
[pbn_moxa_8] = {
.flags = FL_BASE1,
.num_ports = 8,
.base_baud = 921600,
.uart_offset = 0x200,
},
};
#define REPORT_CONFIG(option) \
@ -4076,6 +3893,9 @@ static const struct pci_device_id blacklist[] = {
{ PCI_VDEVICE(PERICOM, PCI_ANY_ID), .driver_data = REPORT_8250_CONFIG(PERICOM), },
{ PCI_VDEVICE(ACCESSIO, PCI_ANY_ID), .driver_data = REPORT_8250_CONFIG(PERICOM), },
/* Moxa devices */
{ PCI_VDEVICE(MOXA, PCI_ANY_ID), REPORT_8250_CONFIG(MOXA), },
/* End of the black list */
{ }
};
@ -5950,65 +5770,6 @@ static const struct pci_device_id serial_pci_tbl[] = {
.driver_data = pbn_ni8430_4,
},
/*
* MOXA
*/
{
PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102E),
.driver_data = pbn_moxa_2,
}, {
PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102EL),
.driver_data = pbn_moxa_2,
}, {
PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102N),
.driver_data = pbn_moxa_2,
}, {
PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL_A),
.driver_data = pbn_moxa_4,
}, {
PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104N),
.driver_data = pbn_moxa_4,
}, {
PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP112N),
.driver_data = pbn_moxa_2,
}, {
PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114EL),
.driver_data = pbn_moxa_4,
}, {
PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114N),
.driver_data = pbn_moxa_4,
}, {
PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_A),
.driver_data = pbn_moxa_8,
}, {
PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP116E_A_B),
.driver_data = pbn_moxa_8,
}, {
PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL_A),
.driver_data = pbn_moxa_8,
}, {
PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118E_A_I),
.driver_data = pbn_moxa_8,
}, {
PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132EL),
.driver_data = pbn_moxa_2,
}, {
PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132N),
.driver_data = pbn_moxa_2,
}, {
PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134EL_A),
.driver_data = pbn_moxa_4,
}, {
PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134N),
.driver_data = pbn_moxa_4,
}, {
PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP138E_A),
.driver_data = pbn_moxa_8,
}, {
PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL_A),
.driver_data = pbn_moxa_8,
},
/*
* ADDI-DATA GmbH communication cards <info@addi-data.com>
*/

View File

@ -284,6 +284,7 @@ static struct platform_driver serial8250_isa_driver = {
.driver = {
.name = "serial8250",
.acpi_match_table = acpi_platform_serial_table,
.probe_type = PROBE_FORCE_SYNCHRONOUS,
},
};

View File

@ -28,351 +28,351 @@
static const struct pnp_device_id pnp_dev_table[] = {
/* Archtek America Corp. */
/* Archtek SmartLink Modem 3334BT Plug & Play */
{ "AAC000F", 0 },
{ .id = "AAC000F", .driver_data = 0 },
/* Anchor Datacomm BV */
/* SXPro 144 External Data Fax Modem Plug & Play */
{ "ADC0001", 0 },
{ .id = "ADC0001", .driver_data = 0 },
/* SXPro 288 External Data Fax Modem Plug & Play */
{ "ADC0002", 0 },
{ .id = "ADC0002", .driver_data = 0 },
/* PROLiNK 1456VH ISA PnP K56flex Fax Modem */
{ "AEI0250", 0 },
{ .id = "AEI0250", .driver_data = 0 },
/* Actiontec ISA PNP 56K X2 Fax Modem */
{ "AEI1240", 0 },
{ .id = "AEI1240", .driver_data = 0 },
/* Rockwell 56K ACF II Fax+Data+Voice Modem */
{ "AKY1021", 0 /*SPCI_FL_NO_SHIRQ*/ },
{ .id ="AKY1021", .driver_data = 0 /*SPCI_FL_NO_SHIRQ*/ },
/*
* ALi Fast Infrared Controller
* Native driver (ali-ircc) is broken so at least
* it can be used with irtty-sir.
*/
{ "ALI5123", 0 },
{ .id = "ALI5123", .driver_data = 0 },
/* AZT3005 PnP SOUND DEVICE */
{ "AZT4001", 0 },
{ .id = "AZT4001", .driver_data = 0 },
/* Best Data Products Inc. Smart One 336F PnP Modem */
{ "BDP3336", 0 },
{ .id = "BDP3336", .driver_data = 0 },
/* Boca Research */
/* Boca Complete Ofc Communicator 14.4 Data-FAX */
{ "BRI0A49", 0 },
{ .id = "BRI0A49", .driver_data = 0 },
/* Boca Research 33,600 ACF Modem */
{ "BRI1400", 0 },
{ .id = "BRI1400", .driver_data = 0 },
/* Boca 33.6 Kbps Internal FD34FSVD */
{ "BRI3400", 0 },
{ .id = "BRI3400", .driver_data = 0 },
/* Computer Peripherals Inc */
/* EuroViVa CommCenter-33.6 SP PnP */
{ "CPI4050", 0 },
{ .id = "CPI4050", .driver_data = 0 },
/* Creative Labs */
/* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */
{ "CTL3001", 0 },
{ .id = "CTL3001", .driver_data = 0 },
/* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */
{ "CTL3011", 0 },
{ .id = "CTL3011", .driver_data = 0 },
/* Davicom ISA 33.6K Modem */
{ "DAV0336", 0 },
{ .id = "DAV0336", .driver_data = 0 },
/* Creative */
/* Creative Modem Blaster Flash56 DI5601-1 */
{ "DMB1032", 0 },
{ .id = "DMB1032", .driver_data = 0 },
/* Creative Modem Blaster V.90 DI5660 */
{ "DMB2001", 0 },
{ .id = "DMB2001", .driver_data = 0 },
/* E-Tech */
/* E-Tech CyberBULLET PC56RVP */
{ "ETT0002", 0 },
{ .id = "ETT0002", .driver_data = 0 },
/* FUJITSU */
/* Fujitsu 33600 PnP-I2 R Plug & Play */
{ "FUJ0202", 0 },
{ .id = "FUJ0202", .driver_data = 0 },
/* Fujitsu FMV-FX431 Plug & Play */
{ "FUJ0205", 0 },
{ .id = "FUJ0205", .driver_data = 0 },
/* Fujitsu 33600 PnP-I4 R Plug & Play */
{ "FUJ0206", 0 },
{ .id = "FUJ0206", .driver_data = 0 },
/* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */
{ "FUJ0209", 0 },
{ .id = "FUJ0209", .driver_data = 0 },
/* Archtek America Corp. */
/* Archtek SmartLink Modem 3334BT Plug & Play */
{ "GVC000F", 0 },
{ .id = "GVC000F", .driver_data = 0 },
/* Archtek SmartLink Modem 3334BRV 33.6K Data Fax Voice */
{ "GVC0303", 0 },
{ .id = "GVC0303", .driver_data = 0 },
/* Hayes */
/* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */
{ "HAY0001", 0 },
{ .id = "HAY0001", .driver_data = 0 },
/* Hayes Optima 336 V.34 + FAX + Voice PnP */
{ "HAY000C", 0 },
{ .id = "HAY000C", .driver_data = 0 },
/* Hayes Optima 336B V.34 + FAX + Voice PnP */
{ "HAY000D", 0 },
{ .id = "HAY000D", .driver_data = 0 },
/* Hayes Accura 56K Ext Fax Modem PnP */
{ "HAY5670", 0 },
{ .id = "HAY5670", .driver_data = 0 },
/* Hayes Accura 56K Ext Fax Modem PnP */
{ "HAY5674", 0 },
{ .id = "HAY5674", .driver_data = 0 },
/* Hayes Accura 56K Fax Modem PnP */
{ "HAY5675", 0 },
{ .id = "HAY5675", .driver_data = 0 },
/* Hayes 288, V.34 + FAX */
{ "HAYF000", 0 },
{ .id = "HAYF000", .driver_data = 0 },
/* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */
{ "HAYF001", 0 },
{ .id = "HAYF001", .driver_data = 0 },
/* IBM */
/* IBM Thinkpad 701 Internal Modem Voice */
{ "IBM0033", 0 },
{ .id = "IBM0033", .driver_data = 0 },
/* Intermec */
/* Intermec CV60 touchscreen port */
{ "PNP4972", 0 },
{ .id = "PNP4972", .driver_data = 0 },
/* Intertex */
/* Intertex 28k8 33k6 Voice EXT PnP */
{ "IXDC801", 0 },
{ .id = "IXDC801", .driver_data = 0 },
/* Intertex 33k6 56k Voice EXT PnP */
{ "IXDC901", 0 },
{ .id = "IXDC901", .driver_data = 0 },
/* Intertex 28k8 33k6 Voice SP EXT PnP */
{ "IXDD801", 0 },
{ .id = "IXDD801", .driver_data = 0 },
/* Intertex 33k6 56k Voice SP EXT PnP */
{ "IXDD901", 0 },
{ .id = "IXDD901", .driver_data = 0 },
/* Intertex 28k8 33k6 Voice SP INT PnP */
{ "IXDF401", 0 },
{ .id = "IXDF401", .driver_data = 0 },
/* Intertex 28k8 33k6 Voice SP EXT PnP */
{ "IXDF801", 0 },
{ .id = "IXDF801", .driver_data = 0 },
/* Intertex 33k6 56k Voice SP EXT PnP */
{ "IXDF901", 0 },
{ .id = "IXDF901", .driver_data = 0 },
/* Kortex International */
/* KORTEX 28800 Externe PnP */
{ "KOR4522", 0 },
{ .id = "KOR4522", .driver_data = 0 },
/* KXPro 33.6 Vocal ASVD PnP */
{ "KORF661", 0 },
{ .id = "KORF661", .driver_data = 0 },
/* Lasat */
/* LASAT Internet 33600 PnP */
{ "LAS4040", 0 },
{ .id = "LAS4040", .driver_data = 0 },
/* Lasat Safire 560 PnP */
{ "LAS4540", 0 },
{ .id = "LAS4540", .driver_data = 0 },
/* Lasat Safire 336 PnP */
{ "LAS5440", 0 },
{ .id = "LAS5440", .driver_data = 0 },
/* Microcom, Inc. */
/* Microcom TravelPorte FAST V.34 Plug & Play */
{ "MNP0281", 0 },
{ .id = "MNP0281", .driver_data = 0 },
/* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */
{ "MNP0336", 0 },
{ .id = "MNP0336", .driver_data = 0 },
/* Microcom DeskPorte FAST EP 28.8 Plug & Play */
{ "MNP0339", 0 },
{ .id = "MNP0339", .driver_data = 0 },
/* Microcom DeskPorte 28.8P Plug & Play */
{ "MNP0342", 0 },
{ .id = "MNP0342", .driver_data = 0 },
/* Microcom DeskPorte FAST ES 28.8 Plug & Play */
{ "MNP0500", 0 },
{ .id = "MNP0500", .driver_data = 0 },
/* Microcom DeskPorte FAST ES 28.8 Plug & Play */
{ "MNP0501", 0 },
{ .id = "MNP0501", .driver_data = 0 },
/* Microcom DeskPorte 28.8S Internal Plug & Play */
{ "MNP0502", 0 },
{ .id = "MNP0502", .driver_data = 0 },
/* Motorola */
/* Motorola BitSURFR Plug & Play */
{ "MOT1105", 0 },
{ .id = "MOT1105", .driver_data = 0 },
/* Motorola TA210 Plug & Play */
{ "MOT1111", 0 },
{ .id = "MOT1111", .driver_data = 0 },
/* Motorola HMTA 200 (ISDN) Plug & Play */
{ "MOT1114", 0 },
{ .id = "MOT1114", .driver_data = 0 },
/* Motorola BitSURFR Plug & Play */
{ "MOT1115", 0 },
{ .id = "MOT1115", .driver_data = 0 },
/* Motorola Lifestyle 28.8 Internal */
{ "MOT1190", 0 },
{ .id = "MOT1190", .driver_data = 0 },
/* Motorola V.3400 Plug & Play */
{ "MOT1501", 0 },
{ .id = "MOT1501", .driver_data = 0 },
/* Motorola Lifestyle 28.8 V.34 Plug & Play */
{ "MOT1502", 0 },
{ .id = "MOT1502", .driver_data = 0 },
/* Motorola Power 28.8 V.34 Plug & Play */
{ "MOT1505", 0 },
{ .id = "MOT1505", .driver_data = 0 },
/* Motorola ModemSURFR External 28.8 Plug & Play */
{ "MOT1509", 0 },
{ .id = "MOT1509", .driver_data = 0 },
/* Motorola Premier 33.6 Desktop Plug & Play */
{ "MOT150A", 0 },
{ .id = "MOT150A", .driver_data = 0 },
/* Motorola VoiceSURFR 56K External PnP */
{ "MOT150F", 0 },
{ .id = "MOT150F", .driver_data = 0 },
/* Motorola ModemSURFR 56K External PnP */
{ "MOT1510", 0 },
{ .id = "MOT1510", .driver_data = 0 },
/* Motorola ModemSURFR 56K Internal PnP */
{ "MOT1550", 0 },
{ .id = "MOT1550", .driver_data = 0 },
/* Motorola ModemSURFR Internal 28.8 Plug & Play */
{ "MOT1560", 0 },
{ .id = "MOT1560", .driver_data = 0 },
/* Motorola Premier 33.6 Internal Plug & Play */
{ "MOT1580", 0 },
{ .id = "MOT1580", .driver_data = 0 },
/* Motorola OnlineSURFR 28.8 Internal Plug & Play */
{ "MOT15B0", 0 },
{ .id = "MOT15B0", .driver_data = 0 },
/* Motorola VoiceSURFR 56K Internal PnP */
{ "MOT15F0", 0 },
{ .id = "MOT15F0", .driver_data = 0 },
/* Com 1 */
/* Deskline K56 Phone System PnP */
{ "MVX00A1", 0 },
{ .id = "MVX00A1", .driver_data = 0 },
/* PC Rider K56 Phone System PnP */
{ "MVX00F2", 0 },
{ .id = "MVX00F2", .driver_data = 0 },
/* NEC 98NOTE SPEAKER PHONE FAX MODEM(33600bps) */
{ "nEC8241", 0 },
{ .id = "nEC8241", .driver_data = 0 },
/* Pace 56 Voice Internal Plug & Play Modem */
{ "PMC2430", 0 },
{ .id = "PMC2430", .driver_data = 0 },
/* Generic */
/* Generic standard PC COM port */
{ "PNP0500", 0 },
{ .id = "PNP0500", .driver_data = 0 },
/* Generic 16550A-compatible COM port */
{ "PNP0501", 0 },
{ .id = "PNP0501", .driver_data = 0 },
/* Compaq 14400 Modem */
{ "PNPC000", 0 },
{ .id = "PNPC000", .driver_data = 0 },
/* Compaq 2400/9600 Modem */
{ "PNPC001", 0 },
{ .id = "PNPC001", .driver_data = 0 },
/* Dial-Up Networking Serial Cable between 2 PCs */
{ "PNPC031", 0 },
{ .id = "PNPC031", .driver_data = 0 },
/* Dial-Up Networking Parallel Cable between 2 PCs */
{ "PNPC032", 0 },
{ .id = "PNPC032", .driver_data = 0 },
/* Standard 9600 bps Modem */
{ "PNPC100", 0 },
{ .id = "PNPC100", .driver_data = 0 },
/* Standard 14400 bps Modem */
{ "PNPC101", 0 },
{ .id = "PNPC101", .driver_data = 0 },
/* Standard 28800 bps Modem*/
{ "PNPC102", 0 },
{ .id = "PNPC102", .driver_data = 0 },
/* Standard Modem*/
{ "PNPC103", 0 },
{ .id = "PNPC103", .driver_data = 0 },
/* Standard 9600 bps Modem*/
{ "PNPC104", 0 },
{ .id = "PNPC104", .driver_data = 0 },
/* Standard 14400 bps Modem*/
{ "PNPC105", 0 },
{ .id = "PNPC105", .driver_data = 0 },
/* Standard 28800 bps Modem*/
{ "PNPC106", 0 },
{ .id = "PNPC106", .driver_data = 0 },
/* Standard Modem */
{ "PNPC107", 0 },
{ .id = "PNPC107", .driver_data = 0 },
/* Standard 9600 bps Modem */
{ "PNPC108", 0 },
{ .id = "PNPC108", .driver_data = 0 },
/* Standard 14400 bps Modem */
{ "PNPC109", 0 },
{ .id = "PNPC109", .driver_data = 0 },
/* Standard 28800 bps Modem */
{ "PNPC10A", 0 },
{ .id = "PNPC10A", .driver_data = 0 },
/* Standard Modem */
{ "PNPC10B", 0 },
{ .id = "PNPC10B", .driver_data = 0 },
/* Standard 9600 bps Modem */
{ "PNPC10C", 0 },
{ .id = "PNPC10C", .driver_data = 0 },
/* Standard 14400 bps Modem */
{ "PNPC10D", 0 },
{ .id = "PNPC10D", .driver_data = 0 },
/* Standard 28800 bps Modem */
{ "PNPC10E", 0 },
{ .id = "PNPC10E", .driver_data = 0 },
/* Standard Modem */
{ "PNPC10F", 0 },
{ .id = "PNPC10F", .driver_data = 0 },
/* Standard PCMCIA Card Modem */
{ "PNP2000", 0 },
{ .id = "PNP2000", .driver_data = 0 },
/* Rockwell */
/* Modular Technology */
/* Rockwell 33.6 DPF Internal PnP */
/* Modular Technology 33.6 Internal PnP */
{ "ROK0030", 0 },
{ .id = "ROK0030", .driver_data = 0 },
/* Kortex International */
/* KORTEX 14400 Externe PnP */
{ "ROK0100", 0 },
{ .id = "ROK0100", .driver_data = 0 },
/* Rockwell 28.8 */
{ "ROK4120", 0 },
{ .id = "ROK4120", .driver_data = 0 },
/* Viking Components, Inc */
/* Viking 28.8 INTERNAL Fax+Data+Voice PnP */
{ "ROK4920", 0 },
{ .id = "ROK4920", .driver_data = 0 },
/* Rockwell */
/* British Telecom */
/* Modular Technology */
/* Rockwell 33.6 DPF External PnP */
/* BT Prologue 33.6 External PnP */
/* Modular Technology 33.6 External PnP */
{ "RSS00A0", 0 },
{ .id = "RSS00A0", .driver_data = 0 },
/* Viking 56K FAX INT */
{ "RSS0262", 0 },
{ .id = "RSS0262", .driver_data = 0 },
/* K56 par,VV,Voice,Speakphone,AudioSpan,PnP */
{ "RSS0250", 0 },
{ .id = "RSS0250", .driver_data = 0 },
/* SupraExpress 28.8 Data/Fax PnP modem */
{ "SUP1310", 0 },
{ .id = "SUP1310", .driver_data = 0 },
/* SupraExpress 336i PnP Voice Modem */
{ "SUP1381", 0 },
{ .id = "SUP1381", .driver_data = 0 },
/* SupraExpress 33.6 Data/Fax PnP modem */
{ "SUP1421", 0 },
{ .id = "SUP1421", .driver_data = 0 },
/* SupraExpress 33.6 Data/Fax PnP modem */
{ "SUP1590", 0 },
{ .id = "SUP1590", .driver_data = 0 },
/* SupraExpress 336i Sp ASVD */
{ "SUP1620", 0 },
{ .id = "SUP1620", .driver_data = 0 },
/* SupraExpress 33.6 Data/Fax PnP modem */
{ "SUP1760", 0 },
{ .id = "SUP1760", .driver_data = 0 },
/* SupraExpress 56i Sp Intl */
{ "SUP2171", 0 },
{ .id = "SUP2171", .driver_data = 0 },
/* Phoebe Micro */
/* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */
{ "TEX0011", 0 },
{ .id = "TEX0011", .driver_data = 0 },
/* Archtek America Corp. */
/* Archtek SmartLink Modem 3334BT Plug & Play */
{ "UAC000F", 0 },
{ .id = "UAC000F", .driver_data = 0 },
/* 3Com Corp. */
/* Gateway Telepath IIvi 33.6 */
{ "USR0000", 0 },
{ .id = "USR0000", .driver_data = 0 },
/* U.S. Robotics Sporster 33.6K Fax INT PnP */
{ "USR0002", 0 },
{ .id = "USR0002", .driver_data = 0 },
/* Sportster Vi 14.4 PnP FAX Voicemail */
{ "USR0004", 0 },
{ .id = "USR0004", .driver_data = 0 },
/* U.S. Robotics 33.6K Voice INT PnP */
{ "USR0006", 0 },
{ .id = "USR0006", .driver_data = 0 },
/* U.S. Robotics 33.6K Voice EXT PnP */
{ "USR0007", 0 },
{ .id = "USR0007", .driver_data = 0 },
/* U.S. Robotics Courier V.Everything INT PnP */
{ "USR0009", 0 },
{ .id = "USR0009", .driver_data = 0 },
/* U.S. Robotics 33.6K Voice INT PnP */
{ "USR2002", 0 },
{ .id = "USR2002", .driver_data = 0 },
/* U.S. Robotics 56K Voice INT PnP */
{ "USR2070", 0 },
{ .id = "USR2070", .driver_data = 0 },
/* U.S. Robotics 56K Voice EXT PnP */
{ "USR2080", 0 },
{ .id = "USR2080", .driver_data = 0 },
/* U.S. Robotics 56K FAX INT */
{ "USR3031", 0 },
{ .id = "USR3031", .driver_data = 0 },
/* U.S. Robotics 56K FAX INT */
{ "USR3050", 0 },
{ .id = "USR3050", .driver_data = 0 },
/* U.S. Robotics 56K Voice INT PnP */
{ "USR3070", 0 },
{ .id = "USR3070", .driver_data = 0 },
/* U.S. Robotics 56K Voice EXT PnP */
{ "USR3080", 0 },
{ .id = "USR3080", .driver_data = 0 },
/* U.S. Robotics 56K Voice INT PnP */
{ "USR3090", 0 },
{ .id = "USR3090", .driver_data = 0 },
/* U.S. Robotics 56K Message */
{ "USR9100", 0 },
{ .id = "USR9100", .driver_data = 0 },
/* U.S. Robotics 56K FAX EXT PnP*/
{ "USR9160", 0 },
{ .id = "USR9160", .driver_data = 0 },
/* U.S. Robotics 56K FAX INT PnP*/
{ "USR9170", 0 },
{ .id = "USR9170", .driver_data = 0 },
/* U.S. Robotics 56K Voice EXT PnP*/
{ "USR9180", 0 },
{ .id = "USR9180", .driver_data = 0 },
/* U.S. Robotics 56K Voice INT PnP*/
{ "USR9190", 0 },
{ .id = "USR9190", .driver_data = 0 },
/* Wacom tablets */
{ "WACFXXX", 0 },
{ .id = "WACFXXX", .driver_data = 0 },
/* Compaq touchscreen */
{ "FPI2002", 0 },
{ .id = "FPI2002", .driver_data = 0 },
/* Fujitsu Stylistic touchscreens */
{ "FUJ02B2", 0 },
{ "FUJ02B3", 0 },
{ .id = "FUJ02B2", .driver_data = 0 },
{ .id = "FUJ02B3", .driver_data = 0 },
/* Fujitsu Stylistic LT touchscreens */
{ "FUJ02B4", 0 },
{ .id = "FUJ02B4", .driver_data = 0 },
/* Passive Fujitsu Stylistic touchscreens */
{ "FUJ02B6", 0 },
{ "FUJ02B7", 0 },
{ "FUJ02B8", 0 },
{ "FUJ02B9", 0 },
{ "FUJ02BC", 0 },
{ .id = "FUJ02B6", .driver_data = 0 },
{ .id = "FUJ02B7", .driver_data = 0 },
{ .id = "FUJ02B8", .driver_data = 0 },
{ .id = "FUJ02B9", .driver_data = 0 },
{ .id = "FUJ02BC", .driver_data = 0 },
/* Fujitsu Wacom Tablet PC device */
{ "FUJ02E5", 0 },
{ .id = "FUJ02E5", .driver_data = 0 },
/* Fujitsu P-series tablet PC device */
{ "FUJ02E6", 0 },
{ .id = "FUJ02E6", .driver_data = 0 },
/* Fujitsu Wacom 2FGT Tablet PC device */
{ "FUJ02E7", 0 },
{ .id = "FUJ02E7", .driver_data = 0 },
/* Fujitsu Wacom 1FGT Tablet PC device */
{ "FUJ02E9", 0 },
{ .id = "FUJ02E9", .driver_data = 0 },
/*
* LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6
* in disguise).
*/
{ "LTS0001", 0 },
{ .id = "LTS0001", .driver_data = 0 },
/* Rockwell's (PORALiNK) 33600 INT PNP */
{ "WCI0003", 0 },
{ .id = "WCI0003", .driver_data = 0 },
/* Unknown PnP modems */
{ "PNPCXXX", UNKNOWN_DEV },
{ .id = "PNPCXXX", .driver_data = UNKNOWN_DEV },
/* More unknown PnP modems */
{ "PNPDXXX", UNKNOWN_DEV },
{ .id = "PNPDXXX", .driver_data = UNKNOWN_DEV },
/*
* Winbond CIR port, should not be probed. We should keep track of
* it to prevent the legacy serial driver from probing it.
*/
{ "WEC1022", CIR_PORT },
{ .id = "WEC1022", .driver_data = CIR_PORT },
/*
* SMSC IrCC SIR/FIR port, should not be probed by serial driver as
* well so its own driver can bind to it.
*/
{ "SMCF010", CIR_PORT },
{ "", 0 }
{ .id = "SMCF010", .driver_data = CIR_PORT },
{ }
};
MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
@ -521,6 +521,7 @@ static struct pnp_driver serial_pnp_driver = {
.remove = serial_pnp_remove,
.driver = {
.pm = pm_sleep_ptr(&serial_pnp_pm_ops),
.probe_type = PROBE_FORCE_SYNCHRONOUS,
},
.id_table = pnp_dev_table,
};

View File

@ -311,6 +311,14 @@ static const struct serial8250_config uart_config[] = {
.rxtrig_bytes = {1, 8, 16, 30},
.flags = UART_CAP_FIFO | UART_CAP_AFE,
},
[PORT_MUEX50] = {
.name = "Moxa MUEx50 UART",
.fifo_size = 128,
.tx_loadsz = 128,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.rxtrig_bytes = {15, 31, 63, 111},
.flags = UART_CAP_FIFO,
},
};
/* Uart divisor latch read */
@ -474,16 +482,10 @@ static void set_io_from_upio(struct uart_port *p)
static void
serial_port_out_sync(struct uart_port *p, int offset, int value)
{
switch (p->iotype) {
case UPIO_MEM:
case UPIO_MEM16:
case UPIO_MEM32:
case UPIO_MEM32BE:
case UPIO_AU:
if (uart_iotype_mmio(p->iotype)) {
p->serial_out(p, offset, value);
p->serial_in(p, UART_LCR); /* safe, no side-effects */
break;
default:
} else {
p->serial_out(p, offset, value);
}
}
@ -710,7 +712,12 @@ static void serial8250_clear_interrupts(struct uart_port *port)
serial_port_in(port, UART_MSR);
}
static void serial8250_clear_IER(struct uart_8250_port *up)
/*
* Only to be directly used by serial8250_console_write() and
* serial8250_put_poll_char(), which do not require the port lock.
* Use serial8250_clear_IER() instead for all other cases.
*/
static void __serial8250_clear_IER(struct uart_8250_port *up)
{
if (up->capabilities & UART_CAP_UUE)
serial_out(up, UART_IER, UART_IER_UUE);
@ -718,6 +725,14 @@ static void serial8250_clear_IER(struct uart_8250_port *up)
serial_out(up, UART_IER, 0);
}
static inline void serial8250_clear_IER(struct uart_8250_port *up)
{
/* Port locked to synchronize UART_IER access against the console */
lockdep_assert_held_once(&up->port.lock);
__serial8250_clear_IER(up);
}
/*
* This is a quickie test to see how big the FIFO is.
* It doesn't work at all the time, more's the pity.
@ -1290,9 +1305,6 @@ void serial8250_em485_stop_tx(struct uart_8250_port *p, bool toggle_ier)
{
unsigned char mcr = serial8250_in_MCR(p);
/* Port locked to synchronize UART_IER access against the console. */
lockdep_assert_held_once(&p->port.lock);
if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
mcr |= UART_MCR_RTS;
else
@ -1308,6 +1320,16 @@ void serial8250_em485_stop_tx(struct uart_8250_port *p, bool toggle_ier)
serial8250_clear_and_reinit_fifos(p);
if (toggle_ier) {
/*
* Port locked to synchronize UART_IER access against
* the console. The lockdep_assert must be restricted
* to this condition because only here is it
* guaranteed that the port lock is held. The other
* hardware access in this function is synchronized
* by console ownership.
*/
lockdep_assert_held_once(&p->port.lock);
p->ier |= UART_IER_RLSI | UART_IER_RDI;
serial_port_out(&p->port, UART_IER, p->ier);
}
@ -1950,7 +1972,7 @@ static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
serial8250_do_set_mctrl(port, mctrl);
}
static void serial8250_break_ctl(struct uart_port *port, int break_state)
void serial8250_do_break_ctl(struct uart_port *port, int break_state)
{
struct uart_8250_port *up = up_to_u8250p(port);
@ -1963,6 +1985,15 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
up->lcr &= ~UART_LCR_SBC;
serial_port_out(port, UART_LCR, up->lcr);
}
EXPORT_SYMBOL_GPL(serial8250_do_break_ctl);
static void serial8250_break_ctl(struct uart_port *port, int break_state)
{
if (port->break_ctl)
port->break_ctl(port, break_state);
else
serial8250_do_break_ctl(port, break_state);
}
/* Returns true if @bits were set, false on timeout */
static bool wait_for_lsr(struct uart_8250_port *up, int bits)
@ -2059,10 +2090,13 @@ static void serial8250_put_poll_char(struct uart_port *port,
guard(serial8250_rpm)(up);
/*
* First save the IER then disable the interrupts
* First, save the IER, then disable the interrupts. The special
* variant to clear the IER is used because KDB/KGDB printing
* is synchronized via CPU quiescence without holding the port
* lock.
*/
ier = serial_port_in(port, UART_IER);
serial8250_clear_IER(up);
__serial8250_clear_IER(up);
wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
/*
@ -2891,13 +2925,7 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
unsigned int size = serial8250_port_size(up);
struct uart_port *port = &up->port;
switch (port->iotype) {
case UPIO_AU:
case UPIO_TSI:
case UPIO_MEM32:
case UPIO_MEM32BE:
case UPIO_MEM16:
case UPIO_MEM:
if (uart_iotype_mmio(port->iotype)) {
if (!port->mapbase)
return -EINVAL;
@ -2911,14 +2939,9 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
return -ENOMEM;
}
}
return 0;
case UPIO_HUB6:
case UPIO_PORT:
} else if (uart_iotype_io(port->iotype)) {
if (!request_region(port->iobase, size, "serial"))
return -EBUSY;
return 0;
case UPIO_UNKNOWN:
break;
}
return 0;
@ -2929,15 +2952,9 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
unsigned int size = serial8250_port_size(up);
struct uart_port *port = &up->port;
switch (port->iotype) {
case UPIO_AU:
case UPIO_TSI:
case UPIO_MEM32:
case UPIO_MEM32BE:
case UPIO_MEM16:
case UPIO_MEM:
if (uart_iotype_mmio(port->iotype)) {
if (!port->mapbase)
break;
return;
if (port->flags & UPF_IOREMAP) {
iounmap(port->membase);
@ -2945,14 +2962,8 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
}
release_mem_region(port->mapbase, size);
break;
case UPIO_HUB6:
case UPIO_PORT:
} else if (uart_iotype_io(port->iotype)) {
release_region(port->iobase, size);
break;
case UPIO_UNKNOWN:
break;
}
}
@ -3024,9 +3035,14 @@ static ssize_t rx_trig_bytes_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct tty_port *port = dev_get_drvdata(dev);
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = state->uart_port;
int rxtrig_bytes;
rxtrig_bytes = do_serial8250_get_rxtrig(port);
if (uport->get_rxtrig)
rxtrig_bytes = uport->get_rxtrig(uport);
else
rxtrig_bytes = do_serial8250_get_rxtrig(port);
if (rxtrig_bytes < 0)
return rxtrig_bytes;
@ -3069,6 +3085,8 @@ static ssize_t rx_trig_bytes_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct tty_port *port = dev_get_drvdata(dev);
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = state->uart_port;
unsigned char bytes;
int ret;
@ -3079,7 +3097,10 @@ static ssize_t rx_trig_bytes_store(struct device *dev,
if (ret < 0)
return ret;
ret = do_serial8250_set_rxtrig(port, bytes);
if (uport->set_rxtrig)
ret = uport->set_rxtrig(uport, bytes);
else
ret = do_serial8250_set_rxtrig(port, bytes);
if (ret < 0)
return ret;
@ -3227,13 +3248,32 @@ void serial8250_set_defaults(struct uart_8250_port *up)
}
EXPORT_SYMBOL_GPL(serial8250_set_defaults);
void serial8250_fifo_wait_for_lsr_thre(struct uart_8250_port *up, unsigned int count)
void serial8250_fifo_wait_for_lsr_thre(struct uart_8250_port *up,
struct nbcon_write_context *wctxt,
unsigned int count)
{
unsigned int i;
/*
* For console writing, enter/exit an unsafe section for each byte
* in order to pass the ownership as quickly as possible if a higher
* priority context wants ownership. Otherwise, an attempt to take
* over the ownership might timeout. The new owner will wait for
* UART_LSR_THRE before reusing the fifo.
*/
for (i = 0; i < count; i++) {
if (wait_for_lsr(up, UART_LSR_THRE))
bool tx_ready;
if (wctxt && !nbcon_enter_unsafe(wctxt))
return;
tx_ready = wait_for_lsr(up, UART_LSR_THRE);
if (wctxt)
nbcon_exit_unsafe(wctxt);
if (tx_ready)
break;
}
}
EXPORT_SYMBOL_NS_GPL(serial8250_fifo_wait_for_lsr_thre, "SERIAL_8250");
@ -3242,7 +3282,11 @@ EXPORT_SYMBOL_NS_GPL(serial8250_fifo_wait_for_lsr_thre, "SERIAL_8250");
static void serial8250_console_putchar(struct uart_port *port, unsigned char ch)
{
struct uart_8250_port *up = up_to_u8250p(port);
serial_port_out(port, UART_TX, ch);
up->console_line_ended = (ch == '\n');
}
static void serial8250_console_wait_putchar(struct uart_port *port, unsigned char ch)
@ -3285,8 +3329,9 @@ static void serial8250_console_restore(struct uart_8250_port *up)
* It sends fifosize bytes and then waits for the fifo
* to get empty.
*/
static void serial8250_console_fifo_write(struct uart_8250_port *up,
const char *s, unsigned int count)
static void __serial8250_console_fifo_write(struct uart_8250_port *up,
struct nbcon_write_context *wctxt,
const char *s, unsigned int count)
{
const char *end = s + count;
unsigned int fifosize = up->tx_loadsz;
@ -3297,9 +3342,16 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up,
while (s != end) {
/* Allow timeout for each byte of a possibly full FIFO */
serial8250_fifo_wait_for_lsr_thre(up, fifosize);
serial8250_fifo_wait_for_lsr_thre(up, wctxt, fifosize);
/*
* Fill the FIFO. If a handover or takeover occurs, writing
* must be aborted since the string data is no longer valid.
*/
for (i = 0; i < fifosize && s != end; ++i) {
if (!nbcon_enter_unsafe(wctxt))
return;
if (*s == '\n' && !cr_sent) {
serial8250_console_putchar(port, '\r');
cr_sent = true;
@ -3307,6 +3359,8 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up,
serial8250_console_putchar(port, *s++);
cr_sent = false;
}
nbcon_exit_unsafe(wctxt);
}
tx_count = i;
}
@ -3315,39 +3369,92 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up,
* Allow timeout for each byte written since the caller will only wait
* for UART_LSR_BOTH_EMPTY using the timeout of a single character
*/
serial8250_fifo_wait_for_lsr_thre(up, tx_count);
serial8250_fifo_wait_for_lsr_thre(up, wctxt, tx_count);
}
static void serial8250_console_fifo_write(struct uart_8250_port *up,
struct nbcon_write_context *wctxt)
{
__serial8250_console_fifo_write(up, wctxt, wctxt->outbuf, wctxt->len);
}
static void __serial8250_console_byte_write(struct uart_8250_port *up,
struct nbcon_write_context *wctxt,
const char *s, unsigned int count)
{
struct uart_port *port = &up->port;
const char *end = s + count;
/*
* Write out the message. If a handover or takeover occurs, writing
* must be aborted since the string data is no longer valid.
*/
while (s != end) {
if (!nbcon_enter_unsafe(wctxt))
return;
uart_console_write(port, s++, 1, serial8250_console_wait_putchar);
nbcon_exit_unsafe(wctxt);
}
}
static void serial8250_console_byte_write(struct uart_8250_port *up,
struct nbcon_write_context *wctxt)
{
__serial8250_console_byte_write(up, wctxt, wctxt->outbuf, wctxt->len);
}
/*
* Print a string to the serial port trying not to disturb
* any possible real use of the port...
*
* The console_lock must be held when we get here.
*
* Doing runtime PM is really a bad idea for the kernel console.
* Thus, we assume the function is called when device is powered up.
* Print the console line using the appropriate variant. If ownership is lost
* at any time during printing, the printing is aborted.
*/
void serial8250_console_write(struct uart_8250_port *up, const char *s,
unsigned int count)
static void __serial8250_console_write(struct uart_8250_port *up,
struct nbcon_write_context *wctxt,
bool use_fifo)
{
/*
* If the console printer did not fully output the previous line, it
* must have been handed or taken over. Insert a newline in order to
* maintain clean output.
*/
if (!up->console_line_ended) {
if (use_fifo)
__serial8250_console_fifo_write(up, wctxt, "\n", 1);
else
__serial8250_console_byte_write(up, wctxt, "\n", 1);
}
if (use_fifo)
serial8250_console_fifo_write(up, wctxt);
else
serial8250_console_byte_write(up, wctxt);
}
/*
* Print a string to the serial port trying not to disturb
* any possible real use of the port...
*/
void serial8250_console_write(struct uart_8250_port *up,
struct nbcon_write_context *wctxt,
bool is_atomic)
{
struct uart_8250_em485 *em485 = up->em485;
struct uart_port *port = &up->port;
unsigned long flags;
unsigned int ier, use_fifo;
int locked = 1;
unsigned int ier;
bool use_fifo;
touch_nmi_watchdog();
if (oops_in_progress)
locked = uart_port_trylock_irqsave(port, &flags);
else
uart_port_lock_irqsave(port, &flags);
if (!nbcon_enter_unsafe(wctxt))
return;
/*
* First save the IER then disable the interrupts
* First, save the IER, then disable the interrupts. The special
* variant to clear the IER is used because emergency and panic
* printing is synchronized only by nbcon ownership without
* holding the port lock.
*/
ier = serial_port_in(port, UART_IER);
serial8250_clear_IER(up);
__serial8250_clear_IER(up);
/* check scratch reg to see if port powered off during system sleep */
if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) {
@ -3381,10 +3488,17 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
*/
!uart_console_hwflow_active(&up->port);
if (likely(use_fifo))
serial8250_console_fifo_write(up, s, count);
else
uart_console_write(port, s, count, serial8250_console_wait_putchar);
nbcon_exit_unsafe(wctxt);
__serial8250_console_write(up, wctxt, use_fifo);
/*
* Re-enter an unsafe section in order to perform final actions
* (such as re-enabling interrupts). If ownership was lost, this
* context must reacquire ownership.
*/
while (!nbcon_enter_unsafe(wctxt))
nbcon_reacquire_nobuf(wctxt);
/*
* Finally, wait for transmitter to become empty
@ -3394,10 +3508,21 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
if (em485) {
mdelay(port->rs485.delay_rts_after_send);
/* Toggle unsafe after possibly long delay */
nbcon_exit_unsafe(wctxt);
while (!nbcon_enter_unsafe(wctxt))
nbcon_reacquire_nobuf(wctxt);
if (em485->tx_stopped)
up->rs485_stop_tx(up, false);
}
/* Toggle unsafe after possibly long delay */
nbcon_exit_unsafe(wctxt);
while (!nbcon_enter_unsafe(wctxt))
nbcon_reacquire_nobuf(wctxt);
serial_port_out(port, UART_IER, ier);
/*
@ -3407,11 +3532,25 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
* call it if we have saved something in the saved flags
* while processing with interrupts off.
*/
if (up->msr_saved_flags)
serial8250_modem_status(up);
if (up->msr_saved_flags) {
if (is_atomic) {
/*
* For atomic, MSR handling must be deferred to
* irq_work because this may be a context that does
* not permit waking up tasks.
*
* But no irq_work may be queued when suspending.
* In that case, the MSR handling will occur during
* resume in serial8250_resume_port().
*/
if (up->console_msr_work_allow)
irq_work_queue(&up->console_msr_work);
} else {
serial8250_modem_status(up);
}
}
if (locked)
uart_port_unlock_irqrestore(port, flags);
nbcon_exit_unsafe(wctxt);
}
static unsigned int probe_baud(struct uart_port *port)
@ -3429,8 +3568,24 @@ static unsigned int probe_baud(struct uart_port *port)
return (port->uartclk / 16) / quot;
}
/*
* irq_work handler to perform modem control during console output.
* Only triggered via ->write_atomic() callback because it may be
* in a scheduler or NMI context, unable to wake tasks.
*/
static void console_msr_handler(struct irq_work *iwp)
{
struct uart_8250_port *up = container_of(iwp, struct uart_8250_port, console_msr_work);
struct uart_port *port = &up->port;
guard(uart_port_lock)(port);
serial8250_modem_status(up);
}
int serial8250_console_setup(struct uart_port *port, char *options, bool probe)
{
struct uart_8250_port *up = up_to_u8250p(port);
int baud = 9600;
int bits = 8;
int parity = 'n';
@ -3440,6 +3595,10 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe)
if (!port->iobase && !port->membase)
return -ENODEV;
up->console_line_ended = true;
up->console_msr_work_allow = true;
init_irq_work(&up->console_msr_work, console_msr_handler);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else if (probe)
@ -3460,6 +3619,10 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe)
int serial8250_console_exit(struct uart_port *port)
{
struct uart_8250_port *up = up_to_u8250p(port);
irq_work_sync(&up->console_msr_work);
if (port->dev)
pm_runtime_put_sync(port->dev);

View File

@ -19,35 +19,33 @@ static const struct uart_ops *core_port_base_ops;
static int rsa8250_request_resource(struct uart_8250_port *up)
{
struct uart_port *port = &up->port;
unsigned long start = UART_RSA_BASE << port->regshift;
unsigned int size = 8 << port->regshift;
unsigned long start;
unsigned int size;
switch (port->iotype) {
case UPIO_HUB6:
case UPIO_PORT:
start += port->iobase;
if (!request_region(start, size, "serial-rsa"))
return -EBUSY;
return 0;
default:
if (!uart_iotype_io(port->iotype))
return -EINVAL;
}
start = UART_RSA_BASE << port->regshift;
start += port->iobase;
size = 8 << port->regshift;
if (!request_region(start, size, "serial-rsa"))
return -EBUSY;
return 0;
}
static void rsa8250_release_resource(struct uart_8250_port *up)
{
struct uart_port *port = &up->port;
unsigned long offset = UART_RSA_BASE << port->regshift;
unsigned int size = 8 << port->regshift;
unsigned long offset;
unsigned int size;
switch (port->iotype) {
case UPIO_HUB6:
case UPIO_PORT:
release_region(port->iobase + offset, size);
break;
default:
break;
}
if (!uart_iotype_io(port->iotype))
return;
offset = UART_RSA_BASE << port->regshift;
size = 8 << port->regshift;
release_region(port->iobase + offset, size);
}
static void univ8250_config_port(struct uart_port *port, int flags)

View File

@ -141,6 +141,16 @@ config SERIAL_8250_EXAR
422x PCIe serial cards that are not covered by the more generic
SERIAL_8250_PCI option.
config SERIAL_8250_MOXA_PCIE
tristate "8250/16550 Moxa PCIe device support"
depends on SERIAL_8250 && PCI
default SERIAL_8250
help
Say Y here if you have a Moxa PCIe serial card.
To compile this driver as a module, choose M here: the
module will be called 8250_mxpcie.
config SERIAL_8250_HP300
tristate
depends on SERIAL_8250 && HP300

View File

@ -44,6 +44,7 @@ obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o
obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o
obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o
obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o
obj-$(CONFIG_SERIAL_8250_MOXA_PCIE) += 8250_mxpcie.o
obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
obj-$(CONFIG_SERIAL_8250_NI) += 8250_ni.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o

View File

@ -2543,7 +2543,7 @@ static int pl011_console_setup(struct console *co, char *options)
/* Allow pins to be muxed in and configured */
pinctrl_pm_select_default_state(uap->port.dev);
ret = clk_prepare(uap->clk);
ret = clk_prepare_enable(uap->clk);
if (ret)
return ret;
@ -2572,6 +2572,15 @@ static int pl011_console_setup(struct console *co, char *options)
return uart_set_options(&uap->port, co, baud, parity, bits, flow);
}
static int pl011_console_exit(struct console *co)
{
struct uart_amba_port *uap = amba_ports[co->index];
clk_disable_unprepare(uap->clk);
return 0;
}
/**
* pl011_console_match - non-standard console matching
* @co: registering console
@ -2641,8 +2650,6 @@ pl011_console_write_atomic(struct console *co, struct nbcon_write_context *wctxt
if (!nbcon_enter_unsafe(wctxt))
return;
clk_enable(uap->clk);
if (!uap->vendor->always_enabled) {
old_cr = pl011_read(uap, REG_CR);
pl011_write((old_cr & ~UART011_CR_CTSEN) | (UART01x_CR_UARTEN | UART011_CR_TXE),
@ -2659,8 +2666,6 @@ pl011_console_write_atomic(struct console *co, struct nbcon_write_context *wctxt
if (!uap->vendor->always_enabled)
pl011_write(old_cr, uap, REG_CR);
clk_disable(uap->clk);
nbcon_exit_unsafe(wctxt);
}
@ -2673,8 +2678,6 @@ pl011_console_write_thread(struct console *co, struct nbcon_write_context *wctxt
if (!nbcon_enter_unsafe(wctxt))
return;
clk_enable(uap->clk);
if (!uap->vendor->always_enabled) {
old_cr = pl011_read(uap, REG_CR);
pl011_write((old_cr & ~UART011_CR_CTSEN) | (UART01x_CR_UARTEN | UART011_CR_TXE),
@ -2703,8 +2706,6 @@ pl011_console_write_thread(struct console *co, struct nbcon_write_context *wctxt
if (!uap->vendor->always_enabled)
pl011_write(old_cr, uap, REG_CR);
clk_disable(uap->clk);
nbcon_exit_unsafe(wctxt);
}
@ -2725,6 +2726,7 @@ static struct console amba_console = {
.name = "ttyAMA",
.device = uart_console_device,
.setup = pl011_console_setup,
.exit = pl011_console_exit,
.match = pl011_console_match,
.write_atomic = pl011_console_write_atomic,
.write_thread = pl011_console_write_thread,
@ -3092,21 +3094,45 @@ static void pl011_remove(struct amba_device *dev)
static int pl011_suspend(struct device *dev)
{
struct uart_amba_port *uap = dev_get_drvdata(dev);
int ret;
if (!uap)
return -EINVAL;
return uart_suspend_port(&amba_reg, &uap->port);
ret = uart_suspend_port(&amba_reg, &uap->port);
if (ret)
return ret;
if (console_suspend_enabled && uap->port.suspended &&
uart_console_registered(&uap->port))
clk_disable_unprepare(uap->clk);
return 0;
}
static int pl011_resume(struct device *dev)
{
struct uart_amba_port *uap = dev_get_drvdata(dev);
bool resume_console;
int ret;
if (!uap)
return -EINVAL;
return uart_resume_port(&amba_reg, &uap->port);
resume_console = console_suspend_enabled &&
uap->port.suspended &&
uart_console_registered(&uap->port);
if (resume_console) {
ret = clk_prepare_enable(uap->clk);
if (ret)
return ret;
}
ret = uart_resume_port(&amba_reg, &uap->port);
if (ret && resume_console)
clk_disable_unprepare(uap->clk);
return ret;
}
#endif

View File

@ -838,11 +838,12 @@ static int bcm_uart_probe(struct platform_device *pdev)
port->irq = ret;
clk = clk_get(&pdev->dev, "refclk");
if (IS_ERR(clk) && pdev->dev.of_node)
clk = of_clk_get(pdev->dev.of_node, 0);
if (IS_ERR(clk))
return -ENODEV;
if (IS_ERR(clk)) {
if (pdev->dev.of_node)
clk = of_clk_get(pdev->dev.of_node, 0);
if (IS_ERR(clk))
return -ENODEV;
}
port->iotype = UPIO_MEM;
port->ops = &bcm_uart_ops;

View File

@ -27,7 +27,6 @@
#include <linux/memblock.h>
#include <linux/dma-mapping.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/gpio/consumer.h>
#include <linux/clk.h>
@ -1530,16 +1529,14 @@ static int cpm_uart_probe(struct platform_device *ofdev)
/* initialize the device pointer for the port */
pinfo->port.dev = &ofdev->dev;
pinfo->port.irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
if (!pinfo->port.irq)
return -EINVAL;
pinfo->port.irq = platform_get_irq(ofdev, 0);
if (pinfo->port.irq < 0)
return pinfo->port.irq;
ret = cpm_uart_init_port(ofdev->dev.of_node, pinfo);
if (!ret)
return uart_add_one_port(&cpm_reg, &pinfo->port);
irq_dispose_mapping(pinfo->port.irq);
return ret;
}

View File

@ -75,19 +75,12 @@ static void __init earlycon_print_info(struct earlycon_device *device)
{
struct console *earlycon = device->con;
struct uart_port *port = &device->port;
char ioinfos[64];
if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM16 ||
port->iotype == UPIO_MEM32 || port->iotype == UPIO_MEM32BE)
pr_info("%s%d at MMIO%s %pa (options '%s')\n",
earlycon->name, earlycon->index,
(port->iotype == UPIO_MEM) ? "" :
(port->iotype == UPIO_MEM16) ? "16" :
(port->iotype == UPIO_MEM32) ? "32" : "32be",
&port->mapbase, device->options);
else
pr_info("%s%d at I/O port 0x%lx (options '%s')\n",
earlycon->name, earlycon->index,
port->iobase, device->options);
uart_get_ioinfos(port, ioinfos, sizeof(ioinfos));
pr_info("%s%d%s (options '%s')\n", earlycon->name, earlycon->index,
ioinfos, device->options);
}
static int __init parse_options(struct earlycon_device *device, char *options)

View File

@ -22,6 +22,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/ktime.h>
#include <linux/mutex.h>
#include <linux/pinctrl/consumer.h>
#include <linux/rational.h>
#include <linux/slab.h>
@ -2080,6 +2081,9 @@ static const struct uart_ops imx_uart_pops = {
static struct imx_port *imx_uart_ports[UART_NR];
/* Held across uart_add/remove_one_port(); console callbacks must not take it. */
static DEFINE_MUTEX(imx_uart_ports_lock);
#if IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE)
static void imx_uart_console_putchar(struct uart_port *port, unsigned char ch)
{
@ -2602,41 +2606,38 @@ static int imx_uart_probe(struct platform_device *pdev)
if (txirq > 0) {
ret = devm_request_irq(&pdev->dev, rxirq, imx_uart_rxint, 0,
dev_name(&pdev->dev), sport);
if (ret) {
dev_err(&pdev->dev, "failed to request rx irq: %d\n",
ret);
if (ret)
goto err_clk;
}
ret = devm_request_irq(&pdev->dev, txirq, imx_uart_txint, 0,
dev_name(&pdev->dev), sport);
if (ret) {
dev_err(&pdev->dev, "failed to request tx irq: %d\n",
ret);
if (ret)
goto err_clk;
}
ret = devm_request_irq(&pdev->dev, rtsirq, imx_uart_rtsint, 0,
dev_name(&pdev->dev), sport);
if (ret) {
dev_err(&pdev->dev, "failed to request rts irq: %d\n",
ret);
if (ret)
goto err_clk;
}
} else {
ret = devm_request_irq(&pdev->dev, rxirq, imx_uart_int, 0,
dev_name(&pdev->dev), sport);
if (ret) {
dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
if (ret)
goto err_clk;
}
}
imx_uart_ports[sport->port.line] = sport;
platform_set_drvdata(pdev, sport);
ret = uart_add_one_port(&imx_uart_uart_driver, &sport->port);
scoped_guard(mutex, &imx_uart_ports_lock) {
if (imx_uart_ports[sport->port.line]) {
ret = -EBUSY;
} else {
imx_uart_ports[sport->port.line] = sport;
ret = uart_add_one_port(&imx_uart_uart_driver,
&sport->port);
if (ret)
imx_uart_ports[sport->port.line] = NULL;
}
}
err_clk:
clk_disable_unprepare(sport->clk_ipg);
@ -2648,7 +2649,9 @@ static void imx_uart_remove(struct platform_device *pdev)
{
struct imx_port *sport = platform_get_drvdata(pdev);
guard(mutex)(&imx_uart_ports_lock);
uart_remove_one_port(&imx_uart_uart_driver, &sport->port);
imx_uart_ports[sport->port.line] = NULL;
}
static void imx_uart_restore_context(struct imx_port *sport)

View File

@ -363,7 +363,7 @@ static int param_set_kgdboc_var(const char *kmessage,
mutex_lock(&config_mutex);
strcpy(config, kmessage);
strscpy(config, kmessage);
/* Chop out \n char as a result of echo */
if (len && config[len - 1] == '\n')
config[len - 1] = '\0';

View File

@ -608,8 +608,14 @@ static int __init ma35d1serial_console_setup(struct console *co, char *options)
if (!np || !p)
return -ENODEV;
if (of_property_read_u32_array(np, "reg", val32, ARRAY_SIZE(val32)) != 0)
if (of_property_read_u32_array(np, "reg", val32, ARRAY_SIZE(val32)) != 0) {
of_node_put(np);
ma35d1serial_uart_nodes[co->index] = NULL;
return -EINVAL;
}
of_node_put(np);
ma35d1serial_uart_nodes[co->index] = NULL;
p->port.iobase = val32[1];
p->port.membase = ioremap(p->port.iobase, MA35_UART_REG_SIZE);
@ -648,8 +654,10 @@ static void ma35d1serial_console_init_port(void)
of_node_get(np);
ma35d1serial_uart_nodes[i] = np;
i++;
if (i == MA35_UART_NR)
if (i == MA35_UART_NR) {
of_node_put(np);
break;
}
}
}
}

View File

@ -724,6 +724,7 @@ static int max3100_probe(struct spi_device *spi)
max3100s[i]->port.ops = &max3100_ops;
max3100s[i]->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
max3100s[i]->port.line = i;
max3100s[i]->port.iotype = UPIO_BUS;
max3100s[i]->port.type = PORT_MAX3100;
max3100s[i]->port.dev = &spi->dev;

View File

@ -16,7 +16,6 @@
#include <linux/device.h>
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/kconfig.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/regmap.h>
@ -1400,30 +1399,18 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk);
/*
* Set up each port's state before registering the gpiochip,
* since the gpiochip callbacks will read s->p[i].regmap as
* soon as gpiolib exposes the controller.
*/
for (i = 0; i < devtype->nr; i++) {
unsigned int line;
line = find_first_zero_bit(max310x_lines, MAX310X_UART_NRMAX);
if (line == MAX310X_UART_NRMAX) {
ret = -ERANGE;
goto out_uart;
}
/* Initialize port data */
s->p[i].port.line = line;
s->p[i].port.dev = dev;
s->p[i].port.irq = irq;
s->p[i].port.type = PORT_MAX310X;
s->p[i].port.fifosize = MAX310X_FIFO_SIZE;
s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
s->p[i].port.iotype = UPIO_PORT;
s->p[i].port.iobase = i;
/*
* Use all ones as membase to make sure uart_configure_port() in
* serial_core.c does not abort for SPI/I2C devices where the
* membase address is not applicable.
*/
s->p[i].port.membase = (void __iomem *)~0;
s->p[i].port.iotype = UPIO_BUS;
s->p[i].port.uartclk = uartclk;
s->p[i].port.rs485_config = max310x_rs485_config;
s->p[i].port.rs485_supported = max310x_rs485_supported;
@ -1440,20 +1427,16 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
INIT_WORK(&s->p[i].md_work, max310x_md_proc);
/* Initialize queue for changing RS485 mode */
INIT_WORK(&s->p[i].rs_work, max310x_rs_proc);
/* Register port */
ret = uart_add_one_port(&max310x_uart, &s->p[i].port);
if (ret)
goto out_uart;
set_bit(line, max310x_lines);
/* Go to suspend mode */
max310x_power(&s->p[i].port, 0);
}
#ifdef CONFIG_GPIOLIB
/* Setup GPIO controller */
/*
* Register the GPIO controller before adding the UART ports so
* that consumers referencing the chip's own GPIOs from device
* tree (for example rs485-term-gpios = <&max310x ...>) can
* resolve them at uart_add_one_port() time instead of receiving
* -EPROBE_DEFER from their own provider.
*/
s->gpio.owner = THIS_MODULE;
s->gpio.parent = dev;
s->gpio.label = devtype->name;
@ -1471,6 +1454,64 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
goto out_uart;
#endif
for (i = 0; i < devtype->nr; i++) {
struct fwnode_handle *saved_fwnode = dev_fwnode(dev);
struct device_node *port_np = NULL;
struct device_node *child;
unsigned int line;
line = find_first_zero_bit(max310x_lines, MAX310X_UART_NRMAX);
if (line == MAX310X_UART_NRMAX) {
ret = -ERANGE;
goto out_uart;
}
s->p[i].port.line = line;
/* Locate the matching "serial@i" DT subnode, if any. */
for_each_available_child_of_node(dev->of_node, child) {
u32 reg;
if (!of_node_name_eq(child, "serial"))
continue;
if (of_property_read_u32(child, "reg", &reg))
continue;
if (reg == i) {
port_np = child;
break;
}
}
/*
* Temporarily retarget dev's fwnode to the per-port subnode
* so uart_get_rs485_mode() picks up the per-port properties.
* For single-port variants, fall back to the chip's own
* fwnode so legacy DTs that declare rs485 properties at the
* top level keep working.
*/
if (port_np) {
device_set_node(dev, of_fwnode_handle(port_np));
ret = uart_get_rs485_mode(&s->p[i].port);
device_set_node(dev, saved_fwnode);
of_node_put(port_np);
if (ret)
goto out_uart;
} else if (devtype->nr == 1) {
ret = uart_get_rs485_mode(&s->p[i].port);
if (ret)
goto out_uart;
}
/* Register port */
ret = uart_add_one_port(&max310x_uart, &s->p[i].port);
if (ret)
goto out_uart;
set_bit(line, max310x_lines);
/* Go to suspend mode */
max310x_power(&s->p[i].port, 0);
}
/* Setup interrupt */
ret = devm_request_threaded_irq(dev, irq, NULL, max310x_ist,
IRQF_ONESHOT | IRQF_SHARED, dev_name(dev), s);

View File

@ -16,6 +16,7 @@
#include <linux/tty_flip.h>
#include <linux/bitops.h>
#include <linux/mcb.h>
#include <linux/slab.h>
#define MEN_Z135_MAX_PORTS 12
#define MEN_Z135_BASECLK 29491200
@ -811,7 +812,7 @@ static int men_z135_probe(struct mcb_device *mdev,
if (!uart)
return -ENOMEM;
uart->rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
uart->rxbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!uart->rxbuf)
return -ENOMEM;
@ -841,7 +842,7 @@ static int men_z135_probe(struct mcb_device *mdev,
return 0;
err:
free_page((unsigned long) uart->rxbuf);
kfree(uart->rxbuf);
dev_err(dev, "Failed to add UART: %d\n", err);
return err;
@ -858,7 +859,7 @@ static void men_z135_remove(struct mcb_device *mdev)
line--;
uart_remove_one_port(&men_z135_driver, &uart->port);
free_page((unsigned long) uart->rxbuf);
kfree(uart->rxbuf);
}
static const struct mcb_device_id men_z135_ids[] = {

View File

@ -645,6 +645,8 @@ static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port)
/* Check if it is an interrupt for this port */
psc_num = (port->mapbase & 0xf00) >> 8;
if (psc_num >= ARRAY_SIZE(psc_mclk_clk))
return IRQ_NONE;
if (test_bit(psc_num, &fifoc_int) ||
test_bit(psc_num + 16, &fifoc_int))
return mpc5xxx_uart_process_int(port);
@ -663,6 +665,8 @@ static int mpc512x_psc_alloc_clock(struct uart_port *port)
int err;
psc_num = (port->mapbase & 0xf00) >> 8;
if (psc_num >= ARRAY_SIZE(psc_mclk_clk))
return -EINVAL;
clk = devm_clk_get(port->dev, "mclk");
if (IS_ERR(clk)) {
@ -711,6 +715,8 @@ static void mpc512x_psc_relse_clock(struct uart_port *port)
struct clk *clk;
psc_num = (port->mapbase & 0xf00) >> 8;
if (psc_num >= ARRAY_SIZE(psc_mclk_clk))
return;
clk = psc_mclk_clk[psc_num];
if (clk) {
clk_disable_unprepare(clk);
@ -733,6 +739,8 @@ static int mpc512x_psc_endis_clock(struct uart_port *port, int enable)
return 0;
psc_num = (port->mapbase & 0xf00) >> 8;
if (psc_num >= ARRAY_SIZE(psc_mclk_clk))
return -ENODEV;
psc_clk = psc_mclk_clk[psc_num];
if (!psc_clk) {
dev_err(port->dev, "Failed to get PSC clock entry!\n");

View File

@ -404,29 +404,21 @@ static int mvebu_uart_startup(struct uart_port *port)
ret = devm_request_irq(port->dev, mvuart->irq[UART_IRQ_SUM],
mvebu_uart_isr, port->irqflags,
dev_name(port->dev), port);
if (ret) {
dev_err(port->dev, "unable to request IRQ %d\n",
mvuart->irq[UART_IRQ_SUM]);
if (ret)
return ret;
}
} else {
/* New bindings with an IRQ for RX and TX (both UART) */
ret = devm_request_irq(port->dev, mvuart->irq[UART_RX_IRQ],
mvebu_uart_rx_isr, port->irqflags,
dev_name(port->dev), port);
if (ret) {
dev_err(port->dev, "unable to request IRQ %d\n",
mvuart->irq[UART_RX_IRQ]);
if (ret)
return ret;
}
ret = devm_request_irq(port->dev, mvuart->irq[UART_TX_IRQ],
mvebu_uart_tx_isr, port->irqflags,
dev_name(port->dev),
port);
if (ret) {
dev_err(port->dev, "unable to request IRQ %d\n",
mvuart->irq[UART_TX_IRQ]);
devm_free_irq(port->dev, mvuart->irq[UART_RX_IRQ],
port);
return ret;

View File

@ -678,6 +678,11 @@ static void pch_request_dma(struct uart_port *port)
/* Get DMA's dev information */
dma_dev = pci_get_slot(priv->pdev->bus,
PCI_DEVFN(PCI_SLOT(priv->pdev->devfn), 0));
if (!dma_dev) {
dev_err(priv->port.dev, "%s: failed to get DMA device\n",
__func__);
return;
}
/* Set Tx DMA */
param = &priv->param_tx;
@ -1662,7 +1667,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
if (priv == NULL)
goto init_port_alloc_err;
rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
rxbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!rxbuf)
goto init_port_free_txbuf;
@ -1735,7 +1740,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
pch_uart_ports[board->line_no] = NULL;
#endif
free_page((unsigned long)rxbuf);
kfree(rxbuf);
init_port_free_txbuf:
kfree(priv);
init_port_alloc_err:
@ -1750,7 +1755,7 @@ static void pch_uart_exit_port(struct eg20t_port *priv)
snprintf(name, sizeof(name), "uart%d_regs", priv->port.line);
debugfs_lookup_and_remove(name, NULL);
uart_remove_one_port(&pch_uart_driver, &priv->port);
free_page((unsigned long)priv->rxbuf.buf);
kfree(priv->rxbuf.buf);
}
static void pch_uart_pci_remove(struct pci_dev *pdev)

File diff suppressed because it is too large Load Diff

View File

@ -197,7 +197,7 @@ struct rp2_card {
};
#define RP_ID(prod) PCI_VDEVICE(RP, (prod))
#define RP_CAP(ports, smpte) (((ports) << 8) | ((smpte) << 0))
#define RP_CAP(ports, smpte) .driver_data = (((ports) << 8) | ((smpte) << 0))
static inline void rp2_decode_cap(const struct pci_device_id *id,
int *ports, int *smpte)

View File

@ -265,8 +265,6 @@ static void rsci_set_termios(struct uart_port *port, struct ktermios *termios,
}
baud = uart_get_baud_rate(port, termios, old, 0, max_freq);
if (!baud)
goto done;
/* Divided Functional Clock using standard Bit Rate Register */
err = sci_scbrr_calc(s, baud, &brr1, &srr1, &cks1);
@ -278,7 +276,6 @@ static void rsci_set_termios(struct uart_port *port, struct ktermios *termios,
cks = cks1;
}
done:
if (best_clk >= 0)
dev_dbg(port->dev, "Using clk %pC for %u%+d bps\n",
s->clks[best_clk], baud, min_err);

View File

@ -1486,14 +1486,7 @@ static int sc16is7xx_setup_channel(struct sc16is7xx_one *one, int i,
port->type = PORT_SC16IS7XX;
port->fifosize = SC16IS7XX_FIFO_SIZE;
port->flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
port->iobase = i;
/*
* Use all ones as membase to make sure uart_configure_port() in
* serial_core.c does not abort for SPI/I2C devices where the
* membase address is not applicable.
*/
port->membase = (void __iomem *)~0;
port->iotype = UPIO_PORT;
port->iotype = UPIO_BUS;
port->rs485_config = sc16is7xx_config_rs485;
port->rs485_supported = sc16is7xx_rs485_supported;
port->ops = &sc16is7xx_ops;

View File

@ -33,6 +33,7 @@
#include <linux/uaccess.h>
#include "serial_base.h"
#include "8250/8250.h" /* For hub6_match_port() */
/*
* This is used to lock changes in serial line configuration.
@ -1962,6 +1963,34 @@ static const char *uart_type(struct uart_port *port)
return str;
}
bool uart_iotype_mmio(enum uart_iotype iotype)
{
switch (iotype) {
case UPIO_MEM:
case UPIO_MEM32:
case UPIO_AU:
case UPIO_TSI:
case UPIO_MEM32BE:
case UPIO_MEM16:
return true;
default:
return false;
}
}
EXPORT_SYMBOL_GPL(uart_iotype_mmio);
bool uart_iotype_io(enum uart_iotype iotype)
{
switch (iotype) {
case UPIO_PORT:
case UPIO_HUB6:
return true;
default:
return false;
}
}
EXPORT_SYMBOL_GPL(uart_iotype_io);
#ifdef CONFIG_PROC_FS
static void uart_line_info(struct seq_file *m, struct uart_state *state)
@ -1969,9 +1998,9 @@ static void uart_line_info(struct seq_file *m, struct uart_state *state)
struct tty_port *port = &state->port;
enum uart_pm_state pm_state;
struct uart_port *uport;
char ioinfos[64];
char stat_buf[32];
unsigned int status;
int mmio;
guard(mutex)(&port->mutex);
@ -1979,13 +2008,10 @@ static void uart_line_info(struct seq_file *m, struct uart_state *state)
if (!uport)
return;
mmio = uport->iotype >= UPIO_MEM;
seq_printf(m, "%u: uart:%s %s%08llX irq:%u",
uport->line, uart_type(uport),
mmio ? "mmio:0x" : "port:",
mmio ? (unsigned long long)uport->mapbase
: (unsigned long long)uport->iobase,
uport->irq);
seq_printf(m, "%u: uart:%s", uport->line, uart_type(uport));
uart_get_ioinfos(uport, ioinfos, sizeof(ioinfos));
seq_printf(m, "%s", ioinfos);
seq_printf(m, " irq:%u", uport->irq);
if (uport->type == PORT_UNKNOWN) {
seq_putc(m, '\n');
@ -2459,38 +2485,47 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
}
EXPORT_SYMBOL(uart_resume_port);
static const char *uart_get_mmio_width(struct uart_port *port)
{
switch (port->iotype) {
case UPIO_MEM16:
return "16";
case UPIO_MEM32:
case UPIO_MEM32BE:
return "32";
case UPIO_AU:
case UPIO_MEM:
default:
return "";
}
}
void uart_get_ioinfos(struct uart_port *port, char *buf, size_t size)
{
buf[0] = '\0';
if (uart_iotype_mmio(port->iotype)) {
scnprintf(buf, size, " MMIO%s:%pa", uart_get_mmio_width(port), &port->mapbase);
} else if (uart_iotype_io(port->iotype)) {
if (port->iotype == UPIO_PORT)
scnprintf(buf, size, " I/O:0x%lx", port->iobase);
else if (port->iotype == UPIO_HUB6)
scnprintf(buf, size, " I/O:0x%lx, offset 0x%x", port->iobase, port->hub6);
}
}
EXPORT_SYMBOL(uart_get_ioinfos);
static inline void
uart_report_port(struct uart_driver *drv, struct uart_port *port)
{
char address[64];
char ioinfos[64];
switch (port->iotype) {
case UPIO_PORT:
snprintf(address, sizeof(address), "I/O 0x%lx", port->iobase);
break;
case UPIO_HUB6:
snprintf(address, sizeof(address),
"I/O 0x%lx offset 0x%x", port->iobase, port->hub6);
break;
case UPIO_MEM:
case UPIO_MEM16:
case UPIO_MEM32:
case UPIO_MEM32BE:
case UPIO_AU:
case UPIO_TSI:
snprintf(address, sizeof(address),
"MMIO 0x%llx", (unsigned long long)port->mapbase);
break;
default:
strscpy(address, "*unknown*", sizeof(address));
break;
}
uart_get_ioinfos(port, ioinfos, sizeof(ioinfos));
pr_info("%s%s%s at %s (irq = %u, base_baud = %u) is a %s\n",
port->dev ? dev_name(port->dev) : "",
port->dev ? ": " : "",
port->name,
address, port->irq, port->uartclk / 16, uart_type(port));
pr_info("%s%s%s%s (irq = %u, base_baud = %u) is a %s\n",
port->dev ? dev_name(port->dev) : "",
port->dev ? ": " : "",
port->name, ioinfos, port->irq, port->uartclk / 16, uart_type(port));
/* The magic multiplier feature is a bit obscure, so report it too. */
if (port->flags & UPF_MAGIC_MULTIPLIER)
@ -2507,11 +2542,10 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
{
unsigned int flags;
/*
* If there isn't a port here, don't do anything further.
*/
if (!port->iobase && !port->mapbase && !port->membase)
return;
/* If there isn't a port here, don't do anything further. */
if (uart_iotype_mmio(port->iotype) || uart_iotype_io(port->iotype))
if (!port->iobase && !port->mapbase && !port->membase)
return;
/*
* Now do the auto configuration stuff. Note that config_port
@ -2777,8 +2811,10 @@ int uart_register_driver(struct uart_driver *drv)
for (i = 0; i < drv->nr; i++)
tty_port_destroy(&drv->state[i].port);
tty_driver_kref_put(normal);
drv->tty_driver = NULL;
out_kfree:
kfree(drv->state);
drv->state = NULL;
out:
return retval;
}
@ -3056,7 +3092,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
struct uart_state *state;
struct tty_port *port;
struct device *tty_dev;
int num_groups;
if (uport->line >= drv->nr)
return -EINVAL;
@ -3068,6 +3103,22 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
if (state->uart_port)
return -EINVAL;
uport->name = kasprintf(GFP_KERNEL, "%s%u", drv->dev_name,
drv->tty_driver->name_base + uport->line);
if (!uport->name)
return -ENOMEM;
/*
* uart_configure_port() may set uport->attr_group and register the
* console. Allocate room for both groups and a NULL terminator first.
*/
uport->tty_groups = kzalloc_objs(*uport->tty_groups, 3);
if (!uport->tty_groups) {
kfree(uport->name);
return -ENOMEM;
}
uport->tty_groups[0] = &tty_dev_attr_group;
/* Link the port to the driver state table and vice versa */
atomic_set(&state->refcount, 1);
init_waitqueue_head(&state->remove_wait);
@ -3084,10 +3135,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
state->pm_state = UART_PM_STATE_UNDEFINED;
uart_port_set_cons(uport, drv->cons);
uport->minor = drv->tty_driver->minor_start + uport->line;
uport->name = kasprintf(GFP_KERNEL, "%s%u", drv->dev_name,
drv->tty_driver->name_base + uport->line);
if (!uport->name)
return -ENOMEM;
if (uport->cons && uport->dev)
of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
@ -3102,15 +3149,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
port->console = uart_console(uport);
num_groups = 2;
if (uport->attr_group)
num_groups++;
uport->tty_groups = kzalloc_objs(*uport->tty_groups, num_groups);
if (!uport->tty_groups)
return -ENOMEM;
uport->tty_groups[0] = &tty_dev_attr_group;
if (uport->attr_group)
uport->tty_groups[1] = uport->attr_group;
@ -3208,23 +3246,16 @@ bool uart_match_port(const struct uart_port *port1,
{
if (port1->iotype != port2->iotype)
return false;
switch (port1->iotype) {
case UPIO_PORT:
else if (port1->iotype == UPIO_PORT)
return port1->iobase == port2->iobase;
case UPIO_HUB6:
return port1->iobase == port2->iobase &&
port1->hub6 == port2->hub6;
case UPIO_MEM:
case UPIO_MEM16:
case UPIO_MEM32:
case UPIO_MEM32BE:
case UPIO_AU:
case UPIO_TSI:
else if (port1->iotype == UPIO_HUB6)
return hub6_match_port(port1, port2);
else if (uart_iotype_mmio(port1->iotype))
return port1->mapbase == port2->mapbase;
default:
else if (port1->iotype == UPIO_BUS)
return true;
else
return false;
}
}
EXPORT_SYMBOL(uart_match_port);

View File

@ -256,9 +256,6 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
gpios);
if (ret) {
/* alternatively implement polling */
dev_err(port->dev,
"failed to request irq for %s (idx=%d, err=%d)\n",
mctrl_gpios_desc[i].name, idx, ret);
return ERR_PTR(ret);
}
}

View File

@ -2719,8 +2719,6 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
max_freq = max(max_freq, s->clk_rates[i]);
baud = uart_get_baud_rate(port, termios, old, 0, max_freq / min_sr(s));
if (!baud)
goto done;
/*
* There can be multiple sources for the sampling clock. Find the one

View File

@ -741,11 +741,8 @@ static int sprd_startup(struct uart_port *port)
ret = devm_request_irq(port->dev, port->irq, sprd_handle_irq,
IRQF_SHARED, sp->name, port);
if (ret) {
dev_err(port->dev, "fail to request serial irq %d, ret=%d\n",
port->irq, ret);
if (ret)
return ret;
}
fc = serial_in(port, SPRD_CTL1);
fc |= RX_TOUT_THLD_DEF | RX_HFC_THLD_DEF;
serial_out(port, SPRD_CTL1, fc);

View File

@ -3140,8 +3140,10 @@ static int tty_cdev_add(struct tty_driver *driver, dev_t dev,
driver->cdevs[index]->ops = &tty_fops;
driver->cdevs[index]->owner = driver->owner;
err = cdev_add(driver->cdevs[index], dev, count);
if (err)
if (err) {
kobject_put(&driver->cdevs[index]->kobj);
driver->cdevs[index] = NULL;
}
return err;
}
@ -3278,7 +3280,7 @@ EXPORT_SYMBOL_GPL(tty_register_device_attr);
void tty_unregister_device(struct tty_driver *driver, unsigned index)
{
device_destroy(&tty_class, MKDEV(driver->major, driver->minor_start) + index);
if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) {
if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) && driver->cdevs[index]) {
cdev_del(driver->cdevs[index]);
driver->cdevs[index] = NULL;
}

View File

@ -506,29 +506,23 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
if (pgrp_nr < 0)
return -EINVAL;
spin_lock_irq(&real_tty->ctrl.lock);
guard(spinlock_irq)(&real_tty->ctrl.lock);
if (!current->signal->tty ||
(current->signal->tty != real_tty) ||
(real_tty->ctrl.session != task_session(current))) {
retval = -ENOTTY;
goto out_unlock_ctrl;
}
rcu_read_lock();
(real_tty->ctrl.session != task_session(current)))
return -ENOTTY;
guard(rcu)();
pgrp = find_vpid(pgrp_nr);
retval = -ESRCH;
if (!pgrp)
goto out_unlock;
retval = -EPERM;
return -ESRCH;
if (session_of_pgrp(pgrp) != task_session(current))
goto out_unlock;
retval = 0;
return -EPERM;
put_pid(real_tty->ctrl.pgrp);
real_tty->ctrl.pgrp = get_pid(pgrp);
out_unlock:
rcu_read_unlock();
out_unlock_ctrl:
spin_unlock_irq(&real_tty->ctrl.lock);
return retval;
return 0;
}
/**
@ -542,7 +536,6 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
*/
static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
{
unsigned long flags;
pid_t sid;
/*
@ -552,17 +545,13 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _
if (tty == real_tty && current->signal->tty != real_tty)
return -ENOTTY;
spin_lock_irqsave(&real_tty->ctrl.lock, flags);
if (!real_tty->ctrl.session)
goto err;
sid = pid_vnr(real_tty->ctrl.session);
spin_unlock_irqrestore(&real_tty->ctrl.lock, flags);
scoped_guard(spinlock_irqsave, &real_tty->ctrl.lock) {
if (!real_tty->ctrl.session)
return -ENOTTY;
sid = pid_vnr(real_tty->ctrl.session);
}
return put_user(sid, p);
err:
spin_unlock_irqrestore(&real_tty->ctrl.lock, flags);
return -ENOTTY;
}
/*

View File

@ -53,8 +53,6 @@
#define HEADER_SIZE 4u
#define CON_BUF_SIZE (IS_ENABLED(CONFIG_BASE_SMALL) ? 256 : PAGE_SIZE)
DEFINE_FREE(free_page_ptr, void *, if (_T) free_page((unsigned long)_T));
/*
* Our minor space:
*
@ -371,7 +369,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
loff_t pos;
bool viewed, attr, uni_mode;
char *con_buf __free(free_page_ptr) = (char *)__get_free_page(GFP_KERNEL);
char *con_buf __free(kfree) = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!con_buf)
return -ENOMEM;
@ -596,7 +594,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
if (use_unicode(inode))
return -EOPNOTSUPP;
char *con_buf __free(free_page_ptr) = (char *)__get_free_page(GFP_KERNEL);
char *con_buf __free(kfree) = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!con_buf)
return -ENOMEM;

View File

@ -598,6 +598,8 @@ static int vt_setactivate(struct vt_setactivate __user *sa)
return -EFAULT;
if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES)
return -ENXIO;
if (vsa.mode.mode != VT_AUTO && vsa.mode.mode != VT_PROCESS)
return -EINVAL;
vsa.console--;
vsa.console = array_index_nospec(vsa.console, MAX_NR_CONSOLES);

View File

@ -2,8 +2,6 @@
#ifndef __LINUX_GOLDFISH_H
#define __LINUX_GOLDFISH_H
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/io.h>
/* Helpers for Goldfish virtual platform */
@ -15,26 +13,4 @@
#define gf_iowrite32 iowrite32
#endif
static inline void gf_write_ptr(const void *ptr, void __iomem *portl,
void __iomem *porth)
{
const unsigned long addr = (unsigned long)ptr;
gf_iowrite32(lower_32_bits(addr), portl);
#ifdef CONFIG_64BIT
gf_iowrite32(upper_32_bits(addr), porth);
#endif
}
static inline void gf_write_dma_addr(const dma_addr_t addr,
void __iomem *portl,
void __iomem *porth)
{
gf_iowrite32(lower_32_bits(addr), portl);
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
gf_iowrite32(upper_32_bits(addr), porth);
#endif
}
#endif /* __LINUX_GOLDFISH_H */

View File

@ -150,8 +150,20 @@ struct uart_8250_port {
#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
u16 lsr_saved_flags;
u16 lsr_save_mask;
/*
* Track when a console line has been fully written to the
* hardware, i.e. true when the most recent byte written to
* UART_TX by the console was '\n'.
*/
bool console_line_ended;
/* Allow queuing irq_work for MSR handling */
bool console_msr_work_allow;
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
unsigned char msr_saved_flags;
struct irq_work console_msr_work;
struct uart_8250_dma *dma;
const struct uart_8250_ops *ops;
@ -192,6 +204,7 @@ void serial8250_do_shutdown(struct uart_port *port);
void serial8250_do_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate);
void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl);
void serial8250_do_break_ctl(struct uart_port *port, int break_state);
void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud,
unsigned int quot);
int fsl8250_handle_irq(struct uart_port *port);
@ -203,8 +216,8 @@ void serial8250_tx_chars(struct uart_8250_port *up);
unsigned int serial8250_modem_status(struct uart_8250_port *up);
void serial8250_init_port(struct uart_8250_port *up);
void serial8250_set_defaults(struct uart_8250_port *up);
void serial8250_console_write(struct uart_8250_port *up, const char *s,
unsigned int count);
void serial8250_console_write(struct uart_8250_port *up,
struct nbcon_write_context *wctxt, bool in_atomic);
int serial8250_console_setup(struct uart_port *port, char *options, bool probe);
int serial8250_console_exit(struct uart_port *port);

View File

@ -437,6 +437,7 @@ enum uart_iotype {
UPIO_TSI = SERIAL_IO_TSI, /* Tsi108/109 type IO */
UPIO_MEM32BE = SERIAL_IO_MEM32BE, /* 32b big endian */
UPIO_MEM16 = SERIAL_IO_MEM16, /* 16b little endian */
UPIO_BUS = SERIAL_IO_BUS, /* Serial bus I/O access (ex: SPI, I2C) */
};
struct uart_port {
@ -459,10 +460,13 @@ struct uart_port {
unsigned int baud,
unsigned int quot,
unsigned int quot_frac);
int (*get_rxtrig)(struct uart_port *port);
int (*set_rxtrig)(struct uart_port *port, unsigned char bytes);
int (*startup)(struct uart_port *port);
void (*shutdown)(struct uart_port *port);
void (*throttle)(struct uart_port *port);
void (*unthrottle)(struct uart_port *port);
void (*break_ctl)(struct uart_port *port, int break_state);
int (*handle_irq)(struct uart_port *);
void (*pm)(struct uart_port *, unsigned int state,
unsigned int old);
@ -1338,4 +1342,9 @@ static inline int uart_handle_break(struct uart_port *port)
!((cflag) & CLOCAL))
int uart_get_rs485_mode(struct uart_port *port);
void uart_get_ioinfos(struct uart_port *port, char *buf, size_t size);
bool uart_iotype_mmio(enum uart_iotype iotype);
bool uart_iotype_io(enum uart_iotype iotype);
#endif /* LINUX_SERIAL_CORE_H */

View File

@ -97,18 +97,17 @@ DECLARE_EVENT_CLASS(geni_serial_data,
TP_ARGS(dev, buf, len),
TP_STRUCT__entry(__string(name, dev_name(dev))
__field(unsigned int, len)
__dynamic_array(u8, data, len)
),
TP_fast_assign(__assign_str(name);
__entry->len = len;
memcpy(__get_dynamic_array(data), buf, len);
),
TP_printk("%s: len=%u data=%s",
__get_str(name), __entry->len,
__print_hex(__get_dynamic_array(data), __entry->len))
__get_str(name), __get_dynamic_array_len(data),
__print_hex(__get_dynamic_array(data),
__get_dynamic_array_len(data)))
);
DEFINE_EVENT(geni_serial_data, geni_serial_tx_data,

View File

@ -72,6 +72,7 @@ struct serial_struct {
#define SERIAL_IO_TSI 5
#define SERIAL_IO_MEM32BE 6
#define SERIAL_IO_MEM16 7
#define SERIAL_IO_BUS 8
#define UART_CLEAR_FIFO 0x01
#define UART_USE_FIFO 0x02

View File

@ -100,6 +100,9 @@
/* TXX9 type number */
#define PORT_TXX9 64
/* Moxa MUEx50 UART */
#define PORT_MUEX50 65
/*Digi jsm */
#define PORT_JSM 69