blob: 5e4fa920686151f94042af7b9e193d3d0486481f [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
159module_param_array(maddr, long, NULL, 0);
160module_param_array(irq, int, 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 /*
1979 * Set up the tty->alt_speed kludge
1980 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001981 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
1982 tty->alt_speed = 57600;
1983 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
1984 tty->alt_speed = 115200;
1985 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
1986 tty->alt_speed = 230400;
1987 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
1988 tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989
Jiri Slaby02f11752006-12-08 02:39:28 -08001990 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001991 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08001992
Jiri Slaby2693f482009-06-11 12:31:06 +01001993 if (!cy_is_Z(card)) {
Jiri Slaby46fb7822009-09-19 13:13:17 -07001994 u32 cflags;
1995
Jiri Slaby02f11752006-12-08 02:39:28 -08001996 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001997 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01001998 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08001999 ASYNC_SPD_CUST) {
2000 if (info->custom_divisor)
2001 baud_rate = info->baud / info->custom_divisor;
2002 else
2003 baud_rate = info->baud;
2004 } else if (baud > CD1400_MAX_SPEED) {
2005 baud = CD1400_MAX_SPEED;
2006 }
2007 /* find the baud index */
2008 for (i = 0; i < 20; i++) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002009 if (baud == baud_table[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08002010 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002011 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002012 if (i == 20)
Jiri Slaby02f11752006-12-08 02:39:28 -08002013 i = 19; /* CD1400_MAX_SPEED */
Jiri Slaby02f11752006-12-08 02:39:28 -08002014
Alan Cox77451e52008-07-16 21:57:02 +01002015 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002016 ASYNC_SPD_CUST) {
2017 cyy_baud_calc(info, baud_rate);
2018 } else {
2019 if (info->chip_rev >= CD1400_REV_J) {
2020 /* It is a CD1400 rev. J or later */
2021 info->tbpr = baud_bpr_60[i]; /* Tx BPR */
2022 info->tco = baud_co_60[i]; /* Tx CO */
2023 info->rbpr = baud_bpr_60[i]; /* Rx BPR */
2024 info->rco = baud_co_60[i]; /* Rx CO */
2025 } else {
2026 info->tbpr = baud_bpr_25[i]; /* Tx BPR */
2027 info->tco = baud_co_25[i]; /* Tx CO */
2028 info->rbpr = baud_bpr_25[i]; /* Rx BPR */
2029 info->rco = baud_co_25[i]; /* Rx CO */
2030 }
2031 }
2032 if (baud_table[i] == 134) {
2033 /* get it right for 134.5 baud */
2034 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2035 2;
Alan Cox77451e52008-07-16 21:57:02 +01002036 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002037 ASYNC_SPD_CUST) {
2038 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2039 baud_rate) + 2;
2040 } else if (baud_table[i]) {
2041 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2042 baud_table[i]) + 2;
2043 /* this needs to be propagated into the card info */
2044 } else {
2045 info->timeout = 0;
2046 }
2047 /* By tradition (is it a standard?) a baud rate of zero
2048 implies the line should be/has been closed. A bit
2049 later in this routine such a test is performed. */
2050
2051 /* byte size and parity */
2052 info->cor5 = 0;
2053 info->cor4 = 0;
2054 /* receive threshold */
2055 info->cor3 = (info->default_threshold ?
2056 info->default_threshold : baud_cor3[i]);
2057 info->cor2 = CyETC;
2058 switch (cflag & CSIZE) {
2059 case CS5:
2060 info->cor1 = Cy_5_BITS;
2061 break;
2062 case CS6:
2063 info->cor1 = Cy_6_BITS;
2064 break;
2065 case CS7:
2066 info->cor1 = Cy_7_BITS;
2067 break;
2068 case CS8:
2069 info->cor1 = Cy_8_BITS;
2070 break;
2071 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002072 if (cflag & CSTOPB)
Jiri Slaby02f11752006-12-08 02:39:28 -08002073 info->cor1 |= Cy_2_STOP;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002074
Jiri Slaby02f11752006-12-08 02:39:28 -08002075 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002076 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002077 info->cor1 |= CyPARITY_O;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002078 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002079 info->cor1 |= CyPARITY_E;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002080 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002081 info->cor1 |= CyPARITY_NONE;
Jiri Slaby02f11752006-12-08 02:39:28 -08002082
2083 /* CTS flow control flag */
Peter Hurley5604a982016-04-09 17:53:21 -07002084 tty_port_set_cts_flow(&info->port, cflag & CRTSCTS);
2085 if (cflag & CRTSCTS)
Jiri Slaby02f11752006-12-08 02:39:28 -08002086 info->cor2 |= CyCtsAE;
Peter Hurley5604a982016-04-09 17:53:21 -07002087 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002088 info->cor2 &= ~CyCtsAE;
Peter Hurley2d686552016-04-09 17:53:23 -07002089 tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090
2091 /***********************************************
2092 The hardware option, CyRtsAO, presents RTS when
2093 the chip has characters to send. Since most modems
2094 use RTS as reverse (inbound) flow control, this
2095 option is not used. If inbound flow control is
2096 necessary, DTR can be programmed to provide the
2097 appropriate signals for use with a non-standard
2098 cable. Contact Marcio Saito for details.
2099 ***********************************************/
2100
Jiri Slaby02f11752006-12-08 02:39:28 -08002101 channel &= 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002103 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002104 cyy_writeb(info, CyCAR, channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105
Jiri Slaby02f11752006-12-08 02:39:28 -08002106 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002108 cyy_writeb(info, CyTCOR, info->tco);
2109 cyy_writeb(info, CyTBPR, info->tbpr);
2110 cyy_writeb(info, CyRCOR, info->rco);
2111 cyy_writeb(info, CyRBPR, info->rbpr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112
Jiri Slaby02f11752006-12-08 02:39:28 -08002113 /* set line characteristics according configuration */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002115 cyy_writeb(info, CySCHR1, START_CHAR(tty));
2116 cyy_writeb(info, CySCHR2, STOP_CHAR(tty));
2117 cyy_writeb(info, CyCOR1, info->cor1);
2118 cyy_writeb(info, CyCOR2, info->cor2);
2119 cyy_writeb(info, CyCOR3, info->cor3);
2120 cyy_writeb(info, CyCOR4, info->cor4);
2121 cyy_writeb(info, CyCOR5, info->cor5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002123 cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
2124 CyCOR3ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125
Alan Cox15ed6cc2008-04-30 00:53:55 -07002126 /* !!! Is this needed? */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002127 cyy_writeb(info, CyCAR, channel);
2128 cyy_writeb(info, CyRTPR,
Jiri Slaby02f11752006-12-08 02:39:28 -08002129 (info->default_timeout ? info->default_timeout : 0x02));
2130 /* 10ms rx timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131
Jiri Slaby46fb7822009-09-19 13:13:17 -07002132 cflags = CyCTS;
2133 if (!C_CLOCAL(tty))
2134 cflags |= CyDSR | CyRI | CyDCD;
2135 /* without modem intr */
2136 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyMdmCh);
2137 /* act on 1->0 modem transitions */
2138 if ((cflag & CRTSCTS) && info->rflow)
2139 cyy_writeb(info, CyMCOR1, cflags | rflow_thr[i]);
2140 else
2141 cyy_writeb(info, CyMCOR1, cflags);
2142 /* act on 0->1 modem transitions */
2143 cyy_writeb(info, CyMCOR2, cflags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002144
Jiri Slaby4d768202009-09-19 13:13:15 -07002145 if (i == 0) /* baud rate is zero, turn off line */
2146 cyy_change_rts_dtr(info, 0, TIOCM_DTR);
2147 else
2148 cyy_change_rts_dtr(info, TIOCM_DTR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149
Jiri Slabyd13549f2009-09-19 13:13:12 -07002150 clear_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002151 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002154 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002155 __u32 sw_flow;
Jiri Slaby02f11752006-12-08 02:39:28 -08002156 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157
Jiri Slaby2693f482009-06-11 12:31:06 +01002158 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002159 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160
Jiri Slaby02f11752006-12-08 02:39:28 -08002161 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002162 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002163 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002164 ASYNC_SPD_CUST) {
2165 if (info->custom_divisor)
2166 baud_rate = info->baud / info->custom_divisor;
2167 else
2168 baud_rate = info->baud;
2169 } else if (baud > CYZ_MAX_SPEED) {
2170 baud = CYZ_MAX_SPEED;
2171 }
2172 cy_writel(&ch_ctrl->comm_baud, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173
Jiri Slaby02f11752006-12-08 02:39:28 -08002174 if (baud == 134) {
2175 /* get it right for 134.5 baud */
2176 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2177 2;
Alan Cox77451e52008-07-16 21:57:02 +01002178 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002179 ASYNC_SPD_CUST) {
2180 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2181 baud_rate) + 2;
2182 } else if (baud) {
2183 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2184 baud) + 2;
2185 /* this needs to be propagated into the card info */
2186 } else {
2187 info->timeout = 0;
2188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189
Jiri Slaby02f11752006-12-08 02:39:28 -08002190 /* byte size and parity */
2191 switch (cflag & CSIZE) {
2192 case CS5:
2193 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
2194 break;
2195 case CS6:
2196 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
2197 break;
2198 case CS7:
2199 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
2200 break;
2201 case CS8:
2202 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
2203 break;
2204 }
2205 if (cflag & CSTOPB) {
2206 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002207 readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002208 } else {
2209 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002210 readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002211 }
2212 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002213 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002214 cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002215 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002216 cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002217 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002218 cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219
Jiri Slaby02f11752006-12-08 02:39:28 -08002220 /* CTS flow control flag */
2221 if (cflag & CRTSCTS) {
2222 cy_writel(&ch_ctrl->hw_flow,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002223 readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
Jiri Slaby02f11752006-12-08 02:39:28 -08002224 } else {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002225 cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
2226 ~(C_RS_CTS | C_RS_RTS));
Jiri Slaby02f11752006-12-08 02:39:28 -08002227 }
2228 /* As the HW flow control is done in firmware, the driver
2229 doesn't need to care about it */
Peter Hurley5604a982016-04-09 17:53:21 -07002230 tty_port_set_cts_flow(&info->port, 0);
Jiri Slaby02f11752006-12-08 02:39:28 -08002231
2232 /* XON/XOFF/XANY flow control flags */
2233 sw_flow = 0;
2234 if (iflag & IXON) {
2235 sw_flow |= C_FL_OXX;
2236 if (iflag & IXANY)
2237 sw_flow |= C_FL_OIXANY;
2238 }
2239 cy_writel(&ch_ctrl->sw_flow, sw_flow);
2240
Jiri Slaby875b2062007-05-08 00:36:49 -07002241 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002242 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002243 printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
2244 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002245 }
2246
2247 /* CD sensitivity */
Peter Hurley2d686552016-04-09 17:53:23 -07002248 tty_port_set_check_carrier(&info->port, ~cflag & CLOCAL);
Jiri Slaby02f11752006-12-08 02:39:28 -08002249
2250 if (baud == 0) { /* baud rate is zero, turn off line */
2251 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002252 readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002254 printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002256 } else {
2257 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002258 readl(&ch_ctrl->rs_control) | C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002260 printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002262 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263
Alan Cox15ed6cc2008-04-30 00:53:55 -07002264 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002265 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002266 printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
2267 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269
Jiri Slabyd13549f2009-09-19 13:13:12 -07002270 clear_bit(TTY_IO_ERROR, &tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002272} /* set_line_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273
Jiri Slaby6c281812009-09-19 13:13:15 -07002274static int cy_get_serial_info(struct cyclades_port *info,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002275 struct serial_struct __user *retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276{
Jiri Slaby875b2062007-05-08 00:36:49 -07002277 struct cyclades_card *cinfo = info->card;
Jiri Slaby6c281812009-09-19 13:13:15 -07002278 struct serial_struct tmp = {
2279 .type = info->type,
2280 .line = info->line,
2281 .port = (info->card - cy_card) * 0x100 + info->line -
2282 cinfo->first_line,
2283 .irq = cinfo->irq,
2284 .flags = info->port.flags,
2285 .close_delay = info->port.close_delay,
2286 .closing_wait = info->port.closing_wait,
2287 .baud_base = info->baud,
2288 .custom_divisor = info->custom_divisor,
Jiri Slaby6c281812009-09-19 13:13:15 -07002289 };
Jiri Slaby02f11752006-12-08 02:39:28 -08002290 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
Jiri Slaby6c281812009-09-19 13:13:15 -07002291}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292
2293static int
Jiri Slabyd13549f2009-09-19 13:13:12 -07002294cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002295 struct serial_struct __user *new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296{
Jiri Slaby02f11752006-12-08 02:39:28 -08002297 struct serial_struct new_serial;
Alan Cox25c3cdf2010-06-01 22:52:47 +02002298 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299
Jiri Slaby02f11752006-12-08 02:39:28 -08002300 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
2301 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302
Alan Cox25c3cdf2010-06-01 22:52:47 +02002303 mutex_lock(&info->port.mutex);
Jiri Slaby02f11752006-12-08 02:39:28 -08002304 if (!capable(CAP_SYS_ADMIN)) {
Alan Cox44b7d1b2008-07-16 21:57:18 +01002305 if (new_serial.close_delay != info->port.close_delay ||
Jiri Slaby02f11752006-12-08 02:39:28 -08002306 new_serial.baud_base != info->baud ||
2307 (new_serial.flags & ASYNC_FLAGS &
2308 ~ASYNC_USR_MASK) !=
Alan Cox77451e52008-07-16 21:57:02 +01002309 (info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
Alan Cox25c3cdf2010-06-01 22:52:47 +02002310 {
2311 mutex_unlock(&info->port.mutex);
Jiri Slaby02f11752006-12-08 02:39:28 -08002312 return -EPERM;
Alan Cox25c3cdf2010-06-01 22:52:47 +02002313 }
Alan Cox77451e52008-07-16 21:57:02 +01002314 info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002315 (new_serial.flags & ASYNC_USR_MASK);
2316 info->baud = new_serial.baud_base;
2317 info->custom_divisor = new_serial.custom_divisor;
2318 goto check_and_exit;
2319 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320
Jiri Slaby02f11752006-12-08 02:39:28 -08002321 /*
2322 * OK, past this point, all the error checking has been done.
2323 * At this point, we start making changes.....
2324 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325
Jiri Slaby02f11752006-12-08 02:39:28 -08002326 info->baud = new_serial.baud_base;
2327 info->custom_divisor = new_serial.custom_divisor;
Alan Cox77451e52008-07-16 21:57:02 +01002328 info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002329 (new_serial.flags & ASYNC_FLAGS);
Alan Cox44b7d1b2008-07-16 21:57:18 +01002330 info->port.close_delay = new_serial.close_delay * HZ / 100;
2331 info->port.closing_wait = new_serial.closing_wait * HZ / 100;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332
2333check_and_exit:
Peter Hurleyd41861c2016-04-09 17:53:25 -07002334 if (tty_port_initialized(&info->port)) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07002335 cy_set_line_char(info, tty);
Alan Cox25c3cdf2010-06-01 22:52:47 +02002336 ret = 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002337 } else {
Alan Cox25c3cdf2010-06-01 22:52:47 +02002338 ret = cy_startup(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08002339 }
Alan Cox25c3cdf2010-06-01 22:52:47 +02002340 mutex_unlock(&info->port.mutex);
2341 return ret;
Jiri Slaby02f11752006-12-08 02:39:28 -08002342} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343
2344/*
2345 * get_lsr_info - get line status register info
2346 *
2347 * Purpose: Let user call ioctl() to get info when the UART physically
2348 * is emptied. On bus types like RS485, the transmitter must
2349 * release the bus after transmitting. This must be done when
2350 * the transmit shift register is empty, not be done when the
2351 * transmit holding register is empty. This functionality
2352 * allows an RS485 driver to be written in user space.
2353 */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002354static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002356 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002357 unsigned int result;
2358 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002359 u8 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
Jiri Slaby2693f482009-06-11 12:31:06 +01002361 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002362 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002363 status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002364 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002365 result = (status ? 0 : TIOCSER_TEMT);
2366 } else {
2367 /* Not supported yet */
2368 return -EINVAL;
2369 }
Dan Carpenterdbca36e2012-03-05 21:07:11 +03002370 return put_user(result, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371}
2372
Alan Cox60b33c12011-02-14 16:26:14 +00002373static int cy_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002375 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002376 struct cyclades_card *card;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002377 int result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002379 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002380 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381
Jiri Slaby02f11752006-12-08 02:39:28 -08002382 card = info->card;
Jiri Slaby0d348722009-09-19 13:13:16 -07002383
Jiri Slaby2693f482009-06-11 12:31:06 +01002384 if (!cy_is_Z(card)) {
Jiri Slaby0d348722009-09-19 13:13:16 -07002385 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002386 int channel = info->line - card->first_line;
2387 u8 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002389 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002390 cyy_writeb(info, CyCAR, channel & 0x03);
2391 status = cyy_readb(info, CyMSVR1);
2392 status |= cyy_readb(info, CyMSVR2);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002393 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394
Jiri Slaby02f11752006-12-08 02:39:28 -08002395 if (info->rtsdtr_inv) {
2396 result = ((status & CyRTS) ? TIOCM_DTR : 0) |
2397 ((status & CyDTR) ? TIOCM_RTS : 0);
2398 } else {
2399 result = ((status & CyRTS) ? TIOCM_RTS : 0) |
2400 ((status & CyDTR) ? TIOCM_DTR : 0);
2401 }
2402 result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
2403 ((status & CyRI) ? TIOCM_RNG : 0) |
2404 ((status & CyDSR) ? TIOCM_DSR : 0) |
2405 ((status & CyCTS) ? TIOCM_CTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 } else {
Jiri Slaby0d348722009-09-19 13:13:16 -07002407 u32 lstatus;
2408
2409 if (!cyz_is_loaded(card)) {
2410 result = -ENODEV;
2411 goto end;
Jiri Slaby02f11752006-12-08 02:39:28 -08002412 }
2413
Jiri Slaby0d348722009-09-19 13:13:16 -07002414 lstatus = readl(&info->u.cyz.ch_ctrl->rs_status);
2415 result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
2416 ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
2417 ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
2418 ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
2419 ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
2420 ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 }
Jiri Slaby0d348722009-09-19 13:13:16 -07002422end:
Jiri Slaby02f11752006-12-08 02:39:28 -08002423 return result;
2424} /* cy_tiomget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425
2426static int
Alan Cox20b9d172011-02-14 16:26:50 +00002427cy_tiocmset(struct tty_struct *tty,
Jiri Slaby02f11752006-12-08 02:39:28 -08002428 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002430 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002431 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002432 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002434 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002435 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436
Jiri Slaby02f11752006-12-08 02:39:28 -08002437 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01002438 if (!cy_is_Z(card)) {
Jiri Slaby4d768202009-09-19 13:13:15 -07002439 spin_lock_irqsave(&card->card_lock, flags);
2440 cyy_change_rts_dtr(info, set, clear);
2441 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002442 } else {
Jiri Slaby0d348722009-09-19 13:13:16 -07002443 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
2444 int retval, channel = info->line - card->first_line;
2445 u32 rs;
Jiri Slaby02f11752006-12-08 02:39:28 -08002446
Jiri Slaby0d348722009-09-19 13:13:16 -07002447 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002448 return -ENODEV;
Jiri Slaby0d348722009-09-19 13:13:16 -07002449
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002450 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby0d348722009-09-19 13:13:16 -07002451 rs = readl(&ch_ctrl->rs_control);
2452 if (set & TIOCM_RTS)
2453 rs |= C_RS_RTS;
2454 if (clear & TIOCM_RTS)
2455 rs &= ~C_RS_RTS;
2456 if (set & TIOCM_DTR) {
2457 rs |= C_RS_DTR;
2458#ifdef CY_DEBUG_DTR
2459 printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n");
2460#endif
2461 }
2462 if (clear & TIOCM_DTR) {
2463 rs &= ~C_RS_DTR;
2464#ifdef CY_DEBUG_DTR
2465 printk(KERN_DEBUG "cyc:set_modem_info clearing "
2466 "Z DTR\n");
2467#endif
2468 }
2469 cy_writel(&ch_ctrl->rs_control, rs);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002470 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby0d348722009-09-19 13:13:16 -07002471 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002472 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002473 printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
2474 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002475 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002477 return 0;
Jiri Slaby0d348722009-09-19 13:13:16 -07002478}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479
2480/*
2481 * cy_break() --- routine which turns the break handling on or off
2482 */
Alan Cox9e989662008-07-22 11:18:03 +01002483static int cy_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002485 struct cyclades_port *info = tty->driver_data;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002486 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002487 unsigned long flags;
Alan Cox9e989662008-07-22 11:18:03 +01002488 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489
Jiri Slaby02f11752006-12-08 02:39:28 -08002490 if (serial_paranoia_check(info, tty->name, "cy_break"))
Alan Cox9e989662008-07-22 11:18:03 +01002491 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002493 card = info->card;
2494
2495 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby2693f482009-06-11 12:31:06 +01002496 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002497 /* Let the transmit ISR take care of this (since it
2498 requires stuffing characters into the output stream).
2499 */
2500 if (break_state == -1) {
2501 if (!info->breakon) {
2502 info->breakon = 1;
2503 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002504 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002505 start_xmit(info);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002506 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002507 }
2508 }
2509 } else {
2510 if (!info->breakoff) {
2511 info->breakoff = 1;
2512 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002513 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002514 start_xmit(info);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002515 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002516 }
2517 }
2518 }
2519 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08002520 if (break_state == -1) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002521 retval = cyz_issue_cmd(card,
2522 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002523 C_CM_SET_BREAK, 0L);
2524 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002525 printk(KERN_ERR "cyc:cy_break (set) retval on "
2526 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002527 }
2528 } else {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002529 retval = cyz_issue_cmd(card,
2530 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002531 C_CM_CLR_BREAK, 0L);
2532 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002533 printk(KERN_DEBUG "cyc:cy_break (clr) retval "
2534 "on ttyC%d was %x\n", info->line,
2535 retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002536 }
2537 }
2538 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002539 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Cox9e989662008-07-22 11:18:03 +01002540 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08002541} /* cy_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542
Jiri Slaby02f11752006-12-08 02:39:28 -08002543static int set_threshold(struct cyclades_port *info, unsigned long value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002545 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002546 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547
Jiri Slaby2693f482009-06-11 12:31:06 +01002548 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002549 info->cor3 &= ~CyREC_FIFO;
2550 info->cor3 |= value & CyREC_FIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002552 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002553 cyy_writeb(info, CyCOR3, info->cor3);
2554 cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002555 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002556 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002558} /* set_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559
Alan Cox15ed6cc2008-04-30 00:53:55 -07002560static int get_threshold(struct cyclades_port *info,
2561 unsigned long __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002563 struct cyclades_card *card = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564
Jiri Slaby2693f482009-06-11 12:31:06 +01002565 if (!cy_is_Z(card)) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002566 u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO;
Jiri Slaby02f11752006-12-08 02:39:28 -08002567 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002568 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002569 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002570} /* get_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571
Jiri Slaby02f11752006-12-08 02:39:28 -08002572static int set_timeout(struct cyclades_port *info, unsigned long value)
2573{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002574 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002575 unsigned long flags;
2576
Jiri Slaby2693f482009-06-11 12:31:06 +01002577 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002578 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002579 cyy_writeb(info, CyRTPR, value & 0xff);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002580 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002581 }
2582 return 0;
2583} /* set_timeout */
2584
Alan Cox15ed6cc2008-04-30 00:53:55 -07002585static int get_timeout(struct cyclades_port *info,
2586 unsigned long __user *value)
Jiri Slaby02f11752006-12-08 02:39:28 -08002587{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002588 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002589
Jiri Slaby2693f482009-06-11 12:31:06 +01002590 if (!cy_is_Z(card)) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002591 u8 tmp = cyy_readb(info, CyRTPR);
Jiri Slaby02f11752006-12-08 02:39:28 -08002592 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002593 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002594 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002595} /* get_timeout */
2596
Jiri Slaby6c281812009-09-19 13:13:15 -07002597static int cy_cflags_changed(struct cyclades_port *info, unsigned long arg,
2598 struct cyclades_icount *cprev)
Jiri Slaby02f11752006-12-08 02:39:28 -08002599{
Jiri Slaby6c281812009-09-19 13:13:15 -07002600 struct cyclades_icount cnow;
2601 unsigned long flags;
2602 int ret;
Jiri Slaby02f11752006-12-08 02:39:28 -08002603
Jiri Slaby6c281812009-09-19 13:13:15 -07002604 spin_lock_irqsave(&info->card->card_lock, flags);
2605 cnow = info->icount; /* atomic copy */
2606 spin_unlock_irqrestore(&info->card->card_lock, flags);
2607
2608 ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
2609 ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
2610 ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) ||
2611 ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
2612
2613 *cprev = cnow;
2614
2615 return ret;
2616}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617
2618/*
2619 * This routine allows the tty driver to implement device-
2620 * specific ioctl's. If the ioctl number passed in cmd is
2621 * not recognized by the driver, it should return ENOIOCTLCMD.
2622 */
2623static int
Alan Cox6caa76b2011-02-14 16:27:22 +00002624cy_ioctl(struct tty_struct *tty,
Jiri Slaby02f11752006-12-08 02:39:28 -08002625 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002627 struct cyclades_port *info = tty->driver_data;
Jiri Slaby6c281812009-09-19 13:13:15 -07002628 struct cyclades_icount cnow; /* kernel counter temps */
Jiri Slaby02f11752006-12-08 02:39:28 -08002629 int ret_val = 0;
2630 unsigned long flags;
2631 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632
Jiri Slaby02f11752006-12-08 02:39:28 -08002633 if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
2634 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635
2636#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002637 printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
2638 info->line, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639#endif
2640
Jiri Slaby02f11752006-12-08 02:39:28 -08002641 switch (cmd) {
2642 case CYGETMON:
Jiri Slaby6c281812009-09-19 13:13:15 -07002643 if (copy_to_user(argp, &info->mon, sizeof(info->mon))) {
2644 ret_val = -EFAULT;
2645 break;
2646 }
2647 memset(&info->mon, 0, sizeof(info->mon));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002649 case CYGETTHRESH:
2650 ret_val = get_threshold(info, argp);
2651 break;
2652 case CYSETTHRESH:
2653 ret_val = set_threshold(info, arg);
2654 break;
2655 case CYGETDEFTHRESH:
Jiri Slaby6c281812009-09-19 13:13:15 -07002656 ret_val = put_user(info->default_threshold,
2657 (unsigned long __user *)argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002658 break;
2659 case CYSETDEFTHRESH:
Jiri Slaby6c281812009-09-19 13:13:15 -07002660 info->default_threshold = arg & 0x0f;
Jiri Slaby02f11752006-12-08 02:39:28 -08002661 break;
2662 case CYGETTIMEOUT:
2663 ret_val = get_timeout(info, argp);
2664 break;
2665 case CYSETTIMEOUT:
2666 ret_val = set_timeout(info, arg);
2667 break;
2668 case CYGETDEFTIMEOUT:
Jiri Slaby6c281812009-09-19 13:13:15 -07002669 ret_val = put_user(info->default_timeout,
2670 (unsigned long __user *)argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002671 break;
2672 case CYSETDEFTIMEOUT:
Jiri Slaby6c281812009-09-19 13:13:15 -07002673 info->default_timeout = arg & 0xff;
Jiri Slaby02f11752006-12-08 02:39:28 -08002674 break;
2675 case CYSETRFLOW:
2676 info->rflow = (int)arg;
Jiri Slaby02f11752006-12-08 02:39:28 -08002677 break;
2678 case CYGETRFLOW:
2679 ret_val = info->rflow;
2680 break;
2681 case CYSETRTSDTR_INV:
2682 info->rtsdtr_inv = (int)arg;
Jiri Slaby02f11752006-12-08 02:39:28 -08002683 break;
2684 case CYGETRTSDTR_INV:
2685 ret_val = info->rtsdtr_inv;
2686 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 case CYGETCD1400VER:
Jiri Slaby02f11752006-12-08 02:39:28 -08002688 ret_val = info->chip_rev;
2689 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690#ifndef CONFIG_CYZ_INTR
2691 case CYZSETPOLLCYCLE:
Qixue Xiao351d6202013-12-20 17:51:12 +08002692 if (arg > LONG_MAX / HZ)
2693 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08002694 cyz_polling_cycle = (arg * HZ) / 1000;
Jiri Slaby02f11752006-12-08 02:39:28 -08002695 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 case CYZGETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08002697 ret_val = (cyz_polling_cycle * 1000) / HZ;
2698 break;
2699#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 case CYSETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002701 info->port.closing_wait = (unsigned short)arg * HZ / 100;
Jiri Slaby02f11752006-12-08 02:39:28 -08002702 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 case CYGETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002704 ret_val = info->port.closing_wait / (HZ / 100);
Jiri Slaby02f11752006-12-08 02:39:28 -08002705 break;
2706 case TIOCGSERIAL:
Jiri Slaby6c281812009-09-19 13:13:15 -07002707 ret_val = cy_get_serial_info(info, argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002708 break;
2709 case TIOCSSERIAL:
Jiri Slabyd13549f2009-09-19 13:13:12 -07002710 ret_val = cy_set_serial_info(info, tty, argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002711 break;
2712 case TIOCSERGETLSR: /* Get line status register */
2713 ret_val = get_lsr_info(info, argp);
2714 break;
2715 /*
2716 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
2717 * - mask passed in arg for lines of interest
2718 * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
2719 * Caller should use TIOCGICOUNT to see which one it was
2720 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 case TIOCMIWAIT:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002722 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002723 /* note the counters on entry */
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002724 cnow = info->icount;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002725 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Coxbdc04e32009-09-19 13:13:31 -07002726 ret_val = wait_event_interruptible(info->port.delta_msr_wait,
Jiri Slaby6c281812009-09-19 13:13:15 -07002727 cy_cflags_changed(info, arg, &cnow));
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002728 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002729
2730 /*
2731 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2732 * Return: write counters to the user passed counter struct
2733 * NB: both 1->0 and 0->1 transitions are counted except for
2734 * RI where only 0->1 is counted.
2735 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002736 default:
2737 ret_val = -ENOIOCTLCMD;
2738 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739
2740#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002741 printk(KERN_DEBUG "cyc:cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002743 return ret_val;
2744} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745
Alan Cox05871022010-09-16 18:21:52 +01002746static int cy_get_icount(struct tty_struct *tty,
2747 struct serial_icounter_struct *sic)
2748{
2749 struct cyclades_port *info = tty->driver_data;
2750 struct cyclades_icount cnow; /* Used to snapshot */
2751 unsigned long flags;
2752
2753 spin_lock_irqsave(&info->card->card_lock, flags);
2754 cnow = info->icount;
2755 spin_unlock_irqrestore(&info->card->card_lock, flags);
2756
2757 sic->cts = cnow.cts;
2758 sic->dsr = cnow.dsr;
2759 sic->rng = cnow.rng;
2760 sic->dcd = cnow.dcd;
2761 sic->rx = cnow.rx;
2762 sic->tx = cnow.tx;
2763 sic->frame = cnow.frame;
2764 sic->overrun = cnow.overrun;
2765 sic->parity = cnow.parity;
2766 sic->brk = cnow.brk;
2767 sic->buf_overrun = cnow.buf_overrun;
2768 return 0;
2769}
2770
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771/*
2772 * This routine allows the tty driver to be notified when
2773 * device's termios settings have changed. Note that a
2774 * well-designed tty driver should be prepared to accept the case
2775 * where old == NULL, and try to do something rational.
2776 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002777static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002779 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780
2781#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002782 printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783#endif
2784
Jiri Slabyd13549f2009-09-19 13:13:12 -07002785 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786
Peter Hurley9db276f2016-01-10 20:36:15 -08002787 if ((old_termios->c_cflag & CRTSCTS) && !C_CRTSCTS(tty)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002788 tty->hw_stopped = 0;
2789 cy_start(tty);
2790 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791#if 0
Jiri Slaby02f11752006-12-08 02:39:28 -08002792 /*
2793 * No need to wake up processes in open wait, since they
2794 * sample the CLOCAL flag once, and don't recheck it.
2795 * XXX It's not clear whether the current behavior is correct
2796 * or not. Hence, this may change.....
2797 */
Peter Hurley9db276f2016-01-10 20:36:15 -08002798 if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
Alan Cox77451e52008-07-16 21:57:02 +01002799 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002801} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802
2803/* This function is used to send a high-priority XON/XOFF character to
2804 the device.
2805*/
Jiri Slaby02f11752006-12-08 02:39:28 -08002806static void cy_send_xchar(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002808 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002809 struct cyclades_card *card;
2810 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811
Jiri Slaby02f11752006-12-08 02:39:28 -08002812 if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 return;
2814
Jiri Slaby02f11752006-12-08 02:39:28 -08002815 info->x_char = ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816
2817 if (ch)
Jiri Slaby02f11752006-12-08 02:39:28 -08002818 cy_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819
2820 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002821 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822
Jiri Slaby2693f482009-06-11 12:31:06 +01002823 if (cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002824 if (ch == STOP_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07002825 cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002826 else if (ch == START_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07002827 cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 }
2829}
2830
2831/* This routine is called by the upper-layer tty layer to signal
2832 that incoming characters should be throttled because the input
2833 buffers are close to full.
2834 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002835static void cy_throttle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002837 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002838 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002839 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840
2841#ifdef CY_DEBUG_THROTTLE
Peter Hurleyfdfb7192016-01-10 22:40:54 -08002842 printk(KERN_DEBUG "cyc:throttle %s ...ttyC%d\n", tty_name(tty),
2843 info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844#endif
2845
Alan Cox15ed6cc2008-04-30 00:53:55 -07002846 if (serial_paranoia_check(info, tty->name, "cy_throttle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08002847 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848
Jiri Slaby02f11752006-12-08 02:39:28 -08002849 card = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850
Jiri Slaby02f11752006-12-08 02:39:28 -08002851 if (I_IXOFF(tty)) {
Jiri Slaby2693f482009-06-11 12:31:06 +01002852 if (!cy_is_Z(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002853 cy_send_xchar(tty, STOP_CHAR(tty));
2854 else
2855 info->throttle = 1;
2856 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857
Peter Hurley9db276f2016-01-10 20:36:15 -08002858 if (C_CRTSCTS(tty)) {
Jiri Slaby2693f482009-06-11 12:31:06 +01002859 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002860 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07002861 cyy_change_rts_dtr(info, 0, TIOCM_RTS);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002862 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002863 } else {
2864 info->throttle = 1;
2865 }
2866 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002867} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868
2869/*
2870 * This routine notifies the tty driver that it should signal
2871 * that characters can now be sent to the tty without fear of
2872 * overrunning the input buffers of the line disciplines.
2873 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002874static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002876 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002877 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002878 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879
2880#ifdef CY_DEBUG_THROTTLE
Peter Hurleyfdfb7192016-01-10 22:40:54 -08002881 printk(KERN_DEBUG "cyc:unthrottle %s ...ttyC%d\n",
2882 tty_name(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883#endif
2884
Alan Cox15ed6cc2008-04-30 00:53:55 -07002885 if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08002886 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887
Jiri Slaby02f11752006-12-08 02:39:28 -08002888 if (I_IXOFF(tty)) {
2889 if (info->x_char)
2890 info->x_char = 0;
2891 else
2892 cy_send_xchar(tty, START_CHAR(tty));
2893 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894
Peter Hurley9db276f2016-01-10 20:36:15 -08002895 if (C_CRTSCTS(tty)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002896 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01002897 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002898 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07002899 cyy_change_rts_dtr(info, TIOCM_RTS, 0);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002900 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002901 } else {
2902 info->throttle = 0;
2903 }
2904 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002905} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906
2907/* cy_start and cy_stop provide software output flow control as a
2908 function of XON/XOFF, software CTS, and other such stuff.
2909*/
Jiri Slaby02f11752006-12-08 02:39:28 -08002910static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911{
Jiri Slaby02f11752006-12-08 02:39:28 -08002912 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002913 struct cyclades_port *info = tty->driver_data;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002914 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08002915 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916
2917#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002918 printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919#endif
2920
Jiri Slaby02f11752006-12-08 02:39:28 -08002921 if (serial_paranoia_check(info, tty->name, "cy_stop"))
2922 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923
Jiri Slaby875b2062007-05-08 00:36:49 -07002924 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002925 channel = info->line - cinfo->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002926 if (!cy_is_Z(cinfo)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002927 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002928 cyy_writeb(info, CyCAR, channel & 0x03);
2929 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002930 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002932} /* cy_stop */
2933
2934static void cy_start(struct tty_struct *tty)
2935{
2936 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002937 struct cyclades_port *info = tty->driver_data;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002938 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08002939 unsigned long flags;
2940
2941#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002942 printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
Jiri Slaby02f11752006-12-08 02:39:28 -08002943#endif
2944
2945 if (serial_paranoia_check(info, tty->name, "cy_start"))
2946 return;
2947
Jiri Slaby875b2062007-05-08 00:36:49 -07002948 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002949 channel = info->line - cinfo->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002950 if (!cy_is_Z(cinfo)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002951 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002952 cyy_writeb(info, CyCAR, channel & 0x03);
2953 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002954 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002955 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002956} /* cy_start */
2957
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958/*
2959 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
2960 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002961static void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002963 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08002964
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002966 printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967#endif
2968
Jiri Slaby02f11752006-12-08 02:39:28 -08002969 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
2970 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971
Jiri Slaby02f11752006-12-08 02:39:28 -08002972 cy_flush_buffer(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07002973 cy_shutdown(info, tty);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07002974 tty_port_hangup(&info->port);
Jiri Slaby02f11752006-12-08 02:39:28 -08002975} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976
Jiri Slabyf0737572009-09-19 13:13:12 -07002977static int cyy_carrier_raised(struct tty_port *port)
2978{
2979 struct cyclades_port *info = container_of(port, struct cyclades_port,
2980 port);
2981 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0737572009-09-19 13:13:12 -07002982 unsigned long flags;
2983 int channel = info->line - cinfo->first_line;
Jiri Slabyf0737572009-09-19 13:13:12 -07002984 u32 cd;
2985
Jiri Slabyf0737572009-09-19 13:13:12 -07002986 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002987 cyy_writeb(info, CyCAR, channel & 0x03);
2988 cd = cyy_readb(info, CyMSVR1) & CyDCD;
Jiri Slabyf0737572009-09-19 13:13:12 -07002989 spin_unlock_irqrestore(&cinfo->card_lock, flags);
2990
2991 return cd;
2992}
2993
2994static void cyy_dtr_rts(struct tty_port *port, int raise)
2995{
2996 struct cyclades_port *info = container_of(port, struct cyclades_port,
2997 port);
2998 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0737572009-09-19 13:13:12 -07002999 unsigned long flags;
Jiri Slabyf0737572009-09-19 13:13:12 -07003000
3001 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07003002 cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
3003 raise ? 0 : TIOCM_RTS | TIOCM_DTR);
Jiri Slabyf0737572009-09-19 13:13:12 -07003004 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3005}
3006
3007static int cyz_carrier_raised(struct tty_port *port)
3008{
3009 struct cyclades_port *info = container_of(port, struct cyclades_port,
3010 port);
Jiri Slabyf0737572009-09-19 13:13:12 -07003011
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003012 return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
Jiri Slabyf0737572009-09-19 13:13:12 -07003013}
3014
3015static void cyz_dtr_rts(struct tty_port *port, int raise)
3016{
3017 struct cyclades_port *info = container_of(port, struct cyclades_port,
3018 port);
3019 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003020 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slabyf0737572009-09-19 13:13:12 -07003021 int ret, channel = info->line - cinfo->first_line;
3022 u32 rs;
3023
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003024 rs = readl(&ch_ctrl->rs_control);
Jiri Slabyf0737572009-09-19 13:13:12 -07003025 if (raise)
3026 rs |= C_RS_RTS | C_RS_DTR;
3027 else
3028 rs &= ~(C_RS_RTS | C_RS_DTR);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003029 cy_writel(&ch_ctrl->rs_control, rs);
Jiri Slabyf0737572009-09-19 13:13:12 -07003030 ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L);
3031 if (ret != 0)
3032 printk(KERN_ERR "%s: retval on ttyC%d was %x\n",
3033 __func__, info->line, ret);
3034#ifdef CY_DEBUG_DTR
3035 printk(KERN_DEBUG "%s: raising Z DTR\n", __func__);
3036#endif
3037}
3038
3039static const struct tty_port_operations cyy_port_ops = {
3040 .carrier_raised = cyy_carrier_raised,
3041 .dtr_rts = cyy_dtr_rts,
Alan Coxe936ffd2009-09-19 13:13:22 -07003042 .shutdown = cy_do_close,
Jiri Slabyf0737572009-09-19 13:13:12 -07003043};
3044
3045static const struct tty_port_operations cyz_port_ops = {
3046 .carrier_raised = cyz_carrier_raised,
3047 .dtr_rts = cyz_dtr_rts,
Alan Coxe936ffd2009-09-19 13:13:22 -07003048 .shutdown = cy_do_close,
Jiri Slabyf0737572009-09-19 13:13:12 -07003049};
3050
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051/*
3052 * ---------------------------------------------------------------------
3053 * cy_init() and friends
3054 *
3055 * cy_init() is called at boot-time to initialize the serial driver.
3056 * ---------------------------------------------------------------------
3057 */
3058
Bill Pemberton9671f092012-11-19 13:21:50 -05003059static int cy_init_card(struct cyclades_card *cinfo)
Jiri Slaby0809e262007-05-08 00:36:14 -07003060{
3061 struct cyclades_port *info;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003062 unsigned int channel, port;
Jiri Slaby0809e262007-05-08 00:36:14 -07003063
Jiri Slaby3046d502007-05-08 00:36:46 -07003064 spin_lock_init(&cinfo->card_lock);
Jiri Slaby963118e2009-06-11 12:34:27 +01003065 cinfo->intr_enabled = 0;
Jiri Slaby3046d502007-05-08 00:36:46 -07003066
Jiri Slaby963118e2009-06-11 12:34:27 +01003067 cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
3068 GFP_KERNEL);
Jiri Slabydd025c02007-05-08 00:37:02 -07003069 if (cinfo->ports == NULL) {
3070 printk(KERN_ERR "Cyclades: cannot allocate ports\n");
3071 return -ENOMEM;
3072 }
3073
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003074 for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
3075 channel++, port++) {
3076 info = &cinfo->ports[channel];
Alan Cox44b7d1b2008-07-16 21:57:18 +01003077 tty_port_init(&info->port);
Jiri Slaby3046d502007-05-08 00:36:46 -07003078 info->magic = CYCLADES_MAGIC;
Jiri Slaby875b2062007-05-08 00:36:49 -07003079 info->card = cinfo;
Jiri Slaby3046d502007-05-08 00:36:46 -07003080 info->line = port;
Jiri Slaby3046d502007-05-08 00:36:46 -07003081
Alan Cox44b7d1b2008-07-16 21:57:18 +01003082 info->port.closing_wait = CLOSING_WAIT_DELAY;
3083 info->port.close_delay = 5 * HZ / 10;
Jiri Slaby2c7fea92007-05-08 00:36:51 -07003084 init_completion(&info->shutdown_wait);
Jiri Slaby3046d502007-05-08 00:36:46 -07003085
Jiri Slaby2693f482009-06-11 12:31:06 +01003086 if (cy_is_Z(cinfo)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003087 struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
3088 struct ZFW_CTRL *zfw_ctrl;
3089
Jiri Slabyf0737572009-09-19 13:13:12 -07003090 info->port.ops = &cyz_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003091 info->type = PORT_STARTECH;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003092
3093 zfw_ctrl = cinfo->base_addr +
3094 (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3095 info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
3096 info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
3097
Jiri Slaby101b8152009-06-11 12:30:10 +01003098 if (cinfo->hw_ver == ZO_V1)
Jiri Slaby0809e262007-05-08 00:36:14 -07003099 info->xmit_fifo_size = CYZ_FIFO_SIZE;
3100 else
Jiri Slaby3046d502007-05-08 00:36:46 -07003101 info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
Jiri Slaby0809e262007-05-08 00:36:14 -07003102#ifdef CONFIG_CYZ_INTR
Jiri Slaby39914282007-05-08 00:36:54 -07003103 setup_timer(&cyz_rx_full_timer[port],
3104 cyz_rx_restart, (unsigned long)info);
Jiri Slaby0809e262007-05-08 00:36:14 -07003105#endif
Jiri Slaby3046d502007-05-08 00:36:46 -07003106 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003107 unsigned short chip_number;
Jiri Slaby963118e2009-06-11 12:34:27 +01003108 int index = cinfo->bus_index;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003109
Jiri Slabyf0737572009-09-19 13:13:12 -07003110 info->port.ops = &cyy_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003111 info->type = PORT_CIRRUS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003112 info->xmit_fifo_size = CyMAX_CHAR_FIFO;
Jiri Slaby3046d502007-05-08 00:36:46 -07003113 info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003114 info->cor2 = CyETC;
3115 info->cor3 = 0x08; /* _very_ small rcv threshold */
Jiri Slaby3046d502007-05-08 00:36:46 -07003116
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003117 chip_number = channel / CyPORTS_PER_CHIP;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07003118 info->u.cyy.base_addr = cinfo->base_addr +
3119 (cy_chip_offset[chip_number] << index);
3120 info->chip_rev = cyy_readb(info, CyGFRCR);
Alan Cox15ed6cc2008-04-30 00:53:55 -07003121
3122 if (info->chip_rev >= CD1400_REV_J) {
Jiri Slaby0809e262007-05-08 00:36:14 -07003123 /* It is a CD1400 rev. J or later */
3124 info->tbpr = baud_bpr_60[13]; /* Tx BPR */
3125 info->tco = baud_co_60[13]; /* Tx CO */
3126 info->rbpr = baud_bpr_60[13]; /* Rx BPR */
3127 info->rco = baud_co_60[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003128 info->rtsdtr_inv = 1;
3129 } else {
3130 info->tbpr = baud_bpr_25[13]; /* Tx BPR */
3131 info->tco = baud_co_25[13]; /* Tx CO */
3132 info->rbpr = baud_bpr_25[13]; /* Rx BPR */
3133 info->rco = baud_co_25[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003134 info->rtsdtr_inv = 0;
3135 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003136 info->read_status_mask = CyTIMEOUT | CySPECHAR |
3137 CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
Jiri Slaby0809e262007-05-08 00:36:14 -07003138 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003139
Jiri Slaby0809e262007-05-08 00:36:14 -07003140 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003141
3142#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003143 if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
Jiri Slaby3046d502007-05-08 00:36:46 -07003144 mod_timer(&cyz_timerlist, jiffies + 1);
3145#ifdef CY_PCI_DEBUG
3146 printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
3147#endif
3148 }
3149#endif
Jiri Slabydd025c02007-05-08 00:37:02 -07003150 return 0;
Jiri Slaby0809e262007-05-08 00:36:14 -07003151}
3152
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153/* initialize chips on Cyclom-Y card -- return number of valid
3154 chips (which is number of ports/4) */
Bill Pemberton9671f092012-11-19 13:21:50 -05003155static unsigned short cyy_init_card(void __iomem *true_base_addr,
Jiri Slaby31b4f0a2007-05-08 00:36:44 -07003156 int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157{
Jiri Slaby02f11752006-12-08 02:39:28 -08003158 unsigned int chip_number;
3159 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160
Jiri Slaby02f11752006-12-08 02:39:28 -08003161 cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
3162 /* Cy_HwReset is 0x1400 */
3163 cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
3164 /* Cy_ClrIntr is 0x1800 */
3165 udelay(500L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166
Alan Cox15ed6cc2008-04-30 00:53:55 -07003167 for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
3168 chip_number++) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003169 base_addr =
3170 true_base_addr + (cy_chip_offset[chip_number] << index);
3171 mdelay(1);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003172 if (readb(base_addr + (CyCCR << index)) != 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003173 /*************
3174 printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
3175 chip_number, (unsigned long)base_addr);
3176 *************/
3177 return chip_number;
3178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179
Jiri Slaby02f11752006-12-08 02:39:28 -08003180 cy_writeb(base_addr + (CyGFRCR << index), 0);
3181 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182
Jiri Slaby02f11752006-12-08 02:39:28 -08003183 /* The Cyclom-16Y does not decode address bit 9 and therefore
3184 cannot distinguish between references to chip 0 and a non-
3185 existent chip 4. If the preceding clearing of the supposed
3186 chip 4 GFRCR register appears at chip 0, there is no chip 4
3187 and this must be a Cyclom-16Y, not a Cyclom-32Ye.
3188 */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003189 if (chip_number == 4 && readb(true_base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08003190 (cy_chip_offset[0] << index) +
3191 (CyGFRCR << index)) == 0) {
3192 return chip_number;
3193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194
Jiri Slaby02f11752006-12-08 02:39:28 -08003195 cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
3196 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003198 if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003199 /*
3200 printk(" chip #%d at %#6lx is not responding ",
3201 chip_number, (unsigned long)base_addr);
3202 printk("(GFRCR stayed 0)\n",
3203 */
3204 return chip_number;
3205 }
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003206 if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
Jiri Slaby02f11752006-12-08 02:39:28 -08003207 0x40) {
3208 /*
3209 printk(" chip #%d at %#6lx is not valid (GFRCR == "
3210 "%#2x)\n",
3211 chip_number, (unsigned long)base_addr,
3212 base_addr[CyGFRCR<<index]);
3213 */
3214 return chip_number;
3215 }
3216 cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003217 if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003218 /* It is a CD1400 rev. J or later */
3219 /* Impossible to reach 5ms with this chip.
3220 Changed to 2ms instead (f = 500 Hz). */
3221 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
3222 } else {
3223 /* f = 200 Hz */
3224 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
3225 }
3226
3227 /*
3228 printk(" chip #%d at %#6lx is rev 0x%2x\n",
3229 chip_number, (unsigned long)base_addr,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003230 readb(base_addr+(CyGFRCR<<index)));
Jiri Slaby02f11752006-12-08 02:39:28 -08003231 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003233 return chip_number;
3234} /* cyy_init_card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235
3236/*
3237 * ---------------------------------------------------------------------
3238 * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
3239 * sets global variables and return the number of ISA boards found.
3240 * ---------------------------------------------------------------------
3241 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003242static int __init cy_detect_isa(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243{
3244#ifdef CONFIG_ISA
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003245 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003246 unsigned short cy_isa_irq, nboard;
3247 void __iomem *cy_isa_address;
Jiri Slaby734cc172012-08-07 21:47:47 +02003248 unsigned short i, j, k, cy_isa_nchan;
Jiri Slaby02f11752006-12-08 02:39:28 -08003249 int isparam = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250
Jiri Slaby02f11752006-12-08 02:39:28 -08003251 nboard = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 /* Check for module parameters */
Jiri Slaby02f11752006-12-08 02:39:28 -08003254 for (i = 0; i < NR_CARDS; i++) {
3255 if (maddr[i] || i) {
3256 isparam = 1;
3257 cy_isa_addresses[i] = maddr[i];
3258 }
3259 if (!maddr[i])
3260 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262
Jiri Slaby02f11752006-12-08 02:39:28 -08003263 /* scan the address table probing for Cyclom-Y/ISA boards */
3264 for (i = 0; i < NR_ISA_ADDRS; i++) {
3265 unsigned int isa_address = cy_isa_addresses[i];
Alan Cox15ed6cc2008-04-30 00:53:55 -07003266 if (isa_address == 0x0000)
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003267 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268
Jiri Slaby02f11752006-12-08 02:39:28 -08003269 /* probe for CD1400... */
Alan Coxcd989b32008-04-30 00:53:56 -07003270 cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003271 if (cy_isa_address == NULL) {
3272 printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
3273 "address\n");
3274 continue;
3275 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003276 cy_isa_nchan = CyPORTS_PER_CHIP *
3277 cyy_init_card(cy_isa_address, 0);
3278 if (cy_isa_nchan == 0) {
Jiri Slaby31375532007-05-08 00:37:04 -07003279 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003280 continue;
3281 }
Bartlomiej Zolnierkiewicz20904362009-12-09 12:34:14 -08003282
Roel Kluin196b3162009-10-01 15:44:24 -07003283 if (isparam && i < NR_CARDS && irq[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08003284 cy_isa_irq = irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 else
Jiri Slaby02f11752006-12-08 02:39:28 -08003286 /* find out the board's irq by probing */
3287 cy_isa_irq = detect_isa_irq(cy_isa_address);
3288 if (cy_isa_irq == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003289 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
3290 "IRQ could not be detected.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003291 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003292 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003293 continue;
3294 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295
Jiri Slaby02f11752006-12-08 02:39:28 -08003296 if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
Jiri Slaby21719192007-05-08 00:36:42 -07003297 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3298 "more channels are available. Change NR_PORTS "
3299 "in cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003300 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003301 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003302 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003303 }
3304 /* fill the next cy_card structure available */
3305 for (j = 0; j < NR_CARDS; j++) {
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003306 card = &cy_card[j];
3307 if (card->base_addr == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08003308 break;
3309 }
3310 if (j == NR_CARDS) { /* no more cy_cards available */
Jiri Slaby21719192007-05-08 00:36:42 -07003311 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3312 "more cards can be used. Change NR_CARDS in "
3313 "cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003314 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003315 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003316 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003317 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318
Jiri Slaby02f11752006-12-08 02:39:28 -08003319 /* allocate IRQ */
3320 if (request_irq(cy_isa_irq, cyy_interrupt,
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003321 0, "Cyclom-Y", card)) {
Jiri Slaby21719192007-05-08 00:36:42 -07003322 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
3323 "could not allocate IRQ#%d.\n",
3324 (unsigned long)cy_isa_address, cy_isa_irq);
Jiri Slaby31375532007-05-08 00:37:04 -07003325 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003326 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003327 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328
Jiri Slaby02f11752006-12-08 02:39:28 -08003329 /* set cy_card */
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003330 card->base_addr = cy_isa_address;
3331 card->ctl_addr.p9050 = NULL;
3332 card->irq = (int)cy_isa_irq;
3333 card->bus_index = 0;
3334 card->first_line = cy_next_channel;
3335 card->num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
3336 card->nports = cy_isa_nchan;
3337 if (cy_init_card(card)) {
3338 card->base_addr = NULL;
3339 free_irq(cy_isa_irq, card);
Jiri Slaby31375532007-05-08 00:37:04 -07003340 iounmap(cy_isa_address);
3341 continue;
3342 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003343 nboard++;
3344
Jiri Slaby21719192007-05-08 00:36:42 -07003345 printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
3346 "%d channels starting from port %d\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003347 j + 1, (unsigned long)cy_isa_address,
3348 (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
Jiri Slaby21719192007-05-08 00:36:42 -07003349 cy_isa_irq, cy_isa_nchan, cy_next_channel);
3350
Jiri Slaby734cc172012-08-07 21:47:47 +02003351 for (k = 0, j = cy_next_channel;
3352 j < cy_next_channel + cy_isa_nchan; j++, k++)
3353 tty_port_register_device(&card->ports[k].port,
3354 cy_serial_driver, j, NULL);
Jiri Slaby02f11752006-12-08 02:39:28 -08003355 cy_next_channel += cy_isa_nchan;
3356 }
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003357 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358#else
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003359 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08003360#endif /* CONFIG_ISA */
3361} /* cy_detect_isa */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362
Jiri Slaby58936d82007-05-08 00:36:13 -07003363#ifdef CONFIG_PCI
Bill Pemberton9671f092012-11-19 13:21:50 -05003364static inline int cyc_isfwstr(const char *str, unsigned int size)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003365{
3366 unsigned int a;
3367
3368 for (a = 0; a < size && *str; a++, str++)
3369 if (*str & 0x80)
3370 return -EINVAL;
3371
3372 for (; a < size; a++, str++)
3373 if (*str)
3374 return -EINVAL;
3375
3376 return 0;
3377}
3378
Bill Pemberton9671f092012-11-19 13:21:50 -05003379static inline void cyz_fpga_copy(void __iomem *fpga, const u8 *data,
Jiri Slaby054f5b02007-07-17 04:05:16 -07003380 unsigned int size)
3381{
3382 for (; size > 0; size--) {
3383 cy_writel(fpga, *data++);
3384 udelay(10);
3385 }
3386}
3387
Bill Pemberton9671f092012-11-19 13:21:50 -05003388static void plx_init(struct pci_dev *pdev, int irq,
Jiri Slaby054f5b02007-07-17 04:05:16 -07003389 struct RUNTIME_9060 __iomem *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390{
Jiri Slaby02f11752006-12-08 02:39:28 -08003391 /* Reset PLX */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003392 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003393 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003394 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395
Jiri Slaby02f11752006-12-08 02:39:28 -08003396 /* Reload Config. Registers from EEPROM */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003397 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003398 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003399 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);
3400
3401 /* For some yet unknown reason, once the PLX9060 reloads the EEPROM,
3402 * the IRQ is lost and, thus, we have to re-write it to the PCI config.
3403 * registers. This will remain here until we find a permanent fix.
3404 */
3405 pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
3406}
3407
Bill Pemberton9671f092012-11-19 13:21:50 -05003408static int __cyz_load_fw(const struct firmware *fw,
Jiri Slaby054f5b02007-07-17 04:05:16 -07003409 const char *name, const u32 mailbox, void __iomem *base,
3410 void __iomem *fpga)
3411{
David Woodhousef61e7612008-05-23 23:57:19 +01003412 const void *ptr = fw->data;
3413 const struct zfile_header *h = ptr;
3414 const struct zfile_config *c, *cs;
3415 const struct zfile_block *b, *bs;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003416 unsigned int a, tmp, len = fw->size;
3417#define BAD_FW KERN_ERR "Bad firmware: "
3418 if (len < sizeof(*h)) {
3419 printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h));
3420 return -EINVAL;
3421 }
3422
3423 cs = ptr + h->config_offset;
3424 bs = ptr + h->block_offset;
3425
3426 if ((void *)(cs + h->n_config) > ptr + len ||
3427 (void *)(bs + h->n_blocks) > ptr + len) {
3428 printk(BAD_FW "too short");
3429 return -EINVAL;
3430 }
3431
3432 if (cyc_isfwstr(h->name, sizeof(h->name)) ||
3433 cyc_isfwstr(h->date, sizeof(h->date))) {
3434 printk(BAD_FW "bad formatted header string\n");
3435 return -EINVAL;
3436 }
3437
3438 if (strncmp(name, h->name, sizeof(h->name))) {
3439 printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name);
3440 return -EINVAL;
3441 }
3442
3443 tmp = 0;
3444 for (c = cs; c < cs + h->n_config; c++) {
3445 for (a = 0; a < c->n_blocks; a++)
3446 if (c->block_list[a] > h->n_blocks) {
3447 printk(BAD_FW "bad block ref number in cfgs\n");
3448 return -EINVAL;
3449 }
3450 if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */
3451 tmp++;
3452 }
3453 if (!tmp) {
3454 printk(BAD_FW "nothing appropriate\n");
3455 return -EINVAL;
3456 }
3457
3458 for (b = bs; b < bs + h->n_blocks; b++)
3459 if (b->file_offset + b->size > len) {
3460 printk(BAD_FW "bad block data offset\n");
3461 return -EINVAL;
3462 }
3463
3464 /* everything is OK, let's seek'n'load it */
3465 for (c = cs; c < cs + h->n_config; c++)
3466 if (c->mailbox == mailbox && c->function == 0)
3467 break;
3468
3469 for (a = 0; a < c->n_blocks; a++) {
3470 b = &bs[c->block_list[a]];
3471 if (b->type == ZBLOCK_FPGA) {
3472 if (fpga != NULL)
3473 cyz_fpga_copy(fpga, ptr + b->file_offset,
3474 b->size);
3475 } else {
3476 if (base != NULL)
3477 memcpy_toio(base + b->ram_offset,
3478 ptr + b->file_offset, b->size);
3479 }
3480 }
3481#undef BAD_FW
3482 return 0;
3483}
3484
Bill Pemberton9671f092012-11-19 13:21:50 -05003485static int cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
Jiri Slaby054f5b02007-07-17 04:05:16 -07003486 struct RUNTIME_9060 __iomem *ctl_addr, int irq)
3487{
3488 const struct firmware *fw;
3489 struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
3490 struct CUSTOM_REG __iomem *cust = base_addr;
3491 struct ZFW_CTRL __iomem *pt_zfwctrl;
Jiri Slabyc4923b42007-07-17 04:05:17 -07003492 void __iomem *tmp;
Jiri Slaby963118e2009-06-11 12:34:27 +01003493 u32 mailbox, status, nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003494 unsigned int i;
3495 int retval;
3496
3497 retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev);
3498 if (retval) {
3499 dev_err(&pdev->dev, "can't get firmware\n");
3500 goto err;
3501 }
3502
3503 /* Check whether the firmware is already loaded and running. If
3504 positive, skip this board */
Jiri Slaby2693f482009-06-11 12:31:06 +01003505 if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003506 u32 cntval = readl(base_addr + 0x190);
3507
3508 udelay(100);
3509 if (cntval != readl(base_addr + 0x190)) {
3510 /* FW counter is working, FW is running */
3511 dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. "
3512 "Skipping board.\n");
3513 retval = 0;
3514 goto err_rel;
3515 }
3516 }
3517
3518 /* start boot */
3519 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) &
3520 ~0x00030800UL);
3521
3522 mailbox = readl(&ctl_addr->mail_box_0);
3523
Jiri Slaby2693f482009-06-11 12:31:06 +01003524 if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003525 /* stops CPU and set window to beginning of RAM */
3526 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3527 cy_writel(&cust->cpu_stop, 0);
3528 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3529 udelay(100);
3530 }
3531
3532 plx_init(pdev, irq, ctl_addr);
3533
3534 if (mailbox != 0) {
3535 /* load FPGA */
3536 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL,
3537 base_addr);
3538 if (retval)
3539 goto err_rel;
Jiri Slaby2693f482009-06-11 12:31:06 +01003540 if (!__cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003541 dev_err(&pdev->dev, "fw upload successful, but fw is "
3542 "not loaded\n");
3543 goto err_rel;
3544 }
3545 }
3546
3547 /* stops CPU and set window to beginning of RAM */
3548 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3549 cy_writel(&cust->cpu_stop, 0);
3550 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3551 udelay(100);
3552
3553 /* clear memory */
Jiri Slabyc4923b42007-07-17 04:05:17 -07003554 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003555 cy_writeb(tmp, 255);
3556 if (mailbox != 0) {
3557 /* set window to last 512K of RAM */
3558 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
Jiri Slabyc4923b42007-07-17 04:05:17 -07003559 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003560 cy_writeb(tmp, 255);
3561 /* set window to beginning of RAM */
3562 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003563 }
3564
3565 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
3566 release_firmware(fw);
3567 if (retval)
3568 goto err;
3569
3570 /* finish boot and start boards */
3571 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3572 cy_writel(&cust->cpu_start, 0);
3573 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3574 i = 0;
3575 while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40)
3576 msleep(100);
3577 if (status != ZFIRM_ID) {
3578 if (status == ZFIRM_HLT) {
3579 dev_err(&pdev->dev, "you need an external power supply "
3580 "for this number of ports. Firmware halted and "
3581 "board reset.\n");
3582 retval = -EIO;
3583 goto err;
3584 }
3585 dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting "
3586 "some more time\n", status);
3587 while ((status = readl(&fid->signature)) != ZFIRM_ID &&
3588 i++ < 200)
3589 msleep(100);
3590 if (status != ZFIRM_ID) {
3591 dev_err(&pdev->dev, "Board not started in 20 seconds! "
3592 "Giving up. (fid->signature = 0x%x)\n",
3593 status);
3594 dev_info(&pdev->dev, "*** Warning ***: if you are "
3595 "upgrading the FW, please power cycle the "
3596 "system before loading the new FW to the "
3597 "Cyclades-Z.\n");
3598
Jiri Slaby2693f482009-06-11 12:31:06 +01003599 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003600 plx_init(pdev, irq, ctl_addr);
3601
3602 retval = -EIO;
3603 goto err;
3604 }
3605 dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n",
3606 i / 10);
3607 }
3608 pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr);
3609
3610 dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n",
3611 base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
3612 base_addr + readl(&fid->zfwctrl_addr));
3613
Jiri Slaby963118e2009-06-11 12:34:27 +01003614 nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003615 dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
Jiri Slaby963118e2009-06-11 12:34:27 +01003616 readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003617
Jiri Slaby963118e2009-06-11 12:34:27 +01003618 if (nchan == 0) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003619 dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
3620 "check the connection between the Z host card and the "
3621 "serial expanders.\n");
3622
Jiri Slaby2693f482009-06-11 12:31:06 +01003623 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003624 plx_init(pdev, irq, ctl_addr);
3625
3626 dev_info(&pdev->dev, "Null number of ports detected. Board "
3627 "reset.\n");
3628 retval = 0;
3629 goto err;
3630 }
3631
3632 cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX);
3633 cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION);
3634
3635 /*
3636 Early firmware failed to start looking for commands.
3637 This enables firmware interrupts for those commands.
3638 */
3639 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3640 (1 << 17));
3641 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3642 0x00030800UL);
3643
Jiri Slaby963118e2009-06-11 12:34:27 +01003644 return nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003645err_rel:
3646 release_firmware(fw);
3647err:
3648 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649}
3650
Bill Pemberton9671f092012-11-19 13:21:50 -05003651static int cy_pci_probe(struct pci_dev *pdev,
Jiri Slaby58936d82007-05-08 00:36:13 -07003652 const struct pci_device_id *ent)
3653{
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003654 struct cyclades_card *card;
Jiri Slaby31375532007-05-08 00:37:04 -07003655 void __iomem *addr0 = NULL, *addr2 = NULL;
3656 char *card_name = NULL;
Jiri Slaby101b8152009-06-11 12:30:10 +01003657 u32 uninitialized_var(mailbox);
Jiri Slaby734cc172012-08-07 21:47:47 +02003658 unsigned int device_id, nchan = 0, card_no, i, j;
Jiri Slaby31375532007-05-08 00:37:04 -07003659 unsigned char plx_ver;
3660 int retval, irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003661
3662 retval = pci_enable_device(pdev);
3663 if (retval) {
3664 dev_err(&pdev->dev, "cannot enable device\n");
Jiri Slaby31375532007-05-08 00:37:04 -07003665 goto err;
Jiri Slaby58936d82007-05-08 00:36:13 -07003666 }
3667
3668 /* read PCI configuration area */
Jiri Slaby31375532007-05-08 00:37:04 -07003669 irq = pdev->irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003670 device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
3671
Jiri Slaby31375532007-05-08 00:37:04 -07003672#if defined(__alpha__)
3673 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
3674 dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
3675 "addresses on Alpha systems.\n");
3676 retval = -EIO;
3677 goto err_dis;
3678 }
3679#endif
3680 if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
3681 dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
3682 "addresses\n");
3683 retval = -EIO;
3684 goto err_dis;
3685 }
3686
3687 if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
3688 dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
3689 "it...\n");
3690 pdev->resource[2].flags &= ~IORESOURCE_IO;
3691 }
3692
3693 retval = pci_request_regions(pdev, "cyclades");
3694 if (retval) {
3695 dev_err(&pdev->dev, "failed to reserve resources\n");
3696 goto err_dis;
3697 }
3698
3699 retval = -EIO;
Jiri Slaby58936d82007-05-08 00:36:13 -07003700 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3701 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby31375532007-05-08 00:37:04 -07003702 card_name = "Cyclom-Y";
Jiri Slaby58936d82007-05-08 00:36:13 -07003703
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003704 addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
3705 CyPCI_Yctl);
Jiri Slaby31375532007-05-08 00:37:04 -07003706 if (addr0 == NULL) {
3707 dev_err(&pdev->dev, "can't remap ctl region\n");
3708 goto err_reg;
3709 }
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003710 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
3711 CyPCI_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003712 if (addr2 == NULL) {
3713 dev_err(&pdev->dev, "can't remap base region\n");
3714 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003715 }
3716
Jiri Slaby31375532007-05-08 00:37:04 -07003717 nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
3718 if (nchan == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003719 dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
3720 "Serial-Modules\n");
Andrew Mortonc847d472009-01-02 13:50:07 +00003721 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003722 }
Jiri Slaby31375532007-05-08 00:37:04 -07003723 } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
3724 struct RUNTIME_9060 __iomem *ctl_addr;
3725
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003726 ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
3727 CyPCI_Zctl);
Jiri Slaby31375532007-05-08 00:37:04 -07003728 if (addr0 == NULL) {
3729 dev_err(&pdev->dev, "can't remap ctl region\n");
3730 goto err_reg;
Jiri Slaby58936d82007-05-08 00:36:13 -07003731 }
3732
Jiri Slaby31375532007-05-08 00:37:04 -07003733 /* Disable interrupts on the PLX before resetting it */
Jiri Slaby97e87f82009-06-11 12:29:27 +01003734 cy_writew(&ctl_addr->intr_ctrl_stat,
3735 readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
Jiri Slaby31375532007-05-08 00:37:04 -07003736
Jiri Slaby054f5b02007-07-17 04:05:16 -07003737 plx_init(pdev, irq, addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07003738
Jiri Slaby101b8152009-06-11 12:30:10 +01003739 mailbox = readl(&ctl_addr->mail_box_0);
Jiri Slaby31375532007-05-08 00:37:04 -07003740
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003741 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
3742 mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
Jiri Slaby31375532007-05-08 00:37:04 -07003743 if (addr2 == NULL) {
3744 dev_err(&pdev->dev, "can't remap base region\n");
3745 goto err_unmap;
3746 }
3747
3748 if (mailbox == ZE_V1) {
3749 card_name = "Cyclades-Ze";
Jiri Slaby31375532007-05-08 00:37:04 -07003750 } else {
3751 card_name = "Cyclades-8Zo";
Jiri Slaby31375532007-05-08 00:37:04 -07003752#ifdef CY_PCI_DEBUG
3753 if (mailbox == ZO_V1) {
3754 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3755 dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
3756 "id %lx, ver %lx\n", (ulong)(0xff &
3757 readl(&((struct CUSTOM_REG *)addr2)->
3758 fpga_id)), (ulong)(0xff &
3759 readl(&((struct CUSTOM_REG *)addr2)->
3760 fpga_version)));
3761 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3762 } else {
3763 dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
3764 "Cyclades-Z board. FPGA not loaded\n");
3765 }
3766#endif
3767 /* The following clears the firmware id word. This
3768 ensures that the driver will not attempt to talk to
3769 the board until it has been properly initialized.
3770 */
3771 if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
3772 cy_writel(addr2 + ID_ADDRESS, 0L);
Jiri Slaby31375532007-05-08 00:37:04 -07003773 }
Jiri Slabyace08c32009-06-11 12:20:38 +01003774
3775 retval = cyz_load_fw(pdev, addr2, addr0, irq);
Jiri Slaby963118e2009-06-11 12:34:27 +01003776 if (retval <= 0)
Jiri Slabyace08c32009-06-11 12:20:38 +01003777 goto err_unmap;
Jiri Slaby963118e2009-06-11 12:34:27 +01003778 nchan = retval;
Jiri Slaby31375532007-05-08 00:37:04 -07003779 }
3780
3781 if ((cy_next_channel + nchan) > NR_PORTS) {
3782 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
3783 "channels are available. Change NR_PORTS in "
3784 "cyclades.c and recompile kernel.\n");
3785 goto err_unmap;
3786 }
3787 /* fill the next cy_card structure available */
3788 for (card_no = 0; card_no < NR_CARDS; card_no++) {
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003789 card = &cy_card[card_no];
3790 if (card->base_addr == NULL)
Jiri Slaby31375532007-05-08 00:37:04 -07003791 break;
3792 }
3793 if (card_no == NR_CARDS) { /* no more cy_cards available */
3794 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
3795 "more cards can be used. Change NR_CARDS in "
3796 "cyclades.c and recompile kernel.\n");
3797 goto err_unmap;
3798 }
3799
3800 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3801 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07003802 /* allocate IRQ */
Jiri Slaby31375532007-05-08 00:37:04 -07003803 retval = request_irq(irq, cyy_interrupt,
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003804 IRQF_SHARED, "Cyclom-Y", card);
Jiri Slaby58936d82007-05-08 00:36:13 -07003805 if (retval) {
Jiri Slaby21719192007-05-08 00:36:42 -07003806 dev_err(&pdev->dev, "could not allocate IRQ\n");
Jiri Slaby31375532007-05-08 00:37:04 -07003807 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003808 }
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003809 card->num_chips = nchan / CyPORTS_PER_CHIP;
Jiri Slaby31375532007-05-08 00:37:04 -07003810 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003811 struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
3812 struct ZFW_CTRL __iomem *zfw_ctrl;
3813
3814 zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3815
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003816 card->hw_ver = mailbox;
3817 card->num_chips = (unsigned int)-1;
3818 card->board_ctrl = &zfw_ctrl->board_ctrl;
Jiri Slaby31375532007-05-08 00:37:04 -07003819#ifdef CONFIG_CYZ_INTR
3820 /* allocate IRQ only if board has an IRQ */
3821 if (irq != 0 && irq != 255) {
3822 retval = request_irq(irq, cyz_interrupt,
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003823 IRQF_SHARED, "Cyclades-Z", card);
Jiri Slaby31375532007-05-08 00:37:04 -07003824 if (retval) {
3825 dev_err(&pdev->dev, "could not allocate IRQ\n");
3826 goto err_unmap;
3827 }
3828 }
3829#endif /* CONFIG_CYZ_INTR */
Jiri Slaby31375532007-05-08 00:37:04 -07003830 }
Jiri Slaby58936d82007-05-08 00:36:13 -07003831
Jiri Slaby31375532007-05-08 00:37:04 -07003832 /* set cy_card */
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003833 card->base_addr = addr2;
3834 card->ctl_addr.p9050 = addr0;
3835 card->irq = irq;
3836 card->bus_index = 1;
3837 card->first_line = cy_next_channel;
3838 card->nports = nchan;
3839 retval = cy_init_card(card);
Jiri Slaby31375532007-05-08 00:37:04 -07003840 if (retval)
3841 goto err_null;
Jiri Slaby58936d82007-05-08 00:36:13 -07003842
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003843 pci_set_drvdata(pdev, card);
Jiri Slaby31375532007-05-08 00:37:04 -07003844
3845 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3846 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07003847 /* enable interrupts in the PCI interface */
Jiri Slaby31375532007-05-08 00:37:04 -07003848 plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
Jiri Slaby58936d82007-05-08 00:36:13 -07003849 switch (plx_ver) {
3850 case PLX_9050:
Jiri Slaby31375532007-05-08 00:37:04 -07003851 cy_writeb(addr0 + 0x4c, 0x43);
Jiri Slaby58936d82007-05-08 00:36:13 -07003852 break;
3853
3854 case PLX_9060:
3855 case PLX_9080:
3856 default: /* Old boards, use PLX_9060 */
Jiri Slaby97e87f82009-06-11 12:29:27 +01003857 {
3858 struct RUNTIME_9060 __iomem *ctl_addr = addr0;
3859 plx_init(pdev, irq, ctl_addr);
3860 cy_writew(&ctl_addr->intr_ctrl_stat,
3861 readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
Jiri Slaby58936d82007-05-08 00:36:13 -07003862 break;
3863 }
Jiri Slaby97e87f82009-06-11 12:29:27 +01003864 }
Jiri Slaby58936d82007-05-08 00:36:13 -07003865 }
3866
Jiri Slaby31375532007-05-08 00:37:04 -07003867 dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
3868 "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
Jiri Slaby734cc172012-08-07 21:47:47 +02003869 for (j = 0, i = cy_next_channel; i < cy_next_channel + nchan; i++, j++)
3870 tty_port_register_device(&card->ports[j].port,
3871 cy_serial_driver, i, &pdev->dev);
Jiri Slaby31375532007-05-08 00:37:04 -07003872 cy_next_channel += nchan;
3873
Jiri Slaby58936d82007-05-08 00:36:13 -07003874 return 0;
Jiri Slaby31375532007-05-08 00:37:04 -07003875err_null:
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003876 card->base_addr = NULL;
3877 free_irq(irq, card);
Jiri Slaby31375532007-05-08 00:37:04 -07003878err_unmap:
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003879 iounmap(addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07003880 if (addr2)
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003881 iounmap(addr2);
Jiri Slaby31375532007-05-08 00:37:04 -07003882err_reg:
3883 pci_release_regions(pdev);
3884err_dis:
3885 pci_disable_device(pdev);
3886err:
3887 return retval;
Jiri Slaby58936d82007-05-08 00:36:13 -07003888}
Jiri Slaby58936d82007-05-08 00:36:13 -07003889
Bill Pembertonae8d8a12012-11-19 13:26:18 -05003890static void cy_pci_remove(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891{
Jiri Slaby38d09092007-05-08 00:36:10 -07003892 struct cyclades_card *cinfo = pci_get_drvdata(pdev);
Jiri Slaby191c5f12012-11-15 09:49:56 +01003893 unsigned int i, channel;
Jiri Slaby38d09092007-05-08 00:36:10 -07003894
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003895 /* non-Z with old PLX */
Jiri Slaby2693f482009-06-11 12:31:06 +01003896 if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
Jiri Slabyc2ad4c72007-05-08 00:36:32 -07003897 PLX_9050)
Jiri Slaby97e87f82009-06-11 12:29:27 +01003898 cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003899 else
3900#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003901 if (!cy_is_Z(cinfo))
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003902#endif
Jiri Slaby97e87f82009-06-11 12:29:27 +01003903 cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
3904 readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
3905 ~0x0900);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003906
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003907 iounmap(cinfo->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01003908 if (cinfo->ctl_addr.p9050)
3909 iounmap(cinfo->ctl_addr.p9050);
Jiri Slaby38d09092007-05-08 00:36:10 -07003910 if (cinfo->irq
3911#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003912 && !cy_is_Z(cinfo)
Jiri Slaby38d09092007-05-08 00:36:10 -07003913#endif /* CONFIG_CYZ_INTR */
3914 )
3915 free_irq(cinfo->irq, cinfo);
3916 pci_release_regions(pdev);
3917
3918 cinfo->base_addr = NULL;
Jiri Slaby191c5f12012-11-15 09:49:56 +01003919 for (channel = 0, i = cinfo->first_line; i < cinfo->first_line +
3920 cinfo->nports; i++, channel++) {
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07003921 tty_unregister_device(cy_serial_driver, i);
Jiri Slaby191c5f12012-11-15 09:49:56 +01003922 tty_port_destroy(&cinfo->ports[channel].port);
3923 }
Jiri Slabydd025c02007-05-08 00:37:02 -07003924 cinfo->nports = 0;
3925 kfree(cinfo->ports);
Jiri Slaby38d09092007-05-08 00:36:10 -07003926}
3927
Jiri Slaby6747cd92007-05-08 00:36:34 -07003928static struct pci_driver cy_pci_driver = {
3929 .name = "cyclades",
3930 .id_table = cy_pci_dev_id,
3931 .probe = cy_pci_probe,
Bill Pemberton91116cb2012-11-19 13:21:06 -05003932 .remove = cy_pci_remove
Jiri Slaby6747cd92007-05-08 00:36:34 -07003933};
3934#endif
3935
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003936static int cyclades_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937{
Jiri Slaby02f11752006-12-08 02:39:28 -08003938 struct cyclades_port *info;
Jiri Slabydd025c02007-05-08 00:37:02 -07003939 unsigned int i, j;
Jiri Slaby02f11752006-12-08 02:39:28 -08003940 __u32 cur_jifs = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003942 seq_puts(m, "Dev TimeOpen BytesOut IdleOut BytesIn "
Jiri Slaby02f11752006-12-08 02:39:28 -08003943 "IdleIn Overruns Ldisc\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944
Jiri Slaby02f11752006-12-08 02:39:28 -08003945 /* Output one line for each known port */
Jiri Slabydd025c02007-05-08 00:37:02 -07003946 for (i = 0; i < NR_CARDS; i++)
3947 for (j = 0; j < cy_card[i].nports; j++) {
3948 info = &cy_card[i].ports[j];
Jiri Slaby02f11752006-12-08 02:39:28 -08003949
Jiri Slabyd13549f2009-09-19 13:13:12 -07003950 if (info->port.count) {
3951 /* XXX is the ldisc num worth this? */
3952 struct tty_struct *tty;
3953 struct tty_ldisc *ld;
3954 int num = 0;
3955 tty = tty_port_tty_get(&info->port);
3956 if (tty) {
3957 ld = tty_ldisc_ref(tty);
3958 if (ld) {
3959 num = ld->ops->num;
3960 tty_ldisc_deref(ld);
3961 }
3962 tty_kref_put(tty);
3963 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003964 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabyd13549f2009-09-19 13:13:12 -07003965 "%10lu %8lu %9lu %6d\n", info->line,
Jiri Slabydd025c02007-05-08 00:37:02 -07003966 (cur_jifs - info->idle_stats.in_use) /
3967 HZ, info->idle_stats.xmit_bytes,
3968 (cur_jifs - info->idle_stats.xmit_idle)/
3969 HZ, info->idle_stats.recv_bytes,
3970 (cur_jifs - info->idle_stats.recv_idle)/
3971 HZ, info->idle_stats.overruns,
Jiri Slabyd13549f2009-09-19 13:13:12 -07003972 num);
3973 } else
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003974 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabydd025c02007-05-08 00:37:02 -07003975 "%10lu %8lu %9lu %6ld\n",
3976 info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08003977 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003978 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979}
3980
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003981static int cyclades_proc_open(struct inode *inode, struct file *file)
3982{
3983 return single_open(file, cyclades_proc_show, NULL);
3984}
3985
3986static const struct file_operations cyclades_proc_fops = {
3987 .owner = THIS_MODULE,
3988 .open = cyclades_proc_open,
3989 .read = seq_read,
3990 .llseek = seq_lseek,
3991 .release = single_release,
3992};
3993
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994/* The serial driver boot-time initialization code!
3995 Hardware I/O ports are mapped to character special devices on a
3996 first found, first allocated manner. That is, this code searches
3997 for Cyclom cards in the system. As each is found, it is probed
3998 to discover how many chips (and thus how many ports) are present.
3999 These ports are mapped to the tty ports 32 and upward in monotonic
4000 fashion. If an 8-port card is replaced with a 16-port card, the
4001 port mapping on a following card will shift.
4002
4003 This approach is different from what is used in the other serial
4004 device driver because the Cyclom is more properly a multiplexer,
4005 not just an aggregation of serial ports on one card.
4006
4007 If there are more cards with more ports than have been
4008 statically allocated above, a warning is printed and the
4009 extra ports are ignored.
4010 */
4011
Jeff Dikeb68e31d2006-10-02 02:17:18 -07004012static const struct tty_operations cy_ops = {
Jiri Slaby02f11752006-12-08 02:39:28 -08004013 .open = cy_open,
4014 .close = cy_close,
4015 .write = cy_write,
4016 .put_char = cy_put_char,
4017 .flush_chars = cy_flush_chars,
4018 .write_room = cy_write_room,
4019 .chars_in_buffer = cy_chars_in_buffer,
4020 .flush_buffer = cy_flush_buffer,
4021 .ioctl = cy_ioctl,
4022 .throttle = cy_throttle,
4023 .unthrottle = cy_unthrottle,
4024 .set_termios = cy_set_termios,
4025 .stop = cy_stop,
4026 .start = cy_start,
4027 .hangup = cy_hangup,
4028 .break_ctl = cy_break,
4029 .wait_until_sent = cy_wait_until_sent,
Jiri Slaby02f11752006-12-08 02:39:28 -08004030 .tiocmget = cy_tiocmget,
4031 .tiocmset = cy_tiocmset,
Alan Cox05871022010-09-16 18:21:52 +01004032 .get_icount = cy_get_icount,
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004033 .proc_fops = &cyclades_proc_fops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034};
4035
Jiri Slaby02f11752006-12-08 02:39:28 -08004036static int __init cy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037{
Jiri Slabydd025c02007-05-08 00:37:02 -07004038 unsigned int nboards;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004039 int retval = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040
Jiri Slaby02f11752006-12-08 02:39:28 -08004041 cy_serial_driver = alloc_tty_driver(NR_PORTS);
4042 if (!cy_serial_driver)
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004043 goto err;
Jiri Slaby21719192007-05-08 00:36:42 -07004044
Michal Marek64a14b52011-04-01 12:41:20 +02004045 printk(KERN_INFO "Cyclades driver " CY_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046
Jiri Slaby02f11752006-12-08 02:39:28 -08004047 /* Initialize the tty_driver structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048
Jiri Slaby02f11752006-12-08 02:39:28 -08004049 cy_serial_driver->driver_name = "cyclades";
4050 cy_serial_driver->name = "ttyC";
4051 cy_serial_driver->major = CYCLADES_MAJOR;
4052 cy_serial_driver->minor_start = 0;
4053 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
4054 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
4055 cy_serial_driver->init_termios = tty_std_termios;
4056 cy_serial_driver->init_termios.c_cflag =
4057 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004058 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08004059 tty_set_operations(cy_serial_driver, &cy_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004061 retval = tty_register_driver(cy_serial_driver);
4062 if (retval) {
4063 printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
4064 goto err_frtty;
4065 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066
Jiri Slaby02f11752006-12-08 02:39:28 -08004067 /* the code below is responsible to find the boards. Each different
4068 type of board has its own detection routine. If a board is found,
4069 the next cy_card structure available is set by the detection
4070 routine. These functions are responsible for checking the
4071 availability of cy_card and cy_port data structures and updating
4072 the cy_next_channel. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073
Jiri Slaby02f11752006-12-08 02:39:28 -08004074 /* look for isa boards */
Jiri Slaby14a55a62007-05-08 00:36:18 -07004075 nboards = cy_detect_isa();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076
Jiri Slaby6747cd92007-05-08 00:36:34 -07004077#ifdef CONFIG_PCI
Jiri Slaby02f11752006-12-08 02:39:28 -08004078 /* look for pci boards */
Jiri Slaby6747cd92007-05-08 00:36:34 -07004079 retval = pci_register_driver(&cy_pci_driver);
Jesper Juhld941ea72007-10-18 03:06:23 -07004080 if (retval && !nboards) {
4081 tty_unregister_driver(cy_serial_driver);
4082 goto err_frtty;
4083 }
Jiri Slaby6747cd92007-05-08 00:36:34 -07004084#endif
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004085
4086 return 0;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004087err_frtty:
4088 put_tty_driver(cy_serial_driver);
4089err:
4090 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08004091} /* cy_init */
4092
4093static void __exit cy_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094{
Jiri Slabydd025c02007-05-08 00:37:02 -07004095 struct cyclades_card *card;
Jiri Slaby65f76a82007-10-18 03:06:22 -07004096 unsigned int i, e1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004097
4098#ifndef CONFIG_CYZ_INTR
Jiri Slabyb7050902007-05-08 00:35:48 -07004099 del_timer_sync(&cyz_timerlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100#endif /* CONFIG_CYZ_INTR */
4101
Alan Cox15ed6cc2008-04-30 00:53:55 -07004102 e1 = tty_unregister_driver(cy_serial_driver);
4103 if (e1)
Jiri Slaby21719192007-05-08 00:36:42 -07004104 printk(KERN_ERR "failed to unregister Cyclades serial "
4105 "driver(%d)\n", e1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106
Jiri Slaby6747cd92007-05-08 00:36:34 -07004107#ifdef CONFIG_PCI
4108 pci_unregister_driver(&cy_pci_driver);
4109#endif
4110
Jiri Slaby02f11752006-12-08 02:39:28 -08004111 for (i = 0; i < NR_CARDS; i++) {
Jiri Slabydd025c02007-05-08 00:37:02 -07004112 card = &cy_card[i];
4113 if (card->base_addr) {
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004114 /* clear interrupt */
Jiri Slabydd025c02007-05-08 00:37:02 -07004115 cy_writeb(card->base_addr + Cy_ClrIntr, 0);
4116 iounmap(card->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01004117 if (card->ctl_addr.p9050)
4118 iounmap(card->ctl_addr.p9050);
Jiri Slabydd025c02007-05-08 00:37:02 -07004119 if (card->irq
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004121 && !cy_is_Z(card)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122#endif /* CONFIG_CYZ_INTR */
Jiri Slaby02f11752006-12-08 02:39:28 -08004123 )
Jiri Slabydd025c02007-05-08 00:37:02 -07004124 free_irq(card->irq, card);
Jiri Slaby65f76a82007-10-18 03:06:22 -07004125 for (e1 = card->first_line; e1 < card->first_line +
Jiri Slabydd025c02007-05-08 00:37:02 -07004126 card->nports; e1++)
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004127 tty_unregister_device(cy_serial_driver, e1);
Jiri Slabydd025c02007-05-08 00:37:02 -07004128 kfree(card->ports);
Jiri Slaby02f11752006-12-08 02:39:28 -08004129 }
4130 }
Jiri Slabyf2462bf2007-05-08 00:37:01 -07004131
4132 put_tty_driver(cy_serial_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133} /* cy_cleanup_module */
4134
4135module_init(cy_init);
4136module_exit(cy_cleanup_module);
4137
4138MODULE_LICENSE("GPL");
Jiri Slabyc8e16932007-05-08 00:37:05 -07004139MODULE_VERSION(CY_VERSION);
Scott James Remnant9f56fad72009-04-06 17:33:04 +01004140MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);
Ben Hutchingse6c4ef92010-01-13 23:34:18 +00004141MODULE_FIRMWARE("cyzfirm.bin");