1e3b3d0f5SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+ 2ab4382d2SGreg Kroah-Hartman /* 3ab4382d2SGreg Kroah-Hartman * icom.c 4ab4382d2SGreg Kroah-Hartman * 5ab4382d2SGreg Kroah-Hartman * Copyright (C) 2001 IBM Corporation. All rights reserved. 6ab4382d2SGreg Kroah-Hartman * 7ab4382d2SGreg Kroah-Hartman * Serial device driver. 8ab4382d2SGreg Kroah-Hartman * 9ab4382d2SGreg Kroah-Hartman * Based on code from serial.c 10ab4382d2SGreg Kroah-Hartman */ 11ab4382d2SGreg Kroah-Hartman #include <linux/module.h> 12ab4382d2SGreg Kroah-Hartman #include <linux/kernel.h> 13ab4382d2SGreg Kroah-Hartman #include <linux/errno.h> 14ab4382d2SGreg Kroah-Hartman #include <linux/signal.h> 15ab4382d2SGreg Kroah-Hartman #include <linux/timer.h> 16ab4382d2SGreg Kroah-Hartman #include <linux/interrupt.h> 17ab4382d2SGreg Kroah-Hartman #include <linux/tty.h> 18ab4382d2SGreg Kroah-Hartman #include <linux/termios.h> 19ab4382d2SGreg Kroah-Hartman #include <linux/fs.h> 20ab4382d2SGreg Kroah-Hartman #include <linux/tty_flip.h> 21ab4382d2SGreg Kroah-Hartman #include <linux/serial.h> 2259a1d562SJiri Slaby #include <linux/serial_core.h> 23ab4382d2SGreg Kroah-Hartman #include <linux/serial_reg.h> 24ab4382d2SGreg Kroah-Hartman #include <linux/major.h> 25ab4382d2SGreg Kroah-Hartman #include <linux/string.h> 26ab4382d2SGreg Kroah-Hartman #include <linux/fcntl.h> 27ab4382d2SGreg Kroah-Hartman #include <linux/ptrace.h> 28ab4382d2SGreg Kroah-Hartman #include <linux/ioport.h> 29ab4382d2SGreg Kroah-Hartman #include <linux/mm.h> 30ab4382d2SGreg Kroah-Hartman #include <linux/slab.h> 31ab4382d2SGreg Kroah-Hartman #include <linux/init.h> 32ab4382d2SGreg Kroah-Hartman #include <linux/delay.h> 33ab4382d2SGreg Kroah-Hartman #include <linux/pci.h> 34ab4382d2SGreg Kroah-Hartman #include <linux/vmalloc.h> 35ab4382d2SGreg Kroah-Hartman #include <linux/smp.h> 36ab4382d2SGreg Kroah-Hartman #include <linux/spinlock.h> 37ab4382d2SGreg Kroah-Hartman #include <linux/kref.h> 38ab4382d2SGreg Kroah-Hartman #include <linux/firmware.h> 39ab4382d2SGreg Kroah-Hartman #include <linux/bitops.h> 40ab4382d2SGreg Kroah-Hartman 410ebee1ebSZihao Tang #include <linux/io.h> 42ab4382d2SGreg Kroah-Hartman #include <asm/irq.h> 437c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 44ab4382d2SGreg Kroah-Hartman 45ab4382d2SGreg Kroah-Hartman /*#define ICOM_TRACE enable port trace capabilities */ 46ab4382d2SGreg Kroah-Hartman 47ab4382d2SGreg Kroah-Hartman #define ICOM_DRIVER_NAME "icom" 48ab4382d2SGreg Kroah-Hartman #define NR_PORTS 128 49ab4382d2SGreg Kroah-Hartman 508b026d63SJiri Slaby static const unsigned int icom_acfg_baud[] = { 5159a1d562SJiri Slaby 300, 5259a1d562SJiri Slaby 600, 5359a1d562SJiri Slaby 900, 5459a1d562SJiri Slaby 1200, 5559a1d562SJiri Slaby 1800, 5659a1d562SJiri Slaby 2400, 5759a1d562SJiri Slaby 3600, 5859a1d562SJiri Slaby 4800, 5959a1d562SJiri Slaby 7200, 6059a1d562SJiri Slaby 9600, 6159a1d562SJiri Slaby 14400, 6259a1d562SJiri Slaby 19200, 6359a1d562SJiri Slaby 28800, 6459a1d562SJiri Slaby 38400, 6559a1d562SJiri Slaby 57600, 6659a1d562SJiri Slaby 76800, 6759a1d562SJiri Slaby 115200, 6859a1d562SJiri Slaby 153600, 6959a1d562SJiri Slaby 230400, 7059a1d562SJiri Slaby 307200, 7159a1d562SJiri Slaby 460800, 7259a1d562SJiri Slaby }; 7305ef2f3dSJiri Slaby #define BAUD_TABLE_LIMIT (ARRAY_SIZE(icom_acfg_baud) - 1) 7459a1d562SJiri Slaby 7559a1d562SJiri Slaby struct icom_regs { 7659a1d562SJiri Slaby u32 control; /* Adapter Control Register */ 7759a1d562SJiri Slaby u32 interrupt; /* Adapter Interrupt Register */ 7859a1d562SJiri Slaby u32 int_mask; /* Adapter Interrupt Mask Reg */ 7959a1d562SJiri Slaby u32 int_pri; /* Adapter Interrupt Priority r */ 8059a1d562SJiri Slaby u32 int_reg_b; /* Adapter non-masked Interrupt */ 8159a1d562SJiri Slaby u32 resvd01; 8259a1d562SJiri Slaby u32 resvd02; 8359a1d562SJiri Slaby u32 resvd03; 8459a1d562SJiri Slaby u32 control_2; /* Adapter Control Register 2 */ 8559a1d562SJiri Slaby u32 interrupt_2; /* Adapter Interrupt Register 2 */ 8659a1d562SJiri Slaby u32 int_mask_2; /* Adapter Interrupt Mask 2 */ 8759a1d562SJiri Slaby u32 int_pri_2; /* Adapter Interrupt Prior 2 */ 8859a1d562SJiri Slaby u32 int_reg_2b; /* Adapter non-masked 2 */ 8959a1d562SJiri Slaby }; 9059a1d562SJiri Slaby 9159a1d562SJiri Slaby struct func_dram { 9259a1d562SJiri Slaby u32 reserved[108]; /* 0-1B0 reserved by personality code */ 9359a1d562SJiri Slaby u32 RcvStatusAddr; /* 1B0-1B3 Status Address for Next rcv */ 9459a1d562SJiri Slaby u8 RcvStnAddr; /* 1B4 Receive Station Addr */ 9559a1d562SJiri Slaby u8 IdleState; /* 1B5 Idle State */ 9659a1d562SJiri Slaby u8 IdleMonitor; /* 1B6 Idle Monitor */ 9759a1d562SJiri Slaby u8 FlagFillIdleTimer; /* 1B7 Flag Fill Idle Timer */ 9859a1d562SJiri Slaby u32 XmitStatusAddr; /* 1B8-1BB Transmit Status Address */ 9959a1d562SJiri Slaby u8 StartXmitCmd; /* 1BC Start Xmit Command */ 10059a1d562SJiri Slaby u8 HDLCConfigReg; /* 1BD Reserved */ 10159a1d562SJiri Slaby u8 CauseCode; /* 1BE Cause code for fatal error */ 10259a1d562SJiri Slaby u8 xchar; /* 1BF High priority send */ 10359a1d562SJiri Slaby u32 reserved3; /* 1C0-1C3 Reserved */ 10459a1d562SJiri Slaby u8 PrevCmdReg; /* 1C4 Reserved */ 10559a1d562SJiri Slaby u8 CmdReg; /* 1C5 Command Register */ 10659a1d562SJiri Slaby u8 async_config2; /* 1C6 Async Config Byte 2 */ 10759a1d562SJiri Slaby u8 async_config3; /* 1C7 Async Config Byte 3 */ 10859a1d562SJiri Slaby u8 dce_resvd[20]; /* 1C8-1DB DCE Rsvd */ 10959a1d562SJiri Slaby u8 dce_resvd21; /* 1DC DCE Rsvd (21st byte */ 11059a1d562SJiri Slaby u8 misc_flags; /* 1DD misc flags */ 11159a1d562SJiri Slaby #define V2_HARDWARE 0x40 11259a1d562SJiri Slaby #define ICOM_HDW_ACTIVE 0x01 11359a1d562SJiri Slaby u8 call_length; /* 1DE Phone #/CFI buff ln */ 11459a1d562SJiri Slaby u8 call_length2; /* 1DF Upper byte (unused) */ 11559a1d562SJiri Slaby u32 call_addr; /* 1E0-1E3 Phn #/CFI buff addr */ 11659a1d562SJiri Slaby u16 timer_value; /* 1E4-1E5 general timer value */ 11759a1d562SJiri Slaby u8 timer_command; /* 1E6 general timer cmd */ 11859a1d562SJiri Slaby u8 dce_command; /* 1E7 dce command reg */ 11959a1d562SJiri Slaby u8 dce_cmd_status; /* 1E8 dce command stat */ 12059a1d562SJiri Slaby u8 x21_r1_ioff; /* 1E9 dce ready counter */ 12159a1d562SJiri Slaby u8 x21_r0_ioff; /* 1EA dce not ready ctr */ 12259a1d562SJiri Slaby u8 x21_ralt_ioff; /* 1EB dce CNR counter */ 12359a1d562SJiri Slaby u8 x21_r1_ion; /* 1EC dce ready I on ctr */ 12459a1d562SJiri Slaby u8 rsvd_ier; /* 1ED Rsvd for IER (if ne */ 12559a1d562SJiri Slaby u8 ier; /* 1EE Interrupt Enable */ 12659a1d562SJiri Slaby u8 isr; /* 1EF Input Signal Reg */ 12759a1d562SJiri Slaby u8 osr; /* 1F0 Output Signal Reg */ 12859a1d562SJiri Slaby u8 reset; /* 1F1 Reset/Reload Reg */ 12959a1d562SJiri Slaby u8 disable; /* 1F2 Disable Reg */ 13059a1d562SJiri Slaby u8 sync; /* 1F3 Sync Reg */ 13159a1d562SJiri Slaby u8 error_stat; /* 1F4 Error Status */ 13259a1d562SJiri Slaby u8 cable_id; /* 1F5 Cable ID */ 13359a1d562SJiri Slaby u8 cs_length; /* 1F6 CS Load Length */ 13459a1d562SJiri Slaby u8 mac_length; /* 1F7 Mac Load Length */ 13559a1d562SJiri Slaby u32 cs_load_addr; /* 1F8-1FB Call Load PCI Addr */ 13659a1d562SJiri Slaby u32 mac_load_addr; /* 1FC-1FF Mac Load PCI Addr */ 13759a1d562SJiri Slaby }; 13859a1d562SJiri Slaby 13959a1d562SJiri Slaby /* 14059a1d562SJiri Slaby * adapter defines and structures 14159a1d562SJiri Slaby */ 14259a1d562SJiri Slaby #define ICOM_CONTROL_START_A 0x00000008 14359a1d562SJiri Slaby #define ICOM_CONTROL_STOP_A 0x00000004 14459a1d562SJiri Slaby #define ICOM_CONTROL_START_B 0x00000002 14559a1d562SJiri Slaby #define ICOM_CONTROL_STOP_B 0x00000001 14659a1d562SJiri Slaby #define ICOM_CONTROL_START_C 0x00000008 14759a1d562SJiri Slaby #define ICOM_CONTROL_STOP_C 0x00000004 14859a1d562SJiri Slaby #define ICOM_CONTROL_START_D 0x00000002 14959a1d562SJiri Slaby #define ICOM_CONTROL_STOP_D 0x00000001 15059a1d562SJiri Slaby #define ICOM_IRAM_OFFSET 0x1000 15159a1d562SJiri Slaby #define ICOM_IRAM_SIZE 0x0C00 15259a1d562SJiri Slaby #define ICOM_DCE_IRAM_OFFSET 0x0A00 15359a1d562SJiri Slaby #define ICOM_CABLE_ID_VALID 0x01 15459a1d562SJiri Slaby #define ICOM_CABLE_ID_MASK 0xF0 15559a1d562SJiri Slaby #define ICOM_DISABLE 0x80 15659a1d562SJiri Slaby #define CMD_XMIT_RCV_ENABLE 0xC0 15759a1d562SJiri Slaby #define CMD_XMIT_ENABLE 0x40 15859a1d562SJiri Slaby #define CMD_RCV_DISABLE 0x00 15959a1d562SJiri Slaby #define CMD_RCV_ENABLE 0x80 16059a1d562SJiri Slaby #define CMD_RESTART 0x01 16159a1d562SJiri Slaby #define CMD_HOLD_XMIT 0x02 16259a1d562SJiri Slaby #define CMD_SND_BREAK 0x04 16359a1d562SJiri Slaby #define RS232_CABLE 0x06 16459a1d562SJiri Slaby #define V24_CABLE 0x0E 16559a1d562SJiri Slaby #define V35_CABLE 0x0C 16659a1d562SJiri Slaby #define V36_CABLE 0x02 16759a1d562SJiri Slaby #define NO_CABLE 0x00 16859a1d562SJiri Slaby #define START_DOWNLOAD 0x80 16959a1d562SJiri Slaby #define ICOM_INT_MASK_PRC_A 0x00003FFF 17059a1d562SJiri Slaby #define ICOM_INT_MASK_PRC_B 0x3FFF0000 17159a1d562SJiri Slaby #define ICOM_INT_MASK_PRC_C 0x00003FFF 17259a1d562SJiri Slaby #define ICOM_INT_MASK_PRC_D 0x3FFF0000 17359a1d562SJiri Slaby #define INT_RCV_COMPLETED 0x1000 17459a1d562SJiri Slaby #define INT_XMIT_COMPLETED 0x2000 17559a1d562SJiri Slaby #define INT_IDLE_DETECT 0x0800 17659a1d562SJiri Slaby #define INT_RCV_DISABLED 0x0400 17759a1d562SJiri Slaby #define INT_XMIT_DISABLED 0x0200 17859a1d562SJiri Slaby #define INT_RCV_XMIT_SHUTDOWN 0x0100 17959a1d562SJiri Slaby #define INT_FATAL_ERROR 0x0080 18059a1d562SJiri Slaby #define INT_CABLE_PULL 0x0020 18159a1d562SJiri Slaby #define INT_SIGNAL_CHANGE 0x0010 18259a1d562SJiri Slaby #define HDLC_PPP_PURE_ASYNC 0x02 18359a1d562SJiri Slaby #define HDLC_FF_FILL 0x00 18459a1d562SJiri Slaby #define HDLC_HDW_FLOW 0x01 18559a1d562SJiri Slaby #define START_XMIT 0x80 18659a1d562SJiri Slaby #define ICOM_ACFG_DRIVE1 0x20 18759a1d562SJiri Slaby #define ICOM_ACFG_NO_PARITY 0x00 18859a1d562SJiri Slaby #define ICOM_ACFG_PARITY_ENAB 0x02 18959a1d562SJiri Slaby #define ICOM_ACFG_PARITY_ODD 0x01 19059a1d562SJiri Slaby #define ICOM_ACFG_8BPC 0x00 19159a1d562SJiri Slaby #define ICOM_ACFG_7BPC 0x04 19259a1d562SJiri Slaby #define ICOM_ACFG_6BPC 0x08 19359a1d562SJiri Slaby #define ICOM_ACFG_5BPC 0x0C 19459a1d562SJiri Slaby #define ICOM_ACFG_1STOP_BIT 0x00 19559a1d562SJiri Slaby #define ICOM_ACFG_2STOP_BIT 0x10 19659a1d562SJiri Slaby #define ICOM_DTR 0x80 19759a1d562SJiri Slaby #define ICOM_RTS 0x40 19859a1d562SJiri Slaby #define ICOM_RI 0x08 19959a1d562SJiri Slaby #define ICOM_DSR 0x80 20059a1d562SJiri Slaby #define ICOM_DCD 0x20 20159a1d562SJiri Slaby #define ICOM_CTS 0x40 20259a1d562SJiri Slaby 20359a1d562SJiri Slaby #define NUM_XBUFFS 1 20459a1d562SJiri Slaby #define NUM_RBUFFS 2 20559a1d562SJiri Slaby #define RCV_BUFF_SZ 0x0200 20659a1d562SJiri Slaby #define XMIT_BUFF_SZ 0x1000 20759a1d562SJiri Slaby struct statusArea { 20859a1d562SJiri Slaby /**********************************************/ 20959a1d562SJiri Slaby /* Transmit Status Area */ 21059a1d562SJiri Slaby /**********************************************/ 21159a1d562SJiri Slaby struct xmit_status_area{ 21259a1d562SJiri Slaby __le32 leNext; /* Next entry in Little Endian on Adapter */ 21359a1d562SJiri Slaby __le32 leNextASD; 21459a1d562SJiri Slaby __le32 leBuffer; /* Buffer for entry in LE for Adapter */ 21559a1d562SJiri Slaby __le16 leLengthASD; 21659a1d562SJiri Slaby __le16 leOffsetASD; 21759a1d562SJiri Slaby __le16 leLength; /* Length of data in segment */ 21859a1d562SJiri Slaby __le16 flags; 21959a1d562SJiri Slaby #define SA_FLAGS_DONE 0x0080 /* Done with Segment */ 22059a1d562SJiri Slaby #define SA_FLAGS_CONTINUED 0x8000 /* More Segments */ 22159a1d562SJiri Slaby #define SA_FLAGS_IDLE 0x4000 /* Mark IDLE after frm */ 22259a1d562SJiri Slaby #define SA_FLAGS_READY_TO_XMIT 0x0800 22359a1d562SJiri Slaby #define SA_FLAGS_STAT_MASK 0x007F 22459a1d562SJiri Slaby } xmit[NUM_XBUFFS]; 22559a1d562SJiri Slaby 22659a1d562SJiri Slaby /**********************************************/ 22759a1d562SJiri Slaby /* Receive Status Area */ 22859a1d562SJiri Slaby /**********************************************/ 22959a1d562SJiri Slaby struct { 23059a1d562SJiri Slaby __le32 leNext; /* Next entry in Little Endian on Adapter */ 23159a1d562SJiri Slaby __le32 leNextASD; 23259a1d562SJiri Slaby __le32 leBuffer; /* Buffer for entry in LE for Adapter */ 23359a1d562SJiri Slaby __le16 WorkingLength; /* size of segment */ 23459a1d562SJiri Slaby __le16 reserv01; 23559a1d562SJiri Slaby __le16 leLength; /* Length of data in segment */ 23659a1d562SJiri Slaby __le16 flags; 23759a1d562SJiri Slaby #define SA_FL_RCV_DONE 0x0010 /* Data ready */ 23859a1d562SJiri Slaby #define SA_FLAGS_OVERRUN 0x0040 23959a1d562SJiri Slaby #define SA_FLAGS_PARITY_ERROR 0x0080 24059a1d562SJiri Slaby #define SA_FLAGS_FRAME_ERROR 0x0001 24159a1d562SJiri Slaby #define SA_FLAGS_FRAME_TRUNC 0x0002 24259a1d562SJiri Slaby #define SA_FLAGS_BREAK_DET 0x0004 /* set conditionally by device driver, not hardware */ 24359a1d562SJiri Slaby #define SA_FLAGS_RCV_MASK 0xFFE6 24459a1d562SJiri Slaby } rcv[NUM_RBUFFS]; 24559a1d562SJiri Slaby }; 24659a1d562SJiri Slaby 24759a1d562SJiri Slaby struct icom_adapter; 24859a1d562SJiri Slaby 24959a1d562SJiri Slaby 25059a1d562SJiri Slaby #define ICOM_MAJOR 243 25159a1d562SJiri Slaby #define ICOM_MINOR_START 0 25259a1d562SJiri Slaby 25359a1d562SJiri Slaby struct icom_port { 25459a1d562SJiri Slaby struct uart_port uart_port; 25559a1d562SJiri Slaby unsigned char cable_id; 25659a1d562SJiri Slaby unsigned char read_status_mask; 25759a1d562SJiri Slaby unsigned char ignore_status_mask; 25859a1d562SJiri Slaby void __iomem * int_reg; 25959a1d562SJiri Slaby struct icom_regs __iomem *global_reg; 26059a1d562SJiri Slaby struct func_dram __iomem *dram; 26159a1d562SJiri Slaby int port; 26259a1d562SJiri Slaby struct statusArea *statStg; 26359a1d562SJiri Slaby dma_addr_t statStg_pci; 26459a1d562SJiri Slaby __le32 *xmitRestart; 26559a1d562SJiri Slaby dma_addr_t xmitRestart_pci; 26659a1d562SJiri Slaby unsigned char *xmit_buf; 26759a1d562SJiri Slaby dma_addr_t xmit_buf_pci; 26859a1d562SJiri Slaby unsigned char *recv_buf; 26959a1d562SJiri Slaby dma_addr_t recv_buf_pci; 27059a1d562SJiri Slaby int next_rcv; 27159a1d562SJiri Slaby int status; 27259a1d562SJiri Slaby #define ICOM_PORT_ACTIVE 1 /* Port exists. */ 27359a1d562SJiri Slaby #define ICOM_PORT_OFF 0 /* Port does not exist. */ 27459a1d562SJiri Slaby struct icom_adapter *adapter; 27559a1d562SJiri Slaby }; 27659a1d562SJiri Slaby 27759a1d562SJiri Slaby struct icom_adapter { 27859a1d562SJiri Slaby void __iomem * base_addr; 27959a1d562SJiri Slaby unsigned long base_addr_pci; 28059a1d562SJiri Slaby struct pci_dev *pci_dev; 28159a1d562SJiri Slaby struct icom_port port_info[4]; 28259a1d562SJiri Slaby int index; 28359a1d562SJiri Slaby int version; 28459a1d562SJiri Slaby #define ADAPTER_V1 0x0001 28559a1d562SJiri Slaby #define ADAPTER_V2 0x0002 28659a1d562SJiri Slaby u32 subsystem_id; 28759a1d562SJiri Slaby #define FOUR_PORT_MODEL 0x0252 28859a1d562SJiri Slaby #define V2_TWO_PORTS_RVX 0x021A 28959a1d562SJiri Slaby #define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM 0x0251 29059a1d562SJiri Slaby int numb_ports; 29159a1d562SJiri Slaby struct list_head icom_adapter_entry; 29259a1d562SJiri Slaby struct kref kref; 29359a1d562SJiri Slaby }; 29459a1d562SJiri Slaby 29559a1d562SJiri Slaby /* prototype */ 29659a1d562SJiri Slaby extern void iCom_sercons_init(void); 29759a1d562SJiri Slaby 29859a1d562SJiri Slaby struct lookup_proc_table { 29959a1d562SJiri Slaby u32 __iomem *global_control_reg; 30059a1d562SJiri Slaby unsigned long processor_id; 30159a1d562SJiri Slaby }; 30259a1d562SJiri Slaby 30359a1d562SJiri Slaby struct lookup_int_table { 30459a1d562SJiri Slaby u32 __iomem *global_int_mask; 30559a1d562SJiri Slaby unsigned long processor_id; 30659a1d562SJiri Slaby }; 30759a1d562SJiri Slaby 308f73989f5SJiri Slaby static inline struct icom_port *to_icom_port(struct uart_port *port) 309f73989f5SJiri Slaby { 310f73989f5SJiri Slaby return container_of(port, struct icom_port, uart_port); 311f73989f5SJiri Slaby } 312f73989f5SJiri Slaby 313ab4382d2SGreg Kroah-Hartman static const struct pci_device_id icom_pci_table[] = { 314ab4382d2SGreg Kroah-Hartman { 315ab4382d2SGreg Kroah-Hartman .vendor = PCI_VENDOR_ID_IBM, 316ab4382d2SGreg Kroah-Hartman .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1, 317ab4382d2SGreg Kroah-Hartman .subvendor = PCI_ANY_ID, 318ab4382d2SGreg Kroah-Hartman .subdevice = PCI_ANY_ID, 319ab4382d2SGreg Kroah-Hartman .driver_data = ADAPTER_V1, 320ab4382d2SGreg Kroah-Hartman }, 321ab4382d2SGreg Kroah-Hartman { 322ab4382d2SGreg Kroah-Hartman .vendor = PCI_VENDOR_ID_IBM, 323ab4382d2SGreg Kroah-Hartman .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, 324ab4382d2SGreg Kroah-Hartman .subvendor = PCI_VENDOR_ID_IBM, 325ab4382d2SGreg Kroah-Hartman .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX, 326ab4382d2SGreg Kroah-Hartman .driver_data = ADAPTER_V2, 327ab4382d2SGreg Kroah-Hartman }, 328ab4382d2SGreg Kroah-Hartman { 329ab4382d2SGreg Kroah-Hartman .vendor = PCI_VENDOR_ID_IBM, 330ab4382d2SGreg Kroah-Hartman .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, 331ab4382d2SGreg Kroah-Hartman .subvendor = PCI_VENDOR_ID_IBM, 332ab4382d2SGreg Kroah-Hartman .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM, 333ab4382d2SGreg Kroah-Hartman .driver_data = ADAPTER_V2, 334ab4382d2SGreg Kroah-Hartman }, 335ab4382d2SGreg Kroah-Hartman { 336ab4382d2SGreg Kroah-Hartman .vendor = PCI_VENDOR_ID_IBM, 337ab4382d2SGreg Kroah-Hartman .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, 338ab4382d2SGreg Kroah-Hartman .subvendor = PCI_VENDOR_ID_IBM, 339ab4382d2SGreg Kroah-Hartman .subdevice = PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL, 340ab4382d2SGreg Kroah-Hartman .driver_data = ADAPTER_V2, 341ab4382d2SGreg Kroah-Hartman }, 342ab4382d2SGreg Kroah-Hartman { 343ab4382d2SGreg Kroah-Hartman .vendor = PCI_VENDOR_ID_IBM, 344ab4382d2SGreg Kroah-Hartman .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2, 345ab4382d2SGreg Kroah-Hartman .subvendor = PCI_VENDOR_ID_IBM, 346ab4382d2SGreg Kroah-Hartman .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM_PCIE, 347ab4382d2SGreg Kroah-Hartman .driver_data = ADAPTER_V2, 348ab4382d2SGreg Kroah-Hartman }, 349ab4382d2SGreg Kroah-Hartman {} 350ab4382d2SGreg Kroah-Hartman }; 351ab4382d2SGreg Kroah-Hartman 3525a7daed8SJingoo Han static struct lookup_proc_table start_proc[4] = { 353ab4382d2SGreg Kroah-Hartman {NULL, ICOM_CONTROL_START_A}, 354ab4382d2SGreg Kroah-Hartman {NULL, ICOM_CONTROL_START_B}, 355ab4382d2SGreg Kroah-Hartman {NULL, ICOM_CONTROL_START_C}, 356ab4382d2SGreg Kroah-Hartman {NULL, ICOM_CONTROL_START_D} 357ab4382d2SGreg Kroah-Hartman }; 358ab4382d2SGreg Kroah-Hartman 359ab4382d2SGreg Kroah-Hartman 3605a7daed8SJingoo Han static struct lookup_proc_table stop_proc[4] = { 361ab4382d2SGreg Kroah-Hartman {NULL, ICOM_CONTROL_STOP_A}, 362ab4382d2SGreg Kroah-Hartman {NULL, ICOM_CONTROL_STOP_B}, 363ab4382d2SGreg Kroah-Hartman {NULL, ICOM_CONTROL_STOP_C}, 364ab4382d2SGreg Kroah-Hartman {NULL, ICOM_CONTROL_STOP_D} 365ab4382d2SGreg Kroah-Hartman }; 366ab4382d2SGreg Kroah-Hartman 3675a7daed8SJingoo Han static struct lookup_int_table int_mask_tbl[4] = { 368ab4382d2SGreg Kroah-Hartman {NULL, ICOM_INT_MASK_PRC_A}, 369ab4382d2SGreg Kroah-Hartman {NULL, ICOM_INT_MASK_PRC_B}, 370ab4382d2SGreg Kroah-Hartman {NULL, ICOM_INT_MASK_PRC_C}, 371ab4382d2SGreg Kroah-Hartman {NULL, ICOM_INT_MASK_PRC_D}, 372ab4382d2SGreg Kroah-Hartman }; 373ab4382d2SGreg Kroah-Hartman 374ab4382d2SGreg Kroah-Hartman 375ab4382d2SGreg Kroah-Hartman MODULE_DEVICE_TABLE(pci, icom_pci_table); 376ab4382d2SGreg Kroah-Hartman 377ab4382d2SGreg Kroah-Hartman static LIST_HEAD(icom_adapter_head); 378ab4382d2SGreg Kroah-Hartman 379ab4382d2SGreg Kroah-Hartman /* spinlock for adapter initialization and changing adapter operations */ 38001493ccbSZheng Yongjun static DEFINE_SPINLOCK(icom_lock); 381ab4382d2SGreg Kroah-Hartman 382ab4382d2SGreg Kroah-Hartman #ifdef ICOM_TRACE 383ab4382d2SGreg Kroah-Hartman static inline void trace(struct icom_port *icom_port, char *trace_pt, 384ab4382d2SGreg Kroah-Hartman unsigned long trace_data) 385ab4382d2SGreg Kroah-Hartman { 386ab4382d2SGreg Kroah-Hartman dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n", 387ab4382d2SGreg Kroah-Hartman icom_port->port, trace_pt, trace_data); 388ab4382d2SGreg Kroah-Hartman } 389ab4382d2SGreg Kroah-Hartman #else 390ab4382d2SGreg Kroah-Hartman static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {}; 391ab4382d2SGreg Kroah-Hartman #endif 392ab4382d2SGreg Kroah-Hartman static void icom_kref_release(struct kref *kref); 393ab4382d2SGreg Kroah-Hartman 394ab4382d2SGreg Kroah-Hartman static void free_port_memory(struct icom_port *icom_port) 395ab4382d2SGreg Kroah-Hartman { 396ab4382d2SGreg Kroah-Hartman struct pci_dev *dev = icom_port->adapter->pci_dev; 397ab4382d2SGreg Kroah-Hartman 398ab4382d2SGreg Kroah-Hartman trace(icom_port, "RET_PORT_MEM", 0); 399ab4382d2SGreg Kroah-Hartman if (icom_port->recv_buf) { 400c3647f2fSChristophe JAILLET dma_free_coherent(&dev->dev, 4096, icom_port->recv_buf, 401ab4382d2SGreg Kroah-Hartman icom_port->recv_buf_pci); 402ab4382d2SGreg Kroah-Hartman icom_port->recv_buf = NULL; 403ab4382d2SGreg Kroah-Hartman } 404ab4382d2SGreg Kroah-Hartman if (icom_port->xmit_buf) { 405c3647f2fSChristophe JAILLET dma_free_coherent(&dev->dev, 4096, icom_port->xmit_buf, 406ab4382d2SGreg Kroah-Hartman icom_port->xmit_buf_pci); 407ab4382d2SGreg Kroah-Hartman icom_port->xmit_buf = NULL; 408ab4382d2SGreg Kroah-Hartman } 409ab4382d2SGreg Kroah-Hartman if (icom_port->statStg) { 410c3647f2fSChristophe JAILLET dma_free_coherent(&dev->dev, 4096, icom_port->statStg, 411ab4382d2SGreg Kroah-Hartman icom_port->statStg_pci); 412ab4382d2SGreg Kroah-Hartman icom_port->statStg = NULL; 413ab4382d2SGreg Kroah-Hartman } 414ab4382d2SGreg Kroah-Hartman 415ab4382d2SGreg Kroah-Hartman if (icom_port->xmitRestart) { 416c3647f2fSChristophe JAILLET dma_free_coherent(&dev->dev, 4096, icom_port->xmitRestart, 417ab4382d2SGreg Kroah-Hartman icom_port->xmitRestart_pci); 418ab4382d2SGreg Kroah-Hartman icom_port->xmitRestart = NULL; 419ab4382d2SGreg Kroah-Hartman } 420ab4382d2SGreg Kroah-Hartman } 421ab4382d2SGreg Kroah-Hartman 4229671f099SBill Pemberton static int get_port_memory(struct icom_port *icom_port) 423ab4382d2SGreg Kroah-Hartman { 424ab4382d2SGreg Kroah-Hartman int index; 425ab4382d2SGreg Kroah-Hartman unsigned long stgAddr; 426ab4382d2SGreg Kroah-Hartman unsigned long startStgAddr; 427ab4382d2SGreg Kroah-Hartman unsigned long offset; 428ab4382d2SGreg Kroah-Hartman struct pci_dev *dev = icom_port->adapter->pci_dev; 429ab4382d2SGreg Kroah-Hartman 430ab4382d2SGreg Kroah-Hartman icom_port->xmit_buf = 431c3647f2fSChristophe JAILLET dma_alloc_coherent(&dev->dev, 4096, &icom_port->xmit_buf_pci, 432c3647f2fSChristophe JAILLET GFP_KERNEL); 433ab4382d2SGreg Kroah-Hartman if (!icom_port->xmit_buf) { 434ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "Can not allocate Transmit buffer\n"); 435ab4382d2SGreg Kroah-Hartman return -ENOMEM; 436ab4382d2SGreg Kroah-Hartman } 437ab4382d2SGreg Kroah-Hartman 438ab4382d2SGreg Kroah-Hartman trace(icom_port, "GET_PORT_MEM", 439ab4382d2SGreg Kroah-Hartman (unsigned long) icom_port->xmit_buf); 440ab4382d2SGreg Kroah-Hartman 441ab4382d2SGreg Kroah-Hartman icom_port->recv_buf = 442c3647f2fSChristophe JAILLET dma_alloc_coherent(&dev->dev, 4096, &icom_port->recv_buf_pci, 443c3647f2fSChristophe JAILLET GFP_KERNEL); 444ab4382d2SGreg Kroah-Hartman if (!icom_port->recv_buf) { 445ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "Can not allocate Receive buffer\n"); 446ab4382d2SGreg Kroah-Hartman free_port_memory(icom_port); 447ab4382d2SGreg Kroah-Hartman return -ENOMEM; 448ab4382d2SGreg Kroah-Hartman } 449ab4382d2SGreg Kroah-Hartman trace(icom_port, "GET_PORT_MEM", 450ab4382d2SGreg Kroah-Hartman (unsigned long) icom_port->recv_buf); 451ab4382d2SGreg Kroah-Hartman 452ab4382d2SGreg Kroah-Hartman icom_port->statStg = 453c3647f2fSChristophe JAILLET dma_alloc_coherent(&dev->dev, 4096, &icom_port->statStg_pci, 454c3647f2fSChristophe JAILLET GFP_KERNEL); 455ab4382d2SGreg Kroah-Hartman if (!icom_port->statStg) { 456ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "Can not allocate Status buffer\n"); 457ab4382d2SGreg Kroah-Hartman free_port_memory(icom_port); 458ab4382d2SGreg Kroah-Hartman return -ENOMEM; 459ab4382d2SGreg Kroah-Hartman } 460ab4382d2SGreg Kroah-Hartman trace(icom_port, "GET_PORT_MEM", 461ab4382d2SGreg Kroah-Hartman (unsigned long) icom_port->statStg); 462ab4382d2SGreg Kroah-Hartman 463ab4382d2SGreg Kroah-Hartman icom_port->xmitRestart = 464c3647f2fSChristophe JAILLET dma_alloc_coherent(&dev->dev, 4096, &icom_port->xmitRestart_pci, 465c3647f2fSChristophe JAILLET GFP_KERNEL); 466ab4382d2SGreg Kroah-Hartman if (!icom_port->xmitRestart) { 467ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, 468ab4382d2SGreg Kroah-Hartman "Can not allocate xmit Restart buffer\n"); 469ab4382d2SGreg Kroah-Hartman free_port_memory(icom_port); 470ab4382d2SGreg Kroah-Hartman return -ENOMEM; 471ab4382d2SGreg Kroah-Hartman } 472ab4382d2SGreg Kroah-Hartman 473ab4382d2SGreg Kroah-Hartman /* FODs: Frame Out Descriptor Queue, this is a FIFO queue that 474ab4382d2SGreg Kroah-Hartman indicates that frames are to be transmitted 475ab4382d2SGreg Kroah-Hartman */ 476ab4382d2SGreg Kroah-Hartman 477ab4382d2SGreg Kroah-Hartman stgAddr = (unsigned long) icom_port->statStg; 478ab4382d2SGreg Kroah-Hartman for (index = 0; index < NUM_XBUFFS; index++) { 479ab4382d2SGreg Kroah-Hartman trace(icom_port, "FOD_ADDR", stgAddr); 480ab4382d2SGreg Kroah-Hartman stgAddr = stgAddr + sizeof(icom_port->statStg->xmit[0]); 481ab4382d2SGreg Kroah-Hartman if (index < (NUM_XBUFFS - 1)) { 482ab4382d2SGreg Kroah-Hartman memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area)); 483ab4382d2SGreg Kroah-Hartman icom_port->statStg->xmit[index].leLengthASD = 4847a5f86e8SJiri Slaby cpu_to_le16(XMIT_BUFF_SZ); 485ab4382d2SGreg Kroah-Hartman trace(icom_port, "FOD_ADDR", stgAddr); 486ab4382d2SGreg Kroah-Hartman trace(icom_port, "FOD_XBUFF", 487ab4382d2SGreg Kroah-Hartman (unsigned long) icom_port->xmit_buf); 488ab4382d2SGreg Kroah-Hartman icom_port->statStg->xmit[index].leBuffer = 489ab4382d2SGreg Kroah-Hartman cpu_to_le32(icom_port->xmit_buf_pci); 490ab4382d2SGreg Kroah-Hartman } else if (index == (NUM_XBUFFS - 1)) { 491ab4382d2SGreg Kroah-Hartman memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area)); 492ab4382d2SGreg Kroah-Hartman icom_port->statStg->xmit[index].leLengthASD = 4937a5f86e8SJiri Slaby cpu_to_le16(XMIT_BUFF_SZ); 494ab4382d2SGreg Kroah-Hartman trace(icom_port, "FOD_XBUFF", 495ab4382d2SGreg Kroah-Hartman (unsigned long) icom_port->xmit_buf); 496ab4382d2SGreg Kroah-Hartman icom_port->statStg->xmit[index].leBuffer = 497ab4382d2SGreg Kroah-Hartman cpu_to_le32(icom_port->xmit_buf_pci); 498ab4382d2SGreg Kroah-Hartman } else { 499ab4382d2SGreg Kroah-Hartman memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area)); 500ab4382d2SGreg Kroah-Hartman } 501ab4382d2SGreg Kroah-Hartman } 502ab4382d2SGreg Kroah-Hartman /* FIDs */ 503ab4382d2SGreg Kroah-Hartman startStgAddr = stgAddr; 504ab4382d2SGreg Kroah-Hartman 505ab4382d2SGreg Kroah-Hartman /* fill in every entry, even if no buffer */ 506ab4382d2SGreg Kroah-Hartman for (index = 0; index < NUM_RBUFFS; index++) { 507ab4382d2SGreg Kroah-Hartman trace(icom_port, "FID_ADDR", stgAddr); 508ab4382d2SGreg Kroah-Hartman stgAddr = stgAddr + sizeof(icom_port->statStg->rcv[0]); 509ab4382d2SGreg Kroah-Hartman icom_port->statStg->rcv[index].leLength = 0; 510ab4382d2SGreg Kroah-Hartman icom_port->statStg->rcv[index].WorkingLength = 5117a5f86e8SJiri Slaby cpu_to_le16(RCV_BUFF_SZ); 512ab4382d2SGreg Kroah-Hartman if (index < (NUM_RBUFFS - 1) ) { 513ab4382d2SGreg Kroah-Hartman offset = stgAddr - (unsigned long) icom_port->statStg; 514ab4382d2SGreg Kroah-Hartman icom_port->statStg->rcv[index].leNext = 515ab4382d2SGreg Kroah-Hartman cpu_to_le32(icom_port-> statStg_pci + offset); 516ab4382d2SGreg Kroah-Hartman trace(icom_port, "FID_RBUFF", 517ab4382d2SGreg Kroah-Hartman (unsigned long) icom_port->recv_buf); 518ab4382d2SGreg Kroah-Hartman icom_port->statStg->rcv[index].leBuffer = 519ab4382d2SGreg Kroah-Hartman cpu_to_le32(icom_port->recv_buf_pci); 520ab4382d2SGreg Kroah-Hartman } else if (index == (NUM_RBUFFS -1) ) { 521ab4382d2SGreg Kroah-Hartman offset = startStgAddr - (unsigned long) icom_port->statStg; 522ab4382d2SGreg Kroah-Hartman icom_port->statStg->rcv[index].leNext = 523ab4382d2SGreg Kroah-Hartman cpu_to_le32(icom_port-> statStg_pci + offset); 524ab4382d2SGreg Kroah-Hartman trace(icom_port, "FID_RBUFF", 525ab4382d2SGreg Kroah-Hartman (unsigned long) icom_port->recv_buf + 2048); 526ab4382d2SGreg Kroah-Hartman icom_port->statStg->rcv[index].leBuffer = 527ab4382d2SGreg Kroah-Hartman cpu_to_le32(icom_port->recv_buf_pci + 2048); 528ab4382d2SGreg Kroah-Hartman } else { 529ab4382d2SGreg Kroah-Hartman icom_port->statStg->rcv[index].leNext = 0; 530ab4382d2SGreg Kroah-Hartman icom_port->statStg->rcv[index].leBuffer = 0; 531ab4382d2SGreg Kroah-Hartman } 532ab4382d2SGreg Kroah-Hartman } 533ab4382d2SGreg Kroah-Hartman 534ab4382d2SGreg Kroah-Hartman return 0; 535ab4382d2SGreg Kroah-Hartman } 536ab4382d2SGreg Kroah-Hartman 537ab4382d2SGreg Kroah-Hartman static void stop_processor(struct icom_port *icom_port) 538ab4382d2SGreg Kroah-Hartman { 539ab4382d2SGreg Kroah-Hartman unsigned long temp; 540ab4382d2SGreg Kroah-Hartman unsigned long flags; 541ab4382d2SGreg Kroah-Hartman int port; 542ab4382d2SGreg Kroah-Hartman 543ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&icom_lock, flags); 544ab4382d2SGreg Kroah-Hartman 545ab4382d2SGreg Kroah-Hartman port = icom_port->port; 5464f03ffcdSDan Carpenter if (port >= ARRAY_SIZE(stop_proc)) { 5474f03ffcdSDan Carpenter dev_err(&icom_port->adapter->pci_dev->dev, 5484f03ffcdSDan Carpenter "Invalid port assignment\n"); 5494f03ffcdSDan Carpenter goto unlock; 5504f03ffcdSDan Carpenter } 5514f03ffcdSDan Carpenter 552ab4382d2SGreg Kroah-Hartman if (port == 0 || port == 1) 553ab4382d2SGreg Kroah-Hartman stop_proc[port].global_control_reg = &icom_port->global_reg->control; 554ab4382d2SGreg Kroah-Hartman else 555ab4382d2SGreg Kroah-Hartman stop_proc[port].global_control_reg = &icom_port->global_reg->control_2; 556ab4382d2SGreg Kroah-Hartman 557ab4382d2SGreg Kroah-Hartman temp = readl(stop_proc[port].global_control_reg); 5584f03ffcdSDan Carpenter temp = (temp & ~start_proc[port].processor_id) | stop_proc[port].processor_id; 559ab4382d2SGreg Kroah-Hartman writel(temp, stop_proc[port].global_control_reg); 560ab4382d2SGreg Kroah-Hartman 561ab4382d2SGreg Kroah-Hartman /* write flush */ 562ab4382d2SGreg Kroah-Hartman readl(stop_proc[port].global_control_reg); 563ab4382d2SGreg Kroah-Hartman 5644f03ffcdSDan Carpenter unlock: 565ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&icom_lock, flags); 566ab4382d2SGreg Kroah-Hartman } 567ab4382d2SGreg Kroah-Hartman 568ab4382d2SGreg Kroah-Hartman static void start_processor(struct icom_port *icom_port) 569ab4382d2SGreg Kroah-Hartman { 570ab4382d2SGreg Kroah-Hartman unsigned long temp; 571ab4382d2SGreg Kroah-Hartman unsigned long flags; 572ab4382d2SGreg Kroah-Hartman int port; 573ab4382d2SGreg Kroah-Hartman 574ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&icom_lock, flags); 575ab4382d2SGreg Kroah-Hartman 576ab4382d2SGreg Kroah-Hartman port = icom_port->port; 5774f03ffcdSDan Carpenter if (port >= ARRAY_SIZE(start_proc)) { 5784f03ffcdSDan Carpenter dev_err(&icom_port->adapter->pci_dev->dev, 5794f03ffcdSDan Carpenter "Invalid port assignment\n"); 5804f03ffcdSDan Carpenter goto unlock; 5814f03ffcdSDan Carpenter } 5824f03ffcdSDan Carpenter 583ab4382d2SGreg Kroah-Hartman if (port == 0 || port == 1) 584ab4382d2SGreg Kroah-Hartman start_proc[port].global_control_reg = &icom_port->global_reg->control; 585ab4382d2SGreg Kroah-Hartman else 586ab4382d2SGreg Kroah-Hartman start_proc[port].global_control_reg = &icom_port->global_reg->control_2; 5874f03ffcdSDan Carpenter 588ab4382d2SGreg Kroah-Hartman temp = readl(start_proc[port].global_control_reg); 5894f03ffcdSDan Carpenter temp = (temp & ~stop_proc[port].processor_id) | start_proc[port].processor_id; 590ab4382d2SGreg Kroah-Hartman writel(temp, start_proc[port].global_control_reg); 591ab4382d2SGreg Kroah-Hartman 592ab4382d2SGreg Kroah-Hartman /* write flush */ 593ab4382d2SGreg Kroah-Hartman readl(start_proc[port].global_control_reg); 594ab4382d2SGreg Kroah-Hartman 5954f03ffcdSDan Carpenter unlock: 596ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&icom_lock, flags); 597ab4382d2SGreg Kroah-Hartman } 598ab4382d2SGreg Kroah-Hartman 599ab4382d2SGreg Kroah-Hartman static void load_code(struct icom_port *icom_port) 600ab4382d2SGreg Kroah-Hartman { 601ab4382d2SGreg Kroah-Hartman const struct firmware *fw; 602ab4382d2SGreg Kroah-Hartman char __iomem *iram_ptr; 603ab4382d2SGreg Kroah-Hartman int index; 604ab4382d2SGreg Kroah-Hartman int status = 0; 605ab4382d2SGreg Kroah-Hartman void __iomem *dram_ptr = icom_port->dram; 606ab4382d2SGreg Kroah-Hartman dma_addr_t temp_pci; 607ab4382d2SGreg Kroah-Hartman unsigned char *new_page = NULL; 608ab4382d2SGreg Kroah-Hartman unsigned char cable_id = NO_CABLE; 609ab4382d2SGreg Kroah-Hartman struct pci_dev *dev = icom_port->adapter->pci_dev; 610ab4382d2SGreg Kroah-Hartman 611ab4382d2SGreg Kroah-Hartman /* Clear out any pending interrupts */ 612ab4382d2SGreg Kroah-Hartman writew(0x3FFF, icom_port->int_reg); 613ab4382d2SGreg Kroah-Hartman 614ab4382d2SGreg Kroah-Hartman trace(icom_port, "CLEAR_INTERRUPTS", 0); 615ab4382d2SGreg Kroah-Hartman 616ab4382d2SGreg Kroah-Hartman /* Stop processor */ 617ab4382d2SGreg Kroah-Hartman stop_processor(icom_port); 618ab4382d2SGreg Kroah-Hartman 619ab4382d2SGreg Kroah-Hartman /* Zero out DRAM */ 620ab4382d2SGreg Kroah-Hartman memset_io(dram_ptr, 0, 512); 621ab4382d2SGreg Kroah-Hartman 622ab4382d2SGreg Kroah-Hartman /* Load Call Setup into Adapter */ 623ab4382d2SGreg Kroah-Hartman if (request_firmware(&fw, "icom_call_setup.bin", &dev->dev) < 0) { 624ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev,"Unable to load icom_call_setup.bin firmware image\n"); 625ab4382d2SGreg Kroah-Hartman status = -1; 626ab4382d2SGreg Kroah-Hartman goto load_code_exit; 627ab4382d2SGreg Kroah-Hartman } 628ab4382d2SGreg Kroah-Hartman 629ab4382d2SGreg Kroah-Hartman if (fw->size > ICOM_DCE_IRAM_OFFSET) { 630ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "Invalid firmware image for icom_call_setup.bin found.\n"); 631ab4382d2SGreg Kroah-Hartman release_firmware(fw); 632ab4382d2SGreg Kroah-Hartman status = -1; 633ab4382d2SGreg Kroah-Hartman goto load_code_exit; 634ab4382d2SGreg Kroah-Hartman } 635ab4382d2SGreg Kroah-Hartman 636ab4382d2SGreg Kroah-Hartman iram_ptr = (char __iomem *)icom_port->dram + ICOM_IRAM_OFFSET; 637ab4382d2SGreg Kroah-Hartman for (index = 0; index < fw->size; index++) 638ab4382d2SGreg Kroah-Hartman writeb(fw->data[index], &iram_ptr[index]); 639ab4382d2SGreg Kroah-Hartman 640ab4382d2SGreg Kroah-Hartman release_firmware(fw); 641ab4382d2SGreg Kroah-Hartman 642ab4382d2SGreg Kroah-Hartman /* Load Resident DCE portion of Adapter */ 643ab4382d2SGreg Kroah-Hartman if (request_firmware(&fw, "icom_res_dce.bin", &dev->dev) < 0) { 644ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev,"Unable to load icom_res_dce.bin firmware image\n"); 645ab4382d2SGreg Kroah-Hartman status = -1; 646ab4382d2SGreg Kroah-Hartman goto load_code_exit; 647ab4382d2SGreg Kroah-Hartman } 648ab4382d2SGreg Kroah-Hartman 649ab4382d2SGreg Kroah-Hartman if (fw->size > ICOM_IRAM_SIZE) { 650ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "Invalid firmware image for icom_res_dce.bin found.\n"); 651ab4382d2SGreg Kroah-Hartman release_firmware(fw); 652ab4382d2SGreg Kroah-Hartman status = -1; 653ab4382d2SGreg Kroah-Hartman goto load_code_exit; 654ab4382d2SGreg Kroah-Hartman } 655ab4382d2SGreg Kroah-Hartman 656ab4382d2SGreg Kroah-Hartman iram_ptr = (char __iomem *) icom_port->dram + ICOM_IRAM_OFFSET; 657ab4382d2SGreg Kroah-Hartman for (index = ICOM_DCE_IRAM_OFFSET; index < fw->size; index++) 658ab4382d2SGreg Kroah-Hartman writeb(fw->data[index], &iram_ptr[index]); 659ab4382d2SGreg Kroah-Hartman 660ab4382d2SGreg Kroah-Hartman release_firmware(fw); 661ab4382d2SGreg Kroah-Hartman 662ab4382d2SGreg Kroah-Hartman /* Set Hardware level */ 663ab4382d2SGreg Kroah-Hartman if (icom_port->adapter->version == ADAPTER_V2) 664ab4382d2SGreg Kroah-Hartman writeb(V2_HARDWARE, &(icom_port->dram->misc_flags)); 665ab4382d2SGreg Kroah-Hartman 666ab4382d2SGreg Kroah-Hartman /* Start the processor in Adapter */ 667ab4382d2SGreg Kroah-Hartman start_processor(icom_port); 668ab4382d2SGreg Kroah-Hartman 669ab4382d2SGreg Kroah-Hartman writeb((HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL), 670ab4382d2SGreg Kroah-Hartman &(icom_port->dram->HDLCConfigReg)); 671ab4382d2SGreg Kroah-Hartman writeb(0x04, &(icom_port->dram->FlagFillIdleTimer)); /* 0.5 seconds */ 672ab4382d2SGreg Kroah-Hartman writeb(0x00, &(icom_port->dram->CmdReg)); 673ab4382d2SGreg Kroah-Hartman writeb(0x10, &(icom_port->dram->async_config3)); 674ab4382d2SGreg Kroah-Hartman writeb((ICOM_ACFG_DRIVE1 | ICOM_ACFG_NO_PARITY | ICOM_ACFG_8BPC | 675ab4382d2SGreg Kroah-Hartman ICOM_ACFG_1STOP_BIT), &(icom_port->dram->async_config2)); 676ab4382d2SGreg Kroah-Hartman 677ab4382d2SGreg Kroah-Hartman /*Set up data in icom DRAM to indicate where personality 678ab4382d2SGreg Kroah-Hartman *code is located and its length. 679ab4382d2SGreg Kroah-Hartman */ 680c3647f2fSChristophe JAILLET new_page = dma_alloc_coherent(&dev->dev, 4096, &temp_pci, GFP_KERNEL); 681ab4382d2SGreg Kroah-Hartman 682ab4382d2SGreg Kroah-Hartman if (!new_page) { 683ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "Can not allocate DMA buffer\n"); 684ab4382d2SGreg Kroah-Hartman status = -1; 685ab4382d2SGreg Kroah-Hartman goto load_code_exit; 686ab4382d2SGreg Kroah-Hartman } 687ab4382d2SGreg Kroah-Hartman 688ab4382d2SGreg Kroah-Hartman if (request_firmware(&fw, "icom_asc.bin", &dev->dev) < 0) { 689ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev,"Unable to load icom_asc.bin firmware image\n"); 690ab4382d2SGreg Kroah-Hartman status = -1; 691ab4382d2SGreg Kroah-Hartman goto load_code_exit; 692ab4382d2SGreg Kroah-Hartman } 693ab4382d2SGreg Kroah-Hartman 694ab4382d2SGreg Kroah-Hartman if (fw->size > ICOM_DCE_IRAM_OFFSET) { 695ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "Invalid firmware image for icom_asc.bin found.\n"); 696ab4382d2SGreg Kroah-Hartman release_firmware(fw); 697ab4382d2SGreg Kroah-Hartman status = -1; 698ab4382d2SGreg Kroah-Hartman goto load_code_exit; 699ab4382d2SGreg Kroah-Hartman } 700ab4382d2SGreg Kroah-Hartman 701ab4382d2SGreg Kroah-Hartman for (index = 0; index < fw->size; index++) 702ab4382d2SGreg Kroah-Hartman new_page[index] = fw->data[index]; 703ab4382d2SGreg Kroah-Hartman 704ab4382d2SGreg Kroah-Hartman writeb((char) ((fw->size + 16)/16), &icom_port->dram->mac_length); 705ab4382d2SGreg Kroah-Hartman writel(temp_pci, &icom_port->dram->mac_load_addr); 706ab4382d2SGreg Kroah-Hartman 707d6a62b3bSDan Carpenter release_firmware(fw); 708d6a62b3bSDan Carpenter 709ab4382d2SGreg Kroah-Hartman /*Setting the syncReg to 0x80 causes adapter to start downloading 710ab4382d2SGreg Kroah-Hartman the personality code into adapter instruction RAM. 711ab4382d2SGreg Kroah-Hartman Once code is loaded, it will begin executing and, based on 712ab4382d2SGreg Kroah-Hartman information provided above, will start DMAing data from 713ab4382d2SGreg Kroah-Hartman shared memory to adapter DRAM. 714ab4382d2SGreg Kroah-Hartman */ 715ab4382d2SGreg Kroah-Hartman /* the wait loop below verifies this write operation has been done 716ab4382d2SGreg Kroah-Hartman and processed 717ab4382d2SGreg Kroah-Hartman */ 718ab4382d2SGreg Kroah-Hartman writeb(START_DOWNLOAD, &icom_port->dram->sync); 719ab4382d2SGreg Kroah-Hartman 720ab4382d2SGreg Kroah-Hartman /* Wait max 1 Sec for data download and processor to start */ 721ab4382d2SGreg Kroah-Hartman for (index = 0; index < 10; index++) { 722ab4382d2SGreg Kroah-Hartman msleep(100); 723ab4382d2SGreg Kroah-Hartman if (readb(&icom_port->dram->misc_flags) & ICOM_HDW_ACTIVE) 724ab4382d2SGreg Kroah-Hartman break; 725ab4382d2SGreg Kroah-Hartman } 726ab4382d2SGreg Kroah-Hartman 727ab4382d2SGreg Kroah-Hartman if (index == 10) 728ab4382d2SGreg Kroah-Hartman status = -1; 729ab4382d2SGreg Kroah-Hartman 730ab4382d2SGreg Kroah-Hartman /* 731ab4382d2SGreg Kroah-Hartman * check Cable ID 732ab4382d2SGreg Kroah-Hartman */ 733ab4382d2SGreg Kroah-Hartman cable_id = readb(&icom_port->dram->cable_id); 734ab4382d2SGreg Kroah-Hartman 735ab4382d2SGreg Kroah-Hartman if (cable_id & ICOM_CABLE_ID_VALID) { 736ab4382d2SGreg Kroah-Hartman /* Get cable ID into the lower 4 bits (standard form) */ 737ab4382d2SGreg Kroah-Hartman cable_id = (cable_id & ICOM_CABLE_ID_MASK) >> 4; 738ab4382d2SGreg Kroah-Hartman icom_port->cable_id = cable_id; 739ab4382d2SGreg Kroah-Hartman } else { 740ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev,"Invalid or no cable attached\n"); 741ab4382d2SGreg Kroah-Hartman icom_port->cable_id = NO_CABLE; 742ab4382d2SGreg Kroah-Hartman } 743ab4382d2SGreg Kroah-Hartman 744ab4382d2SGreg Kroah-Hartman load_code_exit: 745ab4382d2SGreg Kroah-Hartman 746ab4382d2SGreg Kroah-Hartman if (status != 0) { 747ab4382d2SGreg Kroah-Hartman /* Clear out any pending interrupts */ 748ab4382d2SGreg Kroah-Hartman writew(0x3FFF, icom_port->int_reg); 749ab4382d2SGreg Kroah-Hartman 750ab4382d2SGreg Kroah-Hartman /* Turn off port */ 751ab4382d2SGreg Kroah-Hartman writeb(ICOM_DISABLE, &(icom_port->dram->disable)); 752ab4382d2SGreg Kroah-Hartman 753ab4382d2SGreg Kroah-Hartman /* Stop processor */ 754ab4382d2SGreg Kroah-Hartman stop_processor(icom_port); 755ab4382d2SGreg Kroah-Hartman 75646e99c4aSMasanari Iida dev_err(&icom_port->adapter->pci_dev->dev,"Port not operational\n"); 757ab4382d2SGreg Kroah-Hartman } 758ab4382d2SGreg Kroah-Hartman 759ab4382d2SGreg Kroah-Hartman if (new_page != NULL) 760c3647f2fSChristophe JAILLET dma_free_coherent(&dev->dev, 4096, new_page, temp_pci); 761ab4382d2SGreg Kroah-Hartman } 762ab4382d2SGreg Kroah-Hartman 763ab4382d2SGreg Kroah-Hartman static int startup(struct icom_port *icom_port) 764ab4382d2SGreg Kroah-Hartman { 765ab4382d2SGreg Kroah-Hartman unsigned long temp; 766ab4382d2SGreg Kroah-Hartman unsigned char cable_id, raw_cable_id; 767ab4382d2SGreg Kroah-Hartman unsigned long flags; 768ab4382d2SGreg Kroah-Hartman int port; 769ab4382d2SGreg Kroah-Hartman 770ab4382d2SGreg Kroah-Hartman trace(icom_port, "STARTUP", 0); 771ab4382d2SGreg Kroah-Hartman 772ab4382d2SGreg Kroah-Hartman if (!icom_port->dram) { 773ab4382d2SGreg Kroah-Hartman /* should NEVER be NULL */ 774ab4382d2SGreg Kroah-Hartman dev_err(&icom_port->adapter->pci_dev->dev, 775ab4382d2SGreg Kroah-Hartman "Unusable Port, port configuration missing\n"); 776ab4382d2SGreg Kroah-Hartman return -ENODEV; 777ab4382d2SGreg Kroah-Hartman } 778ab4382d2SGreg Kroah-Hartman 779ab4382d2SGreg Kroah-Hartman /* 780ab4382d2SGreg Kroah-Hartman * check Cable ID 781ab4382d2SGreg Kroah-Hartman */ 782ab4382d2SGreg Kroah-Hartman raw_cable_id = readb(&icom_port->dram->cable_id); 783ab4382d2SGreg Kroah-Hartman trace(icom_port, "CABLE_ID", raw_cable_id); 784ab4382d2SGreg Kroah-Hartman 785ab4382d2SGreg Kroah-Hartman /* Get cable ID into the lower 4 bits (standard form) */ 786ab4382d2SGreg Kroah-Hartman cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4; 787ab4382d2SGreg Kroah-Hartman 788ab4382d2SGreg Kroah-Hartman /* Check for valid Cable ID */ 789ab4382d2SGreg Kroah-Hartman if (!(raw_cable_id & ICOM_CABLE_ID_VALID) || 790ab4382d2SGreg Kroah-Hartman (cable_id != icom_port->cable_id)) { 791ab4382d2SGreg Kroah-Hartman 792ab4382d2SGreg Kroah-Hartman /* reload adapter code, pick up any potential changes in cable id */ 793ab4382d2SGreg Kroah-Hartman load_code(icom_port); 794ab4382d2SGreg Kroah-Hartman 795ab4382d2SGreg Kroah-Hartman /* still no sign of cable, error out */ 796ab4382d2SGreg Kroah-Hartman raw_cable_id = readb(&icom_port->dram->cable_id); 797ab4382d2SGreg Kroah-Hartman cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4; 798ab4382d2SGreg Kroah-Hartman if (!(raw_cable_id & ICOM_CABLE_ID_VALID) || 799ab4382d2SGreg Kroah-Hartman (icom_port->cable_id == NO_CABLE)) 800ab4382d2SGreg Kroah-Hartman return -EIO; 801ab4382d2SGreg Kroah-Hartman } 802ab4382d2SGreg Kroah-Hartman 803ab4382d2SGreg Kroah-Hartman /* 804ab4382d2SGreg Kroah-Hartman * Finally, clear and enable interrupts 805ab4382d2SGreg Kroah-Hartman */ 806ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&icom_lock, flags); 807ab4382d2SGreg Kroah-Hartman port = icom_port->port; 8084f03ffcdSDan Carpenter if (port >= ARRAY_SIZE(int_mask_tbl)) { 8094f03ffcdSDan Carpenter dev_err(&icom_port->adapter->pci_dev->dev, 8104f03ffcdSDan Carpenter "Invalid port assignment\n"); 8114f03ffcdSDan Carpenter goto unlock; 8124f03ffcdSDan Carpenter } 8134f03ffcdSDan Carpenter 814ab4382d2SGreg Kroah-Hartman if (port == 0 || port == 1) 815ab4382d2SGreg Kroah-Hartman int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask; 816ab4382d2SGreg Kroah-Hartman else 817ab4382d2SGreg Kroah-Hartman int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2; 818ab4382d2SGreg Kroah-Hartman 819ab4382d2SGreg Kroah-Hartman if (port == 0 || port == 2) 820ab4382d2SGreg Kroah-Hartman writew(0x00FF, icom_port->int_reg); 821ab4382d2SGreg Kroah-Hartman else 822ab4382d2SGreg Kroah-Hartman writew(0x3F00, icom_port->int_reg); 8234f03ffcdSDan Carpenter 824ab4382d2SGreg Kroah-Hartman temp = readl(int_mask_tbl[port].global_int_mask); 825ab4382d2SGreg Kroah-Hartman writel(temp & ~int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask); 826ab4382d2SGreg Kroah-Hartman 827ab4382d2SGreg Kroah-Hartman /* write flush */ 828ab4382d2SGreg Kroah-Hartman readl(int_mask_tbl[port].global_int_mask); 829ab4382d2SGreg Kroah-Hartman 8304f03ffcdSDan Carpenter unlock: 831ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&icom_lock, flags); 832ab4382d2SGreg Kroah-Hartman return 0; 833ab4382d2SGreg Kroah-Hartman } 834ab4382d2SGreg Kroah-Hartman 835ab4382d2SGreg Kroah-Hartman static void shutdown(struct icom_port *icom_port) 836ab4382d2SGreg Kroah-Hartman { 837ab4382d2SGreg Kroah-Hartman unsigned long temp; 838ab4382d2SGreg Kroah-Hartman unsigned char cmdReg; 839ab4382d2SGreg Kroah-Hartman unsigned long flags; 840ab4382d2SGreg Kroah-Hartman int port; 841ab4382d2SGreg Kroah-Hartman 842ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&icom_lock, flags); 843ab4382d2SGreg Kroah-Hartman trace(icom_port, "SHUTDOWN", 0); 844ab4382d2SGreg Kroah-Hartman 845ab4382d2SGreg Kroah-Hartman /* 846ab4382d2SGreg Kroah-Hartman * disable all interrupts 847ab4382d2SGreg Kroah-Hartman */ 848ab4382d2SGreg Kroah-Hartman port = icom_port->port; 8494f03ffcdSDan Carpenter if (port >= ARRAY_SIZE(int_mask_tbl)) { 8504f03ffcdSDan Carpenter dev_err(&icom_port->adapter->pci_dev->dev, 8514f03ffcdSDan Carpenter "Invalid port assignment\n"); 8524f03ffcdSDan Carpenter goto unlock; 8534f03ffcdSDan Carpenter } 854ab4382d2SGreg Kroah-Hartman if (port == 0 || port == 1) 855ab4382d2SGreg Kroah-Hartman int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask; 856ab4382d2SGreg Kroah-Hartman else 857ab4382d2SGreg Kroah-Hartman int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2; 858ab4382d2SGreg Kroah-Hartman 859ab4382d2SGreg Kroah-Hartman temp = readl(int_mask_tbl[port].global_int_mask); 860ab4382d2SGreg Kroah-Hartman writel(temp | int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask); 861ab4382d2SGreg Kroah-Hartman 862ab4382d2SGreg Kroah-Hartman /* write flush */ 863ab4382d2SGreg Kroah-Hartman readl(int_mask_tbl[port].global_int_mask); 8644f03ffcdSDan Carpenter 8654f03ffcdSDan Carpenter unlock: 866ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&icom_lock, flags); 867ab4382d2SGreg Kroah-Hartman 868ab4382d2SGreg Kroah-Hartman /* 869ab4382d2SGreg Kroah-Hartman * disable break condition 870ab4382d2SGreg Kroah-Hartman */ 871ab4382d2SGreg Kroah-Hartman cmdReg = readb(&icom_port->dram->CmdReg); 872ab4382d2SGreg Kroah-Hartman if (cmdReg & CMD_SND_BREAK) { 873ab4382d2SGreg Kroah-Hartman writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg); 874ab4382d2SGreg Kroah-Hartman } 875ab4382d2SGreg Kroah-Hartman } 876ab4382d2SGreg Kroah-Hartman 877ab4382d2SGreg Kroah-Hartman static int icom_write(struct uart_port *port) 878ab4382d2SGreg Kroah-Hartman { 879f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port); 880*1788cf6aSJiri Slaby (SUSE) struct tty_port *tport = &port->state->port; 881ab4382d2SGreg Kroah-Hartman unsigned long data_count; 882ab4382d2SGreg Kroah-Hartman unsigned char cmdReg; 883ab4382d2SGreg Kroah-Hartman unsigned long offset; 884ab4382d2SGreg Kroah-Hartman 885f73989f5SJiri Slaby trace(icom_port, "WRITE", 0); 886ab4382d2SGreg Kroah-Hartman 8877a5f86e8SJiri Slaby if (le16_to_cpu(icom_port->statStg->xmit[0].flags) & 888ab4382d2SGreg Kroah-Hartman SA_FLAGS_READY_TO_XMIT) { 889f73989f5SJiri Slaby trace(icom_port, "WRITE_FULL", 0); 890ab4382d2SGreg Kroah-Hartman return 0; 891ab4382d2SGreg Kroah-Hartman } 892ab4382d2SGreg Kroah-Hartman 893*1788cf6aSJiri Slaby (SUSE) data_count = kfifo_out_peek(&tport->xmit_fifo, icom_port->xmit_buf, 894*1788cf6aSJiri Slaby (SUSE) XMIT_BUFF_SZ); 895ab4382d2SGreg Kroah-Hartman 896ab4382d2SGreg Kroah-Hartman if (data_count) { 897f73989f5SJiri Slaby icom_port->statStg->xmit[0].flags = 898ab4382d2SGreg Kroah-Hartman cpu_to_le16(SA_FLAGS_READY_TO_XMIT); 899f73989f5SJiri Slaby icom_port->statStg->xmit[0].leLength = 900ab4382d2SGreg Kroah-Hartman cpu_to_le16(data_count); 901ab4382d2SGreg Kroah-Hartman offset = 902f73989f5SJiri Slaby (unsigned long) &icom_port->statStg->xmit[0] - 903f73989f5SJiri Slaby (unsigned long) icom_port->statStg; 904f73989f5SJiri Slaby *icom_port->xmitRestart = 905f73989f5SJiri Slaby cpu_to_le32(icom_port->statStg_pci + offset); 906f73989f5SJiri Slaby cmdReg = readb(&icom_port->dram->CmdReg); 907ab4382d2SGreg Kroah-Hartman writeb(cmdReg | CMD_XMIT_RCV_ENABLE, 908f73989f5SJiri Slaby &icom_port->dram->CmdReg); 909f73989f5SJiri Slaby writeb(START_XMIT, &icom_port->dram->StartXmitCmd); 910f73989f5SJiri Slaby trace(icom_port, "WRITE_START", data_count); 911ab4382d2SGreg Kroah-Hartman /* write flush */ 912f73989f5SJiri Slaby readb(&icom_port->dram->StartXmitCmd); 913ab4382d2SGreg Kroah-Hartman } 914ab4382d2SGreg Kroah-Hartman 915ab4382d2SGreg Kroah-Hartman return data_count; 916ab4382d2SGreg Kroah-Hartman } 917ab4382d2SGreg Kroah-Hartman 918ab4382d2SGreg Kroah-Hartman static inline void check_modem_status(struct icom_port *icom_port) 919ab4382d2SGreg Kroah-Hartman { 920ab4382d2SGreg Kroah-Hartman static char old_status = 0; 921ab4382d2SGreg Kroah-Hartman char delta_status; 922ab4382d2SGreg Kroah-Hartman unsigned char status; 923ab4382d2SGreg Kroah-Hartman 924b4c7ba24SThomas Gleixner uart_port_lock(&icom_port->uart_port); 925ab4382d2SGreg Kroah-Hartman 926ab4382d2SGreg Kroah-Hartman /*modem input register */ 927ab4382d2SGreg Kroah-Hartman status = readb(&icom_port->dram->isr); 928ab4382d2SGreg Kroah-Hartman trace(icom_port, "CHECK_MODEM", status); 929ab4382d2SGreg Kroah-Hartman delta_status = status ^ old_status; 930ab4382d2SGreg Kroah-Hartman if (delta_status) { 931ab4382d2SGreg Kroah-Hartman if (delta_status & ICOM_RI) 932ab4382d2SGreg Kroah-Hartman icom_port->uart_port.icount.rng++; 933ab4382d2SGreg Kroah-Hartman if (delta_status & ICOM_DSR) 934ab4382d2SGreg Kroah-Hartman icom_port->uart_port.icount.dsr++; 935ab4382d2SGreg Kroah-Hartman if (delta_status & ICOM_DCD) 936ab4382d2SGreg Kroah-Hartman uart_handle_dcd_change(&icom_port->uart_port, 937ab4382d2SGreg Kroah-Hartman delta_status & ICOM_DCD); 938ab4382d2SGreg Kroah-Hartman if (delta_status & ICOM_CTS) 939ab4382d2SGreg Kroah-Hartman uart_handle_cts_change(&icom_port->uart_port, 940ab4382d2SGreg Kroah-Hartman delta_status & ICOM_CTS); 941ab4382d2SGreg Kroah-Hartman 942ab4382d2SGreg Kroah-Hartman wake_up_interruptible(&icom_port->uart_port.state-> 943ab4382d2SGreg Kroah-Hartman port.delta_msr_wait); 944ab4382d2SGreg Kroah-Hartman old_status = status; 945ab4382d2SGreg Kroah-Hartman } 946b4c7ba24SThomas Gleixner uart_port_unlock(&icom_port->uart_port); 947ab4382d2SGreg Kroah-Hartman } 948ab4382d2SGreg Kroah-Hartman 949ab4382d2SGreg Kroah-Hartman static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port) 950ab4382d2SGreg Kroah-Hartman { 951*1788cf6aSJiri Slaby (SUSE) struct tty_port *tport = &icom_port->uart_port.state->port; 952*1788cf6aSJiri Slaby (SUSE) u16 count; 953ab4382d2SGreg Kroah-Hartman 954ab4382d2SGreg Kroah-Hartman if (port_int_reg & (INT_XMIT_COMPLETED)) { 955ab4382d2SGreg Kroah-Hartman trace(icom_port, "XMIT_COMPLETE", 0); 956ab4382d2SGreg Kroah-Hartman 957ab4382d2SGreg Kroah-Hartman /* clear buffer in use bit */ 958ab4382d2SGreg Kroah-Hartman icom_port->statStg->xmit[0].flags &= 959ab4382d2SGreg Kroah-Hartman cpu_to_le16(~SA_FLAGS_READY_TO_XMIT); 960ab4382d2SGreg Kroah-Hartman 9617a5f86e8SJiri Slaby count = le16_to_cpu(icom_port->statStg->xmit[0].leLength); 962ab4382d2SGreg Kroah-Hartman icom_port->uart_port.icount.tx += count; 963ab4382d2SGreg Kroah-Hartman 964*1788cf6aSJiri Slaby (SUSE) kfifo_skip_count(&tport->xmit_fifo, count); 965ab4382d2SGreg Kroah-Hartman 966ab4382d2SGreg Kroah-Hartman if (!icom_write(&icom_port->uart_port)) 967ab4382d2SGreg Kroah-Hartman /* activate write queue */ 968ab4382d2SGreg Kroah-Hartman uart_write_wakeup(&icom_port->uart_port); 969ab4382d2SGreg Kroah-Hartman } else 970ab4382d2SGreg Kroah-Hartman trace(icom_port, "XMIT_DISABLED", 0); 971ab4382d2SGreg Kroah-Hartman } 972ab4382d2SGreg Kroah-Hartman 973ab4382d2SGreg Kroah-Hartman static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port) 974ab4382d2SGreg Kroah-Hartman { 975ab4382d2SGreg Kroah-Hartman short int count, rcv_buff; 97692a19f9cSJiri Slaby struct tty_port *port = &icom_port->uart_port.state->port; 9777a5f86e8SJiri Slaby u16 status; 978ab4382d2SGreg Kroah-Hartman struct uart_icount *icount; 979ab4382d2SGreg Kroah-Hartman unsigned long offset; 980ab4382d2SGreg Kroah-Hartman unsigned char flag; 981ab4382d2SGreg Kroah-Hartman 982ab4382d2SGreg Kroah-Hartman trace(icom_port, "RCV_COMPLETE", 0); 983ab4382d2SGreg Kroah-Hartman rcv_buff = icom_port->next_rcv; 984ab4382d2SGreg Kroah-Hartman 9857a5f86e8SJiri Slaby status = le16_to_cpu(icom_port->statStg->rcv[rcv_buff].flags); 986ab4382d2SGreg Kroah-Hartman while (status & SA_FL_RCV_DONE) { 987ab4382d2SGreg Kroah-Hartman int first = -1; 988ab4382d2SGreg Kroah-Hartman 989ab4382d2SGreg Kroah-Hartman trace(icom_port, "FID_STATUS", status); 9907a5f86e8SJiri Slaby count = le16_to_cpu(icom_port->statStg->rcv[rcv_buff].leLength); 991ab4382d2SGreg Kroah-Hartman 992ab4382d2SGreg Kroah-Hartman trace(icom_port, "RCV_COUNT", count); 993ab4382d2SGreg Kroah-Hartman 994ab4382d2SGreg Kroah-Hartman trace(icom_port, "REAL_COUNT", count); 995ab4382d2SGreg Kroah-Hartman 9967a5f86e8SJiri Slaby offset = le32_to_cpu(icom_port->statStg->rcv[rcv_buff].leBuffer) - 997ab4382d2SGreg Kroah-Hartman icom_port->recv_buf_pci; 998ab4382d2SGreg Kroah-Hartman 999ab4382d2SGreg Kroah-Hartman /* Block copy all but the last byte as this may have status */ 1000ab4382d2SGreg Kroah-Hartman if (count > 0) { 1001ab4382d2SGreg Kroah-Hartman first = icom_port->recv_buf[offset]; 100205c7cd39SJiri Slaby tty_insert_flip_string(port, icom_port->recv_buf + offset, count - 1); 1003ab4382d2SGreg Kroah-Hartman } 1004ab4382d2SGreg Kroah-Hartman 1005ab4382d2SGreg Kroah-Hartman icount = &icom_port->uart_port.icount; 1006ab4382d2SGreg Kroah-Hartman icount->rx += count; 1007ab4382d2SGreg Kroah-Hartman 1008ab4382d2SGreg Kroah-Hartman /* Break detect logic */ 1009ab4382d2SGreg Kroah-Hartman if ((status & SA_FLAGS_FRAME_ERROR) 1010ab4382d2SGreg Kroah-Hartman && first == 0) { 1011ab4382d2SGreg Kroah-Hartman status &= ~SA_FLAGS_FRAME_ERROR; 1012ab4382d2SGreg Kroah-Hartman status |= SA_FLAGS_BREAK_DET; 1013ab4382d2SGreg Kroah-Hartman trace(icom_port, "BREAK_DET", 0); 1014ab4382d2SGreg Kroah-Hartman } 1015ab4382d2SGreg Kroah-Hartman 1016ab4382d2SGreg Kroah-Hartman flag = TTY_NORMAL; 1017ab4382d2SGreg Kroah-Hartman 1018ab4382d2SGreg Kroah-Hartman if (status & 1019ab4382d2SGreg Kroah-Hartman (SA_FLAGS_BREAK_DET | SA_FLAGS_PARITY_ERROR | 1020ab4382d2SGreg Kroah-Hartman SA_FLAGS_FRAME_ERROR | SA_FLAGS_OVERRUN)) { 1021ab4382d2SGreg Kroah-Hartman 1022ab4382d2SGreg Kroah-Hartman if (status & SA_FLAGS_BREAK_DET) 1023ab4382d2SGreg Kroah-Hartman icount->brk++; 1024ab4382d2SGreg Kroah-Hartman if (status & SA_FLAGS_PARITY_ERROR) 1025ab4382d2SGreg Kroah-Hartman icount->parity++; 1026ab4382d2SGreg Kroah-Hartman if (status & SA_FLAGS_FRAME_ERROR) 1027ab4382d2SGreg Kroah-Hartman icount->frame++; 1028ab4382d2SGreg Kroah-Hartman if (status & SA_FLAGS_OVERRUN) 1029ab4382d2SGreg Kroah-Hartman icount->overrun++; 1030ab4382d2SGreg Kroah-Hartman 1031ab4382d2SGreg Kroah-Hartman /* 1032ab4382d2SGreg Kroah-Hartman * Now check to see if character should be 1033ab4382d2SGreg Kroah-Hartman * ignored, and mask off conditions which 1034ab4382d2SGreg Kroah-Hartman * should be ignored. 1035ab4382d2SGreg Kroah-Hartman */ 1036ab4382d2SGreg Kroah-Hartman if (status & icom_port->ignore_status_mask) { 1037ab4382d2SGreg Kroah-Hartman trace(icom_port, "IGNORE_CHAR", 0); 1038ab4382d2SGreg Kroah-Hartman goto ignore_char; 1039ab4382d2SGreg Kroah-Hartman } 1040ab4382d2SGreg Kroah-Hartman 1041ab4382d2SGreg Kroah-Hartman status &= icom_port->read_status_mask; 1042ab4382d2SGreg Kroah-Hartman 1043ab4382d2SGreg Kroah-Hartman if (status & SA_FLAGS_BREAK_DET) { 1044ab4382d2SGreg Kroah-Hartman flag = TTY_BREAK; 1045ab4382d2SGreg Kroah-Hartman } else if (status & SA_FLAGS_PARITY_ERROR) { 1046ab4382d2SGreg Kroah-Hartman trace(icom_port, "PARITY_ERROR", 0); 1047ab4382d2SGreg Kroah-Hartman flag = TTY_PARITY; 1048ab4382d2SGreg Kroah-Hartman } else if (status & SA_FLAGS_FRAME_ERROR) 1049ab4382d2SGreg Kroah-Hartman flag = TTY_FRAME; 1050ab4382d2SGreg Kroah-Hartman 1051ab4382d2SGreg Kroah-Hartman } 1052ab4382d2SGreg Kroah-Hartman 105392a19f9cSJiri Slaby tty_insert_flip_char(port, *(icom_port->recv_buf + offset + count - 1), flag); 1054ab4382d2SGreg Kroah-Hartman 1055ab4382d2SGreg Kroah-Hartman if (status & SA_FLAGS_OVERRUN) 1056ab4382d2SGreg Kroah-Hartman /* 1057ab4382d2SGreg Kroah-Hartman * Overrun is special, since it's 1058ab4382d2SGreg Kroah-Hartman * reported immediately, and doesn't 1059ab4382d2SGreg Kroah-Hartman * affect the current character 1060ab4382d2SGreg Kroah-Hartman */ 106192a19f9cSJiri Slaby tty_insert_flip_char(port, 0, TTY_OVERRUN); 1062ab4382d2SGreg Kroah-Hartman ignore_char: 1063ab4382d2SGreg Kroah-Hartman icom_port->statStg->rcv[rcv_buff].flags = 0; 1064ab4382d2SGreg Kroah-Hartman icom_port->statStg->rcv[rcv_buff].leLength = 0; 1065ab4382d2SGreg Kroah-Hartman icom_port->statStg->rcv[rcv_buff].WorkingLength = 10667a5f86e8SJiri Slaby cpu_to_le16(RCV_BUFF_SZ); 1067ab4382d2SGreg Kroah-Hartman 1068ab4382d2SGreg Kroah-Hartman rcv_buff++; 1069ab4382d2SGreg Kroah-Hartman if (rcv_buff == NUM_RBUFFS) 1070ab4382d2SGreg Kroah-Hartman rcv_buff = 0; 1071ab4382d2SGreg Kroah-Hartman 10727a5f86e8SJiri Slaby status = le16_to_cpu(icom_port->statStg->rcv[rcv_buff].flags); 1073ab4382d2SGreg Kroah-Hartman } 1074ab4382d2SGreg Kroah-Hartman icom_port->next_rcv = rcv_buff; 10755faf75d7SViresh Kumar 10762e124b4aSJiri Slaby tty_flip_buffer_push(port); 1077ab4382d2SGreg Kroah-Hartman } 1078ab4382d2SGreg Kroah-Hartman 1079ab4382d2SGreg Kroah-Hartman static void process_interrupt(u16 port_int_reg, 1080ab4382d2SGreg Kroah-Hartman struct icom_port *icom_port) 1081ab4382d2SGreg Kroah-Hartman { 1082ab4382d2SGreg Kroah-Hartman 1083b4c7ba24SThomas Gleixner uart_port_lock(&icom_port->uart_port); 1084ab4382d2SGreg Kroah-Hartman trace(icom_port, "INTERRUPT", port_int_reg); 1085ab4382d2SGreg Kroah-Hartman 1086ab4382d2SGreg Kroah-Hartman if (port_int_reg & (INT_XMIT_COMPLETED | INT_XMIT_DISABLED)) 1087ab4382d2SGreg Kroah-Hartman xmit_interrupt(port_int_reg, icom_port); 1088ab4382d2SGreg Kroah-Hartman 1089ab4382d2SGreg Kroah-Hartman if (port_int_reg & INT_RCV_COMPLETED) 1090ab4382d2SGreg Kroah-Hartman recv_interrupt(port_int_reg, icom_port); 1091ab4382d2SGreg Kroah-Hartman 1092b4c7ba24SThomas Gleixner uart_port_unlock(&icom_port->uart_port); 1093ab4382d2SGreg Kroah-Hartman } 1094ab4382d2SGreg Kroah-Hartman 1095ab4382d2SGreg Kroah-Hartman static irqreturn_t icom_interrupt(int irq, void *dev_id) 1096ab4382d2SGreg Kroah-Hartman { 1097ab4382d2SGreg Kroah-Hartman void __iomem * int_reg; 1098ab4382d2SGreg Kroah-Hartman u32 adapter_interrupts; 1099ab4382d2SGreg Kroah-Hartman u16 port_int_reg; 1100ab4382d2SGreg Kroah-Hartman struct icom_adapter *icom_adapter; 1101ab4382d2SGreg Kroah-Hartman struct icom_port *icom_port; 1102ab4382d2SGreg Kroah-Hartman 1103ab4382d2SGreg Kroah-Hartman /* find icom_port for this interrupt */ 1104ab4382d2SGreg Kroah-Hartman icom_adapter = (struct icom_adapter *) dev_id; 1105ab4382d2SGreg Kroah-Hartman 1106ab4382d2SGreg Kroah-Hartman if (icom_adapter->version == ADAPTER_V2) { 1107ab4382d2SGreg Kroah-Hartman int_reg = icom_adapter->base_addr + 0x8024; 1108ab4382d2SGreg Kroah-Hartman 1109ab4382d2SGreg Kroah-Hartman adapter_interrupts = readl(int_reg); 1110ab4382d2SGreg Kroah-Hartman 1111ab4382d2SGreg Kroah-Hartman if (adapter_interrupts & 0x00003FFF) { 1112ab4382d2SGreg Kroah-Hartman /* port 2 interrupt, NOTE: for all ADAPTER_V2, port 2 will be active */ 1113ab4382d2SGreg Kroah-Hartman icom_port = &icom_adapter->port_info[2]; 1114ab4382d2SGreg Kroah-Hartman port_int_reg = (u16) adapter_interrupts; 1115ab4382d2SGreg Kroah-Hartman process_interrupt(port_int_reg, icom_port); 1116ab4382d2SGreg Kroah-Hartman check_modem_status(icom_port); 1117ab4382d2SGreg Kroah-Hartman } 1118ab4382d2SGreg Kroah-Hartman if (adapter_interrupts & 0x3FFF0000) { 1119ab4382d2SGreg Kroah-Hartman /* port 3 interrupt */ 1120ab4382d2SGreg Kroah-Hartman icom_port = &icom_adapter->port_info[3]; 1121ab4382d2SGreg Kroah-Hartman if (icom_port->status == ICOM_PORT_ACTIVE) { 1122ab4382d2SGreg Kroah-Hartman port_int_reg = 1123ab4382d2SGreg Kroah-Hartman (u16) (adapter_interrupts >> 16); 1124ab4382d2SGreg Kroah-Hartman process_interrupt(port_int_reg, icom_port); 1125ab4382d2SGreg Kroah-Hartman check_modem_status(icom_port); 1126ab4382d2SGreg Kroah-Hartman } 1127ab4382d2SGreg Kroah-Hartman } 1128ab4382d2SGreg Kroah-Hartman 1129ab4382d2SGreg Kroah-Hartman /* Clear out any pending interrupts */ 1130ab4382d2SGreg Kroah-Hartman writel(adapter_interrupts, int_reg); 1131ab4382d2SGreg Kroah-Hartman 1132ab4382d2SGreg Kroah-Hartman int_reg = icom_adapter->base_addr + 0x8004; 1133ab4382d2SGreg Kroah-Hartman } else { 1134ab4382d2SGreg Kroah-Hartman int_reg = icom_adapter->base_addr + 0x4004; 1135ab4382d2SGreg Kroah-Hartman } 1136ab4382d2SGreg Kroah-Hartman 1137ab4382d2SGreg Kroah-Hartman adapter_interrupts = readl(int_reg); 1138ab4382d2SGreg Kroah-Hartman 1139ab4382d2SGreg Kroah-Hartman if (adapter_interrupts & 0x00003FFF) { 1140ab4382d2SGreg Kroah-Hartman /* port 0 interrupt, NOTE: for all adapters, port 0 will be active */ 1141ab4382d2SGreg Kroah-Hartman icom_port = &icom_adapter->port_info[0]; 1142ab4382d2SGreg Kroah-Hartman port_int_reg = (u16) adapter_interrupts; 1143ab4382d2SGreg Kroah-Hartman process_interrupt(port_int_reg, icom_port); 1144ab4382d2SGreg Kroah-Hartman check_modem_status(icom_port); 1145ab4382d2SGreg Kroah-Hartman } 1146ab4382d2SGreg Kroah-Hartman if (adapter_interrupts & 0x3FFF0000) { 1147ab4382d2SGreg Kroah-Hartman /* port 1 interrupt */ 1148ab4382d2SGreg Kroah-Hartman icom_port = &icom_adapter->port_info[1]; 1149ab4382d2SGreg Kroah-Hartman if (icom_port->status == ICOM_PORT_ACTIVE) { 1150ab4382d2SGreg Kroah-Hartman port_int_reg = (u16) (adapter_interrupts >> 16); 1151ab4382d2SGreg Kroah-Hartman process_interrupt(port_int_reg, icom_port); 1152ab4382d2SGreg Kroah-Hartman check_modem_status(icom_port); 1153ab4382d2SGreg Kroah-Hartman } 1154ab4382d2SGreg Kroah-Hartman } 1155ab4382d2SGreg Kroah-Hartman 1156ab4382d2SGreg Kroah-Hartman /* Clear out any pending interrupts */ 1157ab4382d2SGreg Kroah-Hartman writel(adapter_interrupts, int_reg); 1158ab4382d2SGreg Kroah-Hartman 1159ab4382d2SGreg Kroah-Hartman /* flush the write */ 1160ab4382d2SGreg Kroah-Hartman adapter_interrupts = readl(int_reg); 1161ab4382d2SGreg Kroah-Hartman 1162ab4382d2SGreg Kroah-Hartman return IRQ_HANDLED; 1163ab4382d2SGreg Kroah-Hartman } 1164ab4382d2SGreg Kroah-Hartman 1165ab4382d2SGreg Kroah-Hartman /* 1166ab4382d2SGreg Kroah-Hartman * ------------------------------------------------------------------ 1167ab4382d2SGreg Kroah-Hartman * Begin serial-core API 1168ab4382d2SGreg Kroah-Hartman * ------------------------------------------------------------------ 1169ab4382d2SGreg Kroah-Hartman */ 1170ab4382d2SGreg Kroah-Hartman static unsigned int icom_tx_empty(struct uart_port *port) 1171ab4382d2SGreg Kroah-Hartman { 1172f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port); 1173ab4382d2SGreg Kroah-Hartman int ret; 1174ab4382d2SGreg Kroah-Hartman unsigned long flags; 1175ab4382d2SGreg Kroah-Hartman 1176b4c7ba24SThomas Gleixner uart_port_lock_irqsave(port, &flags); 11777a5f86e8SJiri Slaby if (le16_to_cpu(icom_port->statStg->xmit[0].flags) & 1178ab4382d2SGreg Kroah-Hartman SA_FLAGS_READY_TO_XMIT) 1179ab4382d2SGreg Kroah-Hartman ret = TIOCSER_TEMT; 1180ab4382d2SGreg Kroah-Hartman else 1181ab4382d2SGreg Kroah-Hartman ret = 0; 1182ab4382d2SGreg Kroah-Hartman 1183b4c7ba24SThomas Gleixner uart_port_unlock_irqrestore(port, flags); 1184ab4382d2SGreg Kroah-Hartman return ret; 1185ab4382d2SGreg Kroah-Hartman } 1186ab4382d2SGreg Kroah-Hartman 1187ab4382d2SGreg Kroah-Hartman static void icom_set_mctrl(struct uart_port *port, unsigned int mctrl) 1188ab4382d2SGreg Kroah-Hartman { 1189f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port); 1190ab4382d2SGreg Kroah-Hartman unsigned char local_osr; 1191ab4382d2SGreg Kroah-Hartman 1192f73989f5SJiri Slaby trace(icom_port, "SET_MODEM", 0); 1193f73989f5SJiri Slaby local_osr = readb(&icom_port->dram->osr); 1194ab4382d2SGreg Kroah-Hartman 1195ab4382d2SGreg Kroah-Hartman if (mctrl & TIOCM_RTS) { 1196f73989f5SJiri Slaby trace(icom_port, "RAISE_RTS", 0); 1197ab4382d2SGreg Kroah-Hartman local_osr |= ICOM_RTS; 1198ab4382d2SGreg Kroah-Hartman } else { 1199f73989f5SJiri Slaby trace(icom_port, "LOWER_RTS", 0); 1200ab4382d2SGreg Kroah-Hartman local_osr &= ~ICOM_RTS; 1201ab4382d2SGreg Kroah-Hartman } 1202ab4382d2SGreg Kroah-Hartman 1203ab4382d2SGreg Kroah-Hartman if (mctrl & TIOCM_DTR) { 1204f73989f5SJiri Slaby trace(icom_port, "RAISE_DTR", 0); 1205ab4382d2SGreg Kroah-Hartman local_osr |= ICOM_DTR; 1206ab4382d2SGreg Kroah-Hartman } else { 1207f73989f5SJiri Slaby trace(icom_port, "LOWER_DTR", 0); 1208ab4382d2SGreg Kroah-Hartman local_osr &= ~ICOM_DTR; 1209ab4382d2SGreg Kroah-Hartman } 1210ab4382d2SGreg Kroah-Hartman 1211f73989f5SJiri Slaby writeb(local_osr, &icom_port->dram->osr); 1212ab4382d2SGreg Kroah-Hartman } 1213ab4382d2SGreg Kroah-Hartman 1214ab4382d2SGreg Kroah-Hartman static unsigned int icom_get_mctrl(struct uart_port *port) 1215ab4382d2SGreg Kroah-Hartman { 1216f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port); 1217ab4382d2SGreg Kroah-Hartman unsigned char status; 1218ab4382d2SGreg Kroah-Hartman unsigned int result; 1219ab4382d2SGreg Kroah-Hartman 1220f73989f5SJiri Slaby trace(icom_port, "GET_MODEM", 0); 1221ab4382d2SGreg Kroah-Hartman 1222f73989f5SJiri Slaby status = readb(&icom_port->dram->isr); 1223ab4382d2SGreg Kroah-Hartman 1224ab4382d2SGreg Kroah-Hartman result = ((status & ICOM_DCD) ? TIOCM_CAR : 0) 1225ab4382d2SGreg Kroah-Hartman | ((status & ICOM_RI) ? TIOCM_RNG : 0) 1226ab4382d2SGreg Kroah-Hartman | ((status & ICOM_DSR) ? TIOCM_DSR : 0) 1227ab4382d2SGreg Kroah-Hartman | ((status & ICOM_CTS) ? TIOCM_CTS : 0); 1228ab4382d2SGreg Kroah-Hartman return result; 1229ab4382d2SGreg Kroah-Hartman } 1230ab4382d2SGreg Kroah-Hartman 1231ab4382d2SGreg Kroah-Hartman static void icom_stop_tx(struct uart_port *port) 1232ab4382d2SGreg Kroah-Hartman { 1233f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port); 1234ab4382d2SGreg Kroah-Hartman unsigned char cmdReg; 1235ab4382d2SGreg Kroah-Hartman 1236f73989f5SJiri Slaby trace(icom_port, "STOP", 0); 1237f73989f5SJiri Slaby cmdReg = readb(&icom_port->dram->CmdReg); 1238f73989f5SJiri Slaby writeb(cmdReg | CMD_HOLD_XMIT, &icom_port->dram->CmdReg); 1239ab4382d2SGreg Kroah-Hartman } 1240ab4382d2SGreg Kroah-Hartman 1241ab4382d2SGreg Kroah-Hartman static void icom_start_tx(struct uart_port *port) 1242ab4382d2SGreg Kroah-Hartman { 1243f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port); 1244ab4382d2SGreg Kroah-Hartman unsigned char cmdReg; 1245ab4382d2SGreg Kroah-Hartman 1246f73989f5SJiri Slaby trace(icom_port, "START", 0); 1247f73989f5SJiri Slaby cmdReg = readb(&icom_port->dram->CmdReg); 1248ab4382d2SGreg Kroah-Hartman if ((cmdReg & CMD_HOLD_XMIT) == CMD_HOLD_XMIT) 1249ab4382d2SGreg Kroah-Hartman writeb(cmdReg & ~CMD_HOLD_XMIT, 1250f73989f5SJiri Slaby &icom_port->dram->CmdReg); 1251ab4382d2SGreg Kroah-Hartman 1252ab4382d2SGreg Kroah-Hartman icom_write(port); 1253ab4382d2SGreg Kroah-Hartman } 1254ab4382d2SGreg Kroah-Hartman 1255ab4382d2SGreg Kroah-Hartman static void icom_send_xchar(struct uart_port *port, char ch) 1256ab4382d2SGreg Kroah-Hartman { 1257f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port); 1258ab4382d2SGreg Kroah-Hartman unsigned char xdata; 1259ab4382d2SGreg Kroah-Hartman int index; 1260ab4382d2SGreg Kroah-Hartman unsigned long flags; 1261ab4382d2SGreg Kroah-Hartman 1262f73989f5SJiri Slaby trace(icom_port, "SEND_XCHAR", ch); 1263ab4382d2SGreg Kroah-Hartman 1264ab4382d2SGreg Kroah-Hartman /* wait .1 sec to send char */ 1265ab4382d2SGreg Kroah-Hartman for (index = 0; index < 10; index++) { 1266b4c7ba24SThomas Gleixner uart_port_lock_irqsave(port, &flags); 1267f73989f5SJiri Slaby xdata = readb(&icom_port->dram->xchar); 1268ab4382d2SGreg Kroah-Hartman if (xdata == 0x00) { 1269f73989f5SJiri Slaby trace(icom_port, "QUICK_WRITE", 0); 1270f73989f5SJiri Slaby writeb(ch, &icom_port->dram->xchar); 1271ab4382d2SGreg Kroah-Hartman 1272ab4382d2SGreg Kroah-Hartman /* flush write operation */ 1273f73989f5SJiri Slaby xdata = readb(&icom_port->dram->xchar); 1274b4c7ba24SThomas Gleixner uart_port_unlock_irqrestore(port, flags); 1275ab4382d2SGreg Kroah-Hartman break; 1276ab4382d2SGreg Kroah-Hartman } 1277b4c7ba24SThomas Gleixner uart_port_unlock_irqrestore(port, flags); 1278ab4382d2SGreg Kroah-Hartman msleep(10); 1279ab4382d2SGreg Kroah-Hartman } 1280ab4382d2SGreg Kroah-Hartman } 1281ab4382d2SGreg Kroah-Hartman 1282ab4382d2SGreg Kroah-Hartman static void icom_stop_rx(struct uart_port *port) 1283ab4382d2SGreg Kroah-Hartman { 1284f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port); 1285ab4382d2SGreg Kroah-Hartman unsigned char cmdReg; 1286ab4382d2SGreg Kroah-Hartman 1287f73989f5SJiri Slaby cmdReg = readb(&icom_port->dram->CmdReg); 1288f73989f5SJiri Slaby writeb(cmdReg & ~CMD_RCV_ENABLE, &icom_port->dram->CmdReg); 1289ab4382d2SGreg Kroah-Hartman } 1290ab4382d2SGreg Kroah-Hartman 1291ab4382d2SGreg Kroah-Hartman static void icom_break(struct uart_port *port, int break_state) 1292ab4382d2SGreg Kroah-Hartman { 1293f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port); 1294ab4382d2SGreg Kroah-Hartman unsigned char cmdReg; 1295ab4382d2SGreg Kroah-Hartman unsigned long flags; 1296ab4382d2SGreg Kroah-Hartman 1297b4c7ba24SThomas Gleixner uart_port_lock_irqsave(port, &flags); 1298f73989f5SJiri Slaby trace(icom_port, "BREAK", 0); 1299f73989f5SJiri Slaby cmdReg = readb(&icom_port->dram->CmdReg); 1300ab4382d2SGreg Kroah-Hartman if (break_state == -1) { 1301f73989f5SJiri Slaby writeb(cmdReg | CMD_SND_BREAK, &icom_port->dram->CmdReg); 1302ab4382d2SGreg Kroah-Hartman } else { 1303f73989f5SJiri Slaby writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg); 1304ab4382d2SGreg Kroah-Hartman } 1305b4c7ba24SThomas Gleixner uart_port_unlock_irqrestore(port, flags); 1306ab4382d2SGreg Kroah-Hartman } 1307ab4382d2SGreg Kroah-Hartman 1308ab4382d2SGreg Kroah-Hartman static int icom_open(struct uart_port *port) 1309ab4382d2SGreg Kroah-Hartman { 1310f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port); 1311ab4382d2SGreg Kroah-Hartman int retval; 1312ab4382d2SGreg Kroah-Hartman 1313f73989f5SJiri Slaby kref_get(&icom_port->adapter->kref); 1314f73989f5SJiri Slaby retval = startup(icom_port); 1315ab4382d2SGreg Kroah-Hartman 1316ab4382d2SGreg Kroah-Hartman if (retval) { 1317f73989f5SJiri Slaby kref_put(&icom_port->adapter->kref, icom_kref_release); 1318f73989f5SJiri Slaby trace(icom_port, "STARTUP_ERROR", 0); 1319ab4382d2SGreg Kroah-Hartman return retval; 1320ab4382d2SGreg Kroah-Hartman } 1321ab4382d2SGreg Kroah-Hartman 1322ab4382d2SGreg Kroah-Hartman return 0; 1323ab4382d2SGreg Kroah-Hartman } 1324ab4382d2SGreg Kroah-Hartman 1325ab4382d2SGreg Kroah-Hartman static void icom_close(struct uart_port *port) 1326ab4382d2SGreg Kroah-Hartman { 1327f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port); 1328ab4382d2SGreg Kroah-Hartman unsigned char cmdReg; 1329ab4382d2SGreg Kroah-Hartman 1330f73989f5SJiri Slaby trace(icom_port, "CLOSE", 0); 1331ab4382d2SGreg Kroah-Hartman 1332ab4382d2SGreg Kroah-Hartman /* stop receiver */ 1333f73989f5SJiri Slaby cmdReg = readb(&icom_port->dram->CmdReg); 1334f73989f5SJiri Slaby writeb(cmdReg & ~CMD_RCV_ENABLE, &icom_port->dram->CmdReg); 1335ab4382d2SGreg Kroah-Hartman 1336f73989f5SJiri Slaby shutdown(icom_port); 1337ab4382d2SGreg Kroah-Hartman 1338f73989f5SJiri Slaby kref_put(&icom_port->adapter->kref, icom_kref_release); 1339ab4382d2SGreg Kroah-Hartman } 1340ab4382d2SGreg Kroah-Hartman 1341bec5b814SIlpo Järvinen static void icom_set_termios(struct uart_port *port, struct ktermios *termios, 1342bec5b814SIlpo Järvinen const struct ktermios *old_termios) 1343ab4382d2SGreg Kroah-Hartman { 1344f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port); 1345ab4382d2SGreg Kroah-Hartman int baud; 1346ab4382d2SGreg Kroah-Hartman unsigned cflag, iflag; 1347ab4382d2SGreg Kroah-Hartman char new_config2; 1348ab4382d2SGreg Kroah-Hartman char new_config3 = 0; 1349ab4382d2SGreg Kroah-Hartman char tmp_byte; 1350ab4382d2SGreg Kroah-Hartman int index; 1351ab4382d2SGreg Kroah-Hartman int rcv_buff, xmit_buff; 1352ab4382d2SGreg Kroah-Hartman unsigned long offset; 1353ab4382d2SGreg Kroah-Hartman unsigned long flags; 1354ab4382d2SGreg Kroah-Hartman 1355b4c7ba24SThomas Gleixner uart_port_lock_irqsave(port, &flags); 1356f73989f5SJiri Slaby trace(icom_port, "CHANGE_SPEED", 0); 1357ab4382d2SGreg Kroah-Hartman 1358ab4382d2SGreg Kroah-Hartman cflag = termios->c_cflag; 1359ab4382d2SGreg Kroah-Hartman iflag = termios->c_iflag; 1360ab4382d2SGreg Kroah-Hartman 1361ab4382d2SGreg Kroah-Hartman new_config2 = ICOM_ACFG_DRIVE1; 1362ab4382d2SGreg Kroah-Hartman 1363ab4382d2SGreg Kroah-Hartman /* byte size and parity */ 1364ab4382d2SGreg Kroah-Hartman switch (cflag & CSIZE) { 1365ab4382d2SGreg Kroah-Hartman case CS5: /* 5 bits/char */ 1366ab4382d2SGreg Kroah-Hartman new_config2 |= ICOM_ACFG_5BPC; 1367ab4382d2SGreg Kroah-Hartman break; 1368ab4382d2SGreg Kroah-Hartman case CS6: /* 6 bits/char */ 1369ab4382d2SGreg Kroah-Hartman new_config2 |= ICOM_ACFG_6BPC; 1370ab4382d2SGreg Kroah-Hartman break; 1371ab4382d2SGreg Kroah-Hartman case CS7: /* 7 bits/char */ 1372ab4382d2SGreg Kroah-Hartman new_config2 |= ICOM_ACFG_7BPC; 1373ab4382d2SGreg Kroah-Hartman break; 1374ab4382d2SGreg Kroah-Hartman case CS8: /* 8 bits/char */ 1375ab4382d2SGreg Kroah-Hartman new_config2 |= ICOM_ACFG_8BPC; 1376ab4382d2SGreg Kroah-Hartman break; 1377ab4382d2SGreg Kroah-Hartman default: 1378ab4382d2SGreg Kroah-Hartman break; 1379ab4382d2SGreg Kroah-Hartman } 1380ab4382d2SGreg Kroah-Hartman if (cflag & CSTOPB) { 1381ab4382d2SGreg Kroah-Hartman /* 2 stop bits */ 1382ab4382d2SGreg Kroah-Hartman new_config2 |= ICOM_ACFG_2STOP_BIT; 1383ab4382d2SGreg Kroah-Hartman } 1384ab4382d2SGreg Kroah-Hartman if (cflag & PARENB) { 1385ab4382d2SGreg Kroah-Hartman /* parity bit enabled */ 1386ab4382d2SGreg Kroah-Hartman new_config2 |= ICOM_ACFG_PARITY_ENAB; 1387f73989f5SJiri Slaby trace(icom_port, "PARENB", 0); 1388ab4382d2SGreg Kroah-Hartman } 1389ab4382d2SGreg Kroah-Hartman if (cflag & PARODD) { 1390ab4382d2SGreg Kroah-Hartman /* odd parity */ 1391ab4382d2SGreg Kroah-Hartman new_config2 |= ICOM_ACFG_PARITY_ODD; 1392f73989f5SJiri Slaby trace(icom_port, "PARODD", 0); 1393ab4382d2SGreg Kroah-Hartman } 1394ab4382d2SGreg Kroah-Hartman 1395ab4382d2SGreg Kroah-Hartman /* Determine divisor based on baud rate */ 1396ab4382d2SGreg Kroah-Hartman baud = uart_get_baud_rate(port, termios, old_termios, 1397ab4382d2SGreg Kroah-Hartman icom_acfg_baud[0], 1398ab4382d2SGreg Kroah-Hartman icom_acfg_baud[BAUD_TABLE_LIMIT]); 1399ab4382d2SGreg Kroah-Hartman if (!baud) 1400ab4382d2SGreg Kroah-Hartman baud = 9600; /* B0 transition handled in rs_set_termios */ 1401ab4382d2SGreg Kroah-Hartman 1402ab4382d2SGreg Kroah-Hartman for (index = 0; index < BAUD_TABLE_LIMIT; index++) { 1403ab4382d2SGreg Kroah-Hartman if (icom_acfg_baud[index] == baud) { 1404ab4382d2SGreg Kroah-Hartman new_config3 = index; 1405ab4382d2SGreg Kroah-Hartman break; 1406ab4382d2SGreg Kroah-Hartman } 1407ab4382d2SGreg Kroah-Hartman } 1408ab4382d2SGreg Kroah-Hartman 1409ab4382d2SGreg Kroah-Hartman uart_update_timeout(port, cflag, baud); 1410ab4382d2SGreg Kroah-Hartman 1411ab4382d2SGreg Kroah-Hartman /* CTS flow control flag and modem status interrupts */ 1412f73989f5SJiri Slaby tmp_byte = readb(&(icom_port->dram->HDLCConfigReg)); 1413ab4382d2SGreg Kroah-Hartman if (cflag & CRTSCTS) 1414ab4382d2SGreg Kroah-Hartman tmp_byte |= HDLC_HDW_FLOW; 1415ab4382d2SGreg Kroah-Hartman else 1416ab4382d2SGreg Kroah-Hartman tmp_byte &= ~HDLC_HDW_FLOW; 1417f73989f5SJiri Slaby writeb(tmp_byte, &(icom_port->dram->HDLCConfigReg)); 1418ab4382d2SGreg Kroah-Hartman 1419ab4382d2SGreg Kroah-Hartman /* 1420ab4382d2SGreg Kroah-Hartman * Set up parity check flag 1421ab4382d2SGreg Kroah-Hartman */ 1422f73989f5SJiri Slaby icom_port->read_status_mask = SA_FLAGS_OVERRUN | SA_FL_RCV_DONE; 1423ab4382d2SGreg Kroah-Hartman if (iflag & INPCK) 1424f73989f5SJiri Slaby icom_port->read_status_mask |= 1425ab4382d2SGreg Kroah-Hartman SA_FLAGS_FRAME_ERROR | SA_FLAGS_PARITY_ERROR; 1426ab4382d2SGreg Kroah-Hartman 1427ab4382d2SGreg Kroah-Hartman if ((iflag & BRKINT) || (iflag & PARMRK)) 1428f73989f5SJiri Slaby icom_port->read_status_mask |= SA_FLAGS_BREAK_DET; 1429ab4382d2SGreg Kroah-Hartman 1430ab4382d2SGreg Kroah-Hartman /* 1431ab4382d2SGreg Kroah-Hartman * Characters to ignore 1432ab4382d2SGreg Kroah-Hartman */ 1433f73989f5SJiri Slaby icom_port->ignore_status_mask = 0; 1434ab4382d2SGreg Kroah-Hartman if (iflag & IGNPAR) 1435f73989f5SJiri Slaby icom_port->ignore_status_mask |= 1436ab4382d2SGreg Kroah-Hartman SA_FLAGS_PARITY_ERROR | SA_FLAGS_FRAME_ERROR; 1437ab4382d2SGreg Kroah-Hartman if (iflag & IGNBRK) { 1438f73989f5SJiri Slaby icom_port->ignore_status_mask |= SA_FLAGS_BREAK_DET; 1439ab4382d2SGreg Kroah-Hartman /* 1440ab4382d2SGreg Kroah-Hartman * If we're ignore parity and break indicators, ignore 1441ab4382d2SGreg Kroah-Hartman * overruns too. (For real raw support). 1442ab4382d2SGreg Kroah-Hartman */ 1443ab4382d2SGreg Kroah-Hartman if (iflag & IGNPAR) 1444f73989f5SJiri Slaby icom_port->ignore_status_mask |= SA_FLAGS_OVERRUN; 1445ab4382d2SGreg Kroah-Hartman } 1446ab4382d2SGreg Kroah-Hartman 1447ab4382d2SGreg Kroah-Hartman /* 1448ab4382d2SGreg Kroah-Hartman * !!! ignore all characters if CREAD is not set 1449ab4382d2SGreg Kroah-Hartman */ 1450ab4382d2SGreg Kroah-Hartman if ((cflag & CREAD) == 0) 1451f73989f5SJiri Slaby icom_port->ignore_status_mask |= SA_FL_RCV_DONE; 1452ab4382d2SGreg Kroah-Hartman 1453ab4382d2SGreg Kroah-Hartman /* Turn off Receiver to prepare for reset */ 1454f73989f5SJiri Slaby writeb(CMD_RCV_DISABLE, &icom_port->dram->CmdReg); 1455ab4382d2SGreg Kroah-Hartman 1456ab4382d2SGreg Kroah-Hartman for (index = 0; index < 10; index++) { 1457f73989f5SJiri Slaby if (readb(&icom_port->dram->PrevCmdReg) == 0x00) { 1458ab4382d2SGreg Kroah-Hartman break; 1459ab4382d2SGreg Kroah-Hartman } 1460ab4382d2SGreg Kroah-Hartman } 1461ab4382d2SGreg Kroah-Hartman 1462ab4382d2SGreg Kroah-Hartman /* clear all current buffers of data */ 1463ab4382d2SGreg Kroah-Hartman for (rcv_buff = 0; rcv_buff < NUM_RBUFFS; rcv_buff++) { 1464f73989f5SJiri Slaby icom_port->statStg->rcv[rcv_buff].flags = 0; 1465f73989f5SJiri Slaby icom_port->statStg->rcv[rcv_buff].leLength = 0; 1466f73989f5SJiri Slaby icom_port->statStg->rcv[rcv_buff].WorkingLength = 14677a5f86e8SJiri Slaby cpu_to_le16(RCV_BUFF_SZ); 1468ab4382d2SGreg Kroah-Hartman } 1469ab4382d2SGreg Kroah-Hartman 1470ab4382d2SGreg Kroah-Hartman for (xmit_buff = 0; xmit_buff < NUM_XBUFFS; xmit_buff++) { 1471f73989f5SJiri Slaby icom_port->statStg->xmit[xmit_buff].flags = 0; 1472ab4382d2SGreg Kroah-Hartman } 1473ab4382d2SGreg Kroah-Hartman 1474ab4382d2SGreg Kroah-Hartman /* activate changes and start xmit and receiver here */ 1475ab4382d2SGreg Kroah-Hartman /* Enable the receiver */ 1476f73989f5SJiri Slaby writeb(new_config3, &(icom_port->dram->async_config3)); 1477f73989f5SJiri Slaby writeb(new_config2, &(icom_port->dram->async_config2)); 1478f73989f5SJiri Slaby tmp_byte = readb(&(icom_port->dram->HDLCConfigReg)); 1479ab4382d2SGreg Kroah-Hartman tmp_byte |= HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL; 1480f73989f5SJiri Slaby writeb(tmp_byte, &(icom_port->dram->HDLCConfigReg)); 1481f73989f5SJiri Slaby writeb(0x04, &(icom_port->dram->FlagFillIdleTimer)); /* 0.5 seconds */ 1482f73989f5SJiri Slaby writeb(0xFF, &(icom_port->dram->ier)); /* enable modem signal interrupts */ 1483ab4382d2SGreg Kroah-Hartman 1484ab4382d2SGreg Kroah-Hartman /* reset processor */ 1485f73989f5SJiri Slaby writeb(CMD_RESTART, &icom_port->dram->CmdReg); 1486ab4382d2SGreg Kroah-Hartman 1487ab4382d2SGreg Kroah-Hartman for (index = 0; index < 10; index++) { 1488f73989f5SJiri Slaby if (readb(&icom_port->dram->CmdReg) == 0x00) { 1489ab4382d2SGreg Kroah-Hartman break; 1490ab4382d2SGreg Kroah-Hartman } 1491ab4382d2SGreg Kroah-Hartman } 1492ab4382d2SGreg Kroah-Hartman 149325985edcSLucas De Marchi /* Enable Transmitter and Receiver */ 1494ab4382d2SGreg Kroah-Hartman offset = 1495f73989f5SJiri Slaby (unsigned long) &icom_port->statStg->rcv[0] - 1496f73989f5SJiri Slaby (unsigned long) icom_port->statStg; 1497f73989f5SJiri Slaby writel(icom_port->statStg_pci + offset, 1498f73989f5SJiri Slaby &icom_port->dram->RcvStatusAddr); 1499f73989f5SJiri Slaby icom_port->next_rcv = 0; 1500f73989f5SJiri Slaby *icom_port->xmitRestart = 0; 1501f73989f5SJiri Slaby writel(icom_port->xmitRestart_pci, 1502f73989f5SJiri Slaby &icom_port->dram->XmitStatusAddr); 1503f73989f5SJiri Slaby trace(icom_port, "XR_ENAB", 0); 1504f73989f5SJiri Slaby writeb(CMD_XMIT_RCV_ENABLE, &icom_port->dram->CmdReg); 1505ab4382d2SGreg Kroah-Hartman 1506b4c7ba24SThomas Gleixner uart_port_unlock_irqrestore(port, flags); 1507ab4382d2SGreg Kroah-Hartman } 1508ab4382d2SGreg Kroah-Hartman 1509ab4382d2SGreg Kroah-Hartman static const char *icom_type(struct uart_port *port) 1510ab4382d2SGreg Kroah-Hartman { 1511ab4382d2SGreg Kroah-Hartman return "icom"; 1512ab4382d2SGreg Kroah-Hartman } 1513ab4382d2SGreg Kroah-Hartman 1514ab4382d2SGreg Kroah-Hartman static void icom_config_port(struct uart_port *port, int flags) 1515ab4382d2SGreg Kroah-Hartman { 1516ab4382d2SGreg Kroah-Hartman port->type = PORT_ICOM; 1517ab4382d2SGreg Kroah-Hartman } 1518ab4382d2SGreg Kroah-Hartman 15192331e068SBhumika Goyal static const struct uart_ops icom_ops = { 1520ab4382d2SGreg Kroah-Hartman .tx_empty = icom_tx_empty, 1521ab4382d2SGreg Kroah-Hartman .set_mctrl = icom_set_mctrl, 1522ab4382d2SGreg Kroah-Hartman .get_mctrl = icom_get_mctrl, 1523ab4382d2SGreg Kroah-Hartman .stop_tx = icom_stop_tx, 1524ab4382d2SGreg Kroah-Hartman .start_tx = icom_start_tx, 1525ab4382d2SGreg Kroah-Hartman .send_xchar = icom_send_xchar, 1526ab4382d2SGreg Kroah-Hartman .stop_rx = icom_stop_rx, 1527ab4382d2SGreg Kroah-Hartman .break_ctl = icom_break, 1528ab4382d2SGreg Kroah-Hartman .startup = icom_open, 1529ab4382d2SGreg Kroah-Hartman .shutdown = icom_close, 1530ab4382d2SGreg Kroah-Hartman .set_termios = icom_set_termios, 1531ab4382d2SGreg Kroah-Hartman .type = icom_type, 1532ab4382d2SGreg Kroah-Hartman .config_port = icom_config_port, 1533ab4382d2SGreg Kroah-Hartman }; 1534ab4382d2SGreg Kroah-Hartman 1535ab4382d2SGreg Kroah-Hartman #define ICOM_CONSOLE NULL 1536ab4382d2SGreg Kroah-Hartman 1537ab4382d2SGreg Kroah-Hartman static struct uart_driver icom_uart_driver = { 1538ab4382d2SGreg Kroah-Hartman .owner = THIS_MODULE, 1539ab4382d2SGreg Kroah-Hartman .driver_name = ICOM_DRIVER_NAME, 1540ab4382d2SGreg Kroah-Hartman .dev_name = "ttyA", 1541ab4382d2SGreg Kroah-Hartman .major = ICOM_MAJOR, 1542ab4382d2SGreg Kroah-Hartman .minor = ICOM_MINOR_START, 1543ab4382d2SGreg Kroah-Hartman .nr = NR_PORTS, 1544ab4382d2SGreg Kroah-Hartman .cons = ICOM_CONSOLE, 1545ab4382d2SGreg Kroah-Hartman }; 1546ab4382d2SGreg Kroah-Hartman 15479671f099SBill Pemberton static int icom_init_ports(struct icom_adapter *icom_adapter) 1548ab4382d2SGreg Kroah-Hartman { 1549ab4382d2SGreg Kroah-Hartman u32 subsystem_id = icom_adapter->subsystem_id; 1550ab4382d2SGreg Kroah-Hartman int i; 1551ab4382d2SGreg Kroah-Hartman struct icom_port *icom_port; 1552ab4382d2SGreg Kroah-Hartman 1553ab4382d2SGreg Kroah-Hartman if (icom_adapter->version == ADAPTER_V1) { 1554ab4382d2SGreg Kroah-Hartman icom_adapter->numb_ports = 2; 1555ab4382d2SGreg Kroah-Hartman 1556ab4382d2SGreg Kroah-Hartman for (i = 0; i < 2; i++) { 1557ab4382d2SGreg Kroah-Hartman icom_port = &icom_adapter->port_info[i]; 1558ab4382d2SGreg Kroah-Hartman icom_port->port = i; 1559ab4382d2SGreg Kroah-Hartman icom_port->status = ICOM_PORT_ACTIVE; 1560ab4382d2SGreg Kroah-Hartman } 1561ab4382d2SGreg Kroah-Hartman } else { 1562ab4382d2SGreg Kroah-Hartman if (subsystem_id == PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL) { 1563ab4382d2SGreg Kroah-Hartman icom_adapter->numb_ports = 4; 1564ab4382d2SGreg Kroah-Hartman 1565ab4382d2SGreg Kroah-Hartman for (i = 0; i < 4; i++) { 1566ab4382d2SGreg Kroah-Hartman icom_port = &icom_adapter->port_info[i]; 1567ab4382d2SGreg Kroah-Hartman 1568ab4382d2SGreg Kroah-Hartman icom_port->port = i; 1569ab4382d2SGreg Kroah-Hartman icom_port->status = ICOM_PORT_ACTIVE; 1570ab4382d2SGreg Kroah-Hartman } 1571ab4382d2SGreg Kroah-Hartman } else { 1572ab4382d2SGreg Kroah-Hartman icom_adapter->numb_ports = 4; 1573ab4382d2SGreg Kroah-Hartman 1574ab4382d2SGreg Kroah-Hartman icom_adapter->port_info[0].port = 0; 1575ab4382d2SGreg Kroah-Hartman icom_adapter->port_info[0].status = ICOM_PORT_ACTIVE; 1576ab4382d2SGreg Kroah-Hartman icom_adapter->port_info[1].status = ICOM_PORT_OFF; 1577ab4382d2SGreg Kroah-Hartman icom_adapter->port_info[2].port = 2; 1578ab4382d2SGreg Kroah-Hartman icom_adapter->port_info[2].status = ICOM_PORT_ACTIVE; 1579ab4382d2SGreg Kroah-Hartman icom_adapter->port_info[3].status = ICOM_PORT_OFF; 1580ab4382d2SGreg Kroah-Hartman } 1581ab4382d2SGreg Kroah-Hartman } 1582ab4382d2SGreg Kroah-Hartman 1583ab4382d2SGreg Kroah-Hartman return 0; 1584ab4382d2SGreg Kroah-Hartman } 1585ab4382d2SGreg Kroah-Hartman 1586ab4382d2SGreg Kroah-Hartman static void icom_port_active(struct icom_port *icom_port, struct icom_adapter *icom_adapter, int port_num) 1587ab4382d2SGreg Kroah-Hartman { 1588ab4382d2SGreg Kroah-Hartman if (icom_adapter->version == ADAPTER_V1) { 1589ab4382d2SGreg Kroah-Hartman icom_port->global_reg = icom_adapter->base_addr + 0x4000; 1590ab4382d2SGreg Kroah-Hartman icom_port->int_reg = icom_adapter->base_addr + 1591ab4382d2SGreg Kroah-Hartman 0x4004 + 2 - 2 * port_num; 1592ab4382d2SGreg Kroah-Hartman } else { 1593ab4382d2SGreg Kroah-Hartman icom_port->global_reg = icom_adapter->base_addr + 0x8000; 1594ab4382d2SGreg Kroah-Hartman if (icom_port->port < 2) 1595ab4382d2SGreg Kroah-Hartman icom_port->int_reg = icom_adapter->base_addr + 1596ab4382d2SGreg Kroah-Hartman 0x8004 + 2 - 2 * icom_port->port; 1597ab4382d2SGreg Kroah-Hartman else 1598ab4382d2SGreg Kroah-Hartman icom_port->int_reg = icom_adapter->base_addr + 1599ab4382d2SGreg Kroah-Hartman 0x8024 + 2 - 2 * (icom_port->port - 2); 1600ab4382d2SGreg Kroah-Hartman } 1601ab4382d2SGreg Kroah-Hartman } 16029671f099SBill Pemberton static int icom_load_ports(struct icom_adapter *icom_adapter) 1603ab4382d2SGreg Kroah-Hartman { 1604ab4382d2SGreg Kroah-Hartman struct icom_port *icom_port; 1605ab4382d2SGreg Kroah-Hartman int port_num; 1606ab4382d2SGreg Kroah-Hartman 1607ab4382d2SGreg Kroah-Hartman for (port_num = 0; port_num < icom_adapter->numb_ports; port_num++) { 1608ab4382d2SGreg Kroah-Hartman 1609ab4382d2SGreg Kroah-Hartman icom_port = &icom_adapter->port_info[port_num]; 1610ab4382d2SGreg Kroah-Hartman 1611ab4382d2SGreg Kroah-Hartman if (icom_port->status == ICOM_PORT_ACTIVE) { 1612ab4382d2SGreg Kroah-Hartman icom_port_active(icom_port, icom_adapter, port_num); 1613ab4382d2SGreg Kroah-Hartman icom_port->dram = icom_adapter->base_addr + 1614ab4382d2SGreg Kroah-Hartman 0x2000 * icom_port->port; 1615ab4382d2SGreg Kroah-Hartman 1616ab4382d2SGreg Kroah-Hartman icom_port->adapter = icom_adapter; 1617ab4382d2SGreg Kroah-Hartman 1618ab4382d2SGreg Kroah-Hartman /* get port memory */ 1619ab4382d2SGreg Kroah-Hartman if (get_port_memory(icom_port) != 0) { 1620ab4382d2SGreg Kroah-Hartman dev_err(&icom_port->adapter->pci_dev->dev, 1621ab4382d2SGreg Kroah-Hartman "Memory allocation for port FAILED\n"); 1622ab4382d2SGreg Kroah-Hartman } 1623ab4382d2SGreg Kroah-Hartman } 1624ab4382d2SGreg Kroah-Hartman } 1625ab4382d2SGreg Kroah-Hartman return 0; 1626ab4382d2SGreg Kroah-Hartman } 1627ab4382d2SGreg Kroah-Hartman 16289671f099SBill Pemberton static int icom_alloc_adapter(struct icom_adapter 1629ab4382d2SGreg Kroah-Hartman **icom_adapter_ref) 1630ab4382d2SGreg Kroah-Hartman { 1631ab4382d2SGreg Kroah-Hartman int adapter_count = 0; 1632ab4382d2SGreg Kroah-Hartman struct icom_adapter *icom_adapter; 1633ab4382d2SGreg Kroah-Hartman struct icom_adapter *cur_adapter_entry; 1634ab4382d2SGreg Kroah-Hartman 1635b9a129f4SZhang Yanfei icom_adapter = kzalloc(sizeof(struct icom_adapter), GFP_KERNEL); 1636ab4382d2SGreg Kroah-Hartman 1637ab4382d2SGreg Kroah-Hartman if (!icom_adapter) { 1638ab4382d2SGreg Kroah-Hartman return -ENOMEM; 1639ab4382d2SGreg Kroah-Hartman } 1640ab4382d2SGreg Kroah-Hartman 1641e391e325SJiri Slaby list_for_each_entry(cur_adapter_entry, &icom_adapter_head, 1642e391e325SJiri Slaby icom_adapter_entry) { 1643ab4382d2SGreg Kroah-Hartman if (cur_adapter_entry->index != adapter_count) { 1644ab4382d2SGreg Kroah-Hartman break; 1645ab4382d2SGreg Kroah-Hartman } 1646ab4382d2SGreg Kroah-Hartman adapter_count++; 1647ab4382d2SGreg Kroah-Hartman } 1648ab4382d2SGreg Kroah-Hartman 1649ab4382d2SGreg Kroah-Hartman icom_adapter->index = adapter_count; 1650e391e325SJiri Slaby list_add_tail(&icom_adapter->icom_adapter_entry, 1651e391e325SJiri Slaby &cur_adapter_entry->icom_adapter_entry); 1652ab4382d2SGreg Kroah-Hartman 1653ab4382d2SGreg Kroah-Hartman *icom_adapter_ref = icom_adapter; 1654ab4382d2SGreg Kroah-Hartman return 0; 1655ab4382d2SGreg Kroah-Hartman } 1656ab4382d2SGreg Kroah-Hartman 1657ab4382d2SGreg Kroah-Hartman static void icom_free_adapter(struct icom_adapter *icom_adapter) 1658ab4382d2SGreg Kroah-Hartman { 1659ab4382d2SGreg Kroah-Hartman list_del(&icom_adapter->icom_adapter_entry); 1660ab4382d2SGreg Kroah-Hartman kfree(icom_adapter); 1661ab4382d2SGreg Kroah-Hartman } 1662ab4382d2SGreg Kroah-Hartman 16632c334f12SJiri Slaby static void icom_kref_release(struct kref *kref) 1664ab4382d2SGreg Kroah-Hartman { 16652c334f12SJiri Slaby struct icom_adapter *icom_adapter = container_of(kref, 16662c334f12SJiri Slaby struct icom_adapter, kref); 1667ab4382d2SGreg Kroah-Hartman struct icom_port *icom_port; 1668ab4382d2SGreg Kroah-Hartman int index; 1669ab4382d2SGreg Kroah-Hartman 1670ab4382d2SGreg Kroah-Hartman for (index = 0; index < icom_adapter->numb_ports; index++) { 1671ab4382d2SGreg Kroah-Hartman icom_port = &icom_adapter->port_info[index]; 1672ab4382d2SGreg Kroah-Hartman 1673ab4382d2SGreg Kroah-Hartman if (icom_port->status == ICOM_PORT_ACTIVE) { 1674ab4382d2SGreg Kroah-Hartman dev_info(&icom_adapter->pci_dev->dev, 1675ab4382d2SGreg Kroah-Hartman "Device removed\n"); 1676ab4382d2SGreg Kroah-Hartman 1677ab4382d2SGreg Kroah-Hartman uart_remove_one_port(&icom_uart_driver, 1678ab4382d2SGreg Kroah-Hartman &icom_port->uart_port); 1679ab4382d2SGreg Kroah-Hartman 1680ab4382d2SGreg Kroah-Hartman /* be sure that DTR and RTS are dropped */ 1681ab4382d2SGreg Kroah-Hartman writeb(0x00, &icom_port->dram->osr); 1682ab4382d2SGreg Kroah-Hartman 1683ab4382d2SGreg Kroah-Hartman /* Wait 0.1 Sec for simple Init to complete */ 1684ab4382d2SGreg Kroah-Hartman msleep(100); 1685ab4382d2SGreg Kroah-Hartman 1686ab4382d2SGreg Kroah-Hartman /* Stop proccessor */ 1687ab4382d2SGreg Kroah-Hartman stop_processor(icom_port); 1688ab4382d2SGreg Kroah-Hartman 1689ab4382d2SGreg Kroah-Hartman free_port_memory(icom_port); 1690ab4382d2SGreg Kroah-Hartman } 1691ab4382d2SGreg Kroah-Hartman } 1692ab4382d2SGreg Kroah-Hartman 1693ab4382d2SGreg Kroah-Hartman free_irq(icom_adapter->pci_dev->irq, (void *) icom_adapter); 1694ab4382d2SGreg Kroah-Hartman iounmap(icom_adapter->base_addr); 1695ab4382d2SGreg Kroah-Hartman pci_release_regions(icom_adapter->pci_dev); 1696ab4382d2SGreg Kroah-Hartman icom_free_adapter(icom_adapter); 1697ab4382d2SGreg Kroah-Hartman } 1698ab4382d2SGreg Kroah-Hartman 16999671f099SBill Pemberton static int icom_probe(struct pci_dev *dev, 1700ab4382d2SGreg Kroah-Hartman const struct pci_device_id *ent) 1701ab4382d2SGreg Kroah-Hartman { 1702ab4382d2SGreg Kroah-Hartman int index; 1703ab4382d2SGreg Kroah-Hartman unsigned int command_reg; 1704ab4382d2SGreg Kroah-Hartman int retval; 1705ab4382d2SGreg Kroah-Hartman struct icom_adapter *icom_adapter; 1706ab4382d2SGreg Kroah-Hartman struct icom_port *icom_port; 1707ab4382d2SGreg Kroah-Hartman 1708ab4382d2SGreg Kroah-Hartman retval = pci_enable_device(dev); 1709ab4382d2SGreg Kroah-Hartman if (retval) { 1710ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "Device enable FAILED\n"); 1711ab4382d2SGreg Kroah-Hartman return retval; 1712ab4382d2SGreg Kroah-Hartman } 1713ab4382d2SGreg Kroah-Hartman 171401e51df5SGreg Kroah-Hartman retval = pci_request_regions(dev, "icom"); 171501e51df5SGreg Kroah-Hartman if (retval) { 1716ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "pci_request_regions FAILED\n"); 1717ab4382d2SGreg Kroah-Hartman pci_disable_device(dev); 1718ab4382d2SGreg Kroah-Hartman return retval; 1719ab4382d2SGreg Kroah-Hartman } 1720ab4382d2SGreg Kroah-Hartman 1721ab4382d2SGreg Kroah-Hartman pci_set_master(dev); 1722ab4382d2SGreg Kroah-Hartman 172301e51df5SGreg Kroah-Hartman retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg); 172401e51df5SGreg Kroah-Hartman if (retval) { 1725ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "PCI Config read FAILED\n"); 1726ee157a79SHuang Guobin goto probe_exit0; 1727ab4382d2SGreg Kroah-Hartman } 1728ab4382d2SGreg Kroah-Hartman 1729ab4382d2SGreg Kroah-Hartman pci_write_config_dword(dev, PCI_COMMAND, 1730ab4382d2SGreg Kroah-Hartman command_reg | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER 1731ab4382d2SGreg Kroah-Hartman | PCI_COMMAND_PARITY | PCI_COMMAND_SERR); 1732ab4382d2SGreg Kroah-Hartman 1733ab4382d2SGreg Kroah-Hartman if (ent->driver_data == ADAPTER_V1) { 1734ab4382d2SGreg Kroah-Hartman pci_write_config_dword(dev, 0x44, 0x8300830A); 1735ab4382d2SGreg Kroah-Hartman } else { 1736ab4382d2SGreg Kroah-Hartman pci_write_config_dword(dev, 0x44, 0x42004200); 1737ab4382d2SGreg Kroah-Hartman pci_write_config_dword(dev, 0x48, 0x42004200); 1738ab4382d2SGreg Kroah-Hartman } 1739ab4382d2SGreg Kroah-Hartman 1740ab4382d2SGreg Kroah-Hartman 1741ab4382d2SGreg Kroah-Hartman retval = icom_alloc_adapter(&icom_adapter); 1742ab4382d2SGreg Kroah-Hartman if (retval) { 1743ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "icom_alloc_adapter FAILED\n"); 1744ab4382d2SGreg Kroah-Hartman retval = -EIO; 1745ab4382d2SGreg Kroah-Hartman goto probe_exit0; 1746ab4382d2SGreg Kroah-Hartman } 1747ab4382d2SGreg Kroah-Hartman 1748ab4382d2SGreg Kroah-Hartman icom_adapter->base_addr_pci = pci_resource_start(dev, 0); 1749ab4382d2SGreg Kroah-Hartman icom_adapter->pci_dev = dev; 1750ab4382d2SGreg Kroah-Hartman icom_adapter->version = ent->driver_data; 1751ab4382d2SGreg Kroah-Hartman icom_adapter->subsystem_id = ent->subdevice; 1752ab4382d2SGreg Kroah-Hartman 1753ab4382d2SGreg Kroah-Hartman 1754ab4382d2SGreg Kroah-Hartman retval = icom_init_ports(icom_adapter); 1755ab4382d2SGreg Kroah-Hartman if (retval) { 1756ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "Port configuration failed\n"); 1757ab4382d2SGreg Kroah-Hartman goto probe_exit1; 1758ab4382d2SGreg Kroah-Hartman } 1759ab4382d2SGreg Kroah-Hartman 1760ab4382d2SGreg Kroah-Hartman icom_adapter->base_addr = pci_ioremap_bar(dev, 0); 1761ab4382d2SGreg Kroah-Hartman 1762ddcbad92SJulia Lawall if (!icom_adapter->base_addr) { 1763ddcbad92SJulia Lawall retval = -ENOMEM; 1764ab4382d2SGreg Kroah-Hartman goto probe_exit1; 1765ddcbad92SJulia Lawall } 1766ab4382d2SGreg Kroah-Hartman 1767ab4382d2SGreg Kroah-Hartman /* save off irq and request irq line */ 176801e51df5SGreg Kroah-Hartman retval = request_irq(dev->irq, icom_interrupt, IRQF_SHARED, ICOM_DRIVER_NAME, (void *)icom_adapter); 176901e51df5SGreg Kroah-Hartman if (retval) { 1770ab4382d2SGreg Kroah-Hartman goto probe_exit2; 1771ab4382d2SGreg Kroah-Hartman } 1772ab4382d2SGreg Kroah-Hartman 1773ab4382d2SGreg Kroah-Hartman retval = icom_load_ports(icom_adapter); 1774ab4382d2SGreg Kroah-Hartman 1775ab4382d2SGreg Kroah-Hartman for (index = 0; index < icom_adapter->numb_ports; index++) { 1776ab4382d2SGreg Kroah-Hartman icom_port = &icom_adapter->port_info[index]; 1777ab4382d2SGreg Kroah-Hartman 1778ab4382d2SGreg Kroah-Hartman if (icom_port->status == ICOM_PORT_ACTIVE) { 1779ab4382d2SGreg Kroah-Hartman icom_port->uart_port.irq = icom_port->adapter->pci_dev->irq; 1780ab4382d2SGreg Kroah-Hartman icom_port->uart_port.type = PORT_ICOM; 1781ab4382d2SGreg Kroah-Hartman icom_port->uart_port.iotype = UPIO_MEM; 1782ab4382d2SGreg Kroah-Hartman icom_port->uart_port.membase = 17835a7daed8SJingoo Han (unsigned char __iomem *)icom_adapter->base_addr_pci; 1784ab4382d2SGreg Kroah-Hartman icom_port->uart_port.fifosize = 16; 1785ab4382d2SGreg Kroah-Hartman icom_port->uart_port.ops = &icom_ops; 1786ab4382d2SGreg Kroah-Hartman icom_port->uart_port.line = 1787ab4382d2SGreg Kroah-Hartman icom_port->port + icom_adapter->index * 4; 1788ab4382d2SGreg Kroah-Hartman if (uart_add_one_port (&icom_uart_driver, &icom_port->uart_port)) { 1789ab4382d2SGreg Kroah-Hartman icom_port->status = ICOM_PORT_OFF; 1790ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "Device add failed\n"); 1791ab4382d2SGreg Kroah-Hartman } else 1792ab4382d2SGreg Kroah-Hartman dev_info(&dev->dev, "Device added\n"); 1793ab4382d2SGreg Kroah-Hartman } 1794ab4382d2SGreg Kroah-Hartman } 1795ab4382d2SGreg Kroah-Hartman 1796ab4382d2SGreg Kroah-Hartman kref_init(&icom_adapter->kref); 1797ab4382d2SGreg Kroah-Hartman return 0; 1798ab4382d2SGreg Kroah-Hartman 1799ab4382d2SGreg Kroah-Hartman probe_exit2: 1800ab4382d2SGreg Kroah-Hartman iounmap(icom_adapter->base_addr); 1801ab4382d2SGreg Kroah-Hartman probe_exit1: 1802ab4382d2SGreg Kroah-Hartman icom_free_adapter(icom_adapter); 1803ab4382d2SGreg Kroah-Hartman 1804ab4382d2SGreg Kroah-Hartman probe_exit0: 1805ab4382d2SGreg Kroah-Hartman pci_release_regions(dev); 1806ab4382d2SGreg Kroah-Hartman pci_disable_device(dev); 1807ab4382d2SGreg Kroah-Hartman 1808ab4382d2SGreg Kroah-Hartman return retval; 1809ab4382d2SGreg Kroah-Hartman } 1810ab4382d2SGreg Kroah-Hartman 1811ae8d8a14SBill Pemberton static void icom_remove(struct pci_dev *dev) 1812ab4382d2SGreg Kroah-Hartman { 1813ab4382d2SGreg Kroah-Hartman struct icom_adapter *icom_adapter; 1814ab4382d2SGreg Kroah-Hartman 1815e391e325SJiri Slaby list_for_each_entry(icom_adapter, &icom_adapter_head, 1816e391e325SJiri Slaby icom_adapter_entry) { 1817ab4382d2SGreg Kroah-Hartman if (icom_adapter->pci_dev == dev) { 1818ab4382d2SGreg Kroah-Hartman kref_put(&icom_adapter->kref, icom_kref_release); 1819ab4382d2SGreg Kroah-Hartman return; 1820ab4382d2SGreg Kroah-Hartman } 1821ab4382d2SGreg Kroah-Hartman } 1822ab4382d2SGreg Kroah-Hartman 1823ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "Unable to find device to remove\n"); 1824ab4382d2SGreg Kroah-Hartman } 1825ab4382d2SGreg Kroah-Hartman 1826ab4382d2SGreg Kroah-Hartman static struct pci_driver icom_pci_driver = { 1827ab4382d2SGreg Kroah-Hartman .name = ICOM_DRIVER_NAME, 1828ab4382d2SGreg Kroah-Hartman .id_table = icom_pci_table, 1829ab4382d2SGreg Kroah-Hartman .probe = icom_probe, 18302d47b716SBill Pemberton .remove = icom_remove, 1831ab4382d2SGreg Kroah-Hartman }; 1832ab4382d2SGreg Kroah-Hartman 1833ab4382d2SGreg Kroah-Hartman static int __init icom_init(void) 1834ab4382d2SGreg Kroah-Hartman { 1835ab4382d2SGreg Kroah-Hartman int ret; 1836ab4382d2SGreg Kroah-Hartman 1837ab4382d2SGreg Kroah-Hartman ret = uart_register_driver(&icom_uart_driver); 1838ab4382d2SGreg Kroah-Hartman if (ret) 1839ab4382d2SGreg Kroah-Hartman return ret; 1840ab4382d2SGreg Kroah-Hartman 1841ab4382d2SGreg Kroah-Hartman ret = pci_register_driver(&icom_pci_driver); 1842ab4382d2SGreg Kroah-Hartman 1843ab4382d2SGreg Kroah-Hartman if (ret < 0) 1844ab4382d2SGreg Kroah-Hartman uart_unregister_driver(&icom_uart_driver); 1845ab4382d2SGreg Kroah-Hartman 1846ab4382d2SGreg Kroah-Hartman return ret; 1847ab4382d2SGreg Kroah-Hartman } 1848ab4382d2SGreg Kroah-Hartman 1849ab4382d2SGreg Kroah-Hartman static void __exit icom_exit(void) 1850ab4382d2SGreg Kroah-Hartman { 1851ab4382d2SGreg Kroah-Hartman pci_unregister_driver(&icom_pci_driver); 1852ab4382d2SGreg Kroah-Hartman uart_unregister_driver(&icom_uart_driver); 1853ab4382d2SGreg Kroah-Hartman } 1854ab4382d2SGreg Kroah-Hartman 1855ab4382d2SGreg Kroah-Hartman module_init(icom_init); 1856ab4382d2SGreg Kroah-Hartman module_exit(icom_exit); 1857ab4382d2SGreg Kroah-Hartman 1858ab4382d2SGreg Kroah-Hartman MODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>"); 1859ab4382d2SGreg Kroah-Hartman MODULE_DESCRIPTION("IBM iSeries Serial IOA driver"); 1860ab4382d2SGreg Kroah-Hartman MODULE_LICENSE("GPL"); 1861ab4382d2SGreg Kroah-Hartman MODULE_FIRMWARE("icom_call_setup.bin"); 1862ab4382d2SGreg Kroah-Hartman MODULE_FIRMWARE("icom_res_dce.bin"); 1863ab4382d2SGreg Kroah-Hartman MODULE_FIRMWARE("icom_asc.bin"); 1864