xref: /OK3568_Linux_fs/kernel/drivers/tty/cyclades.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #undef	BLOCKMOVE
3*4882a593Smuzhiyun #define	Z_WAKE
4*4882a593Smuzhiyun #undef	Z_EXT_CHARS_IN_BUFFER
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun /*
7*4882a593Smuzhiyun  * This file contains the driver for the Cyclades async multiport
8*4882a593Smuzhiyun  * serial boards.
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * Initially written by Randolph Bentson <bentson@grieg.seaslug.org>.
11*4882a593Smuzhiyun  * Modified and maintained by Marcio Saito <marcio@cyclades.com>.
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  * Copyright (C) 2007-2009 Jiri Slaby <jirislaby@gmail.com>
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  * Much of the design and some of the code came from serial.c
16*4882a593Smuzhiyun  * which was copyright (C) 1991, 1992  Linus Torvalds.  It was
17*4882a593Smuzhiyun  * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
18*4882a593Smuzhiyun  * and then fixed as suggested by Michael K. Johnson 12/12/92.
19*4882a593Smuzhiyun  * Converted to pci probing and cleaned up by Jiri Slaby.
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  */
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #define CY_VERSION	"2.6"
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /* If you need to install more boards than NR_CARDS, change the constant
26*4882a593Smuzhiyun    in the definition below. No other change is necessary to support up to
27*4882a593Smuzhiyun    eight boards. Beyond that you'll have to extend cy_isa_addresses. */
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #define NR_CARDS	4
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /*
32*4882a593Smuzhiyun    If the total number of ports is larger than NR_PORTS, change this
33*4882a593Smuzhiyun    constant in the definition below. No other change is necessary to
34*4882a593Smuzhiyun    support more boards/ports. */
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun #define NR_PORTS	256
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #define ZO_V1	0
39*4882a593Smuzhiyun #define ZO_V2	1
40*4882a593Smuzhiyun #define ZE_V1	2
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #define	SERIAL_PARANOIA_CHECK
43*4882a593Smuzhiyun #undef	CY_DEBUG_OPEN
44*4882a593Smuzhiyun #undef	CY_DEBUG_THROTTLE
45*4882a593Smuzhiyun #undef	CY_DEBUG_OTHER
46*4882a593Smuzhiyun #undef	CY_DEBUG_IO
47*4882a593Smuzhiyun #undef	CY_DEBUG_COUNT
48*4882a593Smuzhiyun #undef	CY_DEBUG_DTR
49*4882a593Smuzhiyun #undef	CY_DEBUG_INTERRUPTS
50*4882a593Smuzhiyun #undef	CY_16Y_HACK
51*4882a593Smuzhiyun #undef	CY_ENABLE_MONITORING
52*4882a593Smuzhiyun #undef	CY_PCI_DEBUG
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun /*
55*4882a593Smuzhiyun  * Include section
56*4882a593Smuzhiyun  */
57*4882a593Smuzhiyun #include <linux/module.h>
58*4882a593Smuzhiyun #include <linux/errno.h>
59*4882a593Smuzhiyun #include <linux/signal.h>
60*4882a593Smuzhiyun #include <linux/sched.h>
61*4882a593Smuzhiyun #include <linux/timer.h>
62*4882a593Smuzhiyun #include <linux/interrupt.h>
63*4882a593Smuzhiyun #include <linux/tty.h>
64*4882a593Smuzhiyun #include <linux/tty_flip.h>
65*4882a593Smuzhiyun #include <linux/serial.h>
66*4882a593Smuzhiyun #include <linux/major.h>
67*4882a593Smuzhiyun #include <linux/string.h>
68*4882a593Smuzhiyun #include <linux/fcntl.h>
69*4882a593Smuzhiyun #include <linux/ptrace.h>
70*4882a593Smuzhiyun #include <linux/cyclades.h>
71*4882a593Smuzhiyun #include <linux/mm.h>
72*4882a593Smuzhiyun #include <linux/ioport.h>
73*4882a593Smuzhiyun #include <linux/init.h>
74*4882a593Smuzhiyun #include <linux/delay.h>
75*4882a593Smuzhiyun #include <linux/spinlock.h>
76*4882a593Smuzhiyun #include <linux/bitops.h>
77*4882a593Smuzhiyun #include <linux/firmware.h>
78*4882a593Smuzhiyun #include <linux/device.h>
79*4882a593Smuzhiyun #include <linux/slab.h>
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun #include <linux/io.h>
82*4882a593Smuzhiyun #include <linux/uaccess.h>
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun #include <linux/kernel.h>
85*4882a593Smuzhiyun #include <linux/pci.h>
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun #include <linux/stat.h>
88*4882a593Smuzhiyun #include <linux/proc_fs.h>
89*4882a593Smuzhiyun #include <linux/seq_file.h>
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun static void cy_send_xchar(struct tty_struct *tty, char ch);
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun #ifndef SERIAL_XMIT_SIZE
94*4882a593Smuzhiyun #define	SERIAL_XMIT_SIZE	(min(PAGE_SIZE, 4096))
95*4882a593Smuzhiyun #endif
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun /* firmware stuff */
98*4882a593Smuzhiyun #define ZL_MAX_BLOCKS	16
99*4882a593Smuzhiyun #define DRIVER_VERSION	0x02010203
100*4882a593Smuzhiyun #define RAM_SIZE 0x80000
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun enum zblock_type {
103*4882a593Smuzhiyun 	ZBLOCK_PRG = 0,
104*4882a593Smuzhiyun 	ZBLOCK_FPGA = 1
105*4882a593Smuzhiyun };
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun struct zfile_header {
108*4882a593Smuzhiyun 	char name[64];
109*4882a593Smuzhiyun 	char date[32];
110*4882a593Smuzhiyun 	char aux[32];
111*4882a593Smuzhiyun 	u32 n_config;
112*4882a593Smuzhiyun 	u32 config_offset;
113*4882a593Smuzhiyun 	u32 n_blocks;
114*4882a593Smuzhiyun 	u32 block_offset;
115*4882a593Smuzhiyun 	u32 reserved[9];
116*4882a593Smuzhiyun } __attribute__ ((packed));
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun struct zfile_config {
119*4882a593Smuzhiyun 	char name[64];
120*4882a593Smuzhiyun 	u32 mailbox;
121*4882a593Smuzhiyun 	u32 function;
122*4882a593Smuzhiyun 	u32 n_blocks;
123*4882a593Smuzhiyun 	u32 block_list[ZL_MAX_BLOCKS];
124*4882a593Smuzhiyun } __attribute__ ((packed));
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun struct zfile_block {
127*4882a593Smuzhiyun 	u32 type;
128*4882a593Smuzhiyun 	u32 file_offset;
129*4882a593Smuzhiyun 	u32 ram_offset;
130*4882a593Smuzhiyun 	u32 size;
131*4882a593Smuzhiyun } __attribute__ ((packed));
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun static struct tty_driver *cy_serial_driver;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun #ifdef CONFIG_ISA
136*4882a593Smuzhiyun /* This is the address lookup table. The driver will probe for
137*4882a593Smuzhiyun    Cyclom-Y/ISA boards at all addresses in here. If you want the
138*4882a593Smuzhiyun    driver to probe addresses at a different address, add it to
139*4882a593Smuzhiyun    this table.  If the driver is probing some other board and
140*4882a593Smuzhiyun    causing problems, remove the offending address from this table.
141*4882a593Smuzhiyun */
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun static unsigned int cy_isa_addresses[] = {
144*4882a593Smuzhiyun 	0xD0000,
145*4882a593Smuzhiyun 	0xD2000,
146*4882a593Smuzhiyun 	0xD4000,
147*4882a593Smuzhiyun 	0xD6000,
148*4882a593Smuzhiyun 	0xD8000,
149*4882a593Smuzhiyun 	0xDA000,
150*4882a593Smuzhiyun 	0xDC000,
151*4882a593Smuzhiyun 	0xDE000,
152*4882a593Smuzhiyun 	0, 0, 0, 0, 0, 0, 0, 0
153*4882a593Smuzhiyun };
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun #define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun static long maddr[NR_CARDS];
158*4882a593Smuzhiyun static int irq[NR_CARDS];
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun module_param_hw_array(maddr, long, iomem, NULL, 0);
161*4882a593Smuzhiyun module_param_hw_array(irq, int, irq, NULL, 0);
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun #endif				/* CONFIG_ISA */
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun /* This is the per-card data structure containing address, irq, number of
166*4882a593Smuzhiyun    channels, etc. This driver supports a maximum of NR_CARDS cards.
167*4882a593Smuzhiyun */
168*4882a593Smuzhiyun static struct cyclades_card cy_card[NR_CARDS];
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun static int cy_next_channel;	/* next minor available */
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun /*
173*4882a593Smuzhiyun  * This is used to look up the divisor speeds and the timeouts
174*4882a593Smuzhiyun  * We're normally limited to 15 distinct baud rates.  The extra
175*4882a593Smuzhiyun  * are accessed via settings in info->port.flags.
176*4882a593Smuzhiyun  *      0,     1,     2,     3,     4,     5,     6,     7,     8,     9,
177*4882a593Smuzhiyun  *     10,    11,    12,    13,    14,    15,    16,    17,    18,    19,
178*4882a593Smuzhiyun  *                                               HI            VHI
179*4882a593Smuzhiyun  *     20
180*4882a593Smuzhiyun  */
181*4882a593Smuzhiyun static const int baud_table[] = {
182*4882a593Smuzhiyun 	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
183*4882a593Smuzhiyun 	1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
184*4882a593Smuzhiyun 	230400, 0
185*4882a593Smuzhiyun };
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun static const char baud_co_25[] = {	/* 25 MHz clock option table */
188*4882a593Smuzhiyun 	/* value =>    00    01   02    03    04 */
189*4882a593Smuzhiyun 	/* divide by    8    32   128   512  2048 */
190*4882a593Smuzhiyun 	0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
191*4882a593Smuzhiyun 	0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
192*4882a593Smuzhiyun };
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun static const char baud_bpr_25[] = {	/* 25 MHz baud rate period table */
195*4882a593Smuzhiyun 	0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
196*4882a593Smuzhiyun 	0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
197*4882a593Smuzhiyun };
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun static const char baud_co_60[] = {	/* 60 MHz clock option table (CD1400 J) */
200*4882a593Smuzhiyun 	/* value =>    00    01   02    03    04 */
201*4882a593Smuzhiyun 	/* divide by    8    32   128   512  2048 */
202*4882a593Smuzhiyun 	0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
203*4882a593Smuzhiyun 	0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
204*4882a593Smuzhiyun 	0x00
205*4882a593Smuzhiyun };
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun static const char baud_bpr_60[] = {	/* 60 MHz baud rate period table (CD1400 J) */
208*4882a593Smuzhiyun 	0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
209*4882a593Smuzhiyun 	0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
210*4882a593Smuzhiyun 	0x21
211*4882a593Smuzhiyun };
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun static const char baud_cor3[] = {	/* receive threshold */
214*4882a593Smuzhiyun 	0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
215*4882a593Smuzhiyun 	0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07,
216*4882a593Smuzhiyun 	0x07
217*4882a593Smuzhiyun };
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun /*
220*4882a593Smuzhiyun  * The Cyclades driver implements HW flow control as any serial driver.
221*4882a593Smuzhiyun  * The cyclades_port structure member rflow and the vector rflow_thr
222*4882a593Smuzhiyun  * allows us to take advantage of a special feature in the CD1400 to avoid
223*4882a593Smuzhiyun  * data loss even when the system interrupt latency is too high. These flags
224*4882a593Smuzhiyun  * are to be used only with very special applications. Setting these flags
225*4882a593Smuzhiyun  * requires the use of a special cable (DTR and RTS reversed). In the new
226*4882a593Smuzhiyun  * CD1400-based boards (rev. 6.00 or later), there is no need for special
227*4882a593Smuzhiyun  * cables.
228*4882a593Smuzhiyun  */
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun static const char rflow_thr[] = {	/* rflow threshold */
231*4882a593Smuzhiyun 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232*4882a593Smuzhiyun 	0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
233*4882a593Smuzhiyun 	0x0a
234*4882a593Smuzhiyun };
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun /*  The Cyclom-Ye has placed the sequential chips in non-sequential
237*4882a593Smuzhiyun  *  address order.  This look-up table overcomes that problem.
238*4882a593Smuzhiyun  */
239*4882a593Smuzhiyun static const unsigned int cy_chip_offset[] = { 0x0000,
240*4882a593Smuzhiyun 	0x0400,
241*4882a593Smuzhiyun 	0x0800,
242*4882a593Smuzhiyun 	0x0C00,
243*4882a593Smuzhiyun 	0x0200,
244*4882a593Smuzhiyun 	0x0600,
245*4882a593Smuzhiyun 	0x0A00,
246*4882a593Smuzhiyun 	0x0E00
247*4882a593Smuzhiyun };
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun /* PCI related definitions */
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun #ifdef CONFIG_PCI
252*4882a593Smuzhiyun static const struct pci_device_id cy_pci_dev_id[] = {
253*4882a593Smuzhiyun 	/* PCI < 1Mb */
254*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) },
255*4882a593Smuzhiyun 	/* PCI > 1Mb */
256*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) },
257*4882a593Smuzhiyun 	/* 4Y PCI < 1Mb */
258*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) },
259*4882a593Smuzhiyun 	/* 4Y PCI > 1Mb */
260*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) },
261*4882a593Smuzhiyun 	/* 8Y PCI < 1Mb */
262*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) },
263*4882a593Smuzhiyun 	/* 8Y PCI > 1Mb */
264*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) },
265*4882a593Smuzhiyun 	/* Z PCI < 1Mb */
266*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) },
267*4882a593Smuzhiyun 	/* Z PCI > 1Mb */
268*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) },
269*4882a593Smuzhiyun 	{ }			/* end of table */
270*4882a593Smuzhiyun };
271*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
272*4882a593Smuzhiyun #endif
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun static void cy_start(struct tty_struct *);
275*4882a593Smuzhiyun static void cy_set_line_char(struct cyclades_port *, struct tty_struct *);
276*4882a593Smuzhiyun static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32);
277*4882a593Smuzhiyun #ifdef CONFIG_ISA
278*4882a593Smuzhiyun static unsigned detect_isa_irq(void __iomem *);
279*4882a593Smuzhiyun #endif				/* CONFIG_ISA */
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun #ifndef CONFIG_CYZ_INTR
282*4882a593Smuzhiyun static void cyz_poll(struct timer_list *);
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun /* The Cyclades-Z polling cycle is defined by this variable */
285*4882a593Smuzhiyun static long cyz_polling_cycle = CZ_DEF_POLL;
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun static DEFINE_TIMER(cyz_timerlist, cyz_poll);
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun #else				/* CONFIG_CYZ_INTR */
290*4882a593Smuzhiyun static void cyz_rx_restart(struct timer_list *);
291*4882a593Smuzhiyun #endif				/* CONFIG_CYZ_INTR */
292*4882a593Smuzhiyun 
cyy_writeb(struct cyclades_port * port,u32 reg,u8 val)293*4882a593Smuzhiyun static void cyy_writeb(struct cyclades_port *port, u32 reg, u8 val)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun 	struct cyclades_card *card = port->card;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	cy_writeb(port->u.cyy.base_addr + (reg << card->bus_index), val);
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun 
cyy_readb(struct cyclades_port * port,u32 reg)300*4882a593Smuzhiyun static u8 cyy_readb(struct cyclades_port *port, u32 reg)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun 	struct cyclades_card *card = port->card;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	return readb(port->u.cyy.base_addr + (reg << card->bus_index));
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun 
cy_is_Z(struct cyclades_card * card)307*4882a593Smuzhiyun static inline bool cy_is_Z(struct cyclades_card *card)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun 	return card->num_chips == (unsigned int)-1;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun 
__cyz_fpga_loaded(struct RUNTIME_9060 __iomem * ctl_addr)312*4882a593Smuzhiyun static inline bool __cyz_fpga_loaded(struct RUNTIME_9060 __iomem *ctl_addr)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun 	return readl(&ctl_addr->init_ctrl) & (1 << 17);
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun 
cyz_fpga_loaded(struct cyclades_card * card)317*4882a593Smuzhiyun static inline bool cyz_fpga_loaded(struct cyclades_card *card)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun 	return __cyz_fpga_loaded(card->ctl_addr.p9060);
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun 
cyz_is_loaded(struct cyclades_card * card)322*4882a593Smuzhiyun static bool cyz_is_loaded(struct cyclades_card *card)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun 	struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	return (card->hw_ver == ZO_V1 || cyz_fpga_loaded(card)) &&
327*4882a593Smuzhiyun 			readl(&fw_id->signature) == ZFIRM_ID;
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun 
serial_paranoia_check(struct cyclades_port * info,const char * name,const char * routine)330*4882a593Smuzhiyun static int serial_paranoia_check(struct cyclades_port *info,
331*4882a593Smuzhiyun 		const char *name, const char *routine)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun #ifdef SERIAL_PARANOIA_CHECK
334*4882a593Smuzhiyun 	if (!info) {
335*4882a593Smuzhiyun 		printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) "
336*4882a593Smuzhiyun 				"in %s\n", name, routine);
337*4882a593Smuzhiyun 		return 1;
338*4882a593Smuzhiyun 	}
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	if (info->magic != CYCLADES_MAGIC) {
341*4882a593Smuzhiyun 		printk(KERN_WARNING "cyc Warning: bad magic number for serial "
342*4882a593Smuzhiyun 				"struct (%s) in %s\n", name, routine);
343*4882a593Smuzhiyun 		return 1;
344*4882a593Smuzhiyun 	}
345*4882a593Smuzhiyun #endif
346*4882a593Smuzhiyun 	return 0;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun /***********************************************************/
350*4882a593Smuzhiyun /********* Start of block of Cyclom-Y specific code ********/
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun /* This routine waits up to 1000 micro-seconds for the previous
353*4882a593Smuzhiyun    command to the Cirrus chip to complete and then issues the
354*4882a593Smuzhiyun    new command.  An error is returned if the previous command
355*4882a593Smuzhiyun    didn't finish within the time limit.
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun    This function is only called from inside spinlock-protected code.
358*4882a593Smuzhiyun  */
__cyy_issue_cmd(void __iomem * base_addr,u8 cmd,int index)359*4882a593Smuzhiyun static int __cyy_issue_cmd(void __iomem *base_addr, u8 cmd, int index)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun 	void __iomem *ccr = base_addr + (CyCCR << index);
362*4882a593Smuzhiyun 	unsigned int i;
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	/* Check to see that the previous command has completed */
365*4882a593Smuzhiyun 	for (i = 0; i < 100; i++) {
366*4882a593Smuzhiyun 		if (readb(ccr) == 0)
367*4882a593Smuzhiyun 			break;
368*4882a593Smuzhiyun 		udelay(10L);
369*4882a593Smuzhiyun 	}
370*4882a593Smuzhiyun 	/* if the CCR never cleared, the previous command
371*4882a593Smuzhiyun 	   didn't finish within the "reasonable time" */
372*4882a593Smuzhiyun 	if (i == 100)
373*4882a593Smuzhiyun 		return -1;
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	/* Issue the new command */
376*4882a593Smuzhiyun 	cy_writeb(ccr, cmd);
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	return 0;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun 
cyy_issue_cmd(struct cyclades_port * port,u8 cmd)381*4882a593Smuzhiyun static inline int cyy_issue_cmd(struct cyclades_port *port, u8 cmd)
382*4882a593Smuzhiyun {
383*4882a593Smuzhiyun 	return __cyy_issue_cmd(port->u.cyy.base_addr, cmd,
384*4882a593Smuzhiyun 			port->card->bus_index);
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun #ifdef CONFIG_ISA
388*4882a593Smuzhiyun /* ISA interrupt detection code */
detect_isa_irq(void __iomem * address)389*4882a593Smuzhiyun static unsigned detect_isa_irq(void __iomem *address)
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun 	int irq;
392*4882a593Smuzhiyun 	unsigned long irqs, flags;
393*4882a593Smuzhiyun 	int save_xir, save_car;
394*4882a593Smuzhiyun 	int index = 0;		/* IRQ probing is only for ISA */
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	/* forget possible initially masked and pending IRQ */
397*4882a593Smuzhiyun 	irq = probe_irq_off(probe_irq_on());
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	/* Clear interrupts on the board first */
400*4882a593Smuzhiyun 	cy_writeb(address + (Cy_ClrIntr << index), 0);
401*4882a593Smuzhiyun 	/* Cy_ClrIntr is 0x1800 */
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	irqs = probe_irq_on();
404*4882a593Smuzhiyun 	/* Wait ... */
405*4882a593Smuzhiyun 	msleep(5);
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	/* Enable the Tx interrupts on the CD1400 */
408*4882a593Smuzhiyun 	local_irq_save(flags);
409*4882a593Smuzhiyun 	cy_writeb(address + (CyCAR << index), 0);
410*4882a593Smuzhiyun 	__cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index);
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	cy_writeb(address + (CyCAR << index), 0);
413*4882a593Smuzhiyun 	cy_writeb(address + (CySRER << index),
414*4882a593Smuzhiyun 		  readb(address + (CySRER << index)) | CyTxRdy);
415*4882a593Smuzhiyun 	local_irq_restore(flags);
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	/* Wait ... */
418*4882a593Smuzhiyun 	msleep(5);
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	/* Check which interrupt is in use */
421*4882a593Smuzhiyun 	irq = probe_irq_off(irqs);
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	/* Clean up */
424*4882a593Smuzhiyun 	save_xir = (u_char) readb(address + (CyTIR << index));
425*4882a593Smuzhiyun 	save_car = readb(address + (CyCAR << index));
426*4882a593Smuzhiyun 	cy_writeb(address + (CyCAR << index), (save_xir & 0x3));
427*4882a593Smuzhiyun 	cy_writeb(address + (CySRER << index),
428*4882a593Smuzhiyun 		  readb(address + (CySRER << index)) & ~CyTxRdy);
429*4882a593Smuzhiyun 	cy_writeb(address + (CyTIR << index), (save_xir & 0x3f));
430*4882a593Smuzhiyun 	cy_writeb(address + (CyCAR << index), (save_car));
431*4882a593Smuzhiyun 	cy_writeb(address + (Cy_ClrIntr << index), 0);
432*4882a593Smuzhiyun 	/* Cy_ClrIntr is 0x1800 */
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	return (irq > 0) ? irq : 0;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun #endif				/* CONFIG_ISA */
437*4882a593Smuzhiyun 
cyy_chip_rx(struct cyclades_card * cinfo,int chip,void __iomem * base_addr)438*4882a593Smuzhiyun static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
439*4882a593Smuzhiyun 		void __iomem *base_addr)
440*4882a593Smuzhiyun {
441*4882a593Smuzhiyun 	struct cyclades_port *info;
442*4882a593Smuzhiyun 	struct tty_port *port;
443*4882a593Smuzhiyun 	int len, index = cinfo->bus_index;
444*4882a593Smuzhiyun 	u8 ivr, save_xir, channel, save_car, data, char_count;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun #ifdef CY_DEBUG_INTERRUPTS
447*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
448*4882a593Smuzhiyun #endif
449*4882a593Smuzhiyun 	/* determine the channel & change to that context */
450*4882a593Smuzhiyun 	save_xir = readb(base_addr + (CyRIR << index));
451*4882a593Smuzhiyun 	channel = save_xir & CyIRChannel;
452*4882a593Smuzhiyun 	info = &cinfo->ports[channel + chip * 4];
453*4882a593Smuzhiyun 	port = &info->port;
454*4882a593Smuzhiyun 	save_car = cyy_readb(info, CyCAR);
455*4882a593Smuzhiyun 	cyy_writeb(info, CyCAR, save_xir);
456*4882a593Smuzhiyun 	ivr = cyy_readb(info, CyRIVR) & CyIVRMask;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	/* there is an open port for this data */
459*4882a593Smuzhiyun 	if (ivr == CyIVRRxEx) {	/* exception */
460*4882a593Smuzhiyun 		data = cyy_readb(info, CyRDSR);
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 		/* For statistics only */
463*4882a593Smuzhiyun 		if (data & CyBREAK)
464*4882a593Smuzhiyun 			info->icount.brk++;
465*4882a593Smuzhiyun 		else if (data & CyFRAME)
466*4882a593Smuzhiyun 			info->icount.frame++;
467*4882a593Smuzhiyun 		else if (data & CyPARITY)
468*4882a593Smuzhiyun 			info->icount.parity++;
469*4882a593Smuzhiyun 		else if (data & CyOVERRUN)
470*4882a593Smuzhiyun 			info->icount.overrun++;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 		if (data & info->ignore_status_mask) {
473*4882a593Smuzhiyun 			info->icount.rx++;
474*4882a593Smuzhiyun 			return;
475*4882a593Smuzhiyun 		}
476*4882a593Smuzhiyun 		if (tty_buffer_request_room(port, 1)) {
477*4882a593Smuzhiyun 			if (data & info->read_status_mask) {
478*4882a593Smuzhiyun 				if (data & CyBREAK) {
479*4882a593Smuzhiyun 					tty_insert_flip_char(port,
480*4882a593Smuzhiyun 						cyy_readb(info, CyRDSR),
481*4882a593Smuzhiyun 						TTY_BREAK);
482*4882a593Smuzhiyun 					info->icount.rx++;
483*4882a593Smuzhiyun 					if (port->flags & ASYNC_SAK) {
484*4882a593Smuzhiyun 						struct tty_struct *tty =
485*4882a593Smuzhiyun 							tty_port_tty_get(port);
486*4882a593Smuzhiyun 						if (tty) {
487*4882a593Smuzhiyun 							do_SAK(tty);
488*4882a593Smuzhiyun 							tty_kref_put(tty);
489*4882a593Smuzhiyun 						}
490*4882a593Smuzhiyun 					}
491*4882a593Smuzhiyun 				} else if (data & CyFRAME) {
492*4882a593Smuzhiyun 					tty_insert_flip_char(port,
493*4882a593Smuzhiyun 						cyy_readb(info, CyRDSR),
494*4882a593Smuzhiyun 						TTY_FRAME);
495*4882a593Smuzhiyun 					info->icount.rx++;
496*4882a593Smuzhiyun 					info->idle_stats.frame_errs++;
497*4882a593Smuzhiyun 				} else if (data & CyPARITY) {
498*4882a593Smuzhiyun 					/* Pieces of seven... */
499*4882a593Smuzhiyun 					tty_insert_flip_char(port,
500*4882a593Smuzhiyun 						cyy_readb(info, CyRDSR),
501*4882a593Smuzhiyun 						TTY_PARITY);
502*4882a593Smuzhiyun 					info->icount.rx++;
503*4882a593Smuzhiyun 					info->idle_stats.parity_errs++;
504*4882a593Smuzhiyun 				} else if (data & CyOVERRUN) {
505*4882a593Smuzhiyun 					tty_insert_flip_char(port, 0,
506*4882a593Smuzhiyun 							TTY_OVERRUN);
507*4882a593Smuzhiyun 					info->icount.rx++;
508*4882a593Smuzhiyun 					/* If the flip buffer itself is
509*4882a593Smuzhiyun 					   overflowing, we still lose
510*4882a593Smuzhiyun 					   the next incoming character.
511*4882a593Smuzhiyun 					 */
512*4882a593Smuzhiyun 					tty_insert_flip_char(port,
513*4882a593Smuzhiyun 						cyy_readb(info, CyRDSR),
514*4882a593Smuzhiyun 						TTY_FRAME);
515*4882a593Smuzhiyun 					info->icount.rx++;
516*4882a593Smuzhiyun 					info->idle_stats.overruns++;
517*4882a593Smuzhiyun 				/* These two conditions may imply */
518*4882a593Smuzhiyun 				/* a normal read should be done. */
519*4882a593Smuzhiyun 				/* } else if(data & CyTIMEOUT) { */
520*4882a593Smuzhiyun 				/* } else if(data & CySPECHAR) { */
521*4882a593Smuzhiyun 				} else {
522*4882a593Smuzhiyun 					tty_insert_flip_char(port, 0,
523*4882a593Smuzhiyun 							TTY_NORMAL);
524*4882a593Smuzhiyun 					info->icount.rx++;
525*4882a593Smuzhiyun 				}
526*4882a593Smuzhiyun 			} else {
527*4882a593Smuzhiyun 				tty_insert_flip_char(port, 0, TTY_NORMAL);
528*4882a593Smuzhiyun 				info->icount.rx++;
529*4882a593Smuzhiyun 			}
530*4882a593Smuzhiyun 		} else {
531*4882a593Smuzhiyun 			/* there was a software buffer overrun and nothing
532*4882a593Smuzhiyun 			 * could be done about it!!! */
533*4882a593Smuzhiyun 			info->icount.buf_overrun++;
534*4882a593Smuzhiyun 			info->idle_stats.overruns++;
535*4882a593Smuzhiyun 		}
536*4882a593Smuzhiyun 	} else {	/* normal character reception */
537*4882a593Smuzhiyun 		/* load # chars available from the chip */
538*4882a593Smuzhiyun 		char_count = cyy_readb(info, CyRDCR);
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun #ifdef CY_ENABLE_MONITORING
541*4882a593Smuzhiyun 		++info->mon.int_count;
542*4882a593Smuzhiyun 		info->mon.char_count += char_count;
543*4882a593Smuzhiyun 		if (char_count > info->mon.char_max)
544*4882a593Smuzhiyun 			info->mon.char_max = char_count;
545*4882a593Smuzhiyun 		info->mon.char_last = char_count;
546*4882a593Smuzhiyun #endif
547*4882a593Smuzhiyun 		len = tty_buffer_request_room(port, char_count);
548*4882a593Smuzhiyun 		while (len--) {
549*4882a593Smuzhiyun 			data = cyy_readb(info, CyRDSR);
550*4882a593Smuzhiyun 			tty_insert_flip_char(port, data, TTY_NORMAL);
551*4882a593Smuzhiyun 			info->idle_stats.recv_bytes++;
552*4882a593Smuzhiyun 			info->icount.rx++;
553*4882a593Smuzhiyun #ifdef CY_16Y_HACK
554*4882a593Smuzhiyun 			udelay(10L);
555*4882a593Smuzhiyun #endif
556*4882a593Smuzhiyun 		}
557*4882a593Smuzhiyun 		info->idle_stats.recv_idle = jiffies;
558*4882a593Smuzhiyun 	}
559*4882a593Smuzhiyun 	tty_flip_buffer_push(port);
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 	/* end of service */
562*4882a593Smuzhiyun 	cyy_writeb(info, CyRIR, save_xir & 0x3f);
563*4882a593Smuzhiyun 	cyy_writeb(info, CyCAR, save_car);
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun 
cyy_chip_tx(struct cyclades_card * cinfo,unsigned int chip,void __iomem * base_addr)566*4882a593Smuzhiyun static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
567*4882a593Smuzhiyun 		void __iomem *base_addr)
568*4882a593Smuzhiyun {
569*4882a593Smuzhiyun 	struct cyclades_port *info;
570*4882a593Smuzhiyun 	struct tty_struct *tty;
571*4882a593Smuzhiyun 	int char_count, index = cinfo->bus_index;
572*4882a593Smuzhiyun 	u8 save_xir, channel, save_car, outch;
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	/* Since we only get here when the transmit buffer
575*4882a593Smuzhiyun 	   is empty, we know we can always stuff a dozen
576*4882a593Smuzhiyun 	   characters. */
577*4882a593Smuzhiyun #ifdef CY_DEBUG_INTERRUPTS
578*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip);
579*4882a593Smuzhiyun #endif
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	/* determine the channel & change to that context */
582*4882a593Smuzhiyun 	save_xir = readb(base_addr + (CyTIR << index));
583*4882a593Smuzhiyun 	channel = save_xir & CyIRChannel;
584*4882a593Smuzhiyun 	save_car = readb(base_addr + (CyCAR << index));
585*4882a593Smuzhiyun 	cy_writeb(base_addr + (CyCAR << index), save_xir);
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	info = &cinfo->ports[channel + chip * 4];
588*4882a593Smuzhiyun 	tty = tty_port_tty_get(&info->port);
589*4882a593Smuzhiyun 	if (tty == NULL) {
590*4882a593Smuzhiyun 		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
591*4882a593Smuzhiyun 		goto end;
592*4882a593Smuzhiyun 	}
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	/* load the on-chip space for outbound data */
595*4882a593Smuzhiyun 	char_count = info->xmit_fifo_size;
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	if (info->x_char) {	/* send special char */
598*4882a593Smuzhiyun 		outch = info->x_char;
599*4882a593Smuzhiyun 		cyy_writeb(info, CyTDR, outch);
600*4882a593Smuzhiyun 		char_count--;
601*4882a593Smuzhiyun 		info->icount.tx++;
602*4882a593Smuzhiyun 		info->x_char = 0;
603*4882a593Smuzhiyun 	}
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	if (info->breakon || info->breakoff) {
606*4882a593Smuzhiyun 		if (info->breakon) {
607*4882a593Smuzhiyun 			cyy_writeb(info, CyTDR, 0);
608*4882a593Smuzhiyun 			cyy_writeb(info, CyTDR, 0x81);
609*4882a593Smuzhiyun 			info->breakon = 0;
610*4882a593Smuzhiyun 			char_count -= 2;
611*4882a593Smuzhiyun 		}
612*4882a593Smuzhiyun 		if (info->breakoff) {
613*4882a593Smuzhiyun 			cyy_writeb(info, CyTDR, 0);
614*4882a593Smuzhiyun 			cyy_writeb(info, CyTDR, 0x83);
615*4882a593Smuzhiyun 			info->breakoff = 0;
616*4882a593Smuzhiyun 			char_count -= 2;
617*4882a593Smuzhiyun 		}
618*4882a593Smuzhiyun 	}
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 	while (char_count-- > 0) {
621*4882a593Smuzhiyun 		if (!info->xmit_cnt) {
622*4882a593Smuzhiyun 			if (cyy_readb(info, CySRER) & CyTxMpty) {
623*4882a593Smuzhiyun 				cyy_writeb(info, CySRER,
624*4882a593Smuzhiyun 					cyy_readb(info, CySRER) & ~CyTxMpty);
625*4882a593Smuzhiyun 			} else {
626*4882a593Smuzhiyun 				cyy_writeb(info, CySRER, CyTxMpty |
627*4882a593Smuzhiyun 					(cyy_readb(info, CySRER) & ~CyTxRdy));
628*4882a593Smuzhiyun 			}
629*4882a593Smuzhiyun 			goto done;
630*4882a593Smuzhiyun 		}
631*4882a593Smuzhiyun 		if (info->port.xmit_buf == NULL) {
632*4882a593Smuzhiyun 			cyy_writeb(info, CySRER,
633*4882a593Smuzhiyun 				cyy_readb(info, CySRER) & ~CyTxRdy);
634*4882a593Smuzhiyun 			goto done;
635*4882a593Smuzhiyun 		}
636*4882a593Smuzhiyun 		if (tty->stopped || tty->hw_stopped) {
637*4882a593Smuzhiyun 			cyy_writeb(info, CySRER,
638*4882a593Smuzhiyun 				cyy_readb(info, CySRER) & ~CyTxRdy);
639*4882a593Smuzhiyun 			goto done;
640*4882a593Smuzhiyun 		}
641*4882a593Smuzhiyun 		/* Because the Embedded Transmit Commands have been enabled,
642*4882a593Smuzhiyun 		 * we must check to see if the escape character, NULL, is being
643*4882a593Smuzhiyun 		 * sent. If it is, we must ensure that there is room for it to
644*4882a593Smuzhiyun 		 * be doubled in the output stream.  Therefore we no longer
645*4882a593Smuzhiyun 		 * advance the pointer when the character is fetched, but
646*4882a593Smuzhiyun 		 * rather wait until after the check for a NULL output
647*4882a593Smuzhiyun 		 * character. This is necessary because there may not be room
648*4882a593Smuzhiyun 		 * for the two chars needed to send a NULL.)
649*4882a593Smuzhiyun 		 */
650*4882a593Smuzhiyun 		outch = info->port.xmit_buf[info->xmit_tail];
651*4882a593Smuzhiyun 		if (outch) {
652*4882a593Smuzhiyun 			info->xmit_cnt--;
653*4882a593Smuzhiyun 			info->xmit_tail = (info->xmit_tail + 1) &
654*4882a593Smuzhiyun 					(SERIAL_XMIT_SIZE - 1);
655*4882a593Smuzhiyun 			cyy_writeb(info, CyTDR, outch);
656*4882a593Smuzhiyun 			info->icount.tx++;
657*4882a593Smuzhiyun 		} else {
658*4882a593Smuzhiyun 			if (char_count > 1) {
659*4882a593Smuzhiyun 				info->xmit_cnt--;
660*4882a593Smuzhiyun 				info->xmit_tail = (info->xmit_tail + 1) &
661*4882a593Smuzhiyun 					(SERIAL_XMIT_SIZE - 1);
662*4882a593Smuzhiyun 				cyy_writeb(info, CyTDR, outch);
663*4882a593Smuzhiyun 				cyy_writeb(info, CyTDR, 0);
664*4882a593Smuzhiyun 				info->icount.tx++;
665*4882a593Smuzhiyun 				char_count--;
666*4882a593Smuzhiyun 			}
667*4882a593Smuzhiyun 		}
668*4882a593Smuzhiyun 	}
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun done:
671*4882a593Smuzhiyun 	tty_wakeup(tty);
672*4882a593Smuzhiyun 	tty_kref_put(tty);
673*4882a593Smuzhiyun end:
674*4882a593Smuzhiyun 	/* end of service */
675*4882a593Smuzhiyun 	cyy_writeb(info, CyTIR, save_xir & 0x3f);
676*4882a593Smuzhiyun 	cyy_writeb(info, CyCAR, save_car);
677*4882a593Smuzhiyun }
678*4882a593Smuzhiyun 
cyy_chip_modem(struct cyclades_card * cinfo,int chip,void __iomem * base_addr)679*4882a593Smuzhiyun static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
680*4882a593Smuzhiyun 		void __iomem *base_addr)
681*4882a593Smuzhiyun {
682*4882a593Smuzhiyun 	struct cyclades_port *info;
683*4882a593Smuzhiyun 	struct tty_struct *tty;
684*4882a593Smuzhiyun 	int index = cinfo->bus_index;
685*4882a593Smuzhiyun 	u8 save_xir, channel, save_car, mdm_change, mdm_status;
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	/* determine the channel & change to that context */
688*4882a593Smuzhiyun 	save_xir = readb(base_addr + (CyMIR << index));
689*4882a593Smuzhiyun 	channel = save_xir & CyIRChannel;
690*4882a593Smuzhiyun 	info = &cinfo->ports[channel + chip * 4];
691*4882a593Smuzhiyun 	save_car = cyy_readb(info, CyCAR);
692*4882a593Smuzhiyun 	cyy_writeb(info, CyCAR, save_xir);
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun 	mdm_change = cyy_readb(info, CyMISR);
695*4882a593Smuzhiyun 	mdm_status = cyy_readb(info, CyMSVR1);
696*4882a593Smuzhiyun 
697*4882a593Smuzhiyun 	tty = tty_port_tty_get(&info->port);
698*4882a593Smuzhiyun 	if (!tty)
699*4882a593Smuzhiyun 		goto end;
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	if (mdm_change & CyANY_DELTA) {
702*4882a593Smuzhiyun 		/* For statistics only */
703*4882a593Smuzhiyun 		if (mdm_change & CyDCD)
704*4882a593Smuzhiyun 			info->icount.dcd++;
705*4882a593Smuzhiyun 		if (mdm_change & CyCTS)
706*4882a593Smuzhiyun 			info->icount.cts++;
707*4882a593Smuzhiyun 		if (mdm_change & CyDSR)
708*4882a593Smuzhiyun 			info->icount.dsr++;
709*4882a593Smuzhiyun 		if (mdm_change & CyRI)
710*4882a593Smuzhiyun 			info->icount.rng++;
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 		wake_up_interruptible(&info->port.delta_msr_wait);
713*4882a593Smuzhiyun 	}
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 	if ((mdm_change & CyDCD) && tty_port_check_carrier(&info->port)) {
716*4882a593Smuzhiyun 		if (mdm_status & CyDCD)
717*4882a593Smuzhiyun 			wake_up_interruptible(&info->port.open_wait);
718*4882a593Smuzhiyun 		else
719*4882a593Smuzhiyun 			tty_hangup(tty);
720*4882a593Smuzhiyun 	}
721*4882a593Smuzhiyun 	if ((mdm_change & CyCTS) && tty_port_cts_enabled(&info->port)) {
722*4882a593Smuzhiyun 		if (tty->hw_stopped) {
723*4882a593Smuzhiyun 			if (mdm_status & CyCTS) {
724*4882a593Smuzhiyun 				/* cy_start isn't used
725*4882a593Smuzhiyun 				   because... !!! */
726*4882a593Smuzhiyun 				tty->hw_stopped = 0;
727*4882a593Smuzhiyun 				cyy_writeb(info, CySRER,
728*4882a593Smuzhiyun 					cyy_readb(info, CySRER) | CyTxRdy);
729*4882a593Smuzhiyun 				tty_wakeup(tty);
730*4882a593Smuzhiyun 			}
731*4882a593Smuzhiyun 		} else {
732*4882a593Smuzhiyun 			if (!(mdm_status & CyCTS)) {
733*4882a593Smuzhiyun 				/* cy_stop isn't used
734*4882a593Smuzhiyun 				   because ... !!! */
735*4882a593Smuzhiyun 				tty->hw_stopped = 1;
736*4882a593Smuzhiyun 				cyy_writeb(info, CySRER,
737*4882a593Smuzhiyun 					cyy_readb(info, CySRER) & ~CyTxRdy);
738*4882a593Smuzhiyun 			}
739*4882a593Smuzhiyun 		}
740*4882a593Smuzhiyun 	}
741*4882a593Smuzhiyun /*	if (mdm_change & CyDSR) {
742*4882a593Smuzhiyun 	}
743*4882a593Smuzhiyun 	if (mdm_change & CyRI) {
744*4882a593Smuzhiyun 	}*/
745*4882a593Smuzhiyun 	tty_kref_put(tty);
746*4882a593Smuzhiyun end:
747*4882a593Smuzhiyun 	/* end of service */
748*4882a593Smuzhiyun 	cyy_writeb(info, CyMIR, save_xir & 0x3f);
749*4882a593Smuzhiyun 	cyy_writeb(info, CyCAR, save_car);
750*4882a593Smuzhiyun }
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun /* The real interrupt service routine is called
753*4882a593Smuzhiyun    whenever the card wants its hand held--chars
754*4882a593Smuzhiyun    received, out buffer empty, modem change, etc.
755*4882a593Smuzhiyun  */
cyy_interrupt(int irq,void * dev_id)756*4882a593Smuzhiyun static irqreturn_t cyy_interrupt(int irq, void *dev_id)
757*4882a593Smuzhiyun {
758*4882a593Smuzhiyun 	int status;
759*4882a593Smuzhiyun 	struct cyclades_card *cinfo = dev_id;
760*4882a593Smuzhiyun 	void __iomem *base_addr, *card_base_addr;
761*4882a593Smuzhiyun 	unsigned int chip, too_many, had_work;
762*4882a593Smuzhiyun 	int index;
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 	if (unlikely(cinfo == NULL)) {
765*4882a593Smuzhiyun #ifdef CY_DEBUG_INTERRUPTS
766*4882a593Smuzhiyun 		printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",
767*4882a593Smuzhiyun 				irq);
768*4882a593Smuzhiyun #endif
769*4882a593Smuzhiyun 		return IRQ_NONE;	/* spurious interrupt */
770*4882a593Smuzhiyun 	}
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 	card_base_addr = cinfo->base_addr;
773*4882a593Smuzhiyun 	index = cinfo->bus_index;
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	/* card was not initialized yet (e.g. DEBUG_SHIRQ) */
776*4882a593Smuzhiyun 	if (unlikely(card_base_addr == NULL))
777*4882a593Smuzhiyun 		return IRQ_HANDLED;
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	/* This loop checks all chips in the card.  Make a note whenever
780*4882a593Smuzhiyun 	   _any_ chip had some work to do, as this is considered an
781*4882a593Smuzhiyun 	   indication that there will be more to do.  Only when no chip
782*4882a593Smuzhiyun 	   has any work does this outermost loop exit.
783*4882a593Smuzhiyun 	 */
784*4882a593Smuzhiyun 	do {
785*4882a593Smuzhiyun 		had_work = 0;
786*4882a593Smuzhiyun 		for (chip = 0; chip < cinfo->num_chips; chip++) {
787*4882a593Smuzhiyun 			base_addr = cinfo->base_addr +
788*4882a593Smuzhiyun 					(cy_chip_offset[chip] << index);
789*4882a593Smuzhiyun 			too_many = 0;
790*4882a593Smuzhiyun 			while ((status = readb(base_addr +
791*4882a593Smuzhiyun 						(CySVRR << index))) != 0x00) {
792*4882a593Smuzhiyun 				had_work++;
793*4882a593Smuzhiyun 			/* The purpose of the following test is to ensure that
794*4882a593Smuzhiyun 			   no chip can monopolize the driver.  This forces the
795*4882a593Smuzhiyun 			   chips to be checked in a round-robin fashion (after
796*4882a593Smuzhiyun 			   draining each of a bunch (1000) of characters).
797*4882a593Smuzhiyun 			 */
798*4882a593Smuzhiyun 				if (1000 < too_many++)
799*4882a593Smuzhiyun 					break;
800*4882a593Smuzhiyun 				spin_lock(&cinfo->card_lock);
801*4882a593Smuzhiyun 				if (status & CySRReceive) /* rx intr */
802*4882a593Smuzhiyun 					cyy_chip_rx(cinfo, chip, base_addr);
803*4882a593Smuzhiyun 				if (status & CySRTransmit) /* tx intr */
804*4882a593Smuzhiyun 					cyy_chip_tx(cinfo, chip, base_addr);
805*4882a593Smuzhiyun 				if (status & CySRModem) /* modem intr */
806*4882a593Smuzhiyun 					cyy_chip_modem(cinfo, chip, base_addr);
807*4882a593Smuzhiyun 				spin_unlock(&cinfo->card_lock);
808*4882a593Smuzhiyun 			}
809*4882a593Smuzhiyun 		}
810*4882a593Smuzhiyun 	} while (had_work);
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun 	/* clear interrupts */
813*4882a593Smuzhiyun 	spin_lock(&cinfo->card_lock);
814*4882a593Smuzhiyun 	cy_writeb(card_base_addr + (Cy_ClrIntr << index), 0);
815*4882a593Smuzhiyun 	/* Cy_ClrIntr is 0x1800 */
816*4882a593Smuzhiyun 	spin_unlock(&cinfo->card_lock);
817*4882a593Smuzhiyun 	return IRQ_HANDLED;
818*4882a593Smuzhiyun }				/* cyy_interrupt */
819*4882a593Smuzhiyun 
cyy_change_rts_dtr(struct cyclades_port * info,unsigned int set,unsigned int clear)820*4882a593Smuzhiyun static void cyy_change_rts_dtr(struct cyclades_port *info, unsigned int set,
821*4882a593Smuzhiyun 		unsigned int clear)
822*4882a593Smuzhiyun {
823*4882a593Smuzhiyun 	struct cyclades_card *card = info->card;
824*4882a593Smuzhiyun 	int channel = info->line - card->first_line;
825*4882a593Smuzhiyun 	u32 rts, dtr, msvrr, msvrd;
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun 	channel &= 0x03;
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun 	if (info->rtsdtr_inv) {
830*4882a593Smuzhiyun 		msvrr = CyMSVR2;
831*4882a593Smuzhiyun 		msvrd = CyMSVR1;
832*4882a593Smuzhiyun 		rts = CyDTR;
833*4882a593Smuzhiyun 		dtr = CyRTS;
834*4882a593Smuzhiyun 	} else {
835*4882a593Smuzhiyun 		msvrr = CyMSVR1;
836*4882a593Smuzhiyun 		msvrd = CyMSVR2;
837*4882a593Smuzhiyun 		rts = CyRTS;
838*4882a593Smuzhiyun 		dtr = CyDTR;
839*4882a593Smuzhiyun 	}
840*4882a593Smuzhiyun 	if (set & TIOCM_RTS) {
841*4882a593Smuzhiyun 		cyy_writeb(info, CyCAR, channel);
842*4882a593Smuzhiyun 		cyy_writeb(info, msvrr, rts);
843*4882a593Smuzhiyun 	}
844*4882a593Smuzhiyun 	if (clear & TIOCM_RTS) {
845*4882a593Smuzhiyun 		cyy_writeb(info, CyCAR, channel);
846*4882a593Smuzhiyun 		cyy_writeb(info, msvrr, ~rts);
847*4882a593Smuzhiyun 	}
848*4882a593Smuzhiyun 	if (set & TIOCM_DTR) {
849*4882a593Smuzhiyun 		cyy_writeb(info, CyCAR, channel);
850*4882a593Smuzhiyun 		cyy_writeb(info, msvrd, dtr);
851*4882a593Smuzhiyun #ifdef CY_DEBUG_DTR
852*4882a593Smuzhiyun 		printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
853*4882a593Smuzhiyun 		printk(KERN_DEBUG "     status: 0x%x, 0x%x\n",
854*4882a593Smuzhiyun 			cyy_readb(info, CyMSVR1),
855*4882a593Smuzhiyun 			cyy_readb(info, CyMSVR2));
856*4882a593Smuzhiyun #endif
857*4882a593Smuzhiyun 	}
858*4882a593Smuzhiyun 	if (clear & TIOCM_DTR) {
859*4882a593Smuzhiyun 		cyy_writeb(info, CyCAR, channel);
860*4882a593Smuzhiyun 		cyy_writeb(info, msvrd, ~dtr);
861*4882a593Smuzhiyun #ifdef CY_DEBUG_DTR
862*4882a593Smuzhiyun 		printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
863*4882a593Smuzhiyun 		printk(KERN_DEBUG "     status: 0x%x, 0x%x\n",
864*4882a593Smuzhiyun 			cyy_readb(info, CyMSVR1),
865*4882a593Smuzhiyun 			cyy_readb(info, CyMSVR2));
866*4882a593Smuzhiyun #endif
867*4882a593Smuzhiyun 	}
868*4882a593Smuzhiyun }
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun /***********************************************************/
871*4882a593Smuzhiyun /********* End of block of Cyclom-Y specific code **********/
872*4882a593Smuzhiyun /******** Start of block of Cyclades-Z specific code *******/
873*4882a593Smuzhiyun /***********************************************************/
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun static int
cyz_fetch_msg(struct cyclades_card * cinfo,__u32 * channel,__u8 * cmd,__u32 * param)876*4882a593Smuzhiyun cyz_fetch_msg(struct cyclades_card *cinfo,
877*4882a593Smuzhiyun 		__u32 *channel, __u8 *cmd, __u32 *param)
878*4882a593Smuzhiyun {
879*4882a593Smuzhiyun 	struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
880*4882a593Smuzhiyun 	unsigned long loc_doorbell;
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun 	loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell);
883*4882a593Smuzhiyun 	if (loc_doorbell) {
884*4882a593Smuzhiyun 		*cmd = (char)(0xff & loc_doorbell);
885*4882a593Smuzhiyun 		*channel = readl(&board_ctrl->fwcmd_channel);
886*4882a593Smuzhiyun 		*param = (__u32) readl(&board_ctrl->fwcmd_param);
887*4882a593Smuzhiyun 		cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff);
888*4882a593Smuzhiyun 		return 1;
889*4882a593Smuzhiyun 	}
890*4882a593Smuzhiyun 	return 0;
891*4882a593Smuzhiyun }				/* cyz_fetch_msg */
892*4882a593Smuzhiyun 
893*4882a593Smuzhiyun static int
cyz_issue_cmd(struct cyclades_card * cinfo,__u32 channel,__u8 cmd,__u32 param)894*4882a593Smuzhiyun cyz_issue_cmd(struct cyclades_card *cinfo,
895*4882a593Smuzhiyun 		__u32 channel, __u8 cmd, __u32 param)
896*4882a593Smuzhiyun {
897*4882a593Smuzhiyun 	struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
898*4882a593Smuzhiyun 	__u32 __iomem *pci_doorbell;
899*4882a593Smuzhiyun 	unsigned int index;
900*4882a593Smuzhiyun 
901*4882a593Smuzhiyun 	if (!cyz_is_loaded(cinfo))
902*4882a593Smuzhiyun 		return -1;
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 	index = 0;
905*4882a593Smuzhiyun 	pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
906*4882a593Smuzhiyun 	while ((readl(pci_doorbell) & 0xff) != 0) {
907*4882a593Smuzhiyun 		if (index++ == 1000)
908*4882a593Smuzhiyun 			return (int)(readl(pci_doorbell) & 0xff);
909*4882a593Smuzhiyun 		udelay(50L);
910*4882a593Smuzhiyun 	}
911*4882a593Smuzhiyun 	cy_writel(&board_ctrl->hcmd_channel, channel);
912*4882a593Smuzhiyun 	cy_writel(&board_ctrl->hcmd_param, param);
913*4882a593Smuzhiyun 	cy_writel(pci_doorbell, (long)cmd);
914*4882a593Smuzhiyun 
915*4882a593Smuzhiyun 	return 0;
916*4882a593Smuzhiyun }				/* cyz_issue_cmd */
917*4882a593Smuzhiyun 
cyz_handle_rx(struct cyclades_port * info)918*4882a593Smuzhiyun static void cyz_handle_rx(struct cyclades_port *info)
919*4882a593Smuzhiyun {
920*4882a593Smuzhiyun 	struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
921*4882a593Smuzhiyun 	struct cyclades_card *cinfo = info->card;
922*4882a593Smuzhiyun 	struct tty_port *port = &info->port;
923*4882a593Smuzhiyun 	unsigned int char_count;
924*4882a593Smuzhiyun 	int len;
925*4882a593Smuzhiyun #ifdef BLOCKMOVE
926*4882a593Smuzhiyun 	unsigned char *buf;
927*4882a593Smuzhiyun #else
928*4882a593Smuzhiyun 	char data;
929*4882a593Smuzhiyun #endif
930*4882a593Smuzhiyun 	__u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
931*4882a593Smuzhiyun 
932*4882a593Smuzhiyun 	rx_get = new_rx_get = readl(&buf_ctrl->rx_get);
933*4882a593Smuzhiyun 	rx_put = readl(&buf_ctrl->rx_put);
934*4882a593Smuzhiyun 	rx_bufsize = readl(&buf_ctrl->rx_bufsize);
935*4882a593Smuzhiyun 	rx_bufaddr = readl(&buf_ctrl->rx_bufaddr);
936*4882a593Smuzhiyun 	if (rx_put >= rx_get)
937*4882a593Smuzhiyun 		char_count = rx_put - rx_get;
938*4882a593Smuzhiyun 	else
939*4882a593Smuzhiyun 		char_count = rx_put - rx_get + rx_bufsize;
940*4882a593Smuzhiyun 
941*4882a593Smuzhiyun 	if (!char_count)
942*4882a593Smuzhiyun 		return;
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun #ifdef CY_ENABLE_MONITORING
945*4882a593Smuzhiyun 	info->mon.int_count++;
946*4882a593Smuzhiyun 	info->mon.char_count += char_count;
947*4882a593Smuzhiyun 	if (char_count > info->mon.char_max)
948*4882a593Smuzhiyun 		info->mon.char_max = char_count;
949*4882a593Smuzhiyun 	info->mon.char_last = char_count;
950*4882a593Smuzhiyun #endif
951*4882a593Smuzhiyun 
952*4882a593Smuzhiyun #ifdef BLOCKMOVE
953*4882a593Smuzhiyun 	/* we'd like to use memcpy(t, f, n) and memset(s, c, count)
954*4882a593Smuzhiyun 	   for performance, but because of buffer boundaries, there
955*4882a593Smuzhiyun 	   may be several steps to the operation */
956*4882a593Smuzhiyun 	while (1) {
957*4882a593Smuzhiyun 		len = tty_prepare_flip_string(port, &buf,
958*4882a593Smuzhiyun 				char_count);
959*4882a593Smuzhiyun 		if (!len)
960*4882a593Smuzhiyun 			break;
961*4882a593Smuzhiyun 
962*4882a593Smuzhiyun 		len = min_t(unsigned int, min(len, char_count),
963*4882a593Smuzhiyun 				rx_bufsize - new_rx_get);
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 		memcpy_fromio(buf, cinfo->base_addr +
966*4882a593Smuzhiyun 				rx_bufaddr + new_rx_get, len);
967*4882a593Smuzhiyun 
968*4882a593Smuzhiyun 		new_rx_get = (new_rx_get + len) &
969*4882a593Smuzhiyun 				(rx_bufsize - 1);
970*4882a593Smuzhiyun 		char_count -= len;
971*4882a593Smuzhiyun 		info->icount.rx += len;
972*4882a593Smuzhiyun 		info->idle_stats.recv_bytes += len;
973*4882a593Smuzhiyun 	}
974*4882a593Smuzhiyun #else
975*4882a593Smuzhiyun 	len = tty_buffer_request_room(port, char_count);
976*4882a593Smuzhiyun 	while (len--) {
977*4882a593Smuzhiyun 		data = readb(cinfo->base_addr + rx_bufaddr +
978*4882a593Smuzhiyun 				new_rx_get);
979*4882a593Smuzhiyun 		new_rx_get = (new_rx_get + 1) &
980*4882a593Smuzhiyun 					(rx_bufsize - 1);
981*4882a593Smuzhiyun 		tty_insert_flip_char(port, data, TTY_NORMAL);
982*4882a593Smuzhiyun 		info->idle_stats.recv_bytes++;
983*4882a593Smuzhiyun 		info->icount.rx++;
984*4882a593Smuzhiyun 	}
985*4882a593Smuzhiyun #endif
986*4882a593Smuzhiyun #ifdef CONFIG_CYZ_INTR
987*4882a593Smuzhiyun 	/* Recalculate the number of chars in the RX buffer and issue
988*4882a593Smuzhiyun 	   a cmd in case it's higher than the RX high water mark */
989*4882a593Smuzhiyun 	rx_put = readl(&buf_ctrl->rx_put);
990*4882a593Smuzhiyun 	if (rx_put >= rx_get)
991*4882a593Smuzhiyun 		char_count = rx_put - rx_get;
992*4882a593Smuzhiyun 	else
993*4882a593Smuzhiyun 		char_count = rx_put - rx_get + rx_bufsize;
994*4882a593Smuzhiyun 	if (char_count >= readl(&buf_ctrl->rx_threshold) &&
995*4882a593Smuzhiyun 			!timer_pending(&info->rx_full_timer))
996*4882a593Smuzhiyun 		mod_timer(&info->rx_full_timer, jiffies + 1);
997*4882a593Smuzhiyun #endif
998*4882a593Smuzhiyun 	info->idle_stats.recv_idle = jiffies;
999*4882a593Smuzhiyun 	tty_flip_buffer_push(&info->port);
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun 	/* Update rx_get */
1002*4882a593Smuzhiyun 	cy_writel(&buf_ctrl->rx_get, new_rx_get);
1003*4882a593Smuzhiyun }
1004*4882a593Smuzhiyun 
cyz_handle_tx(struct cyclades_port * info)1005*4882a593Smuzhiyun static void cyz_handle_tx(struct cyclades_port *info)
1006*4882a593Smuzhiyun {
1007*4882a593Smuzhiyun 	struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
1008*4882a593Smuzhiyun 	struct cyclades_card *cinfo = info->card;
1009*4882a593Smuzhiyun 	struct tty_struct *tty;
1010*4882a593Smuzhiyun 	u8 data;
1011*4882a593Smuzhiyun 	unsigned int char_count;
1012*4882a593Smuzhiyun #ifdef BLOCKMOVE
1013*4882a593Smuzhiyun 	int small_count;
1014*4882a593Smuzhiyun #endif
1015*4882a593Smuzhiyun 	__u32 tx_put, tx_get, tx_bufsize, tx_bufaddr;
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun 	if (info->xmit_cnt <= 0)	/* Nothing to transmit */
1018*4882a593Smuzhiyun 		return;
1019*4882a593Smuzhiyun 
1020*4882a593Smuzhiyun 	tx_get = readl(&buf_ctrl->tx_get);
1021*4882a593Smuzhiyun 	tx_put = readl(&buf_ctrl->tx_put);
1022*4882a593Smuzhiyun 	tx_bufsize = readl(&buf_ctrl->tx_bufsize);
1023*4882a593Smuzhiyun 	tx_bufaddr = readl(&buf_ctrl->tx_bufaddr);
1024*4882a593Smuzhiyun 	if (tx_put >= tx_get)
1025*4882a593Smuzhiyun 		char_count = tx_get - tx_put - 1 + tx_bufsize;
1026*4882a593Smuzhiyun 	else
1027*4882a593Smuzhiyun 		char_count = tx_get - tx_put - 1;
1028*4882a593Smuzhiyun 
1029*4882a593Smuzhiyun 	if (!char_count)
1030*4882a593Smuzhiyun 		return;
1031*4882a593Smuzhiyun 
1032*4882a593Smuzhiyun 	tty = tty_port_tty_get(&info->port);
1033*4882a593Smuzhiyun 	if (tty == NULL)
1034*4882a593Smuzhiyun 		goto ztxdone;
1035*4882a593Smuzhiyun 
1036*4882a593Smuzhiyun 	if (info->x_char) {	/* send special char */
1037*4882a593Smuzhiyun 		data = info->x_char;
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun 		cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1040*4882a593Smuzhiyun 		tx_put = (tx_put + 1) & (tx_bufsize - 1);
1041*4882a593Smuzhiyun 		info->x_char = 0;
1042*4882a593Smuzhiyun 		char_count--;
1043*4882a593Smuzhiyun 		info->icount.tx++;
1044*4882a593Smuzhiyun 	}
1045*4882a593Smuzhiyun #ifdef BLOCKMOVE
1046*4882a593Smuzhiyun 	while (0 < (small_count = min_t(unsigned int,
1047*4882a593Smuzhiyun 			tx_bufsize - tx_put, min_t(unsigned int,
1048*4882a593Smuzhiyun 				(SERIAL_XMIT_SIZE - info->xmit_tail),
1049*4882a593Smuzhiyun 				min_t(unsigned int, info->xmit_cnt,
1050*4882a593Smuzhiyun 					char_count))))) {
1051*4882a593Smuzhiyun 
1052*4882a593Smuzhiyun 		memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr + tx_put),
1053*4882a593Smuzhiyun 				&info->port.xmit_buf[info->xmit_tail],
1054*4882a593Smuzhiyun 				small_count);
1055*4882a593Smuzhiyun 
1056*4882a593Smuzhiyun 		tx_put = (tx_put + small_count) & (tx_bufsize - 1);
1057*4882a593Smuzhiyun 		char_count -= small_count;
1058*4882a593Smuzhiyun 		info->icount.tx += small_count;
1059*4882a593Smuzhiyun 		info->xmit_cnt -= small_count;
1060*4882a593Smuzhiyun 		info->xmit_tail = (info->xmit_tail + small_count) &
1061*4882a593Smuzhiyun 				(SERIAL_XMIT_SIZE - 1);
1062*4882a593Smuzhiyun 	}
1063*4882a593Smuzhiyun #else
1064*4882a593Smuzhiyun 	while (info->xmit_cnt && char_count) {
1065*4882a593Smuzhiyun 		data = info->port.xmit_buf[info->xmit_tail];
1066*4882a593Smuzhiyun 		info->xmit_cnt--;
1067*4882a593Smuzhiyun 		info->xmit_tail = (info->xmit_tail + 1) &
1068*4882a593Smuzhiyun 				(SERIAL_XMIT_SIZE - 1);
1069*4882a593Smuzhiyun 
1070*4882a593Smuzhiyun 		cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1071*4882a593Smuzhiyun 		tx_put = (tx_put + 1) & (tx_bufsize - 1);
1072*4882a593Smuzhiyun 		char_count--;
1073*4882a593Smuzhiyun 		info->icount.tx++;
1074*4882a593Smuzhiyun 	}
1075*4882a593Smuzhiyun #endif
1076*4882a593Smuzhiyun 	tty_wakeup(tty);
1077*4882a593Smuzhiyun 	tty_kref_put(tty);
1078*4882a593Smuzhiyun ztxdone:
1079*4882a593Smuzhiyun 	/* Update tx_put */
1080*4882a593Smuzhiyun 	cy_writel(&buf_ctrl->tx_put, tx_put);
1081*4882a593Smuzhiyun }
1082*4882a593Smuzhiyun 
cyz_handle_cmd(struct cyclades_card * cinfo)1083*4882a593Smuzhiyun static void cyz_handle_cmd(struct cyclades_card *cinfo)
1084*4882a593Smuzhiyun {
1085*4882a593Smuzhiyun 	struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
1086*4882a593Smuzhiyun 	struct cyclades_port *info;
1087*4882a593Smuzhiyun 	__u32 channel, param, fw_ver;
1088*4882a593Smuzhiyun 	__u8 cmd;
1089*4882a593Smuzhiyun 	int special_count;
1090*4882a593Smuzhiyun 	int delta_count;
1091*4882a593Smuzhiyun 
1092*4882a593Smuzhiyun 	fw_ver = readl(&board_ctrl->fw_version);
1093*4882a593Smuzhiyun 
1094*4882a593Smuzhiyun 	while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
1095*4882a593Smuzhiyun 		special_count = 0;
1096*4882a593Smuzhiyun 		delta_count = 0;
1097*4882a593Smuzhiyun 		info = &cinfo->ports[channel];
1098*4882a593Smuzhiyun 
1099*4882a593Smuzhiyun 		switch (cmd) {
1100*4882a593Smuzhiyun 		case C_CM_PR_ERROR:
1101*4882a593Smuzhiyun 			tty_insert_flip_char(&info->port, 0, TTY_PARITY);
1102*4882a593Smuzhiyun 			info->icount.rx++;
1103*4882a593Smuzhiyun 			special_count++;
1104*4882a593Smuzhiyun 			break;
1105*4882a593Smuzhiyun 		case C_CM_FR_ERROR:
1106*4882a593Smuzhiyun 			tty_insert_flip_char(&info->port, 0, TTY_FRAME);
1107*4882a593Smuzhiyun 			info->icount.rx++;
1108*4882a593Smuzhiyun 			special_count++;
1109*4882a593Smuzhiyun 			break;
1110*4882a593Smuzhiyun 		case C_CM_RXBRK:
1111*4882a593Smuzhiyun 			tty_insert_flip_char(&info->port, 0, TTY_BREAK);
1112*4882a593Smuzhiyun 			info->icount.rx++;
1113*4882a593Smuzhiyun 			special_count++;
1114*4882a593Smuzhiyun 			break;
1115*4882a593Smuzhiyun 		case C_CM_MDCD:
1116*4882a593Smuzhiyun 			info->icount.dcd++;
1117*4882a593Smuzhiyun 			delta_count++;
1118*4882a593Smuzhiyun 			if (tty_port_check_carrier(&info->port)) {
1119*4882a593Smuzhiyun 				u32 dcd = fw_ver > 241 ? param :
1120*4882a593Smuzhiyun 					readl(&info->u.cyz.ch_ctrl->rs_status);
1121*4882a593Smuzhiyun 				if (dcd & C_RS_DCD)
1122*4882a593Smuzhiyun 					wake_up_interruptible(&info->port.open_wait);
1123*4882a593Smuzhiyun 				else
1124*4882a593Smuzhiyun 					tty_port_tty_hangup(&info->port, false);
1125*4882a593Smuzhiyun 			}
1126*4882a593Smuzhiyun 			break;
1127*4882a593Smuzhiyun 		case C_CM_MCTS:
1128*4882a593Smuzhiyun 			info->icount.cts++;
1129*4882a593Smuzhiyun 			delta_count++;
1130*4882a593Smuzhiyun 			break;
1131*4882a593Smuzhiyun 		case C_CM_MRI:
1132*4882a593Smuzhiyun 			info->icount.rng++;
1133*4882a593Smuzhiyun 			delta_count++;
1134*4882a593Smuzhiyun 			break;
1135*4882a593Smuzhiyun 		case C_CM_MDSR:
1136*4882a593Smuzhiyun 			info->icount.dsr++;
1137*4882a593Smuzhiyun 			delta_count++;
1138*4882a593Smuzhiyun 			break;
1139*4882a593Smuzhiyun #ifdef Z_WAKE
1140*4882a593Smuzhiyun 		case C_CM_IOCTLW:
1141*4882a593Smuzhiyun 			complete(&info->shutdown_wait);
1142*4882a593Smuzhiyun 			break;
1143*4882a593Smuzhiyun #endif
1144*4882a593Smuzhiyun #ifdef CONFIG_CYZ_INTR
1145*4882a593Smuzhiyun 		case C_CM_RXHIWM:
1146*4882a593Smuzhiyun 		case C_CM_RXNNDT:
1147*4882a593Smuzhiyun 		case C_CM_INTBACK2:
1148*4882a593Smuzhiyun 			/* Reception Interrupt */
1149*4882a593Smuzhiyun #ifdef CY_DEBUG_INTERRUPTS
1150*4882a593Smuzhiyun 			printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
1151*4882a593Smuzhiyun 					"port %ld\n", info->card, channel);
1152*4882a593Smuzhiyun #endif
1153*4882a593Smuzhiyun 			cyz_handle_rx(info);
1154*4882a593Smuzhiyun 			break;
1155*4882a593Smuzhiyun 		case C_CM_TXBEMPTY:
1156*4882a593Smuzhiyun 		case C_CM_TXLOWWM:
1157*4882a593Smuzhiyun 		case C_CM_INTBACK:
1158*4882a593Smuzhiyun 			/* Transmission Interrupt */
1159*4882a593Smuzhiyun #ifdef CY_DEBUG_INTERRUPTS
1160*4882a593Smuzhiyun 			printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
1161*4882a593Smuzhiyun 					"port %ld\n", info->card, channel);
1162*4882a593Smuzhiyun #endif
1163*4882a593Smuzhiyun 			cyz_handle_tx(info);
1164*4882a593Smuzhiyun 			break;
1165*4882a593Smuzhiyun #endif				/* CONFIG_CYZ_INTR */
1166*4882a593Smuzhiyun 		case C_CM_FATAL:
1167*4882a593Smuzhiyun 			/* should do something with this !!! */
1168*4882a593Smuzhiyun 			break;
1169*4882a593Smuzhiyun 		default:
1170*4882a593Smuzhiyun 			break;
1171*4882a593Smuzhiyun 		}
1172*4882a593Smuzhiyun 		if (delta_count)
1173*4882a593Smuzhiyun 			wake_up_interruptible(&info->port.delta_msr_wait);
1174*4882a593Smuzhiyun 		if (special_count)
1175*4882a593Smuzhiyun 			tty_flip_buffer_push(&info->port);
1176*4882a593Smuzhiyun 	}
1177*4882a593Smuzhiyun }
1178*4882a593Smuzhiyun 
1179*4882a593Smuzhiyun #ifdef CONFIG_CYZ_INTR
cyz_interrupt(int irq,void * dev_id)1180*4882a593Smuzhiyun static irqreturn_t cyz_interrupt(int irq, void *dev_id)
1181*4882a593Smuzhiyun {
1182*4882a593Smuzhiyun 	struct cyclades_card *cinfo = dev_id;
1183*4882a593Smuzhiyun 
1184*4882a593Smuzhiyun 	if (unlikely(!cyz_is_loaded(cinfo))) {
1185*4882a593Smuzhiyun #ifdef CY_DEBUG_INTERRUPTS
1186*4882a593Smuzhiyun 		printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
1187*4882a593Smuzhiyun 				"(IRQ%d).\n", irq);
1188*4882a593Smuzhiyun #endif
1189*4882a593Smuzhiyun 		return IRQ_NONE;
1190*4882a593Smuzhiyun 	}
1191*4882a593Smuzhiyun 
1192*4882a593Smuzhiyun 	/* Handle the interrupts */
1193*4882a593Smuzhiyun 	cyz_handle_cmd(cinfo);
1194*4882a593Smuzhiyun 
1195*4882a593Smuzhiyun 	return IRQ_HANDLED;
1196*4882a593Smuzhiyun }				/* cyz_interrupt */
1197*4882a593Smuzhiyun 
cyz_rx_restart(struct timer_list * t)1198*4882a593Smuzhiyun static void cyz_rx_restart(struct timer_list *t)
1199*4882a593Smuzhiyun {
1200*4882a593Smuzhiyun 	struct cyclades_port *info = from_timer(info, t, rx_full_timer);
1201*4882a593Smuzhiyun 	struct cyclades_card *card = info->card;
1202*4882a593Smuzhiyun 	int retval;
1203*4882a593Smuzhiyun 	__u32 channel = info->line - card->first_line;
1204*4882a593Smuzhiyun 	unsigned long flags;
1205*4882a593Smuzhiyun 
1206*4882a593Smuzhiyun 	spin_lock_irqsave(&card->card_lock, flags);
1207*4882a593Smuzhiyun 	retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L);
1208*4882a593Smuzhiyun 	if (retval != 0) {
1209*4882a593Smuzhiyun 		printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n",
1210*4882a593Smuzhiyun 			info->line, retval);
1211*4882a593Smuzhiyun 	}
1212*4882a593Smuzhiyun 	spin_unlock_irqrestore(&card->card_lock, flags);
1213*4882a593Smuzhiyun }
1214*4882a593Smuzhiyun 
1215*4882a593Smuzhiyun #else				/* CONFIG_CYZ_INTR */
1216*4882a593Smuzhiyun 
cyz_poll(struct timer_list * unused)1217*4882a593Smuzhiyun static void cyz_poll(struct timer_list *unused)
1218*4882a593Smuzhiyun {
1219*4882a593Smuzhiyun 	struct cyclades_card *cinfo;
1220*4882a593Smuzhiyun 	struct cyclades_port *info;
1221*4882a593Smuzhiyun 	unsigned long expires = jiffies + HZ;
1222*4882a593Smuzhiyun 	unsigned int port, card;
1223*4882a593Smuzhiyun 
1224*4882a593Smuzhiyun 	for (card = 0; card < NR_CARDS; card++) {
1225*4882a593Smuzhiyun 		cinfo = &cy_card[card];
1226*4882a593Smuzhiyun 
1227*4882a593Smuzhiyun 		if (!cy_is_Z(cinfo))
1228*4882a593Smuzhiyun 			continue;
1229*4882a593Smuzhiyun 		if (!cyz_is_loaded(cinfo))
1230*4882a593Smuzhiyun 			continue;
1231*4882a593Smuzhiyun 
1232*4882a593Smuzhiyun 	/* Skip first polling cycle to avoid racing conditions with the FW */
1233*4882a593Smuzhiyun 		if (!cinfo->intr_enabled) {
1234*4882a593Smuzhiyun 			cinfo->intr_enabled = 1;
1235*4882a593Smuzhiyun 			continue;
1236*4882a593Smuzhiyun 		}
1237*4882a593Smuzhiyun 
1238*4882a593Smuzhiyun 		cyz_handle_cmd(cinfo);
1239*4882a593Smuzhiyun 
1240*4882a593Smuzhiyun 		for (port = 0; port < cinfo->nports; port++) {
1241*4882a593Smuzhiyun 			info = &cinfo->ports[port];
1242*4882a593Smuzhiyun 
1243*4882a593Smuzhiyun 			if (!info->throttle)
1244*4882a593Smuzhiyun 				cyz_handle_rx(info);
1245*4882a593Smuzhiyun 			cyz_handle_tx(info);
1246*4882a593Smuzhiyun 		}
1247*4882a593Smuzhiyun 		/* poll every 'cyz_polling_cycle' period */
1248*4882a593Smuzhiyun 		expires = jiffies + cyz_polling_cycle;
1249*4882a593Smuzhiyun 	}
1250*4882a593Smuzhiyun 	mod_timer(&cyz_timerlist, expires);
1251*4882a593Smuzhiyun }				/* cyz_poll */
1252*4882a593Smuzhiyun 
1253*4882a593Smuzhiyun #endif				/* CONFIG_CYZ_INTR */
1254*4882a593Smuzhiyun 
1255*4882a593Smuzhiyun /********** End of block of Cyclades-Z specific code *********/
1256*4882a593Smuzhiyun /***********************************************************/
1257*4882a593Smuzhiyun 
1258*4882a593Smuzhiyun /* This is called whenever a port becomes active;
1259*4882a593Smuzhiyun    interrupts are enabled and DTR & RTS are turned on.
1260*4882a593Smuzhiyun  */
cy_startup(struct cyclades_port * info,struct tty_struct * tty)1261*4882a593Smuzhiyun static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
1262*4882a593Smuzhiyun {
1263*4882a593Smuzhiyun 	struct cyclades_card *card;
1264*4882a593Smuzhiyun 	unsigned long flags;
1265*4882a593Smuzhiyun 	int retval = 0;
1266*4882a593Smuzhiyun 	int channel;
1267*4882a593Smuzhiyun 	unsigned long page;
1268*4882a593Smuzhiyun 
1269*4882a593Smuzhiyun 	card = info->card;
1270*4882a593Smuzhiyun 	channel = info->line - card->first_line;
1271*4882a593Smuzhiyun 
1272*4882a593Smuzhiyun 	page = get_zeroed_page(GFP_KERNEL);
1273*4882a593Smuzhiyun 	if (!page)
1274*4882a593Smuzhiyun 		return -ENOMEM;
1275*4882a593Smuzhiyun 
1276*4882a593Smuzhiyun 	spin_lock_irqsave(&card->card_lock, flags);
1277*4882a593Smuzhiyun 
1278*4882a593Smuzhiyun 	if (tty_port_initialized(&info->port))
1279*4882a593Smuzhiyun 		goto errout;
1280*4882a593Smuzhiyun 
1281*4882a593Smuzhiyun 	if (!info->type) {
1282*4882a593Smuzhiyun 		set_bit(TTY_IO_ERROR, &tty->flags);
1283*4882a593Smuzhiyun 		goto errout;
1284*4882a593Smuzhiyun 	}
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun 	if (info->port.xmit_buf)
1287*4882a593Smuzhiyun 		free_page(page);
1288*4882a593Smuzhiyun 	else
1289*4882a593Smuzhiyun 		info->port.xmit_buf = (unsigned char *)page;
1290*4882a593Smuzhiyun 
1291*4882a593Smuzhiyun 	spin_unlock_irqrestore(&card->card_lock, flags);
1292*4882a593Smuzhiyun 
1293*4882a593Smuzhiyun 	cy_set_line_char(info, tty);
1294*4882a593Smuzhiyun 
1295*4882a593Smuzhiyun 	if (!cy_is_Z(card)) {
1296*4882a593Smuzhiyun 		channel &= 0x03;
1297*4882a593Smuzhiyun 
1298*4882a593Smuzhiyun 		spin_lock_irqsave(&card->card_lock, flags);
1299*4882a593Smuzhiyun 
1300*4882a593Smuzhiyun 		cyy_writeb(info, CyCAR, channel);
1301*4882a593Smuzhiyun 
1302*4882a593Smuzhiyun 		cyy_writeb(info, CyRTPR,
1303*4882a593Smuzhiyun 			(info->default_timeout ? info->default_timeout : 0x02));
1304*4882a593Smuzhiyun 		/* 10ms rx timeout */
1305*4882a593Smuzhiyun 
1306*4882a593Smuzhiyun 		cyy_issue_cmd(info, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR);
1307*4882a593Smuzhiyun 
1308*4882a593Smuzhiyun 		cyy_change_rts_dtr(info, TIOCM_RTS | TIOCM_DTR, 0);
1309*4882a593Smuzhiyun 
1310*4882a593Smuzhiyun 		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyRxData);
1311*4882a593Smuzhiyun 	} else {
1312*4882a593Smuzhiyun 		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
1313*4882a593Smuzhiyun 
1314*4882a593Smuzhiyun 		if (!cyz_is_loaded(card))
1315*4882a593Smuzhiyun 			return -ENODEV;
1316*4882a593Smuzhiyun 
1317*4882a593Smuzhiyun #ifdef CY_DEBUG_OPEN
1318*4882a593Smuzhiyun 		printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
1319*4882a593Smuzhiyun 			"base_addr %p\n", card, channel, card->base_addr);
1320*4882a593Smuzhiyun #endif
1321*4882a593Smuzhiyun 		spin_lock_irqsave(&card->card_lock, flags);
1322*4882a593Smuzhiyun 
1323*4882a593Smuzhiyun 		cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE);
1324*4882a593Smuzhiyun #ifdef Z_WAKE
1325*4882a593Smuzhiyun #ifdef CONFIG_CYZ_INTR
1326*4882a593Smuzhiyun 		cy_writel(&ch_ctrl->intr_enable,
1327*4882a593Smuzhiyun 			  C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1328*4882a593Smuzhiyun 			  C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
1329*4882a593Smuzhiyun #else
1330*4882a593Smuzhiyun 		cy_writel(&ch_ctrl->intr_enable,
1331*4882a593Smuzhiyun 			  C_IN_IOCTLW | C_IN_MDCD);
1332*4882a593Smuzhiyun #endif				/* CONFIG_CYZ_INTR */
1333*4882a593Smuzhiyun #else
1334*4882a593Smuzhiyun #ifdef CONFIG_CYZ_INTR
1335*4882a593Smuzhiyun 		cy_writel(&ch_ctrl->intr_enable,
1336*4882a593Smuzhiyun 			  C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1337*4882a593Smuzhiyun 			  C_IN_RXNNDT | C_IN_MDCD);
1338*4882a593Smuzhiyun #else
1339*4882a593Smuzhiyun 		cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD);
1340*4882a593Smuzhiyun #endif				/* CONFIG_CYZ_INTR */
1341*4882a593Smuzhiyun #endif				/* Z_WAKE */
1342*4882a593Smuzhiyun 
1343*4882a593Smuzhiyun 		retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
1344*4882a593Smuzhiyun 		if (retval != 0) {
1345*4882a593Smuzhiyun 			printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "
1346*4882a593Smuzhiyun 				"%x\n", info->line, retval);
1347*4882a593Smuzhiyun 		}
1348*4882a593Smuzhiyun 
1349*4882a593Smuzhiyun 		/* Flush RX buffers before raising DTR and RTS */
1350*4882a593Smuzhiyun 		retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L);
1351*4882a593Smuzhiyun 		if (retval != 0) {
1352*4882a593Smuzhiyun 			printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was "
1353*4882a593Smuzhiyun 				"%x\n", info->line, retval);
1354*4882a593Smuzhiyun 		}
1355*4882a593Smuzhiyun 
1356*4882a593Smuzhiyun 		/* set timeout !!! */
1357*4882a593Smuzhiyun 		/* set RTS and DTR !!! */
1358*4882a593Smuzhiyun 		tty_port_raise_dtr_rts(&info->port);
1359*4882a593Smuzhiyun 
1360*4882a593Smuzhiyun 		/* enable send, recv, modem !!! */
1361*4882a593Smuzhiyun 	}
1362*4882a593Smuzhiyun 
1363*4882a593Smuzhiyun 	tty_port_set_initialized(&info->port, 1);
1364*4882a593Smuzhiyun 
1365*4882a593Smuzhiyun 	clear_bit(TTY_IO_ERROR, &tty->flags);
1366*4882a593Smuzhiyun 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1367*4882a593Smuzhiyun 	info->breakon = info->breakoff = 0;
1368*4882a593Smuzhiyun 	memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
1369*4882a593Smuzhiyun 	info->idle_stats.in_use =
1370*4882a593Smuzhiyun 	info->idle_stats.recv_idle =
1371*4882a593Smuzhiyun 	info->idle_stats.xmit_idle = jiffies;
1372*4882a593Smuzhiyun 
1373*4882a593Smuzhiyun 	spin_unlock_irqrestore(&card->card_lock, flags);
1374*4882a593Smuzhiyun 
1375*4882a593Smuzhiyun #ifdef CY_DEBUG_OPEN
1376*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyc startup done\n");
1377*4882a593Smuzhiyun #endif
1378*4882a593Smuzhiyun 	return 0;
1379*4882a593Smuzhiyun 
1380*4882a593Smuzhiyun errout:
1381*4882a593Smuzhiyun 	spin_unlock_irqrestore(&card->card_lock, flags);
1382*4882a593Smuzhiyun 	free_page(page);
1383*4882a593Smuzhiyun 	return retval;
1384*4882a593Smuzhiyun }				/* startup */
1385*4882a593Smuzhiyun 
start_xmit(struct cyclades_port * info)1386*4882a593Smuzhiyun static void start_xmit(struct cyclades_port *info)
1387*4882a593Smuzhiyun {
1388*4882a593Smuzhiyun 	struct cyclades_card *card = info->card;
1389*4882a593Smuzhiyun 	unsigned long flags;
1390*4882a593Smuzhiyun 	int channel = info->line - card->first_line;
1391*4882a593Smuzhiyun 
1392*4882a593Smuzhiyun 	if (!cy_is_Z(card)) {
1393*4882a593Smuzhiyun 		spin_lock_irqsave(&card->card_lock, flags);
1394*4882a593Smuzhiyun 		cyy_writeb(info, CyCAR, channel & 0x03);
1395*4882a593Smuzhiyun 		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
1396*4882a593Smuzhiyun 		spin_unlock_irqrestore(&card->card_lock, flags);
1397*4882a593Smuzhiyun 	} else {
1398*4882a593Smuzhiyun #ifdef CONFIG_CYZ_INTR
1399*4882a593Smuzhiyun 		int retval;
1400*4882a593Smuzhiyun 
1401*4882a593Smuzhiyun 		spin_lock_irqsave(&card->card_lock, flags);
1402*4882a593Smuzhiyun 		retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);
1403*4882a593Smuzhiyun 		if (retval != 0) {
1404*4882a593Smuzhiyun 			printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "
1405*4882a593Smuzhiyun 				"%x\n", info->line, retval);
1406*4882a593Smuzhiyun 		}
1407*4882a593Smuzhiyun 		spin_unlock_irqrestore(&card->card_lock, flags);
1408*4882a593Smuzhiyun #else				/* CONFIG_CYZ_INTR */
1409*4882a593Smuzhiyun 		/* Don't have to do anything at this time */
1410*4882a593Smuzhiyun #endif				/* CONFIG_CYZ_INTR */
1411*4882a593Smuzhiyun 	}
1412*4882a593Smuzhiyun }				/* start_xmit */
1413*4882a593Smuzhiyun 
1414*4882a593Smuzhiyun /*
1415*4882a593Smuzhiyun  * This routine shuts down a serial port; interrupts are disabled,
1416*4882a593Smuzhiyun  * and DTR is dropped if the hangup on close termio flag is on.
1417*4882a593Smuzhiyun  */
cy_shutdown(struct cyclades_port * info,struct tty_struct * tty)1418*4882a593Smuzhiyun static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
1419*4882a593Smuzhiyun {
1420*4882a593Smuzhiyun 	struct cyclades_card *card;
1421*4882a593Smuzhiyun 	unsigned long flags;
1422*4882a593Smuzhiyun 
1423*4882a593Smuzhiyun 	if (!tty_port_initialized(&info->port))
1424*4882a593Smuzhiyun 		return;
1425*4882a593Smuzhiyun 
1426*4882a593Smuzhiyun 	card = info->card;
1427*4882a593Smuzhiyun 	if (!cy_is_Z(card)) {
1428*4882a593Smuzhiyun 		spin_lock_irqsave(&card->card_lock, flags);
1429*4882a593Smuzhiyun 
1430*4882a593Smuzhiyun 		/* Clear delta_msr_wait queue to avoid mem leaks. */
1431*4882a593Smuzhiyun 		wake_up_interruptible(&info->port.delta_msr_wait);
1432*4882a593Smuzhiyun 
1433*4882a593Smuzhiyun 		if (info->port.xmit_buf) {
1434*4882a593Smuzhiyun 			unsigned char *temp;
1435*4882a593Smuzhiyun 			temp = info->port.xmit_buf;
1436*4882a593Smuzhiyun 			info->port.xmit_buf = NULL;
1437*4882a593Smuzhiyun 			free_page((unsigned long)temp);
1438*4882a593Smuzhiyun 		}
1439*4882a593Smuzhiyun 		if (C_HUPCL(tty))
1440*4882a593Smuzhiyun 			cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);
1441*4882a593Smuzhiyun 
1442*4882a593Smuzhiyun 		cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR);
1443*4882a593Smuzhiyun 		/* it may be appropriate to clear _XMIT at
1444*4882a593Smuzhiyun 		   some later date (after testing)!!! */
1445*4882a593Smuzhiyun 
1446*4882a593Smuzhiyun 		set_bit(TTY_IO_ERROR, &tty->flags);
1447*4882a593Smuzhiyun 		tty_port_set_initialized(&info->port, 0);
1448*4882a593Smuzhiyun 		spin_unlock_irqrestore(&card->card_lock, flags);
1449*4882a593Smuzhiyun 	} else {
1450*4882a593Smuzhiyun #ifdef CY_DEBUG_OPEN
1451*4882a593Smuzhiyun 		int channel = info->line - card->first_line;
1452*4882a593Smuzhiyun 		printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
1453*4882a593Smuzhiyun 			"base_addr %p\n", card, channel, card->base_addr);
1454*4882a593Smuzhiyun #endif
1455*4882a593Smuzhiyun 
1456*4882a593Smuzhiyun 		if (!cyz_is_loaded(card))
1457*4882a593Smuzhiyun 			return;
1458*4882a593Smuzhiyun 
1459*4882a593Smuzhiyun 		spin_lock_irqsave(&card->card_lock, flags);
1460*4882a593Smuzhiyun 
1461*4882a593Smuzhiyun 		if (info->port.xmit_buf) {
1462*4882a593Smuzhiyun 			unsigned char *temp;
1463*4882a593Smuzhiyun 			temp = info->port.xmit_buf;
1464*4882a593Smuzhiyun 			info->port.xmit_buf = NULL;
1465*4882a593Smuzhiyun 			free_page((unsigned long)temp);
1466*4882a593Smuzhiyun 		}
1467*4882a593Smuzhiyun 
1468*4882a593Smuzhiyun 		if (C_HUPCL(tty))
1469*4882a593Smuzhiyun 			tty_port_lower_dtr_rts(&info->port);
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun 		set_bit(TTY_IO_ERROR, &tty->flags);
1472*4882a593Smuzhiyun 		tty_port_set_initialized(&info->port, 0);
1473*4882a593Smuzhiyun 
1474*4882a593Smuzhiyun 		spin_unlock_irqrestore(&card->card_lock, flags);
1475*4882a593Smuzhiyun 	}
1476*4882a593Smuzhiyun 
1477*4882a593Smuzhiyun #ifdef CY_DEBUG_OPEN
1478*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyc shutdown done\n");
1479*4882a593Smuzhiyun #endif
1480*4882a593Smuzhiyun }				/* shutdown */
1481*4882a593Smuzhiyun 
1482*4882a593Smuzhiyun /*
1483*4882a593Smuzhiyun  * ------------------------------------------------------------
1484*4882a593Smuzhiyun  * cy_open() and friends
1485*4882a593Smuzhiyun  * ------------------------------------------------------------
1486*4882a593Smuzhiyun  */
1487*4882a593Smuzhiyun 
1488*4882a593Smuzhiyun /*
1489*4882a593Smuzhiyun  * This routine is called whenever a serial port is opened.  It
1490*4882a593Smuzhiyun  * performs the serial-specific initialization for the tty structure.
1491*4882a593Smuzhiyun  */
cy_open(struct tty_struct * tty,struct file * filp)1492*4882a593Smuzhiyun static int cy_open(struct tty_struct *tty, struct file *filp)
1493*4882a593Smuzhiyun {
1494*4882a593Smuzhiyun 	struct cyclades_port *info;
1495*4882a593Smuzhiyun 	unsigned int i, line = tty->index;
1496*4882a593Smuzhiyun 	int retval;
1497*4882a593Smuzhiyun 
1498*4882a593Smuzhiyun 	for (i = 0; i < NR_CARDS; i++)
1499*4882a593Smuzhiyun 		if (line < cy_card[i].first_line + cy_card[i].nports &&
1500*4882a593Smuzhiyun 				line >= cy_card[i].first_line)
1501*4882a593Smuzhiyun 			break;
1502*4882a593Smuzhiyun 	if (i >= NR_CARDS)
1503*4882a593Smuzhiyun 		return -ENODEV;
1504*4882a593Smuzhiyun 	info = &cy_card[i].ports[line - cy_card[i].first_line];
1505*4882a593Smuzhiyun 	if (info->line < 0)
1506*4882a593Smuzhiyun 		return -ENODEV;
1507*4882a593Smuzhiyun 
1508*4882a593Smuzhiyun 	/* If the card's firmware hasn't been loaded,
1509*4882a593Smuzhiyun 	   treat it as absent from the system.  This
1510*4882a593Smuzhiyun 	   will make the user pay attention.
1511*4882a593Smuzhiyun 	 */
1512*4882a593Smuzhiyun 	if (cy_is_Z(info->card)) {
1513*4882a593Smuzhiyun 		struct cyclades_card *cinfo = info->card;
1514*4882a593Smuzhiyun 		struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
1515*4882a593Smuzhiyun 
1516*4882a593Smuzhiyun 		if (!cyz_is_loaded(cinfo)) {
1517*4882a593Smuzhiyun 			if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
1518*4882a593Smuzhiyun 					readl(&firm_id->signature) ==
1519*4882a593Smuzhiyun 					ZFIRM_HLT) {
1520*4882a593Smuzhiyun 				printk(KERN_ERR "cyc:Cyclades-Z Error: you "
1521*4882a593Smuzhiyun 					"need an external power supply for "
1522*4882a593Smuzhiyun 					"this number of ports.\nFirmware "
1523*4882a593Smuzhiyun 					"halted.\n");
1524*4882a593Smuzhiyun 			} else {
1525*4882a593Smuzhiyun 				printk(KERN_ERR "cyc:Cyclades-Z firmware not "
1526*4882a593Smuzhiyun 					"yet loaded\n");
1527*4882a593Smuzhiyun 			}
1528*4882a593Smuzhiyun 			return -ENODEV;
1529*4882a593Smuzhiyun 		}
1530*4882a593Smuzhiyun #ifdef CONFIG_CYZ_INTR
1531*4882a593Smuzhiyun 		else {
1532*4882a593Smuzhiyun 		/* In case this Z board is operating in interrupt mode, its
1533*4882a593Smuzhiyun 		   interrupts should be enabled as soon as the first open
1534*4882a593Smuzhiyun 		   happens to one of its ports. */
1535*4882a593Smuzhiyun 			if (!cinfo->intr_enabled) {
1536*4882a593Smuzhiyun 				u16 intr;
1537*4882a593Smuzhiyun 
1538*4882a593Smuzhiyun 				/* Enable interrupts on the PLX chip */
1539*4882a593Smuzhiyun 				intr = readw(&cinfo->ctl_addr.p9060->
1540*4882a593Smuzhiyun 						intr_ctrl_stat) | 0x0900;
1541*4882a593Smuzhiyun 				cy_writew(&cinfo->ctl_addr.p9060->
1542*4882a593Smuzhiyun 						intr_ctrl_stat, intr);
1543*4882a593Smuzhiyun 				/* Enable interrupts on the FW */
1544*4882a593Smuzhiyun 				retval = cyz_issue_cmd(cinfo, 0,
1545*4882a593Smuzhiyun 						C_CM_IRQ_ENBL, 0L);
1546*4882a593Smuzhiyun 				if (retval != 0) {
1547*4882a593Smuzhiyun 					printk(KERN_ERR "cyc:IRQ enable retval "
1548*4882a593Smuzhiyun 						"was %x\n", retval);
1549*4882a593Smuzhiyun 				}
1550*4882a593Smuzhiyun 				cinfo->intr_enabled = 1;
1551*4882a593Smuzhiyun 			}
1552*4882a593Smuzhiyun 		}
1553*4882a593Smuzhiyun #endif				/* CONFIG_CYZ_INTR */
1554*4882a593Smuzhiyun 		/* Make sure this Z port really exists in hardware */
1555*4882a593Smuzhiyun 		if (info->line > (cinfo->first_line + cinfo->nports - 1))
1556*4882a593Smuzhiyun 			return -ENODEV;
1557*4882a593Smuzhiyun 	}
1558*4882a593Smuzhiyun #ifdef CY_DEBUG_OTHER
1559*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
1560*4882a593Smuzhiyun #endif
1561*4882a593Smuzhiyun 	tty->driver_data = info;
1562*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, "cy_open"))
1563*4882a593Smuzhiyun 		return -ENODEV;
1564*4882a593Smuzhiyun 
1565*4882a593Smuzhiyun #ifdef CY_DEBUG_OPEN
1566*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
1567*4882a593Smuzhiyun 			info->port.count);
1568*4882a593Smuzhiyun #endif
1569*4882a593Smuzhiyun 	info->port.count++;
1570*4882a593Smuzhiyun #ifdef CY_DEBUG_COUNT
1571*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
1572*4882a593Smuzhiyun 		current->pid, info->port.count);
1573*4882a593Smuzhiyun #endif
1574*4882a593Smuzhiyun 
1575*4882a593Smuzhiyun 	/*
1576*4882a593Smuzhiyun 	 * Start up serial port
1577*4882a593Smuzhiyun 	 */
1578*4882a593Smuzhiyun 	retval = cy_startup(info, tty);
1579*4882a593Smuzhiyun 	if (retval)
1580*4882a593Smuzhiyun 		return retval;
1581*4882a593Smuzhiyun 
1582*4882a593Smuzhiyun 	retval = tty_port_block_til_ready(&info->port, tty, filp);
1583*4882a593Smuzhiyun 	if (retval) {
1584*4882a593Smuzhiyun #ifdef CY_DEBUG_OPEN
1585*4882a593Smuzhiyun 		printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
1586*4882a593Smuzhiyun 			"with %d\n", retval);
1587*4882a593Smuzhiyun #endif
1588*4882a593Smuzhiyun 		return retval;
1589*4882a593Smuzhiyun 	}
1590*4882a593Smuzhiyun 
1591*4882a593Smuzhiyun 	info->throttle = 0;
1592*4882a593Smuzhiyun 	tty_port_tty_set(&info->port, tty);
1593*4882a593Smuzhiyun 
1594*4882a593Smuzhiyun #ifdef CY_DEBUG_OPEN
1595*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyc:cy_open done\n");
1596*4882a593Smuzhiyun #endif
1597*4882a593Smuzhiyun 	return 0;
1598*4882a593Smuzhiyun }				/* cy_open */
1599*4882a593Smuzhiyun 
1600*4882a593Smuzhiyun /*
1601*4882a593Smuzhiyun  * cy_wait_until_sent() --- wait until the transmitter is empty
1602*4882a593Smuzhiyun  */
cy_wait_until_sent(struct tty_struct * tty,int timeout)1603*4882a593Smuzhiyun static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
1604*4882a593Smuzhiyun {
1605*4882a593Smuzhiyun 	struct cyclades_card *card;
1606*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
1607*4882a593Smuzhiyun 	unsigned long orig_jiffies;
1608*4882a593Smuzhiyun 	int char_time;
1609*4882a593Smuzhiyun 
1610*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
1611*4882a593Smuzhiyun 		return;
1612*4882a593Smuzhiyun 
1613*4882a593Smuzhiyun 	if (info->xmit_fifo_size == 0)
1614*4882a593Smuzhiyun 		return;		/* Just in case.... */
1615*4882a593Smuzhiyun 
1616*4882a593Smuzhiyun 	orig_jiffies = jiffies;
1617*4882a593Smuzhiyun 	/*
1618*4882a593Smuzhiyun 	 * Set the check interval to be 1/5 of the estimated time to
1619*4882a593Smuzhiyun 	 * send a single character, and make it at least 1.  The check
1620*4882a593Smuzhiyun 	 * interval should also be less than the timeout.
1621*4882a593Smuzhiyun 	 *
1622*4882a593Smuzhiyun 	 * Note: we have to use pretty tight timings here to satisfy
1623*4882a593Smuzhiyun 	 * the NIST-PCTS.
1624*4882a593Smuzhiyun 	 */
1625*4882a593Smuzhiyun 	char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
1626*4882a593Smuzhiyun 	char_time = char_time / 5;
1627*4882a593Smuzhiyun 	if (char_time <= 0)
1628*4882a593Smuzhiyun 		char_time = 1;
1629*4882a593Smuzhiyun 	if (timeout < 0)
1630*4882a593Smuzhiyun 		timeout = 0;
1631*4882a593Smuzhiyun 	if (timeout)
1632*4882a593Smuzhiyun 		char_time = min(char_time, timeout);
1633*4882a593Smuzhiyun 	/*
1634*4882a593Smuzhiyun 	 * If the transmitter hasn't cleared in twice the approximate
1635*4882a593Smuzhiyun 	 * amount of time to send the entire FIFO, it probably won't
1636*4882a593Smuzhiyun 	 * ever clear.  This assumes the UART isn't doing flow
1637*4882a593Smuzhiyun 	 * control, which is currently the case.  Hence, if it ever
1638*4882a593Smuzhiyun 	 * takes longer than info->timeout, this is probably due to a
1639*4882a593Smuzhiyun 	 * UART bug of some kind.  So, we clamp the timeout parameter at
1640*4882a593Smuzhiyun 	 * 2*info->timeout.
1641*4882a593Smuzhiyun 	 */
1642*4882a593Smuzhiyun 	if (!timeout || timeout > 2 * info->timeout)
1643*4882a593Smuzhiyun 		timeout = 2 * info->timeout;
1644*4882a593Smuzhiyun 
1645*4882a593Smuzhiyun 	card = info->card;
1646*4882a593Smuzhiyun 	if (!cy_is_Z(card)) {
1647*4882a593Smuzhiyun 		while (cyy_readb(info, CySRER) & CyTxRdy) {
1648*4882a593Smuzhiyun 			if (msleep_interruptible(jiffies_to_msecs(char_time)))
1649*4882a593Smuzhiyun 				break;
1650*4882a593Smuzhiyun 			if (timeout && time_after(jiffies, orig_jiffies +
1651*4882a593Smuzhiyun 					timeout))
1652*4882a593Smuzhiyun 				break;
1653*4882a593Smuzhiyun 		}
1654*4882a593Smuzhiyun 	}
1655*4882a593Smuzhiyun 	/* Run one more char cycle */
1656*4882a593Smuzhiyun 	msleep_interruptible(jiffies_to_msecs(char_time * 5));
1657*4882a593Smuzhiyun }
1658*4882a593Smuzhiyun 
cy_flush_buffer(struct tty_struct * tty)1659*4882a593Smuzhiyun static void cy_flush_buffer(struct tty_struct *tty)
1660*4882a593Smuzhiyun {
1661*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
1662*4882a593Smuzhiyun 	struct cyclades_card *card;
1663*4882a593Smuzhiyun 	int channel, retval;
1664*4882a593Smuzhiyun 	unsigned long flags;
1665*4882a593Smuzhiyun 
1666*4882a593Smuzhiyun #ifdef CY_DEBUG_IO
1667*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
1668*4882a593Smuzhiyun #endif
1669*4882a593Smuzhiyun 
1670*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1671*4882a593Smuzhiyun 		return;
1672*4882a593Smuzhiyun 
1673*4882a593Smuzhiyun 	card = info->card;
1674*4882a593Smuzhiyun 	channel = info->line - card->first_line;
1675*4882a593Smuzhiyun 
1676*4882a593Smuzhiyun 	spin_lock_irqsave(&card->card_lock, flags);
1677*4882a593Smuzhiyun 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1678*4882a593Smuzhiyun 	spin_unlock_irqrestore(&card->card_lock, flags);
1679*4882a593Smuzhiyun 
1680*4882a593Smuzhiyun 	if (cy_is_Z(card)) {	/* If it is a Z card, flush the on-board
1681*4882a593Smuzhiyun 					   buffers as well */
1682*4882a593Smuzhiyun 		spin_lock_irqsave(&card->card_lock, flags);
1683*4882a593Smuzhiyun 		retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
1684*4882a593Smuzhiyun 		if (retval != 0) {
1685*4882a593Smuzhiyun 			printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
1686*4882a593Smuzhiyun 				"was %x\n", info->line, retval);
1687*4882a593Smuzhiyun 		}
1688*4882a593Smuzhiyun 		spin_unlock_irqrestore(&card->card_lock, flags);
1689*4882a593Smuzhiyun 	}
1690*4882a593Smuzhiyun 	tty_wakeup(tty);
1691*4882a593Smuzhiyun }				/* cy_flush_buffer */
1692*4882a593Smuzhiyun 
1693*4882a593Smuzhiyun 
cy_do_close(struct tty_port * port)1694*4882a593Smuzhiyun static void cy_do_close(struct tty_port *port)
1695*4882a593Smuzhiyun {
1696*4882a593Smuzhiyun 	struct cyclades_port *info = container_of(port, struct cyclades_port,
1697*4882a593Smuzhiyun 								port);
1698*4882a593Smuzhiyun 	struct cyclades_card *card;
1699*4882a593Smuzhiyun 	unsigned long flags;
1700*4882a593Smuzhiyun 	int channel;
1701*4882a593Smuzhiyun 
1702*4882a593Smuzhiyun 	card = info->card;
1703*4882a593Smuzhiyun 	channel = info->line - card->first_line;
1704*4882a593Smuzhiyun 	spin_lock_irqsave(&card->card_lock, flags);
1705*4882a593Smuzhiyun 
1706*4882a593Smuzhiyun 	if (!cy_is_Z(card)) {
1707*4882a593Smuzhiyun 		/* Stop accepting input */
1708*4882a593Smuzhiyun 		cyy_writeb(info, CyCAR, channel & 0x03);
1709*4882a593Smuzhiyun 		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData);
1710*4882a593Smuzhiyun 		if (tty_port_initialized(&info->port)) {
1711*4882a593Smuzhiyun 			/* Waiting for on-board buffers to be empty before
1712*4882a593Smuzhiyun 			   closing the port */
1713*4882a593Smuzhiyun 			spin_unlock_irqrestore(&card->card_lock, flags);
1714*4882a593Smuzhiyun 			cy_wait_until_sent(port->tty, info->timeout);
1715*4882a593Smuzhiyun 			spin_lock_irqsave(&card->card_lock, flags);
1716*4882a593Smuzhiyun 		}
1717*4882a593Smuzhiyun 	} else {
1718*4882a593Smuzhiyun #ifdef Z_WAKE
1719*4882a593Smuzhiyun 		/* Waiting for on-board buffers to be empty before closing
1720*4882a593Smuzhiyun 		   the port */
1721*4882a593Smuzhiyun 		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
1722*4882a593Smuzhiyun 		int retval;
1723*4882a593Smuzhiyun 
1724*4882a593Smuzhiyun 		if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
1725*4882a593Smuzhiyun 			retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
1726*4882a593Smuzhiyun 			if (retval != 0) {
1727*4882a593Smuzhiyun 				printk(KERN_DEBUG "cyc:cy_close retval on "
1728*4882a593Smuzhiyun 					"ttyC%d was %x\n", info->line, retval);
1729*4882a593Smuzhiyun 			}
1730*4882a593Smuzhiyun 			spin_unlock_irqrestore(&card->card_lock, flags);
1731*4882a593Smuzhiyun 			wait_for_completion_interruptible(&info->shutdown_wait);
1732*4882a593Smuzhiyun 			spin_lock_irqsave(&card->card_lock, flags);
1733*4882a593Smuzhiyun 		}
1734*4882a593Smuzhiyun #endif
1735*4882a593Smuzhiyun 	}
1736*4882a593Smuzhiyun 	spin_unlock_irqrestore(&card->card_lock, flags);
1737*4882a593Smuzhiyun 	cy_shutdown(info, port->tty);
1738*4882a593Smuzhiyun }
1739*4882a593Smuzhiyun 
1740*4882a593Smuzhiyun /*
1741*4882a593Smuzhiyun  * This routine is called when a particular tty device is closed.
1742*4882a593Smuzhiyun  */
cy_close(struct tty_struct * tty,struct file * filp)1743*4882a593Smuzhiyun static void cy_close(struct tty_struct *tty, struct file *filp)
1744*4882a593Smuzhiyun {
1745*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
1746*4882a593Smuzhiyun 	if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
1747*4882a593Smuzhiyun 		return;
1748*4882a593Smuzhiyun 	tty_port_close(&info->port, tty, filp);
1749*4882a593Smuzhiyun }				/* cy_close */
1750*4882a593Smuzhiyun 
1751*4882a593Smuzhiyun /* This routine gets called when tty_write has put something into
1752*4882a593Smuzhiyun  * the write_queue.  The characters may come from user space or
1753*4882a593Smuzhiyun  * kernel space.
1754*4882a593Smuzhiyun  *
1755*4882a593Smuzhiyun  * This routine will return the number of characters actually
1756*4882a593Smuzhiyun  * accepted for writing.
1757*4882a593Smuzhiyun  *
1758*4882a593Smuzhiyun  * If the port is not already transmitting stuff, start it off by
1759*4882a593Smuzhiyun  * enabling interrupts.  The interrupt service routine will then
1760*4882a593Smuzhiyun  * ensure that the characters are sent.
1761*4882a593Smuzhiyun  * If the port is already active, there is no need to kick it.
1762*4882a593Smuzhiyun  *
1763*4882a593Smuzhiyun  */
cy_write(struct tty_struct * tty,const unsigned char * buf,int count)1764*4882a593Smuzhiyun static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
1765*4882a593Smuzhiyun {
1766*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
1767*4882a593Smuzhiyun 	unsigned long flags;
1768*4882a593Smuzhiyun 	int c, ret = 0;
1769*4882a593Smuzhiyun 
1770*4882a593Smuzhiyun #ifdef CY_DEBUG_IO
1771*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
1772*4882a593Smuzhiyun #endif
1773*4882a593Smuzhiyun 
1774*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, "cy_write"))
1775*4882a593Smuzhiyun 		return 0;
1776*4882a593Smuzhiyun 
1777*4882a593Smuzhiyun 	if (!info->port.xmit_buf)
1778*4882a593Smuzhiyun 		return 0;
1779*4882a593Smuzhiyun 
1780*4882a593Smuzhiyun 	spin_lock_irqsave(&info->card->card_lock, flags);
1781*4882a593Smuzhiyun 	while (1) {
1782*4882a593Smuzhiyun 		c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
1783*4882a593Smuzhiyun 		c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
1784*4882a593Smuzhiyun 
1785*4882a593Smuzhiyun 		if (c <= 0)
1786*4882a593Smuzhiyun 			break;
1787*4882a593Smuzhiyun 
1788*4882a593Smuzhiyun 		memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
1789*4882a593Smuzhiyun 		info->xmit_head = (info->xmit_head + c) &
1790*4882a593Smuzhiyun 			(SERIAL_XMIT_SIZE - 1);
1791*4882a593Smuzhiyun 		info->xmit_cnt += c;
1792*4882a593Smuzhiyun 		buf += c;
1793*4882a593Smuzhiyun 		count -= c;
1794*4882a593Smuzhiyun 		ret += c;
1795*4882a593Smuzhiyun 	}
1796*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->card->card_lock, flags);
1797*4882a593Smuzhiyun 
1798*4882a593Smuzhiyun 	info->idle_stats.xmit_bytes += ret;
1799*4882a593Smuzhiyun 	info->idle_stats.xmit_idle = jiffies;
1800*4882a593Smuzhiyun 
1801*4882a593Smuzhiyun 	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
1802*4882a593Smuzhiyun 		start_xmit(info);
1803*4882a593Smuzhiyun 
1804*4882a593Smuzhiyun 	return ret;
1805*4882a593Smuzhiyun }				/* cy_write */
1806*4882a593Smuzhiyun 
1807*4882a593Smuzhiyun /*
1808*4882a593Smuzhiyun  * This routine is called by the kernel to write a single
1809*4882a593Smuzhiyun  * character to the tty device.  If the kernel uses this routine,
1810*4882a593Smuzhiyun  * it must call the flush_chars() routine (if defined) when it is
1811*4882a593Smuzhiyun  * done stuffing characters into the driver.  If there is no room
1812*4882a593Smuzhiyun  * in the queue, the character is ignored.
1813*4882a593Smuzhiyun  */
cy_put_char(struct tty_struct * tty,unsigned char ch)1814*4882a593Smuzhiyun static int cy_put_char(struct tty_struct *tty, unsigned char ch)
1815*4882a593Smuzhiyun {
1816*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
1817*4882a593Smuzhiyun 	unsigned long flags;
1818*4882a593Smuzhiyun 
1819*4882a593Smuzhiyun #ifdef CY_DEBUG_IO
1820*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line);
1821*4882a593Smuzhiyun #endif
1822*4882a593Smuzhiyun 
1823*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, "cy_put_char"))
1824*4882a593Smuzhiyun 		return 0;
1825*4882a593Smuzhiyun 
1826*4882a593Smuzhiyun 	if (!info->port.xmit_buf)
1827*4882a593Smuzhiyun 		return 0;
1828*4882a593Smuzhiyun 
1829*4882a593Smuzhiyun 	spin_lock_irqsave(&info->card->card_lock, flags);
1830*4882a593Smuzhiyun 	if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
1831*4882a593Smuzhiyun 		spin_unlock_irqrestore(&info->card->card_lock, flags);
1832*4882a593Smuzhiyun 		return 0;
1833*4882a593Smuzhiyun 	}
1834*4882a593Smuzhiyun 
1835*4882a593Smuzhiyun 	info->port.xmit_buf[info->xmit_head++] = ch;
1836*4882a593Smuzhiyun 	info->xmit_head &= SERIAL_XMIT_SIZE - 1;
1837*4882a593Smuzhiyun 	info->xmit_cnt++;
1838*4882a593Smuzhiyun 	info->idle_stats.xmit_bytes++;
1839*4882a593Smuzhiyun 	info->idle_stats.xmit_idle = jiffies;
1840*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->card->card_lock, flags);
1841*4882a593Smuzhiyun 	return 1;
1842*4882a593Smuzhiyun }				/* cy_put_char */
1843*4882a593Smuzhiyun 
1844*4882a593Smuzhiyun /*
1845*4882a593Smuzhiyun  * This routine is called by the kernel after it has written a
1846*4882a593Smuzhiyun  * series of characters to the tty device using put_char().
1847*4882a593Smuzhiyun  */
cy_flush_chars(struct tty_struct * tty)1848*4882a593Smuzhiyun static void cy_flush_chars(struct tty_struct *tty)
1849*4882a593Smuzhiyun {
1850*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
1851*4882a593Smuzhiyun 
1852*4882a593Smuzhiyun #ifdef CY_DEBUG_IO
1853*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line);
1854*4882a593Smuzhiyun #endif
1855*4882a593Smuzhiyun 
1856*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
1857*4882a593Smuzhiyun 		return;
1858*4882a593Smuzhiyun 
1859*4882a593Smuzhiyun 	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
1860*4882a593Smuzhiyun 			!info->port.xmit_buf)
1861*4882a593Smuzhiyun 		return;
1862*4882a593Smuzhiyun 
1863*4882a593Smuzhiyun 	start_xmit(info);
1864*4882a593Smuzhiyun }				/* cy_flush_chars */
1865*4882a593Smuzhiyun 
1866*4882a593Smuzhiyun /*
1867*4882a593Smuzhiyun  * This routine returns the numbers of characters the tty driver
1868*4882a593Smuzhiyun  * will accept for queuing to be written.  This number is subject
1869*4882a593Smuzhiyun  * to change as output buffers get emptied, or if the output flow
1870*4882a593Smuzhiyun  * control is activated.
1871*4882a593Smuzhiyun  */
cy_write_room(struct tty_struct * tty)1872*4882a593Smuzhiyun static int cy_write_room(struct tty_struct *tty)
1873*4882a593Smuzhiyun {
1874*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
1875*4882a593Smuzhiyun 	int ret;
1876*4882a593Smuzhiyun 
1877*4882a593Smuzhiyun #ifdef CY_DEBUG_IO
1878*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line);
1879*4882a593Smuzhiyun #endif
1880*4882a593Smuzhiyun 
1881*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, "cy_write_room"))
1882*4882a593Smuzhiyun 		return 0;
1883*4882a593Smuzhiyun 	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
1884*4882a593Smuzhiyun 	if (ret < 0)
1885*4882a593Smuzhiyun 		ret = 0;
1886*4882a593Smuzhiyun 	return ret;
1887*4882a593Smuzhiyun }				/* cy_write_room */
1888*4882a593Smuzhiyun 
cy_chars_in_buffer(struct tty_struct * tty)1889*4882a593Smuzhiyun static int cy_chars_in_buffer(struct tty_struct *tty)
1890*4882a593Smuzhiyun {
1891*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
1892*4882a593Smuzhiyun 
1893*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
1894*4882a593Smuzhiyun 		return 0;
1895*4882a593Smuzhiyun 
1896*4882a593Smuzhiyun #ifdef Z_EXT_CHARS_IN_BUFFER
1897*4882a593Smuzhiyun 	if (!cy_is_Z(info->card)) {
1898*4882a593Smuzhiyun #endif				/* Z_EXT_CHARS_IN_BUFFER */
1899*4882a593Smuzhiyun #ifdef CY_DEBUG_IO
1900*4882a593Smuzhiyun 		printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
1901*4882a593Smuzhiyun 			info->line, info->xmit_cnt);
1902*4882a593Smuzhiyun #endif
1903*4882a593Smuzhiyun 		return info->xmit_cnt;
1904*4882a593Smuzhiyun #ifdef Z_EXT_CHARS_IN_BUFFER
1905*4882a593Smuzhiyun 	} else {
1906*4882a593Smuzhiyun 		struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
1907*4882a593Smuzhiyun 		int char_count;
1908*4882a593Smuzhiyun 		__u32 tx_put, tx_get, tx_bufsize;
1909*4882a593Smuzhiyun 
1910*4882a593Smuzhiyun 		tx_get = readl(&buf_ctrl->tx_get);
1911*4882a593Smuzhiyun 		tx_put = readl(&buf_ctrl->tx_put);
1912*4882a593Smuzhiyun 		tx_bufsize = readl(&buf_ctrl->tx_bufsize);
1913*4882a593Smuzhiyun 		if (tx_put >= tx_get)
1914*4882a593Smuzhiyun 			char_count = tx_put - tx_get;
1915*4882a593Smuzhiyun 		else
1916*4882a593Smuzhiyun 			char_count = tx_put - tx_get + tx_bufsize;
1917*4882a593Smuzhiyun #ifdef CY_DEBUG_IO
1918*4882a593Smuzhiyun 		printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
1919*4882a593Smuzhiyun 			info->line, info->xmit_cnt + char_count);
1920*4882a593Smuzhiyun #endif
1921*4882a593Smuzhiyun 		return info->xmit_cnt + char_count;
1922*4882a593Smuzhiyun 	}
1923*4882a593Smuzhiyun #endif				/* Z_EXT_CHARS_IN_BUFFER */
1924*4882a593Smuzhiyun }				/* cy_chars_in_buffer */
1925*4882a593Smuzhiyun 
1926*4882a593Smuzhiyun /*
1927*4882a593Smuzhiyun  * ------------------------------------------------------------
1928*4882a593Smuzhiyun  * cy_ioctl() and friends
1929*4882a593Smuzhiyun  * ------------------------------------------------------------
1930*4882a593Smuzhiyun  */
1931*4882a593Smuzhiyun 
cyy_baud_calc(struct cyclades_port * info,__u32 baud)1932*4882a593Smuzhiyun static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
1933*4882a593Smuzhiyun {
1934*4882a593Smuzhiyun 	int co, co_val, bpr;
1935*4882a593Smuzhiyun 	__u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
1936*4882a593Smuzhiyun 			25000000);
1937*4882a593Smuzhiyun 
1938*4882a593Smuzhiyun 	if (baud == 0) {
1939*4882a593Smuzhiyun 		info->tbpr = info->tco = info->rbpr = info->rco = 0;
1940*4882a593Smuzhiyun 		return;
1941*4882a593Smuzhiyun 	}
1942*4882a593Smuzhiyun 
1943*4882a593Smuzhiyun 	/* determine which prescaler to use */
1944*4882a593Smuzhiyun 	for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
1945*4882a593Smuzhiyun 		if (cy_clock / co_val / baud > 63)
1946*4882a593Smuzhiyun 			break;
1947*4882a593Smuzhiyun 	}
1948*4882a593Smuzhiyun 
1949*4882a593Smuzhiyun 	bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
1950*4882a593Smuzhiyun 	if (bpr > 255)
1951*4882a593Smuzhiyun 		bpr = 255;
1952*4882a593Smuzhiyun 
1953*4882a593Smuzhiyun 	info->tbpr = info->rbpr = bpr;
1954*4882a593Smuzhiyun 	info->tco = info->rco = co;
1955*4882a593Smuzhiyun }
1956*4882a593Smuzhiyun 
1957*4882a593Smuzhiyun /*
1958*4882a593Smuzhiyun  * This routine finds or computes the various line characteristics.
1959*4882a593Smuzhiyun  * It used to be called config_setup
1960*4882a593Smuzhiyun  */
cy_set_line_char(struct cyclades_port * info,struct tty_struct * tty)1961*4882a593Smuzhiyun static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
1962*4882a593Smuzhiyun {
1963*4882a593Smuzhiyun 	struct cyclades_card *card;
1964*4882a593Smuzhiyun 	unsigned long flags;
1965*4882a593Smuzhiyun 	int channel;
1966*4882a593Smuzhiyun 	unsigned cflag, iflag;
1967*4882a593Smuzhiyun 	int baud, baud_rate = 0;
1968*4882a593Smuzhiyun 	int i;
1969*4882a593Smuzhiyun 
1970*4882a593Smuzhiyun 	if (info->line == -1)
1971*4882a593Smuzhiyun 		return;
1972*4882a593Smuzhiyun 
1973*4882a593Smuzhiyun 	cflag = tty->termios.c_cflag;
1974*4882a593Smuzhiyun 	iflag = tty->termios.c_iflag;
1975*4882a593Smuzhiyun 
1976*4882a593Smuzhiyun 	card = info->card;
1977*4882a593Smuzhiyun 	channel = info->line - card->first_line;
1978*4882a593Smuzhiyun 
1979*4882a593Smuzhiyun 	if (!cy_is_Z(card)) {
1980*4882a593Smuzhiyun 		u32 cflags;
1981*4882a593Smuzhiyun 
1982*4882a593Smuzhiyun 		/* baud rate */
1983*4882a593Smuzhiyun 		baud = tty_get_baud_rate(tty);
1984*4882a593Smuzhiyun 		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
1985*4882a593Smuzhiyun 				ASYNC_SPD_CUST) {
1986*4882a593Smuzhiyun 			if (info->custom_divisor)
1987*4882a593Smuzhiyun 				baud_rate = info->baud / info->custom_divisor;
1988*4882a593Smuzhiyun 			else
1989*4882a593Smuzhiyun 				baud_rate = info->baud;
1990*4882a593Smuzhiyun 		} else if (baud > CD1400_MAX_SPEED) {
1991*4882a593Smuzhiyun 			baud = CD1400_MAX_SPEED;
1992*4882a593Smuzhiyun 		}
1993*4882a593Smuzhiyun 		/* find the baud index */
1994*4882a593Smuzhiyun 		for (i = 0; i < 20; i++) {
1995*4882a593Smuzhiyun 			if (baud == baud_table[i])
1996*4882a593Smuzhiyun 				break;
1997*4882a593Smuzhiyun 		}
1998*4882a593Smuzhiyun 		if (i == 20)
1999*4882a593Smuzhiyun 			i = 19;	/* CD1400_MAX_SPEED */
2000*4882a593Smuzhiyun 
2001*4882a593Smuzhiyun 		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2002*4882a593Smuzhiyun 				ASYNC_SPD_CUST) {
2003*4882a593Smuzhiyun 			cyy_baud_calc(info, baud_rate);
2004*4882a593Smuzhiyun 		} else {
2005*4882a593Smuzhiyun 			if (info->chip_rev >= CD1400_REV_J) {
2006*4882a593Smuzhiyun 				/* It is a CD1400 rev. J or later */
2007*4882a593Smuzhiyun 				info->tbpr = baud_bpr_60[i];	/* Tx BPR */
2008*4882a593Smuzhiyun 				info->tco = baud_co_60[i];	/* Tx CO */
2009*4882a593Smuzhiyun 				info->rbpr = baud_bpr_60[i];	/* Rx BPR */
2010*4882a593Smuzhiyun 				info->rco = baud_co_60[i];	/* Rx CO */
2011*4882a593Smuzhiyun 			} else {
2012*4882a593Smuzhiyun 				info->tbpr = baud_bpr_25[i];	/* Tx BPR */
2013*4882a593Smuzhiyun 				info->tco = baud_co_25[i];	/* Tx CO */
2014*4882a593Smuzhiyun 				info->rbpr = baud_bpr_25[i];	/* Rx BPR */
2015*4882a593Smuzhiyun 				info->rco = baud_co_25[i];	/* Rx CO */
2016*4882a593Smuzhiyun 			}
2017*4882a593Smuzhiyun 		}
2018*4882a593Smuzhiyun 		if (baud_table[i] == 134) {
2019*4882a593Smuzhiyun 			/* get it right for 134.5 baud */
2020*4882a593Smuzhiyun 			info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2021*4882a593Smuzhiyun 					2;
2022*4882a593Smuzhiyun 		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2023*4882a593Smuzhiyun 				ASYNC_SPD_CUST) {
2024*4882a593Smuzhiyun 			info->timeout = (info->xmit_fifo_size * HZ * 15 /
2025*4882a593Smuzhiyun 					baud_rate) + 2;
2026*4882a593Smuzhiyun 		} else if (baud_table[i]) {
2027*4882a593Smuzhiyun 			info->timeout = (info->xmit_fifo_size * HZ * 15 /
2028*4882a593Smuzhiyun 					baud_table[i]) + 2;
2029*4882a593Smuzhiyun 			/* this needs to be propagated into the card info */
2030*4882a593Smuzhiyun 		} else {
2031*4882a593Smuzhiyun 			info->timeout = 0;
2032*4882a593Smuzhiyun 		}
2033*4882a593Smuzhiyun 		/* By tradition (is it a standard?) a baud rate of zero
2034*4882a593Smuzhiyun 		   implies the line should be/has been closed.  A bit
2035*4882a593Smuzhiyun 		   later in this routine such a test is performed. */
2036*4882a593Smuzhiyun 
2037*4882a593Smuzhiyun 		/* byte size and parity */
2038*4882a593Smuzhiyun 		info->cor5 = 0;
2039*4882a593Smuzhiyun 		info->cor4 = 0;
2040*4882a593Smuzhiyun 		/* receive threshold */
2041*4882a593Smuzhiyun 		info->cor3 = (info->default_threshold ?
2042*4882a593Smuzhiyun 				info->default_threshold : baud_cor3[i]);
2043*4882a593Smuzhiyun 		info->cor2 = CyETC;
2044*4882a593Smuzhiyun 		switch (cflag & CSIZE) {
2045*4882a593Smuzhiyun 		case CS5:
2046*4882a593Smuzhiyun 			info->cor1 = Cy_5_BITS;
2047*4882a593Smuzhiyun 			break;
2048*4882a593Smuzhiyun 		case CS6:
2049*4882a593Smuzhiyun 			info->cor1 = Cy_6_BITS;
2050*4882a593Smuzhiyun 			break;
2051*4882a593Smuzhiyun 		case CS7:
2052*4882a593Smuzhiyun 			info->cor1 = Cy_7_BITS;
2053*4882a593Smuzhiyun 			break;
2054*4882a593Smuzhiyun 		case CS8:
2055*4882a593Smuzhiyun 			info->cor1 = Cy_8_BITS;
2056*4882a593Smuzhiyun 			break;
2057*4882a593Smuzhiyun 		}
2058*4882a593Smuzhiyun 		if (cflag & CSTOPB)
2059*4882a593Smuzhiyun 			info->cor1 |= Cy_2_STOP;
2060*4882a593Smuzhiyun 
2061*4882a593Smuzhiyun 		if (cflag & PARENB) {
2062*4882a593Smuzhiyun 			if (cflag & PARODD)
2063*4882a593Smuzhiyun 				info->cor1 |= CyPARITY_O;
2064*4882a593Smuzhiyun 			else
2065*4882a593Smuzhiyun 				info->cor1 |= CyPARITY_E;
2066*4882a593Smuzhiyun 		} else
2067*4882a593Smuzhiyun 			info->cor1 |= CyPARITY_NONE;
2068*4882a593Smuzhiyun 
2069*4882a593Smuzhiyun 		/* CTS flow control flag */
2070*4882a593Smuzhiyun 		tty_port_set_cts_flow(&info->port, cflag & CRTSCTS);
2071*4882a593Smuzhiyun 		if (cflag & CRTSCTS)
2072*4882a593Smuzhiyun 			info->cor2 |= CyCtsAE;
2073*4882a593Smuzhiyun 		else
2074*4882a593Smuzhiyun 			info->cor2 &= ~CyCtsAE;
2075*4882a593Smuzhiyun 		tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
2076*4882a593Smuzhiyun 
2077*4882a593Smuzhiyun 	 /***********************************************
2078*4882a593Smuzhiyun 	    The hardware option, CyRtsAO, presents RTS when
2079*4882a593Smuzhiyun 	    the chip has characters to send.  Since most modems
2080*4882a593Smuzhiyun 	    use RTS as reverse (inbound) flow control, this
2081*4882a593Smuzhiyun 	    option is not used.  If inbound flow control is
2082*4882a593Smuzhiyun 	    necessary, DTR can be programmed to provide the
2083*4882a593Smuzhiyun 	    appropriate signals for use with a non-standard
2084*4882a593Smuzhiyun 	    cable.  Contact Marcio Saito for details.
2085*4882a593Smuzhiyun 	 ***********************************************/
2086*4882a593Smuzhiyun 
2087*4882a593Smuzhiyun 		channel &= 0x03;
2088*4882a593Smuzhiyun 
2089*4882a593Smuzhiyun 		spin_lock_irqsave(&card->card_lock, flags);
2090*4882a593Smuzhiyun 		cyy_writeb(info, CyCAR, channel);
2091*4882a593Smuzhiyun 
2092*4882a593Smuzhiyun 		/* tx and rx baud rate */
2093*4882a593Smuzhiyun 
2094*4882a593Smuzhiyun 		cyy_writeb(info, CyTCOR, info->tco);
2095*4882a593Smuzhiyun 		cyy_writeb(info, CyTBPR, info->tbpr);
2096*4882a593Smuzhiyun 		cyy_writeb(info, CyRCOR, info->rco);
2097*4882a593Smuzhiyun 		cyy_writeb(info, CyRBPR, info->rbpr);
2098*4882a593Smuzhiyun 
2099*4882a593Smuzhiyun 		/* set line characteristics  according configuration */
2100*4882a593Smuzhiyun 
2101*4882a593Smuzhiyun 		cyy_writeb(info, CySCHR1, START_CHAR(tty));
2102*4882a593Smuzhiyun 		cyy_writeb(info, CySCHR2, STOP_CHAR(tty));
2103*4882a593Smuzhiyun 		cyy_writeb(info, CyCOR1, info->cor1);
2104*4882a593Smuzhiyun 		cyy_writeb(info, CyCOR2, info->cor2);
2105*4882a593Smuzhiyun 		cyy_writeb(info, CyCOR3, info->cor3);
2106*4882a593Smuzhiyun 		cyy_writeb(info, CyCOR4, info->cor4);
2107*4882a593Smuzhiyun 		cyy_writeb(info, CyCOR5, info->cor5);
2108*4882a593Smuzhiyun 
2109*4882a593Smuzhiyun 		cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
2110*4882a593Smuzhiyun 				CyCOR3ch);
2111*4882a593Smuzhiyun 
2112*4882a593Smuzhiyun 		/* !!! Is this needed? */
2113*4882a593Smuzhiyun 		cyy_writeb(info, CyCAR, channel);
2114*4882a593Smuzhiyun 		cyy_writeb(info, CyRTPR,
2115*4882a593Smuzhiyun 			(info->default_timeout ? info->default_timeout : 0x02));
2116*4882a593Smuzhiyun 		/* 10ms rx timeout */
2117*4882a593Smuzhiyun 
2118*4882a593Smuzhiyun 		cflags = CyCTS;
2119*4882a593Smuzhiyun 		if (!C_CLOCAL(tty))
2120*4882a593Smuzhiyun 			cflags |= CyDSR | CyRI | CyDCD;
2121*4882a593Smuzhiyun 		/* without modem intr */
2122*4882a593Smuzhiyun 		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyMdmCh);
2123*4882a593Smuzhiyun 		/* act on 1->0 modem transitions */
2124*4882a593Smuzhiyun 		if ((cflag & CRTSCTS) && info->rflow)
2125*4882a593Smuzhiyun 			cyy_writeb(info, CyMCOR1, cflags | rflow_thr[i]);
2126*4882a593Smuzhiyun 		else
2127*4882a593Smuzhiyun 			cyy_writeb(info, CyMCOR1, cflags);
2128*4882a593Smuzhiyun 		/* act on 0->1 modem transitions */
2129*4882a593Smuzhiyun 		cyy_writeb(info, CyMCOR2, cflags);
2130*4882a593Smuzhiyun 
2131*4882a593Smuzhiyun 		if (i == 0)	/* baud rate is zero, turn off line */
2132*4882a593Smuzhiyun 			cyy_change_rts_dtr(info, 0, TIOCM_DTR);
2133*4882a593Smuzhiyun 		else
2134*4882a593Smuzhiyun 			cyy_change_rts_dtr(info, TIOCM_DTR, 0);
2135*4882a593Smuzhiyun 
2136*4882a593Smuzhiyun 		clear_bit(TTY_IO_ERROR, &tty->flags);
2137*4882a593Smuzhiyun 		spin_unlock_irqrestore(&card->card_lock, flags);
2138*4882a593Smuzhiyun 
2139*4882a593Smuzhiyun 	} else {
2140*4882a593Smuzhiyun 		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
2141*4882a593Smuzhiyun 		__u32 sw_flow;
2142*4882a593Smuzhiyun 		int retval;
2143*4882a593Smuzhiyun 
2144*4882a593Smuzhiyun 		if (!cyz_is_loaded(card))
2145*4882a593Smuzhiyun 			return;
2146*4882a593Smuzhiyun 
2147*4882a593Smuzhiyun 		/* baud rate */
2148*4882a593Smuzhiyun 		baud = tty_get_baud_rate(tty);
2149*4882a593Smuzhiyun 		if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2150*4882a593Smuzhiyun 				ASYNC_SPD_CUST) {
2151*4882a593Smuzhiyun 			if (info->custom_divisor)
2152*4882a593Smuzhiyun 				baud_rate = info->baud / info->custom_divisor;
2153*4882a593Smuzhiyun 			else
2154*4882a593Smuzhiyun 				baud_rate = info->baud;
2155*4882a593Smuzhiyun 		} else if (baud > CYZ_MAX_SPEED) {
2156*4882a593Smuzhiyun 			baud = CYZ_MAX_SPEED;
2157*4882a593Smuzhiyun 		}
2158*4882a593Smuzhiyun 		cy_writel(&ch_ctrl->comm_baud, baud);
2159*4882a593Smuzhiyun 
2160*4882a593Smuzhiyun 		if (baud == 134) {
2161*4882a593Smuzhiyun 			/* get it right for 134.5 baud */
2162*4882a593Smuzhiyun 			info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2163*4882a593Smuzhiyun 					2;
2164*4882a593Smuzhiyun 		} else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
2165*4882a593Smuzhiyun 				ASYNC_SPD_CUST) {
2166*4882a593Smuzhiyun 			info->timeout = (info->xmit_fifo_size * HZ * 15 /
2167*4882a593Smuzhiyun 					baud_rate) + 2;
2168*4882a593Smuzhiyun 		} else if (baud) {
2169*4882a593Smuzhiyun 			info->timeout = (info->xmit_fifo_size * HZ * 15 /
2170*4882a593Smuzhiyun 					baud) + 2;
2171*4882a593Smuzhiyun 			/* this needs to be propagated into the card info */
2172*4882a593Smuzhiyun 		} else {
2173*4882a593Smuzhiyun 			info->timeout = 0;
2174*4882a593Smuzhiyun 		}
2175*4882a593Smuzhiyun 
2176*4882a593Smuzhiyun 		/* byte size and parity */
2177*4882a593Smuzhiyun 		switch (cflag & CSIZE) {
2178*4882a593Smuzhiyun 		case CS5:
2179*4882a593Smuzhiyun 			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
2180*4882a593Smuzhiyun 			break;
2181*4882a593Smuzhiyun 		case CS6:
2182*4882a593Smuzhiyun 			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
2183*4882a593Smuzhiyun 			break;
2184*4882a593Smuzhiyun 		case CS7:
2185*4882a593Smuzhiyun 			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
2186*4882a593Smuzhiyun 			break;
2187*4882a593Smuzhiyun 		case CS8:
2188*4882a593Smuzhiyun 			cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
2189*4882a593Smuzhiyun 			break;
2190*4882a593Smuzhiyun 		}
2191*4882a593Smuzhiyun 		if (cflag & CSTOPB) {
2192*4882a593Smuzhiyun 			cy_writel(&ch_ctrl->comm_data_l,
2193*4882a593Smuzhiyun 				  readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
2194*4882a593Smuzhiyun 		} else {
2195*4882a593Smuzhiyun 			cy_writel(&ch_ctrl->comm_data_l,
2196*4882a593Smuzhiyun 				  readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
2197*4882a593Smuzhiyun 		}
2198*4882a593Smuzhiyun 		if (cflag & PARENB) {
2199*4882a593Smuzhiyun 			if (cflag & PARODD)
2200*4882a593Smuzhiyun 				cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
2201*4882a593Smuzhiyun 			else
2202*4882a593Smuzhiyun 				cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
2203*4882a593Smuzhiyun 		} else
2204*4882a593Smuzhiyun 			cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
2205*4882a593Smuzhiyun 
2206*4882a593Smuzhiyun 		/* CTS flow control flag */
2207*4882a593Smuzhiyun 		if (cflag & CRTSCTS) {
2208*4882a593Smuzhiyun 			cy_writel(&ch_ctrl->hw_flow,
2209*4882a593Smuzhiyun 				readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
2210*4882a593Smuzhiyun 		} else {
2211*4882a593Smuzhiyun 			cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
2212*4882a593Smuzhiyun 					~(C_RS_CTS | C_RS_RTS));
2213*4882a593Smuzhiyun 		}
2214*4882a593Smuzhiyun 		/* As the HW flow control is done in firmware, the driver
2215*4882a593Smuzhiyun 		   doesn't need to care about it */
2216*4882a593Smuzhiyun 		tty_port_set_cts_flow(&info->port, 0);
2217*4882a593Smuzhiyun 
2218*4882a593Smuzhiyun 		/* XON/XOFF/XANY flow control flags */
2219*4882a593Smuzhiyun 		sw_flow = 0;
2220*4882a593Smuzhiyun 		if (iflag & IXON) {
2221*4882a593Smuzhiyun 			sw_flow |= C_FL_OXX;
2222*4882a593Smuzhiyun 			if (iflag & IXANY)
2223*4882a593Smuzhiyun 				sw_flow |= C_FL_OIXANY;
2224*4882a593Smuzhiyun 		}
2225*4882a593Smuzhiyun 		cy_writel(&ch_ctrl->sw_flow, sw_flow);
2226*4882a593Smuzhiyun 
2227*4882a593Smuzhiyun 		retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
2228*4882a593Smuzhiyun 		if (retval != 0) {
2229*4882a593Smuzhiyun 			printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
2230*4882a593Smuzhiyun 				"was %x\n", info->line, retval);
2231*4882a593Smuzhiyun 		}
2232*4882a593Smuzhiyun 
2233*4882a593Smuzhiyun 		/* CD sensitivity */
2234*4882a593Smuzhiyun 		tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
2235*4882a593Smuzhiyun 
2236*4882a593Smuzhiyun 		if (baud == 0) {	/* baud rate is zero, turn off line */
2237*4882a593Smuzhiyun 			cy_writel(&ch_ctrl->rs_control,
2238*4882a593Smuzhiyun 				  readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
2239*4882a593Smuzhiyun #ifdef CY_DEBUG_DTR
2240*4882a593Smuzhiyun 			printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
2241*4882a593Smuzhiyun #endif
2242*4882a593Smuzhiyun 		} else {
2243*4882a593Smuzhiyun 			cy_writel(&ch_ctrl->rs_control,
2244*4882a593Smuzhiyun 				  readl(&ch_ctrl->rs_control) | C_RS_DTR);
2245*4882a593Smuzhiyun #ifdef CY_DEBUG_DTR
2246*4882a593Smuzhiyun 			printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
2247*4882a593Smuzhiyun #endif
2248*4882a593Smuzhiyun 		}
2249*4882a593Smuzhiyun 
2250*4882a593Smuzhiyun 		retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
2251*4882a593Smuzhiyun 		if (retval != 0) {
2252*4882a593Smuzhiyun 			printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
2253*4882a593Smuzhiyun 				"was %x\n", info->line, retval);
2254*4882a593Smuzhiyun 		}
2255*4882a593Smuzhiyun 
2256*4882a593Smuzhiyun 		clear_bit(TTY_IO_ERROR, &tty->flags);
2257*4882a593Smuzhiyun 	}
2258*4882a593Smuzhiyun }				/* set_line_char */
2259*4882a593Smuzhiyun 
cy_get_serial_info(struct tty_struct * tty,struct serial_struct * ss)2260*4882a593Smuzhiyun static int cy_get_serial_info(struct tty_struct *tty,
2261*4882a593Smuzhiyun 				struct serial_struct *ss)
2262*4882a593Smuzhiyun {
2263*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
2264*4882a593Smuzhiyun 	struct cyclades_card *cinfo = info->card;
2265*4882a593Smuzhiyun 
2266*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
2267*4882a593Smuzhiyun 		return -ENODEV;
2268*4882a593Smuzhiyun 	ss->type = info->type;
2269*4882a593Smuzhiyun 	ss->line = info->line;
2270*4882a593Smuzhiyun 	ss->port = (info->card - cy_card) * 0x100 + info->line -
2271*4882a593Smuzhiyun 			cinfo->first_line;
2272*4882a593Smuzhiyun 	ss->irq = cinfo->irq;
2273*4882a593Smuzhiyun 	ss->flags = info->port.flags;
2274*4882a593Smuzhiyun 	ss->close_delay = info->port.close_delay;
2275*4882a593Smuzhiyun 	ss->closing_wait = info->port.closing_wait;
2276*4882a593Smuzhiyun 	ss->baud_base = info->baud;
2277*4882a593Smuzhiyun 	ss->custom_divisor = info->custom_divisor;
2278*4882a593Smuzhiyun 	return 0;
2279*4882a593Smuzhiyun }
2280*4882a593Smuzhiyun 
cy_set_serial_info(struct tty_struct * tty,struct serial_struct * ss)2281*4882a593Smuzhiyun static int cy_set_serial_info(struct tty_struct *tty,
2282*4882a593Smuzhiyun 				struct serial_struct *ss)
2283*4882a593Smuzhiyun {
2284*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
2285*4882a593Smuzhiyun 	int old_flags;
2286*4882a593Smuzhiyun 	int ret;
2287*4882a593Smuzhiyun 
2288*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
2289*4882a593Smuzhiyun 		return -ENODEV;
2290*4882a593Smuzhiyun 
2291*4882a593Smuzhiyun 	mutex_lock(&info->port.mutex);
2292*4882a593Smuzhiyun 
2293*4882a593Smuzhiyun 	old_flags = info->port.flags;
2294*4882a593Smuzhiyun 
2295*4882a593Smuzhiyun 	if (!capable(CAP_SYS_ADMIN)) {
2296*4882a593Smuzhiyun 		if (ss->close_delay != info->port.close_delay ||
2297*4882a593Smuzhiyun 				ss->baud_base != info->baud ||
2298*4882a593Smuzhiyun 				(ss->flags & ASYNC_FLAGS &
2299*4882a593Smuzhiyun 					~ASYNC_USR_MASK) !=
2300*4882a593Smuzhiyun 				(info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
2301*4882a593Smuzhiyun 		{
2302*4882a593Smuzhiyun 			mutex_unlock(&info->port.mutex);
2303*4882a593Smuzhiyun 			return -EPERM;
2304*4882a593Smuzhiyun 		}
2305*4882a593Smuzhiyun 		info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
2306*4882a593Smuzhiyun 				(ss->flags & ASYNC_USR_MASK);
2307*4882a593Smuzhiyun 		info->baud = ss->baud_base;
2308*4882a593Smuzhiyun 		info->custom_divisor = ss->custom_divisor;
2309*4882a593Smuzhiyun 		goto check_and_exit;
2310*4882a593Smuzhiyun 	}
2311*4882a593Smuzhiyun 
2312*4882a593Smuzhiyun 	/*
2313*4882a593Smuzhiyun 	 * OK, past this point, all the error checking has been done.
2314*4882a593Smuzhiyun 	 * At this point, we start making changes.....
2315*4882a593Smuzhiyun 	 */
2316*4882a593Smuzhiyun 
2317*4882a593Smuzhiyun 	info->baud = ss->baud_base;
2318*4882a593Smuzhiyun 	info->custom_divisor = ss->custom_divisor;
2319*4882a593Smuzhiyun 	info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
2320*4882a593Smuzhiyun 			(ss->flags & ASYNC_FLAGS);
2321*4882a593Smuzhiyun 	info->port.close_delay = ss->close_delay * HZ / 100;
2322*4882a593Smuzhiyun 	info->port.closing_wait = ss->closing_wait * HZ / 100;
2323*4882a593Smuzhiyun 
2324*4882a593Smuzhiyun check_and_exit:
2325*4882a593Smuzhiyun 	if (tty_port_initialized(&info->port)) {
2326*4882a593Smuzhiyun 		if ((ss->flags ^ old_flags) & ASYNC_SPD_MASK) {
2327*4882a593Smuzhiyun 			/* warn about deprecation unless clearing */
2328*4882a593Smuzhiyun 			if (ss->flags & ASYNC_SPD_MASK)
2329*4882a593Smuzhiyun 				dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n");
2330*4882a593Smuzhiyun 		}
2331*4882a593Smuzhiyun 		cy_set_line_char(info, tty);
2332*4882a593Smuzhiyun 		ret = 0;
2333*4882a593Smuzhiyun 	} else {
2334*4882a593Smuzhiyun 		ret = cy_startup(info, tty);
2335*4882a593Smuzhiyun 	}
2336*4882a593Smuzhiyun 	mutex_unlock(&info->port.mutex);
2337*4882a593Smuzhiyun 	return ret;
2338*4882a593Smuzhiyun }				/* set_serial_info */
2339*4882a593Smuzhiyun 
2340*4882a593Smuzhiyun /*
2341*4882a593Smuzhiyun  * get_lsr_info - get line status register info
2342*4882a593Smuzhiyun  *
2343*4882a593Smuzhiyun  * Purpose: Let user call ioctl() to get info when the UART physically
2344*4882a593Smuzhiyun  *	    is emptied.  On bus types like RS485, the transmitter must
2345*4882a593Smuzhiyun  *	    release the bus after transmitting. This must be done when
2346*4882a593Smuzhiyun  *	    the transmit shift register is empty, not be done when the
2347*4882a593Smuzhiyun  *	    transmit holding register is empty.  This functionality
2348*4882a593Smuzhiyun  *	    allows an RS485 driver to be written in user space.
2349*4882a593Smuzhiyun  */
get_lsr_info(struct cyclades_port * info,unsigned int __user * value)2350*4882a593Smuzhiyun static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
2351*4882a593Smuzhiyun {
2352*4882a593Smuzhiyun 	struct cyclades_card *card = info->card;
2353*4882a593Smuzhiyun 	unsigned int result;
2354*4882a593Smuzhiyun 	unsigned long flags;
2355*4882a593Smuzhiyun 	u8 status;
2356*4882a593Smuzhiyun 
2357*4882a593Smuzhiyun 	if (!cy_is_Z(card)) {
2358*4882a593Smuzhiyun 		spin_lock_irqsave(&card->card_lock, flags);
2359*4882a593Smuzhiyun 		status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty);
2360*4882a593Smuzhiyun 		spin_unlock_irqrestore(&card->card_lock, flags);
2361*4882a593Smuzhiyun 		result = (status ? 0 : TIOCSER_TEMT);
2362*4882a593Smuzhiyun 	} else {
2363*4882a593Smuzhiyun 		/* Not supported yet */
2364*4882a593Smuzhiyun 		return -EINVAL;
2365*4882a593Smuzhiyun 	}
2366*4882a593Smuzhiyun 	return put_user(result, value);
2367*4882a593Smuzhiyun }
2368*4882a593Smuzhiyun 
cy_tiocmget(struct tty_struct * tty)2369*4882a593Smuzhiyun static int cy_tiocmget(struct tty_struct *tty)
2370*4882a593Smuzhiyun {
2371*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
2372*4882a593Smuzhiyun 	struct cyclades_card *card;
2373*4882a593Smuzhiyun 	int result;
2374*4882a593Smuzhiyun 
2375*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, __func__))
2376*4882a593Smuzhiyun 		return -ENODEV;
2377*4882a593Smuzhiyun 
2378*4882a593Smuzhiyun 	card = info->card;
2379*4882a593Smuzhiyun 
2380*4882a593Smuzhiyun 	if (!cy_is_Z(card)) {
2381*4882a593Smuzhiyun 		unsigned long flags;
2382*4882a593Smuzhiyun 		int channel = info->line - card->first_line;
2383*4882a593Smuzhiyun 		u8 status;
2384*4882a593Smuzhiyun 
2385*4882a593Smuzhiyun 		spin_lock_irqsave(&card->card_lock, flags);
2386*4882a593Smuzhiyun 		cyy_writeb(info, CyCAR, channel & 0x03);
2387*4882a593Smuzhiyun 		status = cyy_readb(info, CyMSVR1);
2388*4882a593Smuzhiyun 		status |= cyy_readb(info, CyMSVR2);
2389*4882a593Smuzhiyun 		spin_unlock_irqrestore(&card->card_lock, flags);
2390*4882a593Smuzhiyun 
2391*4882a593Smuzhiyun 		if (info->rtsdtr_inv) {
2392*4882a593Smuzhiyun 			result = ((status & CyRTS) ? TIOCM_DTR : 0) |
2393*4882a593Smuzhiyun 				((status & CyDTR) ? TIOCM_RTS : 0);
2394*4882a593Smuzhiyun 		} else {
2395*4882a593Smuzhiyun 			result = ((status & CyRTS) ? TIOCM_RTS : 0) |
2396*4882a593Smuzhiyun 				((status & CyDTR) ? TIOCM_DTR : 0);
2397*4882a593Smuzhiyun 		}
2398*4882a593Smuzhiyun 		result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
2399*4882a593Smuzhiyun 			((status & CyRI) ? TIOCM_RNG : 0) |
2400*4882a593Smuzhiyun 			((status & CyDSR) ? TIOCM_DSR : 0) |
2401*4882a593Smuzhiyun 			((status & CyCTS) ? TIOCM_CTS : 0);
2402*4882a593Smuzhiyun 	} else {
2403*4882a593Smuzhiyun 		u32 lstatus;
2404*4882a593Smuzhiyun 
2405*4882a593Smuzhiyun 		if (!cyz_is_loaded(card)) {
2406*4882a593Smuzhiyun 			result = -ENODEV;
2407*4882a593Smuzhiyun 			goto end;
2408*4882a593Smuzhiyun 		}
2409*4882a593Smuzhiyun 
2410*4882a593Smuzhiyun 		lstatus = readl(&info->u.cyz.ch_ctrl->rs_status);
2411*4882a593Smuzhiyun 		result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
2412*4882a593Smuzhiyun 			((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
2413*4882a593Smuzhiyun 			((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
2414*4882a593Smuzhiyun 			((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
2415*4882a593Smuzhiyun 			((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
2416*4882a593Smuzhiyun 			((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
2417*4882a593Smuzhiyun 	}
2418*4882a593Smuzhiyun end:
2419*4882a593Smuzhiyun 	return result;
2420*4882a593Smuzhiyun }				/* cy_tiomget */
2421*4882a593Smuzhiyun 
2422*4882a593Smuzhiyun static int
cy_tiocmset(struct tty_struct * tty,unsigned int set,unsigned int clear)2423*4882a593Smuzhiyun cy_tiocmset(struct tty_struct *tty,
2424*4882a593Smuzhiyun 		unsigned int set, unsigned int clear)
2425*4882a593Smuzhiyun {
2426*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
2427*4882a593Smuzhiyun 	struct cyclades_card *card;
2428*4882a593Smuzhiyun 	unsigned long flags;
2429*4882a593Smuzhiyun 
2430*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, __func__))
2431*4882a593Smuzhiyun 		return -ENODEV;
2432*4882a593Smuzhiyun 
2433*4882a593Smuzhiyun 	card = info->card;
2434*4882a593Smuzhiyun 	if (!cy_is_Z(card)) {
2435*4882a593Smuzhiyun 		spin_lock_irqsave(&card->card_lock, flags);
2436*4882a593Smuzhiyun 		cyy_change_rts_dtr(info, set, clear);
2437*4882a593Smuzhiyun 		spin_unlock_irqrestore(&card->card_lock, flags);
2438*4882a593Smuzhiyun 	} else {
2439*4882a593Smuzhiyun 		struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
2440*4882a593Smuzhiyun 		int retval, channel = info->line - card->first_line;
2441*4882a593Smuzhiyun 		u32 rs;
2442*4882a593Smuzhiyun 
2443*4882a593Smuzhiyun 		if (!cyz_is_loaded(card))
2444*4882a593Smuzhiyun 			return -ENODEV;
2445*4882a593Smuzhiyun 
2446*4882a593Smuzhiyun 		spin_lock_irqsave(&card->card_lock, flags);
2447*4882a593Smuzhiyun 		rs = readl(&ch_ctrl->rs_control);
2448*4882a593Smuzhiyun 		if (set & TIOCM_RTS)
2449*4882a593Smuzhiyun 			rs |= C_RS_RTS;
2450*4882a593Smuzhiyun 		if (clear & TIOCM_RTS)
2451*4882a593Smuzhiyun 			rs &= ~C_RS_RTS;
2452*4882a593Smuzhiyun 		if (set & TIOCM_DTR) {
2453*4882a593Smuzhiyun 			rs |= C_RS_DTR;
2454*4882a593Smuzhiyun #ifdef CY_DEBUG_DTR
2455*4882a593Smuzhiyun 			printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n");
2456*4882a593Smuzhiyun #endif
2457*4882a593Smuzhiyun 		}
2458*4882a593Smuzhiyun 		if (clear & TIOCM_DTR) {
2459*4882a593Smuzhiyun 			rs &= ~C_RS_DTR;
2460*4882a593Smuzhiyun #ifdef CY_DEBUG_DTR
2461*4882a593Smuzhiyun 			printk(KERN_DEBUG "cyc:set_modem_info clearing "
2462*4882a593Smuzhiyun 				"Z DTR\n");
2463*4882a593Smuzhiyun #endif
2464*4882a593Smuzhiyun 		}
2465*4882a593Smuzhiyun 		cy_writel(&ch_ctrl->rs_control, rs);
2466*4882a593Smuzhiyun 		retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
2467*4882a593Smuzhiyun 		spin_unlock_irqrestore(&card->card_lock, flags);
2468*4882a593Smuzhiyun 		if (retval != 0) {
2469*4882a593Smuzhiyun 			printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
2470*4882a593Smuzhiyun 				"was %x\n", info->line, retval);
2471*4882a593Smuzhiyun 		}
2472*4882a593Smuzhiyun 	}
2473*4882a593Smuzhiyun 	return 0;
2474*4882a593Smuzhiyun }
2475*4882a593Smuzhiyun 
2476*4882a593Smuzhiyun /*
2477*4882a593Smuzhiyun  * cy_break() --- routine which turns the break handling on or off
2478*4882a593Smuzhiyun  */
cy_break(struct tty_struct * tty,int break_state)2479*4882a593Smuzhiyun static int cy_break(struct tty_struct *tty, int break_state)
2480*4882a593Smuzhiyun {
2481*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
2482*4882a593Smuzhiyun 	struct cyclades_card *card;
2483*4882a593Smuzhiyun 	unsigned long flags;
2484*4882a593Smuzhiyun 	int retval = 0;
2485*4882a593Smuzhiyun 
2486*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, "cy_break"))
2487*4882a593Smuzhiyun 		return -EINVAL;
2488*4882a593Smuzhiyun 
2489*4882a593Smuzhiyun 	card = info->card;
2490*4882a593Smuzhiyun 
2491*4882a593Smuzhiyun 	spin_lock_irqsave(&card->card_lock, flags);
2492*4882a593Smuzhiyun 	if (!cy_is_Z(card)) {
2493*4882a593Smuzhiyun 		/* Let the transmit ISR take care of this (since it
2494*4882a593Smuzhiyun 		   requires stuffing characters into the output stream).
2495*4882a593Smuzhiyun 		 */
2496*4882a593Smuzhiyun 		if (break_state == -1) {
2497*4882a593Smuzhiyun 			if (!info->breakon) {
2498*4882a593Smuzhiyun 				info->breakon = 1;
2499*4882a593Smuzhiyun 				if (!info->xmit_cnt) {
2500*4882a593Smuzhiyun 					spin_unlock_irqrestore(&card->card_lock, flags);
2501*4882a593Smuzhiyun 					start_xmit(info);
2502*4882a593Smuzhiyun 					spin_lock_irqsave(&card->card_lock, flags);
2503*4882a593Smuzhiyun 				}
2504*4882a593Smuzhiyun 			}
2505*4882a593Smuzhiyun 		} else {
2506*4882a593Smuzhiyun 			if (!info->breakoff) {
2507*4882a593Smuzhiyun 				info->breakoff = 1;
2508*4882a593Smuzhiyun 				if (!info->xmit_cnt) {
2509*4882a593Smuzhiyun 					spin_unlock_irqrestore(&card->card_lock, flags);
2510*4882a593Smuzhiyun 					start_xmit(info);
2511*4882a593Smuzhiyun 					spin_lock_irqsave(&card->card_lock, flags);
2512*4882a593Smuzhiyun 				}
2513*4882a593Smuzhiyun 			}
2514*4882a593Smuzhiyun 		}
2515*4882a593Smuzhiyun 	} else {
2516*4882a593Smuzhiyun 		if (break_state == -1) {
2517*4882a593Smuzhiyun 			retval = cyz_issue_cmd(card,
2518*4882a593Smuzhiyun 				info->line - card->first_line,
2519*4882a593Smuzhiyun 				C_CM_SET_BREAK, 0L);
2520*4882a593Smuzhiyun 			if (retval != 0) {
2521*4882a593Smuzhiyun 				printk(KERN_ERR "cyc:cy_break (set) retval on "
2522*4882a593Smuzhiyun 					"ttyC%d was %x\n", info->line, retval);
2523*4882a593Smuzhiyun 			}
2524*4882a593Smuzhiyun 		} else {
2525*4882a593Smuzhiyun 			retval = cyz_issue_cmd(card,
2526*4882a593Smuzhiyun 				info->line - card->first_line,
2527*4882a593Smuzhiyun 				C_CM_CLR_BREAK, 0L);
2528*4882a593Smuzhiyun 			if (retval != 0) {
2529*4882a593Smuzhiyun 				printk(KERN_DEBUG "cyc:cy_break (clr) retval "
2530*4882a593Smuzhiyun 					"on ttyC%d was %x\n", info->line,
2531*4882a593Smuzhiyun 					retval);
2532*4882a593Smuzhiyun 			}
2533*4882a593Smuzhiyun 		}
2534*4882a593Smuzhiyun 	}
2535*4882a593Smuzhiyun 	spin_unlock_irqrestore(&card->card_lock, flags);
2536*4882a593Smuzhiyun 	return retval;
2537*4882a593Smuzhiyun }				/* cy_break */
2538*4882a593Smuzhiyun 
set_threshold(struct cyclades_port * info,unsigned long value)2539*4882a593Smuzhiyun static int set_threshold(struct cyclades_port *info, unsigned long value)
2540*4882a593Smuzhiyun {
2541*4882a593Smuzhiyun 	struct cyclades_card *card = info->card;
2542*4882a593Smuzhiyun 	unsigned long flags;
2543*4882a593Smuzhiyun 
2544*4882a593Smuzhiyun 	if (!cy_is_Z(card)) {
2545*4882a593Smuzhiyun 		info->cor3 &= ~CyREC_FIFO;
2546*4882a593Smuzhiyun 		info->cor3 |= value & CyREC_FIFO;
2547*4882a593Smuzhiyun 
2548*4882a593Smuzhiyun 		spin_lock_irqsave(&card->card_lock, flags);
2549*4882a593Smuzhiyun 		cyy_writeb(info, CyCOR3, info->cor3);
2550*4882a593Smuzhiyun 		cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch);
2551*4882a593Smuzhiyun 		spin_unlock_irqrestore(&card->card_lock, flags);
2552*4882a593Smuzhiyun 	}
2553*4882a593Smuzhiyun 	return 0;
2554*4882a593Smuzhiyun }				/* set_threshold */
2555*4882a593Smuzhiyun 
get_threshold(struct cyclades_port * info,unsigned long __user * value)2556*4882a593Smuzhiyun static int get_threshold(struct cyclades_port *info,
2557*4882a593Smuzhiyun 						unsigned long __user *value)
2558*4882a593Smuzhiyun {
2559*4882a593Smuzhiyun 	struct cyclades_card *card = info->card;
2560*4882a593Smuzhiyun 
2561*4882a593Smuzhiyun 	if (!cy_is_Z(card)) {
2562*4882a593Smuzhiyun 		u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO;
2563*4882a593Smuzhiyun 		return put_user(tmp, value);
2564*4882a593Smuzhiyun 	}
2565*4882a593Smuzhiyun 	return 0;
2566*4882a593Smuzhiyun }				/* get_threshold */
2567*4882a593Smuzhiyun 
set_timeout(struct cyclades_port * info,unsigned long value)2568*4882a593Smuzhiyun static int set_timeout(struct cyclades_port *info, unsigned long value)
2569*4882a593Smuzhiyun {
2570*4882a593Smuzhiyun 	struct cyclades_card *card = info->card;
2571*4882a593Smuzhiyun 	unsigned long flags;
2572*4882a593Smuzhiyun 
2573*4882a593Smuzhiyun 	if (!cy_is_Z(card)) {
2574*4882a593Smuzhiyun 		spin_lock_irqsave(&card->card_lock, flags);
2575*4882a593Smuzhiyun 		cyy_writeb(info, CyRTPR, value & 0xff);
2576*4882a593Smuzhiyun 		spin_unlock_irqrestore(&card->card_lock, flags);
2577*4882a593Smuzhiyun 	}
2578*4882a593Smuzhiyun 	return 0;
2579*4882a593Smuzhiyun }				/* set_timeout */
2580*4882a593Smuzhiyun 
get_timeout(struct cyclades_port * info,unsigned long __user * value)2581*4882a593Smuzhiyun static int get_timeout(struct cyclades_port *info,
2582*4882a593Smuzhiyun 						unsigned long __user *value)
2583*4882a593Smuzhiyun {
2584*4882a593Smuzhiyun 	struct cyclades_card *card = info->card;
2585*4882a593Smuzhiyun 
2586*4882a593Smuzhiyun 	if (!cy_is_Z(card)) {
2587*4882a593Smuzhiyun 		u8 tmp = cyy_readb(info, CyRTPR);
2588*4882a593Smuzhiyun 		return put_user(tmp, value);
2589*4882a593Smuzhiyun 	}
2590*4882a593Smuzhiyun 	return 0;
2591*4882a593Smuzhiyun }				/* get_timeout */
2592*4882a593Smuzhiyun 
cy_cflags_changed(struct cyclades_port * info,unsigned long arg,struct cyclades_icount * cprev)2593*4882a593Smuzhiyun static int cy_cflags_changed(struct cyclades_port *info, unsigned long arg,
2594*4882a593Smuzhiyun 		struct cyclades_icount *cprev)
2595*4882a593Smuzhiyun {
2596*4882a593Smuzhiyun 	struct cyclades_icount cnow;
2597*4882a593Smuzhiyun 	unsigned long flags;
2598*4882a593Smuzhiyun 	int ret;
2599*4882a593Smuzhiyun 
2600*4882a593Smuzhiyun 	spin_lock_irqsave(&info->card->card_lock, flags);
2601*4882a593Smuzhiyun 	cnow = info->icount;	/* atomic copy */
2602*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->card->card_lock, flags);
2603*4882a593Smuzhiyun 
2604*4882a593Smuzhiyun 	ret =	((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
2605*4882a593Smuzhiyun 		((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
2606*4882a593Smuzhiyun 		((arg & TIOCM_CD)  && (cnow.dcd != cprev->dcd)) ||
2607*4882a593Smuzhiyun 		((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
2608*4882a593Smuzhiyun 
2609*4882a593Smuzhiyun 	*cprev = cnow;
2610*4882a593Smuzhiyun 
2611*4882a593Smuzhiyun 	return ret;
2612*4882a593Smuzhiyun }
2613*4882a593Smuzhiyun 
2614*4882a593Smuzhiyun /*
2615*4882a593Smuzhiyun  * This routine allows the tty driver to implement device-
2616*4882a593Smuzhiyun  * specific ioctl's.  If the ioctl number passed in cmd is
2617*4882a593Smuzhiyun  * not recognized by the driver, it should return ENOIOCTLCMD.
2618*4882a593Smuzhiyun  */
2619*4882a593Smuzhiyun static int
cy_ioctl(struct tty_struct * tty,unsigned int cmd,unsigned long arg)2620*4882a593Smuzhiyun cy_ioctl(struct tty_struct *tty,
2621*4882a593Smuzhiyun 	 unsigned int cmd, unsigned long arg)
2622*4882a593Smuzhiyun {
2623*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
2624*4882a593Smuzhiyun 	struct cyclades_icount cnow;	/* kernel counter temps */
2625*4882a593Smuzhiyun 	int ret_val = 0;
2626*4882a593Smuzhiyun 	unsigned long flags;
2627*4882a593Smuzhiyun 	void __user *argp = (void __user *)arg;
2628*4882a593Smuzhiyun 
2629*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
2630*4882a593Smuzhiyun 		return -ENODEV;
2631*4882a593Smuzhiyun 
2632*4882a593Smuzhiyun #ifdef CY_DEBUG_OTHER
2633*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
2634*4882a593Smuzhiyun 		info->line, cmd, arg);
2635*4882a593Smuzhiyun #endif
2636*4882a593Smuzhiyun 
2637*4882a593Smuzhiyun 	switch (cmd) {
2638*4882a593Smuzhiyun 	case CYGETMON:
2639*4882a593Smuzhiyun 		if (copy_to_user(argp, &info->mon, sizeof(info->mon))) {
2640*4882a593Smuzhiyun 			ret_val = -EFAULT;
2641*4882a593Smuzhiyun 			break;
2642*4882a593Smuzhiyun 		}
2643*4882a593Smuzhiyun 		memset(&info->mon, 0, sizeof(info->mon));
2644*4882a593Smuzhiyun 		break;
2645*4882a593Smuzhiyun 	case CYGETTHRESH:
2646*4882a593Smuzhiyun 		ret_val = get_threshold(info, argp);
2647*4882a593Smuzhiyun 		break;
2648*4882a593Smuzhiyun 	case CYSETTHRESH:
2649*4882a593Smuzhiyun 		ret_val = set_threshold(info, arg);
2650*4882a593Smuzhiyun 		break;
2651*4882a593Smuzhiyun 	case CYGETDEFTHRESH:
2652*4882a593Smuzhiyun 		ret_val = put_user(info->default_threshold,
2653*4882a593Smuzhiyun 				(unsigned long __user *)argp);
2654*4882a593Smuzhiyun 		break;
2655*4882a593Smuzhiyun 	case CYSETDEFTHRESH:
2656*4882a593Smuzhiyun 		info->default_threshold = arg & 0x0f;
2657*4882a593Smuzhiyun 		break;
2658*4882a593Smuzhiyun 	case CYGETTIMEOUT:
2659*4882a593Smuzhiyun 		ret_val = get_timeout(info, argp);
2660*4882a593Smuzhiyun 		break;
2661*4882a593Smuzhiyun 	case CYSETTIMEOUT:
2662*4882a593Smuzhiyun 		ret_val = set_timeout(info, arg);
2663*4882a593Smuzhiyun 		break;
2664*4882a593Smuzhiyun 	case CYGETDEFTIMEOUT:
2665*4882a593Smuzhiyun 		ret_val = put_user(info->default_timeout,
2666*4882a593Smuzhiyun 				(unsigned long __user *)argp);
2667*4882a593Smuzhiyun 		break;
2668*4882a593Smuzhiyun 	case CYSETDEFTIMEOUT:
2669*4882a593Smuzhiyun 		info->default_timeout = arg & 0xff;
2670*4882a593Smuzhiyun 		break;
2671*4882a593Smuzhiyun 	case CYSETRFLOW:
2672*4882a593Smuzhiyun 		info->rflow = (int)arg;
2673*4882a593Smuzhiyun 		break;
2674*4882a593Smuzhiyun 	case CYGETRFLOW:
2675*4882a593Smuzhiyun 		ret_val = info->rflow;
2676*4882a593Smuzhiyun 		break;
2677*4882a593Smuzhiyun 	case CYSETRTSDTR_INV:
2678*4882a593Smuzhiyun 		info->rtsdtr_inv = (int)arg;
2679*4882a593Smuzhiyun 		break;
2680*4882a593Smuzhiyun 	case CYGETRTSDTR_INV:
2681*4882a593Smuzhiyun 		ret_val = info->rtsdtr_inv;
2682*4882a593Smuzhiyun 		break;
2683*4882a593Smuzhiyun 	case CYGETCD1400VER:
2684*4882a593Smuzhiyun 		ret_val = info->chip_rev;
2685*4882a593Smuzhiyun 		break;
2686*4882a593Smuzhiyun #ifndef CONFIG_CYZ_INTR
2687*4882a593Smuzhiyun 	case CYZSETPOLLCYCLE:
2688*4882a593Smuzhiyun 		if (arg > LONG_MAX / HZ)
2689*4882a593Smuzhiyun 			return -ENODEV;
2690*4882a593Smuzhiyun 		cyz_polling_cycle = (arg * HZ) / 1000;
2691*4882a593Smuzhiyun 		break;
2692*4882a593Smuzhiyun 	case CYZGETPOLLCYCLE:
2693*4882a593Smuzhiyun 		ret_val = (cyz_polling_cycle * 1000) / HZ;
2694*4882a593Smuzhiyun 		break;
2695*4882a593Smuzhiyun #endif				/* CONFIG_CYZ_INTR */
2696*4882a593Smuzhiyun 	case CYSETWAIT:
2697*4882a593Smuzhiyun 		info->port.closing_wait = (unsigned short)arg * HZ / 100;
2698*4882a593Smuzhiyun 		break;
2699*4882a593Smuzhiyun 	case CYGETWAIT:
2700*4882a593Smuzhiyun 		ret_val = info->port.closing_wait / (HZ / 100);
2701*4882a593Smuzhiyun 		break;
2702*4882a593Smuzhiyun 	case TIOCSERGETLSR:	/* Get line status register */
2703*4882a593Smuzhiyun 		ret_val = get_lsr_info(info, argp);
2704*4882a593Smuzhiyun 		break;
2705*4882a593Smuzhiyun 		/*
2706*4882a593Smuzhiyun 		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
2707*4882a593Smuzhiyun 		 * - mask passed in arg for lines of interest
2708*4882a593Smuzhiyun 		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
2709*4882a593Smuzhiyun 		 * Caller should use TIOCGICOUNT to see which one it was
2710*4882a593Smuzhiyun 		 */
2711*4882a593Smuzhiyun 	case TIOCMIWAIT:
2712*4882a593Smuzhiyun 		spin_lock_irqsave(&info->card->card_lock, flags);
2713*4882a593Smuzhiyun 		/* note the counters on entry */
2714*4882a593Smuzhiyun 		cnow = info->icount;
2715*4882a593Smuzhiyun 		spin_unlock_irqrestore(&info->card->card_lock, flags);
2716*4882a593Smuzhiyun 		ret_val = wait_event_interruptible(info->port.delta_msr_wait,
2717*4882a593Smuzhiyun 				cy_cflags_changed(info, arg, &cnow));
2718*4882a593Smuzhiyun 		break;
2719*4882a593Smuzhiyun 
2720*4882a593Smuzhiyun 		/*
2721*4882a593Smuzhiyun 		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2722*4882a593Smuzhiyun 		 * Return: write counters to the user passed counter struct
2723*4882a593Smuzhiyun 		 * NB: both 1->0 and 0->1 transitions are counted except for
2724*4882a593Smuzhiyun 		 *     RI where only 0->1 is counted.
2725*4882a593Smuzhiyun 		 */
2726*4882a593Smuzhiyun 	default:
2727*4882a593Smuzhiyun 		ret_val = -ENOIOCTLCMD;
2728*4882a593Smuzhiyun 	}
2729*4882a593Smuzhiyun 
2730*4882a593Smuzhiyun #ifdef CY_DEBUG_OTHER
2731*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyc:cy_ioctl done\n");
2732*4882a593Smuzhiyun #endif
2733*4882a593Smuzhiyun 	return ret_val;
2734*4882a593Smuzhiyun }				/* cy_ioctl */
2735*4882a593Smuzhiyun 
cy_get_icount(struct tty_struct * tty,struct serial_icounter_struct * sic)2736*4882a593Smuzhiyun static int cy_get_icount(struct tty_struct *tty,
2737*4882a593Smuzhiyun 				struct serial_icounter_struct *sic)
2738*4882a593Smuzhiyun {
2739*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
2740*4882a593Smuzhiyun 	struct cyclades_icount cnow;	/* Used to snapshot */
2741*4882a593Smuzhiyun 	unsigned long flags;
2742*4882a593Smuzhiyun 
2743*4882a593Smuzhiyun 	spin_lock_irqsave(&info->card->card_lock, flags);
2744*4882a593Smuzhiyun 	cnow = info->icount;
2745*4882a593Smuzhiyun 	spin_unlock_irqrestore(&info->card->card_lock, flags);
2746*4882a593Smuzhiyun 
2747*4882a593Smuzhiyun 	sic->cts = cnow.cts;
2748*4882a593Smuzhiyun 	sic->dsr = cnow.dsr;
2749*4882a593Smuzhiyun 	sic->rng = cnow.rng;
2750*4882a593Smuzhiyun 	sic->dcd = cnow.dcd;
2751*4882a593Smuzhiyun 	sic->rx = cnow.rx;
2752*4882a593Smuzhiyun 	sic->tx = cnow.tx;
2753*4882a593Smuzhiyun 	sic->frame = cnow.frame;
2754*4882a593Smuzhiyun 	sic->overrun = cnow.overrun;
2755*4882a593Smuzhiyun 	sic->parity = cnow.parity;
2756*4882a593Smuzhiyun 	sic->brk = cnow.brk;
2757*4882a593Smuzhiyun 	sic->buf_overrun = cnow.buf_overrun;
2758*4882a593Smuzhiyun 	return 0;
2759*4882a593Smuzhiyun }
2760*4882a593Smuzhiyun 
2761*4882a593Smuzhiyun /*
2762*4882a593Smuzhiyun  * This routine allows the tty driver to be notified when
2763*4882a593Smuzhiyun  * device's termios settings have changed.  Note that a
2764*4882a593Smuzhiyun  * well-designed tty driver should be prepared to accept the case
2765*4882a593Smuzhiyun  * where old == NULL, and try to do something rational.
2766*4882a593Smuzhiyun  */
cy_set_termios(struct tty_struct * tty,struct ktermios * old_termios)2767*4882a593Smuzhiyun static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
2768*4882a593Smuzhiyun {
2769*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
2770*4882a593Smuzhiyun 
2771*4882a593Smuzhiyun #ifdef CY_DEBUG_OTHER
2772*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
2773*4882a593Smuzhiyun #endif
2774*4882a593Smuzhiyun 
2775*4882a593Smuzhiyun 	cy_set_line_char(info, tty);
2776*4882a593Smuzhiyun 
2777*4882a593Smuzhiyun 	if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
2778*4882a593Smuzhiyun 		tty->hw_stopped = 0;
2779*4882a593Smuzhiyun 		cy_start(tty);
2780*4882a593Smuzhiyun 	}
2781*4882a593Smuzhiyun #if 0
2782*4882a593Smuzhiyun 	/*
2783*4882a593Smuzhiyun 	 * No need to wake up processes in open wait, since they
2784*4882a593Smuzhiyun 	 * sample the CLOCAL flag once, and don't recheck it.
2785*4882a593Smuzhiyun 	 * XXX  It's not clear whether the current behavior is correct
2786*4882a593Smuzhiyun 	 * or not.  Hence, this may change.....
2787*4882a593Smuzhiyun 	 */
2788*4882a593Smuzhiyun 	if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
2789*4882a593Smuzhiyun 		wake_up_interruptible(&info->port.open_wait);
2790*4882a593Smuzhiyun #endif
2791*4882a593Smuzhiyun }				/* cy_set_termios */
2792*4882a593Smuzhiyun 
2793*4882a593Smuzhiyun /* This function is used to send a high-priority XON/XOFF character to
2794*4882a593Smuzhiyun    the device.
2795*4882a593Smuzhiyun */
cy_send_xchar(struct tty_struct * tty,char ch)2796*4882a593Smuzhiyun static void cy_send_xchar(struct tty_struct *tty, char ch)
2797*4882a593Smuzhiyun {
2798*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
2799*4882a593Smuzhiyun 	struct cyclades_card *card;
2800*4882a593Smuzhiyun 	int channel;
2801*4882a593Smuzhiyun 
2802*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
2803*4882a593Smuzhiyun 		return;
2804*4882a593Smuzhiyun 
2805*4882a593Smuzhiyun 	info->x_char = ch;
2806*4882a593Smuzhiyun 
2807*4882a593Smuzhiyun 	if (ch)
2808*4882a593Smuzhiyun 		cy_start(tty);
2809*4882a593Smuzhiyun 
2810*4882a593Smuzhiyun 	card = info->card;
2811*4882a593Smuzhiyun 	channel = info->line - card->first_line;
2812*4882a593Smuzhiyun 
2813*4882a593Smuzhiyun 	if (cy_is_Z(card)) {
2814*4882a593Smuzhiyun 		if (ch == STOP_CHAR(tty))
2815*4882a593Smuzhiyun 			cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
2816*4882a593Smuzhiyun 		else if (ch == START_CHAR(tty))
2817*4882a593Smuzhiyun 			cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
2818*4882a593Smuzhiyun 	}
2819*4882a593Smuzhiyun }
2820*4882a593Smuzhiyun 
2821*4882a593Smuzhiyun /* This routine is called by the upper-layer tty layer to signal
2822*4882a593Smuzhiyun    that incoming characters should be throttled because the input
2823*4882a593Smuzhiyun    buffers are close to full.
2824*4882a593Smuzhiyun  */
cy_throttle(struct tty_struct * tty)2825*4882a593Smuzhiyun static void cy_throttle(struct tty_struct *tty)
2826*4882a593Smuzhiyun {
2827*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
2828*4882a593Smuzhiyun 	struct cyclades_card *card;
2829*4882a593Smuzhiyun 	unsigned long flags;
2830*4882a593Smuzhiyun 
2831*4882a593Smuzhiyun #ifdef CY_DEBUG_THROTTLE
2832*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyc:throttle %s ...ttyC%d\n", tty_name(tty),
2833*4882a593Smuzhiyun 			 info->line);
2834*4882a593Smuzhiyun #endif
2835*4882a593Smuzhiyun 
2836*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, "cy_throttle"))
2837*4882a593Smuzhiyun 		return;
2838*4882a593Smuzhiyun 
2839*4882a593Smuzhiyun 	card = info->card;
2840*4882a593Smuzhiyun 
2841*4882a593Smuzhiyun 	if (I_IXOFF(tty)) {
2842*4882a593Smuzhiyun 		if (!cy_is_Z(card))
2843*4882a593Smuzhiyun 			cy_send_xchar(tty, STOP_CHAR(tty));
2844*4882a593Smuzhiyun 		else
2845*4882a593Smuzhiyun 			info->throttle = 1;
2846*4882a593Smuzhiyun 	}
2847*4882a593Smuzhiyun 
2848*4882a593Smuzhiyun 	if (C_CRTSCTS(tty)) {
2849*4882a593Smuzhiyun 		if (!cy_is_Z(card)) {
2850*4882a593Smuzhiyun 			spin_lock_irqsave(&card->card_lock, flags);
2851*4882a593Smuzhiyun 			cyy_change_rts_dtr(info, 0, TIOCM_RTS);
2852*4882a593Smuzhiyun 			spin_unlock_irqrestore(&card->card_lock, flags);
2853*4882a593Smuzhiyun 		} else {
2854*4882a593Smuzhiyun 			info->throttle = 1;
2855*4882a593Smuzhiyun 		}
2856*4882a593Smuzhiyun 	}
2857*4882a593Smuzhiyun }				/* cy_throttle */
2858*4882a593Smuzhiyun 
2859*4882a593Smuzhiyun /*
2860*4882a593Smuzhiyun  * This routine notifies the tty driver that it should signal
2861*4882a593Smuzhiyun  * that characters can now be sent to the tty without fear of
2862*4882a593Smuzhiyun  * overrunning the input buffers of the line disciplines.
2863*4882a593Smuzhiyun  */
cy_unthrottle(struct tty_struct * tty)2864*4882a593Smuzhiyun static void cy_unthrottle(struct tty_struct *tty)
2865*4882a593Smuzhiyun {
2866*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
2867*4882a593Smuzhiyun 	struct cyclades_card *card;
2868*4882a593Smuzhiyun 	unsigned long flags;
2869*4882a593Smuzhiyun 
2870*4882a593Smuzhiyun #ifdef CY_DEBUG_THROTTLE
2871*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyc:unthrottle %s ...ttyC%d\n",
2872*4882a593Smuzhiyun 		tty_name(tty), info->line);
2873*4882a593Smuzhiyun #endif
2874*4882a593Smuzhiyun 
2875*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
2876*4882a593Smuzhiyun 		return;
2877*4882a593Smuzhiyun 
2878*4882a593Smuzhiyun 	if (I_IXOFF(tty)) {
2879*4882a593Smuzhiyun 		if (info->x_char)
2880*4882a593Smuzhiyun 			info->x_char = 0;
2881*4882a593Smuzhiyun 		else
2882*4882a593Smuzhiyun 			cy_send_xchar(tty, START_CHAR(tty));
2883*4882a593Smuzhiyun 	}
2884*4882a593Smuzhiyun 
2885*4882a593Smuzhiyun 	if (C_CRTSCTS(tty)) {
2886*4882a593Smuzhiyun 		card = info->card;
2887*4882a593Smuzhiyun 		if (!cy_is_Z(card)) {
2888*4882a593Smuzhiyun 			spin_lock_irqsave(&card->card_lock, flags);
2889*4882a593Smuzhiyun 			cyy_change_rts_dtr(info, TIOCM_RTS, 0);
2890*4882a593Smuzhiyun 			spin_unlock_irqrestore(&card->card_lock, flags);
2891*4882a593Smuzhiyun 		} else {
2892*4882a593Smuzhiyun 			info->throttle = 0;
2893*4882a593Smuzhiyun 		}
2894*4882a593Smuzhiyun 	}
2895*4882a593Smuzhiyun }				/* cy_unthrottle */
2896*4882a593Smuzhiyun 
2897*4882a593Smuzhiyun /* cy_start and cy_stop provide software output flow control as a
2898*4882a593Smuzhiyun    function of XON/XOFF, software CTS, and other such stuff.
2899*4882a593Smuzhiyun */
cy_stop(struct tty_struct * tty)2900*4882a593Smuzhiyun static void cy_stop(struct tty_struct *tty)
2901*4882a593Smuzhiyun {
2902*4882a593Smuzhiyun 	struct cyclades_card *cinfo;
2903*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
2904*4882a593Smuzhiyun 	int channel;
2905*4882a593Smuzhiyun 	unsigned long flags;
2906*4882a593Smuzhiyun 
2907*4882a593Smuzhiyun #ifdef CY_DEBUG_OTHER
2908*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
2909*4882a593Smuzhiyun #endif
2910*4882a593Smuzhiyun 
2911*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, "cy_stop"))
2912*4882a593Smuzhiyun 		return;
2913*4882a593Smuzhiyun 
2914*4882a593Smuzhiyun 	cinfo = info->card;
2915*4882a593Smuzhiyun 	channel = info->line - cinfo->first_line;
2916*4882a593Smuzhiyun 	if (!cy_is_Z(cinfo)) {
2917*4882a593Smuzhiyun 		spin_lock_irqsave(&cinfo->card_lock, flags);
2918*4882a593Smuzhiyun 		cyy_writeb(info, CyCAR, channel & 0x03);
2919*4882a593Smuzhiyun 		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
2920*4882a593Smuzhiyun 		spin_unlock_irqrestore(&cinfo->card_lock, flags);
2921*4882a593Smuzhiyun 	}
2922*4882a593Smuzhiyun }				/* cy_stop */
2923*4882a593Smuzhiyun 
cy_start(struct tty_struct * tty)2924*4882a593Smuzhiyun static void cy_start(struct tty_struct *tty)
2925*4882a593Smuzhiyun {
2926*4882a593Smuzhiyun 	struct cyclades_card *cinfo;
2927*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
2928*4882a593Smuzhiyun 	int channel;
2929*4882a593Smuzhiyun 	unsigned long flags;
2930*4882a593Smuzhiyun 
2931*4882a593Smuzhiyun #ifdef CY_DEBUG_OTHER
2932*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
2933*4882a593Smuzhiyun #endif
2934*4882a593Smuzhiyun 
2935*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, "cy_start"))
2936*4882a593Smuzhiyun 		return;
2937*4882a593Smuzhiyun 
2938*4882a593Smuzhiyun 	cinfo = info->card;
2939*4882a593Smuzhiyun 	channel = info->line - cinfo->first_line;
2940*4882a593Smuzhiyun 	if (!cy_is_Z(cinfo)) {
2941*4882a593Smuzhiyun 		spin_lock_irqsave(&cinfo->card_lock, flags);
2942*4882a593Smuzhiyun 		cyy_writeb(info, CyCAR, channel & 0x03);
2943*4882a593Smuzhiyun 		cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
2944*4882a593Smuzhiyun 		spin_unlock_irqrestore(&cinfo->card_lock, flags);
2945*4882a593Smuzhiyun 	}
2946*4882a593Smuzhiyun }				/* cy_start */
2947*4882a593Smuzhiyun 
2948*4882a593Smuzhiyun /*
2949*4882a593Smuzhiyun  * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
2950*4882a593Smuzhiyun  */
cy_hangup(struct tty_struct * tty)2951*4882a593Smuzhiyun static void cy_hangup(struct tty_struct *tty)
2952*4882a593Smuzhiyun {
2953*4882a593Smuzhiyun 	struct cyclades_port *info = tty->driver_data;
2954*4882a593Smuzhiyun 
2955*4882a593Smuzhiyun #ifdef CY_DEBUG_OTHER
2956*4882a593Smuzhiyun 	printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
2957*4882a593Smuzhiyun #endif
2958*4882a593Smuzhiyun 
2959*4882a593Smuzhiyun 	if (serial_paranoia_check(info, tty->name, "cy_hangup"))
2960*4882a593Smuzhiyun 		return;
2961*4882a593Smuzhiyun 
2962*4882a593Smuzhiyun 	cy_flush_buffer(tty);
2963*4882a593Smuzhiyun 	cy_shutdown(info, tty);
2964*4882a593Smuzhiyun 	tty_port_hangup(&info->port);
2965*4882a593Smuzhiyun }				/* cy_hangup */
2966*4882a593Smuzhiyun 
cyy_carrier_raised(struct tty_port * port)2967*4882a593Smuzhiyun static int cyy_carrier_raised(struct tty_port *port)
2968*4882a593Smuzhiyun {
2969*4882a593Smuzhiyun 	struct cyclades_port *info = container_of(port, struct cyclades_port,
2970*4882a593Smuzhiyun 			port);
2971*4882a593Smuzhiyun 	struct cyclades_card *cinfo = info->card;
2972*4882a593Smuzhiyun 	unsigned long flags;
2973*4882a593Smuzhiyun 	int channel = info->line - cinfo->first_line;
2974*4882a593Smuzhiyun 	u32 cd;
2975*4882a593Smuzhiyun 
2976*4882a593Smuzhiyun 	spin_lock_irqsave(&cinfo->card_lock, flags);
2977*4882a593Smuzhiyun 	cyy_writeb(info, CyCAR, channel & 0x03);
2978*4882a593Smuzhiyun 	cd = cyy_readb(info, CyMSVR1) & CyDCD;
2979*4882a593Smuzhiyun 	spin_unlock_irqrestore(&cinfo->card_lock, flags);
2980*4882a593Smuzhiyun 
2981*4882a593Smuzhiyun 	return cd;
2982*4882a593Smuzhiyun }
2983*4882a593Smuzhiyun 
cyy_dtr_rts(struct tty_port * port,int raise)2984*4882a593Smuzhiyun static void cyy_dtr_rts(struct tty_port *port, int raise)
2985*4882a593Smuzhiyun {
2986*4882a593Smuzhiyun 	struct cyclades_port *info = container_of(port, struct cyclades_port,
2987*4882a593Smuzhiyun 			port);
2988*4882a593Smuzhiyun 	struct cyclades_card *cinfo = info->card;
2989*4882a593Smuzhiyun 	unsigned long flags;
2990*4882a593Smuzhiyun 
2991*4882a593Smuzhiyun 	spin_lock_irqsave(&cinfo->card_lock, flags);
2992*4882a593Smuzhiyun 	cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
2993*4882a593Smuzhiyun 			raise ? 0 : TIOCM_RTS | TIOCM_DTR);
2994*4882a593Smuzhiyun 	spin_unlock_irqrestore(&cinfo->card_lock, flags);
2995*4882a593Smuzhiyun }
2996*4882a593Smuzhiyun 
cyz_carrier_raised(struct tty_port * port)2997*4882a593Smuzhiyun static int cyz_carrier_raised(struct tty_port *port)
2998*4882a593Smuzhiyun {
2999*4882a593Smuzhiyun 	struct cyclades_port *info = container_of(port, struct cyclades_port,
3000*4882a593Smuzhiyun 			port);
3001*4882a593Smuzhiyun 
3002*4882a593Smuzhiyun 	return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
3003*4882a593Smuzhiyun }
3004*4882a593Smuzhiyun 
cyz_dtr_rts(struct tty_port * port,int raise)3005*4882a593Smuzhiyun static void cyz_dtr_rts(struct tty_port *port, int raise)
3006*4882a593Smuzhiyun {
3007*4882a593Smuzhiyun 	struct cyclades_port *info = container_of(port, struct cyclades_port,
3008*4882a593Smuzhiyun 			port);
3009*4882a593Smuzhiyun 	struct cyclades_card *cinfo = info->card;
3010*4882a593Smuzhiyun 	struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
3011*4882a593Smuzhiyun 	int ret, channel = info->line - cinfo->first_line;
3012*4882a593Smuzhiyun 	u32 rs;
3013*4882a593Smuzhiyun 
3014*4882a593Smuzhiyun 	rs = readl(&ch_ctrl->rs_control);
3015*4882a593Smuzhiyun 	if (raise)
3016*4882a593Smuzhiyun 		rs |= C_RS_RTS | C_RS_DTR;
3017*4882a593Smuzhiyun 	else
3018*4882a593Smuzhiyun 		rs &= ~(C_RS_RTS | C_RS_DTR);
3019*4882a593Smuzhiyun 	cy_writel(&ch_ctrl->rs_control, rs);
3020*4882a593Smuzhiyun 	ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L);
3021*4882a593Smuzhiyun 	if (ret != 0)
3022*4882a593Smuzhiyun 		printk(KERN_ERR "%s: retval on ttyC%d was %x\n",
3023*4882a593Smuzhiyun 				__func__, info->line, ret);
3024*4882a593Smuzhiyun #ifdef CY_DEBUG_DTR
3025*4882a593Smuzhiyun 	printk(KERN_DEBUG "%s: raising Z DTR\n", __func__);
3026*4882a593Smuzhiyun #endif
3027*4882a593Smuzhiyun }
3028*4882a593Smuzhiyun 
3029*4882a593Smuzhiyun static const struct tty_port_operations cyy_port_ops = {
3030*4882a593Smuzhiyun 	.carrier_raised = cyy_carrier_raised,
3031*4882a593Smuzhiyun 	.dtr_rts = cyy_dtr_rts,
3032*4882a593Smuzhiyun 	.shutdown = cy_do_close,
3033*4882a593Smuzhiyun };
3034*4882a593Smuzhiyun 
3035*4882a593Smuzhiyun static const struct tty_port_operations cyz_port_ops = {
3036*4882a593Smuzhiyun 	.carrier_raised = cyz_carrier_raised,
3037*4882a593Smuzhiyun 	.dtr_rts = cyz_dtr_rts,
3038*4882a593Smuzhiyun 	.shutdown = cy_do_close,
3039*4882a593Smuzhiyun };
3040*4882a593Smuzhiyun 
3041*4882a593Smuzhiyun /*
3042*4882a593Smuzhiyun  * ---------------------------------------------------------------------
3043*4882a593Smuzhiyun  * cy_init() and friends
3044*4882a593Smuzhiyun  *
3045*4882a593Smuzhiyun  * cy_init() is called at boot-time to initialize the serial driver.
3046*4882a593Smuzhiyun  * ---------------------------------------------------------------------
3047*4882a593Smuzhiyun  */
3048*4882a593Smuzhiyun 
cy_init_card(struct cyclades_card * cinfo)3049*4882a593Smuzhiyun static int cy_init_card(struct cyclades_card *cinfo)
3050*4882a593Smuzhiyun {
3051*4882a593Smuzhiyun 	struct cyclades_port *info;
3052*4882a593Smuzhiyun 	unsigned int channel, port;
3053*4882a593Smuzhiyun 
3054*4882a593Smuzhiyun 	spin_lock_init(&cinfo->card_lock);
3055*4882a593Smuzhiyun 	cinfo->intr_enabled = 0;
3056*4882a593Smuzhiyun 
3057*4882a593Smuzhiyun 	cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
3058*4882a593Smuzhiyun 			GFP_KERNEL);
3059*4882a593Smuzhiyun 	if (cinfo->ports == NULL) {
3060*4882a593Smuzhiyun 		printk(KERN_ERR "Cyclades: cannot allocate ports\n");
3061*4882a593Smuzhiyun 		return -ENOMEM;
3062*4882a593Smuzhiyun 	}
3063*4882a593Smuzhiyun 
3064*4882a593Smuzhiyun 	for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
3065*4882a593Smuzhiyun 			channel++, port++) {
3066*4882a593Smuzhiyun 		info = &cinfo->ports[channel];
3067*4882a593Smuzhiyun 		tty_port_init(&info->port);
3068*4882a593Smuzhiyun 		info->magic = CYCLADES_MAGIC;
3069*4882a593Smuzhiyun 		info->card = cinfo;
3070*4882a593Smuzhiyun 		info->line = port;
3071*4882a593Smuzhiyun 
3072*4882a593Smuzhiyun 		info->port.closing_wait = CLOSING_WAIT_DELAY;
3073*4882a593Smuzhiyun 		info->port.close_delay = 5 * HZ / 10;
3074*4882a593Smuzhiyun 		init_completion(&info->shutdown_wait);
3075*4882a593Smuzhiyun 
3076*4882a593Smuzhiyun 		if (cy_is_Z(cinfo)) {
3077*4882a593Smuzhiyun 			struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
3078*4882a593Smuzhiyun 			struct ZFW_CTRL *zfw_ctrl;
3079*4882a593Smuzhiyun 
3080*4882a593Smuzhiyun 			info->port.ops = &cyz_port_ops;
3081*4882a593Smuzhiyun 			info->type = PORT_STARTECH;
3082*4882a593Smuzhiyun 
3083*4882a593Smuzhiyun 			zfw_ctrl = cinfo->base_addr +
3084*4882a593Smuzhiyun 				(readl(&firm_id->zfwctrl_addr) & 0xfffff);
3085*4882a593Smuzhiyun 			info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
3086*4882a593Smuzhiyun 			info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
3087*4882a593Smuzhiyun 
3088*4882a593Smuzhiyun 			if (cinfo->hw_ver == ZO_V1)
3089*4882a593Smuzhiyun 				info->xmit_fifo_size = CYZ_FIFO_SIZE;
3090*4882a593Smuzhiyun 			else
3091*4882a593Smuzhiyun 				info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
3092*4882a593Smuzhiyun #ifdef CONFIG_CYZ_INTR
3093*4882a593Smuzhiyun 			timer_setup(&info->rx_full_timer, cyz_rx_restart, 0);
3094*4882a593Smuzhiyun #endif
3095*4882a593Smuzhiyun 		} else {
3096*4882a593Smuzhiyun 			unsigned short chip_number;
3097*4882a593Smuzhiyun 			int index = cinfo->bus_index;
3098*4882a593Smuzhiyun 
3099*4882a593Smuzhiyun 			info->port.ops = &cyy_port_ops;
3100*4882a593Smuzhiyun 			info->type = PORT_CIRRUS;
3101*4882a593Smuzhiyun 			info->xmit_fifo_size = CyMAX_CHAR_FIFO;
3102*4882a593Smuzhiyun 			info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
3103*4882a593Smuzhiyun 			info->cor2 = CyETC;
3104*4882a593Smuzhiyun 			info->cor3 = 0x08;	/* _very_ small rcv threshold */
3105*4882a593Smuzhiyun 
3106*4882a593Smuzhiyun 			chip_number = channel / CyPORTS_PER_CHIP;
3107*4882a593Smuzhiyun 			info->u.cyy.base_addr = cinfo->base_addr +
3108*4882a593Smuzhiyun 				(cy_chip_offset[chip_number] << index);
3109*4882a593Smuzhiyun 			info->chip_rev = cyy_readb(info, CyGFRCR);
3110*4882a593Smuzhiyun 
3111*4882a593Smuzhiyun 			if (info->chip_rev >= CD1400_REV_J) {
3112*4882a593Smuzhiyun 				/* It is a CD1400 rev. J or later */
3113*4882a593Smuzhiyun 				info->tbpr = baud_bpr_60[13];	/* Tx BPR */
3114*4882a593Smuzhiyun 				info->tco = baud_co_60[13];	/* Tx CO */
3115*4882a593Smuzhiyun 				info->rbpr = baud_bpr_60[13];	/* Rx BPR */
3116*4882a593Smuzhiyun 				info->rco = baud_co_60[13];	/* Rx CO */
3117*4882a593Smuzhiyun 				info->rtsdtr_inv = 1;
3118*4882a593Smuzhiyun 			} else {
3119*4882a593Smuzhiyun 				info->tbpr = baud_bpr_25[13];	/* Tx BPR */
3120*4882a593Smuzhiyun 				info->tco = baud_co_25[13];	/* Tx CO */
3121*4882a593Smuzhiyun 				info->rbpr = baud_bpr_25[13];	/* Rx BPR */
3122*4882a593Smuzhiyun 				info->rco = baud_co_25[13];	/* Rx CO */
3123*4882a593Smuzhiyun 				info->rtsdtr_inv = 0;
3124*4882a593Smuzhiyun 			}
3125*4882a593Smuzhiyun 			info->read_status_mask = CyTIMEOUT | CySPECHAR |
3126*4882a593Smuzhiyun 				CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
3127*4882a593Smuzhiyun 		}
3128*4882a593Smuzhiyun 
3129*4882a593Smuzhiyun 	}
3130*4882a593Smuzhiyun 
3131*4882a593Smuzhiyun #ifndef CONFIG_CYZ_INTR
3132*4882a593Smuzhiyun 	if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
3133*4882a593Smuzhiyun 		mod_timer(&cyz_timerlist, jiffies + 1);
3134*4882a593Smuzhiyun #ifdef CY_PCI_DEBUG
3135*4882a593Smuzhiyun 		printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
3136*4882a593Smuzhiyun #endif
3137*4882a593Smuzhiyun 	}
3138*4882a593Smuzhiyun #endif
3139*4882a593Smuzhiyun 	return 0;
3140*4882a593Smuzhiyun }
3141*4882a593Smuzhiyun 
3142*4882a593Smuzhiyun /* initialize chips on Cyclom-Y card -- return number of valid
3143*4882a593Smuzhiyun    chips (which is number of ports/4) */
cyy_init_card(void __iomem * true_base_addr,int index)3144*4882a593Smuzhiyun static unsigned short cyy_init_card(void __iomem *true_base_addr,
3145*4882a593Smuzhiyun 		int index)
3146*4882a593Smuzhiyun {
3147*4882a593Smuzhiyun 	unsigned int chip_number;
3148*4882a593Smuzhiyun 	void __iomem *base_addr;
3149*4882a593Smuzhiyun 
3150*4882a593Smuzhiyun 	cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
3151*4882a593Smuzhiyun 	/* Cy_HwReset is 0x1400 */
3152*4882a593Smuzhiyun 	cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
3153*4882a593Smuzhiyun 	/* Cy_ClrIntr is 0x1800 */
3154*4882a593Smuzhiyun 	udelay(500L);
3155*4882a593Smuzhiyun 
3156*4882a593Smuzhiyun 	for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
3157*4882a593Smuzhiyun 							chip_number++) {
3158*4882a593Smuzhiyun 		base_addr =
3159*4882a593Smuzhiyun 		    true_base_addr + (cy_chip_offset[chip_number] << index);
3160*4882a593Smuzhiyun 		mdelay(1);
3161*4882a593Smuzhiyun 		if (readb(base_addr + (CyCCR << index)) != 0x00) {
3162*4882a593Smuzhiyun 			/*************
3163*4882a593Smuzhiyun 			printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
3164*4882a593Smuzhiyun 			chip_number, (unsigned long)base_addr);
3165*4882a593Smuzhiyun 			*************/
3166*4882a593Smuzhiyun 			return chip_number;
3167*4882a593Smuzhiyun 		}
3168*4882a593Smuzhiyun 
3169*4882a593Smuzhiyun 		cy_writeb(base_addr + (CyGFRCR << index), 0);
3170*4882a593Smuzhiyun 		udelay(10L);
3171*4882a593Smuzhiyun 
3172*4882a593Smuzhiyun 		/* The Cyclom-16Y does not decode address bit 9 and therefore
3173*4882a593Smuzhiyun 		   cannot distinguish between references to chip 0 and a non-
3174*4882a593Smuzhiyun 		   existent chip 4.  If the preceding clearing of the supposed
3175*4882a593Smuzhiyun 		   chip 4 GFRCR register appears at chip 0, there is no chip 4
3176*4882a593Smuzhiyun 		   and this must be a Cyclom-16Y, not a Cyclom-32Ye.
3177*4882a593Smuzhiyun 		 */
3178*4882a593Smuzhiyun 		if (chip_number == 4 && readb(true_base_addr +
3179*4882a593Smuzhiyun 				(cy_chip_offset[0] << index) +
3180*4882a593Smuzhiyun 				(CyGFRCR << index)) == 0) {
3181*4882a593Smuzhiyun 			return chip_number;
3182*4882a593Smuzhiyun 		}
3183*4882a593Smuzhiyun 
3184*4882a593Smuzhiyun 		cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
3185*4882a593Smuzhiyun 		mdelay(1);
3186*4882a593Smuzhiyun 
3187*4882a593Smuzhiyun 		if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
3188*4882a593Smuzhiyun 			/*
3189*4882a593Smuzhiyun 			   printk(" chip #%d at %#6lx is not responding ",
3190*4882a593Smuzhiyun 			   chip_number, (unsigned long)base_addr);
3191*4882a593Smuzhiyun 			   printk("(GFRCR stayed 0)\n",
3192*4882a593Smuzhiyun 			 */
3193*4882a593Smuzhiyun 			return chip_number;
3194*4882a593Smuzhiyun 		}
3195*4882a593Smuzhiyun 		if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
3196*4882a593Smuzhiyun 				0x40) {
3197*4882a593Smuzhiyun 			/*
3198*4882a593Smuzhiyun 			printk(" chip #%d at %#6lx is not valid (GFRCR == "
3199*4882a593Smuzhiyun 					"%#2x)\n",
3200*4882a593Smuzhiyun 					chip_number, (unsigned long)base_addr,
3201*4882a593Smuzhiyun 					base_addr[CyGFRCR<<index]);
3202*4882a593Smuzhiyun 			 */
3203*4882a593Smuzhiyun 			return chip_number;
3204*4882a593Smuzhiyun 		}
3205*4882a593Smuzhiyun 		cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
3206*4882a593Smuzhiyun 		if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
3207*4882a593Smuzhiyun 			/* It is a CD1400 rev. J or later */
3208*4882a593Smuzhiyun 			/* Impossible to reach 5ms with this chip.
3209*4882a593Smuzhiyun 			   Changed to 2ms instead (f = 500 Hz). */
3210*4882a593Smuzhiyun 			cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
3211*4882a593Smuzhiyun 		} else {
3212*4882a593Smuzhiyun 			/* f = 200 Hz */
3213*4882a593Smuzhiyun 			cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
3214*4882a593Smuzhiyun 		}
3215*4882a593Smuzhiyun 
3216*4882a593Smuzhiyun 		/*
3217*4882a593Smuzhiyun 		   printk(" chip #%d at %#6lx is rev 0x%2x\n",
3218*4882a593Smuzhiyun 		   chip_number, (unsigned long)base_addr,
3219*4882a593Smuzhiyun 		   readb(base_addr+(CyGFRCR<<index)));
3220*4882a593Smuzhiyun 		 */
3221*4882a593Smuzhiyun 	}
3222*4882a593Smuzhiyun 	return chip_number;
3223*4882a593Smuzhiyun }				/* cyy_init_card */
3224*4882a593Smuzhiyun 
3225*4882a593Smuzhiyun /*
3226*4882a593Smuzhiyun  * ---------------------------------------------------------------------
3227*4882a593Smuzhiyun  * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
3228*4882a593Smuzhiyun  * sets global variables and return the number of ISA boards found.
3229*4882a593Smuzhiyun  * ---------------------------------------------------------------------
3230*4882a593Smuzhiyun  */
cy_detect_isa(void)3231*4882a593Smuzhiyun static int __init cy_detect_isa(void)
3232*4882a593Smuzhiyun {
3233*4882a593Smuzhiyun #ifdef CONFIG_ISA
3234*4882a593Smuzhiyun 	struct cyclades_card *card;
3235*4882a593Smuzhiyun 	unsigned short cy_isa_irq, nboard;
3236*4882a593Smuzhiyun 	void __iomem *cy_isa_address;
3237*4882a593Smuzhiyun 	unsigned short i, j, k, cy_isa_nchan;
3238*4882a593Smuzhiyun 	int isparam = 0;
3239*4882a593Smuzhiyun 
3240*4882a593Smuzhiyun 	nboard = 0;
3241*4882a593Smuzhiyun 
3242*4882a593Smuzhiyun 	/* Check for module parameters */
3243*4882a593Smuzhiyun 	for (i = 0; i < NR_CARDS; i++) {
3244*4882a593Smuzhiyun 		if (maddr[i] || i) {
3245*4882a593Smuzhiyun 			isparam = 1;
3246*4882a593Smuzhiyun 			cy_isa_addresses[i] = maddr[i];
3247*4882a593Smuzhiyun 		}
3248*4882a593Smuzhiyun 		if (!maddr[i])
3249*4882a593Smuzhiyun 			break;
3250*4882a593Smuzhiyun 	}
3251*4882a593Smuzhiyun 
3252*4882a593Smuzhiyun 	/* scan the address table probing for Cyclom-Y/ISA boards */
3253*4882a593Smuzhiyun 	for (i = 0; i < NR_ISA_ADDRS; i++) {
3254*4882a593Smuzhiyun 		unsigned int isa_address = cy_isa_addresses[i];
3255*4882a593Smuzhiyun 		if (isa_address == 0x0000)
3256*4882a593Smuzhiyun 			return nboard;
3257*4882a593Smuzhiyun 
3258*4882a593Smuzhiyun 		/* probe for CD1400... */
3259*4882a593Smuzhiyun 		cy_isa_address = ioremap(isa_address, CyISA_Ywin);
3260*4882a593Smuzhiyun 		if (cy_isa_address == NULL) {
3261*4882a593Smuzhiyun 			printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
3262*4882a593Smuzhiyun 					"address\n");
3263*4882a593Smuzhiyun 			continue;
3264*4882a593Smuzhiyun 		}
3265*4882a593Smuzhiyun 		cy_isa_nchan = CyPORTS_PER_CHIP *
3266*4882a593Smuzhiyun 			cyy_init_card(cy_isa_address, 0);
3267*4882a593Smuzhiyun 		if (cy_isa_nchan == 0) {
3268*4882a593Smuzhiyun 			iounmap(cy_isa_address);
3269*4882a593Smuzhiyun 			continue;
3270*4882a593Smuzhiyun 		}
3271*4882a593Smuzhiyun 
3272*4882a593Smuzhiyun 		if (isparam && i < NR_CARDS && irq[i])
3273*4882a593Smuzhiyun 			cy_isa_irq = irq[i];
3274*4882a593Smuzhiyun 		else
3275*4882a593Smuzhiyun 			/* find out the board's irq by probing */
3276*4882a593Smuzhiyun 			cy_isa_irq = detect_isa_irq(cy_isa_address);
3277*4882a593Smuzhiyun 		if (cy_isa_irq == 0) {
3278*4882a593Smuzhiyun 			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
3279*4882a593Smuzhiyun 				"IRQ could not be detected.\n",
3280*4882a593Smuzhiyun 				(unsigned long)cy_isa_address);
3281*4882a593Smuzhiyun 			iounmap(cy_isa_address);
3282*4882a593Smuzhiyun 			continue;
3283*4882a593Smuzhiyun 		}
3284*4882a593Smuzhiyun 
3285*4882a593Smuzhiyun 		if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
3286*4882a593Smuzhiyun 			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3287*4882a593Smuzhiyun 				"more channels are available. Change NR_PORTS "
3288*4882a593Smuzhiyun 				"in cyclades.c and recompile kernel.\n",
3289*4882a593Smuzhiyun 				(unsigned long)cy_isa_address);
3290*4882a593Smuzhiyun 			iounmap(cy_isa_address);
3291*4882a593Smuzhiyun 			return nboard;
3292*4882a593Smuzhiyun 		}
3293*4882a593Smuzhiyun 		/* fill the next cy_card structure available */
3294*4882a593Smuzhiyun 		for (j = 0; j < NR_CARDS; j++) {
3295*4882a593Smuzhiyun 			card = &cy_card[j];
3296*4882a593Smuzhiyun 			if (card->base_addr == NULL)
3297*4882a593Smuzhiyun 				break;
3298*4882a593Smuzhiyun 		}
3299*4882a593Smuzhiyun 		if (j == NR_CARDS) {	/* no more cy_cards available */
3300*4882a593Smuzhiyun 			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3301*4882a593Smuzhiyun 				"more cards can be used. Change NR_CARDS in "
3302*4882a593Smuzhiyun 				"cyclades.c and recompile kernel.\n",
3303*4882a593Smuzhiyun 				(unsigned long)cy_isa_address);
3304*4882a593Smuzhiyun 			iounmap(cy_isa_address);
3305*4882a593Smuzhiyun 			return nboard;
3306*4882a593Smuzhiyun 		}
3307*4882a593Smuzhiyun 
3308*4882a593Smuzhiyun 		/* allocate IRQ */
3309*4882a593Smuzhiyun 		if (request_irq(cy_isa_irq, cyy_interrupt,
3310*4882a593Smuzhiyun 				0, "Cyclom-Y", card)) {
3311*4882a593Smuzhiyun 			printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
3312*4882a593Smuzhiyun 				"could not allocate IRQ#%d.\n",
3313*4882a593Smuzhiyun 				(unsigned long)cy_isa_address, cy_isa_irq);
3314*4882a593Smuzhiyun 			iounmap(cy_isa_address);
3315*4882a593Smuzhiyun 			return nboard;
3316*4882a593Smuzhiyun 		}
3317*4882a593Smuzhiyun 
3318*4882a593Smuzhiyun 		/* set cy_card */
3319*4882a593Smuzhiyun 		card->base_addr = cy_isa_address;
3320*4882a593Smuzhiyun 		card->ctl_addr.p9050 = NULL;
3321*4882a593Smuzhiyun 		card->irq = (int)cy_isa_irq;
3322*4882a593Smuzhiyun 		card->bus_index = 0;
3323*4882a593Smuzhiyun 		card->first_line = cy_next_channel;
3324*4882a593Smuzhiyun 		card->num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
3325*4882a593Smuzhiyun 		card->nports = cy_isa_nchan;
3326*4882a593Smuzhiyun 		if (cy_init_card(card)) {
3327*4882a593Smuzhiyun 			card->base_addr = NULL;
3328*4882a593Smuzhiyun 			free_irq(cy_isa_irq, card);
3329*4882a593Smuzhiyun 			iounmap(cy_isa_address);
3330*4882a593Smuzhiyun 			continue;
3331*4882a593Smuzhiyun 		}
3332*4882a593Smuzhiyun 		nboard++;
3333*4882a593Smuzhiyun 
3334*4882a593Smuzhiyun 		printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
3335*4882a593Smuzhiyun 			"%d channels starting from port %d\n",
3336*4882a593Smuzhiyun 			j + 1, (unsigned long)cy_isa_address,
3337*4882a593Smuzhiyun 			(unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
3338*4882a593Smuzhiyun 			cy_isa_irq, cy_isa_nchan, cy_next_channel);
3339*4882a593Smuzhiyun 
3340*4882a593Smuzhiyun 		for (k = 0, j = cy_next_channel;
3341*4882a593Smuzhiyun 				j < cy_next_channel + cy_isa_nchan; j++, k++)
3342*4882a593Smuzhiyun 			tty_port_register_device(&card->ports[k].port,
3343*4882a593Smuzhiyun 					cy_serial_driver, j, NULL);
3344*4882a593Smuzhiyun 		cy_next_channel += cy_isa_nchan;
3345*4882a593Smuzhiyun 	}
3346*4882a593Smuzhiyun 	return nboard;
3347*4882a593Smuzhiyun #else
3348*4882a593Smuzhiyun 	return 0;
3349*4882a593Smuzhiyun #endif				/* CONFIG_ISA */
3350*4882a593Smuzhiyun }				/* cy_detect_isa */
3351*4882a593Smuzhiyun 
3352*4882a593Smuzhiyun #ifdef CONFIG_PCI
cyc_isfwstr(const char * str,unsigned int size)3353*4882a593Smuzhiyun static inline int cyc_isfwstr(const char *str, unsigned int size)
3354*4882a593Smuzhiyun {
3355*4882a593Smuzhiyun 	unsigned int a;
3356*4882a593Smuzhiyun 
3357*4882a593Smuzhiyun 	for (a = 0; a < size && *str; a++, str++)
3358*4882a593Smuzhiyun 		if (*str & 0x80)
3359*4882a593Smuzhiyun 			return -EINVAL;
3360*4882a593Smuzhiyun 
3361*4882a593Smuzhiyun 	for (; a < size; a++, str++)
3362*4882a593Smuzhiyun 		if (*str)
3363*4882a593Smuzhiyun 			return -EINVAL;
3364*4882a593Smuzhiyun 
3365*4882a593Smuzhiyun 	return 0;
3366*4882a593Smuzhiyun }
3367*4882a593Smuzhiyun 
cyz_fpga_copy(void __iomem * fpga,const u8 * data,unsigned int size)3368*4882a593Smuzhiyun static inline void cyz_fpga_copy(void __iomem *fpga, const u8 *data,
3369*4882a593Smuzhiyun 		unsigned int size)
3370*4882a593Smuzhiyun {
3371*4882a593Smuzhiyun 	for (; size > 0; size--) {
3372*4882a593Smuzhiyun 		cy_writel(fpga, *data++);
3373*4882a593Smuzhiyun 		udelay(10);
3374*4882a593Smuzhiyun 	}
3375*4882a593Smuzhiyun }
3376*4882a593Smuzhiyun 
plx_init(struct pci_dev * pdev,int irq,struct RUNTIME_9060 __iomem * addr)3377*4882a593Smuzhiyun static void plx_init(struct pci_dev *pdev, int irq,
3378*4882a593Smuzhiyun 		struct RUNTIME_9060 __iomem *addr)
3379*4882a593Smuzhiyun {
3380*4882a593Smuzhiyun 	/* Reset PLX */
3381*4882a593Smuzhiyun 	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
3382*4882a593Smuzhiyun 	udelay(100L);
3383*4882a593Smuzhiyun 	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
3384*4882a593Smuzhiyun 
3385*4882a593Smuzhiyun 	/* Reload Config. Registers from EEPROM */
3386*4882a593Smuzhiyun 	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
3387*4882a593Smuzhiyun 	udelay(100L);
3388*4882a593Smuzhiyun 	cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);
3389*4882a593Smuzhiyun 
3390*4882a593Smuzhiyun 	/* For some yet unknown reason, once the PLX9060 reloads the EEPROM,
3391*4882a593Smuzhiyun 	 * the IRQ is lost and, thus, we have to re-write it to the PCI config.
3392*4882a593Smuzhiyun 	 * registers. This will remain here until we find a permanent fix.
3393*4882a593Smuzhiyun 	 */
3394*4882a593Smuzhiyun 	pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
3395*4882a593Smuzhiyun }
3396*4882a593Smuzhiyun 
__cyz_load_fw(const struct firmware * fw,const char * name,const u32 mailbox,void __iomem * base,void __iomem * fpga)3397*4882a593Smuzhiyun static int __cyz_load_fw(const struct firmware *fw,
3398*4882a593Smuzhiyun 		const char *name, const u32 mailbox, void __iomem *base,
3399*4882a593Smuzhiyun 		void __iomem *fpga)
3400*4882a593Smuzhiyun {
3401*4882a593Smuzhiyun 	const void *ptr = fw->data;
3402*4882a593Smuzhiyun 	const struct zfile_header *h = ptr;
3403*4882a593Smuzhiyun 	const struct zfile_config *c, *cs;
3404*4882a593Smuzhiyun 	const struct zfile_block *b, *bs;
3405*4882a593Smuzhiyun 	unsigned int a, tmp, len = fw->size;
3406*4882a593Smuzhiyun #define BAD_FW KERN_ERR "Bad firmware: "
3407*4882a593Smuzhiyun 	if (len < sizeof(*h)) {
3408*4882a593Smuzhiyun 		printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h));
3409*4882a593Smuzhiyun 		return -EINVAL;
3410*4882a593Smuzhiyun 	}
3411*4882a593Smuzhiyun 
3412*4882a593Smuzhiyun 	cs = ptr + h->config_offset;
3413*4882a593Smuzhiyun 	bs = ptr + h->block_offset;
3414*4882a593Smuzhiyun 
3415*4882a593Smuzhiyun 	if ((void *)(cs + h->n_config) > ptr + len ||
3416*4882a593Smuzhiyun 			(void *)(bs + h->n_blocks) > ptr + len) {
3417*4882a593Smuzhiyun 		printk(BAD_FW "too short");
3418*4882a593Smuzhiyun 		return  -EINVAL;
3419*4882a593Smuzhiyun 	}
3420*4882a593Smuzhiyun 
3421*4882a593Smuzhiyun 	if (cyc_isfwstr(h->name, sizeof(h->name)) ||
3422*4882a593Smuzhiyun 			cyc_isfwstr(h->date, sizeof(h->date))) {
3423*4882a593Smuzhiyun 		printk(BAD_FW "bad formatted header string\n");
3424*4882a593Smuzhiyun 		return -EINVAL;
3425*4882a593Smuzhiyun 	}
3426*4882a593Smuzhiyun 
3427*4882a593Smuzhiyun 	if (strncmp(name, h->name, sizeof(h->name))) {
3428*4882a593Smuzhiyun 		printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name);
3429*4882a593Smuzhiyun 		return -EINVAL;
3430*4882a593Smuzhiyun 	}
3431*4882a593Smuzhiyun 
3432*4882a593Smuzhiyun 	tmp = 0;
3433*4882a593Smuzhiyun 	for (c = cs; c < cs + h->n_config; c++) {
3434*4882a593Smuzhiyun 		for (a = 0; a < c->n_blocks; a++)
3435*4882a593Smuzhiyun 			if (c->block_list[a] > h->n_blocks) {
3436*4882a593Smuzhiyun 				printk(BAD_FW "bad block ref number in cfgs\n");
3437*4882a593Smuzhiyun 				return -EINVAL;
3438*4882a593Smuzhiyun 			}
3439*4882a593Smuzhiyun 		if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */
3440*4882a593Smuzhiyun 			tmp++;
3441*4882a593Smuzhiyun 	}
3442*4882a593Smuzhiyun 	if (!tmp) {
3443*4882a593Smuzhiyun 		printk(BAD_FW "nothing appropriate\n");
3444*4882a593Smuzhiyun 		return -EINVAL;
3445*4882a593Smuzhiyun 	}
3446*4882a593Smuzhiyun 
3447*4882a593Smuzhiyun 	for (b = bs; b < bs + h->n_blocks; b++)
3448*4882a593Smuzhiyun 		if (b->file_offset + b->size > len) {
3449*4882a593Smuzhiyun 			printk(BAD_FW "bad block data offset\n");
3450*4882a593Smuzhiyun 			return -EINVAL;
3451*4882a593Smuzhiyun 		}
3452*4882a593Smuzhiyun 
3453*4882a593Smuzhiyun 	/* everything is OK, let's seek'n'load it */
3454*4882a593Smuzhiyun 	for (c = cs; c < cs + h->n_config; c++)
3455*4882a593Smuzhiyun 		if (c->mailbox == mailbox && c->function == 0)
3456*4882a593Smuzhiyun 			break;
3457*4882a593Smuzhiyun 
3458*4882a593Smuzhiyun 	for (a = 0; a < c->n_blocks; a++) {
3459*4882a593Smuzhiyun 		b = &bs[c->block_list[a]];
3460*4882a593Smuzhiyun 		if (b->type == ZBLOCK_FPGA) {
3461*4882a593Smuzhiyun 			if (fpga != NULL)
3462*4882a593Smuzhiyun 				cyz_fpga_copy(fpga, ptr + b->file_offset,
3463*4882a593Smuzhiyun 						b->size);
3464*4882a593Smuzhiyun 		} else {
3465*4882a593Smuzhiyun 			if (base != NULL)
3466*4882a593Smuzhiyun 				memcpy_toio(base + b->ram_offset,
3467*4882a593Smuzhiyun 					       ptr + b->file_offset, b->size);
3468*4882a593Smuzhiyun 		}
3469*4882a593Smuzhiyun 	}
3470*4882a593Smuzhiyun #undef BAD_FW
3471*4882a593Smuzhiyun 	return 0;
3472*4882a593Smuzhiyun }
3473*4882a593Smuzhiyun 
cyz_load_fw(struct pci_dev * pdev,void __iomem * base_addr,struct RUNTIME_9060 __iomem * ctl_addr,int irq)3474*4882a593Smuzhiyun static int cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
3475*4882a593Smuzhiyun 		struct RUNTIME_9060 __iomem *ctl_addr, int irq)
3476*4882a593Smuzhiyun {
3477*4882a593Smuzhiyun 	const struct firmware *fw;
3478*4882a593Smuzhiyun 	struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
3479*4882a593Smuzhiyun 	struct CUSTOM_REG __iomem *cust = base_addr;
3480*4882a593Smuzhiyun 	struct ZFW_CTRL __iomem *pt_zfwctrl;
3481*4882a593Smuzhiyun 	void __iomem *tmp;
3482*4882a593Smuzhiyun 	u32 mailbox, status, nchan;
3483*4882a593Smuzhiyun 	unsigned int i;
3484*4882a593Smuzhiyun 	int retval;
3485*4882a593Smuzhiyun 
3486*4882a593Smuzhiyun 	retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev);
3487*4882a593Smuzhiyun 	if (retval) {
3488*4882a593Smuzhiyun 		dev_err(&pdev->dev, "can't get firmware\n");
3489*4882a593Smuzhiyun 		goto err;
3490*4882a593Smuzhiyun 	}
3491*4882a593Smuzhiyun 
3492*4882a593Smuzhiyun 	/* Check whether the firmware is already loaded and running. If
3493*4882a593Smuzhiyun 	   positive, skip this board */
3494*4882a593Smuzhiyun 	if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
3495*4882a593Smuzhiyun 		u32 cntval = readl(base_addr + 0x190);
3496*4882a593Smuzhiyun 
3497*4882a593Smuzhiyun 		udelay(100);
3498*4882a593Smuzhiyun 		if (cntval != readl(base_addr + 0x190)) {
3499*4882a593Smuzhiyun 			/* FW counter is working, FW is running */
3500*4882a593Smuzhiyun 			dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. "
3501*4882a593Smuzhiyun 					"Skipping board.\n");
3502*4882a593Smuzhiyun 			retval = 0;
3503*4882a593Smuzhiyun 			goto err_rel;
3504*4882a593Smuzhiyun 		}
3505*4882a593Smuzhiyun 	}
3506*4882a593Smuzhiyun 
3507*4882a593Smuzhiyun 	/* start boot */
3508*4882a593Smuzhiyun 	cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) &
3509*4882a593Smuzhiyun 			~0x00030800UL);
3510*4882a593Smuzhiyun 
3511*4882a593Smuzhiyun 	mailbox = readl(&ctl_addr->mail_box_0);
3512*4882a593Smuzhiyun 
3513*4882a593Smuzhiyun 	if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
3514*4882a593Smuzhiyun 		/* stops CPU and set window to beginning of RAM */
3515*4882a593Smuzhiyun 		cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3516*4882a593Smuzhiyun 		cy_writel(&cust->cpu_stop, 0);
3517*4882a593Smuzhiyun 		cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3518*4882a593Smuzhiyun 		udelay(100);
3519*4882a593Smuzhiyun 	}
3520*4882a593Smuzhiyun 
3521*4882a593Smuzhiyun 	plx_init(pdev, irq, ctl_addr);
3522*4882a593Smuzhiyun 
3523*4882a593Smuzhiyun 	if (mailbox != 0) {
3524*4882a593Smuzhiyun 		/* load FPGA */
3525*4882a593Smuzhiyun 		retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL,
3526*4882a593Smuzhiyun 				base_addr);
3527*4882a593Smuzhiyun 		if (retval)
3528*4882a593Smuzhiyun 			goto err_rel;
3529*4882a593Smuzhiyun 		if (!__cyz_fpga_loaded(ctl_addr)) {
3530*4882a593Smuzhiyun 			dev_err(&pdev->dev, "fw upload successful, but fw is "
3531*4882a593Smuzhiyun 					"not loaded\n");
3532*4882a593Smuzhiyun 			goto err_rel;
3533*4882a593Smuzhiyun 		}
3534*4882a593Smuzhiyun 	}
3535*4882a593Smuzhiyun 
3536*4882a593Smuzhiyun 	/* stops CPU and set window to beginning of RAM */
3537*4882a593Smuzhiyun 	cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3538*4882a593Smuzhiyun 	cy_writel(&cust->cpu_stop, 0);
3539*4882a593Smuzhiyun 	cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3540*4882a593Smuzhiyun 	udelay(100);
3541*4882a593Smuzhiyun 
3542*4882a593Smuzhiyun 	/* clear memory */
3543*4882a593Smuzhiyun 	for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
3544*4882a593Smuzhiyun 		cy_writeb(tmp, 255);
3545*4882a593Smuzhiyun 	if (mailbox != 0) {
3546*4882a593Smuzhiyun 		/* set window to last 512K of RAM */
3547*4882a593Smuzhiyun 		cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
3548*4882a593Smuzhiyun 		for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
3549*4882a593Smuzhiyun 			cy_writeb(tmp, 255);
3550*4882a593Smuzhiyun 		/* set window to beginning of RAM */
3551*4882a593Smuzhiyun 		cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3552*4882a593Smuzhiyun 	}
3553*4882a593Smuzhiyun 
3554*4882a593Smuzhiyun 	retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
3555*4882a593Smuzhiyun 	release_firmware(fw);
3556*4882a593Smuzhiyun 	if (retval)
3557*4882a593Smuzhiyun 		goto err;
3558*4882a593Smuzhiyun 
3559*4882a593Smuzhiyun 	/* finish boot and start boards */
3560*4882a593Smuzhiyun 	cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3561*4882a593Smuzhiyun 	cy_writel(&cust->cpu_start, 0);
3562*4882a593Smuzhiyun 	cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3563*4882a593Smuzhiyun 	i = 0;
3564*4882a593Smuzhiyun 	while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40)
3565*4882a593Smuzhiyun 		msleep(100);
3566*4882a593Smuzhiyun 	if (status != ZFIRM_ID) {
3567*4882a593Smuzhiyun 		if (status == ZFIRM_HLT) {
3568*4882a593Smuzhiyun 			dev_err(&pdev->dev, "you need an external power supply "
3569*4882a593Smuzhiyun 				"for this number of ports. Firmware halted and "
3570*4882a593Smuzhiyun 				"board reset.\n");
3571*4882a593Smuzhiyun 			retval = -EIO;
3572*4882a593Smuzhiyun 			goto err;
3573*4882a593Smuzhiyun 		}
3574*4882a593Smuzhiyun 		dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting "
3575*4882a593Smuzhiyun 				"some more time\n", status);
3576*4882a593Smuzhiyun 		while ((status = readl(&fid->signature)) != ZFIRM_ID &&
3577*4882a593Smuzhiyun 				i++ < 200)
3578*4882a593Smuzhiyun 			msleep(100);
3579*4882a593Smuzhiyun 		if (status != ZFIRM_ID) {
3580*4882a593Smuzhiyun 			dev_err(&pdev->dev, "Board not started in 20 seconds! "
3581*4882a593Smuzhiyun 					"Giving up. (fid->signature = 0x%x)\n",
3582*4882a593Smuzhiyun 					status);
3583*4882a593Smuzhiyun 			dev_info(&pdev->dev, "*** Warning ***: if you are "
3584*4882a593Smuzhiyun 				"upgrading the FW, please power cycle the "
3585*4882a593Smuzhiyun 				"system before loading the new FW to the "
3586*4882a593Smuzhiyun 				"Cyclades-Z.\n");
3587*4882a593Smuzhiyun 
3588*4882a593Smuzhiyun 			if (__cyz_fpga_loaded(ctl_addr))
3589*4882a593Smuzhiyun 				plx_init(pdev, irq, ctl_addr);
3590*4882a593Smuzhiyun 
3591*4882a593Smuzhiyun 			retval = -EIO;
3592*4882a593Smuzhiyun 			goto err;
3593*4882a593Smuzhiyun 		}
3594*4882a593Smuzhiyun 		dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n",
3595*4882a593Smuzhiyun 				i / 10);
3596*4882a593Smuzhiyun 	}
3597*4882a593Smuzhiyun 	pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr);
3598*4882a593Smuzhiyun 
3599*4882a593Smuzhiyun 	dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n",
3600*4882a593Smuzhiyun 			base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
3601*4882a593Smuzhiyun 			base_addr + readl(&fid->zfwctrl_addr));
3602*4882a593Smuzhiyun 
3603*4882a593Smuzhiyun 	nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
3604*4882a593Smuzhiyun 	dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
3605*4882a593Smuzhiyun 		readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
3606*4882a593Smuzhiyun 
3607*4882a593Smuzhiyun 	if (nchan == 0) {
3608*4882a593Smuzhiyun 		dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
3609*4882a593Smuzhiyun 			"check the connection between the Z host card and the "
3610*4882a593Smuzhiyun 			"serial expanders.\n");
3611*4882a593Smuzhiyun 
3612*4882a593Smuzhiyun 		if (__cyz_fpga_loaded(ctl_addr))
3613*4882a593Smuzhiyun 			plx_init(pdev, irq, ctl_addr);
3614*4882a593Smuzhiyun 
3615*4882a593Smuzhiyun 		dev_info(&pdev->dev, "Null number of ports detected. Board "
3616*4882a593Smuzhiyun 				"reset.\n");
3617*4882a593Smuzhiyun 		retval = 0;
3618*4882a593Smuzhiyun 		goto err;
3619*4882a593Smuzhiyun 	}
3620*4882a593Smuzhiyun 
3621*4882a593Smuzhiyun 	cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX);
3622*4882a593Smuzhiyun 	cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION);
3623*4882a593Smuzhiyun 
3624*4882a593Smuzhiyun 	/*
3625*4882a593Smuzhiyun 	   Early firmware failed to start looking for commands.
3626*4882a593Smuzhiyun 	   This enables firmware interrupts for those commands.
3627*4882a593Smuzhiyun 	 */
3628*4882a593Smuzhiyun 	cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3629*4882a593Smuzhiyun 			(1 << 17));
3630*4882a593Smuzhiyun 	cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3631*4882a593Smuzhiyun 			0x00030800UL);
3632*4882a593Smuzhiyun 
3633*4882a593Smuzhiyun 	return nchan;
3634*4882a593Smuzhiyun err_rel:
3635*4882a593Smuzhiyun 	release_firmware(fw);
3636*4882a593Smuzhiyun err:
3637*4882a593Smuzhiyun 	return retval;
3638*4882a593Smuzhiyun }
3639*4882a593Smuzhiyun 
cy_pci_probe(struct pci_dev * pdev,const struct pci_device_id * ent)3640*4882a593Smuzhiyun static int cy_pci_probe(struct pci_dev *pdev,
3641*4882a593Smuzhiyun 		const struct pci_device_id *ent)
3642*4882a593Smuzhiyun {
3643*4882a593Smuzhiyun 	struct cyclades_card *card;
3644*4882a593Smuzhiyun 	void __iomem *addr0 = NULL, *addr2 = NULL;
3645*4882a593Smuzhiyun 	char *card_name = NULL;
3646*4882a593Smuzhiyun 	u32 mailbox;
3647*4882a593Smuzhiyun 	unsigned int device_id, nchan = 0, card_no, i, j;
3648*4882a593Smuzhiyun 	unsigned char plx_ver;
3649*4882a593Smuzhiyun 	int retval, irq;
3650*4882a593Smuzhiyun 
3651*4882a593Smuzhiyun 	retval = pci_enable_device(pdev);
3652*4882a593Smuzhiyun 	if (retval) {
3653*4882a593Smuzhiyun 		dev_err(&pdev->dev, "cannot enable device\n");
3654*4882a593Smuzhiyun 		goto err;
3655*4882a593Smuzhiyun 	}
3656*4882a593Smuzhiyun 
3657*4882a593Smuzhiyun 	/* read PCI configuration area */
3658*4882a593Smuzhiyun 	irq = pdev->irq;
3659*4882a593Smuzhiyun 	device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
3660*4882a593Smuzhiyun 
3661*4882a593Smuzhiyun #if defined(__alpha__)
3662*4882a593Smuzhiyun 	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) {	/* below 1M? */
3663*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
3664*4882a593Smuzhiyun 			"addresses on Alpha systems.\n");
3665*4882a593Smuzhiyun 		retval = -EIO;
3666*4882a593Smuzhiyun 		goto err_dis;
3667*4882a593Smuzhiyun 	}
3668*4882a593Smuzhiyun #endif
3669*4882a593Smuzhiyun 	if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
3670*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
3671*4882a593Smuzhiyun 			"addresses\n");
3672*4882a593Smuzhiyun 		retval = -EIO;
3673*4882a593Smuzhiyun 		goto err_dis;
3674*4882a593Smuzhiyun 	}
3675*4882a593Smuzhiyun 
3676*4882a593Smuzhiyun 	if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
3677*4882a593Smuzhiyun 		dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
3678*4882a593Smuzhiyun 				"it...\n");
3679*4882a593Smuzhiyun 		pdev->resource[2].flags &= ~IORESOURCE_IO;
3680*4882a593Smuzhiyun 	}
3681*4882a593Smuzhiyun 
3682*4882a593Smuzhiyun 	retval = pci_request_regions(pdev, "cyclades");
3683*4882a593Smuzhiyun 	if (retval) {
3684*4882a593Smuzhiyun 		dev_err(&pdev->dev, "failed to reserve resources\n");
3685*4882a593Smuzhiyun 		goto err_dis;
3686*4882a593Smuzhiyun 	}
3687*4882a593Smuzhiyun 
3688*4882a593Smuzhiyun 	retval = -EIO;
3689*4882a593Smuzhiyun 	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3690*4882a593Smuzhiyun 			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
3691*4882a593Smuzhiyun 		card_name = "Cyclom-Y";
3692*4882a593Smuzhiyun 
3693*4882a593Smuzhiyun 		addr0 = ioremap(pci_resource_start(pdev, 0),
3694*4882a593Smuzhiyun 				CyPCI_Yctl);
3695*4882a593Smuzhiyun 		if (addr0 == NULL) {
3696*4882a593Smuzhiyun 			dev_err(&pdev->dev, "can't remap ctl region\n");
3697*4882a593Smuzhiyun 			goto err_reg;
3698*4882a593Smuzhiyun 		}
3699*4882a593Smuzhiyun 		addr2 = ioremap(pci_resource_start(pdev, 2),
3700*4882a593Smuzhiyun 				CyPCI_Ywin);
3701*4882a593Smuzhiyun 		if (addr2 == NULL) {
3702*4882a593Smuzhiyun 			dev_err(&pdev->dev, "can't remap base region\n");
3703*4882a593Smuzhiyun 			goto err_unmap;
3704*4882a593Smuzhiyun 		}
3705*4882a593Smuzhiyun 
3706*4882a593Smuzhiyun 		nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
3707*4882a593Smuzhiyun 		if (nchan == 0) {
3708*4882a593Smuzhiyun 			dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
3709*4882a593Smuzhiyun 					"Serial-Modules\n");
3710*4882a593Smuzhiyun 			goto err_unmap;
3711*4882a593Smuzhiyun 		}
3712*4882a593Smuzhiyun 	} else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
3713*4882a593Smuzhiyun 		struct RUNTIME_9060 __iomem *ctl_addr;
3714*4882a593Smuzhiyun 
3715*4882a593Smuzhiyun 		ctl_addr = addr0 = ioremap(pci_resource_start(pdev, 0),
3716*4882a593Smuzhiyun 				CyPCI_Zctl);
3717*4882a593Smuzhiyun 		if (addr0 == NULL) {
3718*4882a593Smuzhiyun 			dev_err(&pdev->dev, "can't remap ctl region\n");
3719*4882a593Smuzhiyun 			goto err_reg;
3720*4882a593Smuzhiyun 		}
3721*4882a593Smuzhiyun 
3722*4882a593Smuzhiyun 		/* Disable interrupts on the PLX before resetting it */
3723*4882a593Smuzhiyun 		cy_writew(&ctl_addr->intr_ctrl_stat,
3724*4882a593Smuzhiyun 				readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
3725*4882a593Smuzhiyun 
3726*4882a593Smuzhiyun 		plx_init(pdev, irq, addr0);
3727*4882a593Smuzhiyun 
3728*4882a593Smuzhiyun 		mailbox = readl(&ctl_addr->mail_box_0);
3729*4882a593Smuzhiyun 
3730*4882a593Smuzhiyun 		addr2 = ioremap(pci_resource_start(pdev, 2),
3731*4882a593Smuzhiyun 				mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
3732*4882a593Smuzhiyun 		if (addr2 == NULL) {
3733*4882a593Smuzhiyun 			dev_err(&pdev->dev, "can't remap base region\n");
3734*4882a593Smuzhiyun 			goto err_unmap;
3735*4882a593Smuzhiyun 		}
3736*4882a593Smuzhiyun 
3737*4882a593Smuzhiyun 		if (mailbox == ZE_V1) {
3738*4882a593Smuzhiyun 			card_name = "Cyclades-Ze";
3739*4882a593Smuzhiyun 		} else {
3740*4882a593Smuzhiyun 			card_name = "Cyclades-8Zo";
3741*4882a593Smuzhiyun #ifdef CY_PCI_DEBUG
3742*4882a593Smuzhiyun 			if (mailbox == ZO_V1) {
3743*4882a593Smuzhiyun 				cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3744*4882a593Smuzhiyun 				dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
3745*4882a593Smuzhiyun 					"id %lx, ver %lx\n", (ulong)(0xff &
3746*4882a593Smuzhiyun 					readl(&((struct CUSTOM_REG *)addr2)->
3747*4882a593Smuzhiyun 						fpga_id)), (ulong)(0xff &
3748*4882a593Smuzhiyun 					readl(&((struct CUSTOM_REG *)addr2)->
3749*4882a593Smuzhiyun 						fpga_version)));
3750*4882a593Smuzhiyun 				cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3751*4882a593Smuzhiyun 			} else {
3752*4882a593Smuzhiyun 				dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
3753*4882a593Smuzhiyun 					"Cyclades-Z board.  FPGA not loaded\n");
3754*4882a593Smuzhiyun 			}
3755*4882a593Smuzhiyun #endif
3756*4882a593Smuzhiyun 			/* The following clears the firmware id word.  This
3757*4882a593Smuzhiyun 			   ensures that the driver will not attempt to talk to
3758*4882a593Smuzhiyun 			   the board until it has been properly initialized.
3759*4882a593Smuzhiyun 			 */
3760*4882a593Smuzhiyun 			if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
3761*4882a593Smuzhiyun 				cy_writel(addr2 + ID_ADDRESS, 0L);
3762*4882a593Smuzhiyun 		}
3763*4882a593Smuzhiyun 
3764*4882a593Smuzhiyun 		retval = cyz_load_fw(pdev, addr2, addr0, irq);
3765*4882a593Smuzhiyun 		if (retval <= 0)
3766*4882a593Smuzhiyun 			goto err_unmap;
3767*4882a593Smuzhiyun 		nchan = retval;
3768*4882a593Smuzhiyun 	}
3769*4882a593Smuzhiyun 
3770*4882a593Smuzhiyun 	if ((cy_next_channel + nchan) > NR_PORTS) {
3771*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
3772*4882a593Smuzhiyun 			"channels are available. Change NR_PORTS in "
3773*4882a593Smuzhiyun 			"cyclades.c and recompile kernel.\n");
3774*4882a593Smuzhiyun 		goto err_unmap;
3775*4882a593Smuzhiyun 	}
3776*4882a593Smuzhiyun 	/* fill the next cy_card structure available */
3777*4882a593Smuzhiyun 	for (card_no = 0; card_no < NR_CARDS; card_no++) {
3778*4882a593Smuzhiyun 		card = &cy_card[card_no];
3779*4882a593Smuzhiyun 		if (card->base_addr == NULL)
3780*4882a593Smuzhiyun 			break;
3781*4882a593Smuzhiyun 	}
3782*4882a593Smuzhiyun 	if (card_no == NR_CARDS) {	/* no more cy_cards available */
3783*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
3784*4882a593Smuzhiyun 			"more cards can be used. Change NR_CARDS in "
3785*4882a593Smuzhiyun 			"cyclades.c and recompile kernel.\n");
3786*4882a593Smuzhiyun 		goto err_unmap;
3787*4882a593Smuzhiyun 	}
3788*4882a593Smuzhiyun 
3789*4882a593Smuzhiyun 	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3790*4882a593Smuzhiyun 			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
3791*4882a593Smuzhiyun 		/* allocate IRQ */
3792*4882a593Smuzhiyun 		retval = request_irq(irq, cyy_interrupt,
3793*4882a593Smuzhiyun 				IRQF_SHARED, "Cyclom-Y", card);
3794*4882a593Smuzhiyun 		if (retval) {
3795*4882a593Smuzhiyun 			dev_err(&pdev->dev, "could not allocate IRQ\n");
3796*4882a593Smuzhiyun 			goto err_unmap;
3797*4882a593Smuzhiyun 		}
3798*4882a593Smuzhiyun 		card->num_chips = nchan / CyPORTS_PER_CHIP;
3799*4882a593Smuzhiyun 	} else {
3800*4882a593Smuzhiyun 		struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
3801*4882a593Smuzhiyun 		struct ZFW_CTRL __iomem *zfw_ctrl;
3802*4882a593Smuzhiyun 
3803*4882a593Smuzhiyun 		zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3804*4882a593Smuzhiyun 
3805*4882a593Smuzhiyun 		card->hw_ver = mailbox;
3806*4882a593Smuzhiyun 		card->num_chips = (unsigned int)-1;
3807*4882a593Smuzhiyun 		card->board_ctrl = &zfw_ctrl->board_ctrl;
3808*4882a593Smuzhiyun #ifdef CONFIG_CYZ_INTR
3809*4882a593Smuzhiyun 		/* allocate IRQ only if board has an IRQ */
3810*4882a593Smuzhiyun 		if (irq != 0 && irq != 255) {
3811*4882a593Smuzhiyun 			retval = request_irq(irq, cyz_interrupt,
3812*4882a593Smuzhiyun 					IRQF_SHARED, "Cyclades-Z", card);
3813*4882a593Smuzhiyun 			if (retval) {
3814*4882a593Smuzhiyun 				dev_err(&pdev->dev, "could not allocate IRQ\n");
3815*4882a593Smuzhiyun 				goto err_unmap;
3816*4882a593Smuzhiyun 			}
3817*4882a593Smuzhiyun 		}
3818*4882a593Smuzhiyun #endif				/* CONFIG_CYZ_INTR */
3819*4882a593Smuzhiyun 	}
3820*4882a593Smuzhiyun 
3821*4882a593Smuzhiyun 	/* set cy_card */
3822*4882a593Smuzhiyun 	card->base_addr = addr2;
3823*4882a593Smuzhiyun 	card->ctl_addr.p9050 = addr0;
3824*4882a593Smuzhiyun 	card->irq = irq;
3825*4882a593Smuzhiyun 	card->bus_index = 1;
3826*4882a593Smuzhiyun 	card->first_line = cy_next_channel;
3827*4882a593Smuzhiyun 	card->nports = nchan;
3828*4882a593Smuzhiyun 	retval = cy_init_card(card);
3829*4882a593Smuzhiyun 	if (retval)
3830*4882a593Smuzhiyun 		goto err_null;
3831*4882a593Smuzhiyun 
3832*4882a593Smuzhiyun 	pci_set_drvdata(pdev, card);
3833*4882a593Smuzhiyun 
3834*4882a593Smuzhiyun 	if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3835*4882a593Smuzhiyun 			device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
3836*4882a593Smuzhiyun 		/* enable interrupts in the PCI interface */
3837*4882a593Smuzhiyun 		plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
3838*4882a593Smuzhiyun 		switch (plx_ver) {
3839*4882a593Smuzhiyun 		case PLX_9050:
3840*4882a593Smuzhiyun 			cy_writeb(addr0 + 0x4c, 0x43);
3841*4882a593Smuzhiyun 			break;
3842*4882a593Smuzhiyun 
3843*4882a593Smuzhiyun 		case PLX_9060:
3844*4882a593Smuzhiyun 		case PLX_9080:
3845*4882a593Smuzhiyun 		default:	/* Old boards, use PLX_9060 */
3846*4882a593Smuzhiyun 		{
3847*4882a593Smuzhiyun 			struct RUNTIME_9060 __iomem *ctl_addr = addr0;
3848*4882a593Smuzhiyun 			plx_init(pdev, irq, ctl_addr);
3849*4882a593Smuzhiyun 			cy_writew(&ctl_addr->intr_ctrl_stat,
3850*4882a593Smuzhiyun 				readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
3851*4882a593Smuzhiyun 			break;
3852*4882a593Smuzhiyun 		}
3853*4882a593Smuzhiyun 		}
3854*4882a593Smuzhiyun 	}
3855*4882a593Smuzhiyun 
3856*4882a593Smuzhiyun 	dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
3857*4882a593Smuzhiyun 		"port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
3858*4882a593Smuzhiyun 	for (j = 0, i = cy_next_channel; i < cy_next_channel + nchan; i++, j++)
3859*4882a593Smuzhiyun 		tty_port_register_device(&card->ports[j].port,
3860*4882a593Smuzhiyun 				cy_serial_driver, i, &pdev->dev);
3861*4882a593Smuzhiyun 	cy_next_channel += nchan;
3862*4882a593Smuzhiyun 
3863*4882a593Smuzhiyun 	return 0;
3864*4882a593Smuzhiyun err_null:
3865*4882a593Smuzhiyun 	card->base_addr = NULL;
3866*4882a593Smuzhiyun 	free_irq(irq, card);
3867*4882a593Smuzhiyun err_unmap:
3868*4882a593Smuzhiyun 	iounmap(addr0);
3869*4882a593Smuzhiyun 	if (addr2)
3870*4882a593Smuzhiyun 		iounmap(addr2);
3871*4882a593Smuzhiyun err_reg:
3872*4882a593Smuzhiyun 	pci_release_regions(pdev);
3873*4882a593Smuzhiyun err_dis:
3874*4882a593Smuzhiyun 	pci_disable_device(pdev);
3875*4882a593Smuzhiyun err:
3876*4882a593Smuzhiyun 	return retval;
3877*4882a593Smuzhiyun }
3878*4882a593Smuzhiyun 
cy_pci_remove(struct pci_dev * pdev)3879*4882a593Smuzhiyun static void cy_pci_remove(struct pci_dev *pdev)
3880*4882a593Smuzhiyun {
3881*4882a593Smuzhiyun 	struct cyclades_card *cinfo = pci_get_drvdata(pdev);
3882*4882a593Smuzhiyun 	unsigned int i, channel;
3883*4882a593Smuzhiyun 
3884*4882a593Smuzhiyun 	/* non-Z with old PLX */
3885*4882a593Smuzhiyun 	if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
3886*4882a593Smuzhiyun 			PLX_9050)
3887*4882a593Smuzhiyun 		cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
3888*4882a593Smuzhiyun 	else
3889*4882a593Smuzhiyun #ifndef CONFIG_CYZ_INTR
3890*4882a593Smuzhiyun 		if (!cy_is_Z(cinfo))
3891*4882a593Smuzhiyun #endif
3892*4882a593Smuzhiyun 		cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
3893*4882a593Smuzhiyun 			readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
3894*4882a593Smuzhiyun 			~0x0900);
3895*4882a593Smuzhiyun 
3896*4882a593Smuzhiyun 	iounmap(cinfo->base_addr);
3897*4882a593Smuzhiyun 	if (cinfo->ctl_addr.p9050)
3898*4882a593Smuzhiyun 		iounmap(cinfo->ctl_addr.p9050);
3899*4882a593Smuzhiyun 	if (cinfo->irq
3900*4882a593Smuzhiyun #ifndef CONFIG_CYZ_INTR
3901*4882a593Smuzhiyun 		&& !cy_is_Z(cinfo)
3902*4882a593Smuzhiyun #endif /* CONFIG_CYZ_INTR */
3903*4882a593Smuzhiyun 		)
3904*4882a593Smuzhiyun 		free_irq(cinfo->irq, cinfo);
3905*4882a593Smuzhiyun 	pci_release_regions(pdev);
3906*4882a593Smuzhiyun 
3907*4882a593Smuzhiyun 	cinfo->base_addr = NULL;
3908*4882a593Smuzhiyun 	for (channel = 0, i = cinfo->first_line; i < cinfo->first_line +
3909*4882a593Smuzhiyun 			cinfo->nports; i++, channel++) {
3910*4882a593Smuzhiyun 		tty_unregister_device(cy_serial_driver, i);
3911*4882a593Smuzhiyun 		tty_port_destroy(&cinfo->ports[channel].port);
3912*4882a593Smuzhiyun 	}
3913*4882a593Smuzhiyun 	cinfo->nports = 0;
3914*4882a593Smuzhiyun 	kfree(cinfo->ports);
3915*4882a593Smuzhiyun }
3916*4882a593Smuzhiyun 
3917*4882a593Smuzhiyun static struct pci_driver cy_pci_driver = {
3918*4882a593Smuzhiyun 	.name = "cyclades",
3919*4882a593Smuzhiyun 	.id_table = cy_pci_dev_id,
3920*4882a593Smuzhiyun 	.probe = cy_pci_probe,
3921*4882a593Smuzhiyun 	.remove = cy_pci_remove
3922*4882a593Smuzhiyun };
3923*4882a593Smuzhiyun #endif
3924*4882a593Smuzhiyun 
cyclades_proc_show(struct seq_file * m,void * v)3925*4882a593Smuzhiyun static int cyclades_proc_show(struct seq_file *m, void *v)
3926*4882a593Smuzhiyun {
3927*4882a593Smuzhiyun 	struct cyclades_port *info;
3928*4882a593Smuzhiyun 	unsigned int i, j;
3929*4882a593Smuzhiyun 	__u32 cur_jifs = jiffies;
3930*4882a593Smuzhiyun 
3931*4882a593Smuzhiyun 	seq_puts(m, "Dev TimeOpen   BytesOut  IdleOut    BytesIn   "
3932*4882a593Smuzhiyun 			"IdleIn  Overruns  Ldisc\n");
3933*4882a593Smuzhiyun 
3934*4882a593Smuzhiyun 	/* Output one line for each known port */
3935*4882a593Smuzhiyun 	for (i = 0; i < NR_CARDS; i++)
3936*4882a593Smuzhiyun 		for (j = 0; j < cy_card[i].nports; j++) {
3937*4882a593Smuzhiyun 			info = &cy_card[i].ports[j];
3938*4882a593Smuzhiyun 
3939*4882a593Smuzhiyun 			if (info->port.count) {
3940*4882a593Smuzhiyun 				/* XXX is the ldisc num worth this? */
3941*4882a593Smuzhiyun 				struct tty_struct *tty;
3942*4882a593Smuzhiyun 				struct tty_ldisc *ld;
3943*4882a593Smuzhiyun 				int num = 0;
3944*4882a593Smuzhiyun 				tty = tty_port_tty_get(&info->port);
3945*4882a593Smuzhiyun 				if (tty) {
3946*4882a593Smuzhiyun 					ld = tty_ldisc_ref(tty);
3947*4882a593Smuzhiyun 					if (ld) {
3948*4882a593Smuzhiyun 						num = ld->ops->num;
3949*4882a593Smuzhiyun 						tty_ldisc_deref(ld);
3950*4882a593Smuzhiyun 					}
3951*4882a593Smuzhiyun 					tty_kref_put(tty);
3952*4882a593Smuzhiyun 				}
3953*4882a593Smuzhiyun 				seq_printf(m, "%3d %8lu %10lu %8lu "
3954*4882a593Smuzhiyun 					"%10lu %8lu %9lu %6d\n", info->line,
3955*4882a593Smuzhiyun 					(cur_jifs - info->idle_stats.in_use) /
3956*4882a593Smuzhiyun 					HZ, info->idle_stats.xmit_bytes,
3957*4882a593Smuzhiyun 					(cur_jifs - info->idle_stats.xmit_idle)/
3958*4882a593Smuzhiyun 					HZ, info->idle_stats.recv_bytes,
3959*4882a593Smuzhiyun 					(cur_jifs - info->idle_stats.recv_idle)/
3960*4882a593Smuzhiyun 					HZ, info->idle_stats.overruns,
3961*4882a593Smuzhiyun 					num);
3962*4882a593Smuzhiyun 			} else
3963*4882a593Smuzhiyun 				seq_printf(m, "%3d %8lu %10lu %8lu "
3964*4882a593Smuzhiyun 					"%10lu %8lu %9lu %6ld\n",
3965*4882a593Smuzhiyun 					info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
3966*4882a593Smuzhiyun 		}
3967*4882a593Smuzhiyun 	return 0;
3968*4882a593Smuzhiyun }
3969*4882a593Smuzhiyun 
3970*4882a593Smuzhiyun /* The serial driver boot-time initialization code!
3971*4882a593Smuzhiyun     Hardware I/O ports are mapped to character special devices on a
3972*4882a593Smuzhiyun     first found, first allocated manner.  That is, this code searches
3973*4882a593Smuzhiyun     for Cyclom cards in the system.  As each is found, it is probed
3974*4882a593Smuzhiyun     to discover how many chips (and thus how many ports) are present.
3975*4882a593Smuzhiyun     These ports are mapped to the tty ports 32 and upward in monotonic
3976*4882a593Smuzhiyun     fashion.  If an 8-port card is replaced with a 16-port card, the
3977*4882a593Smuzhiyun     port mapping on a following card will shift.
3978*4882a593Smuzhiyun 
3979*4882a593Smuzhiyun     This approach is different from what is used in the other serial
3980*4882a593Smuzhiyun     device driver because the Cyclom is more properly a multiplexer,
3981*4882a593Smuzhiyun     not just an aggregation of serial ports on one card.
3982*4882a593Smuzhiyun 
3983*4882a593Smuzhiyun     If there are more cards with more ports than have been
3984*4882a593Smuzhiyun     statically allocated above, a warning is printed and the
3985*4882a593Smuzhiyun     extra ports are ignored.
3986*4882a593Smuzhiyun  */
3987*4882a593Smuzhiyun 
3988*4882a593Smuzhiyun static const struct tty_operations cy_ops = {
3989*4882a593Smuzhiyun 	.open = cy_open,
3990*4882a593Smuzhiyun 	.close = cy_close,
3991*4882a593Smuzhiyun 	.write = cy_write,
3992*4882a593Smuzhiyun 	.put_char = cy_put_char,
3993*4882a593Smuzhiyun 	.flush_chars = cy_flush_chars,
3994*4882a593Smuzhiyun 	.write_room = cy_write_room,
3995*4882a593Smuzhiyun 	.chars_in_buffer = cy_chars_in_buffer,
3996*4882a593Smuzhiyun 	.flush_buffer = cy_flush_buffer,
3997*4882a593Smuzhiyun 	.ioctl = cy_ioctl,
3998*4882a593Smuzhiyun 	.throttle = cy_throttle,
3999*4882a593Smuzhiyun 	.unthrottle = cy_unthrottle,
4000*4882a593Smuzhiyun 	.set_termios = cy_set_termios,
4001*4882a593Smuzhiyun 	.stop = cy_stop,
4002*4882a593Smuzhiyun 	.start = cy_start,
4003*4882a593Smuzhiyun 	.hangup = cy_hangup,
4004*4882a593Smuzhiyun 	.break_ctl = cy_break,
4005*4882a593Smuzhiyun 	.wait_until_sent = cy_wait_until_sent,
4006*4882a593Smuzhiyun 	.tiocmget = cy_tiocmget,
4007*4882a593Smuzhiyun 	.tiocmset = cy_tiocmset,
4008*4882a593Smuzhiyun 	.get_icount = cy_get_icount,
4009*4882a593Smuzhiyun 	.set_serial = cy_set_serial_info,
4010*4882a593Smuzhiyun 	.get_serial = cy_get_serial_info,
4011*4882a593Smuzhiyun 	.proc_show = cyclades_proc_show,
4012*4882a593Smuzhiyun };
4013*4882a593Smuzhiyun 
cy_init(void)4014*4882a593Smuzhiyun static int __init cy_init(void)
4015*4882a593Smuzhiyun {
4016*4882a593Smuzhiyun 	unsigned int nboards;
4017*4882a593Smuzhiyun 	int retval = -ENOMEM;
4018*4882a593Smuzhiyun 
4019*4882a593Smuzhiyun 	cy_serial_driver = alloc_tty_driver(NR_PORTS);
4020*4882a593Smuzhiyun 	if (!cy_serial_driver)
4021*4882a593Smuzhiyun 		goto err;
4022*4882a593Smuzhiyun 
4023*4882a593Smuzhiyun 	printk(KERN_INFO "Cyclades driver " CY_VERSION "\n");
4024*4882a593Smuzhiyun 
4025*4882a593Smuzhiyun 	/* Initialize the tty_driver structure */
4026*4882a593Smuzhiyun 
4027*4882a593Smuzhiyun 	cy_serial_driver->driver_name = "cyclades";
4028*4882a593Smuzhiyun 	cy_serial_driver->name = "ttyC";
4029*4882a593Smuzhiyun 	cy_serial_driver->major = CYCLADES_MAJOR;
4030*4882a593Smuzhiyun 	cy_serial_driver->minor_start = 0;
4031*4882a593Smuzhiyun 	cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
4032*4882a593Smuzhiyun 	cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
4033*4882a593Smuzhiyun 	cy_serial_driver->init_termios = tty_std_termios;
4034*4882a593Smuzhiyun 	cy_serial_driver->init_termios.c_cflag =
4035*4882a593Smuzhiyun 	    B9600 | CS8 | CREAD | HUPCL | CLOCAL;
4036*4882a593Smuzhiyun 	cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
4037*4882a593Smuzhiyun 	tty_set_operations(cy_serial_driver, &cy_ops);
4038*4882a593Smuzhiyun 
4039*4882a593Smuzhiyun 	retval = tty_register_driver(cy_serial_driver);
4040*4882a593Smuzhiyun 	if (retval) {
4041*4882a593Smuzhiyun 		printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
4042*4882a593Smuzhiyun 		goto err_frtty;
4043*4882a593Smuzhiyun 	}
4044*4882a593Smuzhiyun 
4045*4882a593Smuzhiyun 	/* the code below is responsible to find the boards. Each different
4046*4882a593Smuzhiyun 	   type of board has its own detection routine. If a board is found,
4047*4882a593Smuzhiyun 	   the next cy_card structure available is set by the detection
4048*4882a593Smuzhiyun 	   routine. These functions are responsible for checking the
4049*4882a593Smuzhiyun 	   availability of cy_card and cy_port data structures and updating
4050*4882a593Smuzhiyun 	   the cy_next_channel. */
4051*4882a593Smuzhiyun 
4052*4882a593Smuzhiyun 	/* look for isa boards */
4053*4882a593Smuzhiyun 	nboards = cy_detect_isa();
4054*4882a593Smuzhiyun 
4055*4882a593Smuzhiyun #ifdef CONFIG_PCI
4056*4882a593Smuzhiyun 	/* look for pci boards */
4057*4882a593Smuzhiyun 	retval = pci_register_driver(&cy_pci_driver);
4058*4882a593Smuzhiyun 	if (retval && !nboards) {
4059*4882a593Smuzhiyun 		tty_unregister_driver(cy_serial_driver);
4060*4882a593Smuzhiyun 		goto err_frtty;
4061*4882a593Smuzhiyun 	}
4062*4882a593Smuzhiyun #endif
4063*4882a593Smuzhiyun 
4064*4882a593Smuzhiyun 	return 0;
4065*4882a593Smuzhiyun err_frtty:
4066*4882a593Smuzhiyun 	put_tty_driver(cy_serial_driver);
4067*4882a593Smuzhiyun err:
4068*4882a593Smuzhiyun 	return retval;
4069*4882a593Smuzhiyun }				/* cy_init */
4070*4882a593Smuzhiyun 
cy_cleanup_module(void)4071*4882a593Smuzhiyun static void __exit cy_cleanup_module(void)
4072*4882a593Smuzhiyun {
4073*4882a593Smuzhiyun 	struct cyclades_card *card;
4074*4882a593Smuzhiyun 	unsigned int i, e1;
4075*4882a593Smuzhiyun 
4076*4882a593Smuzhiyun #ifndef CONFIG_CYZ_INTR
4077*4882a593Smuzhiyun 	del_timer_sync(&cyz_timerlist);
4078*4882a593Smuzhiyun #endif /* CONFIG_CYZ_INTR */
4079*4882a593Smuzhiyun 
4080*4882a593Smuzhiyun 	e1 = tty_unregister_driver(cy_serial_driver);
4081*4882a593Smuzhiyun 	if (e1)
4082*4882a593Smuzhiyun 		printk(KERN_ERR "failed to unregister Cyclades serial "
4083*4882a593Smuzhiyun 				"driver(%d)\n", e1);
4084*4882a593Smuzhiyun 
4085*4882a593Smuzhiyun #ifdef CONFIG_PCI
4086*4882a593Smuzhiyun 	pci_unregister_driver(&cy_pci_driver);
4087*4882a593Smuzhiyun #endif
4088*4882a593Smuzhiyun 
4089*4882a593Smuzhiyun 	for (i = 0; i < NR_CARDS; i++) {
4090*4882a593Smuzhiyun 		card = &cy_card[i];
4091*4882a593Smuzhiyun 		if (card->base_addr) {
4092*4882a593Smuzhiyun 			/* clear interrupt */
4093*4882a593Smuzhiyun 			cy_writeb(card->base_addr + Cy_ClrIntr, 0);
4094*4882a593Smuzhiyun 			iounmap(card->base_addr);
4095*4882a593Smuzhiyun 			if (card->ctl_addr.p9050)
4096*4882a593Smuzhiyun 				iounmap(card->ctl_addr.p9050);
4097*4882a593Smuzhiyun 			if (card->irq
4098*4882a593Smuzhiyun #ifndef CONFIG_CYZ_INTR
4099*4882a593Smuzhiyun 				&& !cy_is_Z(card)
4100*4882a593Smuzhiyun #endif /* CONFIG_CYZ_INTR */
4101*4882a593Smuzhiyun 				)
4102*4882a593Smuzhiyun 				free_irq(card->irq, card);
4103*4882a593Smuzhiyun 			for (e1 = card->first_line; e1 < card->first_line +
4104*4882a593Smuzhiyun 					card->nports; e1++)
4105*4882a593Smuzhiyun 				tty_unregister_device(cy_serial_driver, e1);
4106*4882a593Smuzhiyun 			kfree(card->ports);
4107*4882a593Smuzhiyun 		}
4108*4882a593Smuzhiyun 	}
4109*4882a593Smuzhiyun 
4110*4882a593Smuzhiyun 	put_tty_driver(cy_serial_driver);
4111*4882a593Smuzhiyun } /* cy_cleanup_module */
4112*4882a593Smuzhiyun 
4113*4882a593Smuzhiyun module_init(cy_init);
4114*4882a593Smuzhiyun module_exit(cy_cleanup_module);
4115*4882a593Smuzhiyun 
4116*4882a593Smuzhiyun MODULE_LICENSE("GPL");
4117*4882a593Smuzhiyun MODULE_VERSION(CY_VERSION);
4118*4882a593Smuzhiyun MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);
4119*4882a593Smuzhiyun MODULE_FIRMWARE("cyzfirm.bin");
4120