blob: d272bc4e7fb5699aafabea9483cf6252d7d4fd40 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#undef BLOCKMOVE
2#define Z_WAKE
3#undef Z_EXT_CHARS_IN_BUFFER
Linus Torvalds1da177e2005-04-16 15:20:36 -07004
5/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * This file contains the driver for the Cyclades async multiport
7 * serial boards.
8 *
9 * Initially written by Randolph Bentson <bentson@grieg.seaslug.org>.
10 * Modified and maintained by Marcio Saito <marcio@cyclades.com>.
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 *
Jiri Slabyebdb5132009-09-19 13:13:14 -070012 * Copyright (C) 2007-2009 Jiri Slaby <jirislaby@gmail.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
14 * Much of the design and some of the code came from serial.c
15 * which was copyright (C) 1991, 1992 Linus Torvalds. It was
16 * extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
17 * and then fixed as suggested by Michael K. Johnson 12/12/92.
Jiri Slabyc8e16932007-05-08 00:37:05 -070018 * Converted to pci probing and cleaned up by Jiri Slaby.
Linus Torvalds1da177e2005-04-16 15:20:36 -070019 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 */
21
Jiri Slabyebdb5132009-09-19 13:13:14 -070022#define CY_VERSION "2.6"
Jiri Slaby096dcfc2006-12-08 02:39:30 -080023
Linus Torvalds1da177e2005-04-16 15:20:36 -070024/* If you need to install more boards than NR_CARDS, change the constant
25 in the definition below. No other change is necessary to support up to
26 eight boards. Beyond that you'll have to extend cy_isa_addresses. */
27
Jiri Slaby02f11752006-12-08 02:39:28 -080028#define NR_CARDS 4
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30/*
31 If the total number of ports is larger than NR_PORTS, change this
32 constant in the definition below. No other change is necessary to
33 support more boards/ports. */
34
Jiri Slaby02f11752006-12-08 02:39:28 -080035#define NR_PORTS 256
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#define ZO_V1 0
38#define ZO_V2 1
39#define ZE_V1 2
40
41#define SERIAL_PARANOIA_CHECK
42#undef CY_DEBUG_OPEN
43#undef CY_DEBUG_THROTTLE
44#undef CY_DEBUG_OTHER
45#undef CY_DEBUG_IO
46#undef CY_DEBUG_COUNT
47#undef CY_DEBUG_DTR
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#undef CY_DEBUG_INTERRUPTS
49#undef CY_16Y_HACK
50#undef CY_ENABLE_MONITORING
51#undef CY_PCI_DEBUG
52
Linus Torvalds1da177e2005-04-16 15:20:36 -070053/*
Alan Cox15ed6cc2008-04-30 00:53:55 -070054 * Include section
Linus Torvalds1da177e2005-04-16 15:20:36 -070055 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#include <linux/module.h>
57#include <linux/errno.h>
58#include <linux/signal.h>
59#include <linux/sched.h>
60#include <linux/timer.h>
61#include <linux/interrupt.h>
62#include <linux/tty.h>
Alan Cox33f0f882006-01-09 20:54:13 -080063#include <linux/tty_flip.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#include <linux/serial.h>
65#include <linux/major.h>
66#include <linux/string.h>
67#include <linux/fcntl.h>
68#include <linux/ptrace.h>
69#include <linux/cyclades.h>
70#include <linux/mm.h>
71#include <linux/ioport.h>
72#include <linux/init.h>
73#include <linux/delay.h>
74#include <linux/spinlock.h>
75#include <linux/bitops.h>
Jiri Slaby054f5b02007-07-17 04:05:16 -070076#include <linux/firmware.h>
Scott James Remnant9f56fad72009-04-06 17:33:04 +010077#include <linux/device.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090078#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Alan Cox15ed6cc2008-04-30 00:53:55 -070080#include <linux/io.h>
Alan Cox15ed6cc2008-04-30 00:53:55 -070081#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
Linus Torvalds1da177e2005-04-16 15:20:36 -070083#include <linux/kernel.h>
84#include <linux/pci.h>
85
86#include <linux/stat.h>
87#include <linux/proc_fs.h>
Alexey Dobriyan444697d2009-03-31 15:19:15 -070088#include <linux/seq_file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
Jiri Slaby02f11752006-12-08 02:39:28 -080090static void cy_send_xchar(struct tty_struct *tty, char ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
Linus Torvalds1da177e2005-04-16 15:20:36 -070092#ifndef SERIAL_XMIT_SIZE
93#define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096))
94#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
Jiri Slaby054f5b02007-07-17 04:05:16 -070096/* firmware stuff */
97#define ZL_MAX_BLOCKS 16
98#define DRIVER_VERSION 0x02010203
99#define RAM_SIZE 0x80000
100
Jiri Slaby054f5b02007-07-17 04:05:16 -0700101enum zblock_type {
102 ZBLOCK_PRG = 0,
103 ZBLOCK_FPGA = 1
104};
105
106struct zfile_header {
107 char name[64];
108 char date[32];
109 char aux[32];
110 u32 n_config;
111 u32 config_offset;
112 u32 n_blocks;
113 u32 block_offset;
114 u32 reserved[9];
115} __attribute__ ((packed));
116
117struct zfile_config {
118 char name[64];
119 u32 mailbox;
120 u32 function;
121 u32 n_blocks;
122 u32 block_list[ZL_MAX_BLOCKS];
123} __attribute__ ((packed));
124
125struct zfile_block {
126 u32 type;
127 u32 file_offset;
128 u32 ram_offset;
129 u32 size;
130} __attribute__ ((packed));
131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132static struct tty_driver *cy_serial_driver;
133
134#ifdef CONFIG_ISA
135/* This is the address lookup table. The driver will probe for
136 Cyclom-Y/ISA boards at all addresses in here. If you want the
137 driver to probe addresses at a different address, add it to
138 this table. If the driver is probing some other board and
139 causing problems, remove the offending address from this table.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140*/
141
142static unsigned int cy_isa_addresses[] = {
Jiri Slaby02f11752006-12-08 02:39:28 -0800143 0xD0000,
144 0xD2000,
145 0xD4000,
146 0xD6000,
147 0xD8000,
148 0xDA000,
149 0xDC000,
150 0xDE000,
151 0, 0, 0, 0, 0, 0, 0, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152};
Jiri Slaby02f11752006-12-08 02:39:28 -0800153
Tobias Klauserfe971072006-01-09 20:54:02 -0800154#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
Jiri Slaby3046d502007-05-08 00:36:46 -0700156static long maddr[NR_CARDS];
157static int irq[NR_CARDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
David Howells3b60daf82017-04-04 16:54:29 +0100159module_param_hw_array(maddr, long, iomem, NULL, 0);
160module_param_hw_array(irq, int, irq, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
Jiri Slaby02f11752006-12-08 02:39:28 -0800162#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164/* This is the per-card data structure containing address, irq, number of
165 channels, etc. This driver supports a maximum of NR_CARDS cards.
166*/
167static struct cyclades_card cy_card[NR_CARDS];
168
Jiri Slaby02f11752006-12-08 02:39:28 -0800169static int cy_next_channel; /* next minor available */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
171/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 * This is used to look up the divisor speeds and the timeouts
173 * We're normally limited to 15 distinct baud rates. The extra
Alan Cox77451e52008-07-16 21:57:02 +0100174 * are accessed via settings in info->port.flags.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
176 * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
177 * HI VHI
178 * 20
179 */
Jiri Slabyebdb5132009-09-19 13:13:14 -0700180static const int baud_table[] = {
Jiri Slaby02f11752006-12-08 02:39:28 -0800181 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
182 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
183 230400, 0
184};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
Jiri Slabyebdb5132009-09-19 13:13:14 -0700186static const char baud_co_25[] = { /* 25 MHz clock option table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800187 /* value => 00 01 02 03 04 */
188 /* divide by 8 32 128 512 2048 */
189 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
190 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
191};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
Jiri Slabyebdb5132009-09-19 13:13:14 -0700193static const char baud_bpr_25[] = { /* 25 MHz baud rate period table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800194 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
195 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
196};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
Jiri Slabyebdb5132009-09-19 13:13:14 -0700198static const char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */
Jiri Slaby02f11752006-12-08 02:39:28 -0800199 /* value => 00 01 02 03 04 */
200 /* divide by 8 32 128 512 2048 */
201 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
202 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
203 0x00
204};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Jiri Slabyebdb5132009-09-19 13:13:14 -0700206static const char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */
Jiri Slaby02f11752006-12-08 02:39:28 -0800207 0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
208 0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
209 0x21
210};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
Jiri Slabyebdb5132009-09-19 13:13:14 -0700212static const char baud_cor3[] = { /* receive threshold */
Jiri Slaby02f11752006-12-08 02:39:28 -0800213 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
214 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07,
215 0x07
216};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
218/*
219 * The Cyclades driver implements HW flow control as any serial driver.
Alan Cox15ed6cc2008-04-30 00:53:55 -0700220 * The cyclades_port structure member rflow and the vector rflow_thr
221 * allows us to take advantage of a special feature in the CD1400 to avoid
222 * data loss even when the system interrupt latency is too high. These flags
223 * are to be used only with very special applications. Setting these flags
224 * requires the use of a special cable (DTR and RTS reversed). In the new
225 * CD1400-based boards (rev. 6.00 or later), there is no need for special
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 * cables.
227 */
228
Jiri Slabyebdb5132009-09-19 13:13:14 -0700229static const char rflow_thr[] = { /* rflow threshold */
Jiri Slaby02f11752006-12-08 02:39:28 -0800230 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
232 0x0a
233};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
235/* The Cyclom-Ye has placed the sequential chips in non-sequential
236 * address order. This look-up table overcomes that problem.
237 */
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700238static const unsigned int cy_chip_offset[] = { 0x0000,
Jiri Slaby02f11752006-12-08 02:39:28 -0800239 0x0400,
240 0x0800,
241 0x0C00,
242 0x0200,
243 0x0600,
244 0x0A00,
245 0x0E00
246};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
248/* PCI related definitions */
249
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250#ifdef CONFIG_PCI
Jiri Slabyebdb5132009-09-19 13:13:14 -0700251static const struct pci_device_id cy_pci_dev_id[] = {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700252 /* PCI < 1Mb */
253 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) },
254 /* PCI > 1Mb */
255 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) },
256 /* 4Y PCI < 1Mb */
257 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) },
258 /* 4Y PCI > 1Mb */
259 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) },
260 /* 8Y PCI < 1Mb */
261 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) },
262 /* 8Y PCI > 1Mb */
263 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) },
264 /* Z PCI < 1Mb */
265 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) },
266 /* Z PCI > 1Mb */
267 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) },
Jiri Slaby893de2d2007-02-12 00:51:49 -0800268 { } /* end of table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800269};
Jiri Slaby893de2d2007-02-12 00:51:49 -0800270MODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271#endif
272
273static void cy_start(struct tty_struct *);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700274static void cy_set_line_char(struct cyclades_port *, struct tty_struct *);
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700275static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276#ifdef CONFIG_ISA
277static unsigned detect_isa_irq(void __iomem *);
Jiri Slaby02f11752006-12-08 02:39:28 -0800278#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280#ifndef CONFIG_CYZ_INTR
281static void cyz_poll(unsigned long);
282
283/* The Cyclades-Z polling cycle is defined by this variable */
284static long cyz_polling_cycle = CZ_DEF_POLL;
285
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700286static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Jiri Slaby02f11752006-12-08 02:39:28 -0800288#else /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289static void cyz_rx_restart(unsigned long);
290static struct timer_list cyz_rx_full_timer[NR_PORTS];
Jiri Slaby02f11752006-12-08 02:39:28 -0800291#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Denys Vlasenkof25d5962015-10-27 17:39:56 +0100293static void cyy_writeb(struct cyclades_port *port, u32 reg, u8 val)
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700294{
295 struct cyclades_card *card = port->card;
296
297 cy_writeb(port->u.cyy.base_addr + (reg << card->bus_index), val);
298}
299
Denys Vlasenkof88d8682015-10-27 17:39:55 +0100300static u8 cyy_readb(struct cyclades_port *port, u32 reg)
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700301{
302 struct cyclades_card *card = port->card;
303
304 return readb(port->u.cyy.base_addr + (reg << card->bus_index));
305}
306
Jiri Slaby2693f482009-06-11 12:31:06 +0100307static inline bool cy_is_Z(struct cyclades_card *card)
308{
309 return card->num_chips == (unsigned int)-1;
310}
311
312static inline bool __cyz_fpga_loaded(struct RUNTIME_9060 __iomem *ctl_addr)
313{
314 return readl(&ctl_addr->init_ctrl) & (1 << 17);
315}
316
317static inline bool cyz_fpga_loaded(struct cyclades_card *card)
318{
319 return __cyz_fpga_loaded(card->ctl_addr.p9060);
320}
321
Denys Vlasenko1c823632015-10-27 18:46:33 +0100322static bool cyz_is_loaded(struct cyclades_card *card)
Jiri Slaby2693f482009-06-11 12:31:06 +0100323{
324 struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS;
325
326 return (card->hw_ver == ZO_V1 || cyz_fpga_loaded(card)) &&
327 readl(&fw_id->signature) == ZFIRM_ID;
328}
329
Denys Vlasenko8c6ba002015-10-27 17:39:57 +0100330static int serial_paranoia_check(struct cyclades_port *info,
Jiri Slabyebdb5132009-09-19 13:13:14 -0700331 const char *name, const char *routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332{
333#ifdef SERIAL_PARANOIA_CHECK
Jiri Slaby02f11752006-12-08 02:39:28 -0800334 if (!info) {
Jiri Slaby21719192007-05-08 00:36:42 -0700335 printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) "
336 "in %s\n", name, routine);
Jiri Slaby02f11752006-12-08 02:39:28 -0800337 return 1;
338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
Jiri Slaby02f11752006-12-08 02:39:28 -0800340 if (info->magic != CYCLADES_MAGIC) {
Jiri Slaby21719192007-05-08 00:36:42 -0700341 printk(KERN_WARNING "cyc Warning: bad magic number for serial "
342 "struct (%s) in %s\n", name, routine);
Jiri Slaby02f11752006-12-08 02:39:28 -0800343 return 1;
344 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345#endif
Jiri Slaby02f11752006-12-08 02:39:28 -0800346 return 0;
Jiri Slabyebdb5132009-09-19 13:13:14 -0700347}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349/***********************************************************/
350/********* Start of block of Cyclom-Y specific code ********/
351
352/* This routine waits up to 1000 micro-seconds for the previous
353 command to the Cirrus chip to complete and then issues the
354 new command. An error is returned if the previous command
355 didn't finish within the time limit.
356
357 This function is only called from inside spinlock-protected code.
358 */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700359static int __cyy_issue_cmd(void __iomem *base_addr, u8 cmd, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700361 void __iomem *ccr = base_addr + (CyCCR << index);
Jiri Slabyad39c302007-05-08 00:35:49 -0700362 unsigned int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
Jiri Slaby02f11752006-12-08 02:39:28 -0800364 /* Check to see that the previous command has completed */
365 for (i = 0; i < 100; i++) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700366 if (readb(ccr) == 0)
Jiri Slaby02f11752006-12-08 02:39:28 -0800367 break;
Jiri Slaby02f11752006-12-08 02:39:28 -0800368 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 }
Jiri Slaby02f11752006-12-08 02:39:28 -0800370 /* if the CCR never cleared, the previous command
371 didn't finish within the "reasonable time" */
372 if (i == 100)
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800373 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
Jiri Slaby02f11752006-12-08 02:39:28 -0800375 /* Issue the new command */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700376 cy_writeb(ccr, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800378 return 0;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700379}
380
381static inline int cyy_issue_cmd(struct cyclades_port *port, u8 cmd)
382{
383 return __cyy_issue_cmd(port->u.cyy.base_addr, cmd,
384 port->card->bus_index);
385}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
387#ifdef CONFIG_ISA
388/* ISA interrupt detection code */
Alan Cox15ed6cc2008-04-30 00:53:55 -0700389static unsigned detect_isa_irq(void __iomem *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390{
Jiri Slaby02f11752006-12-08 02:39:28 -0800391 int irq;
392 unsigned long irqs, flags;
393 int save_xir, save_car;
394 int index = 0; /* IRQ probing is only for ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395
Jiri Slaby02f11752006-12-08 02:39:28 -0800396 /* forget possible initially masked and pending IRQ */
397 irq = probe_irq_off(probe_irq_on());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
Jiri Slaby02f11752006-12-08 02:39:28 -0800399 /* Clear interrupts on the board first */
400 cy_writeb(address + (Cy_ClrIntr << index), 0);
401 /* Cy_ClrIntr is 0x1800 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
Jiri Slaby02f11752006-12-08 02:39:28 -0800403 irqs = probe_irq_on();
404 /* Wait ... */
Jiri Slabyf6e208c2009-09-19 13:13:14 -0700405 msleep(5);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
Jiri Slaby02f11752006-12-08 02:39:28 -0800407 /* Enable the Tx interrupts on the CD1400 */
408 local_irq_save(flags);
409 cy_writeb(address + (CyCAR << index), 0);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700410 __cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411
Jiri Slaby02f11752006-12-08 02:39:28 -0800412 cy_writeb(address + (CyCAR << index), 0);
413 cy_writeb(address + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700414 readb(address + (CySRER << index)) | CyTxRdy);
Jiri Slaby02f11752006-12-08 02:39:28 -0800415 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
Jiri Slaby02f11752006-12-08 02:39:28 -0800417 /* Wait ... */
Jiri Slabyf6e208c2009-09-19 13:13:14 -0700418 msleep(5);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
Jiri Slaby02f11752006-12-08 02:39:28 -0800420 /* Check which interrupt is in use */
421 irq = probe_irq_off(irqs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422
Jiri Slaby02f11752006-12-08 02:39:28 -0800423 /* Clean up */
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700424 save_xir = (u_char) readb(address + (CyTIR << index));
425 save_car = readb(address + (CyCAR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -0800426 cy_writeb(address + (CyCAR << index), (save_xir & 0x3));
427 cy_writeb(address + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700428 readb(address + (CySRER << index)) & ~CyTxRdy);
Jiri Slaby02f11752006-12-08 02:39:28 -0800429 cy_writeb(address + (CyTIR << index), (save_xir & 0x3f));
430 cy_writeb(address + (CyCAR << index), (save_car));
431 cy_writeb(address + (Cy_ClrIntr << index), 0);
432 /* Cy_ClrIntr is 0x1800 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
Jiri Slaby02f11752006-12-08 02:39:28 -0800434 return (irq > 0) ? irq : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435}
Jiri Slaby02f11752006-12-08 02:39:28 -0800436#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
Jiri Slabyce97a092007-10-18 03:06:21 -0700438static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
439 void __iomem *base_addr)
Jiri Slabye9410272006-12-08 02:39:28 -0800440{
441 struct cyclades_port *info;
Jiri Slaby227434f2013-01-03 15:53:01 +0100442 struct tty_port *port;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700443 int len, index = cinfo->bus_index;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700444 u8 ivr, save_xir, channel, save_car, data, char_count;
Jiri Slabye9410272006-12-08 02:39:28 -0800445
Jiri Slabye9410272006-12-08 02:39:28 -0800446#ifdef CY_DEBUG_INTERRUPTS
Jiri Slabyce97a092007-10-18 03:06:21 -0700447 printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
Jiri Slabye9410272006-12-08 02:39:28 -0800448#endif
Jiri Slabyce97a092007-10-18 03:06:21 -0700449 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700450 save_xir = readb(base_addr + (CyRIR << index));
451 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700452 info = &cinfo->ports[channel + chip * 4];
Jiri Slaby227434f2013-01-03 15:53:01 +0100453 port = &info->port;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700454 save_car = cyy_readb(info, CyCAR);
455 cyy_writeb(info, CyCAR, save_xir);
456 ivr = cyy_readb(info, CyRIVR) & CyIVRMask;
Jiri Slabye9410272006-12-08 02:39:28 -0800457
Jiri Slabyce97a092007-10-18 03:06:21 -0700458 /* there is an open port for this data */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700459 if (ivr == CyIVRRxEx) { /* exception */
460 data = cyy_readb(info, CyRDSR);
Jiri Slaby02f11752006-12-08 02:39:28 -0800461
Jiri Slabyce97a092007-10-18 03:06:21 -0700462 /* For statistics only */
463 if (data & CyBREAK)
464 info->icount.brk++;
465 else if (data & CyFRAME)
466 info->icount.frame++;
467 else if (data & CyPARITY)
468 info->icount.parity++;
469 else if (data & CyOVERRUN)
470 info->icount.overrun++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800471
Jiri Slabyce97a092007-10-18 03:06:21 -0700472 if (data & info->ignore_status_mask) {
473 info->icount.rx++;
Jiri Slabyce97a092007-10-18 03:06:21 -0700474 return;
475 }
Jiri Slaby227434f2013-01-03 15:53:01 +0100476 if (tty_buffer_request_room(port, 1)) {
Jiri Slabyce97a092007-10-18 03:06:21 -0700477 if (data & info->read_status_mask) {
478 if (data & CyBREAK) {
Jiri Slaby92a19f92013-01-03 15:53:03 +0100479 tty_insert_flip_char(port,
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700480 cyy_readb(info, CyRDSR),
481 TTY_BREAK);
Jiri Slaby02f11752006-12-08 02:39:28 -0800482 info->icount.rx++;
Jiri Slaby6732c8b2013-01-03 15:53:07 +0100483 if (port->flags & ASYNC_SAK) {
484 struct tty_struct *tty =
485 tty_port_tty_get(port);
486 if (tty) {
487 do_SAK(tty);
488 tty_kref_put(tty);
489 }
490 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700491 } else if (data & CyFRAME) {
Jiri Slaby92a19f92013-01-03 15:53:03 +0100492 tty_insert_flip_char(port,
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700493 cyy_readb(info, CyRDSR),
494 TTY_FRAME);
Jiri Slabyce97a092007-10-18 03:06:21 -0700495 info->icount.rx++;
496 info->idle_stats.frame_errs++;
497 } else if (data & CyPARITY) {
498 /* Pieces of seven... */
Jiri Slaby92a19f92013-01-03 15:53:03 +0100499 tty_insert_flip_char(port,
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700500 cyy_readb(info, CyRDSR),
501 TTY_PARITY);
Jiri Slabyce97a092007-10-18 03:06:21 -0700502 info->icount.rx++;
503 info->idle_stats.parity_errs++;
504 } else if (data & CyOVERRUN) {
Jiri Slaby92a19f92013-01-03 15:53:03 +0100505 tty_insert_flip_char(port, 0,
Jiri Slabyce97a092007-10-18 03:06:21 -0700506 TTY_OVERRUN);
507 info->icount.rx++;
508 /* If the flip buffer itself is
509 overflowing, we still lose
510 the next incoming character.
511 */
Jiri Slaby92a19f92013-01-03 15:53:03 +0100512 tty_insert_flip_char(port,
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700513 cyy_readb(info, CyRDSR),
514 TTY_FRAME);
Jiri Slabyce97a092007-10-18 03:06:21 -0700515 info->icount.rx++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800516 info->idle_stats.overruns++;
Jiri Slabyce97a092007-10-18 03:06:21 -0700517 /* These two conditions may imply */
518 /* a normal read should be done. */
519 /* } else if(data & CyTIMEOUT) { */
520 /* } else if(data & CySPECHAR) { */
521 } else {
Jiri Slaby92a19f92013-01-03 15:53:03 +0100522 tty_insert_flip_char(port, 0,
Jiri Slabyce97a092007-10-18 03:06:21 -0700523 TTY_NORMAL);
524 info->icount.rx++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800525 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700526 } else {
Jiri Slaby92a19f92013-01-03 15:53:03 +0100527 tty_insert_flip_char(port, 0, TTY_NORMAL);
Jiri Slabyce97a092007-10-18 03:06:21 -0700528 info->icount.rx++;
529 }
530 } else {
531 /* there was a software buffer overrun and nothing
532 * could be done about it!!! */
533 info->icount.buf_overrun++;
534 info->idle_stats.overruns++;
535 }
536 } else { /* normal character reception */
537 /* load # chars available from the chip */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700538 char_count = cyy_readb(info, CyRDCR);
Jiri Slabye9410272006-12-08 02:39:28 -0800539
540#ifdef CY_ENABLE_MONITORING
Jiri Slabyce97a092007-10-18 03:06:21 -0700541 ++info->mon.int_count;
542 info->mon.char_count += char_count;
543 if (char_count > info->mon.char_max)
544 info->mon.char_max = char_count;
545 info->mon.char_last = char_count;
Jiri Slabye9410272006-12-08 02:39:28 -0800546#endif
Jiri Slaby227434f2013-01-03 15:53:01 +0100547 len = tty_buffer_request_room(port, char_count);
Jiri Slabyce97a092007-10-18 03:06:21 -0700548 while (len--) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700549 data = cyy_readb(info, CyRDSR);
Jiri Slaby92a19f92013-01-03 15:53:03 +0100550 tty_insert_flip_char(port, data, TTY_NORMAL);
Jiri Slabyce97a092007-10-18 03:06:21 -0700551 info->idle_stats.recv_bytes++;
552 info->icount.rx++;
Jiri Slabye9410272006-12-08 02:39:28 -0800553#ifdef CY_16Y_HACK
Jiri Slabyce97a092007-10-18 03:06:21 -0700554 udelay(10L);
Jiri Slabye9410272006-12-08 02:39:28 -0800555#endif
Jiri Slabye9410272006-12-08 02:39:28 -0800556 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700557 info->idle_stats.recv_idle = jiffies;
558 }
Jiri Slaby6732c8b2013-01-03 15:53:07 +0100559 tty_schedule_flip(port);
560
Jiri Slabyce97a092007-10-18 03:06:21 -0700561 /* end of service */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700562 cyy_writeb(info, CyRIR, save_xir & 0x3f);
563 cyy_writeb(info, CyCAR, save_car);
Jiri Slabyce97a092007-10-18 03:06:21 -0700564}
565
Jiri Slaby65f76a82007-10-18 03:06:22 -0700566static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
Jiri Slabyce97a092007-10-18 03:06:21 -0700567 void __iomem *base_addr)
568{
569 struct cyclades_port *info;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700570 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700571 int char_count, index = cinfo->bus_index;
572 u8 save_xir, channel, save_car, outch;
Jiri Slabyce97a092007-10-18 03:06:21 -0700573
574 /* Since we only get here when the transmit buffer
575 is empty, we know we can always stuff a dozen
576 characters. */
577#ifdef CY_DEBUG_INTERRUPTS
578 printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip);
579#endif
580
581 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700582 save_xir = readb(base_addr + (CyTIR << index));
583 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700584 save_car = readb(base_addr + (CyCAR << index));
585 cy_writeb(base_addr + (CyCAR << index), save_xir);
586
Jiri Slabyce97a092007-10-18 03:06:21 -0700587 info = &cinfo->ports[channel + chip * 4];
Jiri Slabyd13549f2009-09-19 13:13:12 -0700588 tty = tty_port_tty_get(&info->port);
589 if (tty == NULL) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700590 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700591 goto end;
Jiri Slabye9410272006-12-08 02:39:28 -0800592 }
593
Jiri Slabyce97a092007-10-18 03:06:21 -0700594 /* load the on-chip space for outbound data */
595 char_count = info->xmit_fifo_size;
Jiri Slabye9410272006-12-08 02:39:28 -0800596
Jiri Slabyce97a092007-10-18 03:06:21 -0700597 if (info->x_char) { /* send special char */
598 outch = info->x_char;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700599 cyy_writeb(info, CyTDR, outch);
Jiri Slabyce97a092007-10-18 03:06:21 -0700600 char_count--;
601 info->icount.tx++;
602 info->x_char = 0;
603 }
Jiri Slabye9410272006-12-08 02:39:28 -0800604
Jiri Slabyce97a092007-10-18 03:06:21 -0700605 if (info->breakon || info->breakoff) {
606 if (info->breakon) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700607 cyy_writeb(info, CyTDR, 0);
608 cyy_writeb(info, CyTDR, 0x81);
Jiri Slabyce97a092007-10-18 03:06:21 -0700609 info->breakon = 0;
610 char_count -= 2;
Jiri Slaby02f11752006-12-08 02:39:28 -0800611 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700612 if (info->breakoff) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700613 cyy_writeb(info, CyTDR, 0);
614 cyy_writeb(info, CyTDR, 0x83);
Jiri Slabyce97a092007-10-18 03:06:21 -0700615 info->breakoff = 0;
616 char_count -= 2;
Jiri Slaby02f11752006-12-08 02:39:28 -0800617 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700618 }
Jiri Slabye9410272006-12-08 02:39:28 -0800619
Jiri Slabyce97a092007-10-18 03:06:21 -0700620 while (char_count-- > 0) {
621 if (!info->xmit_cnt) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700622 if (cyy_readb(info, CySRER) & CyTxMpty) {
623 cyy_writeb(info, CySRER,
624 cyy_readb(info, CySRER) & ~CyTxMpty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700625 } else {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700626 cyy_writeb(info, CySRER, CyTxMpty |
627 (cyy_readb(info, CySRER) & ~CyTxRdy));
Jiri Slaby02f11752006-12-08 02:39:28 -0800628 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700629 goto done;
630 }
Alan Cox77451e52008-07-16 21:57:02 +0100631 if (info->port.xmit_buf == NULL) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700632 cyy_writeb(info, CySRER,
633 cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700634 goto done;
635 }
Jiri Slabyd13549f2009-09-19 13:13:12 -0700636 if (tty->stopped || tty->hw_stopped) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700637 cyy_writeb(info, CySRER,
638 cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700639 goto done;
640 }
641 /* Because the Embedded Transmit Commands have been enabled,
642 * we must check to see if the escape character, NULL, is being
643 * sent. If it is, we must ensure that there is room for it to
644 * be doubled in the output stream. Therefore we no longer
645 * advance the pointer when the character is fetched, but
646 * rather wait until after the check for a NULL output
647 * character. This is necessary because there may not be room
648 * for the two chars needed to send a NULL.)
649 */
Alan Cox77451e52008-07-16 21:57:02 +0100650 outch = info->port.xmit_buf[info->xmit_tail];
Jiri Slabyce97a092007-10-18 03:06:21 -0700651 if (outch) {
652 info->xmit_cnt--;
653 info->xmit_tail = (info->xmit_tail + 1) &
654 (SERIAL_XMIT_SIZE - 1);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700655 cyy_writeb(info, CyTDR, outch);
Jiri Slabyce97a092007-10-18 03:06:21 -0700656 info->icount.tx++;
657 } else {
658 if (char_count > 1) {
Jiri Slaby02f11752006-12-08 02:39:28 -0800659 info->xmit_cnt--;
660 info->xmit_tail = (info->xmit_tail + 1) &
Jiri Slabyce97a092007-10-18 03:06:21 -0700661 (SERIAL_XMIT_SIZE - 1);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700662 cyy_writeb(info, CyTDR, outch);
663 cyy_writeb(info, CyTDR, 0);
Jiri Slaby02f11752006-12-08 02:39:28 -0800664 info->icount.tx++;
Jiri Slabyce97a092007-10-18 03:06:21 -0700665 char_count--;
Jiri Slaby02f11752006-12-08 02:39:28 -0800666 }
667 }
Jiri Slabye9410272006-12-08 02:39:28 -0800668 }
669
Jiri Slabyce97a092007-10-18 03:06:21 -0700670done:
Jiri Slabyd13549f2009-09-19 13:13:12 -0700671 tty_wakeup(tty);
672 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700673end:
674 /* end of service */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700675 cyy_writeb(info, CyTIR, save_xir & 0x3f);
676 cyy_writeb(info, CyCAR, save_car);
Jiri Slabyce97a092007-10-18 03:06:21 -0700677}
Jiri Slabye9410272006-12-08 02:39:28 -0800678
Jiri Slabyce97a092007-10-18 03:06:21 -0700679static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
680 void __iomem *base_addr)
681{
682 struct cyclades_port *info;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700683 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700684 int index = cinfo->bus_index;
685 u8 save_xir, channel, save_car, mdm_change, mdm_status;
Jiri Slabye9410272006-12-08 02:39:28 -0800686
Jiri Slabyce97a092007-10-18 03:06:21 -0700687 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700688 save_xir = readb(base_addr + (CyMIR << index));
689 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700690 info = &cinfo->ports[channel + chip * 4];
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700691 save_car = cyy_readb(info, CyCAR);
692 cyy_writeb(info, CyCAR, save_xir);
Jiri Slabye9410272006-12-08 02:39:28 -0800693
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700694 mdm_change = cyy_readb(info, CyMISR);
695 mdm_status = cyy_readb(info, CyMSVR1);
Jiri Slabye9410272006-12-08 02:39:28 -0800696
Jiri Slabyd13549f2009-09-19 13:13:12 -0700697 tty = tty_port_tty_get(&info->port);
698 if (!tty)
Jiri Slabyce97a092007-10-18 03:06:21 -0700699 goto end;
Jiri Slaby02f11752006-12-08 02:39:28 -0800700
Jiri Slabyce97a092007-10-18 03:06:21 -0700701 if (mdm_change & CyANY_DELTA) {
702 /* For statistics only */
703 if (mdm_change & CyDCD)
704 info->icount.dcd++;
705 if (mdm_change & CyCTS)
706 info->icount.cts++;
707 if (mdm_change & CyDSR)
708 info->icount.dsr++;
709 if (mdm_change & CyRI)
710 info->icount.rng++;
711
Alan Coxbdc04e32009-09-19 13:13:31 -0700712 wake_up_interruptible(&info->port.delta_msr_wait);
Jiri Slabyce97a092007-10-18 03:06:21 -0700713 }
714
Peter Hurley2d686552016-04-09 17:53:23 -0700715 if ((mdm_change & CyDCD) && tty_port_check_carrier(&info->port)) {
Jiri Slaby174e6fe2009-09-19 13:13:13 -0700716 if (mdm_status & CyDCD)
717 wake_up_interruptible(&info->port.open_wait);
718 else
Jiri Slabyd13549f2009-09-19 13:13:12 -0700719 tty_hangup(tty);
Jiri Slabye9410272006-12-08 02:39:28 -0800720 }
Huang Shijief21ec3d2012-08-22 22:13:36 -0400721 if ((mdm_change & CyCTS) && tty_port_cts_enabled(&info->port)) {
Jiri Slabyd13549f2009-09-19 13:13:12 -0700722 if (tty->hw_stopped) {
Jiri Slabyce97a092007-10-18 03:06:21 -0700723 if (mdm_status & CyCTS) {
724 /* cy_start isn't used
725 because... !!! */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700726 tty->hw_stopped = 0;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700727 cyy_writeb(info, CySRER,
728 cyy_readb(info, CySRER) | CyTxRdy);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700729 tty_wakeup(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700730 }
731 } else {
732 if (!(mdm_status & CyCTS)) {
733 /* cy_stop isn't used
734 because ... !!! */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700735 tty->hw_stopped = 1;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700736 cyy_writeb(info, CySRER,
737 cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700738 }
739 }
740 }
741/* if (mdm_change & CyDSR) {
742 }
743 if (mdm_change & CyRI) {
744 }*/
Jiri Slabyd13549f2009-09-19 13:13:12 -0700745 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700746end:
747 /* end of service */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700748 cyy_writeb(info, CyMIR, save_xir & 0x3f);
749 cyy_writeb(info, CyCAR, save_car);
Jiri Slabye9410272006-12-08 02:39:28 -0800750}
751
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752/* The real interrupt service routine is called
753 whenever the card wants its hand held--chars
754 received, out buffer empty, modem change, etc.
755 */
Jiri Slaby02f11752006-12-08 02:39:28 -0800756static irqreturn_t cyy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757{
Jiri Slaby02f11752006-12-08 02:39:28 -0800758 int status;
Jiri Slabyf7429032007-05-08 00:36:59 -0700759 struct cyclades_card *cinfo = dev_id;
Jiri Slaby02f11752006-12-08 02:39:28 -0800760 void __iomem *base_addr, *card_base_addr;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700761 unsigned int chip, too_many, had_work;
Jiri Slaby02f11752006-12-08 02:39:28 -0800762 int index;
Jiri Slabye9410272006-12-08 02:39:28 -0800763
Jiri Slabyf7429032007-05-08 00:36:59 -0700764 if (unlikely(cinfo == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765#ifdef CY_DEBUG_INTERRUPTS
Alan Cox15ed6cc2008-04-30 00:53:55 -0700766 printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",
767 irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768#endif
Jiri Slaby02f11752006-12-08 02:39:28 -0800769 return IRQ_NONE; /* spurious interrupt */
770 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Jiri Slaby02f11752006-12-08 02:39:28 -0800772 card_base_addr = cinfo->base_addr;
773 index = cinfo->bus_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
Jiri Slabyf1e83c62007-05-08 00:36:24 -0700775 /* card was not initialized yet (e.g. DEBUG_SHIRQ) */
776 if (unlikely(card_base_addr == NULL))
777 return IRQ_HANDLED;
778
Jiri Slaby02f11752006-12-08 02:39:28 -0800779 /* This loop checks all chips in the card. Make a note whenever
780 _any_ chip had some work to do, as this is considered an
781 indication that there will be more to do. Only when no chip
782 has any work does this outermost loop exit.
783 */
784 do {
785 had_work = 0;
786 for (chip = 0; chip < cinfo->num_chips; chip++) {
787 base_addr = cinfo->base_addr +
788 (cy_chip_offset[chip] << index);
789 too_many = 0;
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700790 while ((status = readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -0800791 (CySVRR << index))) != 0x00) {
792 had_work++;
793 /* The purpose of the following test is to ensure that
794 no chip can monopolize the driver. This forces the
795 chips to be checked in a round-robin fashion (after
796 draining each of a bunch (1000) of characters).
797 */
Jiri Slabyce97a092007-10-18 03:06:21 -0700798 if (1000 < too_many++)
Jiri Slaby02f11752006-12-08 02:39:28 -0800799 break;
Jiri Slaby1c0a3872007-10-18 03:06:22 -0700800 spin_lock(&cinfo->card_lock);
Jiri Slabyce97a092007-10-18 03:06:21 -0700801 if (status & CySRReceive) /* rx intr */
802 cyy_chip_rx(cinfo, chip, base_addr);
803 if (status & CySRTransmit) /* tx intr */
804 cyy_chip_tx(cinfo, chip, base_addr);
805 if (status & CySRModem) /* modem intr */
806 cyy_chip_modem(cinfo, chip, base_addr);
Jiri Slaby1c0a3872007-10-18 03:06:22 -0700807 spin_unlock(&cinfo->card_lock);
Jiri Slaby02f11752006-12-08 02:39:28 -0800808 }
809 }
810 } while (had_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
Jiri Slaby02f11752006-12-08 02:39:28 -0800812 /* clear interrupts */
813 spin_lock(&cinfo->card_lock);
814 cy_writeb(card_base_addr + (Cy_ClrIntr << index), 0);
815 /* Cy_ClrIntr is 0x1800 */
816 spin_unlock(&cinfo->card_lock);
817 return IRQ_HANDLED;
818} /* cyy_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
Jiri Slaby4d768202009-09-19 13:13:15 -0700820static void cyy_change_rts_dtr(struct cyclades_port *info, unsigned int set,
821 unsigned int clear)
822{
823 struct cyclades_card *card = info->card;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700824 int channel = info->line - card->first_line;
Jiri Slaby0d348722009-09-19 13:13:16 -0700825 u32 rts, dtr, msvrr, msvrd;
Jiri Slaby4d768202009-09-19 13:13:15 -0700826
Jiri Slaby4d768202009-09-19 13:13:15 -0700827 channel &= 0x03;
Jiri Slaby4d768202009-09-19 13:13:15 -0700828
Jiri Slaby0d348722009-09-19 13:13:16 -0700829 if (info->rtsdtr_inv) {
830 msvrr = CyMSVR2;
831 msvrd = CyMSVR1;
832 rts = CyDTR;
833 dtr = CyRTS;
834 } else {
835 msvrr = CyMSVR1;
836 msvrd = CyMSVR2;
837 rts = CyRTS;
838 dtr = CyDTR;
839 }
Jiri Slaby4d768202009-09-19 13:13:15 -0700840 if (set & TIOCM_RTS) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700841 cyy_writeb(info, CyCAR, channel);
842 cyy_writeb(info, msvrr, rts);
Jiri Slaby4d768202009-09-19 13:13:15 -0700843 }
844 if (clear & TIOCM_RTS) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700845 cyy_writeb(info, CyCAR, channel);
846 cyy_writeb(info, msvrr, ~rts);
Jiri Slaby4d768202009-09-19 13:13:15 -0700847 }
848 if (set & TIOCM_DTR) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700849 cyy_writeb(info, CyCAR, channel);
850 cyy_writeb(info, msvrd, dtr);
Jiri Slaby4d768202009-09-19 13:13:15 -0700851#ifdef CY_DEBUG_DTR
852 printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
853 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700854 cyy_readb(info, CyMSVR1),
855 cyy_readb(info, CyMSVR2));
Jiri Slaby4d768202009-09-19 13:13:15 -0700856#endif
857 }
858 if (clear & TIOCM_DTR) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700859 cyy_writeb(info, CyCAR, channel);
860 cyy_writeb(info, msvrd, ~dtr);
Jiri Slaby4d768202009-09-19 13:13:15 -0700861#ifdef CY_DEBUG_DTR
862 printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
863 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700864 cyy_readb(info, CyMSVR1),
865 cyy_readb(info, CyMSVR2));
Jiri Slaby4d768202009-09-19 13:13:15 -0700866#endif
867 }
868}
869
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870/***********************************************************/
871/********* End of block of Cyclom-Y specific code **********/
Alan Cox15ed6cc2008-04-30 00:53:55 -0700872/******** Start of block of Cyclades-Z specific code *******/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873/***********************************************************/
874
875static int
Jiri Slaby02f11752006-12-08 02:39:28 -0800876cyz_fetch_msg(struct cyclades_card *cinfo,
Alan Cox15ed6cc2008-04-30 00:53:55 -0700877 __u32 *channel, __u8 *cmd, __u32 *param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700879 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -0800880 unsigned long loc_doorbell;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
Jiri Slaby97e87f82009-06-11 12:29:27 +0100882 loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell);
Jiri Slaby02f11752006-12-08 02:39:28 -0800883 if (loc_doorbell) {
884 *cmd = (char)(0xff & loc_doorbell);
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700885 *channel = readl(&board_ctrl->fwcmd_channel);
886 *param = (__u32) readl(&board_ctrl->fwcmd_param);
Jiri Slaby97e87f82009-06-11 12:29:27 +0100887 cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff);
Jiri Slaby02f11752006-12-08 02:39:28 -0800888 return 1;
889 }
890 return 0;
891} /* cyz_fetch_msg */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892
893static int
Jiri Slaby02f11752006-12-08 02:39:28 -0800894cyz_issue_cmd(struct cyclades_card *cinfo,
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700895 __u32 channel, __u8 cmd, __u32 param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700897 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700898 __u32 __iomem *pci_doorbell;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700899 unsigned int index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900
Jiri Slaby2693f482009-06-11 12:31:06 +0100901 if (!cyz_is_loaded(cinfo))
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800902 return -1;
Alan Cox15ed6cc2008-04-30 00:53:55 -0700903
Jiri Slaby02f11752006-12-08 02:39:28 -0800904 index = 0;
Jiri Slaby97e87f82009-06-11 12:29:27 +0100905 pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700906 while ((readl(pci_doorbell) & 0xff) != 0) {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700907 if (index++ == 1000)
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700908 return (int)(readl(pci_doorbell) & 0xff);
Jiri Slaby02f11752006-12-08 02:39:28 -0800909 udelay(50L);
910 }
911 cy_writel(&board_ctrl->hcmd_channel, channel);
912 cy_writel(&board_ctrl->hcmd_param, param);
913 cy_writel(pci_doorbell, (long)cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800915 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -0800916} /* cyz_issue_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
Jiri Slabydabe2c12013-01-03 15:53:08 +0100918static void cyz_handle_rx(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700920 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby875b2062007-05-08 00:36:49 -0700921 struct cyclades_card *cinfo = info->card;
Jiri Slaby227434f2013-01-03 15:53:01 +0100922 struct tty_port *port = &info->port;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700923 unsigned int char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -0800924 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925#ifdef BLOCKMOVE
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700926 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927#else
Jiri Slaby02f11752006-12-08 02:39:28 -0800928 char data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929#endif
Jiri Slabyad39c302007-05-08 00:35:49 -0700930 __u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700932 rx_get = new_rx_get = readl(&buf_ctrl->rx_get);
933 rx_put = readl(&buf_ctrl->rx_put);
934 rx_bufsize = readl(&buf_ctrl->rx_bufsize);
935 rx_bufaddr = readl(&buf_ctrl->rx_bufaddr);
Jiri Slaby02f11752006-12-08 02:39:28 -0800936 if (rx_put >= rx_get)
937 char_count = rx_put - rx_get;
938 else
939 char_count = rx_put - rx_get + rx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
Jiri Slabydabe2c12013-01-03 15:53:08 +0100941 if (!char_count)
942 return;
943
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944#ifdef CY_ENABLE_MONITORING
Jiri Slabydabe2c12013-01-03 15:53:08 +0100945 info->mon.int_count++;
946 info->mon.char_count += char_count;
947 if (char_count > info->mon.char_max)
948 info->mon.char_max = char_count;
949 info->mon.char_last = char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950#endif
Jiri Slabydabe2c12013-01-03 15:53:08 +0100951
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952#ifdef BLOCKMOVE
Jiri Slabydabe2c12013-01-03 15:53:08 +0100953 /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
954 for performance, but because of buffer boundaries, there
955 may be several steps to the operation */
956 while (1) {
957 len = tty_prepare_flip_string(port, &buf,
958 char_count);
959 if (!len)
960 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Jiri Slabydabe2c12013-01-03 15:53:08 +0100962 len = min_t(unsigned int, min(len, char_count),
963 rx_bufsize - new_rx_get);
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700964
Jiri Slabydabe2c12013-01-03 15:53:08 +0100965 memcpy_fromio(buf, cinfo->base_addr +
966 rx_bufaddr + new_rx_get, len);
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700967
Jiri Slabydabe2c12013-01-03 15:53:08 +0100968 new_rx_get = (new_rx_get + len) &
969 (rx_bufsize - 1);
970 char_count -= len;
971 info->icount.rx += len;
972 info->idle_stats.recv_bytes += len;
973 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974#else
Jiri Slabydabe2c12013-01-03 15:53:08 +0100975 len = tty_buffer_request_room(port, char_count);
976 while (len--) {
977 data = readb(cinfo->base_addr + rx_bufaddr +
978 new_rx_get);
979 new_rx_get = (new_rx_get + 1) &
980 (rx_bufsize - 1);
981 tty_insert_flip_char(port, data, TTY_NORMAL);
982 info->idle_stats.recv_bytes++;
983 info->icount.rx++;
984 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985#endif
986#ifdef CONFIG_CYZ_INTR
Jiri Slabydabe2c12013-01-03 15:53:08 +0100987 /* Recalculate the number of chars in the RX buffer and issue
988 a cmd in case it's higher than the RX high water mark */
989 rx_put = readl(&buf_ctrl->rx_put);
990 if (rx_put >= rx_get)
991 char_count = rx_put - rx_get;
992 else
993 char_count = rx_put - rx_get + rx_bufsize;
994 if (char_count >= readl(&buf_ctrl->rx_threshold) &&
995 !timer_pending(&cyz_rx_full_timer[
996 info->line]))
997 mod_timer(&cyz_rx_full_timer[info->line],
998 jiffies + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999#endif
Jiri Slabydabe2c12013-01-03 15:53:08 +01001000 info->idle_stats.recv_idle = jiffies;
1001 tty_schedule_flip(&info->port);
1002
1003 /* Update rx_get */
1004 cy_writel(&buf_ctrl->rx_get, new_rx_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005}
1006
Jiri Slabydabe2c12013-01-03 15:53:08 +01001007static void cyz_handle_tx(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001009 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby875b2062007-05-08 00:36:49 -07001010 struct cyclades_card *cinfo = info->card;
Jiri Slabydabe2c12013-01-03 15:53:08 +01001011 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001012 u8 data;
1013 unsigned int char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -08001015 int small_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016#endif
Jiri Slabyad39c302007-05-08 00:35:49 -07001017 __u32 tx_put, tx_get, tx_bufsize, tx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
Jiri Slaby02f11752006-12-08 02:39:28 -08001019 if (info->xmit_cnt <= 0) /* Nothing to transmit */
1020 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001022 tx_get = readl(&buf_ctrl->tx_get);
1023 tx_put = readl(&buf_ctrl->tx_put);
1024 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
1025 tx_bufaddr = readl(&buf_ctrl->tx_bufaddr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001026 if (tx_put >= tx_get)
1027 char_count = tx_get - tx_put - 1 + tx_bufsize;
1028 else
1029 char_count = tx_get - tx_put - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030
Jiri Slabydabe2c12013-01-03 15:53:08 +01001031 if (!char_count)
1032 return;
1033
1034 tty = tty_port_tty_get(&info->port);
1035 if (tty == NULL)
1036 goto ztxdone;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
Jiri Slabydabe2c12013-01-03 15:53:08 +01001038 if (info->x_char) { /* send special char */
1039 data = info->x_char;
Jiri Slaby02f11752006-12-08 02:39:28 -08001040
Jiri Slabydabe2c12013-01-03 15:53:08 +01001041 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1042 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1043 info->x_char = 0;
1044 char_count--;
1045 info->icount.tx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 }
Jiri Slabydabe2c12013-01-03 15:53:08 +01001047#ifdef BLOCKMOVE
1048 while (0 < (small_count = min_t(unsigned int,
1049 tx_bufsize - tx_put, min_t(unsigned int,
1050 (SERIAL_XMIT_SIZE - info->xmit_tail),
1051 min_t(unsigned int, info->xmit_cnt,
1052 char_count))))) {
1053
1054 memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr + tx_put),
1055 &info->port.xmit_buf[info->xmit_tail],
1056 small_count);
1057
1058 tx_put = (tx_put + small_count) & (tx_bufsize - 1);
1059 char_count -= small_count;
1060 info->icount.tx += small_count;
1061 info->xmit_cnt -= small_count;
1062 info->xmit_tail = (info->xmit_tail + small_count) &
1063 (SERIAL_XMIT_SIZE - 1);
1064 }
1065#else
1066 while (info->xmit_cnt && char_count) {
1067 data = info->port.xmit_buf[info->xmit_tail];
1068 info->xmit_cnt--;
1069 info->xmit_tail = (info->xmit_tail + 1) &
1070 (SERIAL_XMIT_SIZE - 1);
1071
1072 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1073 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1074 char_count--;
1075 info->icount.tx++;
1076 }
1077#endif
1078 tty_wakeup(tty);
1079 tty_kref_put(tty);
1080ztxdone:
1081 /* Update tx_put */
1082 cy_writel(&buf_ctrl->tx_put, tx_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083}
1084
Jiri Slaby02f11752006-12-08 02:39:28 -08001085static void cyz_handle_cmd(struct cyclades_card *cinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001087 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001088 struct cyclades_port *info;
Jiri Slaby101b8152009-06-11 12:30:10 +01001089 __u32 channel, param, fw_ver;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001090 __u8 cmd;
Jiri Slaby02f11752006-12-08 02:39:28 -08001091 int special_count;
1092 int delta_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001094 fw_ver = readl(&board_ctrl->fw_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
Jiri Slaby02f11752006-12-08 02:39:28 -08001096 while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
1097 special_count = 0;
1098 delta_count = 0;
Jiri Slabydd025c02007-05-08 00:37:02 -07001099 info = &cinfo->ports[channel];
Jiri Slabyf7429032007-05-08 00:36:59 -07001100
Jiri Slaby02f11752006-12-08 02:39:28 -08001101 switch (cmd) {
1102 case C_CM_PR_ERROR:
Jiri Slaby92a19f92013-01-03 15:53:03 +01001103 tty_insert_flip_char(&info->port, 0, TTY_PARITY);
Jiri Slaby02f11752006-12-08 02:39:28 -08001104 info->icount.rx++;
1105 special_count++;
1106 break;
1107 case C_CM_FR_ERROR:
Jiri Slaby92a19f92013-01-03 15:53:03 +01001108 tty_insert_flip_char(&info->port, 0, TTY_FRAME);
Jiri Slaby02f11752006-12-08 02:39:28 -08001109 info->icount.rx++;
1110 special_count++;
1111 break;
1112 case C_CM_RXBRK:
Jiri Slaby92a19f92013-01-03 15:53:03 +01001113 tty_insert_flip_char(&info->port, 0, TTY_BREAK);
Jiri Slaby02f11752006-12-08 02:39:28 -08001114 info->icount.rx++;
1115 special_count++;
1116 break;
1117 case C_CM_MDCD:
1118 info->icount.dcd++;
1119 delta_count++;
Peter Hurley2d686552016-04-09 17:53:23 -07001120 if (tty_port_check_carrier(&info->port)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001121 u32 dcd = fw_ver > 241 ? param :
1122 readl(&info->u.cyz.ch_ctrl->rs_status);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07001123 if (dcd & C_RS_DCD)
Alan Cox77451e52008-07-16 21:57:02 +01001124 wake_up_interruptible(&info->port.open_wait);
Jiri Slabyaa27a092013-03-07 13:12:30 +01001125 else
1126 tty_port_tty_hangup(&info->port, false);
Jiri Slaby02f11752006-12-08 02:39:28 -08001127 }
1128 break;
1129 case C_CM_MCTS:
1130 info->icount.cts++;
1131 delta_count++;
1132 break;
1133 case C_CM_MRI:
1134 info->icount.rng++;
1135 delta_count++;
1136 break;
1137 case C_CM_MDSR:
1138 info->icount.dsr++;
1139 delta_count++;
1140 break;
1141#ifdef Z_WAKE
1142 case C_CM_IOCTLW:
Jiri Slabyebafeef2007-10-18 03:06:20 -07001143 complete(&info->shutdown_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001144 break;
1145#endif
1146#ifdef CONFIG_CYZ_INTR
1147 case C_CM_RXHIWM:
1148 case C_CM_RXNNDT:
1149 case C_CM_INTBACK2:
1150 /* Reception Interrupt */
1151#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001152 printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
1153 "port %ld\n", info->card, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001154#endif
Jiri Slabydabe2c12013-01-03 15:53:08 +01001155 cyz_handle_rx(info);
Jiri Slaby02f11752006-12-08 02:39:28 -08001156 break;
1157 case C_CM_TXBEMPTY:
1158 case C_CM_TXLOWWM:
1159 case C_CM_INTBACK:
1160 /* Transmission Interrupt */
1161#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001162 printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
1163 "port %ld\n", info->card, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001164#endif
Jiri Slabydabe2c12013-01-03 15:53:08 +01001165 cyz_handle_tx(info);
Jiri Slaby02f11752006-12-08 02:39:28 -08001166 break;
1167#endif /* CONFIG_CYZ_INTR */
1168 case C_CM_FATAL:
1169 /* should do something with this !!! */
1170 break;
1171 default:
1172 break;
1173 }
1174 if (delta_count)
Alan Coxbdc04e32009-09-19 13:13:31 -07001175 wake_up_interruptible(&info->port.delta_msr_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001176 if (special_count)
Jiri Slaby6732c8b2013-01-03 15:53:07 +01001177 tty_schedule_flip(&info->port);
Jiri Slaby02f11752006-12-08 02:39:28 -08001178 }
1179}
1180
1181#ifdef CONFIG_CYZ_INTR
1182static irqreturn_t cyz_interrupt(int irq, void *dev_id)
1183{
Jiri Slabyf7429032007-05-08 00:36:59 -07001184 struct cyclades_card *cinfo = dev_id;
Jiri Slaby02f11752006-12-08 02:39:28 -08001185
Jiri Slaby2693f482009-06-11 12:31:06 +01001186 if (unlikely(!cyz_is_loaded(cinfo))) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001187#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001188 printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
1189 "(IRQ%d).\n", irq);
Jiri Slaby02f11752006-12-08 02:39:28 -08001190#endif
1191 return IRQ_NONE;
1192 }
1193
1194 /* Handle the interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 cyz_handle_cmd(cinfo);
1196
Jiri Slaby02f11752006-12-08 02:39:28 -08001197 return IRQ_HANDLED;
1198} /* cyz_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199
Jiri Slaby02f11752006-12-08 02:39:28 -08001200static void cyz_rx_restart(unsigned long arg)
1201{
1202 struct cyclades_port *info = (struct cyclades_port *)arg;
Jiri Slaby875b2062007-05-08 00:36:49 -07001203 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001204 int retval;
Jiri Slaby875b2062007-05-08 00:36:49 -07001205 __u32 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08001206 unsigned long flags;
1207
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001208 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07001209 retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001210 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001211 printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08001212 info->line, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001214 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001215}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216
Jiri Slaby02f11752006-12-08 02:39:28 -08001217#else /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
Jiri Slaby02f11752006-12-08 02:39:28 -08001219static void cyz_poll(unsigned long arg)
1220{
1221 struct cyclades_card *cinfo;
1222 struct cyclades_port *info;
Jiri Slabyb7050902007-05-08 00:35:48 -07001223 unsigned long expires = jiffies + HZ;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001224 unsigned int port, card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001225
Jiri Slaby02f11752006-12-08 02:39:28 -08001226 for (card = 0; card < NR_CARDS; card++) {
1227 cinfo = &cy_card[card];
1228
Jiri Slaby2693f482009-06-11 12:31:06 +01001229 if (!cy_is_Z(cinfo))
Jiri Slaby02f11752006-12-08 02:39:28 -08001230 continue;
Jiri Slaby2693f482009-06-11 12:31:06 +01001231 if (!cyz_is_loaded(cinfo))
Jiri Slaby02f11752006-12-08 02:39:28 -08001232 continue;
1233
Jiri Slaby02f11752006-12-08 02:39:28 -08001234 /* Skip first polling cycle to avoid racing conditions with the FW */
1235 if (!cinfo->intr_enabled) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001236 cinfo->intr_enabled = 1;
1237 continue;
1238 }
1239
1240 cyz_handle_cmd(cinfo);
1241
1242 for (port = 0; port < cinfo->nports; port++) {
Jiri Slabydd025c02007-05-08 00:37:02 -07001243 info = &cinfo->ports[port];
Jiri Slabyd13549f2009-09-19 13:13:12 -07001244
Jiri Slaby02f11752006-12-08 02:39:28 -08001245 if (!info->throttle)
Jiri Slabydabe2c12013-01-03 15:53:08 +01001246 cyz_handle_rx(info);
1247 cyz_handle_tx(info);
Jiri Slaby02f11752006-12-08 02:39:28 -08001248 }
1249 /* poll every 'cyz_polling_cycle' period */
Jiri Slabyb7050902007-05-08 00:35:48 -07001250 expires = jiffies + cyz_polling_cycle;
Jiri Slaby02f11752006-12-08 02:39:28 -08001251 }
Jiri Slabyb7050902007-05-08 00:35:48 -07001252 mod_timer(&cyz_timerlist, expires);
Jiri Slaby02f11752006-12-08 02:39:28 -08001253} /* cyz_poll */
1254
1255#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256
1257/********** End of block of Cyclades-Z specific code *********/
1258/***********************************************************/
1259
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260/* This is called whenever a port becomes active;
1261 interrupts are enabled and DTR & RTS are turned on.
1262 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001263static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264{
Jiri Slaby875b2062007-05-08 00:36:49 -07001265 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001266 unsigned long flags;
1267 int retval = 0;
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001268 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08001269 unsigned long page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270
Jiri Slaby02f11752006-12-08 02:39:28 -08001271 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001272 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273
Jiri Slaby02f11752006-12-08 02:39:28 -08001274 page = get_zeroed_page(GFP_KERNEL);
1275 if (!page)
1276 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001278 spin_lock_irqsave(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
Peter Hurleyd41861c2016-04-09 17:53:25 -07001280 if (tty_port_initialized(&info->port))
Jiri Slaby02f11752006-12-08 02:39:28 -08001281 goto errout;
Jiri Slaby02f11752006-12-08 02:39:28 -08001282
1283 if (!info->type) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07001284 set_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001285 goto errout;
1286 }
1287
Alan Cox77451e52008-07-16 21:57:02 +01001288 if (info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001289 free_page(page);
1290 else
Alan Cox77451e52008-07-16 21:57:02 +01001291 info->port.xmit_buf = (unsigned char *)page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001293 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294
Jiri Slabyd13549f2009-09-19 13:13:12 -07001295 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296
Jiri Slaby2693f482009-06-11 12:31:06 +01001297 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001298 channel &= 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001300 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001301
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001302 cyy_writeb(info, CyCAR, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001303
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001304 cyy_writeb(info, CyRTPR,
Jiri Slaby02f11752006-12-08 02:39:28 -08001305 (info->default_timeout ? info->default_timeout : 0x02));
1306 /* 10ms rx timeout */
1307
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001308 cyy_issue_cmd(info, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR);
Jiri Slaby02f11752006-12-08 02:39:28 -08001309
Jiri Slaby4d768202009-09-19 13:13:15 -07001310 cyy_change_rts_dtr(info, TIOCM_RTS | TIOCM_DTR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001312 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyRxData);
Jiri Slaby02f11752006-12-08 02:39:28 -08001313 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001314 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001315
Jiri Slaby2693f482009-06-11 12:31:06 +01001316 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08001317 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08001318
Jiri Slaby02f11752006-12-08 02:39:28 -08001319#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001320 printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001321 "base_addr %p\n", card, channel, card->base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001322#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001323 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001324
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001325 cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326#ifdef Z_WAKE
1327#ifdef CONFIG_CYZ_INTR
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001328 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001329 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1330 C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331#else
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001332 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001333 C_IN_IOCTLW | C_IN_MDCD);
1334#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335#else
1336#ifdef CONFIG_CYZ_INTR
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001337 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001338 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1339 C_IN_RXNNDT | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340#else
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001341 cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD);
Jiri Slaby02f11752006-12-08 02:39:28 -08001342#endif /* CONFIG_CYZ_INTR */
1343#endif /* Z_WAKE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344
Jiri Slaby875b2062007-05-08 00:36:49 -07001345 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001346 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001347 printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "
1348 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
Jiri Slaby02f11752006-12-08 02:39:28 -08001351 /* Flush RX buffers before raising DTR and RTS */
Jiri Slaby875b2062007-05-08 00:36:49 -07001352 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001353 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001354 printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was "
1355 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001356 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
Jiri Slaby02f11752006-12-08 02:39:28 -08001358 /* set timeout !!! */
1359 /* set RTS and DTR !!! */
Jiri Slaby4d768202009-09-19 13:13:15 -07001360 tty_port_raise_dtr_rts(&info->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361
Jiri Slaby02f11752006-12-08 02:39:28 -08001362 /* enable send, recv, modem !!! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364
Peter Hurleyd41861c2016-04-09 17:53:25 -07001365 tty_port_set_initialized(&info->port, 1);
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001366
1367 clear_bit(TTY_IO_ERROR, &tty->flags);
1368 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1369 info->breakon = info->breakoff = 0;
1370 memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
1371 info->idle_stats.in_use =
1372 info->idle_stats.recv_idle =
1373 info->idle_stats.xmit_idle = jiffies;
1374
1375 spin_unlock_irqrestore(&card->card_lock, flags);
1376
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001378 printk(KERN_DEBUG "cyc startup done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379#endif
1380 return 0;
1381
1382errout:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001383 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001384 free_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08001386} /* startup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
Jiri Slaby02f11752006-12-08 02:39:28 -08001388static void start_xmit(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001390 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001391 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001392 int channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
Jiri Slaby2693f482009-06-11 12:31:06 +01001394 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001395 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001396 cyy_writeb(info, CyCAR, channel & 0x03);
1397 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001398 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001399 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08001401 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001403 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07001404 retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001405 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001406 printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "
1407 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001408 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001409 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001410#else /* CONFIG_CYZ_INTR */
1411 /* Don't have to do anything at this time */
1412#endif /* CONFIG_CYZ_INTR */
1413 }
1414} /* start_xmit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415
1416/*
1417 * This routine shuts down a serial port; interrupts are disabled,
1418 * and DTR is dropped if the hangup on close termio flag is on.
1419 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001420static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421{
Jiri Slaby875b2062007-05-08 00:36:49 -07001422 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001423 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424
Peter Hurleyd41861c2016-04-09 17:53:25 -07001425 if (!tty_port_initialized(&info->port))
Jiri Slaby02f11752006-12-08 02:39:28 -08001426 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
Jiri Slaby02f11752006-12-08 02:39:28 -08001428 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01001429 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001430 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001431
1432 /* Clear delta_msr_wait queue to avoid mem leaks. */
Alan Coxbdc04e32009-09-19 13:13:31 -07001433 wake_up_interruptible(&info->port.delta_msr_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001434
Alan Cox77451e52008-07-16 21:57:02 +01001435 if (info->port.xmit_buf) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001436 unsigned char *temp;
Alan Cox77451e52008-07-16 21:57:02 +01001437 temp = info->port.xmit_buf;
1438 info->port.xmit_buf = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08001439 free_page((unsigned long)temp);
1440 }
Peter Hurley9db276f2016-01-10 20:36:15 -08001441 if (C_HUPCL(tty))
Jiri Slaby4d768202009-09-19 13:13:15 -07001442 cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);
1443
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001444 cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR);
Jiri Slaby02f11752006-12-08 02:39:28 -08001445 /* it may be appropriate to clear _XMIT at
1446 some later date (after testing)!!! */
1447
Jiri Slabyd13549f2009-09-19 13:13:12 -07001448 set_bit(TTY_IO_ERROR, &tty->flags);
Peter Hurleyd41861c2016-04-09 17:53:25 -07001449 tty_port_set_initialized(&info->port, 0);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001450 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001451 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08001452#ifdef CY_DEBUG_OPEN
Jiri Slaby0e7f4192011-03-23 09:49:56 +01001453 int channel = info->line - card->first_line;
Jiri Slaby21719192007-05-08 00:36:42 -07001454 printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001455 "base_addr %p\n", card, channel, card->base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001456#endif
1457
Jiri Slaby2693f482009-06-11 12:31:06 +01001458 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08001459 return;
Jiri Slaby02f11752006-12-08 02:39:28 -08001460
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001461 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001462
Alan Cox77451e52008-07-16 21:57:02 +01001463 if (info->port.xmit_buf) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001464 unsigned char *temp;
Alan Cox77451e52008-07-16 21:57:02 +01001465 temp = info->port.xmit_buf;
1466 info->port.xmit_buf = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08001467 free_page((unsigned long)temp);
1468 }
1469
Peter Hurley9db276f2016-01-10 20:36:15 -08001470 if (C_HUPCL(tty))
Jiri Slaby4d768202009-09-19 13:13:15 -07001471 tty_port_lower_dtr_rts(&info->port);
Jiri Slaby02f11752006-12-08 02:39:28 -08001472
Jiri Slabyd13549f2009-09-19 13:13:12 -07001473 set_bit(TTY_IO_ERROR, &tty->flags);
Peter Hurleyd41861c2016-04-09 17:53:25 -07001474 tty_port_set_initialized(&info->port, 0);
Jiri Slaby02f11752006-12-08 02:39:28 -08001475
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001476 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001477 }
1478
1479#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001480 printk(KERN_DEBUG "cyc shutdown done\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001481#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001482} /* shutdown */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
1484/*
1485 * ------------------------------------------------------------
1486 * cy_open() and friends
1487 * ------------------------------------------------------------
1488 */
1489
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490/*
1491 * This routine is called whenever a serial port is opened. It
1492 * performs the serial-specific initialization for the tty structure.
1493 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001494static int cy_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495{
Jiri Slaby02f11752006-12-08 02:39:28 -08001496 struct cyclades_port *info;
Jiri Slaby410235f2012-03-05 14:52:01 +01001497 unsigned int i, line = tty->index;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001498 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499
Jiri Slabydd025c02007-05-08 00:37:02 -07001500 for (i = 0; i < NR_CARDS; i++)
1501 if (line < cy_card[i].first_line + cy_card[i].nports &&
1502 line >= cy_card[i].first_line)
1503 break;
1504 if (i >= NR_CARDS)
1505 return -ENODEV;
1506 info = &cy_card[i].ports[line - cy_card[i].first_line];
Alan Cox15ed6cc2008-04-30 00:53:55 -07001507 if (info->line < 0)
Jiri Slaby02f11752006-12-08 02:39:28 -08001508 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08001509
1510 /* If the card's firmware hasn't been loaded,
1511 treat it as absent from the system. This
1512 will make the user pay attention.
1513 */
Jiri Slaby2693f482009-06-11 12:31:06 +01001514 if (cy_is_Z(info->card)) {
Jiri Slaby875b2062007-05-08 00:36:49 -07001515 struct cyclades_card *cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001516 struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
1517
Jiri Slaby2693f482009-06-11 12:31:06 +01001518 if (!cyz_is_loaded(cinfo)) {
1519 if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
Jiri Slaby101b8152009-06-11 12:30:10 +01001520 readl(&firm_id->signature) ==
1521 ZFIRM_HLT) {
Jiri Slaby21719192007-05-08 00:36:42 -07001522 printk(KERN_ERR "cyc:Cyclades-Z Error: you "
1523 "need an external power supply for "
1524 "this number of ports.\nFirmware "
1525 "halted.\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001526 } else {
Jiri Slaby21719192007-05-08 00:36:42 -07001527 printk(KERN_ERR "cyc:Cyclades-Z firmware not "
1528 "yet loaded\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001529 }
1530 return -ENODEV;
1531 }
1532#ifdef CONFIG_CYZ_INTR
1533 else {
1534 /* In case this Z board is operating in interrupt mode, its
1535 interrupts should be enabled as soon as the first open
1536 happens to one of its ports. */
1537 if (!cinfo->intr_enabled) {
Jiri Slaby97e87f82009-06-11 12:29:27 +01001538 u16 intr;
Jiri Slaby02f11752006-12-08 02:39:28 -08001539
Jiri Slaby02f11752006-12-08 02:39:28 -08001540 /* Enable interrupts on the PLX chip */
Jiri Slaby97e87f82009-06-11 12:29:27 +01001541 intr = readw(&cinfo->ctl_addr.p9060->
1542 intr_ctrl_stat) | 0x0900;
1543 cy_writew(&cinfo->ctl_addr.p9060->
1544 intr_ctrl_stat, intr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001545 /* Enable interrupts on the FW */
1546 retval = cyz_issue_cmd(cinfo, 0,
1547 C_CM_IRQ_ENBL, 0L);
1548 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001549 printk(KERN_ERR "cyc:IRQ enable retval "
1550 "was %x\n", retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001551 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001552 cinfo->intr_enabled = 1;
1553 }
1554 }
1555#endif /* CONFIG_CYZ_INTR */
1556 /* Make sure this Z port really exists in hardware */
1557 if (info->line > (cinfo->first_line + cinfo->nports - 1))
1558 return -ENODEV;
1559 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07001561 printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001563 tty->driver_data = info;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001564 if (serial_paranoia_check(info, tty->name, "cy_open"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001565 return -ENODEV;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001566
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001568 printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
Alan Cox77451e52008-07-16 21:57:02 +01001569 info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570#endif
Alan Cox77451e52008-07-16 21:57:02 +01001571 info->port.count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572#ifdef CY_DEBUG_COUNT
Jiri Slaby21719192007-05-08 00:36:42 -07001573 printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
Alan Cox77451e52008-07-16 21:57:02 +01001574 current->pid, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576
Jiri Slaby02f11752006-12-08 02:39:28 -08001577 /*
Jiri Slaby02f11752006-12-08 02:39:28 -08001578 * Start up serial port
1579 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001580 retval = cy_startup(info, tty);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001581 if (retval)
Jiri Slaby02f11752006-12-08 02:39:28 -08001582 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
Jiri Slabyf0737572009-09-19 13:13:12 -07001584 retval = tty_port_block_til_ready(&info->port, tty, filp);
Jiri Slaby02f11752006-12-08 02:39:28 -08001585 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001587 printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
1588 "with %d\n", retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001590 return retval;
1591 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592
Jiri Slaby02f11752006-12-08 02:39:28 -08001593 info->throttle = 0;
Jiri Slabyd13549f2009-09-19 13:13:12 -07001594 tty_port_tty_set(&info->port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595
1596#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001597 printk(KERN_DEBUG "cyc:cy_open done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001599 return 0;
1600} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601
1602/*
1603 * cy_wait_until_sent() --- wait until the transmitter is empty
1604 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001605static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606{
Jiri Slaby875b2062007-05-08 00:36:49 -07001607 struct cyclades_card *card;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001608 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001609 unsigned long orig_jiffies;
1610 int char_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611
Jiri Slaby02f11752006-12-08 02:39:28 -08001612 if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
1613 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614
Jiri Slaby02f11752006-12-08 02:39:28 -08001615 if (info->xmit_fifo_size == 0)
1616 return; /* Just in case.... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617
Jiri Slaby02f11752006-12-08 02:39:28 -08001618 orig_jiffies = jiffies;
1619 /*
1620 * Set the check interval to be 1/5 of the estimated time to
1621 * send a single character, and make it at least 1. The check
1622 * interval should also be less than the timeout.
1623 *
1624 * Note: we have to use pretty tight timings here to satisfy
1625 * the NIST-PCTS.
1626 */
1627 char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
1628 char_time = char_time / 5;
1629 if (char_time <= 0)
1630 char_time = 1;
1631 if (timeout < 0)
1632 timeout = 0;
1633 if (timeout)
1634 char_time = min(char_time, timeout);
1635 /*
1636 * If the transmitter hasn't cleared in twice the approximate
1637 * amount of time to send the entire FIFO, it probably won't
1638 * ever clear. This assumes the UART isn't doing flow
1639 * control, which is currently the case. Hence, if it ever
1640 * takes longer than info->timeout, this is probably due to a
1641 * UART bug of some kind. So, we clamp the timeout parameter at
1642 * 2*info->timeout.
1643 */
1644 if (!timeout || timeout > 2 * info->timeout)
1645 timeout = 2 * info->timeout;
Jiri Slaby8bab5342011-07-14 14:35:15 +02001646
Jiri Slaby02f11752006-12-08 02:39:28 -08001647 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01001648 if (!cy_is_Z(card)) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001649 while (cyy_readb(info, CySRER) & CyTxRdy) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001650 if (msleep_interruptible(jiffies_to_msecs(char_time)))
1651 break;
1652 if (timeout && time_after(jiffies, orig_jiffies +
1653 timeout))
1654 break;
1655 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001657 /* Run one more char cycle */
1658 msleep_interruptible(jiffies_to_msecs(char_time * 5));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659}
1660
Alan Cox978e5952008-04-30 00:53:59 -07001661static void cy_flush_buffer(struct tty_struct *tty)
1662{
1663 struct cyclades_port *info = tty->driver_data;
1664 struct cyclades_card *card;
1665 int channel, retval;
1666 unsigned long flags;
1667
1668#ifdef CY_DEBUG_IO
1669 printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
1670#endif
1671
1672 if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1673 return;
1674
1675 card = info->card;
1676 channel = info->line - card->first_line;
1677
1678 spin_lock_irqsave(&card->card_lock, flags);
1679 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1680 spin_unlock_irqrestore(&card->card_lock, flags);
1681
Jiri Slaby2693f482009-06-11 12:31:06 +01001682 if (cy_is_Z(card)) { /* If it is a Z card, flush the on-board
Alan Cox978e5952008-04-30 00:53:59 -07001683 buffers as well */
1684 spin_lock_irqsave(&card->card_lock, flags);
1685 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
1686 if (retval != 0) {
1687 printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
1688 "was %x\n", info->line, retval);
1689 }
1690 spin_unlock_irqrestore(&card->card_lock, flags);
1691 }
1692 tty_wakeup(tty);
1693} /* cy_flush_buffer */
1694
1695
Alan Coxe936ffd2009-09-19 13:13:22 -07001696static void cy_do_close(struct tty_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697{
Alan Coxe936ffd2009-09-19 13:13:22 -07001698 struct cyclades_port *info = container_of(port, struct cyclades_port,
1699 port);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001700 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001701 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001702 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001704 card = info->card;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001705 channel = info->line - card->first_line;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001706 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001707
Jiri Slaby2693f482009-06-11 12:31:06 +01001708 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001709 /* Stop accepting input */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001710 cyy_writeb(info, CyCAR, channel & 0x03);
1711 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData);
Peter Hurleyd41861c2016-04-09 17:53:25 -07001712 if (tty_port_initialized(&info->port)) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07001713 /* Waiting for on-board buffers to be empty before
1714 closing the port */
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001715 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Coxe936ffd2009-09-19 13:13:22 -07001716 cy_wait_until_sent(port->tty, info->timeout);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001717 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001718 }
1719 } else {
1720#ifdef Z_WAKE
Alan Cox15ed6cc2008-04-30 00:53:55 -07001721 /* Waiting for on-board buffers to be empty before closing
1722 the port */
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001723 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001724 int retval;
1725
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001726 if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001727 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001728 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001729 printk(KERN_DEBUG "cyc:cy_close retval on "
1730 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001731 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001732 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby2c7fea92007-05-08 00:36:51 -07001733 wait_for_completion_interruptible(&info->shutdown_wait);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001734 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001735 }
1736#endif
1737 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001738 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Coxe936ffd2009-09-19 13:13:22 -07001739 cy_shutdown(info, port->tty);
1740}
Jiri Slaby02f11752006-12-08 02:39:28 -08001741
Alan Coxe936ffd2009-09-19 13:13:22 -07001742/*
1743 * This routine is called when a particular tty device is closed.
1744 */
1745static void cy_close(struct tty_struct *tty, struct file *filp)
1746{
1747 struct cyclades_port *info = tty->driver_data;
1748 if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
1749 return;
1750 tty_port_close(&info->port, tty, filp);
Jiri Slaby02f11752006-12-08 02:39:28 -08001751} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752
1753/* This routine gets called when tty_write has put something into
1754 * the write_queue. The characters may come from user space or
1755 * kernel space.
1756 *
1757 * This routine will return the number of characters actually
1758 * accepted for writing.
1759 *
1760 * If the port is not already transmitting stuff, start it off by
1761 * enabling interrupts. The interrupt service routine will then
1762 * ensure that the characters are sent.
1763 * If the port is already active, there is no need to kick it.
1764 *
1765 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001766static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001768 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001769 unsigned long flags;
1770 int c, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771
1772#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001773 printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774#endif
1775
Alan Cox15ed6cc2008-04-30 00:53:55 -07001776 if (serial_paranoia_check(info, tty->name, "cy_write"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001777 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778
Alan Cox77451e52008-07-16 21:57:02 +01001779 if (!info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001780 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001782 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001783 while (1) {
Harvey Harrison1a4e2352008-04-30 00:53:52 -07001784 c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
1785 c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786
Jiri Slaby02f11752006-12-08 02:39:28 -08001787 if (c <= 0)
1788 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789
Alan Cox77451e52008-07-16 21:57:02 +01001790 memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
Jiri Slaby02f11752006-12-08 02:39:28 -08001791 info->xmit_head = (info->xmit_head + c) &
1792 (SERIAL_XMIT_SIZE - 1);
1793 info->xmit_cnt += c;
1794 buf += c;
1795 count -= c;
1796 ret += c;
1797 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001798 spin_unlock_irqrestore(&info->card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799
Jiri Slaby02f11752006-12-08 02:39:28 -08001800 info->idle_stats.xmit_bytes += ret;
1801 info->idle_stats.xmit_idle = jiffies;
1802
Alan Cox15ed6cc2008-04-30 00:53:55 -07001803 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
Jiri Slaby02f11752006-12-08 02:39:28 -08001804 start_xmit(info);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001805
Jiri Slaby02f11752006-12-08 02:39:28 -08001806 return ret;
1807} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808
1809/*
1810 * This routine is called by the kernel to write a single
1811 * character to the tty device. If the kernel uses this routine,
1812 * it must call the flush_chars() routine (if defined) when it is
1813 * done stuffing characters into the driver. If there is no room
1814 * in the queue, the character is ignored.
1815 */
Alan Cox76b25a52008-04-30 00:54:03 -07001816static int cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001818 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001819 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820
1821#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001822 printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823#endif
1824
Jiri Slaby02f11752006-12-08 02:39:28 -08001825 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
Alan Cox76b25a52008-04-30 00:54:03 -07001826 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827
Alan Cox77451e52008-07-16 21:57:02 +01001828 if (!info->port.xmit_buf)
Alan Cox76b25a52008-04-30 00:54:03 -07001829 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001831 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby90cc3012006-12-08 02:39:31 -08001832 if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001833 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001834 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08001835 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836
Alan Cox77451e52008-07-16 21:57:02 +01001837 info->port.xmit_buf[info->xmit_head++] = ch;
Jiri Slaby02f11752006-12-08 02:39:28 -08001838 info->xmit_head &= SERIAL_XMIT_SIZE - 1;
1839 info->xmit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 info->idle_stats.xmit_bytes++;
1841 info->idle_stats.xmit_idle = jiffies;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001842 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001843 return 1;
Jiri Slaby02f11752006-12-08 02:39:28 -08001844} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845
1846/*
1847 * This routine is called by the kernel after it has written a
Alan Cox15ed6cc2008-04-30 00:53:55 -07001848 * series of characters to the tty device using put_char().
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001850static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001852 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001853
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001855 printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856#endif
1857
Jiri Slaby02f11752006-12-08 02:39:28 -08001858 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
1859 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860
Jiri Slaby02f11752006-12-08 02:39:28 -08001861 if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
Alan Cox77451e52008-07-16 21:57:02 +01001862 !info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001863 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864
Jiri Slaby02f11752006-12-08 02:39:28 -08001865 start_xmit(info);
1866} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867
1868/*
1869 * This routine returns the numbers of characters the tty driver
1870 * will accept for queuing to be written. This number is subject
1871 * to change as output buffers get emptied, or if the output flow
1872 * control is activated.
1873 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001874static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001876 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001877 int ret;
1878
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001880 printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881#endif
1882
Jiri Slaby02f11752006-12-08 02:39:28 -08001883 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
1884 return 0;
1885 ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
1886 if (ret < 0)
1887 ret = 0;
1888 return ret;
1889} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890
Jiri Slaby02f11752006-12-08 02:39:28 -08001891static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001893 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894
Jiri Slaby02f11752006-12-08 02:39:28 -08001895 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
1896 return 0;
1897
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001899 if (!cy_is_Z(info->card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001900#endif /* Z_EXT_CHARS_IN_BUFFER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001902 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
1903 info->line, info->xmit_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001905 return info->xmit_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slaby02f11752006-12-08 02:39:28 -08001907 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001908 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001909 int char_count;
Jiri Slabyad39c302007-05-08 00:35:49 -07001910 __u32 tx_put, tx_get, tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001912 tx_get = readl(&buf_ctrl->tx_get);
1913 tx_put = readl(&buf_ctrl->tx_put);
1914 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
Jiri Slaby02f11752006-12-08 02:39:28 -08001915 if (tx_put >= tx_get)
1916 char_count = tx_put - tx_get;
1917 else
1918 char_count = tx_put - tx_get + tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001920 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
1921 info->line, info->xmit_cnt + char_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922#endif
Jiri Slaby096dcfc2006-12-08 02:39:30 -08001923 return info->xmit_cnt + char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -08001924 }
1925#endif /* Z_EXT_CHARS_IN_BUFFER */
1926} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927
1928/*
1929 * ------------------------------------------------------------
1930 * cy_ioctl() and friends
1931 * ------------------------------------------------------------
1932 */
1933
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001934static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935{
Jiri Slaby02f11752006-12-08 02:39:28 -08001936 int co, co_val, bpr;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001937 __u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
Jiri Slaby02f11752006-12-08 02:39:28 -08001938 25000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939
Jiri Slaby02f11752006-12-08 02:39:28 -08001940 if (baud == 0) {
1941 info->tbpr = info->tco = info->rbpr = info->rco = 0;
1942 return;
1943 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944
Jiri Slaby02f11752006-12-08 02:39:28 -08001945 /* determine which prescaler to use */
1946 for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
1947 if (cy_clock / co_val / baud > 63)
1948 break;
1949 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950
Jiri Slaby02f11752006-12-08 02:39:28 -08001951 bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
1952 if (bpr > 255)
1953 bpr = 255;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954
Jiri Slaby02f11752006-12-08 02:39:28 -08001955 info->tbpr = info->rbpr = bpr;
1956 info->tco = info->rco = co;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957}
1958
1959/*
1960 * This routine finds or computes the various line characteristics.
1961 * It used to be called config_setup
1962 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001963static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964{
Jiri Slaby875b2062007-05-08 00:36:49 -07001965 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001966 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001967 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08001968 unsigned cflag, iflag;
Jiri Slaby02f11752006-12-08 02:39:28 -08001969 int baud, baud_rate = 0;
1970 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971
Alan Cox15ed6cc2008-04-30 00:53:55 -07001972 if (info->line == -1)
Jiri Slaby02f11752006-12-08 02:39:28 -08001973 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001974
Alan Coxadc8d742012-07-14 15:31:47 +01001975 cflag = tty->termios.c_cflag;
1976 iflag = tty->termios.c_iflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977
Jiri Slaby02f11752006-12-08 02:39:28 -08001978 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001979 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08001980
Jiri Slaby2693f482009-06-11 12:31:06 +01001981 if (!cy_is_Z(card)) {
Jiri Slaby46fb7822009-09-19 13:13:17 -07001982 u32 cflags;
1983
Jiri Slaby02f11752006-12-08 02:39:28 -08001984 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001985 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01001986 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08001987 ASYNC_SPD_CUST) {
1988 if (info->custom_divisor)
1989 baud_rate = info->baud / info->custom_divisor;
1990 else
1991 baud_rate = info->baud;
1992 } else if (baud > CD1400_MAX_SPEED) {
1993 baud = CD1400_MAX_SPEED;
1994 }
1995 /* find the baud index */
1996 for (i = 0; i < 20; i++) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07001997 if (baud == baud_table[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08001998 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08001999 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002000 if (i == 20)
Jiri Slaby02f11752006-12-08 02:39:28 -08002001 i = 19; /* CD1400_MAX_SPEED */
Jiri Slaby02f11752006-12-08 02:39:28 -08002002
Alan Cox77451e52008-07-16 21:57:02 +01002003 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002004 ASYNC_SPD_CUST) {
2005 cyy_baud_calc(info, baud_rate);
2006 } else {
2007 if (info->chip_rev >= CD1400_REV_J) {
2008 /* It is a CD1400 rev. J or later */
2009 info->tbpr = baud_bpr_60[i]; /* Tx BPR */
2010 info->tco = baud_co_60[i]; /* Tx CO */
2011 info->rbpr = baud_bpr_60[i]; /* Rx BPR */
2012 info->rco = baud_co_60[i]; /* Rx CO */
2013 } else {
2014 info->tbpr = baud_bpr_25[i]; /* Tx BPR */
2015 info->tco = baud_co_25[i]; /* Tx CO */
2016 info->rbpr = baud_bpr_25[i]; /* Rx BPR */
2017 info->rco = baud_co_25[i]; /* Rx CO */
2018 }
2019 }
2020 if (baud_table[i] == 134) {
2021 /* get it right for 134.5 baud */
2022 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2023 2;
Alan Cox77451e52008-07-16 21:57:02 +01002024 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002025 ASYNC_SPD_CUST) {
2026 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2027 baud_rate) + 2;
2028 } else if (baud_table[i]) {
2029 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2030 baud_table[i]) + 2;
2031 /* this needs to be propagated into the card info */
2032 } else {
2033 info->timeout = 0;
2034 }
2035 /* By tradition (is it a standard?) a baud rate of zero
2036 implies the line should be/has been closed. A bit
2037 later in this routine such a test is performed. */
2038
2039 /* byte size and parity */
2040 info->cor5 = 0;
2041 info->cor4 = 0;
2042 /* receive threshold */
2043 info->cor3 = (info->default_threshold ?
2044 info->default_threshold : baud_cor3[i]);
2045 info->cor2 = CyETC;
2046 switch (cflag & CSIZE) {
2047 case CS5:
2048 info->cor1 = Cy_5_BITS;
2049 break;
2050 case CS6:
2051 info->cor1 = Cy_6_BITS;
2052 break;
2053 case CS7:
2054 info->cor1 = Cy_7_BITS;
2055 break;
2056 case CS8:
2057 info->cor1 = Cy_8_BITS;
2058 break;
2059 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002060 if (cflag & CSTOPB)
Jiri Slaby02f11752006-12-08 02:39:28 -08002061 info->cor1 |= Cy_2_STOP;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002062
Jiri Slaby02f11752006-12-08 02:39:28 -08002063 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002064 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002065 info->cor1 |= CyPARITY_O;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002066 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002067 info->cor1 |= CyPARITY_E;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002068 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002069 info->cor1 |= CyPARITY_NONE;
Jiri Slaby02f11752006-12-08 02:39:28 -08002070
2071 /* CTS flow control flag */
Peter Hurley5604a982016-04-09 17:53:21 -07002072 tty_port_set_cts_flow(&info->port, cflag & CRTSCTS);
2073 if (cflag & CRTSCTS)
Jiri Slaby02f11752006-12-08 02:39:28 -08002074 info->cor2 |= CyCtsAE;
Peter Hurley5604a982016-04-09 17:53:21 -07002075 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002076 info->cor2 &= ~CyCtsAE;
Peter Hurley2d686552016-04-09 17:53:23 -07002077 tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078
2079 /***********************************************
2080 The hardware option, CyRtsAO, presents RTS when
2081 the chip has characters to send. Since most modems
2082 use RTS as reverse (inbound) flow control, this
2083 option is not used. If inbound flow control is
2084 necessary, DTR can be programmed to provide the
2085 appropriate signals for use with a non-standard
2086 cable. Contact Marcio Saito for details.
2087 ***********************************************/
2088
Jiri Slaby02f11752006-12-08 02:39:28 -08002089 channel &= 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002091 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002092 cyy_writeb(info, CyCAR, channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093
Jiri Slaby02f11752006-12-08 02:39:28 -08002094 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002096 cyy_writeb(info, CyTCOR, info->tco);
2097 cyy_writeb(info, CyTBPR, info->tbpr);
2098 cyy_writeb(info, CyRCOR, info->rco);
2099 cyy_writeb(info, CyRBPR, info->rbpr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100
Jiri Slaby02f11752006-12-08 02:39:28 -08002101 /* set line characteristics according configuration */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002103 cyy_writeb(info, CySCHR1, START_CHAR(tty));
2104 cyy_writeb(info, CySCHR2, STOP_CHAR(tty));
2105 cyy_writeb(info, CyCOR1, info->cor1);
2106 cyy_writeb(info, CyCOR2, info->cor2);
2107 cyy_writeb(info, CyCOR3, info->cor3);
2108 cyy_writeb(info, CyCOR4, info->cor4);
2109 cyy_writeb(info, CyCOR5, info->cor5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002111 cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
2112 CyCOR3ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113
Alan Cox15ed6cc2008-04-30 00:53:55 -07002114 /* !!! Is this needed? */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002115 cyy_writeb(info, CyCAR, channel);
2116 cyy_writeb(info, CyRTPR,
Jiri Slaby02f11752006-12-08 02:39:28 -08002117 (info->default_timeout ? info->default_timeout : 0x02));
2118 /* 10ms rx timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119
Jiri Slaby46fb7822009-09-19 13:13:17 -07002120 cflags = CyCTS;
2121 if (!C_CLOCAL(tty))
2122 cflags |= CyDSR | CyRI | CyDCD;
2123 /* without modem intr */
2124 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyMdmCh);
2125 /* act on 1->0 modem transitions */
2126 if ((cflag & CRTSCTS) && info->rflow)
2127 cyy_writeb(info, CyMCOR1, cflags | rflow_thr[i]);
2128 else
2129 cyy_writeb(info, CyMCOR1, cflags);
2130 /* act on 0->1 modem transitions */
2131 cyy_writeb(info, CyMCOR2, cflags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002132
Jiri Slaby4d768202009-09-19 13:13:15 -07002133 if (i == 0) /* baud rate is zero, turn off line */
2134 cyy_change_rts_dtr(info, 0, TIOCM_DTR);
2135 else
2136 cyy_change_rts_dtr(info, TIOCM_DTR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137
Jiri Slabyd13549f2009-09-19 13:13:12 -07002138 clear_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002139 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002142 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002143 __u32 sw_flow;
Jiri Slaby02f11752006-12-08 02:39:28 -08002144 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145
Jiri Slaby2693f482009-06-11 12:31:06 +01002146 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002147 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148
Jiri Slaby02f11752006-12-08 02:39:28 -08002149 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002150 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002151 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002152 ASYNC_SPD_CUST) {
2153 if (info->custom_divisor)
2154 baud_rate = info->baud / info->custom_divisor;
2155 else
2156 baud_rate = info->baud;
2157 } else if (baud > CYZ_MAX_SPEED) {
2158 baud = CYZ_MAX_SPEED;
2159 }
2160 cy_writel(&ch_ctrl->comm_baud, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161
Jiri Slaby02f11752006-12-08 02:39:28 -08002162 if (baud == 134) {
2163 /* get it right for 134.5 baud */
2164 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2165 2;
Alan Cox77451e52008-07-16 21:57:02 +01002166 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002167 ASYNC_SPD_CUST) {
2168 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2169 baud_rate) + 2;
2170 } else if (baud) {
2171 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2172 baud) + 2;
2173 /* this needs to be propagated into the card info */
2174 } else {
2175 info->timeout = 0;
2176 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177
Jiri Slaby02f11752006-12-08 02:39:28 -08002178 /* byte size and parity */
2179 switch (cflag & CSIZE) {
2180 case CS5:
2181 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
2182 break;
2183 case CS6:
2184 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
2185 break;
2186 case CS7:
2187 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
2188 break;
2189 case CS8:
2190 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
2191 break;
2192 }
2193 if (cflag & CSTOPB) {
2194 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002195 readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002196 } else {
2197 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002198 readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002199 }
2200 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002201 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002202 cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002203 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002204 cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002205 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002206 cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207
Jiri Slaby02f11752006-12-08 02:39:28 -08002208 /* CTS flow control flag */
2209 if (cflag & CRTSCTS) {
2210 cy_writel(&ch_ctrl->hw_flow,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002211 readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
Jiri Slaby02f11752006-12-08 02:39:28 -08002212 } else {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002213 cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
2214 ~(C_RS_CTS | C_RS_RTS));
Jiri Slaby02f11752006-12-08 02:39:28 -08002215 }
2216 /* As the HW flow control is done in firmware, the driver
2217 doesn't need to care about it */
Peter Hurley5604a982016-04-09 17:53:21 -07002218 tty_port_set_cts_flow(&info->port, 0);
Jiri Slaby02f11752006-12-08 02:39:28 -08002219
2220 /* XON/XOFF/XANY flow control flags */
2221 sw_flow = 0;
2222 if (iflag & IXON) {
2223 sw_flow |= C_FL_OXX;
2224 if (iflag & IXANY)
2225 sw_flow |= C_FL_OIXANY;
2226 }
2227 cy_writel(&ch_ctrl->sw_flow, sw_flow);
2228
Jiri Slaby875b2062007-05-08 00:36:49 -07002229 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002230 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002231 printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
2232 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002233 }
2234
2235 /* CD sensitivity */
Peter Hurley2d686552016-04-09 17:53:23 -07002236 tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
Jiri Slaby02f11752006-12-08 02:39:28 -08002237
2238 if (baud == 0) { /* baud rate is zero, turn off line */
2239 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002240 readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002242 printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002244 } else {
2245 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002246 readl(&ch_ctrl->rs_control) | C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002248 printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002250 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251
Alan Cox15ed6cc2008-04-30 00:53:55 -07002252 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002253 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002254 printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
2255 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002256 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257
Jiri Slabyd13549f2009-09-19 13:13:12 -07002258 clear_bit(TTY_IO_ERROR, &tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002260} /* set_line_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261
Jiri Slaby6c281812009-09-19 13:13:15 -07002262static int cy_get_serial_info(struct cyclades_port *info,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002263 struct serial_struct __user *retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264{
Jiri Slaby875b2062007-05-08 00:36:49 -07002265 struct cyclades_card *cinfo = info->card;
Jiri Slaby6c281812009-09-19 13:13:15 -07002266 struct serial_struct tmp = {
2267 .type = info->type,
2268 .line = info->line,
2269 .port = (info->card - cy_card) * 0x100 + info->line -
2270 cinfo->first_line,
2271 .irq = cinfo->irq,
2272 .flags = info->port.flags,
2273 .close_delay = info->port.close_delay,
2274 .closing_wait = info->port.closing_wait,
2275 .baud_base = info->baud,
2276 .custom_divisor = info->custom_divisor,
Jiri Slaby6c281812009-09-19 13:13:15 -07002277 };
Jiri Slaby02f11752006-12-08 02:39:28 -08002278 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
Jiri Slaby6c281812009-09-19 13:13:15 -07002279}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280
2281static int
Jiri Slabyd13549f2009-09-19 13:13:12 -07002282cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002283 struct serial_struct __user *new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284{
Jiri Slaby02f11752006-12-08 02:39:28 -08002285 struct serial_struct new_serial;
Johan Hovoldd1b8bc32017-06-06 12:54:38 +02002286 int old_flags;
Alan Cox25c3cdf2010-06-01 22:52:47 +02002287 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288
Jiri Slaby02f11752006-12-08 02:39:28 -08002289 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
2290 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291
Alan Cox25c3cdf2010-06-01 22:52:47 +02002292 mutex_lock(&info->port.mutex);
Johan Hovoldd1b8bc32017-06-06 12:54:38 +02002293
2294 old_flags = info->port.flags;
2295
Jiri Slaby02f11752006-12-08 02:39:28 -08002296 if (!capable(CAP_SYS_ADMIN)) {
Alan Cox44b7d1b2008-07-16 21:57:18 +01002297 if (new_serial.close_delay != info->port.close_delay ||
Jiri Slaby02f11752006-12-08 02:39:28 -08002298 new_serial.baud_base != info->baud ||
2299 (new_serial.flags & ASYNC_FLAGS &
2300 ~ASYNC_USR_MASK) !=
Alan Cox77451e52008-07-16 21:57:02 +01002301 (info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
Alan Cox25c3cdf2010-06-01 22:52:47 +02002302 {
2303 mutex_unlock(&info->port.mutex);
Jiri Slaby02f11752006-12-08 02:39:28 -08002304 return -EPERM;
Alan Cox25c3cdf2010-06-01 22:52:47 +02002305 }
Alan Cox77451e52008-07-16 21:57:02 +01002306 info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002307 (new_serial.flags & ASYNC_USR_MASK);
2308 info->baud = new_serial.baud_base;
2309 info->custom_divisor = new_serial.custom_divisor;
2310 goto check_and_exit;
2311 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312
Jiri Slaby02f11752006-12-08 02:39:28 -08002313 /*
2314 * OK, past this point, all the error checking has been done.
2315 * At this point, we start making changes.....
2316 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317
Jiri Slaby02f11752006-12-08 02:39:28 -08002318 info->baud = new_serial.baud_base;
2319 info->custom_divisor = new_serial.custom_divisor;
Alan Cox77451e52008-07-16 21:57:02 +01002320 info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002321 (new_serial.flags & ASYNC_FLAGS);
Alan Cox44b7d1b2008-07-16 21:57:18 +01002322 info->port.close_delay = new_serial.close_delay * HZ / 100;
2323 info->port.closing_wait = new_serial.closing_wait * HZ / 100;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324
2325check_and_exit:
Peter Hurleyd41861c2016-04-09 17:53:25 -07002326 if (tty_port_initialized(&info->port)) {
Johan Hovoldd1b8bc32017-06-06 12:54:38 +02002327 if ((new_serial.flags ^ old_flags) & ASYNC_SPD_MASK) {
2328 /* warn about deprecation unless clearing */
2329 if (new_serial.flags & ASYNC_SPD_MASK)
2330 dev_warn_ratelimited(tty->dev, "use of SPD flags is deprecated\n");
2331 }
Jiri Slabyd13549f2009-09-19 13:13:12 -07002332 cy_set_line_char(info, tty);
Alan Cox25c3cdf2010-06-01 22:52:47 +02002333 ret = 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002334 } else {
Alan Cox25c3cdf2010-06-01 22:52:47 +02002335 ret = cy_startup(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08002336 }
Alan Cox25c3cdf2010-06-01 22:52:47 +02002337 mutex_unlock(&info->port.mutex);
2338 return ret;
Jiri Slaby02f11752006-12-08 02:39:28 -08002339} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340
2341/*
2342 * get_lsr_info - get line status register info
2343 *
2344 * Purpose: Let user call ioctl() to get info when the UART physically
2345 * is emptied. On bus types like RS485, the transmitter must
2346 * release the bus after transmitting. This must be done when
2347 * the transmit shift register is empty, not be done when the
2348 * transmit holding register is empty. This functionality
2349 * allows an RS485 driver to be written in user space.
2350 */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002351static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002353 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002354 unsigned int result;
2355 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002356 u8 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357
Jiri Slaby2693f482009-06-11 12:31:06 +01002358 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002359 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002360 status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002361 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002362 result = (status ? 0 : TIOCSER_TEMT);
2363 } else {
2364 /* Not supported yet */
2365 return -EINVAL;
2366 }
Dan Carpenterdbca36e2012-03-05 21:07:11 +03002367 return put_user(result, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368}
2369
Alan Cox60b33c12011-02-14 16:26:14 +00002370static int cy_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002372 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002373 struct cyclades_card *card;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002374 int result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002376 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002377 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378
Jiri Slaby02f11752006-12-08 02:39:28 -08002379 card = info->card;
Jiri Slaby0d348722009-09-19 13:13:16 -07002380
Jiri Slaby2693f482009-06-11 12:31:06 +01002381 if (!cy_is_Z(card)) {
Jiri Slaby0d348722009-09-19 13:13:16 -07002382 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002383 int channel = info->line - card->first_line;
2384 u8 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002386 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002387 cyy_writeb(info, CyCAR, channel & 0x03);
2388 status = cyy_readb(info, CyMSVR1);
2389 status |= cyy_readb(info, CyMSVR2);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002390 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391
Jiri Slaby02f11752006-12-08 02:39:28 -08002392 if (info->rtsdtr_inv) {
2393 result = ((status & CyRTS) ? TIOCM_DTR : 0) |
2394 ((status & CyDTR) ? TIOCM_RTS : 0);
2395 } else {
2396 result = ((status & CyRTS) ? TIOCM_RTS : 0) |
2397 ((status & CyDTR) ? TIOCM_DTR : 0);
2398 }
2399 result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
2400 ((status & CyRI) ? TIOCM_RNG : 0) |
2401 ((status & CyDSR) ? TIOCM_DSR : 0) |
2402 ((status & CyCTS) ? TIOCM_CTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 } else {
Jiri Slaby0d348722009-09-19 13:13:16 -07002404 u32 lstatus;
2405
2406 if (!cyz_is_loaded(card)) {
2407 result = -ENODEV;
2408 goto end;
Jiri Slaby02f11752006-12-08 02:39:28 -08002409 }
2410
Jiri Slaby0d348722009-09-19 13:13:16 -07002411 lstatus = readl(&info->u.cyz.ch_ctrl->rs_status);
2412 result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
2413 ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
2414 ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
2415 ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
2416 ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
2417 ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 }
Jiri Slaby0d348722009-09-19 13:13:16 -07002419end:
Jiri Slaby02f11752006-12-08 02:39:28 -08002420 return result;
2421} /* cy_tiomget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422
2423static int
Alan Cox20b9d172011-02-14 16:26:50 +00002424cy_tiocmset(struct tty_struct *tty,
Jiri Slaby02f11752006-12-08 02:39:28 -08002425 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002427 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002428 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002429 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002431 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002432 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
Jiri Slaby02f11752006-12-08 02:39:28 -08002434 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01002435 if (!cy_is_Z(card)) {
Jiri Slaby4d768202009-09-19 13:13:15 -07002436 spin_lock_irqsave(&card->card_lock, flags);
2437 cyy_change_rts_dtr(info, set, clear);
2438 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002439 } else {
Jiri Slaby0d348722009-09-19 13:13:16 -07002440 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
2441 int retval, channel = info->line - card->first_line;
2442 u32 rs;
Jiri Slaby02f11752006-12-08 02:39:28 -08002443
Jiri Slaby0d348722009-09-19 13:13:16 -07002444 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002445 return -ENODEV;
Jiri Slaby0d348722009-09-19 13:13:16 -07002446
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002447 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby0d348722009-09-19 13:13:16 -07002448 rs = readl(&ch_ctrl->rs_control);
2449 if (set & TIOCM_RTS)
2450 rs |= C_RS_RTS;
2451 if (clear & TIOCM_RTS)
2452 rs &= ~C_RS_RTS;
2453 if (set & TIOCM_DTR) {
2454 rs |= C_RS_DTR;
2455#ifdef CY_DEBUG_DTR
2456 printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n");
2457#endif
2458 }
2459 if (clear & TIOCM_DTR) {
2460 rs &= ~C_RS_DTR;
2461#ifdef CY_DEBUG_DTR
2462 printk(KERN_DEBUG "cyc:set_modem_info clearing "
2463 "Z DTR\n");
2464#endif
2465 }
2466 cy_writel(&ch_ctrl->rs_control, rs);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002467 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby0d348722009-09-19 13:13:16 -07002468 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002469 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002470 printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
2471 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002474 return 0;
Jiri Slaby0d348722009-09-19 13:13:16 -07002475}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476
2477/*
2478 * cy_break() --- routine which turns the break handling on or off
2479 */
Alan Cox9e989662008-07-22 11:18:03 +01002480static int cy_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002482 struct cyclades_port *info = tty->driver_data;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002483 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002484 unsigned long flags;
Alan Cox9e989662008-07-22 11:18:03 +01002485 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486
Jiri Slaby02f11752006-12-08 02:39:28 -08002487 if (serial_paranoia_check(info, tty->name, "cy_break"))
Alan Cox9e989662008-07-22 11:18:03 +01002488 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002490 card = info->card;
2491
2492 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby2693f482009-06-11 12:31:06 +01002493 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002494 /* Let the transmit ISR take care of this (since it
2495 requires stuffing characters into the output stream).
2496 */
2497 if (break_state == -1) {
2498 if (!info->breakon) {
2499 info->breakon = 1;
2500 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002501 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002502 start_xmit(info);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002503 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002504 }
2505 }
2506 } else {
2507 if (!info->breakoff) {
2508 info->breakoff = 1;
2509 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002510 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002511 start_xmit(info);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002512 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002513 }
2514 }
2515 }
2516 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08002517 if (break_state == -1) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002518 retval = cyz_issue_cmd(card,
2519 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002520 C_CM_SET_BREAK, 0L);
2521 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002522 printk(KERN_ERR "cyc:cy_break (set) retval on "
2523 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002524 }
2525 } else {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002526 retval = cyz_issue_cmd(card,
2527 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002528 C_CM_CLR_BREAK, 0L);
2529 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002530 printk(KERN_DEBUG "cyc:cy_break (clr) retval "
2531 "on ttyC%d was %x\n", info->line,
2532 retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002533 }
2534 }
2535 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002536 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Cox9e989662008-07-22 11:18:03 +01002537 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08002538} /* cy_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539
Jiri Slaby02f11752006-12-08 02:39:28 -08002540static int set_threshold(struct cyclades_port *info, unsigned long value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002542 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002543 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544
Jiri Slaby2693f482009-06-11 12:31:06 +01002545 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002546 info->cor3 &= ~CyREC_FIFO;
2547 info->cor3 |= value & CyREC_FIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002549 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002550 cyy_writeb(info, CyCOR3, info->cor3);
2551 cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002552 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002553 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002555} /* set_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556
Alan Cox15ed6cc2008-04-30 00:53:55 -07002557static int get_threshold(struct cyclades_port *info,
2558 unsigned long __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002560 struct cyclades_card *card = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561
Jiri Slaby2693f482009-06-11 12:31:06 +01002562 if (!cy_is_Z(card)) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002563 u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO;
Jiri Slaby02f11752006-12-08 02:39:28 -08002564 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002565 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002566 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002567} /* get_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568
Jiri Slaby02f11752006-12-08 02:39:28 -08002569static int set_timeout(struct cyclades_port *info, unsigned long value)
2570{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002571 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002572 unsigned long flags;
2573
Jiri Slaby2693f482009-06-11 12:31:06 +01002574 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002575 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002576 cyy_writeb(info, CyRTPR, value & 0xff);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002577 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002578 }
2579 return 0;
2580} /* set_timeout */
2581
Alan Cox15ed6cc2008-04-30 00:53:55 -07002582static int get_timeout(struct cyclades_port *info,
2583 unsigned long __user *value)
Jiri Slaby02f11752006-12-08 02:39:28 -08002584{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002585 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002586
Jiri Slaby2693f482009-06-11 12:31:06 +01002587 if (!cy_is_Z(card)) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002588 u8 tmp = cyy_readb(info, CyRTPR);
Jiri Slaby02f11752006-12-08 02:39:28 -08002589 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002590 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002591 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002592} /* get_timeout */
2593
Jiri Slaby6c281812009-09-19 13:13:15 -07002594static int cy_cflags_changed(struct cyclades_port *info, unsigned long arg,
2595 struct cyclades_icount *cprev)
Jiri Slaby02f11752006-12-08 02:39:28 -08002596{
Jiri Slaby6c281812009-09-19 13:13:15 -07002597 struct cyclades_icount cnow;
2598 unsigned long flags;
2599 int ret;
Jiri Slaby02f11752006-12-08 02:39:28 -08002600
Jiri Slaby6c281812009-09-19 13:13:15 -07002601 spin_lock_irqsave(&info->card->card_lock, flags);
2602 cnow = info->icount; /* atomic copy */
2603 spin_unlock_irqrestore(&info->card->card_lock, flags);
2604
2605 ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
2606 ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
2607 ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) ||
2608 ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
2609
2610 *cprev = cnow;
2611
2612 return ret;
2613}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614
2615/*
2616 * This routine allows the tty driver to implement device-
2617 * specific ioctl's. If the ioctl number passed in cmd is
2618 * not recognized by the driver, it should return ENOIOCTLCMD.
2619 */
2620static int
Alan Cox6caa76b2011-02-14 16:27:22 +00002621cy_ioctl(struct tty_struct *tty,
Jiri Slaby02f11752006-12-08 02:39:28 -08002622 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002624 struct cyclades_port *info = tty->driver_data;
Jiri Slaby6c281812009-09-19 13:13:15 -07002625 struct cyclades_icount cnow; /* kernel counter temps */
Jiri Slaby02f11752006-12-08 02:39:28 -08002626 int ret_val = 0;
2627 unsigned long flags;
2628 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629
Jiri Slaby02f11752006-12-08 02:39:28 -08002630 if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
2631 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632
2633#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002634 printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
2635 info->line, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636#endif
2637
Jiri Slaby02f11752006-12-08 02:39:28 -08002638 switch (cmd) {
2639 case CYGETMON:
Jiri Slaby6c281812009-09-19 13:13:15 -07002640 if (copy_to_user(argp, &info->mon, sizeof(info->mon))) {
2641 ret_val = -EFAULT;
2642 break;
2643 }
2644 memset(&info->mon, 0, sizeof(info->mon));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002646 case CYGETTHRESH:
2647 ret_val = get_threshold(info, argp);
2648 break;
2649 case CYSETTHRESH:
2650 ret_val = set_threshold(info, arg);
2651 break;
2652 case CYGETDEFTHRESH:
Jiri Slaby6c281812009-09-19 13:13:15 -07002653 ret_val = put_user(info->default_threshold,
2654 (unsigned long __user *)argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002655 break;
2656 case CYSETDEFTHRESH:
Jiri Slaby6c281812009-09-19 13:13:15 -07002657 info->default_threshold = arg & 0x0f;
Jiri Slaby02f11752006-12-08 02:39:28 -08002658 break;
2659 case CYGETTIMEOUT:
2660 ret_val = get_timeout(info, argp);
2661 break;
2662 case CYSETTIMEOUT:
2663 ret_val = set_timeout(info, arg);
2664 break;
2665 case CYGETDEFTIMEOUT:
Jiri Slaby6c281812009-09-19 13:13:15 -07002666 ret_val = put_user(info->default_timeout,
2667 (unsigned long __user *)argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002668 break;
2669 case CYSETDEFTIMEOUT:
Jiri Slaby6c281812009-09-19 13:13:15 -07002670 info->default_timeout = arg & 0xff;
Jiri Slaby02f11752006-12-08 02:39:28 -08002671 break;
2672 case CYSETRFLOW:
2673 info->rflow = (int)arg;
Jiri Slaby02f11752006-12-08 02:39:28 -08002674 break;
2675 case CYGETRFLOW:
2676 ret_val = info->rflow;
2677 break;
2678 case CYSETRTSDTR_INV:
2679 info->rtsdtr_inv = (int)arg;
Jiri Slaby02f11752006-12-08 02:39:28 -08002680 break;
2681 case CYGETRTSDTR_INV:
2682 ret_val = info->rtsdtr_inv;
2683 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 case CYGETCD1400VER:
Jiri Slaby02f11752006-12-08 02:39:28 -08002685 ret_val = info->chip_rev;
2686 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687#ifndef CONFIG_CYZ_INTR
2688 case CYZSETPOLLCYCLE:
Qixue Xiao351d6202013-12-20 17:51:12 +08002689 if (arg > LONG_MAX / HZ)
2690 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08002691 cyz_polling_cycle = (arg * HZ) / 1000;
Jiri Slaby02f11752006-12-08 02:39:28 -08002692 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 case CYZGETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08002694 ret_val = (cyz_polling_cycle * 1000) / HZ;
2695 break;
2696#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 case CYSETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002698 info->port.closing_wait = (unsigned short)arg * HZ / 100;
Jiri Slaby02f11752006-12-08 02:39:28 -08002699 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 case CYGETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002701 ret_val = info->port.closing_wait / (HZ / 100);
Jiri Slaby02f11752006-12-08 02:39:28 -08002702 break;
2703 case TIOCGSERIAL:
Jiri Slaby6c281812009-09-19 13:13:15 -07002704 ret_val = cy_get_serial_info(info, argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002705 break;
2706 case TIOCSSERIAL:
Jiri Slabyd13549f2009-09-19 13:13:12 -07002707 ret_val = cy_set_serial_info(info, tty, argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002708 break;
2709 case TIOCSERGETLSR: /* Get line status register */
2710 ret_val = get_lsr_info(info, argp);
2711 break;
2712 /*
2713 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
2714 * - mask passed in arg for lines of interest
2715 * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
2716 * Caller should use TIOCGICOUNT to see which one it was
2717 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 case TIOCMIWAIT:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002719 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002720 /* note the counters on entry */
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002721 cnow = info->icount;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002722 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Coxbdc04e32009-09-19 13:13:31 -07002723 ret_val = wait_event_interruptible(info->port.delta_msr_wait,
Jiri Slaby6c281812009-09-19 13:13:15 -07002724 cy_cflags_changed(info, arg, &cnow));
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002725 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002726
2727 /*
2728 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2729 * Return: write counters to the user passed counter struct
2730 * NB: both 1->0 and 0->1 transitions are counted except for
2731 * RI where only 0->1 is counted.
2732 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002733 default:
2734 ret_val = -ENOIOCTLCMD;
2735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736
2737#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002738 printk(KERN_DEBUG "cyc:cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002740 return ret_val;
2741} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742
Alan Cox05871022010-09-16 18:21:52 +01002743static int cy_get_icount(struct tty_struct *tty,
2744 struct serial_icounter_struct *sic)
2745{
2746 struct cyclades_port *info = tty->driver_data;
2747 struct cyclades_icount cnow; /* Used to snapshot */
2748 unsigned long flags;
2749
2750 spin_lock_irqsave(&info->card->card_lock, flags);
2751 cnow = info->icount;
2752 spin_unlock_irqrestore(&info->card->card_lock, flags);
2753
2754 sic->cts = cnow.cts;
2755 sic->dsr = cnow.dsr;
2756 sic->rng = cnow.rng;
2757 sic->dcd = cnow.dcd;
2758 sic->rx = cnow.rx;
2759 sic->tx = cnow.tx;
2760 sic->frame = cnow.frame;
2761 sic->overrun = cnow.overrun;
2762 sic->parity = cnow.parity;
2763 sic->brk = cnow.brk;
2764 sic->buf_overrun = cnow.buf_overrun;
2765 return 0;
2766}
2767
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768/*
2769 * This routine allows the tty driver to be notified when
2770 * device's termios settings have changed. Note that a
2771 * well-designed tty driver should be prepared to accept the case
2772 * where old == NULL, and try to do something rational.
2773 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002774static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002776 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777
2778#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002779 printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780#endif
2781
Jiri Slabyd13549f2009-09-19 13:13:12 -07002782 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783
Peter Hurley9db276f2016-01-10 20:36:15 -08002784 if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002785 tty->hw_stopped = 0;
2786 cy_start(tty);
2787 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788#if 0
Jiri Slaby02f11752006-12-08 02:39:28 -08002789 /*
2790 * No need to wake up processes in open wait, since they
2791 * sample the CLOCAL flag once, and don't recheck it.
2792 * XXX It's not clear whether the current behavior is correct
2793 * or not. Hence, this may change.....
2794 */
Peter Hurley9db276f2016-01-10 20:36:15 -08002795 if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
Alan Cox77451e52008-07-16 21:57:02 +01002796 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002798} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799
2800/* This function is used to send a high-priority XON/XOFF character to
2801 the device.
2802*/
Jiri Slaby02f11752006-12-08 02:39:28 -08002803static void cy_send_xchar(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002805 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002806 struct cyclades_card *card;
2807 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808
Jiri Slaby02f11752006-12-08 02:39:28 -08002809 if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 return;
2811
Jiri Slaby02f11752006-12-08 02:39:28 -08002812 info->x_char = ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813
2814 if (ch)
Jiri Slaby02f11752006-12-08 02:39:28 -08002815 cy_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816
2817 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002818 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819
Jiri Slaby2693f482009-06-11 12:31:06 +01002820 if (cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002821 if (ch == STOP_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07002822 cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002823 else if (ch == START_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07002824 cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 }
2826}
2827
2828/* This routine is called by the upper-layer tty layer to signal
2829 that incoming characters should be throttled because the input
2830 buffers are close to full.
2831 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002832static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002834 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002835 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002836 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837
2838#ifdef CY_DEBUG_THROTTLE
Peter Hurleyfdfb7192016-01-10 22:40:54 -08002839 printk(KERN_DEBUG "cyc:throttle %s ...ttyC%d\n", tty_name(tty),
2840 info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841#endif
2842
Alan Cox15ed6cc2008-04-30 00:53:55 -07002843 if (serial_paranoia_check(info, tty->name, "cy_throttle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08002844 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845
Jiri Slaby02f11752006-12-08 02:39:28 -08002846 card = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847
Jiri Slaby02f11752006-12-08 02:39:28 -08002848 if (I_IXOFF(tty)) {
Jiri Slaby2693f482009-06-11 12:31:06 +01002849 if (!cy_is_Z(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002850 cy_send_xchar(tty, STOP_CHAR(tty));
2851 else
2852 info->throttle = 1;
2853 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854
Peter Hurley9db276f2016-01-10 20:36:15 -08002855 if (C_CRTSCTS(tty)) {
Jiri Slaby2693f482009-06-11 12:31:06 +01002856 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002857 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07002858 cyy_change_rts_dtr(info, 0, TIOCM_RTS);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002859 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002860 } else {
2861 info->throttle = 1;
2862 }
2863 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002864} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865
2866/*
2867 * This routine notifies the tty driver that it should signal
2868 * that characters can now be sent to the tty without fear of
2869 * overrunning the input buffers of the line disciplines.
2870 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002871static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002873 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002874 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002875 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876
2877#ifdef CY_DEBUG_THROTTLE
Peter Hurleyfdfb7192016-01-10 22:40:54 -08002878 printk(KERN_DEBUG "cyc:unthrottle %s ...ttyC%d\n",
2879 tty_name(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880#endif
2881
Alan Cox15ed6cc2008-04-30 00:53:55 -07002882 if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08002883 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884
Jiri Slaby02f11752006-12-08 02:39:28 -08002885 if (I_IXOFF(tty)) {
2886 if (info->x_char)
2887 info->x_char = 0;
2888 else
2889 cy_send_xchar(tty, START_CHAR(tty));
2890 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891
Peter Hurley9db276f2016-01-10 20:36:15 -08002892 if (C_CRTSCTS(tty)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002893 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01002894 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002895 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07002896 cyy_change_rts_dtr(info, TIOCM_RTS, 0);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002897 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002898 } else {
2899 info->throttle = 0;
2900 }
2901 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002902} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903
2904/* cy_start and cy_stop provide software output flow control as a
2905 function of XON/XOFF, software CTS, and other such stuff.
2906*/
Jiri Slaby02f11752006-12-08 02:39:28 -08002907static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908{
Jiri Slaby02f11752006-12-08 02:39:28 -08002909 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002910 struct cyclades_port *info = tty->driver_data;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002911 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08002912 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913
2914#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002915 printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916#endif
2917
Jiri Slaby02f11752006-12-08 02:39:28 -08002918 if (serial_paranoia_check(info, tty->name, "cy_stop"))
2919 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920
Jiri Slaby875b2062007-05-08 00:36:49 -07002921 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002922 channel = info->line - cinfo->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002923 if (!cy_is_Z(cinfo)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002924 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002925 cyy_writeb(info, CyCAR, channel & 0x03);
2926 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002927 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002929} /* cy_stop */
2930
2931static void cy_start(struct tty_struct *tty)
2932{
2933 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002934 struct cyclades_port *info = tty->driver_data;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002935 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08002936 unsigned long flags;
2937
2938#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002939 printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
Jiri Slaby02f11752006-12-08 02:39:28 -08002940#endif
2941
2942 if (serial_paranoia_check(info, tty->name, "cy_start"))
2943 return;
2944
Jiri Slaby875b2062007-05-08 00:36:49 -07002945 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002946 channel = info->line - cinfo->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002947 if (!cy_is_Z(cinfo)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002948 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002949 cyy_writeb(info, CyCAR, channel & 0x03);
2950 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002951 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002952 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002953} /* cy_start */
2954
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955/*
2956 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
2957 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002958static void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002960 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08002961
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002963 printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964#endif
2965
Jiri Slaby02f11752006-12-08 02:39:28 -08002966 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
2967 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968
Jiri Slaby02f11752006-12-08 02:39:28 -08002969 cy_flush_buffer(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07002970 cy_shutdown(info, tty);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07002971 tty_port_hangup(&info->port);
Jiri Slaby02f11752006-12-08 02:39:28 -08002972} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973
Jiri Slabyf0737572009-09-19 13:13:12 -07002974static int cyy_carrier_raised(struct tty_port *port)
2975{
2976 struct cyclades_port *info = container_of(port, struct cyclades_port,
2977 port);
2978 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0737572009-09-19 13:13:12 -07002979 unsigned long flags;
2980 int channel = info->line - cinfo->first_line;
Jiri Slabyf0737572009-09-19 13:13:12 -07002981 u32 cd;
2982
Jiri Slabyf0737572009-09-19 13:13:12 -07002983 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002984 cyy_writeb(info, CyCAR, channel & 0x03);
2985 cd = cyy_readb(info, CyMSVR1) & CyDCD;
Jiri Slabyf0737572009-09-19 13:13:12 -07002986 spin_unlock_irqrestore(&cinfo->card_lock, flags);
2987
2988 return cd;
2989}
2990
2991static void cyy_dtr_rts(struct tty_port *port, int raise)
2992{
2993 struct cyclades_port *info = container_of(port, struct cyclades_port,
2994 port);
2995 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0737572009-09-19 13:13:12 -07002996 unsigned long flags;
Jiri Slabyf0737572009-09-19 13:13:12 -07002997
2998 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07002999 cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
3000 raise ? 0 : TIOCM_RTS | TIOCM_DTR);
Jiri Slabyf0737572009-09-19 13:13:12 -07003001 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3002}
3003
3004static int cyz_carrier_raised(struct tty_port *port)
3005{
3006 struct cyclades_port *info = container_of(port, struct cyclades_port,
3007 port);
Jiri Slabyf0737572009-09-19 13:13:12 -07003008
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003009 return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
Jiri Slabyf0737572009-09-19 13:13:12 -07003010}
3011
3012static void cyz_dtr_rts(struct tty_port *port, int raise)
3013{
3014 struct cyclades_port *info = container_of(port, struct cyclades_port,
3015 port);
3016 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003017 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slabyf0737572009-09-19 13:13:12 -07003018 int ret, channel = info->line - cinfo->first_line;
3019 u32 rs;
3020
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003021 rs = readl(&ch_ctrl->rs_control);
Jiri Slabyf0737572009-09-19 13:13:12 -07003022 if (raise)
3023 rs |= C_RS_RTS | C_RS_DTR;
3024 else
3025 rs &= ~(C_RS_RTS | C_RS_DTR);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003026 cy_writel(&ch_ctrl->rs_control, rs);
Jiri Slabyf0737572009-09-19 13:13:12 -07003027 ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L);
3028 if (ret != 0)
3029 printk(KERN_ERR "%s: retval on ttyC%d was %x\n",
3030 __func__, info->line, ret);
3031#ifdef CY_DEBUG_DTR
3032 printk(KERN_DEBUG "%s: raising Z DTR\n", __func__);
3033#endif
3034}
3035
3036static const struct tty_port_operations cyy_port_ops = {
3037 .carrier_raised = cyy_carrier_raised,
3038 .dtr_rts = cyy_dtr_rts,
Alan Coxe936ffd2009-09-19 13:13:22 -07003039 .shutdown = cy_do_close,
Jiri Slabyf0737572009-09-19 13:13:12 -07003040};
3041
3042static const struct tty_port_operations cyz_port_ops = {
3043 .carrier_raised = cyz_carrier_raised,
3044 .dtr_rts = cyz_dtr_rts,
Alan Coxe936ffd2009-09-19 13:13:22 -07003045 .shutdown = cy_do_close,
Jiri Slabyf0737572009-09-19 13:13:12 -07003046};
3047
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048/*
3049 * ---------------------------------------------------------------------
3050 * cy_init() and friends
3051 *
3052 * cy_init() is called at boot-time to initialize the serial driver.
3053 * ---------------------------------------------------------------------
3054 */
3055
Bill Pemberton9671f092012-11-19 13:21:50 -05003056static int cy_init_card(struct cyclades_card *cinfo)
Jiri Slaby0809e262007-05-08 00:36:14 -07003057{
3058 struct cyclades_port *info;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003059 unsigned int channel, port;
Jiri Slaby0809e262007-05-08 00:36:14 -07003060
Jiri Slaby3046d502007-05-08 00:36:46 -07003061 spin_lock_init(&cinfo->card_lock);
Jiri Slaby963118e2009-06-11 12:34:27 +01003062 cinfo->intr_enabled = 0;
Jiri Slaby3046d502007-05-08 00:36:46 -07003063
Jiri Slaby963118e2009-06-11 12:34:27 +01003064 cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
3065 GFP_KERNEL);
Jiri Slabydd025c02007-05-08 00:37:02 -07003066 if (cinfo->ports == NULL) {
3067 printk(KERN_ERR "Cyclades: cannot allocate ports\n");
3068 return -ENOMEM;
3069 }
3070
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003071 for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
3072 channel++, port++) {
3073 info = &cinfo->ports[channel];
Alan Cox44b7d1b2008-07-16 21:57:18 +01003074 tty_port_init(&info->port);
Jiri Slaby3046d502007-05-08 00:36:46 -07003075 info->magic = CYCLADES_MAGIC;
Jiri Slaby875b2062007-05-08 00:36:49 -07003076 info->card = cinfo;
Jiri Slaby3046d502007-05-08 00:36:46 -07003077 info->line = port;
Jiri Slaby3046d502007-05-08 00:36:46 -07003078
Alan Cox44b7d1b2008-07-16 21:57:18 +01003079 info->port.closing_wait = CLOSING_WAIT_DELAY;
3080 info->port.close_delay = 5 * HZ / 10;
Jiri Slaby2c7fea92007-05-08 00:36:51 -07003081 init_completion(&info->shutdown_wait);
Jiri Slaby3046d502007-05-08 00:36:46 -07003082
Jiri Slaby2693f482009-06-11 12:31:06 +01003083 if (cy_is_Z(cinfo)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003084 struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
3085 struct ZFW_CTRL *zfw_ctrl;
3086
Jiri Slabyf0737572009-09-19 13:13:12 -07003087 info->port.ops = &cyz_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003088 info->type = PORT_STARTECH;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003089
3090 zfw_ctrl = cinfo->base_addr +
3091 (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3092 info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
3093 info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
3094
Jiri Slaby101b8152009-06-11 12:30:10 +01003095 if (cinfo->hw_ver == ZO_V1)
Jiri Slaby0809e262007-05-08 00:36:14 -07003096 info->xmit_fifo_size = CYZ_FIFO_SIZE;
3097 else
Jiri Slaby3046d502007-05-08 00:36:46 -07003098 info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
Jiri Slaby0809e262007-05-08 00:36:14 -07003099#ifdef CONFIG_CYZ_INTR
Jiri Slaby39914282007-05-08 00:36:54 -07003100 setup_timer(&cyz_rx_full_timer[port],
3101 cyz_rx_restart, (unsigned long)info);
Jiri Slaby0809e262007-05-08 00:36:14 -07003102#endif
Jiri Slaby3046d502007-05-08 00:36:46 -07003103 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003104 unsigned short chip_number;
Jiri Slaby963118e2009-06-11 12:34:27 +01003105 int index = cinfo->bus_index;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003106
Jiri Slabyf0737572009-09-19 13:13:12 -07003107 info->port.ops = &cyy_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003108 info->type = PORT_CIRRUS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003109 info->xmit_fifo_size = CyMAX_CHAR_FIFO;
Jiri Slaby3046d502007-05-08 00:36:46 -07003110 info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003111 info->cor2 = CyETC;
3112 info->cor3 = 0x08; /* _very_ small rcv threshold */
Jiri Slaby3046d502007-05-08 00:36:46 -07003113
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003114 chip_number = channel / CyPORTS_PER_CHIP;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07003115 info->u.cyy.base_addr = cinfo->base_addr +
3116 (cy_chip_offset[chip_number] << index);
3117 info->chip_rev = cyy_readb(info, CyGFRCR);
Alan Cox15ed6cc2008-04-30 00:53:55 -07003118
3119 if (info->chip_rev >= CD1400_REV_J) {
Jiri Slaby0809e262007-05-08 00:36:14 -07003120 /* It is a CD1400 rev. J or later */
3121 info->tbpr = baud_bpr_60[13]; /* Tx BPR */
3122 info->tco = baud_co_60[13]; /* Tx CO */
3123 info->rbpr = baud_bpr_60[13]; /* Rx BPR */
3124 info->rco = baud_co_60[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003125 info->rtsdtr_inv = 1;
3126 } else {
3127 info->tbpr = baud_bpr_25[13]; /* Tx BPR */
3128 info->tco = baud_co_25[13]; /* Tx CO */
3129 info->rbpr = baud_bpr_25[13]; /* Rx BPR */
3130 info->rco = baud_co_25[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003131 info->rtsdtr_inv = 0;
3132 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003133 info->read_status_mask = CyTIMEOUT | CySPECHAR |
3134 CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
Jiri Slaby0809e262007-05-08 00:36:14 -07003135 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003136
Jiri Slaby0809e262007-05-08 00:36:14 -07003137 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003138
3139#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003140 if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
Jiri Slaby3046d502007-05-08 00:36:46 -07003141 mod_timer(&cyz_timerlist, jiffies + 1);
3142#ifdef CY_PCI_DEBUG
3143 printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
3144#endif
3145 }
3146#endif
Jiri Slabydd025c02007-05-08 00:37:02 -07003147 return 0;
Jiri Slaby0809e262007-05-08 00:36:14 -07003148}
3149
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150/* initialize chips on Cyclom-Y card -- return number of valid
3151 chips (which is number of ports/4) */
Bill Pemberton9671f092012-11-19 13:21:50 -05003152static unsigned short cyy_init_card(void __iomem *true_base_addr,
Jiri Slaby31b4f0a2007-05-08 00:36:44 -07003153 int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154{
Jiri Slaby02f11752006-12-08 02:39:28 -08003155 unsigned int chip_number;
3156 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157
Jiri Slaby02f11752006-12-08 02:39:28 -08003158 cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
3159 /* Cy_HwReset is 0x1400 */
3160 cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
3161 /* Cy_ClrIntr is 0x1800 */
3162 udelay(500L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163
Alan Cox15ed6cc2008-04-30 00:53:55 -07003164 for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
3165 chip_number++) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003166 base_addr =
3167 true_base_addr + (cy_chip_offset[chip_number] << index);
3168 mdelay(1);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003169 if (readb(base_addr + (CyCCR << index)) != 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003170 /*************
3171 printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
3172 chip_number, (unsigned long)base_addr);
3173 *************/
3174 return chip_number;
3175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176
Jiri Slaby02f11752006-12-08 02:39:28 -08003177 cy_writeb(base_addr + (CyGFRCR << index), 0);
3178 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179
Jiri Slaby02f11752006-12-08 02:39:28 -08003180 /* The Cyclom-16Y does not decode address bit 9 and therefore
3181 cannot distinguish between references to chip 0 and a non-
3182 existent chip 4. If the preceding clearing of the supposed
3183 chip 4 GFRCR register appears at chip 0, there is no chip 4
3184 and this must be a Cyclom-16Y, not a Cyclom-32Ye.
3185 */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003186 if (chip_number == 4 && readb(true_base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08003187 (cy_chip_offset[0] << index) +
3188 (CyGFRCR << index)) == 0) {
3189 return chip_number;
3190 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191
Jiri Slaby02f11752006-12-08 02:39:28 -08003192 cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
3193 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003195 if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003196 /*
3197 printk(" chip #%d at %#6lx is not responding ",
3198 chip_number, (unsigned long)base_addr);
3199 printk("(GFRCR stayed 0)\n",
3200 */
3201 return chip_number;
3202 }
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003203 if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
Jiri Slaby02f11752006-12-08 02:39:28 -08003204 0x40) {
3205 /*
3206 printk(" chip #%d at %#6lx is not valid (GFRCR == "
3207 "%#2x)\n",
3208 chip_number, (unsigned long)base_addr,
3209 base_addr[CyGFRCR<<index]);
3210 */
3211 return chip_number;
3212 }
3213 cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003214 if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003215 /* It is a CD1400 rev. J or later */
3216 /* Impossible to reach 5ms with this chip.
3217 Changed to 2ms instead (f = 500 Hz). */
3218 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
3219 } else {
3220 /* f = 200 Hz */
3221 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
3222 }
3223
3224 /*
3225 printk(" chip #%d at %#6lx is rev 0x%2x\n",
3226 chip_number, (unsigned long)base_addr,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003227 readb(base_addr+(CyGFRCR<<index)));
Jiri Slaby02f11752006-12-08 02:39:28 -08003228 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003230 return chip_number;
3231} /* cyy_init_card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232
3233/*
3234 * ---------------------------------------------------------------------
3235 * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
3236 * sets global variables and return the number of ISA boards found.
3237 * ---------------------------------------------------------------------
3238 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003239static int __init cy_detect_isa(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240{
3241#ifdef CONFIG_ISA
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003242 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003243 unsigned short cy_isa_irq, nboard;
3244 void __iomem *cy_isa_address;
Jiri Slaby734cc172012-08-07 21:47:47 +02003245 unsigned short i, j, k, cy_isa_nchan;
Jiri Slaby02f11752006-12-08 02:39:28 -08003246 int isparam = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247
Jiri Slaby02f11752006-12-08 02:39:28 -08003248 nboard = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 /* Check for module parameters */
Jiri Slaby02f11752006-12-08 02:39:28 -08003251 for (i = 0; i < NR_CARDS; i++) {
3252 if (maddr[i] || i) {
3253 isparam = 1;
3254 cy_isa_addresses[i] = maddr[i];
3255 }
3256 if (!maddr[i])
3257 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259
Jiri Slaby02f11752006-12-08 02:39:28 -08003260 /* scan the address table probing for Cyclom-Y/ISA boards */
3261 for (i = 0; i < NR_ISA_ADDRS; i++) {
3262 unsigned int isa_address = cy_isa_addresses[i];
Alan Cox15ed6cc2008-04-30 00:53:55 -07003263 if (isa_address == 0x0000)
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003264 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265
Jiri Slaby02f11752006-12-08 02:39:28 -08003266 /* probe for CD1400... */
Alan Coxcd989b32008-04-30 00:53:56 -07003267 cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003268 if (cy_isa_address == NULL) {
3269 printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
3270 "address\n");
3271 continue;
3272 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003273 cy_isa_nchan = CyPORTS_PER_CHIP *
3274 cyy_init_card(cy_isa_address, 0);
3275 if (cy_isa_nchan == 0) {
Jiri Slaby31375532007-05-08 00:37:04 -07003276 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003277 continue;
3278 }
Bartlomiej Zolnierkiewicz20904362009-12-09 12:34:14 -08003279
Roel Kluin196b3162009-10-01 15:44:24 -07003280 if (isparam && i < NR_CARDS && irq[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08003281 cy_isa_irq = irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 else
Jiri Slaby02f11752006-12-08 02:39:28 -08003283 /* find out the board's irq by probing */
3284 cy_isa_irq = detect_isa_irq(cy_isa_address);
3285 if (cy_isa_irq == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003286 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
3287 "IRQ could not be detected.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003288 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003289 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003290 continue;
3291 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292
Jiri Slaby02f11752006-12-08 02:39:28 -08003293 if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
Jiri Slaby21719192007-05-08 00:36:42 -07003294 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3295 "more channels are available. Change NR_PORTS "
3296 "in cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003297 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003298 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003299 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003300 }
3301 /* fill the next cy_card structure available */
3302 for (j = 0; j < NR_CARDS; j++) {
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003303 card = &cy_card[j];
3304 if (card->base_addr == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08003305 break;
3306 }
3307 if (j == NR_CARDS) { /* no more cy_cards available */
Jiri Slaby21719192007-05-08 00:36:42 -07003308 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3309 "more cards can be used. Change NR_CARDS in "
3310 "cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003311 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003312 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003313 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003314 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315
Jiri Slaby02f11752006-12-08 02:39:28 -08003316 /* allocate IRQ */
3317 if (request_irq(cy_isa_irq, cyy_interrupt,
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003318 0, "Cyclom-Y", card)) {
Jiri Slaby21719192007-05-08 00:36:42 -07003319 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
3320 "could not allocate IRQ#%d.\n",
3321 (unsigned long)cy_isa_address, cy_isa_irq);
Jiri Slaby31375532007-05-08 00:37:04 -07003322 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003323 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003324 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325
Jiri Slaby02f11752006-12-08 02:39:28 -08003326 /* set cy_card */
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003327 card->base_addr = cy_isa_address;
3328 card->ctl_addr.p9050 = NULL;
3329 card->irq = (int)cy_isa_irq;
3330 card->bus_index = 0;
3331 card->first_line = cy_next_channel;
3332 card->num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
3333 card->nports = cy_isa_nchan;
3334 if (cy_init_card(card)) {
3335 card->base_addr = NULL;
3336 free_irq(cy_isa_irq, card);
Jiri Slaby31375532007-05-08 00:37:04 -07003337 iounmap(cy_isa_address);
3338 continue;
3339 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003340 nboard++;
3341
Jiri Slaby21719192007-05-08 00:36:42 -07003342 printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
3343 "%d channels starting from port %d\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003344 j + 1, (unsigned long)cy_isa_address,
3345 (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
Jiri Slaby21719192007-05-08 00:36:42 -07003346 cy_isa_irq, cy_isa_nchan, cy_next_channel);
3347
Jiri Slaby734cc172012-08-07 21:47:47 +02003348 for (k = 0, j = cy_next_channel;
3349 j < cy_next_channel + cy_isa_nchan; j++, k++)
3350 tty_port_register_device(&card->ports[k].port,
3351 cy_serial_driver, j, NULL);
Jiri Slaby02f11752006-12-08 02:39:28 -08003352 cy_next_channel += cy_isa_nchan;
3353 }
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003354 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355#else
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003356 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08003357#endif /* CONFIG_ISA */
3358} /* cy_detect_isa */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359
Jiri Slaby58936d82007-05-08 00:36:13 -07003360#ifdef CONFIG_PCI
Bill Pemberton9671f092012-11-19 13:21:50 -05003361static inline int cyc_isfwstr(const char *str, unsigned int size)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003362{
3363 unsigned int a;
3364
3365 for (a = 0; a < size && *str; a++, str++)
3366 if (*str & 0x80)
3367 return -EINVAL;
3368
3369 for (; a < size; a++, str++)
3370 if (*str)
3371 return -EINVAL;
3372
3373 return 0;
3374}
3375
Bill Pemberton9671f092012-11-19 13:21:50 -05003376static inline void cyz_fpga_copy(void __iomem *fpga, const u8 *data,
Jiri Slaby054f5b02007-07-17 04:05:16 -07003377 unsigned int size)
3378{
3379 for (; size > 0; size--) {
3380 cy_writel(fpga, *data++);
3381 udelay(10);
3382 }
3383}
3384
Bill Pemberton9671f092012-11-19 13:21:50 -05003385static void plx_init(struct pci_dev *pdev, int irq,
Jiri Slaby054f5b02007-07-17 04:05:16 -07003386 struct RUNTIME_9060 __iomem *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387{
Jiri Slaby02f11752006-12-08 02:39:28 -08003388 /* Reset PLX */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003389 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003390 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003391 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392
Jiri Slaby02f11752006-12-08 02:39:28 -08003393 /* Reload Config. Registers from EEPROM */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003394 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003395 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003396 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);
3397
3398 /* For some yet unknown reason, once the PLX9060 reloads the EEPROM,
3399 * the IRQ is lost and, thus, we have to re-write it to the PCI config.
3400 * registers. This will remain here until we find a permanent fix.
3401 */
3402 pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
3403}
3404
Bill Pemberton9671f092012-11-19 13:21:50 -05003405static int __cyz_load_fw(const struct firmware *fw,
Jiri Slaby054f5b02007-07-17 04:05:16 -07003406 const char *name, const u32 mailbox, void __iomem *base,
3407 void __iomem *fpga)
3408{
David Woodhousef61e7612008-05-23 23:57:19 +01003409 const void *ptr = fw->data;
3410 const struct zfile_header *h = ptr;
3411 const struct zfile_config *c, *cs;
3412 const struct zfile_block *b, *bs;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003413 unsigned int a, tmp, len = fw->size;
3414#define BAD_FW KERN_ERR "Bad firmware: "
3415 if (len < sizeof(*h)) {
3416 printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h));
3417 return -EINVAL;
3418 }
3419
3420 cs = ptr + h->config_offset;
3421 bs = ptr + h->block_offset;
3422
3423 if ((void *)(cs + h->n_config) > ptr + len ||
3424 (void *)(bs + h->n_blocks) > ptr + len) {
3425 printk(BAD_FW "too short");
3426 return -EINVAL;
3427 }
3428
3429 if (cyc_isfwstr(h->name, sizeof(h->name)) ||
3430 cyc_isfwstr(h->date, sizeof(h->date))) {
3431 printk(BAD_FW "bad formatted header string\n");
3432 return -EINVAL;
3433 }
3434
3435 if (strncmp(name, h->name, sizeof(h->name))) {
3436 printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name);
3437 return -EINVAL;
3438 }
3439
3440 tmp = 0;
3441 for (c = cs; c < cs + h->n_config; c++) {
3442 for (a = 0; a < c->n_blocks; a++)
3443 if (c->block_list[a] > h->n_blocks) {
3444 printk(BAD_FW "bad block ref number in cfgs\n");
3445 return -EINVAL;
3446 }
3447 if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */
3448 tmp++;
3449 }
3450 if (!tmp) {
3451 printk(BAD_FW "nothing appropriate\n");
3452 return -EINVAL;
3453 }
3454
3455 for (b = bs; b < bs + h->n_blocks; b++)
3456 if (b->file_offset + b->size > len) {
3457 printk(BAD_FW "bad block data offset\n");
3458 return -EINVAL;
3459 }
3460
3461 /* everything is OK, let's seek'n'load it */
3462 for (c = cs; c < cs + h->n_config; c++)
3463 if (c->mailbox == mailbox && c->function == 0)
3464 break;
3465
3466 for (a = 0; a < c->n_blocks; a++) {
3467 b = &bs[c->block_list[a]];
3468 if (b->type == ZBLOCK_FPGA) {
3469 if (fpga != NULL)
3470 cyz_fpga_copy(fpga, ptr + b->file_offset,
3471 b->size);
3472 } else {
3473 if (base != NULL)
3474 memcpy_toio(base + b->ram_offset,
3475 ptr + b->file_offset, b->size);
3476 }
3477 }
3478#undef BAD_FW
3479 return 0;
3480}
3481
Bill Pemberton9671f092012-11-19 13:21:50 -05003482static int cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
Jiri Slaby054f5b02007-07-17 04:05:16 -07003483 struct RUNTIME_9060 __iomem *ctl_addr, int irq)
3484{
3485 const struct firmware *fw;
3486 struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
3487 struct CUSTOM_REG __iomem *cust = base_addr;
3488 struct ZFW_CTRL __iomem *pt_zfwctrl;
Jiri Slabyc4923b42007-07-17 04:05:17 -07003489 void __iomem *tmp;
Jiri Slaby963118e2009-06-11 12:34:27 +01003490 u32 mailbox, status, nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003491 unsigned int i;
3492 int retval;
3493
3494 retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev);
3495 if (retval) {
3496 dev_err(&pdev->dev, "can't get firmware\n");
3497 goto err;
3498 }
3499
3500 /* Check whether the firmware is already loaded and running. If
3501 positive, skip this board */
Jiri Slaby2693f482009-06-11 12:31:06 +01003502 if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003503 u32 cntval = readl(base_addr + 0x190);
3504
3505 udelay(100);
3506 if (cntval != readl(base_addr + 0x190)) {
3507 /* FW counter is working, FW is running */
3508 dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. "
3509 "Skipping board.\n");
3510 retval = 0;
3511 goto err_rel;
3512 }
3513 }
3514
3515 /* start boot */
3516 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) &
3517 ~0x00030800UL);
3518
3519 mailbox = readl(&ctl_addr->mail_box_0);
3520
Jiri Slaby2693f482009-06-11 12:31:06 +01003521 if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003522 /* stops CPU and set window to beginning of RAM */
3523 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3524 cy_writel(&cust->cpu_stop, 0);
3525 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3526 udelay(100);
3527 }
3528
3529 plx_init(pdev, irq, ctl_addr);
3530
3531 if (mailbox != 0) {
3532 /* load FPGA */
3533 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL,
3534 base_addr);
3535 if (retval)
3536 goto err_rel;
Jiri Slaby2693f482009-06-11 12:31:06 +01003537 if (!__cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003538 dev_err(&pdev->dev, "fw upload successful, but fw is "
3539 "not loaded\n");
3540 goto err_rel;
3541 }
3542 }
3543
3544 /* stops CPU and set window to beginning of RAM */
3545 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3546 cy_writel(&cust->cpu_stop, 0);
3547 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3548 udelay(100);
3549
3550 /* clear memory */
Jiri Slabyc4923b42007-07-17 04:05:17 -07003551 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003552 cy_writeb(tmp, 255);
3553 if (mailbox != 0) {
3554 /* set window to last 512K of RAM */
3555 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
Jiri Slabyc4923b42007-07-17 04:05:17 -07003556 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003557 cy_writeb(tmp, 255);
3558 /* set window to beginning of RAM */
3559 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003560 }
3561
3562 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
3563 release_firmware(fw);
3564 if (retval)
3565 goto err;
3566
3567 /* finish boot and start boards */
3568 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3569 cy_writel(&cust->cpu_start, 0);
3570 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3571 i = 0;
3572 while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40)
3573 msleep(100);
3574 if (status != ZFIRM_ID) {
3575 if (status == ZFIRM_HLT) {
3576 dev_err(&pdev->dev, "you need an external power supply "
3577 "for this number of ports. Firmware halted and "
3578 "board reset.\n");
3579 retval = -EIO;
3580 goto err;
3581 }
3582 dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting "
3583 "some more time\n", status);
3584 while ((status = readl(&fid->signature)) != ZFIRM_ID &&
3585 i++ < 200)
3586 msleep(100);
3587 if (status != ZFIRM_ID) {
3588 dev_err(&pdev->dev, "Board not started in 20 seconds! "
3589 "Giving up. (fid->signature = 0x%x)\n",
3590 status);
3591 dev_info(&pdev->dev, "*** Warning ***: if you are "
3592 "upgrading the FW, please power cycle the "
3593 "system before loading the new FW to the "
3594 "Cyclades-Z.\n");
3595
Jiri Slaby2693f482009-06-11 12:31:06 +01003596 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003597 plx_init(pdev, irq, ctl_addr);
3598
3599 retval = -EIO;
3600 goto err;
3601 }
3602 dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n",
3603 i / 10);
3604 }
3605 pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr);
3606
3607 dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n",
3608 base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
3609 base_addr + readl(&fid->zfwctrl_addr));
3610
Jiri Slaby963118e2009-06-11 12:34:27 +01003611 nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003612 dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
Jiri Slaby963118e2009-06-11 12:34:27 +01003613 readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003614
Jiri Slaby963118e2009-06-11 12:34:27 +01003615 if (nchan == 0) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003616 dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
3617 "check the connection between the Z host card and the "
3618 "serial expanders.\n");
3619
Jiri Slaby2693f482009-06-11 12:31:06 +01003620 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003621 plx_init(pdev, irq, ctl_addr);
3622
3623 dev_info(&pdev->dev, "Null number of ports detected. Board "
3624 "reset.\n");
3625 retval = 0;
3626 goto err;
3627 }
3628
3629 cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX);
3630 cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION);
3631
3632 /*
3633 Early firmware failed to start looking for commands.
3634 This enables firmware interrupts for those commands.
3635 */
3636 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3637 (1 << 17));
3638 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3639 0x00030800UL);
3640
Jiri Slaby963118e2009-06-11 12:34:27 +01003641 return nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003642err_rel:
3643 release_firmware(fw);
3644err:
3645 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646}
3647
Bill Pemberton9671f092012-11-19 13:21:50 -05003648static int cy_pci_probe(struct pci_dev *pdev,
Jiri Slaby58936d82007-05-08 00:36:13 -07003649 const struct pci_device_id *ent)
3650{
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003651 struct cyclades_card *card;
Jiri Slaby31375532007-05-08 00:37:04 -07003652 void __iomem *addr0 = NULL, *addr2 = NULL;
3653 char *card_name = NULL;
Jiri Slaby101b8152009-06-11 12:30:10 +01003654 u32 uninitialized_var(mailbox);
Jiri Slaby734cc172012-08-07 21:47:47 +02003655 unsigned int device_id, nchan = 0, card_no, i, j;
Jiri Slaby31375532007-05-08 00:37:04 -07003656 unsigned char plx_ver;
3657 int retval, irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003658
3659 retval = pci_enable_device(pdev);
3660 if (retval) {
3661 dev_err(&pdev->dev, "cannot enable device\n");
Jiri Slaby31375532007-05-08 00:37:04 -07003662 goto err;
Jiri Slaby58936d82007-05-08 00:36:13 -07003663 }
3664
3665 /* read PCI configuration area */
Jiri Slaby31375532007-05-08 00:37:04 -07003666 irq = pdev->irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003667 device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
3668
Jiri Slaby31375532007-05-08 00:37:04 -07003669#if defined(__alpha__)
3670 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
3671 dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
3672 "addresses on Alpha systems.\n");
3673 retval = -EIO;
3674 goto err_dis;
3675 }
3676#endif
3677 if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
3678 dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
3679 "addresses\n");
3680 retval = -EIO;
3681 goto err_dis;
3682 }
3683
3684 if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
3685 dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
3686 "it...\n");
3687 pdev->resource[2].flags &= ~IORESOURCE_IO;
3688 }
3689
3690 retval = pci_request_regions(pdev, "cyclades");
3691 if (retval) {
3692 dev_err(&pdev->dev, "failed to reserve resources\n");
3693 goto err_dis;
3694 }
3695
3696 retval = -EIO;
Jiri Slaby58936d82007-05-08 00:36:13 -07003697 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3698 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby31375532007-05-08 00:37:04 -07003699 card_name = "Cyclom-Y";
Jiri Slaby58936d82007-05-08 00:36:13 -07003700
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003701 addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
3702 CyPCI_Yctl);
Jiri Slaby31375532007-05-08 00:37:04 -07003703 if (addr0 == NULL) {
3704 dev_err(&pdev->dev, "can't remap ctl region\n");
3705 goto err_reg;
3706 }
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003707 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
3708 CyPCI_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003709 if (addr2 == NULL) {
3710 dev_err(&pdev->dev, "can't remap base region\n");
3711 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003712 }
3713
Jiri Slaby31375532007-05-08 00:37:04 -07003714 nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
3715 if (nchan == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003716 dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
3717 "Serial-Modules\n");
Andrew Mortonc847d472009-01-02 13:50:07 +00003718 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003719 }
Jiri Slaby31375532007-05-08 00:37:04 -07003720 } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
3721 struct RUNTIME_9060 __iomem *ctl_addr;
3722
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003723 ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
3724 CyPCI_Zctl);
Jiri Slaby31375532007-05-08 00:37:04 -07003725 if (addr0 == NULL) {
3726 dev_err(&pdev->dev, "can't remap ctl region\n");
3727 goto err_reg;
Jiri Slaby58936d82007-05-08 00:36:13 -07003728 }
3729
Jiri Slaby31375532007-05-08 00:37:04 -07003730 /* Disable interrupts on the PLX before resetting it */
Jiri Slaby97e87f82009-06-11 12:29:27 +01003731 cy_writew(&ctl_addr->intr_ctrl_stat,
3732 readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
Jiri Slaby31375532007-05-08 00:37:04 -07003733
Jiri Slaby054f5b02007-07-17 04:05:16 -07003734 plx_init(pdev, irq, addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07003735
Jiri Slaby101b8152009-06-11 12:30:10 +01003736 mailbox = readl(&ctl_addr->mail_box_0);
Jiri Slaby31375532007-05-08 00:37:04 -07003737
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003738 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
3739 mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
Jiri Slaby31375532007-05-08 00:37:04 -07003740 if (addr2 == NULL) {
3741 dev_err(&pdev->dev, "can't remap base region\n");
3742 goto err_unmap;
3743 }
3744
3745 if (mailbox == ZE_V1) {
3746 card_name = "Cyclades-Ze";
Jiri Slaby31375532007-05-08 00:37:04 -07003747 } else {
3748 card_name = "Cyclades-8Zo";
Jiri Slaby31375532007-05-08 00:37:04 -07003749#ifdef CY_PCI_DEBUG
3750 if (mailbox == ZO_V1) {
3751 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3752 dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
3753 "id %lx, ver %lx\n", (ulong)(0xff &
3754 readl(&((struct CUSTOM_REG *)addr2)->
3755 fpga_id)), (ulong)(0xff &
3756 readl(&((struct CUSTOM_REG *)addr2)->
3757 fpga_version)));
3758 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3759 } else {
3760 dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
3761 "Cyclades-Z board. FPGA not loaded\n");
3762 }
3763#endif
3764 /* The following clears the firmware id word. This
3765 ensures that the driver will not attempt to talk to
3766 the board until it has been properly initialized.
3767 */
3768 if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
3769 cy_writel(addr2 + ID_ADDRESS, 0L);
Jiri Slaby31375532007-05-08 00:37:04 -07003770 }
Jiri Slabyace08c32009-06-11 12:20:38 +01003771
3772 retval = cyz_load_fw(pdev, addr2, addr0, irq);
Jiri Slaby963118e2009-06-11 12:34:27 +01003773 if (retval <= 0)
Jiri Slabyace08c32009-06-11 12:20:38 +01003774 goto err_unmap;
Jiri Slaby963118e2009-06-11 12:34:27 +01003775 nchan = retval;
Jiri Slaby31375532007-05-08 00:37:04 -07003776 }
3777
3778 if ((cy_next_channel + nchan) > NR_PORTS) {
3779 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
3780 "channels are available. Change NR_PORTS in "
3781 "cyclades.c and recompile kernel.\n");
3782 goto err_unmap;
3783 }
3784 /* fill the next cy_card structure available */
3785 for (card_no = 0; card_no < NR_CARDS; card_no++) {
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003786 card = &cy_card[card_no];
3787 if (card->base_addr == NULL)
Jiri Slaby31375532007-05-08 00:37:04 -07003788 break;
3789 }
3790 if (card_no == NR_CARDS) { /* no more cy_cards available */
3791 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
3792 "more cards can be used. Change NR_CARDS in "
3793 "cyclades.c and recompile kernel.\n");
3794 goto err_unmap;
3795 }
3796
3797 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3798 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07003799 /* allocate IRQ */
Jiri Slaby31375532007-05-08 00:37:04 -07003800 retval = request_irq(irq, cyy_interrupt,
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003801 IRQF_SHARED, "Cyclom-Y", card);
Jiri Slaby58936d82007-05-08 00:36:13 -07003802 if (retval) {
Jiri Slaby21719192007-05-08 00:36:42 -07003803 dev_err(&pdev->dev, "could not allocate IRQ\n");
Jiri Slaby31375532007-05-08 00:37:04 -07003804 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003805 }
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003806 card->num_chips = nchan / CyPORTS_PER_CHIP;
Jiri Slaby31375532007-05-08 00:37:04 -07003807 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003808 struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
3809 struct ZFW_CTRL __iomem *zfw_ctrl;
3810
3811 zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3812
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003813 card->hw_ver = mailbox;
3814 card->num_chips = (unsigned int)-1;
3815 card->board_ctrl = &zfw_ctrl->board_ctrl;
Jiri Slaby31375532007-05-08 00:37:04 -07003816#ifdef CONFIG_CYZ_INTR
3817 /* allocate IRQ only if board has an IRQ */
3818 if (irq != 0 && irq != 255) {
3819 retval = request_irq(irq, cyz_interrupt,
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003820 IRQF_SHARED, "Cyclades-Z", card);
Jiri Slaby31375532007-05-08 00:37:04 -07003821 if (retval) {
3822 dev_err(&pdev->dev, "could not allocate IRQ\n");
3823 goto err_unmap;
3824 }
3825 }
3826#endif /* CONFIG_CYZ_INTR */
Jiri Slaby31375532007-05-08 00:37:04 -07003827 }
Jiri Slaby58936d82007-05-08 00:36:13 -07003828
Jiri Slaby31375532007-05-08 00:37:04 -07003829 /* set cy_card */
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003830 card->base_addr = addr2;
3831 card->ctl_addr.p9050 = addr0;
3832 card->irq = irq;
3833 card->bus_index = 1;
3834 card->first_line = cy_next_channel;
3835 card->nports = nchan;
3836 retval = cy_init_card(card);
Jiri Slaby31375532007-05-08 00:37:04 -07003837 if (retval)
3838 goto err_null;
Jiri Slaby58936d82007-05-08 00:36:13 -07003839
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003840 pci_set_drvdata(pdev, card);
Jiri Slaby31375532007-05-08 00:37:04 -07003841
3842 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3843 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07003844 /* enable interrupts in the PCI interface */
Jiri Slaby31375532007-05-08 00:37:04 -07003845 plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
Jiri Slaby58936d82007-05-08 00:36:13 -07003846 switch (plx_ver) {
3847 case PLX_9050:
Jiri Slaby31375532007-05-08 00:37:04 -07003848 cy_writeb(addr0 + 0x4c, 0x43);
Jiri Slaby58936d82007-05-08 00:36:13 -07003849 break;
3850
3851 case PLX_9060:
3852 case PLX_9080:
3853 default: /* Old boards, use PLX_9060 */
Jiri Slaby97e87f82009-06-11 12:29:27 +01003854 {
3855 struct RUNTIME_9060 __iomem *ctl_addr = addr0;
3856 plx_init(pdev, irq, ctl_addr);
3857 cy_writew(&ctl_addr->intr_ctrl_stat,
3858 readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
Jiri Slaby58936d82007-05-08 00:36:13 -07003859 break;
3860 }
Jiri Slaby97e87f82009-06-11 12:29:27 +01003861 }
Jiri Slaby58936d82007-05-08 00:36:13 -07003862 }
3863
Jiri Slaby31375532007-05-08 00:37:04 -07003864 dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
3865 "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
Jiri Slaby734cc172012-08-07 21:47:47 +02003866 for (j = 0, i = cy_next_channel; i < cy_next_channel + nchan; i++, j++)
3867 tty_port_register_device(&card->ports[j].port,
3868 cy_serial_driver, i, &pdev->dev);
Jiri Slaby31375532007-05-08 00:37:04 -07003869 cy_next_channel += nchan;
3870
Jiri Slaby58936d82007-05-08 00:36:13 -07003871 return 0;
Jiri Slaby31375532007-05-08 00:37:04 -07003872err_null:
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003873 card->base_addr = NULL;
3874 free_irq(irq, card);
Jiri Slaby31375532007-05-08 00:37:04 -07003875err_unmap:
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003876 iounmap(addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07003877 if (addr2)
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003878 iounmap(addr2);
Jiri Slaby31375532007-05-08 00:37:04 -07003879err_reg:
3880 pci_release_regions(pdev);
3881err_dis:
3882 pci_disable_device(pdev);
3883err:
3884 return retval;
Jiri Slaby58936d82007-05-08 00:36:13 -07003885}
Jiri Slaby58936d82007-05-08 00:36:13 -07003886
Bill Pembertonae8d8a12012-11-19 13:26:18 -05003887static void cy_pci_remove(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888{
Jiri Slaby38d09092007-05-08 00:36:10 -07003889 struct cyclades_card *cinfo = pci_get_drvdata(pdev);
Jiri Slaby191c5f12012-11-15 09:49:56 +01003890 unsigned int i, channel;
Jiri Slaby38d09092007-05-08 00:36:10 -07003891
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003892 /* non-Z with old PLX */
Jiri Slaby2693f482009-06-11 12:31:06 +01003893 if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
Jiri Slabyc2ad4c72007-05-08 00:36:32 -07003894 PLX_9050)
Jiri Slaby97e87f82009-06-11 12:29:27 +01003895 cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003896 else
3897#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003898 if (!cy_is_Z(cinfo))
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003899#endif
Jiri Slaby97e87f82009-06-11 12:29:27 +01003900 cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
3901 readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
3902 ~0x0900);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003903
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003904 iounmap(cinfo->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01003905 if (cinfo->ctl_addr.p9050)
3906 iounmap(cinfo->ctl_addr.p9050);
Jiri Slaby38d09092007-05-08 00:36:10 -07003907 if (cinfo->irq
3908#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003909 && !cy_is_Z(cinfo)
Jiri Slaby38d09092007-05-08 00:36:10 -07003910#endif /* CONFIG_CYZ_INTR */
3911 )
3912 free_irq(cinfo->irq, cinfo);
3913 pci_release_regions(pdev);
3914
3915 cinfo->base_addr = NULL;
Jiri Slaby191c5f12012-11-15 09:49:56 +01003916 for (channel = 0, i = cinfo->first_line; i < cinfo->first_line +
3917 cinfo->nports; i++, channel++) {
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07003918 tty_unregister_device(cy_serial_driver, i);
Jiri Slaby191c5f12012-11-15 09:49:56 +01003919 tty_port_destroy(&cinfo->ports[channel].port);
3920 }
Jiri Slabydd025c02007-05-08 00:37:02 -07003921 cinfo->nports = 0;
3922 kfree(cinfo->ports);
Jiri Slaby38d09092007-05-08 00:36:10 -07003923}
3924
Jiri Slaby6747cd92007-05-08 00:36:34 -07003925static struct pci_driver cy_pci_driver = {
3926 .name = "cyclades",
3927 .id_table = cy_pci_dev_id,
3928 .probe = cy_pci_probe,
Bill Pemberton91116cb2012-11-19 13:21:06 -05003929 .remove = cy_pci_remove
Jiri Slaby6747cd92007-05-08 00:36:34 -07003930};
3931#endif
3932
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003933static int cyclades_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934{
Jiri Slaby02f11752006-12-08 02:39:28 -08003935 struct cyclades_port *info;
Jiri Slabydd025c02007-05-08 00:37:02 -07003936 unsigned int i, j;
Jiri Slaby02f11752006-12-08 02:39:28 -08003937 __u32 cur_jifs = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003939 seq_puts(m, "Dev TimeOpen BytesOut IdleOut BytesIn "
Jiri Slaby02f11752006-12-08 02:39:28 -08003940 "IdleIn Overruns Ldisc\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941
Jiri Slaby02f11752006-12-08 02:39:28 -08003942 /* Output one line for each known port */
Jiri Slabydd025c02007-05-08 00:37:02 -07003943 for (i = 0; i < NR_CARDS; i++)
3944 for (j = 0; j < cy_card[i].nports; j++) {
3945 info = &cy_card[i].ports[j];
Jiri Slaby02f11752006-12-08 02:39:28 -08003946
Jiri Slabyd13549f2009-09-19 13:13:12 -07003947 if (info->port.count) {
3948 /* XXX is the ldisc num worth this? */
3949 struct tty_struct *tty;
3950 struct tty_ldisc *ld;
3951 int num = 0;
3952 tty = tty_port_tty_get(&info->port);
3953 if (tty) {
3954 ld = tty_ldisc_ref(tty);
3955 if (ld) {
3956 num = ld->ops->num;
3957 tty_ldisc_deref(ld);
3958 }
3959 tty_kref_put(tty);
3960 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003961 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabyd13549f2009-09-19 13:13:12 -07003962 "%10lu %8lu %9lu %6d\n", info->line,
Jiri Slabydd025c02007-05-08 00:37:02 -07003963 (cur_jifs - info->idle_stats.in_use) /
3964 HZ, info->idle_stats.xmit_bytes,
3965 (cur_jifs - info->idle_stats.xmit_idle)/
3966 HZ, info->idle_stats.recv_bytes,
3967 (cur_jifs - info->idle_stats.recv_idle)/
3968 HZ, info->idle_stats.overruns,
Jiri Slabyd13549f2009-09-19 13:13:12 -07003969 num);
3970 } else
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003971 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabydd025c02007-05-08 00:37:02 -07003972 "%10lu %8lu %9lu %6ld\n",
3973 info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08003974 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003975 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976}
3977
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003978static int cyclades_proc_open(struct inode *inode, struct file *file)
3979{
3980 return single_open(file, cyclades_proc_show, NULL);
3981}
3982
3983static const struct file_operations cyclades_proc_fops = {
3984 .owner = THIS_MODULE,
3985 .open = cyclades_proc_open,
3986 .read = seq_read,
3987 .llseek = seq_lseek,
3988 .release = single_release,
3989};
3990
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991/* The serial driver boot-time initialization code!
3992 Hardware I/O ports are mapped to character special devices on a
3993 first found, first allocated manner. That is, this code searches
3994 for Cyclom cards in the system. As each is found, it is probed
3995 to discover how many chips (and thus how many ports) are present.
3996 These ports are mapped to the tty ports 32 and upward in monotonic
3997 fashion. If an 8-port card is replaced with a 16-port card, the
3998 port mapping on a following card will shift.
3999
4000 This approach is different from what is used in the other serial
4001 device driver because the Cyclom is more properly a multiplexer,
4002 not just an aggregation of serial ports on one card.
4003
4004 If there are more cards with more ports than have been
4005 statically allocated above, a warning is printed and the
4006 extra ports are ignored.
4007 */
4008
Jeff Dikeb68e31d2006-10-02 02:17:18 -07004009static const struct tty_operations cy_ops = {
Jiri Slaby02f11752006-12-08 02:39:28 -08004010 .open = cy_open,
4011 .close = cy_close,
4012 .write = cy_write,
4013 .put_char = cy_put_char,
4014 .flush_chars = cy_flush_chars,
4015 .write_room = cy_write_room,
4016 .chars_in_buffer = cy_chars_in_buffer,
4017 .flush_buffer = cy_flush_buffer,
4018 .ioctl = cy_ioctl,
4019 .throttle = cy_throttle,
4020 .unthrottle = cy_unthrottle,
4021 .set_termios = cy_set_termios,
4022 .stop = cy_stop,
4023 .start = cy_start,
4024 .hangup = cy_hangup,
4025 .break_ctl = cy_break,
4026 .wait_until_sent = cy_wait_until_sent,
Jiri Slaby02f11752006-12-08 02:39:28 -08004027 .tiocmget = cy_tiocmget,
4028 .tiocmset = cy_tiocmset,
Alan Cox05871022010-09-16 18:21:52 +01004029 .get_icount = cy_get_icount,
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004030 .proc_fops = &cyclades_proc_fops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031};
4032
Jiri Slaby02f11752006-12-08 02:39:28 -08004033static int __init cy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034{
Jiri Slabydd025c02007-05-08 00:37:02 -07004035 unsigned int nboards;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004036 int retval = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037
Jiri Slaby02f11752006-12-08 02:39:28 -08004038 cy_serial_driver = alloc_tty_driver(NR_PORTS);
4039 if (!cy_serial_driver)
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004040 goto err;
Jiri Slaby21719192007-05-08 00:36:42 -07004041
Michal Marek64a14b52011-04-01 12:41:20 +02004042 printk(KERN_INFO "Cyclades driver " CY_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043
Jiri Slaby02f11752006-12-08 02:39:28 -08004044 /* Initialize the tty_driver structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045
Jiri Slaby02f11752006-12-08 02:39:28 -08004046 cy_serial_driver->driver_name = "cyclades";
4047 cy_serial_driver->name = "ttyC";
4048 cy_serial_driver->major = CYCLADES_MAJOR;
4049 cy_serial_driver->minor_start = 0;
4050 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
4051 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
4052 cy_serial_driver->init_termios = tty_std_termios;
4053 cy_serial_driver->init_termios.c_cflag =
4054 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004055 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08004056 tty_set_operations(cy_serial_driver, &cy_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004058 retval = tty_register_driver(cy_serial_driver);
4059 if (retval) {
4060 printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
4061 goto err_frtty;
4062 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063
Jiri Slaby02f11752006-12-08 02:39:28 -08004064 /* the code below is responsible to find the boards. Each different
4065 type of board has its own detection routine. If a board is found,
4066 the next cy_card structure available is set by the detection
4067 routine. These functions are responsible for checking the
4068 availability of cy_card and cy_port data structures and updating
4069 the cy_next_channel. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070
Jiri Slaby02f11752006-12-08 02:39:28 -08004071 /* look for isa boards */
Jiri Slaby14a55a62007-05-08 00:36:18 -07004072 nboards = cy_detect_isa();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073
Jiri Slaby6747cd92007-05-08 00:36:34 -07004074#ifdef CONFIG_PCI
Jiri Slaby02f11752006-12-08 02:39:28 -08004075 /* look for pci boards */
Jiri Slaby6747cd92007-05-08 00:36:34 -07004076 retval = pci_register_driver(&cy_pci_driver);
Jesper Juhld941ea72007-10-18 03:06:23 -07004077 if (retval && !nboards) {
4078 tty_unregister_driver(cy_serial_driver);
4079 goto err_frtty;
4080 }
Jiri Slaby6747cd92007-05-08 00:36:34 -07004081#endif
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004082
4083 return 0;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004084err_frtty:
4085 put_tty_driver(cy_serial_driver);
4086err:
4087 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08004088} /* cy_init */
4089
4090static void __exit cy_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091{
Jiri Slabydd025c02007-05-08 00:37:02 -07004092 struct cyclades_card *card;
Jiri Slaby65f76a82007-10-18 03:06:22 -07004093 unsigned int i, e1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094
4095#ifndef CONFIG_CYZ_INTR
Jiri Slabyb7050902007-05-08 00:35:48 -07004096 del_timer_sync(&cyz_timerlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004097#endif /* CONFIG_CYZ_INTR */
4098
Alan Cox15ed6cc2008-04-30 00:53:55 -07004099 e1 = tty_unregister_driver(cy_serial_driver);
4100 if (e1)
Jiri Slaby21719192007-05-08 00:36:42 -07004101 printk(KERN_ERR "failed to unregister Cyclades serial "
4102 "driver(%d)\n", e1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103
Jiri Slaby6747cd92007-05-08 00:36:34 -07004104#ifdef CONFIG_PCI
4105 pci_unregister_driver(&cy_pci_driver);
4106#endif
4107
Jiri Slaby02f11752006-12-08 02:39:28 -08004108 for (i = 0; i < NR_CARDS; i++) {
Jiri Slabydd025c02007-05-08 00:37:02 -07004109 card = &cy_card[i];
4110 if (card->base_addr) {
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004111 /* clear interrupt */
Jiri Slabydd025c02007-05-08 00:37:02 -07004112 cy_writeb(card->base_addr + Cy_ClrIntr, 0);
4113 iounmap(card->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01004114 if (card->ctl_addr.p9050)
4115 iounmap(card->ctl_addr.p9050);
Jiri Slabydd025c02007-05-08 00:37:02 -07004116 if (card->irq
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004118 && !cy_is_Z(card)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004119#endif /* CONFIG_CYZ_INTR */
Jiri Slaby02f11752006-12-08 02:39:28 -08004120 )
Jiri Slabydd025c02007-05-08 00:37:02 -07004121 free_irq(card->irq, card);
Jiri Slaby65f76a82007-10-18 03:06:22 -07004122 for (e1 = card->first_line; e1 < card->first_line +
Jiri Slabydd025c02007-05-08 00:37:02 -07004123 card->nports; e1++)
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004124 tty_unregister_device(cy_serial_driver, e1);
Jiri Slabydd025c02007-05-08 00:37:02 -07004125 kfree(card->ports);
Jiri Slaby02f11752006-12-08 02:39:28 -08004126 }
4127 }
Jiri Slabyf2462bf2007-05-08 00:37:01 -07004128
4129 put_tty_driver(cy_serial_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130} /* cy_cleanup_module */
4131
4132module_init(cy_init);
4133module_exit(cy_cleanup_module);
4134
4135MODULE_LICENSE("GPL");
Jiri Slabyc8e16932007-05-08 00:37:05 -07004136MODULE_VERSION(CY_VERSION);
Scott James Remnant9f56fad72009-04-06 17:33:04 +01004137MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);
Ben Hutchingse6c4ef92010-01-13 23:34:18 +00004138MODULE_FIRMWARE("cyzfirm.bin");