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, ¶m) == 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