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
to_icom_port(struct uart_port * port)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
trace(struct icom_port * icom_port,char * trace_pt,unsigned long trace_data)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
trace(struct icom_port * icom_port,char * trace_pt,unsigned long trace_data)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
free_port_memory(struct icom_port * icom_port)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
get_port_memory(struct icom_port * icom_port)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
stop_processor(struct icom_port * icom_port)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
start_processor(struct icom_port * icom_port)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
load_code(struct icom_port * icom_port)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
startup(struct icom_port * icom_port)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
shutdown(struct icom_port * icom_port)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
icom_write(struct uart_port * port)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);
880ab4382d2SGreg Kroah-Hartman unsigned long data_count;
881ab4382d2SGreg Kroah-Hartman unsigned char cmdReg;
882ab4382d2SGreg Kroah-Hartman unsigned long offset;
883ab4382d2SGreg Kroah-Hartman int temp_tail = port->state->xmit.tail;
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
893ab4382d2SGreg Kroah-Hartman data_count = 0;
894ab4382d2SGreg Kroah-Hartman while ((port->state->xmit.head != temp_tail) &&
895ab4382d2SGreg Kroah-Hartman (data_count <= XMIT_BUFF_SZ)) {
896ab4382d2SGreg Kroah-Hartman
897f73989f5SJiri Slaby icom_port->xmit_buf[data_count++] =
898ab4382d2SGreg Kroah-Hartman port->state->xmit.buf[temp_tail];
899ab4382d2SGreg Kroah-Hartman
900ab4382d2SGreg Kroah-Hartman temp_tail++;
901ab4382d2SGreg Kroah-Hartman temp_tail &= (UART_XMIT_SIZE - 1);
902ab4382d2SGreg Kroah-Hartman }
903ab4382d2SGreg Kroah-Hartman
904ab4382d2SGreg Kroah-Hartman if (data_count) {
905f73989f5SJiri Slaby icom_port->statStg->xmit[0].flags =
906ab4382d2SGreg Kroah-Hartman cpu_to_le16(SA_FLAGS_READY_TO_XMIT);
907f73989f5SJiri Slaby icom_port->statStg->xmit[0].leLength =
908ab4382d2SGreg Kroah-Hartman cpu_to_le16(data_count);
909ab4382d2SGreg Kroah-Hartman offset =
910f73989f5SJiri Slaby (unsigned long) &icom_port->statStg->xmit[0] -
911f73989f5SJiri Slaby (unsigned long) icom_port->statStg;
912f73989f5SJiri Slaby *icom_port->xmitRestart =
913f73989f5SJiri Slaby cpu_to_le32(icom_port->statStg_pci + offset);
914f73989f5SJiri Slaby cmdReg = readb(&icom_port->dram->CmdReg);
915ab4382d2SGreg Kroah-Hartman writeb(cmdReg | CMD_XMIT_RCV_ENABLE,
916f73989f5SJiri Slaby &icom_port->dram->CmdReg);
917f73989f5SJiri Slaby writeb(START_XMIT, &icom_port->dram->StartXmitCmd);
918f73989f5SJiri Slaby trace(icom_port, "WRITE_START", data_count);
919ab4382d2SGreg Kroah-Hartman /* write flush */
920f73989f5SJiri Slaby readb(&icom_port->dram->StartXmitCmd);
921ab4382d2SGreg Kroah-Hartman }
922ab4382d2SGreg Kroah-Hartman
923ab4382d2SGreg Kroah-Hartman return data_count;
924ab4382d2SGreg Kroah-Hartman }
925ab4382d2SGreg Kroah-Hartman
check_modem_status(struct icom_port * icom_port)926ab4382d2SGreg Kroah-Hartman static inline void check_modem_status(struct icom_port *icom_port)
927ab4382d2SGreg Kroah-Hartman {
928ab4382d2SGreg Kroah-Hartman static char old_status = 0;
929ab4382d2SGreg Kroah-Hartman char delta_status;
930ab4382d2SGreg Kroah-Hartman unsigned char status;
931ab4382d2SGreg Kroah-Hartman
932ab4382d2SGreg Kroah-Hartman spin_lock(&icom_port->uart_port.lock);
933ab4382d2SGreg Kroah-Hartman
934ab4382d2SGreg Kroah-Hartman /*modem input register */
935ab4382d2SGreg Kroah-Hartman status = readb(&icom_port->dram->isr);
936ab4382d2SGreg Kroah-Hartman trace(icom_port, "CHECK_MODEM", status);
937ab4382d2SGreg Kroah-Hartman delta_status = status ^ old_status;
938ab4382d2SGreg Kroah-Hartman if (delta_status) {
939ab4382d2SGreg Kroah-Hartman if (delta_status & ICOM_RI)
940ab4382d2SGreg Kroah-Hartman icom_port->uart_port.icount.rng++;
941ab4382d2SGreg Kroah-Hartman if (delta_status & ICOM_DSR)
942ab4382d2SGreg Kroah-Hartman icom_port->uart_port.icount.dsr++;
943ab4382d2SGreg Kroah-Hartman if (delta_status & ICOM_DCD)
944ab4382d2SGreg Kroah-Hartman uart_handle_dcd_change(&icom_port->uart_port,
945ab4382d2SGreg Kroah-Hartman delta_status & ICOM_DCD);
946ab4382d2SGreg Kroah-Hartman if (delta_status & ICOM_CTS)
947ab4382d2SGreg Kroah-Hartman uart_handle_cts_change(&icom_port->uart_port,
948ab4382d2SGreg Kroah-Hartman delta_status & ICOM_CTS);
949ab4382d2SGreg Kroah-Hartman
950ab4382d2SGreg Kroah-Hartman wake_up_interruptible(&icom_port->uart_port.state->
951ab4382d2SGreg Kroah-Hartman port.delta_msr_wait);
952ab4382d2SGreg Kroah-Hartman old_status = status;
953ab4382d2SGreg Kroah-Hartman }
954ab4382d2SGreg Kroah-Hartman spin_unlock(&icom_port->uart_port.lock);
955ab4382d2SGreg Kroah-Hartman }
956ab4382d2SGreg Kroah-Hartman
xmit_interrupt(u16 port_int_reg,struct icom_port * icom_port)957ab4382d2SGreg Kroah-Hartman static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port)
958ab4382d2SGreg Kroah-Hartman {
9597a5f86e8SJiri Slaby u16 count, i;
960ab4382d2SGreg Kroah-Hartman
961ab4382d2SGreg Kroah-Hartman if (port_int_reg & (INT_XMIT_COMPLETED)) {
962ab4382d2SGreg Kroah-Hartman trace(icom_port, "XMIT_COMPLETE", 0);
963ab4382d2SGreg Kroah-Hartman
964ab4382d2SGreg Kroah-Hartman /* clear buffer in use bit */
965ab4382d2SGreg Kroah-Hartman icom_port->statStg->xmit[0].flags &=
966ab4382d2SGreg Kroah-Hartman cpu_to_le16(~SA_FLAGS_READY_TO_XMIT);
967ab4382d2SGreg Kroah-Hartman
9687a5f86e8SJiri Slaby count = le16_to_cpu(icom_port->statStg->xmit[0].leLength);
969ab4382d2SGreg Kroah-Hartman icom_port->uart_port.icount.tx += count;
970ab4382d2SGreg Kroah-Hartman
971ab4382d2SGreg Kroah-Hartman for (i=0; i<count &&
972ab4382d2SGreg Kroah-Hartman !uart_circ_empty(&icom_port->uart_port.state->xmit); i++) {
973ab4382d2SGreg Kroah-Hartman
974ab4382d2SGreg Kroah-Hartman icom_port->uart_port.state->xmit.tail++;
975ab4382d2SGreg Kroah-Hartman icom_port->uart_port.state->xmit.tail &=
976ab4382d2SGreg Kroah-Hartman (UART_XMIT_SIZE - 1);
977ab4382d2SGreg Kroah-Hartman }
978ab4382d2SGreg Kroah-Hartman
979ab4382d2SGreg Kroah-Hartman if (!icom_write(&icom_port->uart_port))
980ab4382d2SGreg Kroah-Hartman /* activate write queue */
981ab4382d2SGreg Kroah-Hartman uart_write_wakeup(&icom_port->uart_port);
982ab4382d2SGreg Kroah-Hartman } else
983ab4382d2SGreg Kroah-Hartman trace(icom_port, "XMIT_DISABLED", 0);
984ab4382d2SGreg Kroah-Hartman }
985ab4382d2SGreg Kroah-Hartman
recv_interrupt(u16 port_int_reg,struct icom_port * icom_port)986ab4382d2SGreg Kroah-Hartman static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port)
987ab4382d2SGreg Kroah-Hartman {
988ab4382d2SGreg Kroah-Hartman short int count, rcv_buff;
98992a19f9cSJiri Slaby struct tty_port *port = &icom_port->uart_port.state->port;
9907a5f86e8SJiri Slaby u16 status;
991ab4382d2SGreg Kroah-Hartman struct uart_icount *icount;
992ab4382d2SGreg Kroah-Hartman unsigned long offset;
993ab4382d2SGreg Kroah-Hartman unsigned char flag;
994ab4382d2SGreg Kroah-Hartman
995ab4382d2SGreg Kroah-Hartman trace(icom_port, "RCV_COMPLETE", 0);
996ab4382d2SGreg Kroah-Hartman rcv_buff = icom_port->next_rcv;
997ab4382d2SGreg Kroah-Hartman
9987a5f86e8SJiri Slaby status = le16_to_cpu(icom_port->statStg->rcv[rcv_buff].flags);
999ab4382d2SGreg Kroah-Hartman while (status & SA_FL_RCV_DONE) {
1000ab4382d2SGreg Kroah-Hartman int first = -1;
1001ab4382d2SGreg Kroah-Hartman
1002ab4382d2SGreg Kroah-Hartman trace(icom_port, "FID_STATUS", status);
10037a5f86e8SJiri Slaby count = le16_to_cpu(icom_port->statStg->rcv[rcv_buff].leLength);
1004ab4382d2SGreg Kroah-Hartman
1005ab4382d2SGreg Kroah-Hartman trace(icom_port, "RCV_COUNT", count);
1006ab4382d2SGreg Kroah-Hartman
1007ab4382d2SGreg Kroah-Hartman trace(icom_port, "REAL_COUNT", count);
1008ab4382d2SGreg Kroah-Hartman
10097a5f86e8SJiri Slaby offset = le32_to_cpu(icom_port->statStg->rcv[rcv_buff].leBuffer) -
1010ab4382d2SGreg Kroah-Hartman icom_port->recv_buf_pci;
1011ab4382d2SGreg Kroah-Hartman
1012ab4382d2SGreg Kroah-Hartman /* Block copy all but the last byte as this may have status */
1013ab4382d2SGreg Kroah-Hartman if (count > 0) {
1014ab4382d2SGreg Kroah-Hartman first = icom_port->recv_buf[offset];
101505c7cd39SJiri Slaby tty_insert_flip_string(port, icom_port->recv_buf + offset, count - 1);
1016ab4382d2SGreg Kroah-Hartman }
1017ab4382d2SGreg Kroah-Hartman
1018ab4382d2SGreg Kroah-Hartman icount = &icom_port->uart_port.icount;
1019ab4382d2SGreg Kroah-Hartman icount->rx += count;
1020ab4382d2SGreg Kroah-Hartman
1021ab4382d2SGreg Kroah-Hartman /* Break detect logic */
1022ab4382d2SGreg Kroah-Hartman if ((status & SA_FLAGS_FRAME_ERROR)
1023ab4382d2SGreg Kroah-Hartman && first == 0) {
1024ab4382d2SGreg Kroah-Hartman status &= ~SA_FLAGS_FRAME_ERROR;
1025ab4382d2SGreg Kroah-Hartman status |= SA_FLAGS_BREAK_DET;
1026ab4382d2SGreg Kroah-Hartman trace(icom_port, "BREAK_DET", 0);
1027ab4382d2SGreg Kroah-Hartman }
1028ab4382d2SGreg Kroah-Hartman
1029ab4382d2SGreg Kroah-Hartman flag = TTY_NORMAL;
1030ab4382d2SGreg Kroah-Hartman
1031ab4382d2SGreg Kroah-Hartman if (status &
1032ab4382d2SGreg Kroah-Hartman (SA_FLAGS_BREAK_DET | SA_FLAGS_PARITY_ERROR |
1033ab4382d2SGreg Kroah-Hartman SA_FLAGS_FRAME_ERROR | SA_FLAGS_OVERRUN)) {
1034ab4382d2SGreg Kroah-Hartman
1035ab4382d2SGreg Kroah-Hartman if (status & SA_FLAGS_BREAK_DET)
1036ab4382d2SGreg Kroah-Hartman icount->brk++;
1037ab4382d2SGreg Kroah-Hartman if (status & SA_FLAGS_PARITY_ERROR)
1038ab4382d2SGreg Kroah-Hartman icount->parity++;
1039ab4382d2SGreg Kroah-Hartman if (status & SA_FLAGS_FRAME_ERROR)
1040ab4382d2SGreg Kroah-Hartman icount->frame++;
1041ab4382d2SGreg Kroah-Hartman if (status & SA_FLAGS_OVERRUN)
1042ab4382d2SGreg Kroah-Hartman icount->overrun++;
1043ab4382d2SGreg Kroah-Hartman
1044ab4382d2SGreg Kroah-Hartman /*
1045ab4382d2SGreg Kroah-Hartman * Now check to see if character should be
1046ab4382d2SGreg Kroah-Hartman * ignored, and mask off conditions which
1047ab4382d2SGreg Kroah-Hartman * should be ignored.
1048ab4382d2SGreg Kroah-Hartman */
1049ab4382d2SGreg Kroah-Hartman if (status & icom_port->ignore_status_mask) {
1050ab4382d2SGreg Kroah-Hartman trace(icom_port, "IGNORE_CHAR", 0);
1051ab4382d2SGreg Kroah-Hartman goto ignore_char;
1052ab4382d2SGreg Kroah-Hartman }
1053ab4382d2SGreg Kroah-Hartman
1054ab4382d2SGreg Kroah-Hartman status &= icom_port->read_status_mask;
1055ab4382d2SGreg Kroah-Hartman
1056ab4382d2SGreg Kroah-Hartman if (status & SA_FLAGS_BREAK_DET) {
1057ab4382d2SGreg Kroah-Hartman flag = TTY_BREAK;
1058ab4382d2SGreg Kroah-Hartman } else if (status & SA_FLAGS_PARITY_ERROR) {
1059ab4382d2SGreg Kroah-Hartman trace(icom_port, "PARITY_ERROR", 0);
1060ab4382d2SGreg Kroah-Hartman flag = TTY_PARITY;
1061ab4382d2SGreg Kroah-Hartman } else if (status & SA_FLAGS_FRAME_ERROR)
1062ab4382d2SGreg Kroah-Hartman flag = TTY_FRAME;
1063ab4382d2SGreg Kroah-Hartman
1064ab4382d2SGreg Kroah-Hartman }
1065ab4382d2SGreg Kroah-Hartman
106692a19f9cSJiri Slaby tty_insert_flip_char(port, *(icom_port->recv_buf + offset + count - 1), flag);
1067ab4382d2SGreg Kroah-Hartman
1068ab4382d2SGreg Kroah-Hartman if (status & SA_FLAGS_OVERRUN)
1069ab4382d2SGreg Kroah-Hartman /*
1070ab4382d2SGreg Kroah-Hartman * Overrun is special, since it's
1071ab4382d2SGreg Kroah-Hartman * reported immediately, and doesn't
1072ab4382d2SGreg Kroah-Hartman * affect the current character
1073ab4382d2SGreg Kroah-Hartman */
107492a19f9cSJiri Slaby tty_insert_flip_char(port, 0, TTY_OVERRUN);
1075ab4382d2SGreg Kroah-Hartman ignore_char:
1076ab4382d2SGreg Kroah-Hartman icom_port->statStg->rcv[rcv_buff].flags = 0;
1077ab4382d2SGreg Kroah-Hartman icom_port->statStg->rcv[rcv_buff].leLength = 0;
1078ab4382d2SGreg Kroah-Hartman icom_port->statStg->rcv[rcv_buff].WorkingLength =
10797a5f86e8SJiri Slaby cpu_to_le16(RCV_BUFF_SZ);
1080ab4382d2SGreg Kroah-Hartman
1081ab4382d2SGreg Kroah-Hartman rcv_buff++;
1082ab4382d2SGreg Kroah-Hartman if (rcv_buff == NUM_RBUFFS)
1083ab4382d2SGreg Kroah-Hartman rcv_buff = 0;
1084ab4382d2SGreg Kroah-Hartman
10857a5f86e8SJiri Slaby status = le16_to_cpu(icom_port->statStg->rcv[rcv_buff].flags);
1086ab4382d2SGreg Kroah-Hartman }
1087ab4382d2SGreg Kroah-Hartman icom_port->next_rcv = rcv_buff;
10885faf75d7SViresh Kumar
10892e124b4aSJiri Slaby tty_flip_buffer_push(port);
1090ab4382d2SGreg Kroah-Hartman }
1091ab4382d2SGreg Kroah-Hartman
process_interrupt(u16 port_int_reg,struct icom_port * icom_port)1092ab4382d2SGreg Kroah-Hartman static void process_interrupt(u16 port_int_reg,
1093ab4382d2SGreg Kroah-Hartman struct icom_port *icom_port)
1094ab4382d2SGreg Kroah-Hartman {
1095ab4382d2SGreg Kroah-Hartman
1096ab4382d2SGreg Kroah-Hartman spin_lock(&icom_port->uart_port.lock);
1097ab4382d2SGreg Kroah-Hartman trace(icom_port, "INTERRUPT", port_int_reg);
1098ab4382d2SGreg Kroah-Hartman
1099ab4382d2SGreg Kroah-Hartman if (port_int_reg & (INT_XMIT_COMPLETED | INT_XMIT_DISABLED))
1100ab4382d2SGreg Kroah-Hartman xmit_interrupt(port_int_reg, icom_port);
1101ab4382d2SGreg Kroah-Hartman
1102ab4382d2SGreg Kroah-Hartman if (port_int_reg & INT_RCV_COMPLETED)
1103ab4382d2SGreg Kroah-Hartman recv_interrupt(port_int_reg, icom_port);
1104ab4382d2SGreg Kroah-Hartman
1105ab4382d2SGreg Kroah-Hartman spin_unlock(&icom_port->uart_port.lock);
1106ab4382d2SGreg Kroah-Hartman }
1107ab4382d2SGreg Kroah-Hartman
icom_interrupt(int irq,void * dev_id)1108ab4382d2SGreg Kroah-Hartman static irqreturn_t icom_interrupt(int irq, void *dev_id)
1109ab4382d2SGreg Kroah-Hartman {
1110ab4382d2SGreg Kroah-Hartman void __iomem * int_reg;
1111ab4382d2SGreg Kroah-Hartman u32 adapter_interrupts;
1112ab4382d2SGreg Kroah-Hartman u16 port_int_reg;
1113ab4382d2SGreg Kroah-Hartman struct icom_adapter *icom_adapter;
1114ab4382d2SGreg Kroah-Hartman struct icom_port *icom_port;
1115ab4382d2SGreg Kroah-Hartman
1116ab4382d2SGreg Kroah-Hartman /* find icom_port for this interrupt */
1117ab4382d2SGreg Kroah-Hartman icom_adapter = (struct icom_adapter *) dev_id;
1118ab4382d2SGreg Kroah-Hartman
1119ab4382d2SGreg Kroah-Hartman if (icom_adapter->version == ADAPTER_V2) {
1120ab4382d2SGreg Kroah-Hartman int_reg = icom_adapter->base_addr + 0x8024;
1121ab4382d2SGreg Kroah-Hartman
1122ab4382d2SGreg Kroah-Hartman adapter_interrupts = readl(int_reg);
1123ab4382d2SGreg Kroah-Hartman
1124ab4382d2SGreg Kroah-Hartman if (adapter_interrupts & 0x00003FFF) {
1125ab4382d2SGreg Kroah-Hartman /* port 2 interrupt, NOTE: for all ADAPTER_V2, port 2 will be active */
1126ab4382d2SGreg Kroah-Hartman icom_port = &icom_adapter->port_info[2];
1127ab4382d2SGreg Kroah-Hartman port_int_reg = (u16) adapter_interrupts;
1128ab4382d2SGreg Kroah-Hartman process_interrupt(port_int_reg, icom_port);
1129ab4382d2SGreg Kroah-Hartman check_modem_status(icom_port);
1130ab4382d2SGreg Kroah-Hartman }
1131ab4382d2SGreg Kroah-Hartman if (adapter_interrupts & 0x3FFF0000) {
1132ab4382d2SGreg Kroah-Hartman /* port 3 interrupt */
1133ab4382d2SGreg Kroah-Hartman icom_port = &icom_adapter->port_info[3];
1134ab4382d2SGreg Kroah-Hartman if (icom_port->status == ICOM_PORT_ACTIVE) {
1135ab4382d2SGreg Kroah-Hartman port_int_reg =
1136ab4382d2SGreg Kroah-Hartman (u16) (adapter_interrupts >> 16);
1137ab4382d2SGreg Kroah-Hartman process_interrupt(port_int_reg, icom_port);
1138ab4382d2SGreg Kroah-Hartman check_modem_status(icom_port);
1139ab4382d2SGreg Kroah-Hartman }
1140ab4382d2SGreg Kroah-Hartman }
1141ab4382d2SGreg Kroah-Hartman
1142ab4382d2SGreg Kroah-Hartman /* Clear out any pending interrupts */
1143ab4382d2SGreg Kroah-Hartman writel(adapter_interrupts, int_reg);
1144ab4382d2SGreg Kroah-Hartman
1145ab4382d2SGreg Kroah-Hartman int_reg = icom_adapter->base_addr + 0x8004;
1146ab4382d2SGreg Kroah-Hartman } else {
1147ab4382d2SGreg Kroah-Hartman int_reg = icom_adapter->base_addr + 0x4004;
1148ab4382d2SGreg Kroah-Hartman }
1149ab4382d2SGreg Kroah-Hartman
1150ab4382d2SGreg Kroah-Hartman adapter_interrupts = readl(int_reg);
1151ab4382d2SGreg Kroah-Hartman
1152ab4382d2SGreg Kroah-Hartman if (adapter_interrupts & 0x00003FFF) {
1153ab4382d2SGreg Kroah-Hartman /* port 0 interrupt, NOTE: for all adapters, port 0 will be active */
1154ab4382d2SGreg Kroah-Hartman icom_port = &icom_adapter->port_info[0];
1155ab4382d2SGreg Kroah-Hartman port_int_reg = (u16) adapter_interrupts;
1156ab4382d2SGreg Kroah-Hartman process_interrupt(port_int_reg, icom_port);
1157ab4382d2SGreg Kroah-Hartman check_modem_status(icom_port);
1158ab4382d2SGreg Kroah-Hartman }
1159ab4382d2SGreg Kroah-Hartman if (adapter_interrupts & 0x3FFF0000) {
1160ab4382d2SGreg Kroah-Hartman /* port 1 interrupt */
1161ab4382d2SGreg Kroah-Hartman icom_port = &icom_adapter->port_info[1];
1162ab4382d2SGreg Kroah-Hartman if (icom_port->status == ICOM_PORT_ACTIVE) {
1163ab4382d2SGreg Kroah-Hartman port_int_reg = (u16) (adapter_interrupts >> 16);
1164ab4382d2SGreg Kroah-Hartman process_interrupt(port_int_reg, icom_port);
1165ab4382d2SGreg Kroah-Hartman check_modem_status(icom_port);
1166ab4382d2SGreg Kroah-Hartman }
1167ab4382d2SGreg Kroah-Hartman }
1168ab4382d2SGreg Kroah-Hartman
1169ab4382d2SGreg Kroah-Hartman /* Clear out any pending interrupts */
1170ab4382d2SGreg Kroah-Hartman writel(adapter_interrupts, int_reg);
1171ab4382d2SGreg Kroah-Hartman
1172ab4382d2SGreg Kroah-Hartman /* flush the write */
1173ab4382d2SGreg Kroah-Hartman adapter_interrupts = readl(int_reg);
1174ab4382d2SGreg Kroah-Hartman
1175ab4382d2SGreg Kroah-Hartman return IRQ_HANDLED;
1176ab4382d2SGreg Kroah-Hartman }
1177ab4382d2SGreg Kroah-Hartman
1178ab4382d2SGreg Kroah-Hartman /*
1179ab4382d2SGreg Kroah-Hartman * ------------------------------------------------------------------
1180ab4382d2SGreg Kroah-Hartman * Begin serial-core API
1181ab4382d2SGreg Kroah-Hartman * ------------------------------------------------------------------
1182ab4382d2SGreg Kroah-Hartman */
icom_tx_empty(struct uart_port * port)1183ab4382d2SGreg Kroah-Hartman static unsigned int icom_tx_empty(struct uart_port *port)
1184ab4382d2SGreg Kroah-Hartman {
1185f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port);
1186ab4382d2SGreg Kroah-Hartman int ret;
1187ab4382d2SGreg Kroah-Hartman unsigned long flags;
1188ab4382d2SGreg Kroah-Hartman
1189ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&port->lock, flags);
11907a5f86e8SJiri Slaby if (le16_to_cpu(icom_port->statStg->xmit[0].flags) &
1191ab4382d2SGreg Kroah-Hartman SA_FLAGS_READY_TO_XMIT)
1192ab4382d2SGreg Kroah-Hartman ret = TIOCSER_TEMT;
1193ab4382d2SGreg Kroah-Hartman else
1194ab4382d2SGreg Kroah-Hartman ret = 0;
1195ab4382d2SGreg Kroah-Hartman
1196ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&port->lock, flags);
1197ab4382d2SGreg Kroah-Hartman return ret;
1198ab4382d2SGreg Kroah-Hartman }
1199ab4382d2SGreg Kroah-Hartman
icom_set_mctrl(struct uart_port * port,unsigned int mctrl)1200ab4382d2SGreg Kroah-Hartman static void icom_set_mctrl(struct uart_port *port, unsigned int mctrl)
1201ab4382d2SGreg Kroah-Hartman {
1202f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port);
1203ab4382d2SGreg Kroah-Hartman unsigned char local_osr;
1204ab4382d2SGreg Kroah-Hartman
1205f73989f5SJiri Slaby trace(icom_port, "SET_MODEM", 0);
1206f73989f5SJiri Slaby local_osr = readb(&icom_port->dram->osr);
1207ab4382d2SGreg Kroah-Hartman
1208ab4382d2SGreg Kroah-Hartman if (mctrl & TIOCM_RTS) {
1209f73989f5SJiri Slaby trace(icom_port, "RAISE_RTS", 0);
1210ab4382d2SGreg Kroah-Hartman local_osr |= ICOM_RTS;
1211ab4382d2SGreg Kroah-Hartman } else {
1212f73989f5SJiri Slaby trace(icom_port, "LOWER_RTS", 0);
1213ab4382d2SGreg Kroah-Hartman local_osr &= ~ICOM_RTS;
1214ab4382d2SGreg Kroah-Hartman }
1215ab4382d2SGreg Kroah-Hartman
1216ab4382d2SGreg Kroah-Hartman if (mctrl & TIOCM_DTR) {
1217f73989f5SJiri Slaby trace(icom_port, "RAISE_DTR", 0);
1218ab4382d2SGreg Kroah-Hartman local_osr |= ICOM_DTR;
1219ab4382d2SGreg Kroah-Hartman } else {
1220f73989f5SJiri Slaby trace(icom_port, "LOWER_DTR", 0);
1221ab4382d2SGreg Kroah-Hartman local_osr &= ~ICOM_DTR;
1222ab4382d2SGreg Kroah-Hartman }
1223ab4382d2SGreg Kroah-Hartman
1224f73989f5SJiri Slaby writeb(local_osr, &icom_port->dram->osr);
1225ab4382d2SGreg Kroah-Hartman }
1226ab4382d2SGreg Kroah-Hartman
icom_get_mctrl(struct uart_port * port)1227ab4382d2SGreg Kroah-Hartman static unsigned int icom_get_mctrl(struct uart_port *port)
1228ab4382d2SGreg Kroah-Hartman {
1229f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port);
1230ab4382d2SGreg Kroah-Hartman unsigned char status;
1231ab4382d2SGreg Kroah-Hartman unsigned int result;
1232ab4382d2SGreg Kroah-Hartman
1233f73989f5SJiri Slaby trace(icom_port, "GET_MODEM", 0);
1234ab4382d2SGreg Kroah-Hartman
1235f73989f5SJiri Slaby status = readb(&icom_port->dram->isr);
1236ab4382d2SGreg Kroah-Hartman
1237ab4382d2SGreg Kroah-Hartman result = ((status & ICOM_DCD) ? TIOCM_CAR : 0)
1238ab4382d2SGreg Kroah-Hartman | ((status & ICOM_RI) ? TIOCM_RNG : 0)
1239ab4382d2SGreg Kroah-Hartman | ((status & ICOM_DSR) ? TIOCM_DSR : 0)
1240ab4382d2SGreg Kroah-Hartman | ((status & ICOM_CTS) ? TIOCM_CTS : 0);
1241ab4382d2SGreg Kroah-Hartman return result;
1242ab4382d2SGreg Kroah-Hartman }
1243ab4382d2SGreg Kroah-Hartman
icom_stop_tx(struct uart_port * port)1244ab4382d2SGreg Kroah-Hartman static void icom_stop_tx(struct uart_port *port)
1245ab4382d2SGreg Kroah-Hartman {
1246f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port);
1247ab4382d2SGreg Kroah-Hartman unsigned char cmdReg;
1248ab4382d2SGreg Kroah-Hartman
1249f73989f5SJiri Slaby trace(icom_port, "STOP", 0);
1250f73989f5SJiri Slaby cmdReg = readb(&icom_port->dram->CmdReg);
1251f73989f5SJiri Slaby writeb(cmdReg | CMD_HOLD_XMIT, &icom_port->dram->CmdReg);
1252ab4382d2SGreg Kroah-Hartman }
1253ab4382d2SGreg Kroah-Hartman
icom_start_tx(struct uart_port * port)1254ab4382d2SGreg Kroah-Hartman static void icom_start_tx(struct uart_port *port)
1255ab4382d2SGreg Kroah-Hartman {
1256f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port);
1257ab4382d2SGreg Kroah-Hartman unsigned char cmdReg;
1258ab4382d2SGreg Kroah-Hartman
1259f73989f5SJiri Slaby trace(icom_port, "START", 0);
1260f73989f5SJiri Slaby cmdReg = readb(&icom_port->dram->CmdReg);
1261ab4382d2SGreg Kroah-Hartman if ((cmdReg & CMD_HOLD_XMIT) == CMD_HOLD_XMIT)
1262ab4382d2SGreg Kroah-Hartman writeb(cmdReg & ~CMD_HOLD_XMIT,
1263f73989f5SJiri Slaby &icom_port->dram->CmdReg);
1264ab4382d2SGreg Kroah-Hartman
1265ab4382d2SGreg Kroah-Hartman icom_write(port);
1266ab4382d2SGreg Kroah-Hartman }
1267ab4382d2SGreg Kroah-Hartman
icom_send_xchar(struct uart_port * port,char ch)1268ab4382d2SGreg Kroah-Hartman static void icom_send_xchar(struct uart_port *port, char ch)
1269ab4382d2SGreg Kroah-Hartman {
1270f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port);
1271ab4382d2SGreg Kroah-Hartman unsigned char xdata;
1272ab4382d2SGreg Kroah-Hartman int index;
1273ab4382d2SGreg Kroah-Hartman unsigned long flags;
1274ab4382d2SGreg Kroah-Hartman
1275f73989f5SJiri Slaby trace(icom_port, "SEND_XCHAR", ch);
1276ab4382d2SGreg Kroah-Hartman
1277ab4382d2SGreg Kroah-Hartman /* wait .1 sec to send char */
1278ab4382d2SGreg Kroah-Hartman for (index = 0; index < 10; index++) {
1279ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&port->lock, flags);
1280f73989f5SJiri Slaby xdata = readb(&icom_port->dram->xchar);
1281ab4382d2SGreg Kroah-Hartman if (xdata == 0x00) {
1282f73989f5SJiri Slaby trace(icom_port, "QUICK_WRITE", 0);
1283f73989f5SJiri Slaby writeb(ch, &icom_port->dram->xchar);
1284ab4382d2SGreg Kroah-Hartman
1285ab4382d2SGreg Kroah-Hartman /* flush write operation */
1286f73989f5SJiri Slaby xdata = readb(&icom_port->dram->xchar);
1287ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&port->lock, flags);
1288ab4382d2SGreg Kroah-Hartman break;
1289ab4382d2SGreg Kroah-Hartman }
1290ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&port->lock, flags);
1291ab4382d2SGreg Kroah-Hartman msleep(10);
1292ab4382d2SGreg Kroah-Hartman }
1293ab4382d2SGreg Kroah-Hartman }
1294ab4382d2SGreg Kroah-Hartman
icom_stop_rx(struct uart_port * port)1295ab4382d2SGreg Kroah-Hartman static void icom_stop_rx(struct uart_port *port)
1296ab4382d2SGreg Kroah-Hartman {
1297f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port);
1298ab4382d2SGreg Kroah-Hartman unsigned char cmdReg;
1299ab4382d2SGreg Kroah-Hartman
1300f73989f5SJiri Slaby cmdReg = readb(&icom_port->dram->CmdReg);
1301f73989f5SJiri Slaby writeb(cmdReg & ~CMD_RCV_ENABLE, &icom_port->dram->CmdReg);
1302ab4382d2SGreg Kroah-Hartman }
1303ab4382d2SGreg Kroah-Hartman
icom_break(struct uart_port * port,int break_state)1304ab4382d2SGreg Kroah-Hartman static void icom_break(struct uart_port *port, int break_state)
1305ab4382d2SGreg Kroah-Hartman {
1306f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port);
1307ab4382d2SGreg Kroah-Hartman unsigned char cmdReg;
1308ab4382d2SGreg Kroah-Hartman unsigned long flags;
1309ab4382d2SGreg Kroah-Hartman
1310ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&port->lock, flags);
1311f73989f5SJiri Slaby trace(icom_port, "BREAK", 0);
1312f73989f5SJiri Slaby cmdReg = readb(&icom_port->dram->CmdReg);
1313ab4382d2SGreg Kroah-Hartman if (break_state == -1) {
1314f73989f5SJiri Slaby writeb(cmdReg | CMD_SND_BREAK, &icom_port->dram->CmdReg);
1315ab4382d2SGreg Kroah-Hartman } else {
1316f73989f5SJiri Slaby writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg);
1317ab4382d2SGreg Kroah-Hartman }
1318ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&port->lock, flags);
1319ab4382d2SGreg Kroah-Hartman }
1320ab4382d2SGreg Kroah-Hartman
icom_open(struct uart_port * port)1321ab4382d2SGreg Kroah-Hartman static int icom_open(struct uart_port *port)
1322ab4382d2SGreg Kroah-Hartman {
1323f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port);
1324ab4382d2SGreg Kroah-Hartman int retval;
1325ab4382d2SGreg Kroah-Hartman
1326f73989f5SJiri Slaby kref_get(&icom_port->adapter->kref);
1327f73989f5SJiri Slaby retval = startup(icom_port);
1328ab4382d2SGreg Kroah-Hartman
1329ab4382d2SGreg Kroah-Hartman if (retval) {
1330f73989f5SJiri Slaby kref_put(&icom_port->adapter->kref, icom_kref_release);
1331f73989f5SJiri Slaby trace(icom_port, "STARTUP_ERROR", 0);
1332ab4382d2SGreg Kroah-Hartman return retval;
1333ab4382d2SGreg Kroah-Hartman }
1334ab4382d2SGreg Kroah-Hartman
1335ab4382d2SGreg Kroah-Hartman return 0;
1336ab4382d2SGreg Kroah-Hartman }
1337ab4382d2SGreg Kroah-Hartman
icom_close(struct uart_port * port)1338ab4382d2SGreg Kroah-Hartman static void icom_close(struct uart_port *port)
1339ab4382d2SGreg Kroah-Hartman {
1340f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port);
1341ab4382d2SGreg Kroah-Hartman unsigned char cmdReg;
1342ab4382d2SGreg Kroah-Hartman
1343f73989f5SJiri Slaby trace(icom_port, "CLOSE", 0);
1344ab4382d2SGreg Kroah-Hartman
1345ab4382d2SGreg Kroah-Hartman /* stop receiver */
1346f73989f5SJiri Slaby cmdReg = readb(&icom_port->dram->CmdReg);
1347f73989f5SJiri Slaby writeb(cmdReg & ~CMD_RCV_ENABLE, &icom_port->dram->CmdReg);
1348ab4382d2SGreg Kroah-Hartman
1349f73989f5SJiri Slaby shutdown(icom_port);
1350ab4382d2SGreg Kroah-Hartman
1351f73989f5SJiri Slaby kref_put(&icom_port->adapter->kref, icom_kref_release);
1352ab4382d2SGreg Kroah-Hartman }
1353ab4382d2SGreg Kroah-Hartman
icom_set_termios(struct uart_port * port,struct ktermios * termios,const struct ktermios * old_termios)1354*bec5b814SIlpo Järvinen static void icom_set_termios(struct uart_port *port, struct ktermios *termios,
1355*bec5b814SIlpo Järvinen const struct ktermios *old_termios)
1356ab4382d2SGreg Kroah-Hartman {
1357f73989f5SJiri Slaby struct icom_port *icom_port = to_icom_port(port);
1358ab4382d2SGreg Kroah-Hartman int baud;
1359ab4382d2SGreg Kroah-Hartman unsigned cflag, iflag;
1360ab4382d2SGreg Kroah-Hartman char new_config2;
1361ab4382d2SGreg Kroah-Hartman char new_config3 = 0;
1362ab4382d2SGreg Kroah-Hartman char tmp_byte;
1363ab4382d2SGreg Kroah-Hartman int index;
1364ab4382d2SGreg Kroah-Hartman int rcv_buff, xmit_buff;
1365ab4382d2SGreg Kroah-Hartman unsigned long offset;
1366ab4382d2SGreg Kroah-Hartman unsigned long flags;
1367ab4382d2SGreg Kroah-Hartman
1368ab4382d2SGreg Kroah-Hartman spin_lock_irqsave(&port->lock, flags);
1369f73989f5SJiri Slaby trace(icom_port, "CHANGE_SPEED", 0);
1370ab4382d2SGreg Kroah-Hartman
1371ab4382d2SGreg Kroah-Hartman cflag = termios->c_cflag;
1372ab4382d2SGreg Kroah-Hartman iflag = termios->c_iflag;
1373ab4382d2SGreg Kroah-Hartman
1374ab4382d2SGreg Kroah-Hartman new_config2 = ICOM_ACFG_DRIVE1;
1375ab4382d2SGreg Kroah-Hartman
1376ab4382d2SGreg Kroah-Hartman /* byte size and parity */
1377ab4382d2SGreg Kroah-Hartman switch (cflag & CSIZE) {
1378ab4382d2SGreg Kroah-Hartman case CS5: /* 5 bits/char */
1379ab4382d2SGreg Kroah-Hartman new_config2 |= ICOM_ACFG_5BPC;
1380ab4382d2SGreg Kroah-Hartman break;
1381ab4382d2SGreg Kroah-Hartman case CS6: /* 6 bits/char */
1382ab4382d2SGreg Kroah-Hartman new_config2 |= ICOM_ACFG_6BPC;
1383ab4382d2SGreg Kroah-Hartman break;
1384ab4382d2SGreg Kroah-Hartman case CS7: /* 7 bits/char */
1385ab4382d2SGreg Kroah-Hartman new_config2 |= ICOM_ACFG_7BPC;
1386ab4382d2SGreg Kroah-Hartman break;
1387ab4382d2SGreg Kroah-Hartman case CS8: /* 8 bits/char */
1388ab4382d2SGreg Kroah-Hartman new_config2 |= ICOM_ACFG_8BPC;
1389ab4382d2SGreg Kroah-Hartman break;
1390ab4382d2SGreg Kroah-Hartman default:
1391ab4382d2SGreg Kroah-Hartman break;
1392ab4382d2SGreg Kroah-Hartman }
1393ab4382d2SGreg Kroah-Hartman if (cflag & CSTOPB) {
1394ab4382d2SGreg Kroah-Hartman /* 2 stop bits */
1395ab4382d2SGreg Kroah-Hartman new_config2 |= ICOM_ACFG_2STOP_BIT;
1396ab4382d2SGreg Kroah-Hartman }
1397ab4382d2SGreg Kroah-Hartman if (cflag & PARENB) {
1398ab4382d2SGreg Kroah-Hartman /* parity bit enabled */
1399ab4382d2SGreg Kroah-Hartman new_config2 |= ICOM_ACFG_PARITY_ENAB;
1400f73989f5SJiri Slaby trace(icom_port, "PARENB", 0);
1401ab4382d2SGreg Kroah-Hartman }
1402ab4382d2SGreg Kroah-Hartman if (cflag & PARODD) {
1403ab4382d2SGreg Kroah-Hartman /* odd parity */
1404ab4382d2SGreg Kroah-Hartman new_config2 |= ICOM_ACFG_PARITY_ODD;
1405f73989f5SJiri Slaby trace(icom_port, "PARODD", 0);
1406ab4382d2SGreg Kroah-Hartman }
1407ab4382d2SGreg Kroah-Hartman
1408ab4382d2SGreg Kroah-Hartman /* Determine divisor based on baud rate */
1409ab4382d2SGreg Kroah-Hartman baud = uart_get_baud_rate(port, termios, old_termios,
1410ab4382d2SGreg Kroah-Hartman icom_acfg_baud[0],
1411ab4382d2SGreg Kroah-Hartman icom_acfg_baud[BAUD_TABLE_LIMIT]);
1412ab4382d2SGreg Kroah-Hartman if (!baud)
1413ab4382d2SGreg Kroah-Hartman baud = 9600; /* B0 transition handled in rs_set_termios */
1414ab4382d2SGreg Kroah-Hartman
1415ab4382d2SGreg Kroah-Hartman for (index = 0; index < BAUD_TABLE_LIMIT; index++) {
1416ab4382d2SGreg Kroah-Hartman if (icom_acfg_baud[index] == baud) {
1417ab4382d2SGreg Kroah-Hartman new_config3 = index;
1418ab4382d2SGreg Kroah-Hartman break;
1419ab4382d2SGreg Kroah-Hartman }
1420ab4382d2SGreg Kroah-Hartman }
1421ab4382d2SGreg Kroah-Hartman
1422ab4382d2SGreg Kroah-Hartman uart_update_timeout(port, cflag, baud);
1423ab4382d2SGreg Kroah-Hartman
1424ab4382d2SGreg Kroah-Hartman /* CTS flow control flag and modem status interrupts */
1425f73989f5SJiri Slaby tmp_byte = readb(&(icom_port->dram->HDLCConfigReg));
1426ab4382d2SGreg Kroah-Hartman if (cflag & CRTSCTS)
1427ab4382d2SGreg Kroah-Hartman tmp_byte |= HDLC_HDW_FLOW;
1428ab4382d2SGreg Kroah-Hartman else
1429ab4382d2SGreg Kroah-Hartman tmp_byte &= ~HDLC_HDW_FLOW;
1430f73989f5SJiri Slaby writeb(tmp_byte, &(icom_port->dram->HDLCConfigReg));
1431ab4382d2SGreg Kroah-Hartman
1432ab4382d2SGreg Kroah-Hartman /*
1433ab4382d2SGreg Kroah-Hartman * Set up parity check flag
1434ab4382d2SGreg Kroah-Hartman */
1435f73989f5SJiri Slaby icom_port->read_status_mask = SA_FLAGS_OVERRUN | SA_FL_RCV_DONE;
1436ab4382d2SGreg Kroah-Hartman if (iflag & INPCK)
1437f73989f5SJiri Slaby icom_port->read_status_mask |=
1438ab4382d2SGreg Kroah-Hartman SA_FLAGS_FRAME_ERROR | SA_FLAGS_PARITY_ERROR;
1439ab4382d2SGreg Kroah-Hartman
1440ab4382d2SGreg Kroah-Hartman if ((iflag & BRKINT) || (iflag & PARMRK))
1441f73989f5SJiri Slaby icom_port->read_status_mask |= SA_FLAGS_BREAK_DET;
1442ab4382d2SGreg Kroah-Hartman
1443ab4382d2SGreg Kroah-Hartman /*
1444ab4382d2SGreg Kroah-Hartman * Characters to ignore
1445ab4382d2SGreg Kroah-Hartman */
1446f73989f5SJiri Slaby icom_port->ignore_status_mask = 0;
1447ab4382d2SGreg Kroah-Hartman if (iflag & IGNPAR)
1448f73989f5SJiri Slaby icom_port->ignore_status_mask |=
1449ab4382d2SGreg Kroah-Hartman SA_FLAGS_PARITY_ERROR | SA_FLAGS_FRAME_ERROR;
1450ab4382d2SGreg Kroah-Hartman if (iflag & IGNBRK) {
1451f73989f5SJiri Slaby icom_port->ignore_status_mask |= SA_FLAGS_BREAK_DET;
1452ab4382d2SGreg Kroah-Hartman /*
1453ab4382d2SGreg Kroah-Hartman * If we're ignore parity and break indicators, ignore
1454ab4382d2SGreg Kroah-Hartman * overruns too. (For real raw support).
1455ab4382d2SGreg Kroah-Hartman */
1456ab4382d2SGreg Kroah-Hartman if (iflag & IGNPAR)
1457f73989f5SJiri Slaby icom_port->ignore_status_mask |= SA_FLAGS_OVERRUN;
1458ab4382d2SGreg Kroah-Hartman }
1459ab4382d2SGreg Kroah-Hartman
1460ab4382d2SGreg Kroah-Hartman /*
1461ab4382d2SGreg Kroah-Hartman * !!! ignore all characters if CREAD is not set
1462ab4382d2SGreg Kroah-Hartman */
1463ab4382d2SGreg Kroah-Hartman if ((cflag & CREAD) == 0)
1464f73989f5SJiri Slaby icom_port->ignore_status_mask |= SA_FL_RCV_DONE;
1465ab4382d2SGreg Kroah-Hartman
1466ab4382d2SGreg Kroah-Hartman /* Turn off Receiver to prepare for reset */
1467f73989f5SJiri Slaby writeb(CMD_RCV_DISABLE, &icom_port->dram->CmdReg);
1468ab4382d2SGreg Kroah-Hartman
1469ab4382d2SGreg Kroah-Hartman for (index = 0; index < 10; index++) {
1470f73989f5SJiri Slaby if (readb(&icom_port->dram->PrevCmdReg) == 0x00) {
1471ab4382d2SGreg Kroah-Hartman break;
1472ab4382d2SGreg Kroah-Hartman }
1473ab4382d2SGreg Kroah-Hartman }
1474ab4382d2SGreg Kroah-Hartman
1475ab4382d2SGreg Kroah-Hartman /* clear all current buffers of data */
1476ab4382d2SGreg Kroah-Hartman for (rcv_buff = 0; rcv_buff < NUM_RBUFFS; rcv_buff++) {
1477f73989f5SJiri Slaby icom_port->statStg->rcv[rcv_buff].flags = 0;
1478f73989f5SJiri Slaby icom_port->statStg->rcv[rcv_buff].leLength = 0;
1479f73989f5SJiri Slaby icom_port->statStg->rcv[rcv_buff].WorkingLength =
14807a5f86e8SJiri Slaby cpu_to_le16(RCV_BUFF_SZ);
1481ab4382d2SGreg Kroah-Hartman }
1482ab4382d2SGreg Kroah-Hartman
1483ab4382d2SGreg Kroah-Hartman for (xmit_buff = 0; xmit_buff < NUM_XBUFFS; xmit_buff++) {
1484f73989f5SJiri Slaby icom_port->statStg->xmit[xmit_buff].flags = 0;
1485ab4382d2SGreg Kroah-Hartman }
1486ab4382d2SGreg Kroah-Hartman
1487ab4382d2SGreg Kroah-Hartman /* activate changes and start xmit and receiver here */
1488ab4382d2SGreg Kroah-Hartman /* Enable the receiver */
1489f73989f5SJiri Slaby writeb(new_config3, &(icom_port->dram->async_config3));
1490f73989f5SJiri Slaby writeb(new_config2, &(icom_port->dram->async_config2));
1491f73989f5SJiri Slaby tmp_byte = readb(&(icom_port->dram->HDLCConfigReg));
1492ab4382d2SGreg Kroah-Hartman tmp_byte |= HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL;
1493f73989f5SJiri Slaby writeb(tmp_byte, &(icom_port->dram->HDLCConfigReg));
1494f73989f5SJiri Slaby writeb(0x04, &(icom_port->dram->FlagFillIdleTimer)); /* 0.5 seconds */
1495f73989f5SJiri Slaby writeb(0xFF, &(icom_port->dram->ier)); /* enable modem signal interrupts */
1496ab4382d2SGreg Kroah-Hartman
1497ab4382d2SGreg Kroah-Hartman /* reset processor */
1498f73989f5SJiri Slaby writeb(CMD_RESTART, &icom_port->dram->CmdReg);
1499ab4382d2SGreg Kroah-Hartman
1500ab4382d2SGreg Kroah-Hartman for (index = 0; index < 10; index++) {
1501f73989f5SJiri Slaby if (readb(&icom_port->dram->CmdReg) == 0x00) {
1502ab4382d2SGreg Kroah-Hartman break;
1503ab4382d2SGreg Kroah-Hartman }
1504ab4382d2SGreg Kroah-Hartman }
1505ab4382d2SGreg Kroah-Hartman
150625985edcSLucas De Marchi /* Enable Transmitter and Receiver */
1507ab4382d2SGreg Kroah-Hartman offset =
1508f73989f5SJiri Slaby (unsigned long) &icom_port->statStg->rcv[0] -
1509f73989f5SJiri Slaby (unsigned long) icom_port->statStg;
1510f73989f5SJiri Slaby writel(icom_port->statStg_pci + offset,
1511f73989f5SJiri Slaby &icom_port->dram->RcvStatusAddr);
1512f73989f5SJiri Slaby icom_port->next_rcv = 0;
1513f73989f5SJiri Slaby *icom_port->xmitRestart = 0;
1514f73989f5SJiri Slaby writel(icom_port->xmitRestart_pci,
1515f73989f5SJiri Slaby &icom_port->dram->XmitStatusAddr);
1516f73989f5SJiri Slaby trace(icom_port, "XR_ENAB", 0);
1517f73989f5SJiri Slaby writeb(CMD_XMIT_RCV_ENABLE, &icom_port->dram->CmdReg);
1518ab4382d2SGreg Kroah-Hartman
1519ab4382d2SGreg Kroah-Hartman spin_unlock_irqrestore(&port->lock, flags);
1520ab4382d2SGreg Kroah-Hartman }
1521ab4382d2SGreg Kroah-Hartman
icom_type(struct uart_port * port)1522ab4382d2SGreg Kroah-Hartman static const char *icom_type(struct uart_port *port)
1523ab4382d2SGreg Kroah-Hartman {
1524ab4382d2SGreg Kroah-Hartman return "icom";
1525ab4382d2SGreg Kroah-Hartman }
1526ab4382d2SGreg Kroah-Hartman
icom_config_port(struct uart_port * port,int flags)1527ab4382d2SGreg Kroah-Hartman static void icom_config_port(struct uart_port *port, int flags)
1528ab4382d2SGreg Kroah-Hartman {
1529ab4382d2SGreg Kroah-Hartman port->type = PORT_ICOM;
1530ab4382d2SGreg Kroah-Hartman }
1531ab4382d2SGreg Kroah-Hartman
15322331e068SBhumika Goyal static const struct uart_ops icom_ops = {
1533ab4382d2SGreg Kroah-Hartman .tx_empty = icom_tx_empty,
1534ab4382d2SGreg Kroah-Hartman .set_mctrl = icom_set_mctrl,
1535ab4382d2SGreg Kroah-Hartman .get_mctrl = icom_get_mctrl,
1536ab4382d2SGreg Kroah-Hartman .stop_tx = icom_stop_tx,
1537ab4382d2SGreg Kroah-Hartman .start_tx = icom_start_tx,
1538ab4382d2SGreg Kroah-Hartman .send_xchar = icom_send_xchar,
1539ab4382d2SGreg Kroah-Hartman .stop_rx = icom_stop_rx,
1540ab4382d2SGreg Kroah-Hartman .break_ctl = icom_break,
1541ab4382d2SGreg Kroah-Hartman .startup = icom_open,
1542ab4382d2SGreg Kroah-Hartman .shutdown = icom_close,
1543ab4382d2SGreg Kroah-Hartman .set_termios = icom_set_termios,
1544ab4382d2SGreg Kroah-Hartman .type = icom_type,
1545ab4382d2SGreg Kroah-Hartman .config_port = icom_config_port,
1546ab4382d2SGreg Kroah-Hartman };
1547ab4382d2SGreg Kroah-Hartman
1548ab4382d2SGreg Kroah-Hartman #define ICOM_CONSOLE NULL
1549ab4382d2SGreg Kroah-Hartman
1550ab4382d2SGreg Kroah-Hartman static struct uart_driver icom_uart_driver = {
1551ab4382d2SGreg Kroah-Hartman .owner = THIS_MODULE,
1552ab4382d2SGreg Kroah-Hartman .driver_name = ICOM_DRIVER_NAME,
1553ab4382d2SGreg Kroah-Hartman .dev_name = "ttyA",
1554ab4382d2SGreg Kroah-Hartman .major = ICOM_MAJOR,
1555ab4382d2SGreg Kroah-Hartman .minor = ICOM_MINOR_START,
1556ab4382d2SGreg Kroah-Hartman .nr = NR_PORTS,
1557ab4382d2SGreg Kroah-Hartman .cons = ICOM_CONSOLE,
1558ab4382d2SGreg Kroah-Hartman };
1559ab4382d2SGreg Kroah-Hartman
icom_init_ports(struct icom_adapter * icom_adapter)15609671f099SBill Pemberton static int icom_init_ports(struct icom_adapter *icom_adapter)
1561ab4382d2SGreg Kroah-Hartman {
1562ab4382d2SGreg Kroah-Hartman u32 subsystem_id = icom_adapter->subsystem_id;
1563ab4382d2SGreg Kroah-Hartman int i;
1564ab4382d2SGreg Kroah-Hartman struct icom_port *icom_port;
1565ab4382d2SGreg Kroah-Hartman
1566ab4382d2SGreg Kroah-Hartman if (icom_adapter->version == ADAPTER_V1) {
1567ab4382d2SGreg Kroah-Hartman icom_adapter->numb_ports = 2;
1568ab4382d2SGreg Kroah-Hartman
1569ab4382d2SGreg Kroah-Hartman for (i = 0; i < 2; i++) {
1570ab4382d2SGreg Kroah-Hartman icom_port = &icom_adapter->port_info[i];
1571ab4382d2SGreg Kroah-Hartman icom_port->port = i;
1572ab4382d2SGreg Kroah-Hartman icom_port->status = ICOM_PORT_ACTIVE;
1573ab4382d2SGreg Kroah-Hartman }
1574ab4382d2SGreg Kroah-Hartman } else {
1575ab4382d2SGreg Kroah-Hartman if (subsystem_id == PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL) {
1576ab4382d2SGreg Kroah-Hartman icom_adapter->numb_ports = 4;
1577ab4382d2SGreg Kroah-Hartman
1578ab4382d2SGreg Kroah-Hartman for (i = 0; i < 4; i++) {
1579ab4382d2SGreg Kroah-Hartman icom_port = &icom_adapter->port_info[i];
1580ab4382d2SGreg Kroah-Hartman
1581ab4382d2SGreg Kroah-Hartman icom_port->port = i;
1582ab4382d2SGreg Kroah-Hartman icom_port->status = ICOM_PORT_ACTIVE;
1583ab4382d2SGreg Kroah-Hartman }
1584ab4382d2SGreg Kroah-Hartman } else {
1585ab4382d2SGreg Kroah-Hartman icom_adapter->numb_ports = 4;
1586ab4382d2SGreg Kroah-Hartman
1587ab4382d2SGreg Kroah-Hartman icom_adapter->port_info[0].port = 0;
1588ab4382d2SGreg Kroah-Hartman icom_adapter->port_info[0].status = ICOM_PORT_ACTIVE;
1589ab4382d2SGreg Kroah-Hartman icom_adapter->port_info[1].status = ICOM_PORT_OFF;
1590ab4382d2SGreg Kroah-Hartman icom_adapter->port_info[2].port = 2;
1591ab4382d2SGreg Kroah-Hartman icom_adapter->port_info[2].status = ICOM_PORT_ACTIVE;
1592ab4382d2SGreg Kroah-Hartman icom_adapter->port_info[3].status = ICOM_PORT_OFF;
1593ab4382d2SGreg Kroah-Hartman }
1594ab4382d2SGreg Kroah-Hartman }
1595ab4382d2SGreg Kroah-Hartman
1596ab4382d2SGreg Kroah-Hartman return 0;
1597ab4382d2SGreg Kroah-Hartman }
1598ab4382d2SGreg Kroah-Hartman
icom_port_active(struct icom_port * icom_port,struct icom_adapter * icom_adapter,int port_num)1599ab4382d2SGreg Kroah-Hartman static void icom_port_active(struct icom_port *icom_port, struct icom_adapter *icom_adapter, int port_num)
1600ab4382d2SGreg Kroah-Hartman {
1601ab4382d2SGreg Kroah-Hartman if (icom_adapter->version == ADAPTER_V1) {
1602ab4382d2SGreg Kroah-Hartman icom_port->global_reg = icom_adapter->base_addr + 0x4000;
1603ab4382d2SGreg Kroah-Hartman icom_port->int_reg = icom_adapter->base_addr +
1604ab4382d2SGreg Kroah-Hartman 0x4004 + 2 - 2 * port_num;
1605ab4382d2SGreg Kroah-Hartman } else {
1606ab4382d2SGreg Kroah-Hartman icom_port->global_reg = icom_adapter->base_addr + 0x8000;
1607ab4382d2SGreg Kroah-Hartman if (icom_port->port < 2)
1608ab4382d2SGreg Kroah-Hartman icom_port->int_reg = icom_adapter->base_addr +
1609ab4382d2SGreg Kroah-Hartman 0x8004 + 2 - 2 * icom_port->port;
1610ab4382d2SGreg Kroah-Hartman else
1611ab4382d2SGreg Kroah-Hartman icom_port->int_reg = icom_adapter->base_addr +
1612ab4382d2SGreg Kroah-Hartman 0x8024 + 2 - 2 * (icom_port->port - 2);
1613ab4382d2SGreg Kroah-Hartman }
1614ab4382d2SGreg Kroah-Hartman }
icom_load_ports(struct icom_adapter * icom_adapter)16159671f099SBill Pemberton static int icom_load_ports(struct icom_adapter *icom_adapter)
1616ab4382d2SGreg Kroah-Hartman {
1617ab4382d2SGreg Kroah-Hartman struct icom_port *icom_port;
1618ab4382d2SGreg Kroah-Hartman int port_num;
1619ab4382d2SGreg Kroah-Hartman
1620ab4382d2SGreg Kroah-Hartman for (port_num = 0; port_num < icom_adapter->numb_ports; port_num++) {
1621ab4382d2SGreg Kroah-Hartman
1622ab4382d2SGreg Kroah-Hartman icom_port = &icom_adapter->port_info[port_num];
1623ab4382d2SGreg Kroah-Hartman
1624ab4382d2SGreg Kroah-Hartman if (icom_port->status == ICOM_PORT_ACTIVE) {
1625ab4382d2SGreg Kroah-Hartman icom_port_active(icom_port, icom_adapter, port_num);
1626ab4382d2SGreg Kroah-Hartman icom_port->dram = icom_adapter->base_addr +
1627ab4382d2SGreg Kroah-Hartman 0x2000 * icom_port->port;
1628ab4382d2SGreg Kroah-Hartman
1629ab4382d2SGreg Kroah-Hartman icom_port->adapter = icom_adapter;
1630ab4382d2SGreg Kroah-Hartman
1631ab4382d2SGreg Kroah-Hartman /* get port memory */
1632ab4382d2SGreg Kroah-Hartman if (get_port_memory(icom_port) != 0) {
1633ab4382d2SGreg Kroah-Hartman dev_err(&icom_port->adapter->pci_dev->dev,
1634ab4382d2SGreg Kroah-Hartman "Memory allocation for port FAILED\n");
1635ab4382d2SGreg Kroah-Hartman }
1636ab4382d2SGreg Kroah-Hartman }
1637ab4382d2SGreg Kroah-Hartman }
1638ab4382d2SGreg Kroah-Hartman return 0;
1639ab4382d2SGreg Kroah-Hartman }
1640ab4382d2SGreg Kroah-Hartman
icom_alloc_adapter(struct icom_adapter ** icom_adapter_ref)16419671f099SBill Pemberton static int icom_alloc_adapter(struct icom_adapter
1642ab4382d2SGreg Kroah-Hartman **icom_adapter_ref)
1643ab4382d2SGreg Kroah-Hartman {
1644ab4382d2SGreg Kroah-Hartman int adapter_count = 0;
1645ab4382d2SGreg Kroah-Hartman struct icom_adapter *icom_adapter;
1646ab4382d2SGreg Kroah-Hartman struct icom_adapter *cur_adapter_entry;
1647ab4382d2SGreg Kroah-Hartman
1648b9a129f4SZhang Yanfei icom_adapter = kzalloc(sizeof(struct icom_adapter), GFP_KERNEL);
1649ab4382d2SGreg Kroah-Hartman
1650ab4382d2SGreg Kroah-Hartman if (!icom_adapter) {
1651ab4382d2SGreg Kroah-Hartman return -ENOMEM;
1652ab4382d2SGreg Kroah-Hartman }
1653ab4382d2SGreg Kroah-Hartman
1654e391e325SJiri Slaby list_for_each_entry(cur_adapter_entry, &icom_adapter_head,
1655e391e325SJiri Slaby icom_adapter_entry) {
1656ab4382d2SGreg Kroah-Hartman if (cur_adapter_entry->index != adapter_count) {
1657ab4382d2SGreg Kroah-Hartman break;
1658ab4382d2SGreg Kroah-Hartman }
1659ab4382d2SGreg Kroah-Hartman adapter_count++;
1660ab4382d2SGreg Kroah-Hartman }
1661ab4382d2SGreg Kroah-Hartman
1662ab4382d2SGreg Kroah-Hartman icom_adapter->index = adapter_count;
1663e391e325SJiri Slaby list_add_tail(&icom_adapter->icom_adapter_entry,
1664e391e325SJiri Slaby &cur_adapter_entry->icom_adapter_entry);
1665ab4382d2SGreg Kroah-Hartman
1666ab4382d2SGreg Kroah-Hartman *icom_adapter_ref = icom_adapter;
1667ab4382d2SGreg Kroah-Hartman return 0;
1668ab4382d2SGreg Kroah-Hartman }
1669ab4382d2SGreg Kroah-Hartman
icom_free_adapter(struct icom_adapter * icom_adapter)1670ab4382d2SGreg Kroah-Hartman static void icom_free_adapter(struct icom_adapter *icom_adapter)
1671ab4382d2SGreg Kroah-Hartman {
1672ab4382d2SGreg Kroah-Hartman list_del(&icom_adapter->icom_adapter_entry);
1673ab4382d2SGreg Kroah-Hartman kfree(icom_adapter);
1674ab4382d2SGreg Kroah-Hartman }
1675ab4382d2SGreg Kroah-Hartman
icom_kref_release(struct kref * kref)16762c334f12SJiri Slaby static void icom_kref_release(struct kref *kref)
1677ab4382d2SGreg Kroah-Hartman {
16782c334f12SJiri Slaby struct icom_adapter *icom_adapter = container_of(kref,
16792c334f12SJiri Slaby struct icom_adapter, kref);
1680ab4382d2SGreg Kroah-Hartman struct icom_port *icom_port;
1681ab4382d2SGreg Kroah-Hartman int index;
1682ab4382d2SGreg Kroah-Hartman
1683ab4382d2SGreg Kroah-Hartman for (index = 0; index < icom_adapter->numb_ports; index++) {
1684ab4382d2SGreg Kroah-Hartman icom_port = &icom_adapter->port_info[index];
1685ab4382d2SGreg Kroah-Hartman
1686ab4382d2SGreg Kroah-Hartman if (icom_port->status == ICOM_PORT_ACTIVE) {
1687ab4382d2SGreg Kroah-Hartman dev_info(&icom_adapter->pci_dev->dev,
1688ab4382d2SGreg Kroah-Hartman "Device removed\n");
1689ab4382d2SGreg Kroah-Hartman
1690ab4382d2SGreg Kroah-Hartman uart_remove_one_port(&icom_uart_driver,
1691ab4382d2SGreg Kroah-Hartman &icom_port->uart_port);
1692ab4382d2SGreg Kroah-Hartman
1693ab4382d2SGreg Kroah-Hartman /* be sure that DTR and RTS are dropped */
1694ab4382d2SGreg Kroah-Hartman writeb(0x00, &icom_port->dram->osr);
1695ab4382d2SGreg Kroah-Hartman
1696ab4382d2SGreg Kroah-Hartman /* Wait 0.1 Sec for simple Init to complete */
1697ab4382d2SGreg Kroah-Hartman msleep(100);
1698ab4382d2SGreg Kroah-Hartman
1699ab4382d2SGreg Kroah-Hartman /* Stop proccessor */
1700ab4382d2SGreg Kroah-Hartman stop_processor(icom_port);
1701ab4382d2SGreg Kroah-Hartman
1702ab4382d2SGreg Kroah-Hartman free_port_memory(icom_port);
1703ab4382d2SGreg Kroah-Hartman }
1704ab4382d2SGreg Kroah-Hartman }
1705ab4382d2SGreg Kroah-Hartman
1706ab4382d2SGreg Kroah-Hartman free_irq(icom_adapter->pci_dev->irq, (void *) icom_adapter);
1707ab4382d2SGreg Kroah-Hartman iounmap(icom_adapter->base_addr);
1708ab4382d2SGreg Kroah-Hartman pci_release_regions(icom_adapter->pci_dev);
1709ab4382d2SGreg Kroah-Hartman icom_free_adapter(icom_adapter);
1710ab4382d2SGreg Kroah-Hartman }
1711ab4382d2SGreg Kroah-Hartman
icom_probe(struct pci_dev * dev,const struct pci_device_id * ent)17129671f099SBill Pemberton static int icom_probe(struct pci_dev *dev,
1713ab4382d2SGreg Kroah-Hartman const struct pci_device_id *ent)
1714ab4382d2SGreg Kroah-Hartman {
1715ab4382d2SGreg Kroah-Hartman int index;
1716ab4382d2SGreg Kroah-Hartman unsigned int command_reg;
1717ab4382d2SGreg Kroah-Hartman int retval;
1718ab4382d2SGreg Kroah-Hartman struct icom_adapter *icom_adapter;
1719ab4382d2SGreg Kroah-Hartman struct icom_port *icom_port;
1720ab4382d2SGreg Kroah-Hartman
1721ab4382d2SGreg Kroah-Hartman retval = pci_enable_device(dev);
1722ab4382d2SGreg Kroah-Hartman if (retval) {
1723ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "Device enable FAILED\n");
1724ab4382d2SGreg Kroah-Hartman return retval;
1725ab4382d2SGreg Kroah-Hartman }
1726ab4382d2SGreg Kroah-Hartman
172701e51df5SGreg Kroah-Hartman retval = pci_request_regions(dev, "icom");
172801e51df5SGreg Kroah-Hartman if (retval) {
1729ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "pci_request_regions FAILED\n");
1730ab4382d2SGreg Kroah-Hartman pci_disable_device(dev);
1731ab4382d2SGreg Kroah-Hartman return retval;
1732ab4382d2SGreg Kroah-Hartman }
1733ab4382d2SGreg Kroah-Hartman
1734ab4382d2SGreg Kroah-Hartman pci_set_master(dev);
1735ab4382d2SGreg Kroah-Hartman
173601e51df5SGreg Kroah-Hartman retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg);
173701e51df5SGreg Kroah-Hartman if (retval) {
1738ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "PCI Config read FAILED\n");
1739ee157a79SHuang Guobin goto probe_exit0;
1740ab4382d2SGreg Kroah-Hartman }
1741ab4382d2SGreg Kroah-Hartman
1742ab4382d2SGreg Kroah-Hartman pci_write_config_dword(dev, PCI_COMMAND,
1743ab4382d2SGreg Kroah-Hartman command_reg | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER
1744ab4382d2SGreg Kroah-Hartman | PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
1745ab4382d2SGreg Kroah-Hartman
1746ab4382d2SGreg Kroah-Hartman if (ent->driver_data == ADAPTER_V1) {
1747ab4382d2SGreg Kroah-Hartman pci_write_config_dword(dev, 0x44, 0x8300830A);
1748ab4382d2SGreg Kroah-Hartman } else {
1749ab4382d2SGreg Kroah-Hartman pci_write_config_dword(dev, 0x44, 0x42004200);
1750ab4382d2SGreg Kroah-Hartman pci_write_config_dword(dev, 0x48, 0x42004200);
1751ab4382d2SGreg Kroah-Hartman }
1752ab4382d2SGreg Kroah-Hartman
1753ab4382d2SGreg Kroah-Hartman
1754ab4382d2SGreg Kroah-Hartman retval = icom_alloc_adapter(&icom_adapter);
1755ab4382d2SGreg Kroah-Hartman if (retval) {
1756ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "icom_alloc_adapter FAILED\n");
1757ab4382d2SGreg Kroah-Hartman retval = -EIO;
1758ab4382d2SGreg Kroah-Hartman goto probe_exit0;
1759ab4382d2SGreg Kroah-Hartman }
1760ab4382d2SGreg Kroah-Hartman
1761ab4382d2SGreg Kroah-Hartman icom_adapter->base_addr_pci = pci_resource_start(dev, 0);
1762ab4382d2SGreg Kroah-Hartman icom_adapter->pci_dev = dev;
1763ab4382d2SGreg Kroah-Hartman icom_adapter->version = ent->driver_data;
1764ab4382d2SGreg Kroah-Hartman icom_adapter->subsystem_id = ent->subdevice;
1765ab4382d2SGreg Kroah-Hartman
1766ab4382d2SGreg Kroah-Hartman
1767ab4382d2SGreg Kroah-Hartman retval = icom_init_ports(icom_adapter);
1768ab4382d2SGreg Kroah-Hartman if (retval) {
1769ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "Port configuration failed\n");
1770ab4382d2SGreg Kroah-Hartman goto probe_exit1;
1771ab4382d2SGreg Kroah-Hartman }
1772ab4382d2SGreg Kroah-Hartman
1773ab4382d2SGreg Kroah-Hartman icom_adapter->base_addr = pci_ioremap_bar(dev, 0);
1774ab4382d2SGreg Kroah-Hartman
1775ddcbad92SJulia Lawall if (!icom_adapter->base_addr) {
1776ddcbad92SJulia Lawall retval = -ENOMEM;
1777ab4382d2SGreg Kroah-Hartman goto probe_exit1;
1778ddcbad92SJulia Lawall }
1779ab4382d2SGreg Kroah-Hartman
1780ab4382d2SGreg Kroah-Hartman /* save off irq and request irq line */
178101e51df5SGreg Kroah-Hartman retval = request_irq(dev->irq, icom_interrupt, IRQF_SHARED, ICOM_DRIVER_NAME, (void *)icom_adapter);
178201e51df5SGreg Kroah-Hartman if (retval) {
1783ab4382d2SGreg Kroah-Hartman goto probe_exit2;
1784ab4382d2SGreg Kroah-Hartman }
1785ab4382d2SGreg Kroah-Hartman
1786ab4382d2SGreg Kroah-Hartman retval = icom_load_ports(icom_adapter);
1787ab4382d2SGreg Kroah-Hartman
1788ab4382d2SGreg Kroah-Hartman for (index = 0; index < icom_adapter->numb_ports; index++) {
1789ab4382d2SGreg Kroah-Hartman icom_port = &icom_adapter->port_info[index];
1790ab4382d2SGreg Kroah-Hartman
1791ab4382d2SGreg Kroah-Hartman if (icom_port->status == ICOM_PORT_ACTIVE) {
1792ab4382d2SGreg Kroah-Hartman icom_port->uart_port.irq = icom_port->adapter->pci_dev->irq;
1793ab4382d2SGreg Kroah-Hartman icom_port->uart_port.type = PORT_ICOM;
1794ab4382d2SGreg Kroah-Hartman icom_port->uart_port.iotype = UPIO_MEM;
1795ab4382d2SGreg Kroah-Hartman icom_port->uart_port.membase =
17965a7daed8SJingoo Han (unsigned char __iomem *)icom_adapter->base_addr_pci;
1797ab4382d2SGreg Kroah-Hartman icom_port->uart_port.fifosize = 16;
1798ab4382d2SGreg Kroah-Hartman icom_port->uart_port.ops = &icom_ops;
1799ab4382d2SGreg Kroah-Hartman icom_port->uart_port.line =
1800ab4382d2SGreg Kroah-Hartman icom_port->port + icom_adapter->index * 4;
1801ab4382d2SGreg Kroah-Hartman if (uart_add_one_port (&icom_uart_driver, &icom_port->uart_port)) {
1802ab4382d2SGreg Kroah-Hartman icom_port->status = ICOM_PORT_OFF;
1803ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "Device add failed\n");
1804ab4382d2SGreg Kroah-Hartman } else
1805ab4382d2SGreg Kroah-Hartman dev_info(&dev->dev, "Device added\n");
1806ab4382d2SGreg Kroah-Hartman }
1807ab4382d2SGreg Kroah-Hartman }
1808ab4382d2SGreg Kroah-Hartman
1809ab4382d2SGreg Kroah-Hartman kref_init(&icom_adapter->kref);
1810ab4382d2SGreg Kroah-Hartman return 0;
1811ab4382d2SGreg Kroah-Hartman
1812ab4382d2SGreg Kroah-Hartman probe_exit2:
1813ab4382d2SGreg Kroah-Hartman iounmap(icom_adapter->base_addr);
1814ab4382d2SGreg Kroah-Hartman probe_exit1:
1815ab4382d2SGreg Kroah-Hartman icom_free_adapter(icom_adapter);
1816ab4382d2SGreg Kroah-Hartman
1817ab4382d2SGreg Kroah-Hartman probe_exit0:
1818ab4382d2SGreg Kroah-Hartman pci_release_regions(dev);
1819ab4382d2SGreg Kroah-Hartman pci_disable_device(dev);
1820ab4382d2SGreg Kroah-Hartman
1821ab4382d2SGreg Kroah-Hartman return retval;
1822ab4382d2SGreg Kroah-Hartman }
1823ab4382d2SGreg Kroah-Hartman
icom_remove(struct pci_dev * dev)1824ae8d8a14SBill Pemberton static void icom_remove(struct pci_dev *dev)
1825ab4382d2SGreg Kroah-Hartman {
1826ab4382d2SGreg Kroah-Hartman struct icom_adapter *icom_adapter;
1827ab4382d2SGreg Kroah-Hartman
1828e391e325SJiri Slaby list_for_each_entry(icom_adapter, &icom_adapter_head,
1829e391e325SJiri Slaby icom_adapter_entry) {
1830ab4382d2SGreg Kroah-Hartman if (icom_adapter->pci_dev == dev) {
1831ab4382d2SGreg Kroah-Hartman kref_put(&icom_adapter->kref, icom_kref_release);
1832ab4382d2SGreg Kroah-Hartman return;
1833ab4382d2SGreg Kroah-Hartman }
1834ab4382d2SGreg Kroah-Hartman }
1835ab4382d2SGreg Kroah-Hartman
1836ab4382d2SGreg Kroah-Hartman dev_err(&dev->dev, "Unable to find device to remove\n");
1837ab4382d2SGreg Kroah-Hartman }
1838ab4382d2SGreg Kroah-Hartman
1839ab4382d2SGreg Kroah-Hartman static struct pci_driver icom_pci_driver = {
1840ab4382d2SGreg Kroah-Hartman .name = ICOM_DRIVER_NAME,
1841ab4382d2SGreg Kroah-Hartman .id_table = icom_pci_table,
1842ab4382d2SGreg Kroah-Hartman .probe = icom_probe,
18432d47b716SBill Pemberton .remove = icom_remove,
1844ab4382d2SGreg Kroah-Hartman };
1845ab4382d2SGreg Kroah-Hartman
icom_init(void)1846ab4382d2SGreg Kroah-Hartman static int __init icom_init(void)
1847ab4382d2SGreg Kroah-Hartman {
1848ab4382d2SGreg Kroah-Hartman int ret;
1849ab4382d2SGreg Kroah-Hartman
1850ab4382d2SGreg Kroah-Hartman ret = uart_register_driver(&icom_uart_driver);
1851ab4382d2SGreg Kroah-Hartman if (ret)
1852ab4382d2SGreg Kroah-Hartman return ret;
1853ab4382d2SGreg Kroah-Hartman
1854ab4382d2SGreg Kroah-Hartman ret = pci_register_driver(&icom_pci_driver);
1855ab4382d2SGreg Kroah-Hartman
1856ab4382d2SGreg Kroah-Hartman if (ret < 0)
1857ab4382d2SGreg Kroah-Hartman uart_unregister_driver(&icom_uart_driver);
1858ab4382d2SGreg Kroah-Hartman
1859ab4382d2SGreg Kroah-Hartman return ret;
1860ab4382d2SGreg Kroah-Hartman }
1861ab4382d2SGreg Kroah-Hartman
icom_exit(void)1862ab4382d2SGreg Kroah-Hartman static void __exit icom_exit(void)
1863ab4382d2SGreg Kroah-Hartman {
1864ab4382d2SGreg Kroah-Hartman pci_unregister_driver(&icom_pci_driver);
1865ab4382d2SGreg Kroah-Hartman uart_unregister_driver(&icom_uart_driver);
1866ab4382d2SGreg Kroah-Hartman }
1867ab4382d2SGreg Kroah-Hartman
1868ab4382d2SGreg Kroah-Hartman module_init(icom_init);
1869ab4382d2SGreg Kroah-Hartman module_exit(icom_exit);
1870ab4382d2SGreg Kroah-Hartman
1871ab4382d2SGreg Kroah-Hartman MODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>");
1872ab4382d2SGreg Kroah-Hartman MODULE_DESCRIPTION("IBM iSeries Serial IOA driver");
1873ab4382d2SGreg Kroah-Hartman MODULE_LICENSE("GPL");
1874ab4382d2SGreg Kroah-Hartman MODULE_FIRMWARE("icom_call_setup.bin");
1875ab4382d2SGreg Kroah-Hartman MODULE_FIRMWARE("icom_res_dce.bin");
1876ab4382d2SGreg Kroah-Hartman MODULE_FIRMWARE("icom_asc.bin");
1877