Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for Jasmine adapter
#
obj-$(CONFIG_SERIAL_JSM) += jsm.o
jsm-objs := jsm_driver.o jsm_neo.o jsm_tty.o jsm_cls.o
+433
View File
@@ -0,0 +1,433 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/************************************************************************
* Copyright 2003 Digi International (www.digi.com)
*
* Copyright (C) 2004 IBM Corporation. All rights reserved.
*
* Contact Information:
* Scott H Kilau <Scott_Kilau@digi.com>
* Wendy Xiong <wendyx@us.ibm.com>
*
***********************************************************************/
#ifndef __JSM_DRIVER_H
#define __JSM_DRIVER_H
#include <linux/kernel.h>
#include <linux/types.h> /* To pick up the varions Linux types */
#include <linux/tty.h>
#include <linux/serial_core.h>
#include <linux/device.h>
/*
* Debugging levels can be set using debug insmod variable
* They can also be compiled out completely.
*/
enum {
DBG_INIT = 0x01,
DBG_BASIC = 0x02,
DBG_CORE = 0x04,
DBG_OPEN = 0x08,
DBG_CLOSE = 0x10,
DBG_READ = 0x20,
DBG_WRITE = 0x40,
DBG_IOCTL = 0x80,
DBG_PROC = 0x100,
DBG_PARAM = 0x200,
DBG_PSCAN = 0x400,
DBG_EVENT = 0x800,
DBG_DRAIN = 0x1000,
DBG_MSIGS = 0x2000,
DBG_MGMT = 0x4000,
DBG_INTR = 0x8000,
DBG_CARR = 0x10000,
};
#define jsm_dbg(nlevel, pdev, fmt, ...) \
do { \
if (DBG_##nlevel & jsm_debug) \
dev_dbg(pdev->dev, fmt, ##__VA_ARGS__); \
} while (0)
#define MAXLINES 256
#define MAXPORTS 8
#define MAX_STOPS_SENT 5
/* Board ids */
#define PCI_DEVICE_ID_CLASSIC_4 0x0028
#define PCI_DEVICE_ID_CLASSIC_8 0x0029
#define PCI_DEVICE_ID_CLASSIC_4_422 0x00D0
#define PCI_DEVICE_ID_CLASSIC_8_422 0x00D1
#define PCI_DEVICE_ID_NEO_4 0x00B0
#define PCI_DEVICE_ID_NEO_1_422 0x00CC
#define PCI_DEVICE_ID_NEO_1_422_485 0x00CD
#define PCI_DEVICE_ID_NEO_2_422_485 0x00CE
#define PCIE_DEVICE_ID_NEO_8 0x00F0
#define PCIE_DEVICE_ID_NEO_4 0x00F1
#define PCIE_DEVICE_ID_NEO_4RJ45 0x00F2
#define PCIE_DEVICE_ID_NEO_8RJ45 0x00F3
/* Board type definitions */
#define T_NEO 0000
#define T_CLASSIC 0001
#define T_PCIBUS 0400
/* Board State Definitions */
#define BD_RUNNING 0x0
#define BD_REASON 0x7f
#define BD_NOTFOUND 0x1
#define BD_NOIOPORT 0x2
#define BD_NOMEM 0x3
#define BD_NOBIOS 0x4
#define BD_NOFEP 0x5
#define BD_FAILED 0x6
#define BD_ALLOCATED 0x7
#define BD_TRIBOOT 0x8
#define BD_BADKME 0x80
/* 4 extra for alignment play space */
#define WRITEBUFLEN ((4096) + 4)
#define JSM_VERSION "jsm: 1.2-1-INKERNEL"
#define JSM_PARTNUM "40002438_A-INKERNEL"
struct jsm_board;
struct jsm_channel;
/************************************************************************
* Per board operations structure *
************************************************************************/
struct board_ops {
irq_handler_t intr;
void (*uart_init)(struct jsm_channel *ch);
void (*uart_off)(struct jsm_channel *ch);
void (*param)(struct jsm_channel *ch);
void (*assert_modem_signals)(struct jsm_channel *ch);
void (*flush_uart_write)(struct jsm_channel *ch);
void (*flush_uart_read)(struct jsm_channel *ch);
void (*disable_receiver)(struct jsm_channel *ch);
void (*enable_receiver)(struct jsm_channel *ch);
void (*send_break)(struct jsm_channel *ch);
void (*clear_break)(struct jsm_channel *ch);
void (*send_start_character)(struct jsm_channel *ch);
void (*send_stop_character)(struct jsm_channel *ch);
void (*copy_data_from_queue_to_uart)(struct jsm_channel *ch);
};
/*
* Per-board information
*/
struct jsm_board
{
int boardnum; /* Board number: 0-32 */
u8 rev; /* PCI revision ID */
struct pci_dev *pci_dev;
u32 maxports; /* MAX ports this board can handle */
spinlock_t bd_intr_lock; /* Used to protect the poller tasklet and
* the interrupt routine from each other.
*/
u32 nasync; /* Number of ports on card */
u32 irq; /* Interrupt request number */
u64 membase; /* Start of base memory of the card */
u64 membase_end; /* End of base memory of the card */
u8 __iomem *re_map_membase;/* Remapped memory of the card */
u64 iobase; /* Start of io base of the card */
u64 iobase_end; /* End of io base of the card */
u32 bd_uart_offset; /* Space between each UART */
struct jsm_channel *channels[MAXPORTS]; /* array of pointers to our channels. */
u32 bd_dividend; /* Board/UARTs specific dividend */
struct board_ops *bd_ops;
};
/************************************************************************
* Device flag definitions for ch_flags.
************************************************************************/
#define CH_PRON 0x0001 /* Printer on string */
#define CH_STOP 0x0002 /* Output is stopped */
#define CH_STOPI 0x0004 /* Input is stopped */
#define CH_CD 0x0008 /* Carrier is present */
#define CH_FCAR 0x0010 /* Carrier forced on */
#define CH_HANGUP 0x0020 /* Hangup received */
#define CH_RECEIVER_OFF 0x0040 /* Receiver is off */
#define CH_OPENING 0x0080 /* Port in fragile open state */
#define CH_CLOSING 0x0100 /* Port in fragile close state */
#define CH_FIFO_ENABLED 0x0200 /* Port has FIFOs enabled */
#define CH_TX_FIFO_EMPTY 0x0400 /* TX Fifo is completely empty */
#define CH_TX_FIFO_LWM 0x0800 /* TX Fifo is below Low Water */
#define CH_BREAK_SENDING 0x1000 /* Break is being sent */
#define CH_LOOPBACK 0x2000 /* Channel is in lookback mode */
#define CH_BAUD0 0x08000 /* Used for checking B0 transitions */
/* Our Read/Error queue sizes */
#define RQUEUEMASK 0x1FFF /* 8 K - 1 */
#define EQUEUEMASK 0x1FFF /* 8 K - 1 */
#define RQUEUESIZE (RQUEUEMASK + 1)
#define EQUEUESIZE RQUEUESIZE
/************************************************************************
* Channel information structure.
************************************************************************/
struct jsm_channel {
struct uart_port uart_port;
struct jsm_board *ch_bd; /* Board structure pointer */
spinlock_t ch_lock; /* provide for serialization */
wait_queue_head_t ch_flags_wait;
u32 ch_portnum; /* Port number, 0 offset. */
u32 ch_open_count; /* open count */
u32 ch_flags; /* Channel flags */
u64 ch_close_delay; /* How long we should drop RTS/DTR for */
tcflag_t ch_c_iflag; /* channel iflags */
tcflag_t ch_c_cflag; /* channel cflags */
tcflag_t ch_c_oflag; /* channel oflags */
tcflag_t ch_c_lflag; /* channel lflags */
u8 ch_stopc; /* Stop character */
u8 ch_startc; /* Start character */
u8 ch_mostat; /* FEP output modem status */
u8 ch_mistat; /* FEP input modem status */
/* Pointers to the "mapped" UART structs */
struct neo_uart_struct __iomem *ch_neo_uart; /* NEO card */
struct cls_uart_struct __iomem *ch_cls_uart; /* Classic card */
u8 ch_cached_lsr; /* Cached value of the LSR register */
u8 *ch_rqueue; /* Our read queue buffer - malloc'ed */
u16 ch_r_head; /* Head location of the read queue */
u16 ch_r_tail; /* Tail location of the read queue */
u8 *ch_equeue; /* Our error queue buffer - malloc'ed */
u16 ch_e_head; /* Head location of the error queue */
u16 ch_e_tail; /* Tail location of the error queue */
u64 ch_rxcount; /* total of data received so far */
u64 ch_txcount; /* total of data transmitted so far */
u8 ch_r_tlevel; /* Receive Trigger level */
u8 ch_t_tlevel; /* Transmit Trigger level */
u8 ch_r_watermark; /* Receive Watermark */
u32 ch_stops_sent; /* How many times I have sent a stop character
* to try to stop the other guy sending.
*/
u64 ch_err_parity; /* Count of parity errors on channel */
u64 ch_err_frame; /* Count of framing errors on channel */
u64 ch_err_break; /* Count of breaks on channel */
u64 ch_err_overrun; /* Count of overruns on channel */
u64 ch_xon_sends; /* Count of xons transmitted */
u64 ch_xoff_sends; /* Count of xoffs transmitted */
};
/************************************************************************
* Per channel/port Classic UART structures *
************************************************************************
* Base Structure Entries Usage Meanings to Host *
* *
* W = read write R = read only *
* U = Unused. *
************************************************************************/
struct cls_uart_struct {
u8 txrx; /* WR RHR/THR - Holding Reg */
u8 ier; /* WR IER - Interrupt Enable Reg */
u8 isr_fcr; /* WR ISR/FCR - Interrupt Status Reg/Fifo Control Reg*/
u8 lcr; /* WR LCR - Line Control Reg */
u8 mcr; /* WR MCR - Modem Control Reg */
u8 lsr; /* WR LSR - Line Status Reg */
u8 msr; /* WR MSR - Modem Status Reg */
u8 spr; /* WR SPR - Scratch Pad Reg */
};
/* Where to read the interrupt register (8bits) */
#define UART_CLASSIC_POLL_ADDR_OFFSET 0x40
#define UART_EXAR654_ENHANCED_REGISTER_SET 0xBF
#define UART_16654_FCR_TXTRIGGER_8 0x0
#define UART_16654_FCR_TXTRIGGER_16 0x10
#define UART_16654_FCR_TXTRIGGER_32 0x20
#define UART_16654_FCR_TXTRIGGER_56 0x30
#define UART_16654_FCR_RXTRIGGER_8 0x0
#define UART_16654_FCR_RXTRIGGER_16 0x40
#define UART_16654_FCR_RXTRIGGER_56 0x80
#define UART_16654_FCR_RXTRIGGER_60 0xC0
#define UART_IIR_CTSRTS 0x20 /* Received CTS/RTS change of state */
#define UART_IIR_RDI_TIMEOUT 0x0C /* Receiver data TIMEOUT */
/*
* These are the EXTENDED definitions for the Exar 654's Interrupt
* Enable Register.
*/
#define UART_EXAR654_EFR_ECB 0x10 /* Enhanced control bit */
#define UART_EXAR654_EFR_IXON 0x2 /* Receiver compares Xon1/Xoff1 */
#define UART_EXAR654_EFR_IXOFF 0x8 /* Transmit Xon1/Xoff1 */
#define UART_EXAR654_EFR_RTSDTR 0x40 /* Auto RTS/DTR Flow Control Enable */
#define UART_EXAR654_EFR_CTSDSR 0x80 /* Auto CTS/DSR Flow COntrol Enable */
#define UART_EXAR654_XOFF_DETECT 0x1 /* Indicates whether chip saw an incoming XOFF char */
#define UART_EXAR654_XON_DETECT 0x2 /* Indicates whether chip saw an incoming XON char */
#define UART_EXAR654_IER_XOFF 0x20 /* Xoff Interrupt Enable */
#define UART_EXAR654_IER_RTSDTR 0x40 /* Output Interrupt Enable */
#define UART_EXAR654_IER_CTSDSR 0x80 /* Input Interrupt Enable */
/************************************************************************
* Per channel/port NEO UART structure *
************************************************************************
* Base Structure Entries Usage Meanings to Host *
* *
* W = read write R = read only *
* U = Unused. *
************************************************************************/
struct neo_uart_struct {
u8 txrx; /* WR RHR/THR - Holding Reg */
u8 ier; /* WR IER - Interrupt Enable Reg */
u8 isr_fcr; /* WR ISR/FCR - Interrupt Status Reg/Fifo Control Reg */
u8 lcr; /* WR LCR - Line Control Reg */
u8 mcr; /* WR MCR - Modem Control Reg */
u8 lsr; /* WR LSR - Line Status Reg */
u8 msr; /* WR MSR - Modem Status Reg */
u8 spr; /* WR SPR - Scratch Pad Reg */
u8 fctr; /* WR FCTR - Feature Control Reg */
u8 efr; /* WR EFR - Enhanced Function Reg */
u8 tfifo; /* WR TXCNT/TXTRG - Transmit FIFO Reg */
u8 rfifo; /* WR RXCNT/RXTRG - Receive FIFO Reg */
u8 xoffchar1; /* WR XOFF 1 - XOff Character 1 Reg */
u8 xoffchar2; /* WR XOFF 2 - XOff Character 2 Reg */
u8 xonchar1; /* WR XON 1 - Xon Character 1 Reg */
u8 xonchar2; /* WR XON 2 - XOn Character 2 Reg */
u8 reserved1[0x2ff - 0x200]; /* U Reserved by Exar */
u8 txrxburst[64]; /* RW 64 bytes of RX/TX FIFO Data */
u8 reserved2[0x37f - 0x340]; /* U Reserved by Exar */
u8 rxburst_with_errors[64]; /* R 64 bytes of RX FIFO Data + LSR */
};
/* Where to read the extended interrupt register (32bits instead of 8bits) */
#define UART_17158_POLL_ADDR_OFFSET 0x80
/*
* These are the redefinitions for the FCTR on the XR17C158, since
* Exar made them different than their earlier design. (XR16C854)
*/
/* These are only applicable when table D is selected */
#define UART_17158_FCTR_RTS_NODELAY 0x00
#define UART_17158_FCTR_RTS_4DELAY 0x01
#define UART_17158_FCTR_RTS_6DELAY 0x02
#define UART_17158_FCTR_RTS_8DELAY 0x03
#define UART_17158_FCTR_RTS_12DELAY 0x12
#define UART_17158_FCTR_RTS_16DELAY 0x05
#define UART_17158_FCTR_RTS_20DELAY 0x13
#define UART_17158_FCTR_RTS_24DELAY 0x06
#define UART_17158_FCTR_RTS_28DELAY 0x14
#define UART_17158_FCTR_RTS_32DELAY 0x07
#define UART_17158_FCTR_RTS_36DELAY 0x16
#define UART_17158_FCTR_RTS_40DELAY 0x08
#define UART_17158_FCTR_RTS_44DELAY 0x09
#define UART_17158_FCTR_RTS_48DELAY 0x10
#define UART_17158_FCTR_RTS_52DELAY 0x11
#define UART_17158_FCTR_RTS_IRDA 0x10
#define UART_17158_FCTR_RS485 0x20
#define UART_17158_FCTR_TRGA 0x00
#define UART_17158_FCTR_TRGB 0x40
#define UART_17158_FCTR_TRGC 0x80
#define UART_17158_FCTR_TRGD 0xC0
/* 17158 trigger table selects.. */
#define UART_17158_FCTR_BIT6 0x40
#define UART_17158_FCTR_BIT7 0x80
/* 17158 TX/RX memmapped buffer offsets */
#define UART_17158_RX_FIFOSIZE 64
#define UART_17158_TX_FIFOSIZE 64
/* 17158 Extended IIR's */
#define UART_17158_IIR_RDI_TIMEOUT 0x0C /* Receiver data TIMEOUT */
#define UART_17158_IIR_XONXOFF 0x10 /* Received an XON/XOFF char */
#define UART_17158_IIR_HWFLOW_STATE_CHANGE 0x20 /* CTS/DSR or RTS/DTR state change */
#define UART_17158_IIR_FIFO_ENABLED 0xC0 /* 16550 FIFOs are Enabled */
/*
* These are the extended interrupts that get sent
* back to us from the UART's 32bit interrupt register
*/
#define UART_17158_RX_LINE_STATUS 0x1 /* RX Ready */
#define UART_17158_RXRDY_TIMEOUT 0x2 /* RX Ready Timeout */
#define UART_17158_TXRDY 0x3 /* TX Ready */
#define UART_17158_MSR 0x4 /* Modem State Change */
#define UART_17158_TX_AND_FIFO_CLR 0x40 /* Transmitter Holding Reg Empty */
#define UART_17158_RX_FIFO_DATA_ERROR 0x80 /* UART detected an RX FIFO Data error */
/*
* These are the EXTENDED definitions for the 17C158's Interrupt
* Enable Register.
*/
#define UART_17158_EFR_ECB 0x10 /* Enhanced control bit */
#define UART_17158_EFR_IXON 0x2 /* Receiver compares Xon1/Xoff1 */
#define UART_17158_EFR_IXOFF 0x8 /* Transmit Xon1/Xoff1 */
#define UART_17158_EFR_RTSDTR 0x40 /* Auto RTS/DTR Flow Control Enable */
#define UART_17158_EFR_CTSDSR 0x80 /* Auto CTS/DSR Flow COntrol Enable */
#define UART_17158_XOFF_DETECT 0x1 /* Indicates whether chip saw an incoming XOFF char */
#define UART_17158_XON_DETECT 0x2 /* Indicates whether chip saw an incoming XON char */
#define UART_17158_IER_RSVD1 0x10 /* Reserved by Exar */
#define UART_17158_IER_XOFF 0x20 /* Xoff Interrupt Enable */
#define UART_17158_IER_RTSDTR 0x40 /* Output Interrupt Enable */
#define UART_17158_IER_CTSDSR 0x80 /* Input Interrupt Enable */
#define PCI_DEVICE_NEO_2DB9_PCI_NAME "Neo 2 - DB9 Universal PCI"
#define PCI_DEVICE_NEO_2DB9PRI_PCI_NAME "Neo 2 - DB9 Universal PCI - Powered Ring Indicator"
#define PCI_DEVICE_NEO_2RJ45_PCI_NAME "Neo 2 - RJ45 Universal PCI"
#define PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME "Neo 2 - RJ45 Universal PCI - Powered Ring Indicator"
#define PCIE_DEVICE_NEO_IBM_PCI_NAME "Neo 4 - PCI Express - IBM"
/*
* Our Global Variables.
*/
extern struct uart_driver jsm_uart_driver;
extern struct board_ops jsm_neo_ops;
extern struct board_ops jsm_cls_ops;
extern int jsm_debug;
/*************************************************************************
*
* Prototypes for non-static functions used in more than one module
*
*************************************************************************/
int jsm_tty_init(struct jsm_board *);
int jsm_uart_port_init(struct jsm_board *);
int jsm_remove_uart_port(struct jsm_board *);
void jsm_input(struct jsm_channel *ch);
void jsm_check_queue_flow_control(struct jsm_channel *ch);
#endif
@@ -0,0 +1,899 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2003 Digi International (www.digi.com)
* Scott H Kilau <Scott_Kilau at digi dot com>
*
* NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE!
*
* This is shared code between Digi's CVS archive and the
* Linux Kernel sources.
* Changing the source just for reformatting needlessly breaks
* our CVS diff history.
*
* Send any bug fixes/changes to: Eng.Linux at digi dot com.
* Thank you.
*
*/
#include <linux/delay.h> /* For udelay */
#include <linux/io.h> /* For read[bwl]/write[bwl] */
#include <linux/serial.h> /* For struct async_serial */
#include <linux/serial_reg.h> /* For the various UART offsets */
#include <linux/pci.h>
#include <linux/tty.h>
#include "jsm.h" /* Driver main header file */
static struct {
unsigned int rate;
unsigned int cflag;
} baud_rates[] = {
{ 921600, B921600 },
{ 460800, B460800 },
{ 230400, B230400 },
{ 115200, B115200 },
{ 57600, B57600 },
{ 38400, B38400 },
{ 19200, B19200 },
{ 9600, B9600 },
{ 4800, B4800 },
{ 2400, B2400 },
{ 1200, B1200 },
{ 600, B600 },
{ 300, B300 },
{ 200, B200 },
{ 150, B150 },
{ 134, B134 },
{ 110, B110 },
{ 75, B75 },
{ 50, B50 },
};
static void cls_set_cts_flow_control(struct jsm_channel *ch)
{
u8 lcrb = readb(&ch->ch_cls_uart->lcr);
u8 ier = readb(&ch->ch_cls_uart->ier);
u8 isr_fcr = 0;
/*
* The Enhanced Register Set may only be accessed when
* the Line Control Register is set to 0xBFh.
*/
writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
/* Turn on CTS flow control, turn off IXON flow control */
isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_CTSDSR);
isr_fcr &= ~(UART_EXAR654_EFR_IXON);
writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
/* Write old LCR value back out, which turns enhanced access off */
writeb(lcrb, &ch->ch_cls_uart->lcr);
/*
* Enable interrupts for CTS flow, turn off interrupts for
* received XOFF chars
*/
ier |= (UART_EXAR654_IER_CTSDSR);
ier &= ~(UART_EXAR654_IER_XOFF);
writeb(ier, &ch->ch_cls_uart->ier);
/* Set the usual FIFO values */
writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 |
UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
&ch->ch_cls_uart->isr_fcr);
ch->ch_t_tlevel = 16;
}
static void cls_set_ixon_flow_control(struct jsm_channel *ch)
{
u8 lcrb = readb(&ch->ch_cls_uart->lcr);
u8 ier = readb(&ch->ch_cls_uart->ier);
u8 isr_fcr = 0;
/*
* The Enhanced Register Set may only be accessed when
* the Line Control Register is set to 0xBFh.
*/
writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
/* Turn on IXON flow control, turn off CTS flow control */
isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXON);
isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR);
writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
/* Now set our current start/stop chars while in enhanced mode */
writeb(ch->ch_startc, &ch->ch_cls_uart->mcr);
writeb(0, &ch->ch_cls_uart->lsr);
writeb(ch->ch_stopc, &ch->ch_cls_uart->msr);
writeb(0, &ch->ch_cls_uart->spr);
/* Write old LCR value back out, which turns enhanced access off */
writeb(lcrb, &ch->ch_cls_uart->lcr);
/*
* Disable interrupts for CTS flow, turn on interrupts for
* received XOFF chars
*/
ier &= ~(UART_EXAR654_IER_CTSDSR);
ier |= (UART_EXAR654_IER_XOFF);
writeb(ier, &ch->ch_cls_uart->ier);
/* Set the usual FIFO values */
writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
&ch->ch_cls_uart->isr_fcr);
}
static void cls_set_no_output_flow_control(struct jsm_channel *ch)
{
u8 lcrb = readb(&ch->ch_cls_uart->lcr);
u8 ier = readb(&ch->ch_cls_uart->ier);
u8 isr_fcr = 0;
/*
* The Enhanced Register Set may only be accessed when
* the Line Control Register is set to 0xBFh.
*/
writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
/* Turn off IXON flow control, turn off CTS flow control */
isr_fcr |= (UART_EXAR654_EFR_ECB);
isr_fcr &= ~(UART_EXAR654_EFR_CTSDSR | UART_EXAR654_EFR_IXON);
writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
/* Write old LCR value back out, which turns enhanced access off */
writeb(lcrb, &ch->ch_cls_uart->lcr);
/*
* Disable interrupts for CTS flow, turn off interrupts for
* received XOFF chars
*/
ier &= ~(UART_EXAR654_IER_CTSDSR);
ier &= ~(UART_EXAR654_IER_XOFF);
writeb(ier, &ch->ch_cls_uart->ier);
/* Set the usual FIFO values */
writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
&ch->ch_cls_uart->isr_fcr);
ch->ch_r_watermark = 0;
ch->ch_t_tlevel = 16;
ch->ch_r_tlevel = 16;
}
static void cls_set_rts_flow_control(struct jsm_channel *ch)
{
u8 lcrb = readb(&ch->ch_cls_uart->lcr);
u8 ier = readb(&ch->ch_cls_uart->ier);
u8 isr_fcr = 0;
/*
* The Enhanced Register Set may only be accessed when
* the Line Control Register is set to 0xBFh.
*/
writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
/* Turn on RTS flow control, turn off IXOFF flow control */
isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_RTSDTR);
isr_fcr &= ~(UART_EXAR654_EFR_IXOFF);
writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
/* Write old LCR value back out, which turns enhanced access off */
writeb(lcrb, &ch->ch_cls_uart->lcr);
/* Enable interrupts for RTS flow */
ier |= (UART_EXAR654_IER_RTSDTR);
writeb(ier, &ch->ch_cls_uart->ier);
/* Set the usual FIFO values */
writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_56 |
UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
&ch->ch_cls_uart->isr_fcr);
ch->ch_r_watermark = 4;
ch->ch_r_tlevel = 8;
}
static void cls_set_ixoff_flow_control(struct jsm_channel *ch)
{
u8 lcrb = readb(&ch->ch_cls_uart->lcr);
u8 ier = readb(&ch->ch_cls_uart->ier);
u8 isr_fcr = 0;
/*
* The Enhanced Register Set may only be accessed when
* the Line Control Register is set to 0xBFh.
*/
writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
/* Turn on IXOFF flow control, turn off RTS flow control */
isr_fcr |= (UART_EXAR654_EFR_ECB | UART_EXAR654_EFR_IXOFF);
isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR);
writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
/* Now set our current start/stop chars while in enhanced mode */
writeb(ch->ch_startc, &ch->ch_cls_uart->mcr);
writeb(0, &ch->ch_cls_uart->lsr);
writeb(ch->ch_stopc, &ch->ch_cls_uart->msr);
writeb(0, &ch->ch_cls_uart->spr);
/* Write old LCR value back out, which turns enhanced access off */
writeb(lcrb, &ch->ch_cls_uart->lcr);
/* Disable interrupts for RTS flow */
ier &= ~(UART_EXAR654_IER_RTSDTR);
writeb(ier, &ch->ch_cls_uart->ier);
/* Set the usual FIFO values */
writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
&ch->ch_cls_uart->isr_fcr);
}
static void cls_set_no_input_flow_control(struct jsm_channel *ch)
{
u8 lcrb = readb(&ch->ch_cls_uart->lcr);
u8 ier = readb(&ch->ch_cls_uart->ier);
u8 isr_fcr = 0;
/*
* The Enhanced Register Set may only be accessed when
* the Line Control Register is set to 0xBFh.
*/
writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
/* Turn off IXOFF flow control, turn off RTS flow control */
isr_fcr |= (UART_EXAR654_EFR_ECB);
isr_fcr &= ~(UART_EXAR654_EFR_RTSDTR | UART_EXAR654_EFR_IXOFF);
writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
/* Write old LCR value back out, which turns enhanced access off */
writeb(lcrb, &ch->ch_cls_uart->lcr);
/* Disable interrupts for RTS flow */
ier &= ~(UART_EXAR654_IER_RTSDTR);
writeb(ier, &ch->ch_cls_uart->ier);
/* Set the usual FIFO values */
writeb((UART_FCR_ENABLE_FIFO), &ch->ch_cls_uart->isr_fcr);
writeb((UART_FCR_ENABLE_FIFO | UART_16654_FCR_RXTRIGGER_16 |
UART_16654_FCR_TXTRIGGER_16 | UART_FCR_CLEAR_RCVR),
&ch->ch_cls_uart->isr_fcr);
ch->ch_t_tlevel = 16;
ch->ch_r_tlevel = 16;
}
/*
* cls_clear_break.
* Determines whether its time to shut off break condition.
*
* No locks are assumed to be held when calling this function.
* channel lock is held and released in this function.
*/
static void cls_clear_break(struct jsm_channel *ch)
{
unsigned long lock_flags;
spin_lock_irqsave(&ch->ch_lock, lock_flags);
/* Turn break off, and unset some variables */
if (ch->ch_flags & CH_BREAK_SENDING) {
u8 temp = readb(&ch->ch_cls_uart->lcr);
writeb((temp & ~UART_LCR_SBC), &ch->ch_cls_uart->lcr);
ch->ch_flags &= ~(CH_BREAK_SENDING);
jsm_dbg(IOCTL, &ch->ch_bd->pci_dev,
"clear break Finishing UART_LCR_SBC! finished: %lx\n",
jiffies);
}
spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
}
static void cls_disable_receiver(struct jsm_channel *ch)
{
u8 tmp = readb(&ch->ch_cls_uart->ier);
tmp &= ~(UART_IER_RDI);
writeb(tmp, &ch->ch_cls_uart->ier);
}
static void cls_enable_receiver(struct jsm_channel *ch)
{
u8 tmp = readb(&ch->ch_cls_uart->ier);
tmp |= (UART_IER_RDI);
writeb(tmp, &ch->ch_cls_uart->ier);
}
/* Make the UART raise any of the output signals we want up */
static void cls_assert_modem_signals(struct jsm_channel *ch)
{
if (!ch)
return;
writeb(ch->ch_mostat, &ch->ch_cls_uart->mcr);
}
static void cls_copy_data_from_uart_to_queue(struct jsm_channel *ch)
{
int qleft = 0;
u8 linestatus;
u8 error_mask = 0;
u16 head;
u16 tail;
unsigned long flags;
if (!ch)
return;
spin_lock_irqsave(&ch->ch_lock, flags);
/* cache head and tail of queue */
head = ch->ch_r_head & RQUEUEMASK;
tail = ch->ch_r_tail & RQUEUEMASK;
ch->ch_cached_lsr = 0;
/* Store how much space we have left in the queue */
qleft = tail - head - 1;
if (qleft < 0)
qleft += RQUEUEMASK + 1;
/*
* Create a mask to determine whether we should
* insert the character (if any) into our queue.
*/
if (ch->ch_c_iflag & IGNBRK)
error_mask |= UART_LSR_BI;
while (1) {
/*
* Grab the linestatus register, we need to
* check to see if there is any data to read
*/
linestatus = readb(&ch->ch_cls_uart->lsr);
/* Break out if there is no data to fetch */
if (!(linestatus & UART_LSR_DR))
break;
/*
* Discard character if we are ignoring the error mask
* which in this case is the break signal.
*/
if (linestatus & error_mask) {
readb(&ch->ch_cls_uart->txrx);
continue;
}
/*
* If our queue is full, we have no choice but to drop some
* data. The assumption is that HWFLOW or SWFLOW should have
* stopped things way way before we got to this point.
*
* I decided that I wanted to ditch the oldest data first,
* I hope thats okay with everyone? Yes? Good.
*/
while (qleft < 1) {
tail = (tail + 1) & RQUEUEMASK;
ch->ch_r_tail = tail;
ch->ch_err_overrun++;
qleft++;
}
ch->ch_equeue[head] = linestatus & (UART_LSR_BI | UART_LSR_PE
| UART_LSR_FE);
ch->ch_rqueue[head] = readb(&ch->ch_cls_uart->txrx);
qleft--;
if (ch->ch_equeue[head] & UART_LSR_PE)
ch->ch_err_parity++;
if (ch->ch_equeue[head] & UART_LSR_BI)
ch->ch_err_break++;
if (ch->ch_equeue[head] & UART_LSR_FE)
ch->ch_err_frame++;
/* Add to, and flip head if needed */
head = (head + 1) & RQUEUEMASK;
ch->ch_rxcount++;
}
/*
* Write new final heads to channel structure.
*/
ch->ch_r_head = head & RQUEUEMASK;
ch->ch_e_head = head & EQUEUEMASK;
spin_unlock_irqrestore(&ch->ch_lock, flags);
}
static void cls_copy_data_from_queue_to_uart(struct jsm_channel *ch)
{
struct tty_port *tport;
int n;
u32 len_written = 0;
if (!ch)
return;
tport = &ch->uart_port.state->port;
/* If port is "stopped", don't send any data to the UART */
if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_BREAK_SENDING))
return;
/* We have to do it this way, because of the EXAR TXFIFO count bug. */
if (!(ch->ch_flags & (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM)))
return;
n = 32;
while (n > 0) {
unsigned char c;
if (!kfifo_get(&tport->xmit_fifo, &c))
break;
writeb(c, &ch->ch_cls_uart->txrx);
n--;
ch->ch_txcount++;
len_written++;
}
if (len_written > ch->ch_t_tlevel)
ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
if (kfifo_is_empty(&tport->xmit_fifo))
uart_write_wakeup(&ch->uart_port);
}
static void cls_parse_modem(struct jsm_channel *ch, u8 signals)
{
u8 msignals = signals;
jsm_dbg(MSIGS, &ch->ch_bd->pci_dev,
"neo_parse_modem: port: %d msignals: %x\n",
ch->ch_portnum, msignals);
/*
* Scrub off lower bits.
* They signify delta's, which I don't care about
* Keep DDCD and DDSR though
*/
msignals &= 0xf8;
if (msignals & UART_MSR_DDCD)
uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD);
if (msignals & UART_MSR_DDSR)
uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_CTS);
if (msignals & UART_MSR_DCD)
ch->ch_mistat |= UART_MSR_DCD;
else
ch->ch_mistat &= ~UART_MSR_DCD;
if (msignals & UART_MSR_DSR)
ch->ch_mistat |= UART_MSR_DSR;
else
ch->ch_mistat &= ~UART_MSR_DSR;
if (msignals & UART_MSR_RI)
ch->ch_mistat |= UART_MSR_RI;
else
ch->ch_mistat &= ~UART_MSR_RI;
if (msignals & UART_MSR_CTS)
ch->ch_mistat |= UART_MSR_CTS;
else
ch->ch_mistat &= ~UART_MSR_CTS;
jsm_dbg(MSIGS, &ch->ch_bd->pci_dev,
"Port: %d DTR: %d RTS: %d CTS: %d DSR: %d " "RI: %d CD: %d\n",
ch->ch_portnum,
!!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_DTR),
!!((ch->ch_mistat | ch->ch_mostat) & UART_MCR_RTS),
!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_CTS),
!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DSR),
!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_RI),
!!((ch->ch_mistat | ch->ch_mostat) & UART_MSR_DCD));
}
/* Parse the ISR register for the specific port */
static inline void cls_parse_isr(struct jsm_board *brd, uint port)
{
struct jsm_channel *ch;
u8 isr = 0;
unsigned long flags;
/*
* No need to verify board pointer, it was already
* verified in the interrupt routine.
*/
if (port >= brd->nasync)
return;
ch = brd->channels[port];
if (!ch)
return;
/* Here we try to figure out what caused the interrupt to happen */
while (1) {
isr = readb(&ch->ch_cls_uart->isr_fcr);
/* Bail if no pending interrupt on port */
if (isr & UART_IIR_NO_INT)
break;
/* Receive Interrupt pending */
if (isr & (UART_IIR_RDI | UART_IIR_RDI_TIMEOUT)) {
/* Read data from uart -> queue */
cls_copy_data_from_uart_to_queue(ch);
jsm_check_queue_flow_control(ch);
}
/* Transmit Hold register empty pending */
if (isr & UART_IIR_THRI) {
/* Transfer data (if any) from Write Queue -> UART. */
spin_lock_irqsave(&ch->ch_lock, flags);
ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
spin_unlock_irqrestore(&ch->ch_lock, flags);
cls_copy_data_from_queue_to_uart(ch);
}
/*
* CTS/RTS change of state:
* Don't need to do anything, the cls_parse_modem
* below will grab the updated modem signals.
*/
/* Parse any modem signal changes */
cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr));
}
}
/* Channel lock MUST be held before calling this function! */
static void cls_flush_uart_write(struct jsm_channel *ch)
{
u8 tmp = 0;
u8 i = 0;
if (!ch)
return;
writeb((UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_XMIT),
&ch->ch_cls_uart->isr_fcr);
for (i = 0; i < 10; i++) {
/* Check to see if the UART feels it completely flushed FIFO */
tmp = readb(&ch->ch_cls_uart->isr_fcr);
if (tmp & UART_FCR_CLEAR_XMIT) {
jsm_dbg(IOCTL, &ch->ch_bd->pci_dev,
"Still flushing TX UART... i: %d\n", i);
udelay(10);
} else
break;
}
ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
}
/* Channel lock MUST be held before calling this function! */
static void cls_flush_uart_read(struct jsm_channel *ch)
{
if (!ch)
return;
/*
* For complete POSIX compatibility, we should be purging the
* read FIFO in the UART here.
*
* However, clearing the read FIFO (UART_FCR_CLEAR_RCVR) also
* incorrectly flushes write data as well as just basically trashing the
* FIFO.
*
* Presumably, this is a bug in this UART.
*/
udelay(10);
}
static void cls_send_start_character(struct jsm_channel *ch)
{
if (!ch)
return;
if (ch->ch_startc != __DISABLED_CHAR) {
ch->ch_xon_sends++;
writeb(ch->ch_startc, &ch->ch_cls_uart->txrx);
}
}
static void cls_send_stop_character(struct jsm_channel *ch)
{
if (!ch)
return;
if (ch->ch_stopc != __DISABLED_CHAR) {
ch->ch_xoff_sends++;
writeb(ch->ch_stopc, &ch->ch_cls_uart->txrx);
}
}
/*
* cls_param()
* Send any/all changes to the line to the UART.
*/
static void cls_param(struct jsm_channel *ch)
{
u8 lcr = 0;
u8 uart_lcr = 0;
u8 ier = 0;
u32 baud = 9600;
int quot = 0;
struct jsm_board *bd;
int i;
unsigned int cflag;
bd = ch->ch_bd;
if (!bd)
return;
/*
* If baud rate is zero, flush queues, and set mval to drop DTR.
*/
if ((ch->ch_c_cflag & CBAUD) == B0) {
ch->ch_r_head = 0;
ch->ch_r_tail = 0;
ch->ch_e_head = 0;
ch->ch_e_tail = 0;
cls_flush_uart_write(ch);
cls_flush_uart_read(ch);
/* The baudrate is B0 so all modem lines are to be dropped. */
ch->ch_flags |= (CH_BAUD0);
ch->ch_mostat &= ~(UART_MCR_RTS | UART_MCR_DTR);
cls_assert_modem_signals(ch);
return;
}
cflag = C_BAUD(ch->uart_port.state->port.tty);
baud = 9600;
for (i = 0; i < ARRAY_SIZE(baud_rates); i++) {
if (baud_rates[i].cflag == cflag) {
baud = baud_rates[i].rate;
break;
}
}
if (ch->ch_flags & CH_BAUD0)
ch->ch_flags &= ~(CH_BAUD0);
if (ch->ch_c_cflag & PARENB)
lcr |= UART_LCR_PARITY;
if (!(ch->ch_c_cflag & PARODD))
lcr |= UART_LCR_EPAR;
if (ch->ch_c_cflag & CMSPAR)
lcr |= UART_LCR_SPAR;
if (ch->ch_c_cflag & CSTOPB)
lcr |= UART_LCR_STOP;
lcr |= UART_LCR_WLEN(tty_get_char_size(ch->ch_c_cflag));
ier = readb(&ch->ch_cls_uart->ier);
uart_lcr = readb(&ch->ch_cls_uart->lcr);
quot = ch->ch_bd->bd_dividend / baud;
if (quot != 0) {
writeb(UART_LCR_DLAB, &ch->ch_cls_uart->lcr);
writeb((quot & 0xff), &ch->ch_cls_uart->txrx);
writeb((quot >> 8), &ch->ch_cls_uart->ier);
writeb(lcr, &ch->ch_cls_uart->lcr);
}
if (uart_lcr != lcr)
writeb(lcr, &ch->ch_cls_uart->lcr);
if (ch->ch_c_cflag & CREAD)
ier |= (UART_IER_RDI | UART_IER_RLSI);
ier |= (UART_IER_THRI | UART_IER_MSI);
writeb(ier, &ch->ch_cls_uart->ier);
if (ch->ch_c_cflag & CRTSCTS)
cls_set_cts_flow_control(ch);
else if (ch->ch_c_iflag & IXON) {
/*
* If start/stop is set to disable,
* then we should disable flow control.
*/
if ((ch->ch_startc == __DISABLED_CHAR) ||
(ch->ch_stopc == __DISABLED_CHAR))
cls_set_no_output_flow_control(ch);
else
cls_set_ixon_flow_control(ch);
} else
cls_set_no_output_flow_control(ch);
if (ch->ch_c_cflag & CRTSCTS)
cls_set_rts_flow_control(ch);
else if (ch->ch_c_iflag & IXOFF) {
/*
* If start/stop is set to disable,
* then we should disable flow control.
*/
if ((ch->ch_startc == __DISABLED_CHAR) ||
(ch->ch_stopc == __DISABLED_CHAR))
cls_set_no_input_flow_control(ch);
else
cls_set_ixoff_flow_control(ch);
} else
cls_set_no_input_flow_control(ch);
cls_assert_modem_signals(ch);
/* get current status of the modem signals now */
cls_parse_modem(ch, readb(&ch->ch_cls_uart->msr));
}
/*
* cls_intr()
*
* Classic specific interrupt handler.
*/
static irqreturn_t cls_intr(int irq, void *voidbrd)
{
struct jsm_board *brd = voidbrd;
unsigned long lock_flags;
unsigned char uart_poll;
uint i = 0;
/* Lock out the slow poller from running on this board. */
spin_lock_irqsave(&brd->bd_intr_lock, lock_flags);
/*
* Check the board's global interrupt offset to see if we
* acctually do have an interrupt pending on us.
*/
uart_poll = readb(brd->re_map_membase + UART_CLASSIC_POLL_ADDR_OFFSET);
jsm_dbg(INTR, &brd->pci_dev, "%s:%d uart_poll: %x\n",
__FILE__, __LINE__, uart_poll);
if (!uart_poll) {
jsm_dbg(INTR, &brd->pci_dev,
"Kernel interrupted to me, but no pending interrupts...\n");
spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
return IRQ_NONE;
}
/* At this point, we have at least SOMETHING to service, dig further. */
/* Parse each port to find out what caused the interrupt */
for (i = 0; i < brd->nasync; i++)
cls_parse_isr(brd, i);
spin_unlock_irqrestore(&brd->bd_intr_lock, lock_flags);
return IRQ_HANDLED;
}
/* Inits UART */
static void cls_uart_init(struct jsm_channel *ch)
{
unsigned char lcrb = readb(&ch->ch_cls_uart->lcr);
unsigned char isr_fcr = 0;
writeb(0, &ch->ch_cls_uart->ier);
/*
* The Enhanced Register Set may only be accessed when
* the Line Control Register is set to 0xBFh.
*/
writeb(UART_EXAR654_ENHANCED_REGISTER_SET, &ch->ch_cls_uart->lcr);
isr_fcr = readb(&ch->ch_cls_uart->isr_fcr);
/* Turn on Enhanced/Extended controls */
isr_fcr |= (UART_EXAR654_EFR_ECB);
writeb(isr_fcr, &ch->ch_cls_uart->isr_fcr);
/* Write old LCR value back out, which turns enhanced access off */
writeb(lcrb, &ch->ch_cls_uart->lcr);
/* Clear out UART and FIFO */
readb(&ch->ch_cls_uart->txrx);
writeb((UART_FCR_ENABLE_FIFO|UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT),
&ch->ch_cls_uart->isr_fcr);
udelay(10);
ch->ch_flags |= (CH_FIFO_ENABLED | CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
readb(&ch->ch_cls_uart->lsr);
readb(&ch->ch_cls_uart->msr);
}
/*
* Turns off UART.
*/
static void cls_uart_off(struct jsm_channel *ch)
{
/* Stop all interrupts from accurring. */
writeb(0, &ch->ch_cls_uart->ier);
}
/*
* cls_send_break.
* Starts sending a break thru the UART.
*
* The channel lock MUST be held by the calling function.
*/
static void cls_send_break(struct jsm_channel *ch)
{
/* Tell the UART to start sending the break */
if (!(ch->ch_flags & CH_BREAK_SENDING)) {
u8 temp = readb(&ch->ch_cls_uart->lcr);
writeb((temp | UART_LCR_SBC), &ch->ch_cls_uart->lcr);
ch->ch_flags |= (CH_BREAK_SENDING);
}
}
struct board_ops jsm_cls_ops = {
.intr = cls_intr,
.uart_init = cls_uart_init,
.uart_off = cls_uart_off,
.param = cls_param,
.assert_modem_signals = cls_assert_modem_signals,
.flush_uart_write = cls_flush_uart_write,
.flush_uart_read = cls_flush_uart_read,
.disable_receiver = cls_disable_receiver,
.enable_receiver = cls_enable_receiver,
.send_break = cls_send_break,
.clear_break = cls_clear_break,
.send_start_character = cls_send_start_character,
.send_stop_character = cls_send_stop_character,
.copy_data_from_queue_to_uart = cls_copy_data_from_queue_to_uart,
};
@@ -0,0 +1,382 @@
// SPDX-License-Identifier: GPL-2.0+
/************************************************************************
* Copyright 2003 Digi International (www.digi.com)
*
* Copyright (C) 2004 IBM Corporation. All rights reserved.
*
* Contact Information:
* Scott H Kilau <Scott_Kilau@digi.com>
* Wendy Xiong <wendyx@us.ibm.com>
*
*
***********************************************************************/
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include "jsm.h"
MODULE_AUTHOR("Digi International, https://www.digi.com");
MODULE_DESCRIPTION("Driver for the Digi International Neo and Classic PCI based product line");
MODULE_LICENSE("GPL");
#define JSM_DRIVER_NAME "jsm"
#define NR_PORTS 32
#define JSM_MINOR_START 0
struct uart_driver jsm_uart_driver = {
.owner = THIS_MODULE,
.driver_name = JSM_DRIVER_NAME,
.dev_name = "ttyn",
.major = 0,
.minor = JSM_MINOR_START,
.nr = NR_PORTS,
};
static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev,
pci_channel_state_t state);
static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev);
static void jsm_io_resume(struct pci_dev *pdev);
static const struct pci_error_handlers jsm_err_handler = {
.error_detected = jsm_io_error_detected,
.slot_reset = jsm_io_slot_reset,
.resume = jsm_io_resume,
};
int jsm_debug;
module_param(jsm_debug, int, 0);
MODULE_PARM_DESC(jsm_debug, "Driver debugging level");
static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int rc = 0;
struct jsm_board *brd;
static int adapter_count;
rc = pci_enable_device(pdev);
if (rc) {
dev_err(&pdev->dev, "Device enable FAILED\n");
goto out;
}
rc = pci_request_regions(pdev, JSM_DRIVER_NAME);
if (rc) {
dev_err(&pdev->dev, "pci_request_region FAILED\n");
goto out_disable_device;
}
brd = kzalloc_obj(*brd);
if (!brd) {
rc = -ENOMEM;
goto out_release_regions;
}
/* store the info for the board we've found */
brd->boardnum = adapter_count++;
brd->pci_dev = pdev;
switch (pdev->device) {
case PCI_DEVICE_ID_NEO_2DB9:
case PCI_DEVICE_ID_NEO_2DB9PRI:
case PCI_DEVICE_ID_NEO_2RJ45:
case PCI_DEVICE_ID_NEO_2RJ45PRI:
case PCI_DEVICE_ID_NEO_2_422_485:
brd->maxports = 2;
break;
case PCI_DEVICE_ID_CLASSIC_4:
case PCI_DEVICE_ID_CLASSIC_4_422:
case PCI_DEVICE_ID_NEO_4:
case PCIE_DEVICE_ID_NEO_4:
case PCIE_DEVICE_ID_NEO_4RJ45:
case PCIE_DEVICE_ID_NEO_4_IBM:
brd->maxports = 4;
break;
case PCI_DEVICE_ID_CLASSIC_8:
case PCI_DEVICE_ID_CLASSIC_8_422:
case PCI_DEVICE_ID_DIGI_NEO_8:
case PCIE_DEVICE_ID_NEO_8:
case PCIE_DEVICE_ID_NEO_8RJ45:
brd->maxports = 8;
break;
default:
brd->maxports = 1;
break;
}
spin_lock_init(&brd->bd_intr_lock);
/* store which revision we have */
brd->rev = pdev->revision;
brd->irq = pdev->irq;
switch (pdev->device) {
case PCI_DEVICE_ID_CLASSIC_4:
case PCI_DEVICE_ID_CLASSIC_4_422:
case PCI_DEVICE_ID_CLASSIC_8:
case PCI_DEVICE_ID_CLASSIC_8_422:
jsm_dbg(INIT, &brd->pci_dev,
"jsm_found_board - Classic adapter\n");
/*
* For PCI ClassicBoards
* PCI Local Address (.i.e. "resource" number) space
* 0 PLX Memory Mapped Config
* 1 PLX I/O Mapped Config
* 2 I/O Mapped UARTs and Status
* 3 Memory Mapped VPD
* 4 Memory Mapped UARTs and Status
*/
/* Get the PCI Base Address Registers */
brd->membase = pci_resource_start(pdev, 4);
brd->membase_end = pci_resource_end(pdev, 4);
if (brd->membase & 0x1)
brd->membase &= ~0x3;
else
brd->membase &= ~0xF;
brd->iobase = pci_resource_start(pdev, 1);
brd->iobase_end = pci_resource_end(pdev, 1);
brd->iobase = ((unsigned int)(brd->iobase)) & 0xFFFE;
/* Assign the board_ops struct */
brd->bd_ops = &jsm_cls_ops;
brd->bd_uart_offset = 0x8;
brd->bd_dividend = 921600;
brd->re_map_membase = ioremap(brd->membase,
pci_resource_len(pdev, 4));
if (!brd->re_map_membase) {
dev_err(&pdev->dev,
"Card has no PCI Memory resources, failing board.\n");
rc = -ENOMEM;
goto out_kfree_brd;
}
/*
* Enable Local Interrupt 1 (0x1),
* Local Interrupt 1 Polarity Active high (0x2),
* Enable PCI interrupt (0x43)
*/
outb(0x43, brd->iobase + 0x4c);
break;
case PCI_DEVICE_ID_NEO_2DB9:
case PCI_DEVICE_ID_NEO_2DB9PRI:
case PCI_DEVICE_ID_NEO_2RJ45:
case PCI_DEVICE_ID_NEO_2RJ45PRI:
case PCI_DEVICE_ID_NEO_2_422_485:
case PCI_DEVICE_ID_NEO_4:
case PCIE_DEVICE_ID_NEO_4:
case PCIE_DEVICE_ID_NEO_4RJ45:
case PCIE_DEVICE_ID_NEO_4_IBM:
case PCI_DEVICE_ID_DIGI_NEO_8:
case PCIE_DEVICE_ID_NEO_8:
case PCIE_DEVICE_ID_NEO_8RJ45:
jsm_dbg(INIT, &brd->pci_dev, "jsm_found_board - NEO adapter\n");
/* get the PCI Base Address Registers */
brd->membase = pci_resource_start(pdev, 0);
brd->membase_end = pci_resource_end(pdev, 0);
if (brd->membase & 1)
brd->membase &= ~0x3;
else
brd->membase &= ~0xF;
/* Assign the board_ops struct */
brd->bd_ops = &jsm_neo_ops;
brd->bd_uart_offset = 0x200;
brd->bd_dividend = 921600;
brd->re_map_membase = ioremap(brd->membase,
pci_resource_len(pdev, 0));
if (!brd->re_map_membase) {
dev_err(&pdev->dev,
"Card has no PCI Memory resources, failing board.\n");
rc = -ENOMEM;
goto out_kfree_brd;
}
break;
default:
rc = -ENXIO;
goto out_kfree_brd;
}
rc = request_irq(brd->irq, brd->bd_ops->intr, IRQF_SHARED, "JSM", brd);
if (rc) {
dev_warn(&pdev->dev, "Failed to hook IRQ %d\n", brd->irq);
goto out_iounmap;
}
rc = jsm_tty_init(brd);
if (rc < 0) {
dev_err(&pdev->dev, "Can't init tty devices (%d)\n", rc);
rc = -ENXIO;
goto out_free_irq;
}
rc = jsm_uart_port_init(brd);
if (rc < 0) {
/* XXX: leaking all resources from jsm_tty_init here! */
dev_err(&pdev->dev, "Can't init uart port (%d)\n", rc);
rc = -ENXIO;
goto out_free_irq;
}
/* Log the information about the board */
dev_info(&pdev->dev, "board %d: Digi Classic/Neo (rev %d), irq %d\n",
adapter_count, brd->rev, brd->irq);
pci_set_drvdata(pdev, brd);
pci_save_state(pdev);
return 0;
out_free_irq:
jsm_remove_uart_port(brd);
free_irq(brd->irq, brd);
out_iounmap:
iounmap(brd->re_map_membase);
out_kfree_brd:
kfree(brd);
out_release_regions:
pci_release_regions(pdev);
out_disable_device:
pci_disable_device(pdev);
out:
return rc;
}
static void jsm_remove_one(struct pci_dev *pdev)
{
struct jsm_board *brd = pci_get_drvdata(pdev);
int i = 0;
switch (pdev->device) {
case PCI_DEVICE_ID_CLASSIC_4:
case PCI_DEVICE_ID_CLASSIC_4_422:
case PCI_DEVICE_ID_CLASSIC_8:
case PCI_DEVICE_ID_CLASSIC_8_422:
/* Tell card not to interrupt anymore. */
outb(0x0, brd->iobase + 0x4c);
break;
default:
break;
}
jsm_remove_uart_port(brd);
free_irq(brd->irq, brd);
iounmap(brd->re_map_membase);
/* Free all allocated channels structs */
for (i = 0; i < brd->maxports; i++) {
if (brd->channels[i]) {
kfree(brd->channels[i]->ch_rqueue);
kfree(brd->channels[i]->ch_equeue);
kfree(brd->channels[i]);
}
}
pci_release_regions(pdev);
pci_disable_device(pdev);
kfree(brd);
}
static const struct pci_device_id jsm_pci_tbl[] = {
{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_NEO_2DB9) },
{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_NEO_2DB9PRI) },
{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_NEO_2RJ45) },
{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI) },
{ PCI_VDEVICE(DIGI, PCIE_DEVICE_ID_NEO_4_IBM) },
{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_NEO_8) },
{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_NEO_4) },
{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_NEO_1_422) },
{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_NEO_1_422_485) },
{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_NEO_2_422_485) },
{ PCI_VDEVICE(DIGI, PCIE_DEVICE_ID_NEO_8) },
{ PCI_VDEVICE(DIGI, PCIE_DEVICE_ID_NEO_4) },
{ PCI_VDEVICE(DIGI, PCIE_DEVICE_ID_NEO_4RJ45) },
{ PCI_VDEVICE(DIGI, PCIE_DEVICE_ID_NEO_8RJ45) },
{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_CLASSIC_4) },
{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_CLASSIC_4_422) },
{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_CLASSIC_8) },
{ PCI_VDEVICE(DIGI, PCI_DEVICE_ID_CLASSIC_8_422) },
{ }
};
MODULE_DEVICE_TABLE(pci, jsm_pci_tbl);
static struct pci_driver jsm_driver = {
.name = JSM_DRIVER_NAME,
.id_table = jsm_pci_tbl,
.probe = jsm_probe_one,
.remove = jsm_remove_one,
.err_handler = &jsm_err_handler,
};
static pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev,
pci_channel_state_t state)
{
struct jsm_board *brd = pci_get_drvdata(pdev);
jsm_remove_uart_port(brd);
return PCI_ERS_RESULT_NEED_RESET;
}
static pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev)
{
int rc;
rc = pci_enable_device(pdev);
if (rc)
return PCI_ERS_RESULT_DISCONNECT;
pci_set_master(pdev);
return PCI_ERS_RESULT_RECOVERED;
}
static void jsm_io_resume(struct pci_dev *pdev)
{
struct jsm_board *brd = pci_get_drvdata(pdev);
pci_restore_state(pdev);
jsm_uart_port_init(brd);
}
static int __init jsm_init_module(void)
{
int rc;
rc = uart_register_driver(&jsm_uart_driver);
if (!rc) {
rc = pci_register_driver(&jsm_driver);
if (rc)
uart_unregister_driver(&jsm_uart_driver);
}
return rc;
}
static void __exit jsm_exit_module(void)
{
pci_unregister_driver(&jsm_driver);
uart_unregister_driver(&jsm_uart_driver);
}
module_init(jsm_init_module);
module_exit(jsm_exit_module);
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,829 @@
// SPDX-License-Identifier: GPL-2.0+
/************************************************************************
* Copyright 2003 Digi International (www.digi.com)
*
* Copyright (C) 2004 IBM Corporation. All rights reserved.
*
* Contact Information:
* Scott H Kilau <Scott_Kilau@digi.com>
* Ananda Venkatarman <mansarov@us.ibm.com>
* Modifications:
* 01/19/06: changed jsm_input routine to use the dynamically allocated
* tty_buffer changes. Contributors: Scott Kilau and Ananda V.
***********************************************************************/
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_reg.h>
#include <linux/delay.h> /* For udelay */
#include <linux/pci.h>
#include <linux/slab.h>
#include "jsm.h"
static DECLARE_BITMAP(linemap, MAXLINES);
static void jsm_carrier(struct jsm_channel *ch);
static inline int jsm_get_mstat(struct jsm_channel *ch)
{
unsigned char mstat;
int result;
jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, "start\n");
mstat = (ch->ch_mostat | ch->ch_mistat);
result = 0;
if (mstat & UART_MCR_DTR)
result |= TIOCM_DTR;
if (mstat & UART_MCR_RTS)
result |= TIOCM_RTS;
if (mstat & UART_MSR_CTS)
result |= TIOCM_CTS;
if (mstat & UART_MSR_DSR)
result |= TIOCM_DSR;
if (mstat & UART_MSR_RI)
result |= TIOCM_RI;
if (mstat & UART_MSR_DCD)
result |= TIOCM_CD;
jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, "finish\n");
return result;
}
static unsigned int jsm_tty_tx_empty(struct uart_port *port)
{
return TIOCSER_TEMT;
}
/*
* Return modem signals to ld.
*/
static unsigned int jsm_tty_get_mctrl(struct uart_port *port)
{
int result;
struct jsm_channel *channel =
container_of(port, struct jsm_channel, uart_port);
jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
result = jsm_get_mstat(channel);
if (result < 0)
return -ENXIO;
jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n");
return result;
}
/*
* jsm_set_modem_info()
*
* Set modem signals, called by ld.
*/
static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct jsm_channel *channel =
container_of(port, struct jsm_channel, uart_port);
jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
if (mctrl & TIOCM_RTS)
channel->ch_mostat |= UART_MCR_RTS;
else
channel->ch_mostat &= ~UART_MCR_RTS;
if (mctrl & TIOCM_DTR)
channel->ch_mostat |= UART_MCR_DTR;
else
channel->ch_mostat &= ~UART_MCR_DTR;
channel->ch_bd->bd_ops->assert_modem_signals(channel);
jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n");
udelay(10);
}
/*
* jsm_tty_write()
*
* Take data from the user or kernel and send it out to the FEP.
* In here exists all the Transparent Print magic as well.
*/
static void jsm_tty_write(struct uart_port *port)
{
struct jsm_channel *channel;
channel = container_of(port, struct jsm_channel, uart_port);
channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel);
}
static void jsm_tty_start_tx(struct uart_port *port)
{
struct jsm_channel *channel =
container_of(port, struct jsm_channel, uart_port);
jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
channel->ch_flags &= ~(CH_STOP);
jsm_tty_write(port);
jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n");
}
static void jsm_tty_stop_tx(struct uart_port *port)
{
struct jsm_channel *channel =
container_of(port, struct jsm_channel, uart_port);
jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "start\n");
channel->ch_flags |= (CH_STOP);
jsm_dbg(IOCTL, &channel->ch_bd->pci_dev, "finish\n");
}
static void jsm_tty_send_xchar(struct uart_port *port, char ch)
{
unsigned long lock_flags;
struct jsm_channel *channel =
container_of(port, struct jsm_channel, uart_port);
struct ktermios *termios;
uart_port_lock_irqsave(port, &lock_flags);
termios = &port->state->port.tty->termios;
if (ch == termios->c_cc[VSTART])
channel->ch_bd->bd_ops->send_start_character(channel);
if (ch == termios->c_cc[VSTOP])
channel->ch_bd->bd_ops->send_stop_character(channel);
uart_port_unlock_irqrestore(port, lock_flags);
}
static void jsm_tty_stop_rx(struct uart_port *port)
{
struct jsm_channel *channel =
container_of(port, struct jsm_channel, uart_port);
channel->ch_bd->bd_ops->disable_receiver(channel);
}
static void jsm_tty_break(struct uart_port *port, int break_state)
{
unsigned long lock_flags;
struct jsm_channel *channel =
container_of(port, struct jsm_channel, uart_port);
uart_port_lock_irqsave(port, &lock_flags);
if (break_state == -1)
channel->ch_bd->bd_ops->send_break(channel);
else
channel->ch_bd->bd_ops->clear_break(channel);
uart_port_unlock_irqrestore(port, lock_flags);
}
static int jsm_tty_open(struct uart_port *port)
{
unsigned long lock_flags;
struct jsm_board *brd;
struct jsm_channel *channel =
container_of(port, struct jsm_channel, uart_port);
struct ktermios *termios;
/* Get board pointer from our array of majors we have allocated */
brd = channel->ch_bd;
/*
* Allocate channel buffers for read/write/error.
* Set flag, so we don't get trounced on.
*/
channel->ch_flags |= (CH_OPENING);
/* Drop locks, as malloc with GFP_KERNEL can sleep */
if (!channel->ch_rqueue) {
channel->ch_rqueue = kzalloc(RQUEUESIZE, GFP_KERNEL);
if (!channel->ch_rqueue) {
jsm_dbg(INIT, &channel->ch_bd->pci_dev,
"unable to allocate read queue buf\n");
return -ENOMEM;
}
}
if (!channel->ch_equeue) {
channel->ch_equeue = kzalloc(EQUEUESIZE, GFP_KERNEL);
if (!channel->ch_equeue) {
jsm_dbg(INIT, &channel->ch_bd->pci_dev,
"unable to allocate error queue buf\n");
return -ENOMEM;
}
}
channel->ch_flags &= ~(CH_OPENING);
/*
* Initialize if neither terminal is open.
*/
jsm_dbg(OPEN, &channel->ch_bd->pci_dev,
"jsm_open: initializing channel in open...\n");
/*
* Flush input queues.
*/
channel->ch_r_head = channel->ch_r_tail = 0;
channel->ch_e_head = channel->ch_e_tail = 0;
brd->bd_ops->flush_uart_write(channel);
brd->bd_ops->flush_uart_read(channel);
channel->ch_flags = 0;
channel->ch_cached_lsr = 0;
channel->ch_stops_sent = 0;
uart_port_lock_irqsave(port, &lock_flags);
termios = &port->state->port.tty->termios;
channel->ch_c_cflag = termios->c_cflag;
channel->ch_c_iflag = termios->c_iflag;
channel->ch_c_oflag = termios->c_oflag;
channel->ch_c_lflag = termios->c_lflag;
channel->ch_startc = termios->c_cc[VSTART];
channel->ch_stopc = termios->c_cc[VSTOP];
/* Tell UART to init itself */
brd->bd_ops->uart_init(channel);
/*
* Run param in case we changed anything
*/
brd->bd_ops->param(channel);
jsm_carrier(channel);
channel->ch_open_count++;
uart_port_unlock_irqrestore(port, lock_flags);
jsm_dbg(OPEN, &channel->ch_bd->pci_dev, "finish\n");
return 0;
}
static void jsm_tty_close(struct uart_port *port)
{
struct jsm_board *bd;
struct jsm_channel *channel =
container_of(port, struct jsm_channel, uart_port);
jsm_dbg(CLOSE, &channel->ch_bd->pci_dev, "start\n");
bd = channel->ch_bd;
channel->ch_flags &= ~(CH_STOPI);
channel->ch_open_count--;
/*
* If we have HUPCL set, lower DTR and RTS
*/
if (channel->ch_c_cflag & HUPCL) {
jsm_dbg(CLOSE, &channel->ch_bd->pci_dev,
"Close. HUPCL set, dropping DTR/RTS\n");
/* Drop RTS/DTR */
channel->ch_mostat &= ~(UART_MCR_DTR | UART_MCR_RTS);
bd->bd_ops->assert_modem_signals(channel);
}
/* Turn off UART interrupts for this port */
channel->ch_bd->bd_ops->uart_off(channel);
jsm_dbg(CLOSE, &channel->ch_bd->pci_dev, "finish\n");
}
static void jsm_tty_set_termios(struct uart_port *port,
struct ktermios *termios,
const struct ktermios *old_termios)
{
unsigned long lock_flags;
struct jsm_channel *channel =
container_of(port, struct jsm_channel, uart_port);
uart_port_lock_irqsave(port, &lock_flags);
channel->ch_c_cflag = termios->c_cflag;
channel->ch_c_iflag = termios->c_iflag;
channel->ch_c_oflag = termios->c_oflag;
channel->ch_c_lflag = termios->c_lflag;
channel->ch_startc = termios->c_cc[VSTART];
channel->ch_stopc = termios->c_cc[VSTOP];
channel->ch_bd->bd_ops->param(channel);
jsm_carrier(channel);
uart_port_unlock_irqrestore(port, lock_flags);
}
static const char *jsm_tty_type(struct uart_port *port)
{
return "jsm";
}
static void jsm_tty_release_port(struct uart_port *port)
{
}
static int jsm_tty_request_port(struct uart_port *port)
{
return 0;
}
static void jsm_config_port(struct uart_port *port, int flags)
{
port->type = PORT_JSM;
}
static const struct uart_ops jsm_ops = {
.tx_empty = jsm_tty_tx_empty,
.set_mctrl = jsm_tty_set_mctrl,
.get_mctrl = jsm_tty_get_mctrl,
.stop_tx = jsm_tty_stop_tx,
.start_tx = jsm_tty_start_tx,
.send_xchar = jsm_tty_send_xchar,
.stop_rx = jsm_tty_stop_rx,
.break_ctl = jsm_tty_break,
.startup = jsm_tty_open,
.shutdown = jsm_tty_close,
.set_termios = jsm_tty_set_termios,
.type = jsm_tty_type,
.release_port = jsm_tty_release_port,
.request_port = jsm_tty_request_port,
.config_port = jsm_config_port,
};
/*
* jsm_tty_init()
*
* Init the tty subsystem. Called once per board after board has been
* downloaded and init'ed.
*/
int jsm_tty_init(struct jsm_board *brd)
{
int i;
void __iomem *vaddr;
struct jsm_channel *ch;
if (!brd)
return -ENXIO;
jsm_dbg(INIT, &brd->pci_dev, "start\n");
/*
* Initialize board structure elements.
*/
brd->nasync = brd->maxports;
/*
* Allocate channel memory that might not have been allocated
* when the driver was first loaded.
*/
for (i = 0; i < brd->nasync; i++) {
if (!brd->channels[i]) {
/*
* Okay to malloc with GFP_KERNEL, we are not at
* interrupt context, and there are no locks held.
*/
brd->channels[i] = kzalloc_obj(struct jsm_channel);
if (!brd->channels[i]) {
jsm_dbg(CORE, &brd->pci_dev,
"%s:%d Unable to allocate memory for channel struct\n",
__FILE__, __LINE__);
}
}
}
ch = brd->channels[0];
vaddr = brd->re_map_membase;
/* Set up channel variables */
for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
if (!brd->channels[i])
continue;
spin_lock_init(&ch->ch_lock);
if (brd->bd_uart_offset == 0x200)
ch->ch_neo_uart = vaddr + (brd->bd_uart_offset * i);
else
ch->ch_cls_uart = vaddr + (brd->bd_uart_offset * i);
ch->ch_bd = brd;
ch->ch_portnum = i;
/* .25 second delay */
ch->ch_close_delay = 250;
init_waitqueue_head(&ch->ch_flags_wait);
}
jsm_dbg(INIT, &brd->pci_dev, "finish\n");
return 0;
}
int jsm_uart_port_init(struct jsm_board *brd)
{
int i, rc;
unsigned int line;
if (!brd)
return -ENXIO;
jsm_dbg(INIT, &brd->pci_dev, "start\n");
/*
* Initialize board structure elements.
*/
brd->nasync = brd->maxports;
/* Set up channel variables */
for (i = 0; i < brd->nasync; i++) {
if (!brd->channels[i])
continue;
brd->channels[i]->uart_port.dev = &brd->pci_dev->dev;
brd->channels[i]->uart_port.irq = brd->irq;
brd->channels[i]->uart_port.uartclk = 14745600;
brd->channels[i]->uart_port.type = PORT_JSM;
brd->channels[i]->uart_port.iotype = UPIO_MEM;
brd->channels[i]->uart_port.membase = brd->re_map_membase;
brd->channels[i]->uart_port.fifosize = 16;
brd->channels[i]->uart_port.ops = &jsm_ops;
line = find_first_zero_bit(linemap, MAXLINES);
if (line >= MAXLINES) {
printk(KERN_INFO "jsm: linemap is full, added device failed\n");
continue;
} else
set_bit(line, linemap);
brd->channels[i]->uart_port.line = line;
rc = uart_add_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port);
if (rc) {
printk(KERN_INFO "jsm: Port %d failed. Aborting...\n", i);
return rc;
} else
printk(KERN_INFO "jsm: Port %d added\n", i);
}
jsm_dbg(INIT, &brd->pci_dev, "finish\n");
return 0;
}
int jsm_remove_uart_port(struct jsm_board *brd)
{
int i;
struct jsm_channel *ch;
if (!brd)
return -ENXIO;
jsm_dbg(INIT, &brd->pci_dev, "start\n");
/*
* Initialize board structure elements.
*/
brd->nasync = brd->maxports;
/* Set up channel variables */
for (i = 0; i < brd->nasync; i++) {
if (!brd->channels[i])
continue;
ch = brd->channels[i];
clear_bit(ch->uart_port.line, linemap);
uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port);
}
jsm_dbg(INIT, &brd->pci_dev, "finish\n");
return 0;
}
void jsm_input(struct jsm_channel *ch)
{
struct jsm_board *bd;
struct tty_struct *tp;
struct tty_port *port;
u32 rmask;
u16 head;
u16 tail;
int data_len;
unsigned long lock_flags;
int len = 0;
int s = 0;
int i = 0;
jsm_dbg(READ, &ch->ch_bd->pci_dev, "start\n");
port = &ch->uart_port.state->port;
tp = port->tty;
bd = ch->ch_bd;
if (!bd)
return;
spin_lock_irqsave(&ch->ch_lock, lock_flags);
/*
*Figure the number of characters in the buffer.
*Exit immediately if none.
*/
rmask = RQUEUEMASK;
head = ch->ch_r_head & rmask;
tail = ch->ch_r_tail & rmask;
data_len = (head - tail) & rmask;
if (data_len == 0) {
spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
return;
}
jsm_dbg(READ, &ch->ch_bd->pci_dev, "start\n");
/*
*If the device is not open, or CREAD is off, flush
*input data and return immediately.
*/
if (!tp || !C_CREAD(tp)) {
jsm_dbg(READ, &ch->ch_bd->pci_dev,
"input. dropping %d bytes on port %d...\n",
data_len, ch->ch_portnum);
ch->ch_r_head = tail;
/* Force queue flow control to be released, if needed */
jsm_check_queue_flow_control(ch);
spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
return;
}
/*
* If we are throttled, simply don't read any data.
*/
if (ch->ch_flags & CH_STOPI) {
spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
jsm_dbg(READ, &ch->ch_bd->pci_dev,
"Port %d throttled, not reading any data. head: %x tail: %x\n",
ch->ch_portnum, head, tail);
return;
}
jsm_dbg(READ, &ch->ch_bd->pci_dev, "start 2\n");
len = tty_buffer_request_room(port, data_len);
/*
* len now contains the most amount of data we can copy,
* bounded either by the flip buffer size or the amount
* of data the card actually has pending...
*/
while (len) {
s = ((head >= tail) ? head : RQUEUESIZE) - tail;
s = min(s, len);
if (s <= 0)
break;
/*
* If conditions are such that ld needs to see all
* UART errors, we will have to walk each character
* and error byte and send them to the buffer one at
* a time.
*/
if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
for (i = 0; i < s; i++) {
u8 chr = ch->ch_rqueue[tail + i];
u8 error = ch->ch_equeue[tail + i];
char flag = TTY_NORMAL;
/*
* Give the Linux ld the flags in the format it
* likes.
*/
if (error & UART_LSR_BI)
flag = TTY_BREAK;
else if (error & UART_LSR_PE)
flag = TTY_PARITY;
else if (error & UART_LSR_FE)
flag = TTY_FRAME;
tty_insert_flip_char(port, chr, flag);
}
} else {
tty_insert_flip_string(port, ch->ch_rqueue + tail, s);
}
tail += s;
len -= s;
/* Flip queue if needed */
tail &= rmask;
}
ch->ch_r_tail = tail & rmask;
ch->ch_e_tail = tail & rmask;
jsm_check_queue_flow_control(ch);
spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
/* Tell the tty layer its okay to "eat" the data now */
tty_flip_buffer_push(port);
jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, "finish\n");
}
static void jsm_carrier(struct jsm_channel *ch)
{
struct jsm_board *bd;
int virt_carrier = 0;
int phys_carrier = 0;
jsm_dbg(CARR, &ch->ch_bd->pci_dev, "start\n");
bd = ch->ch_bd;
if (!bd)
return;
if (ch->ch_mistat & UART_MSR_DCD) {
jsm_dbg(CARR, &ch->ch_bd->pci_dev, "mistat: %x D_CD: %x\n",
ch->ch_mistat, ch->ch_mistat & UART_MSR_DCD);
phys_carrier = 1;
}
if (ch->ch_c_cflag & CLOCAL)
virt_carrier = 1;
jsm_dbg(CARR, &ch->ch_bd->pci_dev, "DCD: physical: %d virt: %d\n",
phys_carrier, virt_carrier);
/*
* Test for a VIRTUAL carrier transition to HIGH.
*/
if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) {
/*
* When carrier rises, wake any threads waiting
* for carrier in the open routine.
*/
jsm_dbg(CARR, &ch->ch_bd->pci_dev, "carrier: virt DCD rose\n");
if (waitqueue_active(&(ch->ch_flags_wait)))
wake_up_interruptible(&ch->ch_flags_wait);
}
/*
* Test for a PHYSICAL carrier transition to HIGH.
*/
if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) {
/*
* When carrier rises, wake any threads waiting
* for carrier in the open routine.
*/
jsm_dbg(CARR, &ch->ch_bd->pci_dev,
"carrier: physical DCD rose\n");
if (waitqueue_active(&(ch->ch_flags_wait)))
wake_up_interruptible(&ch->ch_flags_wait);
}
/*
* Test for a PHYSICAL transition to low, so long as we aren't
* currently ignoring physical transitions (which is what "virtual
* carrier" indicates).
*
* The transition of the virtual carrier to low really doesn't
* matter... it really only means "ignore carrier state", not
* "make pretend that carrier is there".
*/
if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0)
&& (phys_carrier == 0)) {
/*
* When carrier drops:
*
* Drop carrier on all open units.
*
* Flush queues, waking up any task waiting in the
* line discipline.
*
* Send a hangup to the control terminal.
*
* Enable all select calls.
*/
if (waitqueue_active(&(ch->ch_flags_wait)))
wake_up_interruptible(&ch->ch_flags_wait);
}
/*
* Make sure that our cached values reflect the current reality.
*/
if (virt_carrier == 1)
ch->ch_flags |= CH_FCAR;
else
ch->ch_flags &= ~CH_FCAR;
if (phys_carrier == 1)
ch->ch_flags |= CH_CD;
else
ch->ch_flags &= ~CH_CD;
}
void jsm_check_queue_flow_control(struct jsm_channel *ch)
{
struct board_ops *bd_ops = ch->ch_bd->bd_ops;
int qleft;
/* Store how much space we have left in the queue */
qleft = ch->ch_r_tail - ch->ch_r_head - 1;
if (qleft < 0)
qleft += RQUEUEMASK + 1;
/*
* Check to see if we should enforce flow control on our queue because
* the ld (or user) isn't reading data out of our queue fast enuf.
*
* NOTE: This is done based on what the current flow control of the
* port is set for.
*
* 1) HWFLOW (RTS) - Turn off the UART's Receive interrupt.
* This will cause the UART's FIFO to back up, and force
* the RTS signal to be dropped.
* 2) SWFLOW (IXOFF) - Keep trying to send a stop character to
* the other side, in hopes it will stop sending data to us.
* 3) NONE - Nothing we can do. We will simply drop any extra data
* that gets sent into us when the queue fills up.
*/
if (qleft < 256) {
/* HWFLOW */
if (ch->ch_c_cflag & CRTSCTS) {
if (!(ch->ch_flags & CH_RECEIVER_OFF)) {
bd_ops->disable_receiver(ch);
ch->ch_flags |= (CH_RECEIVER_OFF);
jsm_dbg(READ, &ch->ch_bd->pci_dev,
"Internal queue hit hilevel mark (%d)! Turning off interrupts\n",
qleft);
}
}
/* SWFLOW */
else if (ch->ch_c_iflag & IXOFF) {
if (ch->ch_stops_sent <= MAX_STOPS_SENT) {
bd_ops->send_stop_character(ch);
ch->ch_stops_sent++;
jsm_dbg(READ, &ch->ch_bd->pci_dev,
"Sending stop char! Times sent: %x\n",
ch->ch_stops_sent);
}
}
}
/*
* Check to see if we should unenforce flow control because
* ld (or user) finally read enuf data out of our queue.
*
* NOTE: This is done based on what the current flow control of the
* port is set for.
*
* 1) HWFLOW (RTS) - Turn back on the UART's Receive interrupt.
* This will cause the UART's FIFO to raise RTS back up,
* which will allow the other side to start sending data again.
* 2) SWFLOW (IXOFF) - Send a start character to
* the other side, so it will start sending data to us again.
* 3) NONE - Do nothing. Since we didn't do anything to turn off the
* other side, we don't need to do anything now.
*/
if (qleft > (RQUEUESIZE / 2)) {
/* HWFLOW */
if (ch->ch_c_cflag & CRTSCTS) {
if (ch->ch_flags & CH_RECEIVER_OFF) {
bd_ops->enable_receiver(ch);
ch->ch_flags &= ~(CH_RECEIVER_OFF);
jsm_dbg(READ, &ch->ch_bd->pci_dev,
"Internal queue hit lowlevel mark (%d)! Turning on interrupts\n",
qleft);
}
}
/* SWFLOW */
else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) {
ch->ch_stops_sent = 0;
bd_ops->send_start_character(ch);
jsm_dbg(READ, &ch->ch_bd->pci_dev,
"Sending start char!\n");
}
}
}