ioc4_serial.c
来自「linux 内核源代码」· C语言 代码 · 共 2,250 行 · 第 1/5 页
C
2,250 行
/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2003-2006 Silicon Graphics, Inc. All Rights Reserved. *//* * This file contains a module version of the ioc4 serial driver. This * includes all the support functions needed (support functions, etc.) * and the serial driver itself. */#include <linux/errno.h>#include <linux/tty.h>#include <linux/serial.h>#include <linux/serialP.h>#include <linux/circ_buf.h>#include <linux/serial_reg.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/ioc4.h>#include <linux/serial_core.h>/* * interesting things about the ioc4 */#define IOC4_NUM_SERIAL_PORTS 4 /* max ports per card */#define IOC4_NUM_CARDS 8 /* max cards per partition */#define GET_SIO_IR(_n) (_n == 0) ? (IOC4_SIO_IR_S0) : \ (_n == 1) ? (IOC4_SIO_IR_S1) : \ (_n == 2) ? (IOC4_SIO_IR_S2) : \ (IOC4_SIO_IR_S3)#define GET_OTHER_IR(_n) (_n == 0) ? (IOC4_OTHER_IR_S0_MEMERR) : \ (_n == 1) ? (IOC4_OTHER_IR_S1_MEMERR) : \ (_n == 2) ? (IOC4_OTHER_IR_S2_MEMERR) : \ (IOC4_OTHER_IR_S3_MEMERR)/* * All IOC4 registers are 32 bits wide. *//* * PCI Memory Space Map */#define IOC4_PCI_ERR_ADDR_L 0x000 /* Low Error Address */#define IOC4_PCI_ERR_ADDR_VLD (0x1 << 0)#define IOC4_PCI_ERR_ADDR_MST_ID_MSK (0xf << 1)#define IOC4_PCI_ERR_ADDR_MST_NUM_MSK (0xe << 1)#define IOC4_PCI_ERR_ADDR_MST_TYP_MSK (0x1 << 1)#define IOC4_PCI_ERR_ADDR_MUL_ERR (0x1 << 5)#define IOC4_PCI_ERR_ADDR_ADDR_MSK (0x3ffffff << 6)/* Interrupt types */#define IOC4_SIO_INTR_TYPE 0#define IOC4_OTHER_INTR_TYPE 1#define IOC4_NUM_INTR_TYPES 2/* Bitmasks for IOC4_SIO_IR, IOC4_SIO_IEC, and IOC4_SIO_IES */#define IOC4_SIO_IR_S0_TX_MT 0x00000001 /* Serial port 0 TX empty */#define IOC4_SIO_IR_S0_RX_FULL 0x00000002 /* Port 0 RX buf full */#define IOC4_SIO_IR_S0_RX_HIGH 0x00000004 /* Port 0 RX hiwat */#define IOC4_SIO_IR_S0_RX_TIMER 0x00000008 /* Port 0 RX timeout */#define IOC4_SIO_IR_S0_DELTA_DCD 0x00000010 /* Port 0 delta DCD */#define IOC4_SIO_IR_S0_DELTA_CTS 0x00000020 /* Port 0 delta CTS */#define IOC4_SIO_IR_S0_INT 0x00000040 /* Port 0 pass-thru intr */#define IOC4_SIO_IR_S0_TX_EXPLICIT 0x00000080 /* Port 0 explicit TX thru */#define IOC4_SIO_IR_S1_TX_MT 0x00000100 /* Serial port 1 */#define IOC4_SIO_IR_S1_RX_FULL 0x00000200 /* */#define IOC4_SIO_IR_S1_RX_HIGH 0x00000400 /* */#define IOC4_SIO_IR_S1_RX_TIMER 0x00000800 /* */#define IOC4_SIO_IR_S1_DELTA_DCD 0x00001000 /* */#define IOC4_SIO_IR_S1_DELTA_CTS 0x00002000 /* */#define IOC4_SIO_IR_S1_INT 0x00004000 /* */#define IOC4_SIO_IR_S1_TX_EXPLICIT 0x00008000 /* */#define IOC4_SIO_IR_S2_TX_MT 0x00010000 /* Serial port 2 */#define IOC4_SIO_IR_S2_RX_FULL 0x00020000 /* */#define IOC4_SIO_IR_S2_RX_HIGH 0x00040000 /* */#define IOC4_SIO_IR_S2_RX_TIMER 0x00080000 /* */#define IOC4_SIO_IR_S2_DELTA_DCD 0x00100000 /* */#define IOC4_SIO_IR_S2_DELTA_CTS 0x00200000 /* */#define IOC4_SIO_IR_S2_INT 0x00400000 /* */#define IOC4_SIO_IR_S2_TX_EXPLICIT 0x00800000 /* */#define IOC4_SIO_IR_S3_TX_MT 0x01000000 /* Serial port 3 */#define IOC4_SIO_IR_S3_RX_FULL 0x02000000 /* */#define IOC4_SIO_IR_S3_RX_HIGH 0x04000000 /* */#define IOC4_SIO_IR_S3_RX_TIMER 0x08000000 /* */#define IOC4_SIO_IR_S3_DELTA_DCD 0x10000000 /* */#define IOC4_SIO_IR_S3_DELTA_CTS 0x20000000 /* */#define IOC4_SIO_IR_S3_INT 0x40000000 /* */#define IOC4_SIO_IR_S3_TX_EXPLICIT 0x80000000 /* *//* Per device interrupt masks */#define IOC4_SIO_IR_S0 (IOC4_SIO_IR_S0_TX_MT | \ IOC4_SIO_IR_S0_RX_FULL | \ IOC4_SIO_IR_S0_RX_HIGH | \ IOC4_SIO_IR_S0_RX_TIMER | \ IOC4_SIO_IR_S0_DELTA_DCD | \ IOC4_SIO_IR_S0_DELTA_CTS | \ IOC4_SIO_IR_S0_INT | \ IOC4_SIO_IR_S0_TX_EXPLICIT)#define IOC4_SIO_IR_S1 (IOC4_SIO_IR_S1_TX_MT | \ IOC4_SIO_IR_S1_RX_FULL | \ IOC4_SIO_IR_S1_RX_HIGH | \ IOC4_SIO_IR_S1_RX_TIMER | \ IOC4_SIO_IR_S1_DELTA_DCD | \ IOC4_SIO_IR_S1_DELTA_CTS | \ IOC4_SIO_IR_S1_INT | \ IOC4_SIO_IR_S1_TX_EXPLICIT)#define IOC4_SIO_IR_S2 (IOC4_SIO_IR_S2_TX_MT | \ IOC4_SIO_IR_S2_RX_FULL | \ IOC4_SIO_IR_S2_RX_HIGH | \ IOC4_SIO_IR_S2_RX_TIMER | \ IOC4_SIO_IR_S2_DELTA_DCD | \ IOC4_SIO_IR_S2_DELTA_CTS | \ IOC4_SIO_IR_S2_INT | \ IOC4_SIO_IR_S2_TX_EXPLICIT)#define IOC4_SIO_IR_S3 (IOC4_SIO_IR_S3_TX_MT | \ IOC4_SIO_IR_S3_RX_FULL | \ IOC4_SIO_IR_S3_RX_HIGH | \ IOC4_SIO_IR_S3_RX_TIMER | \ IOC4_SIO_IR_S3_DELTA_DCD | \ IOC4_SIO_IR_S3_DELTA_CTS | \ IOC4_SIO_IR_S3_INT | \ IOC4_SIO_IR_S3_TX_EXPLICIT)/* Bitmasks for IOC4_OTHER_IR, IOC4_OTHER_IEC, and IOC4_OTHER_IES */#define IOC4_OTHER_IR_ATA_INT 0x00000001 /* ATAPI intr pass-thru */#define IOC4_OTHER_IR_ATA_MEMERR 0x00000002 /* ATAPI DMA PCI error */#define IOC4_OTHER_IR_S0_MEMERR 0x00000004 /* Port 0 PCI error */#define IOC4_OTHER_IR_S1_MEMERR 0x00000008 /* Port 1 PCI error */#define IOC4_OTHER_IR_S2_MEMERR 0x00000010 /* Port 2 PCI error */#define IOC4_OTHER_IR_S3_MEMERR 0x00000020 /* Port 3 PCI error */#define IOC4_OTHER_IR_KBD_INT 0x00000040 /* Keyboard/mouse */#define IOC4_OTHER_IR_RESERVED 0x007fff80 /* Reserved */#define IOC4_OTHER_IR_RT_INT 0x00800000 /* INT_OUT section output */#define IOC4_OTHER_IR_GEN_INT 0xff000000 /* Generic pins */#define IOC4_OTHER_IR_SER_MEMERR (IOC4_OTHER_IR_S0_MEMERR | IOC4_OTHER_IR_S1_MEMERR | \ IOC4_OTHER_IR_S2_MEMERR | IOC4_OTHER_IR_S3_MEMERR)/* Bitmasks for IOC4_SIO_CR */#define IOC4_SIO_CR_CMD_PULSE_SHIFT 0 /* byte bus strobe shift */#define IOC4_SIO_CR_ARB_DIAG_TX0 0x00000000#define IOC4_SIO_CR_ARB_DIAG_RX0 0x00000010#define IOC4_SIO_CR_ARB_DIAG_TX1 0x00000020#define IOC4_SIO_CR_ARB_DIAG_RX1 0x00000030#define IOC4_SIO_CR_ARB_DIAG_TX2 0x00000040#define IOC4_SIO_CR_ARB_DIAG_RX2 0x00000050#define IOC4_SIO_CR_ARB_DIAG_TX3 0x00000060#define IOC4_SIO_CR_ARB_DIAG_RX3 0x00000070#define IOC4_SIO_CR_SIO_DIAG_IDLE 0x00000080 /* 0 -> active request among serial ports (ro) *//* Defs for some of the generic I/O pins */#define IOC4_GPCR_UART0_MODESEL 0x10 /* Pin is output to port 0 mode sel */#define IOC4_GPCR_UART1_MODESEL 0x20 /* Pin is output to port 1 mode sel */#define IOC4_GPCR_UART2_MODESEL 0x40 /* Pin is output to port 2 mode sel */#define IOC4_GPCR_UART3_MODESEL 0x80 /* Pin is output to port 3 mode sel */#define IOC4_GPPR_UART0_MODESEL_PIN 4 /* GIO pin controlling uart 0 mode select */#define IOC4_GPPR_UART1_MODESEL_PIN 5 /* GIO pin controlling uart 1 mode select */#define IOC4_GPPR_UART2_MODESEL_PIN 6 /* GIO pin controlling uart 2 mode select */#define IOC4_GPPR_UART3_MODESEL_PIN 7 /* GIO pin controlling uart 3 mode select *//* Bitmasks for serial RX status byte */#define IOC4_RXSB_OVERRUN 0x01 /* Char(s) lost */#define IOC4_RXSB_PAR_ERR 0x02 /* Parity error */#define IOC4_RXSB_FRAME_ERR 0x04 /* Framing error */#define IOC4_RXSB_BREAK 0x08 /* Break character */#define IOC4_RXSB_CTS 0x10 /* State of CTS */#define IOC4_RXSB_DCD 0x20 /* State of DCD */#define IOC4_RXSB_MODEM_VALID 0x40 /* DCD, CTS, and OVERRUN are valid */#define IOC4_RXSB_DATA_VALID 0x80 /* Data byte, FRAME_ERR PAR_ERR * & BREAK valid *//* Bitmasks for serial TX control byte */#define IOC4_TXCB_INT_WHEN_DONE 0x20 /* Interrupt after this byte is sent */#define IOC4_TXCB_INVALID 0x00 /* Byte is invalid */#define IOC4_TXCB_VALID 0x40 /* Byte is valid */#define IOC4_TXCB_MCR 0x80 /* Data<7:0> to modem control reg */#define IOC4_TXCB_DELAY 0xc0 /* Delay data<7:0> mSec *//* Bitmasks for IOC4_SBBR_L */#define IOC4_SBBR_L_SIZE 0x00000001 /* 0 == 1KB rings, 1 == 4KB rings *//* Bitmasks for IOC4_SSCR_<3:0> */#define IOC4_SSCR_RX_THRESHOLD 0x000001ff /* Hiwater mark */#define IOC4_SSCR_TX_TIMER_BUSY 0x00010000 /* TX timer in progress */#define IOC4_SSCR_HFC_EN 0x00020000 /* Hardware flow control enabled */#define IOC4_SSCR_RX_RING_DCD 0x00040000 /* Post RX record on delta-DCD */#define IOC4_SSCR_RX_RING_CTS 0x00080000 /* Post RX record on delta-CTS */#define IOC4_SSCR_DIAG 0x00200000 /* Bypass clock divider for sim */#define IOC4_SSCR_RX_DRAIN 0x08000000 /* Drain RX buffer to memory */#define IOC4_SSCR_DMA_EN 0x10000000 /* Enable ring buffer DMA */#define IOC4_SSCR_DMA_PAUSE 0x20000000 /* Pause DMA */#define IOC4_SSCR_PAUSE_STATE 0x40000000 /* Sets when PAUSE takes effect */#define IOC4_SSCR_RESET 0x80000000 /* Reset DMA channels *//* All producer/comsumer pointers are the same bitfield */#define IOC4_PROD_CONS_PTR_4K 0x00000ff8 /* For 4K buffers */#define IOC4_PROD_CONS_PTR_1K 0x000003f8 /* For 1K buffers */#define IOC4_PROD_CONS_PTR_OFF 3/* Bitmasks for IOC4_SRCIR_<3:0> */#define IOC4_SRCIR_ARM 0x80000000 /* Arm RX timer *//* Bitmasks for IOC4_SHADOW_<3:0> */#define IOC4_SHADOW_DR 0x00000001 /* Data ready */#define IOC4_SHADOW_OE 0x00000002 /* Overrun error */#define IOC4_SHADOW_PE 0x00000004 /* Parity error */#define IOC4_SHADOW_FE 0x00000008 /* Framing error */#define IOC4_SHADOW_BI 0x00000010 /* Break interrupt */#define IOC4_SHADOW_THRE 0x00000020 /* Xmit holding register empty */#define IOC4_SHADOW_TEMT 0x00000040 /* Xmit shift register empty */#define IOC4_SHADOW_RFCE 0x00000080 /* Char in RX fifo has an error */#define IOC4_SHADOW_DCTS 0x00010000 /* Delta clear to send */#define IOC4_SHADOW_DDCD 0x00080000 /* Delta data carrier detect */#define IOC4_SHADOW_CTS 0x00100000 /* Clear to send */#define IOC4_SHADOW_DCD 0x00800000 /* Data carrier detect */#define IOC4_SHADOW_DTR 0x01000000 /* Data terminal ready */#define IOC4_SHADOW_RTS 0x02000000 /* Request to send */#define IOC4_SHADOW_OUT1 0x04000000 /* 16550 OUT1 bit */#define IOC4_SHADOW_OUT2 0x08000000 /* 16550 OUT2 bit */#define IOC4_SHADOW_LOOP 0x10000000 /* Loopback enabled *//* Bitmasks for IOC4_SRTR_<3:0> */#define IOC4_SRTR_CNT 0x00000fff /* Reload value for RX timer */#define IOC4_SRTR_CNT_VAL 0x0fff0000 /* Current value of RX timer */#define IOC4_SRTR_CNT_VAL_SHIFT 16#define IOC4_SRTR_HZ 16000 /* SRTR clock frequency *//* Serial port register map used for DMA and PIO serial I/O */struct ioc4_serialregs { uint32_t sscr; uint32_t stpir; uint32_t stcir; uint32_t srpir; uint32_t srcir; uint32_t srtr; uint32_t shadow;};/* IOC4 UART register map */struct ioc4_uartregs { char i4u_lcr; union { char iir; /* read only */ char fcr; /* write only */ } u3; union { char ier; /* DLAB == 0 */ char dlm; /* DLAB == 1 */ } u2; union { char rbr; /* read only, DLAB == 0 */ char thr; /* write only, DLAB == 0 */ char dll; /* DLAB == 1 */ } u1; char i4u_scr; char i4u_msr; char i4u_lsr; char i4u_mcr;};/* short names */#define i4u_dll u1.dll#define i4u_ier u2.ier#define i4u_dlm u2.dlm#define i4u_fcr u3.fcr/* Serial port registers used for DMA serial I/O */struct ioc4_serial { uint32_t sbbr01_l; uint32_t sbbr01_h; uint32_t sbbr23_l; uint32_t sbbr23_h; struct ioc4_serialregs port_0; struct ioc4_serialregs port_1; struct ioc4_serialregs port_2; struct ioc4_serialregs port_3; struct ioc4_uartregs uart_0; struct ioc4_uartregs uart_1; struct ioc4_uartregs uart_2; struct ioc4_uartregs uart_3;} ioc4_serial;/* UART clock speed */#define IOC4_SER_XIN_CLK_66 66666667#define IOC4_SER_XIN_CLK_33 33333333#define IOC4_W_IES 0#define IOC4_W_IEC 1typedef void ioc4_intr_func_f(void *, uint32_t);typedef ioc4_intr_func_f *ioc4_intr_func_t;static unsigned int Num_of_ioc4_cards;/* defining this will get you LOTS of great debug info *///#define DEBUG_INTERRUPTS#define DPRINT_CONFIG(_x...) ;//#define DPRINT_CONFIG(_x...) printk _x/* number of characters left in xmit buffer before we ask for more */#define WAKEUP_CHARS 256/* number of characters we want to transmit to the lower level at a time */#define IOC4_MAX_CHARS 256#define IOC4_FIFO_CHARS 255/* Device name we're using */#define DEVICE_NAME_RS232 "ttyIOC"#define DEVICE_NAME_RS422 "ttyAIOC"#define DEVICE_MAJOR 204#define DEVICE_MINOR_RS232 50#define DEVICE_MINOR_RS422 84/* register offsets */#define IOC4_SERIAL_OFFSET 0x300/* flags for next_char_state */#define NCS_BREAK 0x1#define NCS_PARITY 0x2#define NCS_FRAMING 0x4#define NCS_OVERRUN 0x8/* cause we need SOME parameters ... */#define MIN_BAUD_SUPPORTED 1200#define MAX_BAUD_SUPPORTED 115200/* protocol types supported */#define PROTO_RS232 3#define PROTO_RS422 7/* Notification types */#define N_DATA_READY 0x01#define N_OUTPUT_LOWAT 0x02#define N_BREAK 0x04#define N_PARITY_ERROR 0x08#define N_FRAMING_ERROR 0x10#define N_OVERRUN_ERROR 0x20#define N_DDCD 0x40#define N_DCTS 0x80#define N_ALL_INPUT (N_DATA_READY | N_BREAK | \ N_PARITY_ERROR | N_FRAMING_ERROR | \ N_OVERRUN_ERROR | N_DDCD | N_DCTS)#define N_ALL_OUTPUT N_OUTPUT_LOWAT#define N_ALL_ERRORS (N_PARITY_ERROR | N_FRAMING_ERROR | N_OVERRUN_ERROR)#define N_ALL (N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK | \ N_PARITY_ERROR | N_FRAMING_ERROR | \ N_OVERRUN_ERROR | N_DDCD | N_DCTS)#define SER_DIVISOR(_x, clk) (((clk) + (_x) * 8) / ((_x) * 16))#define DIVISOR_TO_BAUD(div, clk) ((clk) / 16 / (div))/* Some masks */#define LCR_MASK_BITS_CHAR (UART_LCR_WLEN5 | UART_LCR_WLEN6 \ | UART_LCR_WLEN7 | UART_LCR_WLEN8)#define LCR_MASK_STOP_BITS (UART_LCR_STOP)#define PENDING(_p) (readl(&(_p)->ip_mem->sio_ir.raw) & _p->ip_ienb)#define READ_SIO_IR(_p) readl(&(_p)->ip_mem->sio_ir.raw)/* Default to 4k buffers */#ifdef IOC4_1K_BUFFERS#define RING_BUF_SIZE 1024#define IOC4_BUF_SIZE_BIT 0#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_1K#else#define RING_BUF_SIZE 4096#define IOC4_BUF_SIZE_BIT IOC4_SBBR_L_SIZE#define PROD_CONS_MASK IOC4_PROD_CONS_PTR_4K#endif#define TOTAL_RING_BUF_SIZE (RING_BUF_SIZE * 4)/* * This is the entry saved by the driver - one per card */#define UART_PORT_MIN 0#define UART_PORT_RS232 UART_PORT_MIN#define UART_PORT_RS422 1#define UART_PORT_COUNT 2 /* one for each mode */struct ioc4_control { int ic_irq; struct { /* uart ports are allocated here - 1 for rs232, 1 for rs422 */ struct uart_port icp_uart_port[UART_PORT_COUNT]; /* Handy reference material */ struct ioc4_port *icp_port; } ic_port[IOC4_NUM_SERIAL_PORTS]; struct ioc4_soft *ic_soft;};/* * per-IOC4 data structure */#define MAX_IOC4_INTR_ENTS (8 * sizeof(uint32_t))struct ioc4_soft { struct ioc4_misc_regs __iomem *is_ioc4_misc_addr; struct ioc4_serial __iomem *is_ioc4_serial_addr; /* Each interrupt type has an entry in the array */ struct ioc4_intr_type { /* * Each in-use entry in this array contains at least * one nonzero bit in sd_bits; no two entries in this * array have overlapping sd_bits values. */ struct ioc4_intr_info { uint32_t sd_bits; ioc4_intr_func_f *sd_intr; void *sd_info; } is_intr_info[MAX_IOC4_INTR_ENTS]; /* Number of entries active in the above array */ atomic_t is_num_intrs; } is_intr_type[IOC4_NUM_INTR_TYPES]; /* is_ir_lock must be held while * modifying sio_ie values, so * we can be sure that sio_ie is * not changing when we read it * along with sio_ir. */ spinlock_t is_ir_lock; /* SIO_IE[SC] mod lock */};
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?