mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-25 10:42:21 +03:00
Update copyright header to GPLv2, removed proprietary copyright headers Bug 5065840 Change-Id: Ib0b8be01f3c0a4fc963244d7b49489960420dc27 Signed-off-by: Ankit patel <anpatel@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3289171 Reviewed-by: Bibek Basu <bbasu@nvidia.com> Tested-by: Bibek Basu <bbasu@nvidia.com> GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
719 lines
20 KiB
C
719 lines
20 KiB
C
/*
|
|
* SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
* SPDX-License-Identifier: GPL-2.0-only
|
|
*/
|
|
|
|
#ifndef WCH_COMMON
|
|
#define WCH_COMMON
|
|
|
|
#ifdef MODVERSIONS
|
|
#ifndef MODULE
|
|
#define MODULE
|
|
#endif
|
|
#endif
|
|
|
|
#define MOD_INC_USE_COUNT
|
|
#define MOD_DEC_USE_COUNT
|
|
|
|
#include <linux/bitops.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/fcntl.h>
|
|
#include <linux/major.h>
|
|
#include <linux/ptrace.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/serial_core.h>
|
|
#include <linux/semaphore.h>
|
|
#include <linux/string.h>
|
|
#include <linux/timer.h>
|
|
|
|
#ifndef PCI_ANY_ID
|
|
#define PCI_ANY_ID (~0)
|
|
#endif
|
|
|
|
#include <linux/errno.h>
|
|
#include <linux/ioport.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/serial.h>
|
|
#include <linux/serial_reg.h>
|
|
#include <linux/signal.h>
|
|
#include <linux/tty.h>
|
|
#include <linux/tty_flip.h>
|
|
|
|
#include <linux/circ_buf.h>
|
|
#include <linux/init.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/pci.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/tty_driver.h>
|
|
#include <linux/wait.h>
|
|
|
|
#include <asm/io.h>
|
|
#include <asm/irq.h>
|
|
#include <asm/uaccess.h>
|
|
#include <asm/serial.h>
|
|
#include <linux/interrupt.h>
|
|
|
|
#include <linux/console.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/device.h>
|
|
#include <linux/module.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/sysrq.h>
|
|
#include <linux/workqueue.h>
|
|
|
|
#include <linux/kref.h>
|
|
|
|
#include <linux/ctype.h>
|
|
#include <linux/parport.h>
|
|
#include <linux/poll.h>
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <linux/sched/signal.h>
|
|
|
|
#include <linux/sched.h>
|
|
|
|
/*-------------------------------------------------------------------------------
|
|
|
|
for wch_main.c
|
|
|
|
-------------------------------------------------------------------------------*/
|
|
/*******************************************************
|
|
WCH driver information
|
|
*******************************************************/
|
|
#define WCH_DRIVER_VERSION "1.24"
|
|
#define WCH_DRIVER_DATE "2023.02"
|
|
#define WCH_DRIVER_AUTHOR "WCH GROUP"
|
|
#define WCH_DRIVER_DESC "WCH Multi-I/O Board Driver Module"
|
|
|
|
#define WCH_TTY_MAJOR 205
|
|
|
|
/*******************************************************
|
|
WCH driver debug
|
|
*******************************************************/
|
|
#define WCH_DBG 0
|
|
#define WCH_DBG_SERIAL 0
|
|
#define WCH_DBG_BOARD 1
|
|
#define WCH_DBG_SERPORT 1
|
|
|
|
#if WCH_DBG_SERIAL
|
|
static void dbg_serial(const char *fmt, ...)
|
|
{
|
|
char buffer[256];
|
|
int i, len;
|
|
va_list arglist;
|
|
|
|
va_start(arglist, fmt);
|
|
vsprintf(&buffer[0], fmt, arglist);
|
|
va_end(arglist);
|
|
len = strlen(buffer);
|
|
for (i = 0; i < len; i++) {
|
|
outb(buffer[i], 0x3F8);
|
|
mdelay(1);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*******************************************************
|
|
* WCH board information
|
|
*******************************************************/
|
|
|
|
// for vid pid subvid subpid
|
|
#define VENDOR_ID_WCH_PCIE 0x1C00
|
|
#define SUB_VENDOR_ID_WCH_PCIE 0x1C00
|
|
#define VENDOR_ID_WCH_PCI 0x4348
|
|
#define SUB_VENDOR_ID_WCH_PCI 0x4348
|
|
#define VENDOR_ID_WCH_CH351 0x1C00
|
|
#define SUB_VENDOR_ID_WCH_CH351 0x1C00
|
|
#define DEVICE_ID_WCH_CH351_2S 0x2273
|
|
#define SUB_DEVICE_ID_WCH_CH351_2S 0x2273
|
|
#define DEVICE_ID_WCH_CH352_1S1P 0x5053
|
|
#define SUB_DEVICE_ID_WCH_CH352_1S1P 0x5053
|
|
#define DEVICE_ID_WCH_CH352_2S 0x3253
|
|
#define SUB_DEVICE_ID_WCH_CH352_2S 0x3253
|
|
#define DEVICE_ID_WCH_CH353_4S 0x3453
|
|
#define SUB_DEVICE_ID_WCH_CH353_4S 0x3453
|
|
#define DEVICE_ID_WCH_CH353_2S1P 0x7053
|
|
#define SUB_DEVICE_ID_WCH_CH353_2S1P 0x3253
|
|
#define DEVICE_ID_WCH_CH353_2S1PAR 0x5046
|
|
#define SUB_DEVICE_ID_WCH_CH353_2S1PAR 0x5046
|
|
#define DEVICE_ID_WCH_CH355_4S 0x7173
|
|
#define SUB_DEVICE_ID_WCH_CH355_4S 0x3473
|
|
#define DEVICE_ID_WCH_CH356_4S1P 0x7073
|
|
#define SUB_DEVICE_ID_WCH_CH356_4S1P 0x3473
|
|
#define DEVICE_ID_WCH_CH356_6S 0x3873
|
|
#define SUB_DEVICE_ID_WCH_CH356_6S 0x3873
|
|
#define DEVICE_ID_WCH_CH356_8S 0x3853
|
|
#define SUB_DEVICE_ID_WCH_CH356_8S 0x3853
|
|
#define DEVICE_ID_WCH_CH357_4S 0x5334
|
|
#define SUB_DEVICE_ID_WCH_CH357_4S 0x5053
|
|
#define DEVICE_ID_WCH_CH358_4S1P 0x5334
|
|
#define SUB_DEVICE_ID_WCH_CH358_4S1P 0x5334
|
|
#define DEVICE_ID_WCH_CH358_8S 0x5338
|
|
#define SUB_DEVICE_ID_WCH_CH358_8S 0x5338
|
|
#define DEVICE_ID_WCH_CH359_16S 0x5838
|
|
#define SUB_DEVICE_ID_WCH_CH359_16S 0x5838
|
|
#define DEVICE_ID_WCH_CH382_2S 0x3253
|
|
#define SUB_DEVICE_ID_WCH_CH382_2S 0x3253
|
|
#define DEVICE_ID_WCH_CH382_2S1P 0x3250
|
|
#define SUB_DEVICE_ID_WCH_CH382_2S1P 0x3250
|
|
#define DEVICE_ID_WCH_CH384_4S 0x3470
|
|
#define SUB_DEVICE_ID_WCH_CH384_4S 0x3470
|
|
#define DEVICE_ID_WCH_CH384_4S1P 0x3450
|
|
#define SUB_DEVICE_ID_WCH_CH384_4S1P 0x3450
|
|
#define DEVICE_ID_WCH_CH384_8S 0x3853
|
|
#define SUB_DEVICE_ID_WCH_CH384_8S 0x3853
|
|
#define DEVICE_ID_WCH_CH384_28S 0x4353
|
|
#define SUB_DEVICE_ID_WCH_CH384_28S 0x4353
|
|
#define DEVICE_ID_WCH_CH365_32S 0x5049
|
|
#define SUB_DEVICE_ID_WCH_CH365_32S 0x5049
|
|
|
|
// for chip_flag
|
|
enum {
|
|
NONE_BOARD = 0,
|
|
WCH_BOARD_CH351_2S,
|
|
WCH_BOARD_CH352_2S,
|
|
WCH_BOARD_CH352_1S1P,
|
|
WCH_BOARD_CH353_4S,
|
|
WCH_BOARD_CH353_2S1P,
|
|
WCH_BOARD_CH353_2S1PAR,
|
|
WCH_BOARD_CH355_4S,
|
|
WCH_BOARD_CH356_4S1P,
|
|
WCH_BOARD_CH356_6S,
|
|
WCH_BOARD_CH356_8S,
|
|
WCH_BOARD_CH357_4S,
|
|
WCH_BOARD_CH358_4S1P,
|
|
WCH_BOARD_CH358_8S,
|
|
WCH_BOARD_CH359_16S,
|
|
WCH_BOARD_CH382_2S,
|
|
WCH_BOARD_CH382_2S1P,
|
|
WCH_BOARD_CH384_4S,
|
|
WCH_BOARD_CH384_4S1P,
|
|
WCH_BOARD_CH384_8S,
|
|
WCH_BOARD_CH384_28S,
|
|
WCH_BOARD_CH365_32S,
|
|
};
|
|
|
|
// for board_flag
|
|
#define BOARDFLAG_NONE 0x0000
|
|
#define BOARDFLAG_REMAP 0x0001
|
|
#define BOARDFLAG_CH365_04_PORTS 0x0002
|
|
#define BOARDFLAG_CH365_08_PORTS 0x0004
|
|
#define BOARDFLAG_CH365_32_PORTS 0x0008
|
|
#define BOARDFLAG_CH384_8_PORTS 0x0010
|
|
#define BOARDFLAG_CH384_28_PORTS 0x0020
|
|
|
|
// for port_flag
|
|
#define PORTFLAG_NONE 0x0000
|
|
#define PORTFLAG_REMAP 0x0001
|
|
#define PORTFLAG_CH365_04_PORTS 0x0002
|
|
#define PORTFLAG_CH365_08_PORTS 0x0004
|
|
#define PORTFLAG_CH365_32_PORTS 0x0008
|
|
#define PORTFLAG_CH384_8_PORTS 0x0010
|
|
#define PORTFLAG_CH384_28_PORTS 0x0020
|
|
|
|
// board info
|
|
#define WCH_BOARDS_MAX 0x08
|
|
#define WCH_PORT_ONBOARD_MAX 0x20
|
|
#define WCH_SER_TOTAL_MAX 0x100
|
|
|
|
extern int wch_ser_port_total_cnt;
|
|
|
|
/*******************************************************
|
|
* uart information
|
|
*******************************************************/
|
|
|
|
// external crystal freq
|
|
#define CRYSTAL_FREQ 22118400
|
|
|
|
// uart fifo info
|
|
#define CH351_FIFOSIZE_16 16
|
|
#define CH351_TRIGGER_LEVEL_16FIFO_01 1
|
|
#define CH351_TRIGGER_LEVEL_16FIFO_04 4
|
|
#define CH351_TRIGGER_LEVEL_16FIFO_08 8
|
|
#define CH351_TRIGGER_LEVEL_16FIFO_14 14
|
|
|
|
#define CH352_FIFOSIZE_16 16
|
|
#define CH352_TRIGGER_LEVEL_16FIFO_01 1
|
|
#define CH352_TRIGGER_LEVEL_16FIFO_04 4
|
|
#define CH352_TRIGGER_LEVEL_16FIFO_08 8
|
|
#define CH352_TRIGGER_LEVEL_16FIFO_14 14
|
|
|
|
#define CH353_FIFOSIZE_16 16
|
|
#define CH353_TRIGGER_LEVEL_16FIFO_01 1
|
|
#define CH353_TRIGGER_LEVEL_16FIFO_04 4
|
|
#define CH353_TRIGGER_LEVEL_16FIFO_08 8
|
|
#define CH353_TRIGGER_LEVEL_16FIFO_14 14
|
|
|
|
#define CH355_FIFOSIZE_16 16
|
|
#define CH355_TRIGGER_LEVEL_16FIFO_01 1
|
|
#define CH355_TRIGGER_LEVEL_16FIFO_04 4
|
|
#define CH355_TRIGGER_LEVEL_16FIFO_08 8
|
|
#define CH355_TRIGGER_LEVEL_16FIFO_14 14
|
|
|
|
#define CH356_FIFOSIZE_16 16
|
|
#define CH356_TRIGGER_LEVEL_16FIFO_01 1
|
|
#define CH356_TRIGGER_LEVEL_16FIFO_04 4
|
|
#define CH356_TRIGGER_LEVEL_16FIFO_08 8
|
|
#define CH356_TRIGGER_LEVEL_16FIFO_14 14
|
|
|
|
#define CH357_FIFOSIZE_128 128
|
|
#define CH357_TRIGGER_LEVEL_128FIFO_01 1
|
|
#define CH357_TRIGGER_LEVEL_128FIFO_32 32
|
|
#define CH357_TRIGGER_LEVEL_128FIFO_64 64
|
|
#define CH357_TRIGGER_LEVEL_128FIFO_112 112
|
|
|
|
#define CH358_FIFOSIZE_128 128
|
|
#define CH358_TRIGGER_LEVEL_128FIFO_01 1
|
|
#define CH358_TRIGGER_LEVEL_128FIFO_32 32
|
|
#define CH358_TRIGGER_LEVEL_128FIFO_64 64
|
|
#define CH358_TRIGGER_LEVEL_128FIFO_112 112
|
|
|
|
#define CH359_FIFOSIZE_128 128
|
|
#define CH359_TRIGGER_LEVEL_128FIFO_01 1
|
|
#define CH359_TRIGGER_LEVEL_128FIFO_32 32
|
|
#define CH359_TRIGGER_LEVEL_128FIFO_64 64
|
|
#define CH359_TRIGGER_LEVEL_128FIFO_112 112
|
|
|
|
#define CH382_FIFOSIZE_256 256
|
|
#define CH382_TRIGGER_LEVEL_256FIFO_01 1
|
|
#define CH382_TRIGGER_LEVEL_256FIFO_32 32
|
|
#define CH382_TRIGGER_LEVEL_256FIFO_128 128
|
|
#define CH382_TRIGGER_LEVEL_256FIFO_224 224
|
|
|
|
#define CH384_FIFOSIZE_256 256
|
|
#define CH384_TRIGGER_LEVEL_256FIFO_01 1
|
|
#define CH384_TRIGGER_LEVEL_256FIFO_32 32
|
|
#define CH384_TRIGGER_LEVEL_256FIFO_128 128
|
|
#define CH384_TRIGGER_LEVEL_256FIFO_224 224
|
|
|
|
#define CH432_FIFOSIZE_16 16
|
|
#define CH432_TRIGGER_LEVEL_16FIFO_01 1
|
|
#define CH432_TRIGGER_LEVEL_16FIFO_04 4
|
|
#define CH432_TRIGGER_LEVEL_16FIFO_08 8
|
|
#define CH432_TRIGGER_LEVEL_16FIFO_14 14
|
|
|
|
#define CH438_FIFOSIZE_128 128
|
|
#define CH438_TRIGGER_LEVEL_128FIFO_01 1
|
|
#define CH438_TRIGGER_LEVEL_128FIFO_16 16
|
|
#define CH438_TRIGGER_LEVEL_128FIFO_64 64
|
|
#define CH438_TRIGGER_LEVEL_128FIFO_112 112
|
|
|
|
// uart fifo setup
|
|
#define CH351_FIFOSIZE_SET CH351_FIFOSIZE_16
|
|
#define CH351_TRIGGER_LEVEL_SET CH351_TRIGGER_LEVEL_16FIFO_08
|
|
|
|
#define CH352_FIFOSIZE_SET CH352_FIFOSIZE_16
|
|
#define CH352_TRIGGER_LEVEL_SET CH352_TRIGGER_LEVEL_16FIFO_08
|
|
|
|
#define CH353_FIFOSIZE_SET CH353_FIFOSIZE_16
|
|
#define CH353_TRIGGER_LEVEL_SET CH353_TRIGGER_LEVEL_16FIFO_08
|
|
|
|
#define CH355_FIFOSIZE_SET CH355_FIFOSIZE_16
|
|
#define CH355_TRIGGER_LEVEL_SET CH355_TRIGGER_LEVEL_16FIFO_08
|
|
|
|
#define CH356_FIFOSIZE_SET CH356_FIFOSIZE_16
|
|
#define CH356_TRIGGER_LEVEL_SET CH356_TRIGGER_LEVEL_16FIFO_08
|
|
|
|
#define CH357_FIFOSIZE_SET CH357_FIFOSIZE_128
|
|
#define CH357_TRIGGER_LEVEL_SET CH357_TRIGGER_LEVEL_128FIFO_64
|
|
|
|
#define CH358_FIFOSIZE_SET CH358_FIFOSIZE_128
|
|
#define CH358_TRIGGER_LEVEL_SET CH358_TRIGGER_LEVEL_128FIFO_64
|
|
|
|
#define CH359_FIFOSIZE_SET CH359_FIFOSIZE_128
|
|
#define CH359_TRIGGER_LEVEL_SET CH359_TRIGGER_LEVEL_128FIFO_64
|
|
|
|
#define CH382_FIFOSIZE_SET CH382_FIFOSIZE_256
|
|
#define CH382_TRIGGER_LEVEL_SET CH382_TRIGGER_LEVEL_256FIFO_128
|
|
|
|
#define CH384_FIFOSIZE_SET CH384_FIFOSIZE_256
|
|
#define CH384_TRIGGER_LEVEL_SET CH384_TRIGGER_LEVEL_256FIFO_128
|
|
|
|
#define CH432_FIFOSIZE_SET CH432_FIFOSIZE_16
|
|
#define CH432_TRIGGER_LEVEL_SET CH432_TRIGGER_LEVEL_16FIFO_08
|
|
|
|
#define CH438_FIFOSIZE_SET CH438_FIFOSIZE_128
|
|
#define CH438_TRIGGER_LEVEL_SET CH438_TRIGGER_LEVEL_128FIFO_16
|
|
|
|
#define UART_TRIGGER00_FCR 0x00
|
|
#define UART_TRIGGER01_FCR 0x40
|
|
#define UART_TRIGGER10_FCR 0x80
|
|
#define UART_TRIGGER11_FCR 0xC0
|
|
|
|
#define UART_DEFAULT_FCR 0x00
|
|
|
|
#define DEFAULT_FIFOSIZE 1
|
|
#define DEFAULT_TRIGGER_LEVEL 1
|
|
|
|
// register status info
|
|
#define UART_LSR_ERR_IN_RFIFO 0x80
|
|
#define UART_MCR_AFE 0x20
|
|
#define UART_IIR_CTO 0x0C
|
|
|
|
// serial address length
|
|
#define WCH_SER_ADDRESS_LENGTH 0x08
|
|
|
|
// PCI configuration bar 0 ~ 5
|
|
#define WCH_PCICFG_BAR_TOTAL 0x06
|
|
|
|
/*******************************************************
|
|
* miscellaneous Information
|
|
*******************************************************/
|
|
#define INTERRUPT_COUNT 0x80
|
|
#define WAKEUP_CHARS_SER 0x100
|
|
#define WCHTERMIOS ktermios
|
|
|
|
// for ser_port->setserial_flag
|
|
#define WCH_SER_BAUD_SETSERIAL 0x01
|
|
#define WCH_SER_BAUD_NOTSETSER 0x00
|
|
|
|
/*******************************************************
|
|
struct define Information
|
|
*******************************************************/
|
|
|
|
// name length
|
|
#define WCH_BOARDNAME_LENGTH 0x0F
|
|
#define WCH_DRIVERVERSION_LENGTH 0x0F
|
|
|
|
struct ser_port_info {
|
|
char board_name_info[WCH_BOARDNAME_LENGTH];
|
|
unsigned int bus_number_info;
|
|
unsigned int dev_number_info;
|
|
unsigned int port_info;
|
|
unsigned int base_info;
|
|
unsigned int irq_info;
|
|
};
|
|
|
|
struct port {
|
|
char type;
|
|
|
|
int bar1;
|
|
unsigned int offset1;
|
|
unsigned char length1;
|
|
|
|
int bar2;
|
|
unsigned int offset2;
|
|
unsigned char length2;
|
|
|
|
unsigned int chip_flag;
|
|
};
|
|
|
|
struct pci_board {
|
|
unsigned int vendor_id;
|
|
unsigned int device_id;
|
|
unsigned int sub_vendor_id;
|
|
unsigned int sub_device_id;
|
|
|
|
unsigned int num_serport;
|
|
|
|
unsigned int intr_vector_bar;
|
|
unsigned int intr_vector_offset;
|
|
unsigned int intr_vector_offset_1;
|
|
unsigned int intr_vector_offset_2;
|
|
unsigned int intr_vector_offset_3;
|
|
|
|
char board_name[WCH_BOARDNAME_LENGTH];
|
|
unsigned int board_flag;
|
|
|
|
struct port port[WCH_PORT_ONBOARD_MAX];
|
|
};
|
|
|
|
struct wch_board;
|
|
struct wch_ser_port;
|
|
struct wch_par_port;
|
|
|
|
struct wch_board {
|
|
int board_enum;
|
|
int board_number;
|
|
unsigned int bus_number;
|
|
unsigned int dev_number;
|
|
|
|
unsigned int ser_ports;
|
|
|
|
unsigned int ser_port_index;
|
|
|
|
unsigned long bar_addr[WCH_PCICFG_BAR_TOTAL];
|
|
unsigned int irq;
|
|
void *board_membase;
|
|
unsigned int board_flag;
|
|
|
|
unsigned int vector_mask;
|
|
struct pci_board pb_info;
|
|
struct pci_dev *pdev;
|
|
int (*ser_isr)(struct wch_board *, struct wch_ser_port *);
|
|
};
|
|
|
|
/*-------------------------------------------------------------------------------
|
|
|
|
for wch_serial.c
|
|
|
|
-------------------------------------------------------------------------------*/
|
|
/*******************************************************
|
|
* ioctl user define
|
|
*******************************************************/
|
|
#define WCH_IOCTL 0x900
|
|
#define WCH_SER_DUMP_PORT_INFO (WCH_IOCTL + 50)
|
|
#define WCH_SER_DUMP_PORT_PERF (WCH_IOCTL + 51)
|
|
#define WCH_SER_DUMP_DRIVER_VER (WCH_IOCTL + 52)
|
|
|
|
/*******************************************************
|
|
* serial define
|
|
*******************************************************/
|
|
#define PORT_SER_UNKNOWN 0x00
|
|
#define PORT_SER_8250 0x01
|
|
#define PORT_SER_16450 0x02
|
|
#define PORT_SER_16550 0x03
|
|
#define PORT_SER_16550A 0x04
|
|
#define PORT_SER_CIRRUS 0x05
|
|
#define PORT_SER_16650 0x06
|
|
#define PORT_SER_16650V2 0x07
|
|
#define PORT_SER_16750 0x08
|
|
#define PORT_SER_MAX_UART 0x08
|
|
|
|
#define WCH_USF_CLOSING_WAIT_INF (0)
|
|
#define WCH_USF_CLOSING_WAIT_NONE (65535)
|
|
#define WCH_UART_CONFIG_TYPE (1 << 0)
|
|
#define WCH_UART_CONFIG_IRQ (1 << 1)
|
|
|
|
#define WCH_UART_XMIT_SIZE 0x1000
|
|
|
|
#define ser_circ_empty(circ) ((circ)->head == (circ)->tail)
|
|
#define ser_circ_clear(circ) ((circ)->head = (circ)->tail = 0)
|
|
#define ser_circ_chars_pending(circ) (CIRC_CNT((circ)->head, (circ)->tail, WCH_UART_XMIT_SIZE))
|
|
#define ser_circ_chars_free(circ) (CIRC_SPACE((circ)->head, (circ)->tail, WCH_UART_XMIT_SIZE))
|
|
#define ser_tx_stopped(port) ((port)->info->tty->flow.stopped || (port)->info->tty->hw_stopped)
|
|
|
|
#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
|
|
#define WCH_SERIAL_INLINE
|
|
#endif
|
|
|
|
#ifdef WCH_SERIAL_INLINE
|
|
#define _INLINE_ inline
|
|
#else
|
|
#define _INLINE_
|
|
#endif
|
|
|
|
#define WCH_UPIO_PORT (0)
|
|
#define WCH_UPIO_MEM (1)
|
|
|
|
#define WCH_UPF_SAK (1 << 2)
|
|
#define WCH_UPF_SPD_MASK (0x1030)
|
|
#define WCH_UPF_SPD_HI (0x0010)
|
|
#define WCH_UPF_SPD_VHI (0x0020)
|
|
#define WCH_UPF_SPD_CUST (0x0030)
|
|
#define WCH_UPF_SPD_SHI (0x1000)
|
|
#define WCH_UPF_SPD_WARP (0x1010)
|
|
#define WCH_UPF_SKIP_TEST (1 << 6)
|
|
#define WCH_UPF_HARDPPS_CD (1 << 11)
|
|
#define WCH_UPF_LOW_LATENCY (1 << 13)
|
|
#define WCH_UPF_BUGGY_UART (1 << 14)
|
|
#define WCH_UPF_MAGIC_MULTIPLIER (1 << 16)
|
|
|
|
#define WCH_UPF_CHANGE_MASK (0x17fff)
|
|
#define WCH_UPF_USR_MASK (WCH_UPF_SPD_MASK | WCH_UPF_LOW_LATENCY)
|
|
|
|
#define WCH_UIF_CHECK_CD (1 << 25)
|
|
#define WCH_UIF_CTS_FLOW (1 << 26)
|
|
|
|
#define WCH_UIF_NORMAL_ACTIVE (1 << 29)
|
|
#define WCH_UIF_INITIALIZED (1 << 31)
|
|
|
|
#define WCH_ENABLE_MS(port, cflag) ((port)->flags & WCH_UPF_HARDPPS_CD || (cflag)&CRTSCTS || !((cflag)&CLOCAL))
|
|
|
|
#define WCH_SER_DEVNUM(x) ((x)->index)
|
|
|
|
struct ser_info;
|
|
struct ser_port;
|
|
|
|
struct ser_icount {
|
|
__u32 cts;
|
|
__u32 dsr;
|
|
__u32 rng;
|
|
__u32 dcd;
|
|
__u32 rx;
|
|
__u32 tx;
|
|
__u32 frame;
|
|
__u32 overrun;
|
|
__u32 parity;
|
|
__u32 brk;
|
|
__u32 buf_overrun;
|
|
};
|
|
|
|
struct ser_info {
|
|
struct tty_struct *tty;
|
|
struct circ_buf xmit;
|
|
unsigned int flags;
|
|
unsigned char *tmpbuf;
|
|
struct semaphore tmpbuf_sem;
|
|
int blocked_open;
|
|
struct tasklet_struct tlet;
|
|
|
|
wait_queue_head_t open_wait;
|
|
wait_queue_head_t delta_msr_wait;
|
|
};
|
|
|
|
struct ser_driver {
|
|
const char *dev_name;
|
|
int major;
|
|
int minor;
|
|
int nr;
|
|
struct ser_state *state;
|
|
struct tty_driver *tty_driver;
|
|
};
|
|
|
|
struct ser_port {
|
|
spinlock_t lock;
|
|
void *port_membase;
|
|
void *board_membase;
|
|
unsigned long iobase;
|
|
unsigned int irq;
|
|
unsigned int uartclk;
|
|
unsigned int fifosize;
|
|
unsigned char x_char;
|
|
unsigned char iotype;
|
|
|
|
unsigned int read_status_mask;
|
|
unsigned int ignore_status_mask;
|
|
struct ser_info *info;
|
|
struct ser_state *state;
|
|
struct ser_icount icount;
|
|
|
|
unsigned int flags;
|
|
unsigned int mctrl;
|
|
unsigned int timeout;
|
|
unsigned int type;
|
|
unsigned int custom_divisor;
|
|
unsigned int line;
|
|
struct device *dev;
|
|
|
|
int board_enum;
|
|
unsigned int bus_number;
|
|
unsigned int dev_number;
|
|
struct pci_board pb_info;
|
|
unsigned long vector;
|
|
unsigned int chip_iobase;
|
|
unsigned int vector_mask;
|
|
unsigned char chip_flag;
|
|
unsigned int port_flag;
|
|
unsigned int baud_base;
|
|
int rx_trigger;
|
|
bool bext1stport;
|
|
bool bspe1stport;
|
|
bool hardflow;
|
|
unsigned char ldisc_stop_rx;
|
|
|
|
unsigned int setserial_flag;
|
|
};
|
|
|
|
struct ser_state {
|
|
struct tty_port port0;
|
|
unsigned int close_delay;
|
|
unsigned int closing_wait;
|
|
int count;
|
|
struct ser_info *info;
|
|
struct ser_port *port;
|
|
struct semaphore sem;
|
|
};
|
|
|
|
static inline int ser_handle_break(struct ser_port *port)
|
|
{
|
|
struct ser_info *info = port->info;
|
|
|
|
if (info->flags & WCH_UPF_SAK) {
|
|
do_SAK(info->tty);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline void ser_handle_dcd_change(struct ser_port *port, unsigned int status)
|
|
{
|
|
struct ser_info *info = port->info;
|
|
|
|
port->icount.dcd++;
|
|
|
|
if (info->flags & WCH_UIF_CHECK_CD) {
|
|
if (status) {
|
|
wake_up_interruptible(&info->open_wait);
|
|
} else if (info->tty) {
|
|
tty_hangup(info->tty);
|
|
}
|
|
}
|
|
}
|
|
|
|
#include <linux/tty_flip.h>
|
|
|
|
static inline void ser_insert_buffer(struct ser_port *port, unsigned int status, unsigned int overrun,
|
|
unsigned char *buf, unsigned int count, unsigned char flag)
|
|
{
|
|
struct tty_port *tty = &port->state->port0;
|
|
|
|
if ((status & port->ignore_status_mask & ~overrun) == 0) {
|
|
if (tty_insert_flip_string_fixed_flag(tty, buf, flag, count) == 0)
|
|
++port->icount.buf_overrun;
|
|
}
|
|
|
|
if (status & ~port->ignore_status_mask & overrun) {
|
|
if (tty_insert_flip_char(tty, 0, TTY_OVERRUN) == 0)
|
|
++port->icount.buf_overrun;
|
|
}
|
|
}
|
|
|
|
static inline void ser_insert_char(struct ser_port *port, unsigned int status, unsigned int overrun, unsigned int ch,
|
|
unsigned int flag)
|
|
{
|
|
struct tty_port *tty = &port->state->port0;
|
|
|
|
if ((status & port->ignore_status_mask & ~overrun) == 0) {
|
|
if (tty_insert_flip_char(tty, ch, flag) == 0)
|
|
++port->icount.buf_overrun;
|
|
}
|
|
|
|
if (status & ~port->ignore_status_mask & overrun) {
|
|
if (tty_insert_flip_char(tty, 0, TTY_OVERRUN) == 0)
|
|
++port->icount.buf_overrun;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************
|
|
* wch serial port struct
|
|
*******************************************************/
|
|
struct wch_ser_port {
|
|
struct ser_port port;
|
|
struct timer_list timer;
|
|
struct list_head list;
|
|
|
|
unsigned int capabilities;
|
|
unsigned char ier;
|
|
unsigned char lcr;
|
|
unsigned char mcr;
|
|
unsigned char mcr_mask;
|
|
unsigned char mcr_force;
|
|
unsigned char lsr_break_flag;
|
|
};
|
|
|
|
/*-------------------------------------------------------------------------------
|
|
* function and variable extern
|
|
-------------------------------------------------------------------------------*/
|
|
// wch_devtable.c
|
|
extern struct pci_board wch_pci_board_conf[];
|
|
extern struct pci_device_id wch_pci_board_id[];
|
|
|
|
// wch_serial.c
|
|
extern int wch_ser_register_ports(struct ser_driver *);
|
|
extern void wch_ser_unregister_ports(struct ser_driver *);
|
|
extern int wch_ser_register_driver(struct ser_driver *);
|
|
extern void wch_ser_unregister_driver(struct ser_driver *);
|
|
extern int wch_ser_interrupt(struct wch_board *, struct wch_ser_port *);
|
|
|
|
// wch_main.c
|
|
extern struct wch_board wch_board_table[WCH_BOARDS_MAX];
|
|
extern struct wch_ser_port wch_ser_table[WCH_SER_TOTAL_MAX + 1];
|
|
extern int wch_35x_init(void);
|
|
extern void wch_35x_exit(void);
|
|
extern unsigned char ch365_32s;
|
|
|
|
#endif
|