M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
#
# Makefile for Jasmine adapter
#
obj-$(CONFIG_SERIAL_JSM) += jsm.o
jsm-objs := jsm_driver.o jsm_neo.o jsm_tty.o
+378
View File
@@ -0,0 +1,378 @@
/************************************************************************
* Copyright 2003 Digi International (www.digi.com)
*
* Copyright (C) 2004 IBM Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 * Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*
* 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_printk(nlevel, klevel, pdev, fmt, args...) \
if ((DBG_##nlevel & jsm_debug)) \
dev_printk(KERN_##klevel, pdev->dev, fmt, ## args)
#define MAXLINES 256
#define MAXPORTS 8
#define MAX_STOPS_SENT 5
/* 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, int);
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);
u32 (*get_uart_bytes_left) (struct jsm_channel *ch);
void (*send_immediate_char) (struct jsm_channel *ch, unsigned char);
};
/*
* Per-board information
*/
struct jsm_board
{
int boardnum; /* Board number: 0-32 */
int type; /* Type of board */
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;
struct list_head jsm_board_entry;
};
/************************************************************************
* 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/Write 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 */
struct neo_uart_struct __iomem *ch_neo_uart; /* Pointer to the "mapped" UART struct */
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 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 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
+279
View File
@@ -0,0 +1,279 @@
/************************************************************************
* Copyright 2003 Digi International (www.digi.com)
*
* Copyright (C) 2004 IBM Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 * Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*
* 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, http://www.digi.com");
MODULE_DESCRIPTION("Driver for the Digi International "
"Neo PCI based product line");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("jsm");
#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 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 __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int rc = 0;
struct jsm_board *brd;
static int adapter_count = 0;
rc = pci_enable_device(pdev);
if (rc) {
dev_err(&pdev->dev, "Device enable FAILED\n");
goto out;
}
rc = pci_request_regions(pdev, "jsm");
if (rc) {
dev_err(&pdev->dev, "pci_request_region FAILED\n");
goto out_disable_device;
}
brd = kzalloc(sizeof(struct jsm_board), GFP_KERNEL);
if (!brd) {
dev_err(&pdev->dev,
"memory allocation for board structure failed\n");
rc = -ENOMEM;
goto out_release_regions;
}
/* store the info for the board we've found */
brd->boardnum = adapter_count++;
brd->pci_dev = pdev;
if (pdev->device == PCIE_DEVICE_ID_NEO_4_IBM)
brd->maxports = 4;
else if (pdev->device == PCI_DEVICE_ID_DIGI_NEO_8)
brd->maxports = 8;
else
brd->maxports = 2;
spin_lock_init(&brd->bd_intr_lock);
/* store which revision we have */
brd->rev = pdev->revision;
brd->irq = pdev->irq;
jsm_printk(INIT, INFO, &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 &= ~3;
else
brd->membase &= ~15;
/* 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;
}
rc = request_irq(brd->irq, brd->bd_ops->intr,
IRQF_SHARED, "JSM", brd);
if (rc) {
printk(KERN_WARNING "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 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 __devexit jsm_remove_one(struct pci_dev *pdev)
{
struct jsm_board *brd = pci_get_drvdata(pdev);
int i = 0;
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 struct pci_device_id jsm_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9), 0, 0, 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9PRI), 0, 0, 1 },
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 },
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI), 0, 0, 3 },
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4_IBM), 0, 0, 4 },
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_NEO_8), 0, 0, 5 },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, jsm_pci_tbl);
static struct pci_driver jsm_driver = {
.name = "jsm",
.id_table = jsm_pci_tbl,
.probe = jsm_probe_one,
.remove = __devexit_p(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);
pci_save_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
+842
View File
@@ -0,0 +1,842 @@
/************************************************************************
* Copyright 2003 Digi International (www.digi.com)
*
* Copyright (C) 2004 IBM Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 * Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*
* 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;
unsigned result;
jsm_printk(IOCTL, INFO, &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_printk(IOCTL, INFO, &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 = (struct jsm_channel *)port;
jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
result = jsm_get_mstat(channel);
if (result < 0)
return -ENXIO;
jsm_printk(IOCTL, INFO, &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 = (struct jsm_channel *)port;
jsm_printk(IOCTL, INFO, &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_printk(IOCTL, INFO, &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 = (struct jsm_channel *)port;
jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
channel->ch_flags &= ~(CH_STOP);
jsm_tty_write(port);
jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");
}
static void jsm_tty_stop_tx(struct uart_port *port)
{
struct jsm_channel *channel = (struct jsm_channel *)port;
jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n");
channel->ch_flags |= (CH_STOP);
jsm_printk(IOCTL, INFO, &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 = (struct jsm_channel *)port;
struct ktermios *termios;
spin_lock_irqsave(&port->lock, 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);
spin_unlock_irqrestore(&port->lock, lock_flags);
}
static void jsm_tty_stop_rx(struct uart_port *port)
{
struct jsm_channel *channel = (struct jsm_channel *)port;
channel->ch_bd->bd_ops->disable_receiver(channel);
}
static void jsm_tty_enable_ms(struct uart_port *port)
{
/* Nothing needed */
}
static void jsm_tty_break(struct uart_port *port, int break_state)
{
unsigned long lock_flags;
struct jsm_channel *channel = (struct jsm_channel *)port;
spin_lock_irqsave(&port->lock, lock_flags);
if (break_state == -1)
channel->ch_bd->bd_ops->send_break(channel);
else
channel->ch_bd->bd_ops->clear_break(channel, 0);
spin_unlock_irqrestore(&port->lock, lock_flags);
}
static int jsm_tty_open(struct uart_port *port)
{
struct jsm_board *brd;
struct jsm_channel *channel = (struct jsm_channel *)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_printk(INIT, ERR, &channel->ch_bd->pci_dev,
"unable to allocate read queue buf");
return -ENOMEM;
}
}
if (!channel->ch_equeue) {
channel->ch_equeue = kzalloc(EQUEUESIZE, GFP_KERNEL);
if (!channel->ch_equeue) {
jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev,
"unable to allocate error queue buf");
return -ENOMEM;
}
}
channel->ch_flags &= ~(CH_OPENING);
/*
* Initialize if neither terminal is open.
*/
jsm_printk(OPEN, INFO, &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;
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++;
jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev, "finish\n");
return 0;
}
static void jsm_tty_close(struct uart_port *port)
{
struct jsm_board *bd;
struct ktermios *ts;
struct jsm_channel *channel = (struct jsm_channel *)port;
jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n");
bd = channel->ch_bd;
ts = port->state->port.tty->termios;
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_printk(CLOSE, INFO, &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_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "finish\n");
}
static void jsm_tty_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old_termios)
{
unsigned long lock_flags;
struct jsm_channel *channel = (struct jsm_channel *)port;
spin_lock_irqsave(&port->lock, 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);
spin_unlock_irqrestore(&port->lock, 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 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,
.enable_ms = jsm_tty_enable_ms,
.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 __devinit jsm_tty_init(struct jsm_board *brd)
{
int i;
void __iomem *vaddr;
struct jsm_channel *ch;
if (!brd)
return -ENXIO;
jsm_printk(INIT, INFO, &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(sizeof(struct jsm_channel), GFP_KERNEL);
if (!brd->channels[i]) {
jsm_printk(CORE, ERR, &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);
ch->ch_bd = brd;
ch->ch_portnum = i;
/* .25 second delay */
ch->ch_close_delay = 250;
init_waitqueue_head(&ch->ch_flags_wait);
}
jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n");
return 0;
}
int jsm_uart_port_init(struct jsm_board *brd)
{
int i, rc;
unsigned int line;
struct jsm_channel *ch;
if (!brd)
return -ENXIO;
jsm_printk(INIT, INFO, &brd->pci_dev, "start\n");
/*
* Initialize board structure elements.
*/
brd->nasync = brd->maxports;
/* Set up channel variables */
for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) {
if (!brd->channels[i])
continue;
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_printk(INIT, INFO, &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_printk(INIT, INFO, &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_printk(INIT, INFO, &brd->pci_dev, "finish\n");
return 0;
}
void jsm_input(struct jsm_channel *ch)
{
struct jsm_board *bd;
struct tty_struct *tp;
u32 rmask;
u16 head;
u16 tail;
int data_len;
unsigned long lock_flags;
int len = 0;
int n = 0;
int s = 0;
int i = 0;
jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n");
if (!ch)
return;
tp = ch->uart_port.state->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_printk(READ, INFO, &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 ||
!(tp->termios->c_cflag & CREAD) ) {
jsm_printk(READ, INFO, &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_printk(READ, INFO, &ch->ch_bd->pci_dev,
"Port %d throttled, not reading any data. head: %x tail: %x\n",
ch->ch_portnum, head, tail);
return;
}
jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start 2\n");
if (data_len <= 0) {
spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n");
return;
}
len = tty_buffer_request_room(tp, data_len);
n = len;
/*
* n 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 (n) {
s = ((head >= tail) ? head : RQUEUESIZE) - tail;
s = min(s, n);
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++) {
/*
* Give the Linux ld the flags in the
* format it likes.
*/
if (*(ch->ch_equeue +tail +i) & UART_LSR_BI)
tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_BREAK);
else if (*(ch->ch_equeue +tail +i) & UART_LSR_PE)
tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_PARITY);
else if (*(ch->ch_equeue +tail +i) & UART_LSR_FE)
tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_FRAME);
else
tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_NORMAL);
}
} else {
tty_insert_flip_string(tp, ch->ch_rqueue + tail, s) ;
}
tail += s;
n -= 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(tp);
jsm_printk(IOCTL, INFO, &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_printk(CARR, INFO, &ch->ch_bd->pci_dev, "start\n");
if (!ch)
return;
bd = ch->ch_bd;
if (!bd)
return;
if (ch->ch_mistat & UART_MSR_DCD) {
jsm_printk(CARR, INFO, &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_printk(CARR, INFO, &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_printk(CARR, INFO, &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_printk(CARR, INFO, &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 */
if ((qleft = ch->ch_r_tail - ch->ch_r_head - 1) < 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_printk(READ, INFO, &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_printk(READ, INFO, &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_printk(READ, INFO, &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_printk(READ, INFO, &ch->ch_bd->pci_dev, "Sending start char!\n");
}
}
}