blob: e77db714ab26d4a3e2d6e1d15434495d473e7e14 [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
96#define STD_COM_FLAGS (0)
97
Jiri Slaby054f5b02007-07-17 04:05:16 -070098/* firmware stuff */
99#define ZL_MAX_BLOCKS 16
100#define DRIVER_VERSION 0x02010203
101#define RAM_SIZE 0x80000
102
Jiri Slaby054f5b02007-07-17 04:05:16 -0700103enum zblock_type {
104 ZBLOCK_PRG = 0,
105 ZBLOCK_FPGA = 1
106};
107
108struct zfile_header {
109 char name[64];
110 char date[32];
111 char aux[32];
112 u32 n_config;
113 u32 config_offset;
114 u32 n_blocks;
115 u32 block_offset;
116 u32 reserved[9];
117} __attribute__ ((packed));
118
119struct zfile_config {
120 char name[64];
121 u32 mailbox;
122 u32 function;
123 u32 n_blocks;
124 u32 block_list[ZL_MAX_BLOCKS];
125} __attribute__ ((packed));
126
127struct zfile_block {
128 u32 type;
129 u32 file_offset;
130 u32 ram_offset;
131 u32 size;
132} __attribute__ ((packed));
133
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134static struct tty_driver *cy_serial_driver;
135
136#ifdef CONFIG_ISA
137/* This is the address lookup table. The driver will probe for
138 Cyclom-Y/ISA boards at all addresses in here. If you want the
139 driver to probe addresses at a different address, add it to
140 this table. If the driver is probing some other board and
141 causing problems, remove the offending address from this table.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142*/
143
144static unsigned int cy_isa_addresses[] = {
Jiri Slaby02f11752006-12-08 02:39:28 -0800145 0xD0000,
146 0xD2000,
147 0xD4000,
148 0xD6000,
149 0xD8000,
150 0xDA000,
151 0xDC000,
152 0xDE000,
153 0, 0, 0, 0, 0, 0, 0, 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154};
Jiri Slaby02f11752006-12-08 02:39:28 -0800155
Tobias Klauserfe971072006-01-09 20:54:02 -0800156#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
Jiri Slaby3046d502007-05-08 00:36:46 -0700158static long maddr[NR_CARDS];
159static int irq[NR_CARDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
161module_param_array(maddr, long, NULL, 0);
162module_param_array(irq, int, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
Jiri Slaby02f11752006-12-08 02:39:28 -0800164#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
166/* This is the per-card data structure containing address, irq, number of
167 channels, etc. This driver supports a maximum of NR_CARDS cards.
168*/
169static struct cyclades_card cy_card[NR_CARDS];
170
Jiri Slaby02f11752006-12-08 02:39:28 -0800171static int cy_next_channel; /* next minor available */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172
173/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 * This is used to look up the divisor speeds and the timeouts
175 * We're normally limited to 15 distinct baud rates. The extra
Alan Cox77451e52008-07-16 21:57:02 +0100176 * are accessed via settings in info->port.flags.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
178 * 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
179 * HI VHI
180 * 20
181 */
Jiri Slabyebdb5132009-09-19 13:13:14 -0700182static const int baud_table[] = {
Jiri Slaby02f11752006-12-08 02:39:28 -0800183 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
184 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000,
185 230400, 0
186};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Jiri Slabyebdb5132009-09-19 13:13:14 -0700188static const char baud_co_25[] = { /* 25 MHz clock option table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800189 /* value => 00 01 02 03 04 */
190 /* divide by 8 32 128 512 2048 */
191 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02,
192 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
193};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Jiri Slabyebdb5132009-09-19 13:13:14 -0700195static const char baud_bpr_25[] = { /* 25 MHz baud rate period table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800196 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3,
197 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15
198};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
Jiri Slabyebdb5132009-09-19 13:13:14 -0700200static const char baud_co_60[] = { /* 60 MHz clock option table (CD1400 J) */
Jiri Slaby02f11752006-12-08 02:39:28 -0800201 /* value => 00 01 02 03 04 */
202 /* divide by 8 32 128 512 2048 */
203 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03,
204 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
205 0x00
206};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
Jiri Slabyebdb5132009-09-19 13:13:14 -0700208static const char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */
Jiri Slaby02f11752006-12-08 02:39:28 -0800209 0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62,
210 0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32,
211 0x21
212};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
Jiri Slabyebdb5132009-09-19 13:13:14 -0700214static const char baud_cor3[] = { /* receive threshold */
Jiri Slaby02f11752006-12-08 02:39:28 -0800215 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
216 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07,
217 0x07
218};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
220/*
221 * The Cyclades driver implements HW flow control as any serial driver.
Alan Cox15ed6cc2008-04-30 00:53:55 -0700222 * The cyclades_port structure member rflow and the vector rflow_thr
223 * allows us to take advantage of a special feature in the CD1400 to avoid
224 * data loss even when the system interrupt latency is too high. These flags
225 * are to be used only with very special applications. Setting these flags
226 * requires the use of a special cable (DTR and RTS reversed). In the new
227 * CD1400-based boards (rev. 6.00 or later), there is no need for special
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 * cables.
229 */
230
Jiri Slabyebdb5132009-09-19 13:13:14 -0700231static const char rflow_thr[] = { /* rflow threshold */
Jiri Slaby02f11752006-12-08 02:39:28 -0800232 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
233 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
234 0x0a
235};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
237/* The Cyclom-Ye has placed the sequential chips in non-sequential
238 * address order. This look-up table overcomes that problem.
239 */
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700240static const unsigned int cy_chip_offset[] = { 0x0000,
Jiri Slaby02f11752006-12-08 02:39:28 -0800241 0x0400,
242 0x0800,
243 0x0C00,
244 0x0200,
245 0x0600,
246 0x0A00,
247 0x0E00
248};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
250/* PCI related definitions */
251
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252#ifdef CONFIG_PCI
Jiri Slabyebdb5132009-09-19 13:13:14 -0700253static const struct pci_device_id cy_pci_dev_id[] = {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700254 /* PCI < 1Mb */
255 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) },
256 /* PCI > 1Mb */
257 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) },
258 /* 4Y PCI < 1Mb */
259 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) },
260 /* 4Y PCI > 1Mb */
261 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) },
262 /* 8Y PCI < 1Mb */
263 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) },
264 /* 8Y PCI > 1Mb */
265 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) },
266 /* Z PCI < 1Mb */
267 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) },
268 /* Z PCI > 1Mb */
269 { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) },
Jiri Slaby893de2d2007-02-12 00:51:49 -0800270 { } /* end of table */
Jiri Slaby02f11752006-12-08 02:39:28 -0800271};
Jiri Slaby893de2d2007-02-12 00:51:49 -0800272MODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273#endif
274
275static void cy_start(struct tty_struct *);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700276static void cy_set_line_char(struct cyclades_port *, struct tty_struct *);
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700277static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278#ifdef CONFIG_ISA
279static unsigned detect_isa_irq(void __iomem *);
Jiri Slaby02f11752006-12-08 02:39:28 -0800280#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282#ifndef CONFIG_CYZ_INTR
283static void cyz_poll(unsigned long);
284
285/* The Cyclades-Z polling cycle is defined by this variable */
286static long cyz_polling_cycle = CZ_DEF_POLL;
287
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700288static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
Jiri Slaby02f11752006-12-08 02:39:28 -0800290#else /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291static void cyz_rx_restart(unsigned long);
292static struct timer_list cyz_rx_full_timer[NR_PORTS];
Jiri Slaby02f11752006-12-08 02:39:28 -0800293#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700295static inline void cyy_writeb(struct cyclades_port *port, u32 reg, u8 val)
296{
297 struct cyclades_card *card = port->card;
298
299 cy_writeb(port->u.cyy.base_addr + (reg << card->bus_index), val);
300}
301
302static inline u8 cyy_readb(struct cyclades_port *port, u32 reg)
303{
304 struct cyclades_card *card = port->card;
305
306 return readb(port->u.cyy.base_addr + (reg << card->bus_index));
307}
308
Jiri Slaby2693f482009-06-11 12:31:06 +0100309static inline bool cy_is_Z(struct cyclades_card *card)
310{
311 return card->num_chips == (unsigned int)-1;
312}
313
314static inline bool __cyz_fpga_loaded(struct RUNTIME_9060 __iomem *ctl_addr)
315{
316 return readl(&ctl_addr->init_ctrl) & (1 << 17);
317}
318
319static inline bool cyz_fpga_loaded(struct cyclades_card *card)
320{
321 return __cyz_fpga_loaded(card->ctl_addr.p9060);
322}
323
324static inline bool cyz_is_loaded(struct cyclades_card *card)
325{
326 struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS;
327
328 return (card->hw_ver == ZO_V1 || cyz_fpga_loaded(card)) &&
329 readl(&fw_id->signature) == ZFIRM_ID;
330}
331
Jiri Slaby02f11752006-12-08 02:39:28 -0800332static inline int serial_paranoia_check(struct cyclades_port *info,
Jiri Slabyebdb5132009-09-19 13:13:14 -0700333 const char *name, const char *routine)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
335#ifdef SERIAL_PARANOIA_CHECK
Jiri Slaby02f11752006-12-08 02:39:28 -0800336 if (!info) {
Jiri Slaby21719192007-05-08 00:36:42 -0700337 printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) "
338 "in %s\n", name, routine);
Jiri Slaby02f11752006-12-08 02:39:28 -0800339 return 1;
340 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Jiri Slaby02f11752006-12-08 02:39:28 -0800342 if (info->magic != CYCLADES_MAGIC) {
Jiri Slaby21719192007-05-08 00:36:42 -0700343 printk(KERN_WARNING "cyc Warning: bad magic number for serial "
344 "struct (%s) in %s\n", name, routine);
Jiri Slaby02f11752006-12-08 02:39:28 -0800345 return 1;
346 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347#endif
Jiri Slaby02f11752006-12-08 02:39:28 -0800348 return 0;
Jiri Slabyebdb5132009-09-19 13:13:14 -0700349}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351/***********************************************************/
352/********* Start of block of Cyclom-Y specific code ********/
353
354/* This routine waits up to 1000 micro-seconds for the previous
355 command to the Cirrus chip to complete and then issues the
356 new command. An error is returned if the previous command
357 didn't finish within the time limit.
358
359 This function is only called from inside spinlock-protected code.
360 */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700361static int __cyy_issue_cmd(void __iomem *base_addr, u8 cmd, int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700363 void __iomem *ccr = base_addr + (CyCCR << index);
Jiri Slabyad39c302007-05-08 00:35:49 -0700364 unsigned int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
Jiri Slaby02f11752006-12-08 02:39:28 -0800366 /* Check to see that the previous command has completed */
367 for (i = 0; i < 100; i++) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700368 if (readb(ccr) == 0)
Jiri Slaby02f11752006-12-08 02:39:28 -0800369 break;
Jiri Slaby02f11752006-12-08 02:39:28 -0800370 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 }
Jiri Slaby02f11752006-12-08 02:39:28 -0800372 /* if the CCR never cleared, the previous command
373 didn't finish within the "reasonable time" */
374 if (i == 100)
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800375 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
Jiri Slaby02f11752006-12-08 02:39:28 -0800377 /* Issue the new command */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700378 cy_writeb(ccr, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800380 return 0;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700381}
382
383static inline int cyy_issue_cmd(struct cyclades_port *port, u8 cmd)
384{
385 return __cyy_issue_cmd(port->u.cyy.base_addr, cmd,
386 port->card->bus_index);
387}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
389#ifdef CONFIG_ISA
390/* ISA interrupt detection code */
Alan Cox15ed6cc2008-04-30 00:53:55 -0700391static unsigned detect_isa_irq(void __iomem *address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392{
Jiri Slaby02f11752006-12-08 02:39:28 -0800393 int irq;
394 unsigned long irqs, flags;
395 int save_xir, save_car;
396 int index = 0; /* IRQ probing is only for ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
Jiri Slaby02f11752006-12-08 02:39:28 -0800398 /* forget possible initially masked and pending IRQ */
399 irq = probe_irq_off(probe_irq_on());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
Jiri Slaby02f11752006-12-08 02:39:28 -0800401 /* Clear interrupts on the board first */
402 cy_writeb(address + (Cy_ClrIntr << index), 0);
403 /* Cy_ClrIntr is 0x1800 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
Jiri Slaby02f11752006-12-08 02:39:28 -0800405 irqs = probe_irq_on();
406 /* Wait ... */
Jiri Slabyf6e208c2009-09-19 13:13:14 -0700407 msleep(5);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
Jiri Slaby02f11752006-12-08 02:39:28 -0800409 /* Enable the Tx interrupts on the CD1400 */
410 local_irq_save(flags);
411 cy_writeb(address + (CyCAR << index), 0);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700412 __cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
Jiri Slaby02f11752006-12-08 02:39:28 -0800414 cy_writeb(address + (CyCAR << index), 0);
415 cy_writeb(address + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700416 readb(address + (CySRER << index)) | CyTxRdy);
Jiri Slaby02f11752006-12-08 02:39:28 -0800417 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
Jiri Slaby02f11752006-12-08 02:39:28 -0800419 /* Wait ... */
Jiri Slabyf6e208c2009-09-19 13:13:14 -0700420 msleep(5);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421
Jiri Slaby02f11752006-12-08 02:39:28 -0800422 /* Check which interrupt is in use */
423 irq = probe_irq_off(irqs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424
Jiri Slaby02f11752006-12-08 02:39:28 -0800425 /* Clean up */
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700426 save_xir = (u_char) readb(address + (CyTIR << index));
427 save_car = readb(address + (CyCAR << index));
Jiri Slaby02f11752006-12-08 02:39:28 -0800428 cy_writeb(address + (CyCAR << index), (save_xir & 0x3));
429 cy_writeb(address + (CySRER << index),
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700430 readb(address + (CySRER << index)) & ~CyTxRdy);
Jiri Slaby02f11752006-12-08 02:39:28 -0800431 cy_writeb(address + (CyTIR << index), (save_xir & 0x3f));
432 cy_writeb(address + (CyCAR << index), (save_car));
433 cy_writeb(address + (Cy_ClrIntr << index), 0);
434 /* Cy_ClrIntr is 0x1800 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
Jiri Slaby02f11752006-12-08 02:39:28 -0800436 return (irq > 0) ? irq : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437}
Jiri Slaby02f11752006-12-08 02:39:28 -0800438#endif /* CONFIG_ISA */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
Jiri Slabyce97a092007-10-18 03:06:21 -0700440static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
441 void __iomem *base_addr)
Jiri Slabye9410272006-12-08 02:39:28 -0800442{
443 struct cyclades_port *info;
444 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700445 int len, index = cinfo->bus_index;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700446 u8 ivr, save_xir, channel, save_car, data, char_count;
Jiri Slabye9410272006-12-08 02:39:28 -0800447
Jiri Slabye9410272006-12-08 02:39:28 -0800448#ifdef CY_DEBUG_INTERRUPTS
Jiri Slabyce97a092007-10-18 03:06:21 -0700449 printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
Jiri Slabye9410272006-12-08 02:39:28 -0800450#endif
Jiri Slabyce97a092007-10-18 03:06:21 -0700451 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700452 save_xir = readb(base_addr + (CyRIR << index));
453 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700454 info = &cinfo->ports[channel + chip * 4];
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700455 save_car = cyy_readb(info, CyCAR);
456 cyy_writeb(info, CyCAR, save_xir);
457 ivr = cyy_readb(info, CyRIVR) & CyIVRMask;
Jiri Slabye9410272006-12-08 02:39:28 -0800458
Jiri Slabyd13549f2009-09-19 13:13:12 -0700459 tty = tty_port_tty_get(&info->port);
Jiri Slabyce97a092007-10-18 03:06:21 -0700460 /* if there is nowhere to put the data, discard it */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700461 if (tty == NULL) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700462 if (ivr == CyIVRRxEx) { /* exception */
463 data = cyy_readb(info, CyRDSR);
Jiri Slabyce97a092007-10-18 03:06:21 -0700464 } else { /* normal character reception */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700465 char_count = cyy_readb(info, CyRDCR);
Jiri Slabyce97a092007-10-18 03:06:21 -0700466 while (char_count--)
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700467 data = cyy_readb(info, CyRDSR);
Jiri Slabyce97a092007-10-18 03:06:21 -0700468 }
469 goto end;
470 }
471 /* there is an open port for this data */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700472 if (ivr == CyIVRRxEx) { /* exception */
473 data = cyy_readb(info, CyRDSR);
Jiri Slaby02f11752006-12-08 02:39:28 -0800474
Jiri Slabyce97a092007-10-18 03:06:21 -0700475 /* For statistics only */
476 if (data & CyBREAK)
477 info->icount.brk++;
478 else if (data & CyFRAME)
479 info->icount.frame++;
480 else if (data & CyPARITY)
481 info->icount.parity++;
482 else if (data & CyOVERRUN)
483 info->icount.overrun++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800484
Jiri Slabyce97a092007-10-18 03:06:21 -0700485 if (data & info->ignore_status_mask) {
486 info->icount.rx++;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700487 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700488 return;
489 }
490 if (tty_buffer_request_room(tty, 1)) {
491 if (data & info->read_status_mask) {
492 if (data & CyBREAK) {
493 tty_insert_flip_char(tty,
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700494 cyy_readb(info, CyRDSR),
495 TTY_BREAK);
Jiri Slaby02f11752006-12-08 02:39:28 -0800496 info->icount.rx++;
Alan Cox77451e52008-07-16 21:57:02 +0100497 if (info->port.flags & ASYNC_SAK)
Jiri Slabyce97a092007-10-18 03:06:21 -0700498 do_SAK(tty);
499 } else if (data & CyFRAME) {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700500 tty_insert_flip_char(tty,
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700501 cyy_readb(info, CyRDSR),
502 TTY_FRAME);
Jiri Slabyce97a092007-10-18 03:06:21 -0700503 info->icount.rx++;
504 info->idle_stats.frame_errs++;
505 } else if (data & CyPARITY) {
506 /* Pieces of seven... */
507 tty_insert_flip_char(tty,
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700508 cyy_readb(info, CyRDSR),
509 TTY_PARITY);
Jiri Slabyce97a092007-10-18 03:06:21 -0700510 info->icount.rx++;
511 info->idle_stats.parity_errs++;
512 } else if (data & CyOVERRUN) {
513 tty_insert_flip_char(tty, 0,
514 TTY_OVERRUN);
515 info->icount.rx++;
516 /* If the flip buffer itself is
517 overflowing, we still lose
518 the next incoming character.
519 */
520 tty_insert_flip_char(tty,
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700521 cyy_readb(info, CyRDSR),
522 TTY_FRAME);
Jiri Slabyce97a092007-10-18 03:06:21 -0700523 info->icount.rx++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800524 info->idle_stats.overruns++;
Jiri Slabyce97a092007-10-18 03:06:21 -0700525 /* These two conditions may imply */
526 /* a normal read should be done. */
527 /* } else if(data & CyTIMEOUT) { */
528 /* } else if(data & CySPECHAR) { */
529 } else {
530 tty_insert_flip_char(tty, 0,
531 TTY_NORMAL);
532 info->icount.rx++;
Jiri Slaby02f11752006-12-08 02:39:28 -0800533 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700534 } else {
535 tty_insert_flip_char(tty, 0, TTY_NORMAL);
536 info->icount.rx++;
537 }
538 } else {
539 /* there was a software buffer overrun and nothing
540 * could be done about it!!! */
541 info->icount.buf_overrun++;
542 info->idle_stats.overruns++;
543 }
544 } else { /* normal character reception */
545 /* load # chars available from the chip */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700546 char_count = cyy_readb(info, CyRDCR);
Jiri Slabye9410272006-12-08 02:39:28 -0800547
548#ifdef CY_ENABLE_MONITORING
Jiri Slabyce97a092007-10-18 03:06:21 -0700549 ++info->mon.int_count;
550 info->mon.char_count += char_count;
551 if (char_count > info->mon.char_max)
552 info->mon.char_max = char_count;
553 info->mon.char_last = char_count;
Jiri Slabye9410272006-12-08 02:39:28 -0800554#endif
Jiri Slabyce97a092007-10-18 03:06:21 -0700555 len = tty_buffer_request_room(tty, char_count);
556 while (len--) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700557 data = cyy_readb(info, CyRDSR);
Jiri Slabyce97a092007-10-18 03:06:21 -0700558 tty_insert_flip_char(tty, data, TTY_NORMAL);
559 info->idle_stats.recv_bytes++;
560 info->icount.rx++;
Jiri Slabye9410272006-12-08 02:39:28 -0800561#ifdef CY_16Y_HACK
Jiri Slabyce97a092007-10-18 03:06:21 -0700562 udelay(10L);
Jiri Slabye9410272006-12-08 02:39:28 -0800563#endif
Jiri Slabye9410272006-12-08 02:39:28 -0800564 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700565 info->idle_stats.recv_idle = jiffies;
566 }
567 tty_schedule_flip(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700568 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700569end:
570 /* end of service */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700571 cyy_writeb(info, CyRIR, save_xir & 0x3f);
572 cyy_writeb(info, CyCAR, save_car);
Jiri Slabyce97a092007-10-18 03:06:21 -0700573}
574
Jiri Slaby65f76a82007-10-18 03:06:22 -0700575static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
Jiri Slabyce97a092007-10-18 03:06:21 -0700576 void __iomem *base_addr)
577{
578 struct cyclades_port *info;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700579 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700580 int char_count, index = cinfo->bus_index;
581 u8 save_xir, channel, save_car, outch;
Jiri Slabyce97a092007-10-18 03:06:21 -0700582
583 /* Since we only get here when the transmit buffer
584 is empty, we know we can always stuff a dozen
585 characters. */
586#ifdef CY_DEBUG_INTERRUPTS
587 printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip);
588#endif
589
590 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700591 save_xir = readb(base_addr + (CyTIR << index));
592 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700593 save_car = readb(base_addr + (CyCAR << index));
594 cy_writeb(base_addr + (CyCAR << index), save_xir);
595
Jiri Slabyce97a092007-10-18 03:06:21 -0700596 info = &cinfo->ports[channel + chip * 4];
Jiri Slabyd13549f2009-09-19 13:13:12 -0700597 tty = tty_port_tty_get(&info->port);
598 if (tty == NULL) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700599 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700600 goto end;
Jiri Slabye9410272006-12-08 02:39:28 -0800601 }
602
Jiri Slabyce97a092007-10-18 03:06:21 -0700603 /* load the on-chip space for outbound data */
604 char_count = info->xmit_fifo_size;
Jiri Slabye9410272006-12-08 02:39:28 -0800605
Jiri Slabyce97a092007-10-18 03:06:21 -0700606 if (info->x_char) { /* send special char */
607 outch = info->x_char;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700608 cyy_writeb(info, CyTDR, outch);
Jiri Slabyce97a092007-10-18 03:06:21 -0700609 char_count--;
610 info->icount.tx++;
611 info->x_char = 0;
612 }
Jiri Slabye9410272006-12-08 02:39:28 -0800613
Jiri Slabyce97a092007-10-18 03:06:21 -0700614 if (info->breakon || info->breakoff) {
615 if (info->breakon) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700616 cyy_writeb(info, CyTDR, 0);
617 cyy_writeb(info, CyTDR, 0x81);
Jiri Slabyce97a092007-10-18 03:06:21 -0700618 info->breakon = 0;
619 char_count -= 2;
Jiri Slaby02f11752006-12-08 02:39:28 -0800620 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700621 if (info->breakoff) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700622 cyy_writeb(info, CyTDR, 0);
623 cyy_writeb(info, CyTDR, 0x83);
Jiri Slabyce97a092007-10-18 03:06:21 -0700624 info->breakoff = 0;
625 char_count -= 2;
Jiri Slaby02f11752006-12-08 02:39:28 -0800626 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700627 }
Jiri Slabye9410272006-12-08 02:39:28 -0800628
Jiri Slabyce97a092007-10-18 03:06:21 -0700629 while (char_count-- > 0) {
630 if (!info->xmit_cnt) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700631 if (cyy_readb(info, CySRER) & CyTxMpty) {
632 cyy_writeb(info, CySRER,
633 cyy_readb(info, CySRER) & ~CyTxMpty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700634 } else {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700635 cyy_writeb(info, CySRER, CyTxMpty |
636 (cyy_readb(info, CySRER) & ~CyTxRdy));
Jiri Slaby02f11752006-12-08 02:39:28 -0800637 }
Jiri Slabyce97a092007-10-18 03:06:21 -0700638 goto done;
639 }
Alan Cox77451e52008-07-16 21:57:02 +0100640 if (info->port.xmit_buf == NULL) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700641 cyy_writeb(info, CySRER,
642 cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700643 goto done;
644 }
Jiri Slabyd13549f2009-09-19 13:13:12 -0700645 if (tty->stopped || tty->hw_stopped) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700646 cyy_writeb(info, CySRER,
647 cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700648 goto done;
649 }
650 /* Because the Embedded Transmit Commands have been enabled,
651 * we must check to see if the escape character, NULL, is being
652 * sent. If it is, we must ensure that there is room for it to
653 * be doubled in the output stream. Therefore we no longer
654 * advance the pointer when the character is fetched, but
655 * rather wait until after the check for a NULL output
656 * character. This is necessary because there may not be room
657 * for the two chars needed to send a NULL.)
658 */
Alan Cox77451e52008-07-16 21:57:02 +0100659 outch = info->port.xmit_buf[info->xmit_tail];
Jiri Slabyce97a092007-10-18 03:06:21 -0700660 if (outch) {
661 info->xmit_cnt--;
662 info->xmit_tail = (info->xmit_tail + 1) &
663 (SERIAL_XMIT_SIZE - 1);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700664 cyy_writeb(info, CyTDR, outch);
Jiri Slabyce97a092007-10-18 03:06:21 -0700665 info->icount.tx++;
666 } else {
667 if (char_count > 1) {
Jiri Slaby02f11752006-12-08 02:39:28 -0800668 info->xmit_cnt--;
669 info->xmit_tail = (info->xmit_tail + 1) &
Jiri Slabyce97a092007-10-18 03:06:21 -0700670 (SERIAL_XMIT_SIZE - 1);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700671 cyy_writeb(info, CyTDR, outch);
672 cyy_writeb(info, CyTDR, 0);
Jiri Slaby02f11752006-12-08 02:39:28 -0800673 info->icount.tx++;
Jiri Slabyce97a092007-10-18 03:06:21 -0700674 char_count--;
Jiri Slaby02f11752006-12-08 02:39:28 -0800675 }
676 }
Jiri Slabye9410272006-12-08 02:39:28 -0800677 }
678
Jiri Slabyce97a092007-10-18 03:06:21 -0700679done:
Jiri Slabyd13549f2009-09-19 13:13:12 -0700680 tty_wakeup(tty);
681 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700682end:
683 /* end of service */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700684 cyy_writeb(info, CyTIR, save_xir & 0x3f);
685 cyy_writeb(info, CyCAR, save_car);
Jiri Slabyce97a092007-10-18 03:06:21 -0700686}
Jiri Slabye9410272006-12-08 02:39:28 -0800687
Jiri Slabyce97a092007-10-18 03:06:21 -0700688static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
689 void __iomem *base_addr)
690{
691 struct cyclades_port *info;
Jiri Slabyd13549f2009-09-19 13:13:12 -0700692 struct tty_struct *tty;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700693 int index = cinfo->bus_index;
694 u8 save_xir, channel, save_car, mdm_change, mdm_status;
Jiri Slabye9410272006-12-08 02:39:28 -0800695
Jiri Slabyce97a092007-10-18 03:06:21 -0700696 /* determine the channel & change to that context */
Jiri Slaby65f76a82007-10-18 03:06:22 -0700697 save_xir = readb(base_addr + (CyMIR << index));
698 channel = save_xir & CyIRChannel;
Jiri Slabyce97a092007-10-18 03:06:21 -0700699 info = &cinfo->ports[channel + chip * 4];
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700700 save_car = cyy_readb(info, CyCAR);
701 cyy_writeb(info, CyCAR, save_xir);
Jiri Slabye9410272006-12-08 02:39:28 -0800702
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700703 mdm_change = cyy_readb(info, CyMISR);
704 mdm_status = cyy_readb(info, CyMSVR1);
Jiri Slabye9410272006-12-08 02:39:28 -0800705
Jiri Slabyd13549f2009-09-19 13:13:12 -0700706 tty = tty_port_tty_get(&info->port);
707 if (!tty)
Jiri Slabyce97a092007-10-18 03:06:21 -0700708 goto end;
Jiri Slaby02f11752006-12-08 02:39:28 -0800709
Jiri Slabyce97a092007-10-18 03:06:21 -0700710 if (mdm_change & CyANY_DELTA) {
711 /* For statistics only */
712 if (mdm_change & CyDCD)
713 info->icount.dcd++;
714 if (mdm_change & CyCTS)
715 info->icount.cts++;
716 if (mdm_change & CyDSR)
717 info->icount.dsr++;
718 if (mdm_change & CyRI)
719 info->icount.rng++;
720
Alan Coxbdc04e32009-09-19 13:13:31 -0700721 wake_up_interruptible(&info->port.delta_msr_wait);
Jiri Slabyce97a092007-10-18 03:06:21 -0700722 }
723
Alan Cox77451e52008-07-16 21:57:02 +0100724 if ((mdm_change & CyDCD) && (info->port.flags & ASYNC_CHECK_CD)) {
Jiri Slaby174e6fe2009-09-19 13:13:13 -0700725 if (mdm_status & CyDCD)
726 wake_up_interruptible(&info->port.open_wait);
727 else
Jiri Slabyd13549f2009-09-19 13:13:12 -0700728 tty_hangup(tty);
Jiri Slabye9410272006-12-08 02:39:28 -0800729 }
Alan Cox77451e52008-07-16 21:57:02 +0100730 if ((mdm_change & CyCTS) && (info->port.flags & ASYNC_CTS_FLOW)) {
Jiri Slabyd13549f2009-09-19 13:13:12 -0700731 if (tty->hw_stopped) {
Jiri Slabyce97a092007-10-18 03:06:21 -0700732 if (mdm_status & CyCTS) {
733 /* cy_start isn't used
734 because... !!! */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700735 tty->hw_stopped = 0;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700736 cyy_writeb(info, CySRER,
737 cyy_readb(info, CySRER) | CyTxRdy);
Jiri Slabyd13549f2009-09-19 13:13:12 -0700738 tty_wakeup(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700739 }
740 } else {
741 if (!(mdm_status & CyCTS)) {
742 /* cy_stop isn't used
743 because ... !!! */
Jiri Slabyd13549f2009-09-19 13:13:12 -0700744 tty->hw_stopped = 1;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700745 cyy_writeb(info, CySRER,
746 cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slabyce97a092007-10-18 03:06:21 -0700747 }
748 }
749 }
750/* if (mdm_change & CyDSR) {
751 }
752 if (mdm_change & CyRI) {
753 }*/
Jiri Slabyd13549f2009-09-19 13:13:12 -0700754 tty_kref_put(tty);
Jiri Slabyce97a092007-10-18 03:06:21 -0700755end:
756 /* end of service */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700757 cyy_writeb(info, CyMIR, save_xir & 0x3f);
758 cyy_writeb(info, CyCAR, save_car);
Jiri Slabye9410272006-12-08 02:39:28 -0800759}
760
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761/* The real interrupt service routine is called
762 whenever the card wants its hand held--chars
763 received, out buffer empty, modem change, etc.
764 */
Jiri Slaby02f11752006-12-08 02:39:28 -0800765static irqreturn_t cyy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766{
Jiri Slaby02f11752006-12-08 02:39:28 -0800767 int status;
Jiri Slabyf7429032007-05-08 00:36:59 -0700768 struct cyclades_card *cinfo = dev_id;
Jiri Slaby02f11752006-12-08 02:39:28 -0800769 void __iomem *base_addr, *card_base_addr;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700770 unsigned int chip, too_many, had_work;
Jiri Slaby02f11752006-12-08 02:39:28 -0800771 int index;
Jiri Slabye9410272006-12-08 02:39:28 -0800772
Jiri Slabyf7429032007-05-08 00:36:59 -0700773 if (unlikely(cinfo == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774#ifdef CY_DEBUG_INTERRUPTS
Alan Cox15ed6cc2008-04-30 00:53:55 -0700775 printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",
776 irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777#endif
Jiri Slaby02f11752006-12-08 02:39:28 -0800778 return IRQ_NONE; /* spurious interrupt */
779 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
Jiri Slaby02f11752006-12-08 02:39:28 -0800781 card_base_addr = cinfo->base_addr;
782 index = cinfo->bus_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
Jiri Slabyf1e83c62007-05-08 00:36:24 -0700784 /* card was not initialized yet (e.g. DEBUG_SHIRQ) */
785 if (unlikely(card_base_addr == NULL))
786 return IRQ_HANDLED;
787
Jiri Slaby02f11752006-12-08 02:39:28 -0800788 /* This loop checks all chips in the card. Make a note whenever
789 _any_ chip had some work to do, as this is considered an
790 indication that there will be more to do. Only when no chip
791 has any work does this outermost loop exit.
792 */
793 do {
794 had_work = 0;
795 for (chip = 0; chip < cinfo->num_chips; chip++) {
796 base_addr = cinfo->base_addr +
797 (cy_chip_offset[chip] << index);
798 too_many = 0;
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700799 while ((status = readb(base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -0800800 (CySVRR << index))) != 0x00) {
801 had_work++;
802 /* The purpose of the following test is to ensure that
803 no chip can monopolize the driver. This forces the
804 chips to be checked in a round-robin fashion (after
805 draining each of a bunch (1000) of characters).
806 */
Jiri Slabyce97a092007-10-18 03:06:21 -0700807 if (1000 < too_many++)
Jiri Slaby02f11752006-12-08 02:39:28 -0800808 break;
Jiri Slaby1c0a3872007-10-18 03:06:22 -0700809 spin_lock(&cinfo->card_lock);
Jiri Slabyce97a092007-10-18 03:06:21 -0700810 if (status & CySRReceive) /* rx intr */
811 cyy_chip_rx(cinfo, chip, base_addr);
812 if (status & CySRTransmit) /* tx intr */
813 cyy_chip_tx(cinfo, chip, base_addr);
814 if (status & CySRModem) /* modem intr */
815 cyy_chip_modem(cinfo, chip, base_addr);
Jiri Slaby1c0a3872007-10-18 03:06:22 -0700816 spin_unlock(&cinfo->card_lock);
Jiri Slaby02f11752006-12-08 02:39:28 -0800817 }
818 }
819 } while (had_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
Jiri Slaby02f11752006-12-08 02:39:28 -0800821 /* clear interrupts */
822 spin_lock(&cinfo->card_lock);
823 cy_writeb(card_base_addr + (Cy_ClrIntr << index), 0);
824 /* Cy_ClrIntr is 0x1800 */
825 spin_unlock(&cinfo->card_lock);
826 return IRQ_HANDLED;
827} /* cyy_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
Jiri Slaby4d768202009-09-19 13:13:15 -0700829static void cyy_change_rts_dtr(struct cyclades_port *info, unsigned int set,
830 unsigned int clear)
831{
832 struct cyclades_card *card = info->card;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700833 int channel = info->line - card->first_line;
Jiri Slaby0d348722009-09-19 13:13:16 -0700834 u32 rts, dtr, msvrr, msvrd;
Jiri Slaby4d768202009-09-19 13:13:15 -0700835
Jiri Slaby4d768202009-09-19 13:13:15 -0700836 channel &= 0x03;
Jiri Slaby4d768202009-09-19 13:13:15 -0700837
Jiri Slaby0d348722009-09-19 13:13:16 -0700838 if (info->rtsdtr_inv) {
839 msvrr = CyMSVR2;
840 msvrd = CyMSVR1;
841 rts = CyDTR;
842 dtr = CyRTS;
843 } else {
844 msvrr = CyMSVR1;
845 msvrd = CyMSVR2;
846 rts = CyRTS;
847 dtr = CyDTR;
848 }
Jiri Slaby4d768202009-09-19 13:13:15 -0700849 if (set & TIOCM_RTS) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700850 cyy_writeb(info, CyCAR, channel);
851 cyy_writeb(info, msvrr, rts);
Jiri Slaby4d768202009-09-19 13:13:15 -0700852 }
853 if (clear & TIOCM_RTS) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700854 cyy_writeb(info, CyCAR, channel);
855 cyy_writeb(info, msvrr, ~rts);
Jiri Slaby4d768202009-09-19 13:13:15 -0700856 }
857 if (set & TIOCM_DTR) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700858 cyy_writeb(info, CyCAR, channel);
859 cyy_writeb(info, msvrd, dtr);
Jiri Slaby4d768202009-09-19 13:13:15 -0700860#ifdef CY_DEBUG_DTR
861 printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
862 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700863 cyy_readb(info, CyMSVR1),
864 cyy_readb(info, CyMSVR2));
Jiri Slaby4d768202009-09-19 13:13:15 -0700865#endif
866 }
867 if (clear & TIOCM_DTR) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700868 cyy_writeb(info, CyCAR, channel);
869 cyy_writeb(info, msvrd, ~dtr);
Jiri Slaby4d768202009-09-19 13:13:15 -0700870#ifdef CY_DEBUG_DTR
871 printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
872 printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
Jiri Slaby3aeea5b2009-09-19 13:13:16 -0700873 cyy_readb(info, CyMSVR1),
874 cyy_readb(info, CyMSVR2));
Jiri Slaby4d768202009-09-19 13:13:15 -0700875#endif
876 }
877}
878
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879/***********************************************************/
880/********* End of block of Cyclom-Y specific code **********/
Alan Cox15ed6cc2008-04-30 00:53:55 -0700881/******** Start of block of Cyclades-Z specific code *******/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882/***********************************************************/
883
884static int
Jiri Slaby02f11752006-12-08 02:39:28 -0800885cyz_fetch_msg(struct cyclades_card *cinfo,
Alan Cox15ed6cc2008-04-30 00:53:55 -0700886 __u32 *channel, __u8 *cmd, __u32 *param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700888 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -0800889 unsigned long loc_doorbell;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
Jiri Slaby97e87f82009-06-11 12:29:27 +0100891 loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell);
Jiri Slaby02f11752006-12-08 02:39:28 -0800892 if (loc_doorbell) {
893 *cmd = (char)(0xff & loc_doorbell);
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700894 *channel = readl(&board_ctrl->fwcmd_channel);
895 *param = (__u32) readl(&board_ctrl->fwcmd_param);
Jiri Slaby97e87f82009-06-11 12:29:27 +0100896 cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff);
Jiri Slaby02f11752006-12-08 02:39:28 -0800897 return 1;
898 }
899 return 0;
900} /* cyz_fetch_msg */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
902static int
Jiri Slaby02f11752006-12-08 02:39:28 -0800903cyz_issue_cmd(struct cyclades_card *cinfo,
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700904 __u32 channel, __u8 cmd, __u32 param)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700906 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -0700907 __u32 __iomem *pci_doorbell;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700908 unsigned int index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
Jiri Slaby2693f482009-06-11 12:31:06 +0100910 if (!cyz_is_loaded(cinfo))
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800911 return -1;
Alan Cox15ed6cc2008-04-30 00:53:55 -0700912
Jiri Slaby02f11752006-12-08 02:39:28 -0800913 index = 0;
Jiri Slaby97e87f82009-06-11 12:29:27 +0100914 pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700915 while ((readl(pci_doorbell) & 0xff) != 0) {
Alan Cox15ed6cc2008-04-30 00:53:55 -0700916 if (index++ == 1000)
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700917 return (int)(readl(pci_doorbell) & 0xff);
Jiri Slaby02f11752006-12-08 02:39:28 -0800918 udelay(50L);
919 }
920 cy_writel(&board_ctrl->hcmd_channel, channel);
921 cy_writel(&board_ctrl->hcmd_param, param);
922 cy_writel(pci_doorbell, (long)cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
Jiri Slaby096dcfc2006-12-08 02:39:30 -0800924 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -0800925} /* cyz_issue_cmd */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700927static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -0700929 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby875b2062007-05-08 00:36:49 -0700930 struct cyclades_card *cinfo = info->card;
Jiri Slaby65f76a82007-10-18 03:06:22 -0700931 unsigned int char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -0800932 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933#ifdef BLOCKMOVE
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700934 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935#else
Jiri Slaby02f11752006-12-08 02:39:28 -0800936 char data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937#endif
Jiri Slabyad39c302007-05-08 00:35:49 -0700938 __u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700940 rx_get = new_rx_get = readl(&buf_ctrl->rx_get);
941 rx_put = readl(&buf_ctrl->rx_put);
942 rx_bufsize = readl(&buf_ctrl->rx_bufsize);
943 rx_bufaddr = readl(&buf_ctrl->rx_bufaddr);
Jiri Slaby02f11752006-12-08 02:39:28 -0800944 if (rx_put >= rx_get)
945 char_count = rx_put - rx_get;
946 else
947 char_count = rx_put - rx_get + rx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
Jiri Slaby02f11752006-12-08 02:39:28 -0800949 if (char_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950#ifdef CY_ENABLE_MONITORING
Jiri Slaby02f11752006-12-08 02:39:28 -0800951 info->mon.int_count++;
952 info->mon.char_count += char_count;
953 if (char_count > info->mon.char_max)
954 info->mon.char_max = char_count;
955 info->mon.char_last = char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956#endif
Jiri Slabyf7429032007-05-08 00:36:59 -0700957 if (tty == NULL) {
Jiri Slaby02f11752006-12-08 02:39:28 -0800958 /* flush received characters */
959 new_rx_get = (new_rx_get + char_count) &
960 (rx_bufsize - 1);
961 info->rflush_count++;
962 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -0800964 /* we'd like to use memcpy(t, f, n) and memset(s, c, count)
965 for performance, but because of buffer boundaries, there
966 may be several steps to the operation */
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700967 while (1) {
968 len = tty_prepare_flip_string(tty, &buf,
969 char_count);
970 if (!len)
971 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700973 len = min_t(unsigned int, min(len, char_count),
974 rx_bufsize - new_rx_get);
975
976 memcpy_fromio(buf, cinfo->base_addr +
977 rx_bufaddr + new_rx_get, len);
978
979 new_rx_get = (new_rx_get + len) &
Jiri Slaby02f11752006-12-08 02:39:28 -0800980 (rx_bufsize - 1);
Jiri Slabyce71b0f2007-05-08 00:36:53 -0700981 char_count -= len;
982 info->icount.rx += len;
983 info->idle_stats.recv_bytes += len;
Jiri Slaby02f11752006-12-08 02:39:28 -0800984 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985#else
Jiri Slaby02f11752006-12-08 02:39:28 -0800986 len = tty_buffer_request_room(tty, char_count);
987 while (len--) {
Jiri Slabydb05c3b2007-05-08 00:35:46 -0700988 data = readb(cinfo->base_addr + rx_bufaddr +
Jiri Slaby02f11752006-12-08 02:39:28 -0800989 new_rx_get);
Alan Cox15ed6cc2008-04-30 00:53:55 -0700990 new_rx_get = (new_rx_get + 1) &
991 (rx_bufsize - 1);
Jiri Slaby02f11752006-12-08 02:39:28 -0800992 tty_insert_flip_char(tty, data, TTY_NORMAL);
993 info->idle_stats.recv_bytes++;
994 info->icount.rx++;
995 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996#endif
997#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -0800998 /* Recalculate the number of chars in the RX buffer and issue
999 a cmd in case it's higher than the RX high water mark */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001000 rx_put = readl(&buf_ctrl->rx_put);
Jiri Slaby02f11752006-12-08 02:39:28 -08001001 if (rx_put >= rx_get)
1002 char_count = rx_put - rx_get;
1003 else
1004 char_count = rx_put - rx_get + rx_bufsize;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001005 if (char_count >= readl(&buf_ctrl->rx_threshold) &&
Jiri Slabyebafeef2007-10-18 03:06:20 -07001006 !timer_pending(&cyz_rx_full_timer[
1007 info->line]))
1008 mod_timer(&cyz_rx_full_timer[info->line],
1009 jiffies + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001011 info->idle_stats.recv_idle = jiffies;
1012 tty_schedule_flip(tty);
1013 }
1014 /* Update rx_get */
1015 cy_writel(&buf_ctrl->rx_get, new_rx_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017}
1018
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001019static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001021 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby875b2062007-05-08 00:36:49 -07001022 struct cyclades_card *cinfo = info->card;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001023 u8 data;
1024 unsigned int char_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025#ifdef BLOCKMOVE
Jiri Slaby02f11752006-12-08 02:39:28 -08001026 int small_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027#endif
Jiri Slabyad39c302007-05-08 00:35:49 -07001028 __u32 tx_put, tx_get, tx_bufsize, tx_bufaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
Jiri Slaby02f11752006-12-08 02:39:28 -08001030 if (info->xmit_cnt <= 0) /* Nothing to transmit */
1031 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001033 tx_get = readl(&buf_ctrl->tx_get);
1034 tx_put = readl(&buf_ctrl->tx_put);
1035 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
1036 tx_bufaddr = readl(&buf_ctrl->tx_bufaddr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001037 if (tx_put >= tx_get)
1038 char_count = tx_get - tx_put - 1 + tx_bufsize;
1039 else
1040 char_count = tx_get - tx_put - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
Jiri Slaby02f11752006-12-08 02:39:28 -08001042 if (char_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
Jiri Slabyf7429032007-05-08 00:36:59 -07001044 if (tty == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08001045 goto ztxdone;
Jiri Slaby02f11752006-12-08 02:39:28 -08001046
1047 if (info->x_char) { /* send special char */
1048 data = info->x_char;
1049
1050 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1051 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1052 info->x_char = 0;
1053 char_count--;
1054 info->icount.tx++;
Jiri Slaby02f11752006-12-08 02:39:28 -08001055 }
1056#ifdef BLOCKMOVE
1057 while (0 < (small_count = min_t(unsigned int,
1058 tx_bufsize - tx_put, min_t(unsigned int,
1059 (SERIAL_XMIT_SIZE - info->xmit_tail),
1060 min_t(unsigned int, info->xmit_cnt,
1061 char_count))))) {
1062
1063 memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr +
1064 tx_put),
Alan Cox77451e52008-07-16 21:57:02 +01001065 &info->port.xmit_buf[info->xmit_tail],
Jiri Slaby02f11752006-12-08 02:39:28 -08001066 small_count);
1067
1068 tx_put = (tx_put + small_count) & (tx_bufsize - 1);
1069 char_count -= small_count;
1070 info->icount.tx += small_count;
1071 info->xmit_cnt -= small_count;
1072 info->xmit_tail = (info->xmit_tail + small_count) &
1073 (SERIAL_XMIT_SIZE - 1);
Jiri Slaby02f11752006-12-08 02:39:28 -08001074 }
1075#else
1076 while (info->xmit_cnt && char_count) {
Alan Cox77451e52008-07-16 21:57:02 +01001077 data = info->port.xmit_buf[info->xmit_tail];
Jiri Slaby02f11752006-12-08 02:39:28 -08001078 info->xmit_cnt--;
1079 info->xmit_tail = (info->xmit_tail + 1) &
1080 (SERIAL_XMIT_SIZE - 1);
1081
1082 cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
1083 tx_put = (tx_put + 1) & (tx_bufsize - 1);
1084 char_count--;
1085 info->icount.tx++;
Jiri Slaby02f11752006-12-08 02:39:28 -08001086 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087#endif
Jiri Slabyebafeef2007-10-18 03:06:20 -07001088 tty_wakeup(tty);
Jiri Slaby7fa57a02007-10-22 20:45:13 -07001089ztxdone:
Jiri Slaby02f11752006-12-08 02:39:28 -08001090 /* Update tx_put */
1091 cy_writel(&buf_ctrl->tx_put, tx_put);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093}
1094
Jiri Slaby02f11752006-12-08 02:39:28 -08001095static void cyz_handle_cmd(struct cyclades_card *cinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096{
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001097 struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001098 struct tty_struct *tty;
1099 struct cyclades_port *info;
Jiri Slaby101b8152009-06-11 12:30:10 +01001100 __u32 channel, param, fw_ver;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001101 __u8 cmd;
Jiri Slaby02f11752006-12-08 02:39:28 -08001102 int special_count;
1103 int delta_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001105 fw_ver = readl(&board_ctrl->fw_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106
Jiri Slaby02f11752006-12-08 02:39:28 -08001107 while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
1108 special_count = 0;
1109 delta_count = 0;
Jiri Slabydd025c02007-05-08 00:37:02 -07001110 info = &cinfo->ports[channel];
Jiri Slabyd13549f2009-09-19 13:13:12 -07001111 tty = tty_port_tty_get(&info->port);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001112 if (tty == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08001113 continue;
Jiri Slabyf7429032007-05-08 00:36:59 -07001114
Jiri Slaby02f11752006-12-08 02:39:28 -08001115 switch (cmd) {
1116 case C_CM_PR_ERROR:
1117 tty_insert_flip_char(tty, 0, TTY_PARITY);
1118 info->icount.rx++;
1119 special_count++;
1120 break;
1121 case C_CM_FR_ERROR:
1122 tty_insert_flip_char(tty, 0, TTY_FRAME);
1123 info->icount.rx++;
1124 special_count++;
1125 break;
1126 case C_CM_RXBRK:
1127 tty_insert_flip_char(tty, 0, TTY_BREAK);
1128 info->icount.rx++;
1129 special_count++;
1130 break;
1131 case C_CM_MDCD:
1132 info->icount.dcd++;
1133 delta_count++;
Alan Cox77451e52008-07-16 21:57:02 +01001134 if (info->port.flags & ASYNC_CHECK_CD) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001135 u32 dcd = fw_ver > 241 ? param :
1136 readl(&info->u.cyz.ch_ctrl->rs_status);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07001137 if (dcd & C_RS_DCD)
Alan Cox77451e52008-07-16 21:57:02 +01001138 wake_up_interruptible(&info->port.open_wait);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07001139 else
Jiri Slabyd13549f2009-09-19 13:13:12 -07001140 tty_hangup(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001141 }
1142 break;
1143 case C_CM_MCTS:
1144 info->icount.cts++;
1145 delta_count++;
1146 break;
1147 case C_CM_MRI:
1148 info->icount.rng++;
1149 delta_count++;
1150 break;
1151 case C_CM_MDSR:
1152 info->icount.dsr++;
1153 delta_count++;
1154 break;
1155#ifdef Z_WAKE
1156 case C_CM_IOCTLW:
Jiri Slabyebafeef2007-10-18 03:06:20 -07001157 complete(&info->shutdown_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001158 break;
1159#endif
1160#ifdef CONFIG_CYZ_INTR
1161 case C_CM_RXHIWM:
1162 case C_CM_RXNNDT:
1163 case C_CM_INTBACK2:
1164 /* Reception Interrupt */
1165#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001166 printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
1167 "port %ld\n", info->card, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001168#endif
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001169 cyz_handle_rx(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001170 break;
1171 case C_CM_TXBEMPTY:
1172 case C_CM_TXLOWWM:
1173 case C_CM_INTBACK:
1174 /* Transmission Interrupt */
1175#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001176 printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
1177 "port %ld\n", info->card, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001178#endif
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001179 cyz_handle_tx(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001180 break;
1181#endif /* CONFIG_CYZ_INTR */
1182 case C_CM_FATAL:
1183 /* should do something with this !!! */
1184 break;
1185 default:
1186 break;
1187 }
1188 if (delta_count)
Alan Coxbdc04e32009-09-19 13:13:31 -07001189 wake_up_interruptible(&info->port.delta_msr_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001190 if (special_count)
1191 tty_schedule_flip(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001192 tty_kref_put(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001193 }
1194}
1195
1196#ifdef CONFIG_CYZ_INTR
1197static irqreturn_t cyz_interrupt(int irq, void *dev_id)
1198{
Jiri Slabyf7429032007-05-08 00:36:59 -07001199 struct cyclades_card *cinfo = dev_id;
Jiri Slaby02f11752006-12-08 02:39:28 -08001200
Jiri Slaby2693f482009-06-11 12:31:06 +01001201 if (unlikely(!cyz_is_loaded(cinfo))) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001202#ifdef CY_DEBUG_INTERRUPTS
Jiri Slaby21719192007-05-08 00:36:42 -07001203 printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
1204 "(IRQ%d).\n", irq);
Jiri Slaby02f11752006-12-08 02:39:28 -08001205#endif
1206 return IRQ_NONE;
1207 }
1208
1209 /* Handle the interrupts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 cyz_handle_cmd(cinfo);
1211
Jiri Slaby02f11752006-12-08 02:39:28 -08001212 return IRQ_HANDLED;
1213} /* cyz_interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214
Jiri Slaby02f11752006-12-08 02:39:28 -08001215static void cyz_rx_restart(unsigned long arg)
1216{
1217 struct cyclades_port *info = (struct cyclades_port *)arg;
Jiri Slaby875b2062007-05-08 00:36:49 -07001218 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001219 int retval;
Jiri Slaby875b2062007-05-08 00:36:49 -07001220 __u32 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08001221 unsigned long flags;
1222
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001223 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07001224 retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001225 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001226 printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08001227 info->line, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001229 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001230}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231
Jiri Slaby02f11752006-12-08 02:39:28 -08001232#else /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
Jiri Slaby02f11752006-12-08 02:39:28 -08001234static void cyz_poll(unsigned long arg)
1235{
1236 struct cyclades_card *cinfo;
1237 struct cyclades_port *info;
Jiri Slabyb7050902007-05-08 00:35:48 -07001238 unsigned long expires = jiffies + HZ;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001239 unsigned int port, card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001240
Jiri Slaby02f11752006-12-08 02:39:28 -08001241 for (card = 0; card < NR_CARDS; card++) {
1242 cinfo = &cy_card[card];
1243
Jiri Slaby2693f482009-06-11 12:31:06 +01001244 if (!cy_is_Z(cinfo))
Jiri Slaby02f11752006-12-08 02:39:28 -08001245 continue;
Jiri Slaby2693f482009-06-11 12:31:06 +01001246 if (!cyz_is_loaded(cinfo))
Jiri Slaby02f11752006-12-08 02:39:28 -08001247 continue;
1248
Jiri Slaby02f11752006-12-08 02:39:28 -08001249 /* Skip first polling cycle to avoid racing conditions with the FW */
1250 if (!cinfo->intr_enabled) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001251 cinfo->intr_enabled = 1;
1252 continue;
1253 }
1254
1255 cyz_handle_cmd(cinfo);
1256
1257 for (port = 0; port < cinfo->nports; port++) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07001258 struct tty_struct *tty;
1259
Jiri Slabydd025c02007-05-08 00:37:02 -07001260 info = &cinfo->ports[port];
Jiri Slabyd13549f2009-09-19 13:13:12 -07001261 tty = tty_port_tty_get(&info->port);
1262 /* OK to pass NULL to the handle functions below.
1263 They need to drop the data in that case. */
1264
Jiri Slaby02f11752006-12-08 02:39:28 -08001265 if (!info->throttle)
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001266 cyz_handle_rx(info, tty);
1267 cyz_handle_tx(info, tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07001268 tty_kref_put(tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08001269 }
1270 /* poll every 'cyz_polling_cycle' period */
Jiri Slabyb7050902007-05-08 00:35:48 -07001271 expires = jiffies + cyz_polling_cycle;
Jiri Slaby02f11752006-12-08 02:39:28 -08001272 }
Jiri Slabyb7050902007-05-08 00:35:48 -07001273 mod_timer(&cyz_timerlist, expires);
Jiri Slaby02f11752006-12-08 02:39:28 -08001274} /* cyz_poll */
1275
1276#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
1278/********** End of block of Cyclades-Z specific code *********/
1279/***********************************************************/
1280
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281/* This is called whenever a port becomes active;
1282 interrupts are enabled and DTR & RTS are turned on.
1283 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001284static int cy_startup(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285{
Jiri Slaby875b2062007-05-08 00:36:49 -07001286 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001287 unsigned long flags;
1288 int retval = 0;
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001289 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08001290 unsigned long page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291
Jiri Slaby02f11752006-12-08 02:39:28 -08001292 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07001293 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294
Jiri Slaby02f11752006-12-08 02:39:28 -08001295 page = get_zeroed_page(GFP_KERNEL);
1296 if (!page)
1297 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001299 spin_lock_irqsave(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001301 if (info->port.flags & ASYNC_INITIALIZED)
Jiri Slaby02f11752006-12-08 02:39:28 -08001302 goto errout;
Jiri Slaby02f11752006-12-08 02:39:28 -08001303
1304 if (!info->type) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07001305 set_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001306 goto errout;
1307 }
1308
Alan Cox77451e52008-07-16 21:57:02 +01001309 if (info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001310 free_page(page);
1311 else
Alan Cox77451e52008-07-16 21:57:02 +01001312 info->port.xmit_buf = (unsigned char *)page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001314 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315
Jiri Slabyd13549f2009-09-19 13:13:12 -07001316 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
Jiri Slaby2693f482009-06-11 12:31:06 +01001318 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001319 channel &= 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001321 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001322
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001323 cyy_writeb(info, CyCAR, channel);
Jiri Slaby02f11752006-12-08 02:39:28 -08001324
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001325 cyy_writeb(info, CyRTPR,
Jiri Slaby02f11752006-12-08 02:39:28 -08001326 (info->default_timeout ? info->default_timeout : 0x02));
1327 /* 10ms rx timeout */
1328
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001329 cyy_issue_cmd(info, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR);
Jiri Slaby02f11752006-12-08 02:39:28 -08001330
Jiri Slaby4d768202009-09-19 13:13:15 -07001331 cyy_change_rts_dtr(info, TIOCM_RTS | TIOCM_DTR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001333 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyRxData);
Jiri Slaby02f11752006-12-08 02:39:28 -08001334 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001335 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001336
Jiri Slaby2693f482009-06-11 12:31:06 +01001337 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08001338 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08001339
Jiri Slaby02f11752006-12-08 02:39:28 -08001340#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001341 printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001342 "base_addr %p\n", card, channel, card->base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001343#endif
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001344 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001345
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001346 cy_writel(&ch_ctrl->op_mode, C_CH_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347#ifdef Z_WAKE
1348#ifdef CONFIG_CYZ_INTR
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001349 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001350 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1351 C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352#else
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001353 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001354 C_IN_IOCTLW | C_IN_MDCD);
1355#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356#else
1357#ifdef CONFIG_CYZ_INTR
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001358 cy_writel(&ch_ctrl->intr_enable,
Jiri Slaby02f11752006-12-08 02:39:28 -08001359 C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |
1360 C_IN_RXNNDT | C_IN_MDCD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361#else
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001362 cy_writel(&ch_ctrl->intr_enable, C_IN_MDCD);
Jiri Slaby02f11752006-12-08 02:39:28 -08001363#endif /* CONFIG_CYZ_INTR */
1364#endif /* Z_WAKE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
Jiri Slaby875b2062007-05-08 00:36:49 -07001366 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001367 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001368 printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "
1369 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
Jiri Slaby02f11752006-12-08 02:39:28 -08001372 /* Flush RX buffers before raising DTR and RTS */
Jiri Slaby875b2062007-05-08 00:36:49 -07001373 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001374 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001375 printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was "
1376 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
Jiri Slaby02f11752006-12-08 02:39:28 -08001379 /* set timeout !!! */
1380 /* set RTS and DTR !!! */
Jiri Slaby4d768202009-09-19 13:13:15 -07001381 tty_port_raise_dtr_rts(&info->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382
Jiri Slaby02f11752006-12-08 02:39:28 -08001383 /* enable send, recv, modem !!! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001386 info->port.flags |= ASYNC_INITIALIZED;
1387
1388 clear_bit(TTY_IO_ERROR, &tty->flags);
1389 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1390 info->breakon = info->breakoff = 0;
1391 memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
1392 info->idle_stats.in_use =
1393 info->idle_stats.recv_idle =
1394 info->idle_stats.xmit_idle = jiffies;
1395
1396 spin_unlock_irqrestore(&card->card_lock, flags);
1397
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001399 printk(KERN_DEBUG "cyc startup done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400#endif
1401 return 0;
1402
1403errout:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001404 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slabycc7fdf42009-09-19 13:13:15 -07001405 free_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08001407} /* startup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408
Jiri Slaby02f11752006-12-08 02:39:28 -08001409static void start_xmit(struct cyclades_port *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001411 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001412 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001413 int channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414
Jiri Slaby2693f482009-06-11 12:31:06 +01001415 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001416 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001417 cyy_writeb(info, CyCAR, channel & 0x03);
1418 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001419 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001420 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421#ifdef CONFIG_CYZ_INTR
Jiri Slaby02f11752006-12-08 02:39:28 -08001422 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001424 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby875b2062007-05-08 00:36:49 -07001425 retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001426 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001427 printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "
1428 "%x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001429 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001430 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001431#else /* CONFIG_CYZ_INTR */
1432 /* Don't have to do anything at this time */
1433#endif /* CONFIG_CYZ_INTR */
1434 }
1435} /* start_xmit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436
1437/*
1438 * This routine shuts down a serial port; interrupts are disabled,
1439 * and DTR is dropped if the hangup on close termio flag is on.
1440 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001441static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442{
Jiri Slaby875b2062007-05-08 00:36:49 -07001443 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001444 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445
Alan Cox77451e52008-07-16 21:57:02 +01001446 if (!(info->port.flags & ASYNC_INITIALIZED))
Jiri Slaby02f11752006-12-08 02:39:28 -08001447 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
Jiri Slaby02f11752006-12-08 02:39:28 -08001449 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01001450 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001451 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001452
1453 /* Clear delta_msr_wait queue to avoid mem leaks. */
Alan Coxbdc04e32009-09-19 13:13:31 -07001454 wake_up_interruptible(&info->port.delta_msr_wait);
Jiri Slaby02f11752006-12-08 02:39:28 -08001455
Alan Cox77451e52008-07-16 21:57:02 +01001456 if (info->port.xmit_buf) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001457 unsigned char *temp;
Alan Cox77451e52008-07-16 21:57:02 +01001458 temp = info->port.xmit_buf;
1459 info->port.xmit_buf = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08001460 free_page((unsigned long)temp);
1461 }
Alan Coxadc8d742012-07-14 15:31:47 +01001462 if (tty->termios.c_cflag & HUPCL)
Jiri Slaby4d768202009-09-19 13:13:15 -07001463 cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);
1464
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001465 cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR);
Jiri Slaby02f11752006-12-08 02:39:28 -08001466 /* it may be appropriate to clear _XMIT at
1467 some later date (after testing)!!! */
1468
Jiri Slabyd13549f2009-09-19 13:13:12 -07001469 set_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox77451e52008-07-16 21:57:02 +01001470 info->port.flags &= ~ASYNC_INITIALIZED;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001471 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001472 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08001473#ifdef CY_DEBUG_OPEN
Jiri Slaby0e7f4192011-03-23 09:49:56 +01001474 int channel = info->line - card->first_line;
Jiri Slaby21719192007-05-08 00:36:42 -07001475 printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001476 "base_addr %p\n", card, channel, card->base_addr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001477#endif
1478
Jiri Slaby2693f482009-06-11 12:31:06 +01001479 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08001480 return;
Jiri Slaby02f11752006-12-08 02:39:28 -08001481
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001482 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001483
Alan Cox77451e52008-07-16 21:57:02 +01001484 if (info->port.xmit_buf) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001485 unsigned char *temp;
Alan Cox77451e52008-07-16 21:57:02 +01001486 temp = info->port.xmit_buf;
1487 info->port.xmit_buf = NULL;
Jiri Slaby02f11752006-12-08 02:39:28 -08001488 free_page((unsigned long)temp);
1489 }
1490
Alan Coxadc8d742012-07-14 15:31:47 +01001491 if (tty->termios.c_cflag & HUPCL)
Jiri Slaby4d768202009-09-19 13:13:15 -07001492 tty_port_lower_dtr_rts(&info->port);
Jiri Slaby02f11752006-12-08 02:39:28 -08001493
Jiri Slabyd13549f2009-09-19 13:13:12 -07001494 set_bit(TTY_IO_ERROR, &tty->flags);
Alan Cox77451e52008-07-16 21:57:02 +01001495 info->port.flags &= ~ASYNC_INITIALIZED;
Jiri Slaby02f11752006-12-08 02:39:28 -08001496
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001497 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001498 }
1499
1500#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001501 printk(KERN_DEBUG "cyc shutdown done\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001502#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001503} /* shutdown */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504
1505/*
1506 * ------------------------------------------------------------
1507 * cy_open() and friends
1508 * ------------------------------------------------------------
1509 */
1510
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511/*
1512 * This routine is called whenever a serial port is opened. It
1513 * performs the serial-specific initialization for the tty structure.
1514 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001515static int cy_open(struct tty_struct *tty, struct file *filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516{
Jiri Slaby02f11752006-12-08 02:39:28 -08001517 struct cyclades_port *info;
Jiri Slaby410235f2012-03-05 14:52:01 +01001518 unsigned int i, line = tty->index;
Jiri Slaby65f76a82007-10-18 03:06:22 -07001519 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520
Jiri Slabydd025c02007-05-08 00:37:02 -07001521 for (i = 0; i < NR_CARDS; i++)
1522 if (line < cy_card[i].first_line + cy_card[i].nports &&
1523 line >= cy_card[i].first_line)
1524 break;
1525 if (i >= NR_CARDS)
1526 return -ENODEV;
1527 info = &cy_card[i].ports[line - cy_card[i].first_line];
Alan Cox15ed6cc2008-04-30 00:53:55 -07001528 if (info->line < 0)
Jiri Slaby02f11752006-12-08 02:39:28 -08001529 return -ENODEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08001530
1531 /* If the card's firmware hasn't been loaded,
1532 treat it as absent from the system. This
1533 will make the user pay attention.
1534 */
Jiri Slaby2693f482009-06-11 12:31:06 +01001535 if (cy_is_Z(info->card)) {
Jiri Slaby875b2062007-05-08 00:36:49 -07001536 struct cyclades_card *cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001537 struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
1538
Jiri Slaby2693f482009-06-11 12:31:06 +01001539 if (!cyz_is_loaded(cinfo)) {
1540 if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
Jiri Slaby101b8152009-06-11 12:30:10 +01001541 readl(&firm_id->signature) ==
1542 ZFIRM_HLT) {
Jiri Slaby21719192007-05-08 00:36:42 -07001543 printk(KERN_ERR "cyc:Cyclades-Z Error: you "
1544 "need an external power supply for "
1545 "this number of ports.\nFirmware "
1546 "halted.\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001547 } else {
Jiri Slaby21719192007-05-08 00:36:42 -07001548 printk(KERN_ERR "cyc:Cyclades-Z firmware not "
1549 "yet loaded\n");
Jiri Slaby02f11752006-12-08 02:39:28 -08001550 }
1551 return -ENODEV;
1552 }
1553#ifdef CONFIG_CYZ_INTR
1554 else {
1555 /* In case this Z board is operating in interrupt mode, its
1556 interrupts should be enabled as soon as the first open
1557 happens to one of its ports. */
1558 if (!cinfo->intr_enabled) {
Jiri Slaby97e87f82009-06-11 12:29:27 +01001559 u16 intr;
Jiri Slaby02f11752006-12-08 02:39:28 -08001560
Jiri Slaby02f11752006-12-08 02:39:28 -08001561 /* Enable interrupts on the PLX chip */
Jiri Slaby97e87f82009-06-11 12:29:27 +01001562 intr = readw(&cinfo->ctl_addr.p9060->
1563 intr_ctrl_stat) | 0x0900;
1564 cy_writew(&cinfo->ctl_addr.p9060->
1565 intr_ctrl_stat, intr);
Jiri Slaby02f11752006-12-08 02:39:28 -08001566 /* Enable interrupts on the FW */
1567 retval = cyz_issue_cmd(cinfo, 0,
1568 C_CM_IRQ_ENBL, 0L);
1569 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001570 printk(KERN_ERR "cyc:IRQ enable retval "
1571 "was %x\n", retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001572 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001573 cinfo->intr_enabled = 1;
1574 }
1575 }
1576#endif /* CONFIG_CYZ_INTR */
1577 /* Make sure this Z port really exists in hardware */
1578 if (info->line > (cinfo->first_line + cinfo->nports - 1))
1579 return -ENODEV;
1580 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07001582 printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001584 tty->driver_data = info;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001585 if (serial_paranoia_check(info, tty->name, "cy_open"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001586 return -ENODEV;
Alan Cox15ed6cc2008-04-30 00:53:55 -07001587
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001589 printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
Alan Cox77451e52008-07-16 21:57:02 +01001590 info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591#endif
Alan Cox77451e52008-07-16 21:57:02 +01001592 info->port.count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593#ifdef CY_DEBUG_COUNT
Jiri Slaby21719192007-05-08 00:36:42 -07001594 printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
Alan Cox77451e52008-07-16 21:57:02 +01001595 current->pid, info->port.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597
Jiri Slaby02f11752006-12-08 02:39:28 -08001598 /*
1599 * If the port is the middle of closing, bail out now
1600 */
Alan Cox77451e52008-07-16 21:57:02 +01001601 if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
Alan Cox6d31a882012-07-14 15:31:27 +01001602 wait_event_interruptible_tty(info->port.close_wait,
Alan Cox77451e52008-07-16 21:57:02 +01001603 !(info->port.flags & ASYNC_CLOSING));
1604 return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
Jiri Slaby02f11752006-12-08 02:39:28 -08001605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606
Jiri Slaby02f11752006-12-08 02:39:28 -08001607 /*
1608 * Start up serial port
1609 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001610 retval = cy_startup(info, tty);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001611 if (retval)
Jiri Slaby02f11752006-12-08 02:39:28 -08001612 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613
Jiri Slabyf0737572009-09-19 13:13:12 -07001614 retval = tty_port_block_til_ready(&info->port, tty, filp);
Jiri Slaby02f11752006-12-08 02:39:28 -08001615 if (retval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001617 printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
1618 "with %d\n", retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001620 return retval;
1621 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622
Jiri Slaby02f11752006-12-08 02:39:28 -08001623 info->throttle = 0;
Jiri Slabyd13549f2009-09-19 13:13:12 -07001624 tty_port_tty_set(&info->port, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625
1626#ifdef CY_DEBUG_OPEN
Jiri Slaby21719192007-05-08 00:36:42 -07001627 printk(KERN_DEBUG "cyc:cy_open done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001629 return 0;
1630} /* cy_open */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631
1632/*
1633 * cy_wait_until_sent() --- wait until the transmitter is empty
1634 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001635static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636{
Jiri Slaby875b2062007-05-08 00:36:49 -07001637 struct cyclades_card *card;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001638 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001639 unsigned long orig_jiffies;
1640 int char_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641
Jiri Slaby02f11752006-12-08 02:39:28 -08001642 if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
1643 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644
Jiri Slaby02f11752006-12-08 02:39:28 -08001645 if (info->xmit_fifo_size == 0)
1646 return; /* Just in case.... */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647
Jiri Slaby02f11752006-12-08 02:39:28 -08001648 orig_jiffies = jiffies;
1649 /*
1650 * Set the check interval to be 1/5 of the estimated time to
1651 * send a single character, and make it at least 1. The check
1652 * interval should also be less than the timeout.
1653 *
1654 * Note: we have to use pretty tight timings here to satisfy
1655 * the NIST-PCTS.
1656 */
1657 char_time = (info->timeout - HZ / 50) / info->xmit_fifo_size;
1658 char_time = char_time / 5;
1659 if (char_time <= 0)
1660 char_time = 1;
1661 if (timeout < 0)
1662 timeout = 0;
1663 if (timeout)
1664 char_time = min(char_time, timeout);
1665 /*
1666 * If the transmitter hasn't cleared in twice the approximate
1667 * amount of time to send the entire FIFO, it probably won't
1668 * ever clear. This assumes the UART isn't doing flow
1669 * control, which is currently the case. Hence, if it ever
1670 * takes longer than info->timeout, this is probably due to a
1671 * UART bug of some kind. So, we clamp the timeout parameter at
1672 * 2*info->timeout.
1673 */
1674 if (!timeout || timeout > 2 * info->timeout)
1675 timeout = 2 * info->timeout;
Jiri Slaby8bab5342011-07-14 14:35:15 +02001676
Jiri Slaby02f11752006-12-08 02:39:28 -08001677 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01001678 if (!cy_is_Z(card)) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001679 while (cyy_readb(info, CySRER) & CyTxRdy) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001680 if (msleep_interruptible(jiffies_to_msecs(char_time)))
1681 break;
1682 if (timeout && time_after(jiffies, orig_jiffies +
1683 timeout))
1684 break;
1685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 }
Jiri Slaby02f11752006-12-08 02:39:28 -08001687 /* Run one more char cycle */
1688 msleep_interruptible(jiffies_to_msecs(char_time * 5));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689}
1690
Alan Cox978e5952008-04-30 00:53:59 -07001691static void cy_flush_buffer(struct tty_struct *tty)
1692{
1693 struct cyclades_port *info = tty->driver_data;
1694 struct cyclades_card *card;
1695 int channel, retval;
1696 unsigned long flags;
1697
1698#ifdef CY_DEBUG_IO
1699 printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
1700#endif
1701
1702 if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
1703 return;
1704
1705 card = info->card;
1706 channel = info->line - card->first_line;
1707
1708 spin_lock_irqsave(&card->card_lock, flags);
1709 info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
1710 spin_unlock_irqrestore(&card->card_lock, flags);
1711
Jiri Slaby2693f482009-06-11 12:31:06 +01001712 if (cy_is_Z(card)) { /* If it is a Z card, flush the on-board
Alan Cox978e5952008-04-30 00:53:59 -07001713 buffers as well */
1714 spin_lock_irqsave(&card->card_lock, flags);
1715 retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
1716 if (retval != 0) {
1717 printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
1718 "was %x\n", info->line, retval);
1719 }
1720 spin_unlock_irqrestore(&card->card_lock, flags);
1721 }
1722 tty_wakeup(tty);
1723} /* cy_flush_buffer */
1724
1725
Alan Coxe936ffd2009-09-19 13:13:22 -07001726static void cy_do_close(struct tty_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727{
Alan Coxe936ffd2009-09-19 13:13:22 -07001728 struct cyclades_port *info = container_of(port, struct cyclades_port,
1729 port);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001730 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001731 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001732 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001734 card = info->card;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001735 channel = info->line - card->first_line;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001736 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001737
Jiri Slaby2693f482009-06-11 12:31:06 +01001738 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001739 /* Stop accepting input */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001740 cyy_writeb(info, CyCAR, channel & 0x03);
1741 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyRxData);
Alan Cox77451e52008-07-16 21:57:02 +01001742 if (info->port.flags & ASYNC_INITIALIZED) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07001743 /* Waiting for on-board buffers to be empty before
1744 closing the port */
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001745 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Coxe936ffd2009-09-19 13:13:22 -07001746 cy_wait_until_sent(port->tty, info->timeout);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001747 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001748 }
1749 } else {
1750#ifdef Z_WAKE
Alan Cox15ed6cc2008-04-30 00:53:55 -07001751 /* Waiting for on-board buffers to be empty before closing
1752 the port */
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001753 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001754 int retval;
1755
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001756 if (readl(&ch_ctrl->flow_status) != C_FS_TXIDLE) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001757 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08001758 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07001759 printk(KERN_DEBUG "cyc:cy_close retval on "
1760 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08001761 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001762 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby2c7fea92007-05-08 00:36:51 -07001763 wait_for_completion_interruptible(&info->shutdown_wait);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001764 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001765 }
1766#endif
1767 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001768 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Coxe936ffd2009-09-19 13:13:22 -07001769 cy_shutdown(info, port->tty);
1770}
Jiri Slaby02f11752006-12-08 02:39:28 -08001771
Alan Coxe936ffd2009-09-19 13:13:22 -07001772/*
1773 * This routine is called when a particular tty device is closed.
1774 */
1775static void cy_close(struct tty_struct *tty, struct file *filp)
1776{
1777 struct cyclades_port *info = tty->driver_data;
1778 if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
1779 return;
1780 tty_port_close(&info->port, tty, filp);
Jiri Slaby02f11752006-12-08 02:39:28 -08001781} /* cy_close */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782
1783/* This routine gets called when tty_write has put something into
1784 * the write_queue. The characters may come from user space or
1785 * kernel space.
1786 *
1787 * This routine will return the number of characters actually
1788 * accepted for writing.
1789 *
1790 * If the port is not already transmitting stuff, start it off by
1791 * enabling interrupts. The interrupt service routine will then
1792 * ensure that the characters are sent.
1793 * If the port is already active, there is no need to kick it.
1794 *
1795 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001796static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001798 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001799 unsigned long flags;
1800 int c, ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801
1802#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001803 printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804#endif
1805
Alan Cox15ed6cc2008-04-30 00:53:55 -07001806 if (serial_paranoia_check(info, tty->name, "cy_write"))
Jiri Slaby02f11752006-12-08 02:39:28 -08001807 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808
Alan Cox77451e52008-07-16 21:57:02 +01001809 if (!info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001810 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001812 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08001813 while (1) {
Harvey Harrison1a4e2352008-04-30 00:53:52 -07001814 c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
1815 c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816
Jiri Slaby02f11752006-12-08 02:39:28 -08001817 if (c <= 0)
1818 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819
Alan Cox77451e52008-07-16 21:57:02 +01001820 memcpy(info->port.xmit_buf + info->xmit_head, buf, c);
Jiri Slaby02f11752006-12-08 02:39:28 -08001821 info->xmit_head = (info->xmit_head + c) &
1822 (SERIAL_XMIT_SIZE - 1);
1823 info->xmit_cnt += c;
1824 buf += c;
1825 count -= c;
1826 ret += c;
1827 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001828 spin_unlock_irqrestore(&info->card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829
Jiri Slaby02f11752006-12-08 02:39:28 -08001830 info->idle_stats.xmit_bytes += ret;
1831 info->idle_stats.xmit_idle = jiffies;
1832
Alan Cox15ed6cc2008-04-30 00:53:55 -07001833 if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
Jiri Slaby02f11752006-12-08 02:39:28 -08001834 start_xmit(info);
Alan Cox15ed6cc2008-04-30 00:53:55 -07001835
Jiri Slaby02f11752006-12-08 02:39:28 -08001836 return ret;
1837} /* cy_write */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838
1839/*
1840 * This routine is called by the kernel to write a single
1841 * character to the tty device. If the kernel uses this routine,
1842 * it must call the flush_chars() routine (if defined) when it is
1843 * done stuffing characters into the driver. If there is no room
1844 * in the queue, the character is ignored.
1845 */
Alan Cox76b25a52008-04-30 00:54:03 -07001846static int cy_put_char(struct tty_struct *tty, unsigned char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001848 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001849 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850
1851#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001852 printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853#endif
1854
Jiri Slaby02f11752006-12-08 02:39:28 -08001855 if (serial_paranoia_check(info, tty->name, "cy_put_char"))
Alan Cox76b25a52008-04-30 00:54:03 -07001856 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857
Alan Cox77451e52008-07-16 21:57:02 +01001858 if (!info->port.xmit_buf)
Alan Cox76b25a52008-04-30 00:54:03 -07001859 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001861 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby90cc3012006-12-08 02:39:31 -08001862 if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001863 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001864 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08001865 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866
Alan Cox77451e52008-07-16 21:57:02 +01001867 info->port.xmit_buf[info->xmit_head++] = ch;
Jiri Slaby02f11752006-12-08 02:39:28 -08001868 info->xmit_head &= SERIAL_XMIT_SIZE - 1;
1869 info->xmit_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 info->idle_stats.xmit_bytes++;
1871 info->idle_stats.xmit_idle = jiffies;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07001872 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Cox76b25a52008-04-30 00:54:03 -07001873 return 1;
Jiri Slaby02f11752006-12-08 02:39:28 -08001874} /* cy_put_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875
1876/*
1877 * This routine is called by the kernel after it has written a
Alan Cox15ed6cc2008-04-30 00:53:55 -07001878 * series of characters to the tty device using put_char().
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001880static void cy_flush_chars(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001882 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001883
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001885 printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886#endif
1887
Jiri Slaby02f11752006-12-08 02:39:28 -08001888 if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
1889 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890
Jiri Slaby02f11752006-12-08 02:39:28 -08001891 if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
Alan Cox77451e52008-07-16 21:57:02 +01001892 !info->port.xmit_buf)
Jiri Slaby02f11752006-12-08 02:39:28 -08001893 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894
Jiri Slaby02f11752006-12-08 02:39:28 -08001895 start_xmit(info);
1896} /* cy_flush_chars */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897
1898/*
1899 * This routine returns the numbers of characters the tty driver
1900 * will accept for queuing to be written. This number is subject
1901 * to change as output buffers get emptied, or if the output flow
1902 * control is activated.
1903 */
Jiri Slaby02f11752006-12-08 02:39:28 -08001904static int cy_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001906 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08001907 int ret;
1908
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001910 printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911#endif
1912
Jiri Slaby02f11752006-12-08 02:39:28 -08001913 if (serial_paranoia_check(info, tty->name, "cy_write_room"))
1914 return 0;
1915 ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
1916 if (ret < 0)
1917 ret = 0;
1918 return ret;
1919} /* cy_write_room */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920
Jiri Slaby02f11752006-12-08 02:39:28 -08001921static int cy_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07001923 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924
Jiri Slaby02f11752006-12-08 02:39:28 -08001925 if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
1926 return 0;
1927
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001929 if (!cy_is_Z(info->card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08001930#endif /* Z_EXT_CHARS_IN_BUFFER */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001932 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
1933 info->line, info->xmit_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08001935 return info->xmit_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936#ifdef Z_EXT_CHARS_IN_BUFFER
Jiri Slaby02f11752006-12-08 02:39:28 -08001937 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07001938 struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
Jiri Slaby02f11752006-12-08 02:39:28 -08001939 int char_count;
Jiri Slabyad39c302007-05-08 00:35:49 -07001940 __u32 tx_put, tx_get, tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941
Jiri Slabydb05c3b2007-05-08 00:35:46 -07001942 tx_get = readl(&buf_ctrl->tx_get);
1943 tx_put = readl(&buf_ctrl->tx_put);
1944 tx_bufsize = readl(&buf_ctrl->tx_bufsize);
Jiri Slaby02f11752006-12-08 02:39:28 -08001945 if (tx_put >= tx_get)
1946 char_count = tx_put - tx_get;
1947 else
1948 char_count = tx_put - tx_get + tx_bufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949#ifdef CY_DEBUG_IO
Jiri Slaby21719192007-05-08 00:36:42 -07001950 printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
1951 info->line, info->xmit_cnt + char_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952#endif
Jiri Slaby096dcfc2006-12-08 02:39:30 -08001953 return info->xmit_cnt + char_count;
Jiri Slaby02f11752006-12-08 02:39:28 -08001954 }
1955#endif /* Z_EXT_CHARS_IN_BUFFER */
1956} /* cy_chars_in_buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957
1958/*
1959 * ------------------------------------------------------------
1960 * cy_ioctl() and friends
1961 * ------------------------------------------------------------
1962 */
1963
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001964static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965{
Jiri Slaby02f11752006-12-08 02:39:28 -08001966 int co, co_val, bpr;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07001967 __u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
Jiri Slaby02f11752006-12-08 02:39:28 -08001968 25000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969
Jiri Slaby02f11752006-12-08 02:39:28 -08001970 if (baud == 0) {
1971 info->tbpr = info->tco = info->rbpr = info->rco = 0;
1972 return;
1973 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974
Jiri Slaby02f11752006-12-08 02:39:28 -08001975 /* determine which prescaler to use */
1976 for (co = 4, co_val = 2048; co; co--, co_val >>= 2) {
1977 if (cy_clock / co_val / baud > 63)
1978 break;
1979 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980
Jiri Slaby02f11752006-12-08 02:39:28 -08001981 bpr = (cy_clock / co_val * 2 / baud + 1) / 2;
1982 if (bpr > 255)
1983 bpr = 255;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984
Jiri Slaby02f11752006-12-08 02:39:28 -08001985 info->tbpr = info->rbpr = bpr;
1986 info->tco = info->rco = co;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987}
1988
1989/*
1990 * This routine finds or computes the various line characteristics.
1991 * It used to be called config_setup
1992 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07001993static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994{
Jiri Slaby875b2062007-05-08 00:36:49 -07001995 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08001996 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07001997 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08001998 unsigned cflag, iflag;
Jiri Slaby02f11752006-12-08 02:39:28 -08001999 int baud, baud_rate = 0;
2000 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001
Alan Cox15ed6cc2008-04-30 00:53:55 -07002002 if (info->line == -1)
Jiri Slaby02f11752006-12-08 02:39:28 -08002003 return;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002004
Alan Coxadc8d742012-07-14 15:31:47 +01002005 cflag = tty->termios.c_cflag;
2006 iflag = tty->termios.c_iflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007
Jiri Slaby02f11752006-12-08 02:39:28 -08002008 /*
2009 * Set up the tty->alt_speed kludge
2010 */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002011 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
2012 tty->alt_speed = 57600;
2013 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
2014 tty->alt_speed = 115200;
2015 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
2016 tty->alt_speed = 230400;
2017 if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
2018 tty->alt_speed = 460800;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019
Jiri Slaby02f11752006-12-08 02:39:28 -08002020 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002021 channel = info->line - card->first_line;
Jiri Slaby02f11752006-12-08 02:39:28 -08002022
Jiri Slaby2693f482009-06-11 12:31:06 +01002023 if (!cy_is_Z(card)) {
Jiri Slaby46fb7822009-09-19 13:13:17 -07002024 u32 cflags;
2025
Jiri Slaby02f11752006-12-08 02:39:28 -08002026 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002027 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002028 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002029 ASYNC_SPD_CUST) {
2030 if (info->custom_divisor)
2031 baud_rate = info->baud / info->custom_divisor;
2032 else
2033 baud_rate = info->baud;
2034 } else if (baud > CD1400_MAX_SPEED) {
2035 baud = CD1400_MAX_SPEED;
2036 }
2037 /* find the baud index */
2038 for (i = 0; i < 20; i++) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002039 if (baud == baud_table[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08002040 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002041 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002042 if (i == 20)
Jiri Slaby02f11752006-12-08 02:39:28 -08002043 i = 19; /* CD1400_MAX_SPEED */
Jiri Slaby02f11752006-12-08 02:39:28 -08002044
Alan Cox77451e52008-07-16 21:57:02 +01002045 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002046 ASYNC_SPD_CUST) {
2047 cyy_baud_calc(info, baud_rate);
2048 } else {
2049 if (info->chip_rev >= CD1400_REV_J) {
2050 /* It is a CD1400 rev. J or later */
2051 info->tbpr = baud_bpr_60[i]; /* Tx BPR */
2052 info->tco = baud_co_60[i]; /* Tx CO */
2053 info->rbpr = baud_bpr_60[i]; /* Rx BPR */
2054 info->rco = baud_co_60[i]; /* Rx CO */
2055 } else {
2056 info->tbpr = baud_bpr_25[i]; /* Tx BPR */
2057 info->tco = baud_co_25[i]; /* Tx CO */
2058 info->rbpr = baud_bpr_25[i]; /* Rx BPR */
2059 info->rco = baud_co_25[i]; /* Rx CO */
2060 }
2061 }
2062 if (baud_table[i] == 134) {
2063 /* get it right for 134.5 baud */
2064 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2065 2;
Alan Cox77451e52008-07-16 21:57:02 +01002066 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002067 ASYNC_SPD_CUST) {
2068 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2069 baud_rate) + 2;
2070 } else if (baud_table[i]) {
2071 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2072 baud_table[i]) + 2;
2073 /* this needs to be propagated into the card info */
2074 } else {
2075 info->timeout = 0;
2076 }
2077 /* By tradition (is it a standard?) a baud rate of zero
2078 implies the line should be/has been closed. A bit
2079 later in this routine such a test is performed. */
2080
2081 /* byte size and parity */
2082 info->cor5 = 0;
2083 info->cor4 = 0;
2084 /* receive threshold */
2085 info->cor3 = (info->default_threshold ?
2086 info->default_threshold : baud_cor3[i]);
2087 info->cor2 = CyETC;
2088 switch (cflag & CSIZE) {
2089 case CS5:
2090 info->cor1 = Cy_5_BITS;
2091 break;
2092 case CS6:
2093 info->cor1 = Cy_6_BITS;
2094 break;
2095 case CS7:
2096 info->cor1 = Cy_7_BITS;
2097 break;
2098 case CS8:
2099 info->cor1 = Cy_8_BITS;
2100 break;
2101 }
Alan Cox15ed6cc2008-04-30 00:53:55 -07002102 if (cflag & CSTOPB)
Jiri Slaby02f11752006-12-08 02:39:28 -08002103 info->cor1 |= Cy_2_STOP;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002104
Jiri Slaby02f11752006-12-08 02:39:28 -08002105 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002106 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002107 info->cor1 |= CyPARITY_O;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002108 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002109 info->cor1 |= CyPARITY_E;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002110 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002111 info->cor1 |= CyPARITY_NONE;
Jiri Slaby02f11752006-12-08 02:39:28 -08002112
2113 /* CTS flow control flag */
2114 if (cflag & CRTSCTS) {
Alan Cox77451e52008-07-16 21:57:02 +01002115 info->port.flags |= ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002116 info->cor2 |= CyCtsAE;
2117 } else {
Alan Cox77451e52008-07-16 21:57:02 +01002118 info->port.flags &= ~ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002119 info->cor2 &= ~CyCtsAE;
2120 }
2121 if (cflag & CLOCAL)
Alan Cox77451e52008-07-16 21:57:02 +01002122 info->port.flags &= ~ASYNC_CHECK_CD;
Jiri Slaby02f11752006-12-08 02:39:28 -08002123 else
Alan Cox77451e52008-07-16 21:57:02 +01002124 info->port.flags |= ASYNC_CHECK_CD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125
2126 /***********************************************
2127 The hardware option, CyRtsAO, presents RTS when
2128 the chip has characters to send. Since most modems
2129 use RTS as reverse (inbound) flow control, this
2130 option is not used. If inbound flow control is
2131 necessary, DTR can be programmed to provide the
2132 appropriate signals for use with a non-standard
2133 cable. Contact Marcio Saito for details.
2134 ***********************************************/
2135
Jiri Slaby02f11752006-12-08 02:39:28 -08002136 channel &= 0x03;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002138 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002139 cyy_writeb(info, CyCAR, channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140
Jiri Slaby02f11752006-12-08 02:39:28 -08002141 /* tx and rx baud rate */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002143 cyy_writeb(info, CyTCOR, info->tco);
2144 cyy_writeb(info, CyTBPR, info->tbpr);
2145 cyy_writeb(info, CyRCOR, info->rco);
2146 cyy_writeb(info, CyRBPR, info->rbpr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147
Jiri Slaby02f11752006-12-08 02:39:28 -08002148 /* set line characteristics according configuration */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002150 cyy_writeb(info, CySCHR1, START_CHAR(tty));
2151 cyy_writeb(info, CySCHR2, STOP_CHAR(tty));
2152 cyy_writeb(info, CyCOR1, info->cor1);
2153 cyy_writeb(info, CyCOR2, info->cor2);
2154 cyy_writeb(info, CyCOR3, info->cor3);
2155 cyy_writeb(info, CyCOR4, info->cor4);
2156 cyy_writeb(info, CyCOR5, info->cor5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002158 cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
2159 CyCOR3ch);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160
Alan Cox15ed6cc2008-04-30 00:53:55 -07002161 /* !!! Is this needed? */
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002162 cyy_writeb(info, CyCAR, channel);
2163 cyy_writeb(info, CyRTPR,
Jiri Slaby02f11752006-12-08 02:39:28 -08002164 (info->default_timeout ? info->default_timeout : 0x02));
2165 /* 10ms rx timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166
Jiri Slaby46fb7822009-09-19 13:13:17 -07002167 cflags = CyCTS;
2168 if (!C_CLOCAL(tty))
2169 cflags |= CyDSR | CyRI | CyDCD;
2170 /* without modem intr */
2171 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyMdmCh);
2172 /* act on 1->0 modem transitions */
2173 if ((cflag & CRTSCTS) && info->rflow)
2174 cyy_writeb(info, CyMCOR1, cflags | rflow_thr[i]);
2175 else
2176 cyy_writeb(info, CyMCOR1, cflags);
2177 /* act on 0->1 modem transitions */
2178 cyy_writeb(info, CyMCOR2, cflags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002179
Jiri Slaby4d768202009-09-19 13:13:15 -07002180 if (i == 0) /* baud rate is zero, turn off line */
2181 cyy_change_rts_dtr(info, 0, TIOCM_DTR);
2182 else
2183 cyy_change_rts_dtr(info, TIOCM_DTR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184
Jiri Slabyd13549f2009-09-19 13:13:12 -07002185 clear_bit(TTY_IO_ERROR, &tty->flags);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002186 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07002189 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Klaus Kudielka1a86b5e2007-05-08 00:26:26 -07002190 __u32 sw_flow;
Jiri Slaby02f11752006-12-08 02:39:28 -08002191 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192
Jiri Slaby2693f482009-06-11 12:31:06 +01002193 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002194 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195
Jiri Slaby02f11752006-12-08 02:39:28 -08002196 /* baud rate */
Jiri Slabyd13549f2009-09-19 13:13:12 -07002197 baud = tty_get_baud_rate(tty);
Alan Cox77451e52008-07-16 21:57:02 +01002198 if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002199 ASYNC_SPD_CUST) {
2200 if (info->custom_divisor)
2201 baud_rate = info->baud / info->custom_divisor;
2202 else
2203 baud_rate = info->baud;
2204 } else if (baud > CYZ_MAX_SPEED) {
2205 baud = CYZ_MAX_SPEED;
2206 }
2207 cy_writel(&ch_ctrl->comm_baud, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208
Jiri Slaby02f11752006-12-08 02:39:28 -08002209 if (baud == 134) {
2210 /* get it right for 134.5 baud */
2211 info->timeout = (info->xmit_fifo_size * HZ * 30 / 269) +
2212 2;
Alan Cox77451e52008-07-16 21:57:02 +01002213 } else if (baud == 38400 && (info->port.flags & ASYNC_SPD_MASK) ==
Jiri Slaby02f11752006-12-08 02:39:28 -08002214 ASYNC_SPD_CUST) {
2215 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2216 baud_rate) + 2;
2217 } else if (baud) {
2218 info->timeout = (info->xmit_fifo_size * HZ * 15 /
2219 baud) + 2;
2220 /* this needs to be propagated into the card info */
2221 } else {
2222 info->timeout = 0;
2223 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224
Jiri Slaby02f11752006-12-08 02:39:28 -08002225 /* byte size and parity */
2226 switch (cflag & CSIZE) {
2227 case CS5:
2228 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS5);
2229 break;
2230 case CS6:
2231 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS6);
2232 break;
2233 case CS7:
2234 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS7);
2235 break;
2236 case CS8:
2237 cy_writel(&ch_ctrl->comm_data_l, C_DL_CS8);
2238 break;
2239 }
2240 if (cflag & CSTOPB) {
2241 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002242 readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002243 } else {
2244 cy_writel(&ch_ctrl->comm_data_l,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002245 readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
Jiri Slaby02f11752006-12-08 02:39:28 -08002246 }
2247 if (cflag & PARENB) {
Alan Cox15ed6cc2008-04-30 00:53:55 -07002248 if (cflag & PARODD)
Jiri Slaby02f11752006-12-08 02:39:28 -08002249 cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002250 else
Jiri Slaby02f11752006-12-08 02:39:28 -08002251 cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
Alan Cox15ed6cc2008-04-30 00:53:55 -07002252 } else
Jiri Slaby02f11752006-12-08 02:39:28 -08002253 cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254
Jiri Slaby02f11752006-12-08 02:39:28 -08002255 /* CTS flow control flag */
2256 if (cflag & CRTSCTS) {
2257 cy_writel(&ch_ctrl->hw_flow,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002258 readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
Jiri Slaby02f11752006-12-08 02:39:28 -08002259 } else {
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002260 cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
2261 ~(C_RS_CTS | C_RS_RTS));
Jiri Slaby02f11752006-12-08 02:39:28 -08002262 }
2263 /* As the HW flow control is done in firmware, the driver
2264 doesn't need to care about it */
Alan Cox77451e52008-07-16 21:57:02 +01002265 info->port.flags &= ~ASYNC_CTS_FLOW;
Jiri Slaby02f11752006-12-08 02:39:28 -08002266
2267 /* XON/XOFF/XANY flow control flags */
2268 sw_flow = 0;
2269 if (iflag & IXON) {
2270 sw_flow |= C_FL_OXX;
2271 if (iflag & IXANY)
2272 sw_flow |= C_FL_OIXANY;
2273 }
2274 cy_writel(&ch_ctrl->sw_flow, sw_flow);
2275
Jiri Slaby875b2062007-05-08 00:36:49 -07002276 retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002277 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002278 printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
2279 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002280 }
2281
2282 /* CD sensitivity */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002283 if (cflag & CLOCAL)
Alan Cox77451e52008-07-16 21:57:02 +01002284 info->port.flags &= ~ASYNC_CHECK_CD;
Alan Cox15ed6cc2008-04-30 00:53:55 -07002285 else
Alan Cox77451e52008-07-16 21:57:02 +01002286 info->port.flags |= ASYNC_CHECK_CD;
Jiri Slaby02f11752006-12-08 02:39:28 -08002287
2288 if (baud == 0) { /* baud rate is zero, turn off line */
2289 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002290 readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002292 printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002294 } else {
2295 cy_writel(&ch_ctrl->rs_control,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07002296 readl(&ch_ctrl->rs_control) | C_RS_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297#ifdef CY_DEBUG_DTR
Jiri Slaby21719192007-05-08 00:36:42 -07002298 printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301
Alan Cox15ed6cc2008-04-30 00:53:55 -07002302 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002303 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002304 printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
2305 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002306 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307
Jiri Slabyd13549f2009-09-19 13:13:12 -07002308 clear_bit(TTY_IO_ERROR, &tty->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002310} /* set_line_char */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311
Jiri Slaby6c281812009-09-19 13:13:15 -07002312static int cy_get_serial_info(struct cyclades_port *info,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002313 struct serial_struct __user *retinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314{
Jiri Slaby875b2062007-05-08 00:36:49 -07002315 struct cyclades_card *cinfo = info->card;
Jiri Slaby6c281812009-09-19 13:13:15 -07002316 struct serial_struct tmp = {
2317 .type = info->type,
2318 .line = info->line,
2319 .port = (info->card - cy_card) * 0x100 + info->line -
2320 cinfo->first_line,
2321 .irq = cinfo->irq,
2322 .flags = info->port.flags,
2323 .close_delay = info->port.close_delay,
2324 .closing_wait = info->port.closing_wait,
2325 .baud_base = info->baud,
2326 .custom_divisor = info->custom_divisor,
2327 .hub6 = 0, /*!!! */
2328 };
Jiri Slaby02f11752006-12-08 02:39:28 -08002329 return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
Jiri Slaby6c281812009-09-19 13:13:15 -07002330}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331
2332static int
Jiri Slabyd13549f2009-09-19 13:13:12 -07002333cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty,
Alan Cox15ed6cc2008-04-30 00:53:55 -07002334 struct serial_struct __user *new_info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335{
Jiri Slaby02f11752006-12-08 02:39:28 -08002336 struct serial_struct new_serial;
Alan Cox25c3cdf2010-06-01 22:52:47 +02002337 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338
Jiri Slaby02f11752006-12-08 02:39:28 -08002339 if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
2340 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341
Alan Cox25c3cdf2010-06-01 22:52:47 +02002342 mutex_lock(&info->port.mutex);
Jiri Slaby02f11752006-12-08 02:39:28 -08002343 if (!capable(CAP_SYS_ADMIN)) {
Alan Cox44b7d1b2008-07-16 21:57:18 +01002344 if (new_serial.close_delay != info->port.close_delay ||
Jiri Slaby02f11752006-12-08 02:39:28 -08002345 new_serial.baud_base != info->baud ||
2346 (new_serial.flags & ASYNC_FLAGS &
2347 ~ASYNC_USR_MASK) !=
Alan Cox77451e52008-07-16 21:57:02 +01002348 (info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))
Alan Cox25c3cdf2010-06-01 22:52:47 +02002349 {
2350 mutex_unlock(&info->port.mutex);
Jiri Slaby02f11752006-12-08 02:39:28 -08002351 return -EPERM;
Alan Cox25c3cdf2010-06-01 22:52:47 +02002352 }
Alan Cox77451e52008-07-16 21:57:02 +01002353 info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002354 (new_serial.flags & ASYNC_USR_MASK);
2355 info->baud = new_serial.baud_base;
2356 info->custom_divisor = new_serial.custom_divisor;
2357 goto check_and_exit;
2358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359
Jiri Slaby02f11752006-12-08 02:39:28 -08002360 /*
2361 * OK, past this point, all the error checking has been done.
2362 * At this point, we start making changes.....
2363 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364
Jiri Slaby02f11752006-12-08 02:39:28 -08002365 info->baud = new_serial.baud_base;
2366 info->custom_divisor = new_serial.custom_divisor;
Alan Cox77451e52008-07-16 21:57:02 +01002367 info->port.flags = (info->port.flags & ~ASYNC_FLAGS) |
Jiri Slaby02f11752006-12-08 02:39:28 -08002368 (new_serial.flags & ASYNC_FLAGS);
Alan Cox44b7d1b2008-07-16 21:57:18 +01002369 info->port.close_delay = new_serial.close_delay * HZ / 100;
2370 info->port.closing_wait = new_serial.closing_wait * HZ / 100;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
2372check_and_exit:
Alan Cox77451e52008-07-16 21:57:02 +01002373 if (info->port.flags & ASYNC_INITIALIZED) {
Jiri Slabyd13549f2009-09-19 13:13:12 -07002374 cy_set_line_char(info, tty);
Alan Cox25c3cdf2010-06-01 22:52:47 +02002375 ret = 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002376 } else {
Alan Cox25c3cdf2010-06-01 22:52:47 +02002377 ret = cy_startup(info, tty);
Jiri Slaby02f11752006-12-08 02:39:28 -08002378 }
Alan Cox25c3cdf2010-06-01 22:52:47 +02002379 mutex_unlock(&info->port.mutex);
2380 return ret;
Jiri Slaby02f11752006-12-08 02:39:28 -08002381} /* set_serial_info */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382
2383/*
2384 * get_lsr_info - get line status register info
2385 *
2386 * Purpose: Let user call ioctl() to get info when the UART physically
2387 * is emptied. On bus types like RS485, the transmitter must
2388 * release the bus after transmitting. This must be done when
2389 * the transmit shift register is empty, not be done when the
2390 * transmit holding register is empty. This functionality
2391 * allows an RS485 driver to be written in user space.
2392 */
Alan Cox15ed6cc2008-04-30 00:53:55 -07002393static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002395 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002396 unsigned int result;
2397 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002398 u8 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399
Jiri Slaby2693f482009-06-11 12:31:06 +01002400 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002401 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002402 status = cyy_readb(info, CySRER) & (CyTxRdy | CyTxMpty);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002403 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002404 result = (status ? 0 : TIOCSER_TEMT);
2405 } else {
2406 /* Not supported yet */
2407 return -EINVAL;
2408 }
Dan Carpenterdbca36e2012-03-05 21:07:11 +03002409 return put_user(result, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410}
2411
Alan Cox60b33c12011-02-14 16:26:14 +00002412static int cy_tiocmget(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002414 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002415 struct cyclades_card *card;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002416 int result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002418 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002419 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420
Jiri Slaby02f11752006-12-08 02:39:28 -08002421 card = info->card;
Jiri Slaby0d348722009-09-19 13:13:16 -07002422
Jiri Slaby2693f482009-06-11 12:31:06 +01002423 if (!cy_is_Z(card)) {
Jiri Slaby0d348722009-09-19 13:13:16 -07002424 unsigned long flags;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002425 int channel = info->line - card->first_line;
2426 u8 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002428 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002429 cyy_writeb(info, CyCAR, channel & 0x03);
2430 status = cyy_readb(info, CyMSVR1);
2431 status |= cyy_readb(info, CyMSVR2);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002432 spin_unlock_irqrestore(&card->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
Jiri Slaby02f11752006-12-08 02:39:28 -08002434 if (info->rtsdtr_inv) {
2435 result = ((status & CyRTS) ? TIOCM_DTR : 0) |
2436 ((status & CyDTR) ? TIOCM_RTS : 0);
2437 } else {
2438 result = ((status & CyRTS) ? TIOCM_RTS : 0) |
2439 ((status & CyDTR) ? TIOCM_DTR : 0);
2440 }
2441 result |= ((status & CyDCD) ? TIOCM_CAR : 0) |
2442 ((status & CyRI) ? TIOCM_RNG : 0) |
2443 ((status & CyDSR) ? TIOCM_DSR : 0) |
2444 ((status & CyCTS) ? TIOCM_CTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 } else {
Jiri Slaby0d348722009-09-19 13:13:16 -07002446 u32 lstatus;
2447
2448 if (!cyz_is_loaded(card)) {
2449 result = -ENODEV;
2450 goto end;
Jiri Slaby02f11752006-12-08 02:39:28 -08002451 }
2452
Jiri Slaby0d348722009-09-19 13:13:16 -07002453 lstatus = readl(&info->u.cyz.ch_ctrl->rs_status);
2454 result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
2455 ((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
2456 ((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
2457 ((lstatus & C_RS_RI) ? TIOCM_RNG : 0) |
2458 ((lstatus & C_RS_DSR) ? TIOCM_DSR : 0) |
2459 ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 }
Jiri Slaby0d348722009-09-19 13:13:16 -07002461end:
Jiri Slaby02f11752006-12-08 02:39:28 -08002462 return result;
2463} /* cy_tiomget */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464
2465static int
Alan Cox20b9d172011-02-14 16:26:50 +00002466cy_tiocmset(struct tty_struct *tty,
Jiri Slaby02f11752006-12-08 02:39:28 -08002467 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002469 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002470 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002471 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472
Harvey Harrisonbf9d8922008-04-30 00:55:10 -07002473 if (serial_paranoia_check(info, tty->name, __func__))
Jiri Slaby02f11752006-12-08 02:39:28 -08002474 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475
Jiri Slaby02f11752006-12-08 02:39:28 -08002476 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01002477 if (!cy_is_Z(card)) {
Jiri Slaby4d768202009-09-19 13:13:15 -07002478 spin_lock_irqsave(&card->card_lock, flags);
2479 cyy_change_rts_dtr(info, set, clear);
2480 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002481 } else {
Jiri Slaby0d348722009-09-19 13:13:16 -07002482 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
2483 int retval, channel = info->line - card->first_line;
2484 u32 rs;
Jiri Slaby02f11752006-12-08 02:39:28 -08002485
Jiri Slaby0d348722009-09-19 13:13:16 -07002486 if (!cyz_is_loaded(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002487 return -ENODEV;
Jiri Slaby0d348722009-09-19 13:13:16 -07002488
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002489 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby0d348722009-09-19 13:13:16 -07002490 rs = readl(&ch_ctrl->rs_control);
2491 if (set & TIOCM_RTS)
2492 rs |= C_RS_RTS;
2493 if (clear & TIOCM_RTS)
2494 rs &= ~C_RS_RTS;
2495 if (set & TIOCM_DTR) {
2496 rs |= C_RS_DTR;
2497#ifdef CY_DEBUG_DTR
2498 printk(KERN_DEBUG "cyc:set_modem_info raising Z DTR\n");
2499#endif
2500 }
2501 if (clear & TIOCM_DTR) {
2502 rs &= ~C_RS_DTR;
2503#ifdef CY_DEBUG_DTR
2504 printk(KERN_DEBUG "cyc:set_modem_info clearing "
2505 "Z DTR\n");
2506#endif
2507 }
2508 cy_writel(&ch_ctrl->rs_control, rs);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002509 retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
Jiri Slaby0d348722009-09-19 13:13:16 -07002510 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002511 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002512 printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
2513 "was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002514 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002516 return 0;
Jiri Slaby0d348722009-09-19 13:13:16 -07002517}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518
2519/*
2520 * cy_break() --- routine which turns the break handling on or off
2521 */
Alan Cox9e989662008-07-22 11:18:03 +01002522static int cy_break(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002524 struct cyclades_port *info = tty->driver_data;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002525 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002526 unsigned long flags;
Alan Cox9e989662008-07-22 11:18:03 +01002527 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528
Jiri Slaby02f11752006-12-08 02:39:28 -08002529 if (serial_paranoia_check(info, tty->name, "cy_break"))
Alan Cox9e989662008-07-22 11:18:03 +01002530 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002532 card = info->card;
2533
2534 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby2693f482009-06-11 12:31:06 +01002535 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002536 /* Let the transmit ISR take care of this (since it
2537 requires stuffing characters into the output stream).
2538 */
2539 if (break_state == -1) {
2540 if (!info->breakon) {
2541 info->breakon = 1;
2542 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002543 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002544 start_xmit(info);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002545 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002546 }
2547 }
2548 } else {
2549 if (!info->breakoff) {
2550 info->breakoff = 1;
2551 if (!info->xmit_cnt) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002552 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002553 start_xmit(info);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002554 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002555 }
2556 }
2557 }
2558 } else {
Jiri Slaby02f11752006-12-08 02:39:28 -08002559 if (break_state == -1) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002560 retval = cyz_issue_cmd(card,
2561 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002562 C_CM_SET_BREAK, 0L);
2563 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002564 printk(KERN_ERR "cyc:cy_break (set) retval on "
2565 "ttyC%d was %x\n", info->line, retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002566 }
2567 } else {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002568 retval = cyz_issue_cmd(card,
2569 info->line - card->first_line,
Jiri Slaby02f11752006-12-08 02:39:28 -08002570 C_CM_CLR_BREAK, 0L);
2571 if (retval != 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07002572 printk(KERN_DEBUG "cyc:cy_break (clr) retval "
2573 "on ttyC%d was %x\n", info->line,
2574 retval);
Jiri Slaby02f11752006-12-08 02:39:28 -08002575 }
2576 }
2577 }
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002578 spin_unlock_irqrestore(&card->card_lock, flags);
Alan Cox9e989662008-07-22 11:18:03 +01002579 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08002580} /* cy_break */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581
Jiri Slaby02f11752006-12-08 02:39:28 -08002582static int set_threshold(struct cyclades_port *info, unsigned long value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002584 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002585 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586
Jiri Slaby2693f482009-06-11 12:31:06 +01002587 if (!cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002588 info->cor3 &= ~CyREC_FIFO;
2589 info->cor3 |= value & CyREC_FIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002591 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002592 cyy_writeb(info, CyCOR3, info->cor3);
2593 cyy_issue_cmd(info, CyCOR_CHANGE | CyCOR3ch);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002594 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002595 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002597} /* set_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598
Alan Cox15ed6cc2008-04-30 00:53:55 -07002599static int get_threshold(struct cyclades_port *info,
2600 unsigned long __user *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002602 struct cyclades_card *card = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603
Jiri Slaby2693f482009-06-11 12:31:06 +01002604 if (!cy_is_Z(card)) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002605 u8 tmp = cyy_readb(info, CyCOR3) & CyREC_FIFO;
Jiri Slaby02f11752006-12-08 02:39:28 -08002606 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002607 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002608 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002609} /* get_threshold */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610
Jiri Slaby02f11752006-12-08 02:39:28 -08002611static int set_timeout(struct cyclades_port *info, unsigned long value)
2612{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002613 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002614 unsigned long flags;
2615
Jiri Slaby2693f482009-06-11 12:31:06 +01002616 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002617 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002618 cyy_writeb(info, CyRTPR, value & 0xff);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002619 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002620 }
2621 return 0;
2622} /* set_timeout */
2623
Alan Cox15ed6cc2008-04-30 00:53:55 -07002624static int get_timeout(struct cyclades_port *info,
2625 unsigned long __user *value)
Jiri Slaby02f11752006-12-08 02:39:28 -08002626{
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002627 struct cyclades_card *card = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002628
Jiri Slaby2693f482009-06-11 12:31:06 +01002629 if (!cy_is_Z(card)) {
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002630 u8 tmp = cyy_readb(info, CyRTPR);
Jiri Slaby02f11752006-12-08 02:39:28 -08002631 return put_user(tmp, value);
Jiri Slaby02f11752006-12-08 02:39:28 -08002632 }
Jiri Slabyf7429032007-05-08 00:36:59 -07002633 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08002634} /* get_timeout */
2635
Jiri Slaby6c281812009-09-19 13:13:15 -07002636static int cy_cflags_changed(struct cyclades_port *info, unsigned long arg,
2637 struct cyclades_icount *cprev)
Jiri Slaby02f11752006-12-08 02:39:28 -08002638{
Jiri Slaby6c281812009-09-19 13:13:15 -07002639 struct cyclades_icount cnow;
2640 unsigned long flags;
2641 int ret;
Jiri Slaby02f11752006-12-08 02:39:28 -08002642
Jiri Slaby6c281812009-09-19 13:13:15 -07002643 spin_lock_irqsave(&info->card->card_lock, flags);
2644 cnow = info->icount; /* atomic copy */
2645 spin_unlock_irqrestore(&info->card->card_lock, flags);
2646
2647 ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
2648 ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
2649 ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) ||
2650 ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
2651
2652 *cprev = cnow;
2653
2654 return ret;
2655}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656
2657/*
2658 * This routine allows the tty driver to implement device-
2659 * specific ioctl's. If the ioctl number passed in cmd is
2660 * not recognized by the driver, it should return ENOIOCTLCMD.
2661 */
2662static int
Alan Cox6caa76b2011-02-14 16:27:22 +00002663cy_ioctl(struct tty_struct *tty,
Jiri Slaby02f11752006-12-08 02:39:28 -08002664 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002666 struct cyclades_port *info = tty->driver_data;
Jiri Slaby6c281812009-09-19 13:13:15 -07002667 struct cyclades_icount cnow; /* kernel counter temps */
Jiri Slaby02f11752006-12-08 02:39:28 -08002668 int ret_val = 0;
2669 unsigned long flags;
2670 void __user *argp = (void __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671
Jiri Slaby02f11752006-12-08 02:39:28 -08002672 if (serial_paranoia_check(info, tty->name, "cy_ioctl"))
2673 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674
2675#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002676 printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
2677 info->line, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678#endif
2679
Jiri Slaby02f11752006-12-08 02:39:28 -08002680 switch (cmd) {
2681 case CYGETMON:
Jiri Slaby6c281812009-09-19 13:13:15 -07002682 if (copy_to_user(argp, &info->mon, sizeof(info->mon))) {
2683 ret_val = -EFAULT;
2684 break;
2685 }
2686 memset(&info->mon, 0, sizeof(info->mon));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002688 case CYGETTHRESH:
2689 ret_val = get_threshold(info, argp);
2690 break;
2691 case CYSETTHRESH:
2692 ret_val = set_threshold(info, arg);
2693 break;
2694 case CYGETDEFTHRESH:
Jiri Slaby6c281812009-09-19 13:13:15 -07002695 ret_val = put_user(info->default_threshold,
2696 (unsigned long __user *)argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002697 break;
2698 case CYSETDEFTHRESH:
Jiri Slaby6c281812009-09-19 13:13:15 -07002699 info->default_threshold = arg & 0x0f;
Jiri Slaby02f11752006-12-08 02:39:28 -08002700 break;
2701 case CYGETTIMEOUT:
2702 ret_val = get_timeout(info, argp);
2703 break;
2704 case CYSETTIMEOUT:
2705 ret_val = set_timeout(info, arg);
2706 break;
2707 case CYGETDEFTIMEOUT:
Jiri Slaby6c281812009-09-19 13:13:15 -07002708 ret_val = put_user(info->default_timeout,
2709 (unsigned long __user *)argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002710 break;
2711 case CYSETDEFTIMEOUT:
Jiri Slaby6c281812009-09-19 13:13:15 -07002712 info->default_timeout = arg & 0xff;
Jiri Slaby02f11752006-12-08 02:39:28 -08002713 break;
2714 case CYSETRFLOW:
2715 info->rflow = (int)arg;
Jiri Slaby02f11752006-12-08 02:39:28 -08002716 break;
2717 case CYGETRFLOW:
2718 ret_val = info->rflow;
2719 break;
2720 case CYSETRTSDTR_INV:
2721 info->rtsdtr_inv = (int)arg;
Jiri Slaby02f11752006-12-08 02:39:28 -08002722 break;
2723 case CYGETRTSDTR_INV:
2724 ret_val = info->rtsdtr_inv;
2725 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 case CYGETCD1400VER:
Jiri Slaby02f11752006-12-08 02:39:28 -08002727 ret_val = info->chip_rev;
2728 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729#ifndef CONFIG_CYZ_INTR
2730 case CYZSETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08002731 cyz_polling_cycle = (arg * HZ) / 1000;
Jiri Slaby02f11752006-12-08 02:39:28 -08002732 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 case CYZGETPOLLCYCLE:
Jiri Slaby02f11752006-12-08 02:39:28 -08002734 ret_val = (cyz_polling_cycle * 1000) / HZ;
2735 break;
2736#endif /* CONFIG_CYZ_INTR */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 case CYSETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002738 info->port.closing_wait = (unsigned short)arg * HZ / 100;
Jiri Slaby02f11752006-12-08 02:39:28 -08002739 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 case CYGETWAIT:
Alan Cox44b7d1b2008-07-16 21:57:18 +01002741 ret_val = info->port.closing_wait / (HZ / 100);
Jiri Slaby02f11752006-12-08 02:39:28 -08002742 break;
2743 case TIOCGSERIAL:
Jiri Slaby6c281812009-09-19 13:13:15 -07002744 ret_val = cy_get_serial_info(info, argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002745 break;
2746 case TIOCSSERIAL:
Jiri Slabyd13549f2009-09-19 13:13:12 -07002747 ret_val = cy_set_serial_info(info, tty, argp);
Jiri Slaby02f11752006-12-08 02:39:28 -08002748 break;
2749 case TIOCSERGETLSR: /* Get line status register */
2750 ret_val = get_lsr_info(info, argp);
2751 break;
2752 /*
2753 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
2754 * - mask passed in arg for lines of interest
2755 * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
2756 * Caller should use TIOCGICOUNT to see which one it was
2757 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 case TIOCMIWAIT:
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002759 spin_lock_irqsave(&info->card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002760 /* note the counters on entry */
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002761 cnow = info->icount;
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002762 spin_unlock_irqrestore(&info->card->card_lock, flags);
Alan Coxbdc04e32009-09-19 13:13:31 -07002763 ret_val = wait_event_interruptible(info->port.delta_msr_wait,
Jiri Slaby6c281812009-09-19 13:13:15 -07002764 cy_cflags_changed(info, arg, &cnow));
Jiri Slaby2c7fea92007-05-08 00:36:51 -07002765 break;
Jiri Slaby02f11752006-12-08 02:39:28 -08002766
2767 /*
2768 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
2769 * Return: write counters to the user passed counter struct
2770 * NB: both 1->0 and 0->1 transitions are counted except for
2771 * RI where only 0->1 is counted.
2772 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002773 default:
2774 ret_val = -ENOIOCTLCMD;
2775 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776
2777#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002778 printk(KERN_DEBUG "cyc:cy_ioctl done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002780 return ret_val;
2781} /* cy_ioctl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782
Alan Cox05871022010-09-16 18:21:52 +01002783static int cy_get_icount(struct tty_struct *tty,
2784 struct serial_icounter_struct *sic)
2785{
2786 struct cyclades_port *info = tty->driver_data;
2787 struct cyclades_icount cnow; /* Used to snapshot */
2788 unsigned long flags;
2789
2790 spin_lock_irqsave(&info->card->card_lock, flags);
2791 cnow = info->icount;
2792 spin_unlock_irqrestore(&info->card->card_lock, flags);
2793
2794 sic->cts = cnow.cts;
2795 sic->dsr = cnow.dsr;
2796 sic->rng = cnow.rng;
2797 sic->dcd = cnow.dcd;
2798 sic->rx = cnow.rx;
2799 sic->tx = cnow.tx;
2800 sic->frame = cnow.frame;
2801 sic->overrun = cnow.overrun;
2802 sic->parity = cnow.parity;
2803 sic->brk = cnow.brk;
2804 sic->buf_overrun = cnow.buf_overrun;
2805 return 0;
2806}
2807
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808/*
2809 * This routine allows the tty driver to be notified when
2810 * device's termios settings have changed. Note that a
2811 * well-designed tty driver should be prepared to accept the case
2812 * where old == NULL, and try to do something rational.
2813 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002814static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002816 struct cyclades_port *info = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817
2818#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002819 printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820#endif
2821
Jiri Slabyd13549f2009-09-19 13:13:12 -07002822 cy_set_line_char(info, tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823
Jiri Slaby02f11752006-12-08 02:39:28 -08002824 if ((old_termios->c_cflag & CRTSCTS) &&
Alan Coxadc8d742012-07-14 15:31:47 +01002825 !(tty->termios.c_cflag & CRTSCTS)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002826 tty->hw_stopped = 0;
2827 cy_start(tty);
2828 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829#if 0
Jiri Slaby02f11752006-12-08 02:39:28 -08002830 /*
2831 * No need to wake up processes in open wait, since they
2832 * sample the CLOCAL flag once, and don't recheck it.
2833 * XXX It's not clear whether the current behavior is correct
2834 * or not. Hence, this may change.....
2835 */
2836 if (!(old_termios->c_cflag & CLOCAL) &&
Alan Coxadc8d742012-07-14 15:31:47 +01002837 (tty->termios.c_cflag & CLOCAL))
Alan Cox77451e52008-07-16 21:57:02 +01002838 wake_up_interruptible(&info->port.open_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839#endif
Jiri Slaby02f11752006-12-08 02:39:28 -08002840} /* cy_set_termios */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841
2842/* This function is used to send a high-priority XON/XOFF character to
2843 the device.
2844*/
Jiri Slaby02f11752006-12-08 02:39:28 -08002845static void cy_send_xchar(struct tty_struct *tty, char ch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002847 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002848 struct cyclades_card *card;
2849 int channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850
Jiri Slaby02f11752006-12-08 02:39:28 -08002851 if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 return;
2853
Jiri Slaby02f11752006-12-08 02:39:28 -08002854 info->x_char = ch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855
2856 if (ch)
Jiri Slaby02f11752006-12-08 02:39:28 -08002857 cy_start(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858
2859 card = info->card;
Jiri Slaby875b2062007-05-08 00:36:49 -07002860 channel = info->line - card->first_line;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861
Jiri Slaby2693f482009-06-11 12:31:06 +01002862 if (cy_is_Z(card)) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002863 if (ch == STOP_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07002864 cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08002865 else if (ch == START_CHAR(tty))
Jiri Slaby875b2062007-05-08 00:36:49 -07002866 cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 }
2868}
2869
2870/* This routine is called by the upper-layer tty layer to signal
2871 that incoming characters should be throttled because the input
2872 buffers are close to full.
2873 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002874static void cy_throttle(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
Jiri Slaby02f11752006-12-08 02:39:28 -08002881 char buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882
Jiri Slaby21719192007-05-08 00:36:42 -07002883 printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf),
Jiri Slaby02f11752006-12-08 02:39:28 -08002884 tty->ldisc.chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885#endif
2886
Alan Cox15ed6cc2008-04-30 00:53:55 -07002887 if (serial_paranoia_check(info, tty->name, "cy_throttle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08002888 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889
Jiri Slaby02f11752006-12-08 02:39:28 -08002890 card = info->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891
Jiri Slaby02f11752006-12-08 02:39:28 -08002892 if (I_IXOFF(tty)) {
Jiri Slaby2693f482009-06-11 12:31:06 +01002893 if (!cy_is_Z(card))
Jiri Slaby02f11752006-12-08 02:39:28 -08002894 cy_send_xchar(tty, STOP_CHAR(tty));
2895 else
2896 info->throttle = 1;
2897 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898
Alan Coxadc8d742012-07-14 15:31:47 +01002899 if (tty->termios.c_cflag & CRTSCTS) {
Jiri Slaby2693f482009-06-11 12:31:06 +01002900 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002901 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07002902 cyy_change_rts_dtr(info, 0, TIOCM_RTS);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002903 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002904 } else {
2905 info->throttle = 1;
2906 }
2907 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002908} /* cy_throttle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909
2910/*
2911 * This routine notifies the tty driver that it should signal
2912 * that characters can now be sent to the tty without fear of
2913 * overrunning the input buffers of the line disciplines.
2914 */
Jiri Slaby02f11752006-12-08 02:39:28 -08002915static void cy_unthrottle(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002917 struct cyclades_port *info = tty->driver_data;
Jiri Slaby875b2062007-05-08 00:36:49 -07002918 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002919 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920
2921#ifdef CY_DEBUG_THROTTLE
Jiri Slaby02f11752006-12-08 02:39:28 -08002922 char buf[64];
2923
Jiri Slaby21719192007-05-08 00:36:42 -07002924 printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
Alan Cox15ed6cc2008-04-30 00:53:55 -07002925 tty_name(tty, buf), tty_chars_in_buffer(tty), info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926#endif
2927
Alan Cox15ed6cc2008-04-30 00:53:55 -07002928 if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
Jiri Slaby02f11752006-12-08 02:39:28 -08002929 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930
Jiri Slaby02f11752006-12-08 02:39:28 -08002931 if (I_IXOFF(tty)) {
2932 if (info->x_char)
2933 info->x_char = 0;
2934 else
2935 cy_send_xchar(tty, START_CHAR(tty));
2936 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937
Alan Coxadc8d742012-07-14 15:31:47 +01002938 if (tty->termios.c_cflag & CRTSCTS) {
Jiri Slaby02f11752006-12-08 02:39:28 -08002939 card = info->card;
Jiri Slaby2693f482009-06-11 12:31:06 +01002940 if (!cy_is_Z(card)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002941 spin_lock_irqsave(&card->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07002942 cyy_change_rts_dtr(info, TIOCM_RTS, 0);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002943 spin_unlock_irqrestore(&card->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002944 } else {
2945 info->throttle = 0;
2946 }
2947 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002948} /* cy_unthrottle */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949
2950/* cy_start and cy_stop provide software output flow control as a
2951 function of XON/XOFF, software CTS, and other such stuff.
2952*/
Jiri Slaby02f11752006-12-08 02:39:28 -08002953static void cy_stop(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954{
Jiri Slaby02f11752006-12-08 02:39:28 -08002955 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002956 struct cyclades_port *info = tty->driver_data;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002957 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08002958 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959
2960#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002961 printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962#endif
2963
Jiri Slaby02f11752006-12-08 02:39:28 -08002964 if (serial_paranoia_check(info, tty->name, "cy_stop"))
2965 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966
Jiri Slaby875b2062007-05-08 00:36:49 -07002967 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002968 channel = info->line - cinfo->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002969 if (!cy_is_Z(cinfo)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002970 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002971 cyy_writeb(info, CyCAR, channel & 0x03);
2972 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) & ~CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002973 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002975} /* cy_stop */
2976
2977static void cy_start(struct tty_struct *tty)
2978{
2979 struct cyclades_card *cinfo;
Jiri Slabycab9bdd2007-05-08 00:35:51 -07002980 struct cyclades_port *info = tty->driver_data;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002981 int channel;
Jiri Slaby02f11752006-12-08 02:39:28 -08002982 unsigned long flags;
2983
2984#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07002985 printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
Jiri Slaby02f11752006-12-08 02:39:28 -08002986#endif
2987
2988 if (serial_paranoia_check(info, tty->name, "cy_start"))
2989 return;
2990
Jiri Slaby875b2062007-05-08 00:36:49 -07002991 cinfo = info->card;
Jiri Slaby02f11752006-12-08 02:39:28 -08002992 channel = info->line - cinfo->first_line;
Jiri Slaby2693f482009-06-11 12:31:06 +01002993 if (!cy_is_Z(cinfo)) {
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002994 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07002995 cyy_writeb(info, CyCAR, channel & 0x03);
2996 cyy_writeb(info, CySRER, cyy_readb(info, CySRER) | CyTxRdy);
Jiri Slaby9fa1b3b182007-05-08 00:36:57 -07002997 spin_unlock_irqrestore(&cinfo->card_lock, flags);
Jiri Slaby02f11752006-12-08 02:39:28 -08002998 }
Jiri Slaby02f11752006-12-08 02:39:28 -08002999} /* cy_start */
3000
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001/*
3002 * cy_hangup() --- called by tty_hangup() when a hangup is signaled.
3003 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003004static void cy_hangup(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005{
Jiri Slabycab9bdd2007-05-08 00:35:51 -07003006 struct cyclades_port *info = tty->driver_data;
Jiri Slaby02f11752006-12-08 02:39:28 -08003007
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008#ifdef CY_DEBUG_OTHER
Jiri Slaby21719192007-05-08 00:36:42 -07003009 printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010#endif
3011
Jiri Slaby02f11752006-12-08 02:39:28 -08003012 if (serial_paranoia_check(info, tty->name, "cy_hangup"))
3013 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014
Jiri Slaby02f11752006-12-08 02:39:28 -08003015 cy_flush_buffer(tty);
Jiri Slabyd13549f2009-09-19 13:13:12 -07003016 cy_shutdown(info, tty);
Jiri Slaby174e6fe2009-09-19 13:13:13 -07003017 tty_port_hangup(&info->port);
Jiri Slaby02f11752006-12-08 02:39:28 -08003018} /* cy_hangup */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019
Jiri Slabyf0737572009-09-19 13:13:12 -07003020static int cyy_carrier_raised(struct tty_port *port)
3021{
3022 struct cyclades_port *info = container_of(port, struct cyclades_port,
3023 port);
3024 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0737572009-09-19 13:13:12 -07003025 unsigned long flags;
3026 int channel = info->line - cinfo->first_line;
Jiri Slabyf0737572009-09-19 13:13:12 -07003027 u32 cd;
3028
Jiri Slabyf0737572009-09-19 13:13:12 -07003029 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07003030 cyy_writeb(info, CyCAR, channel & 0x03);
3031 cd = cyy_readb(info, CyMSVR1) & CyDCD;
Jiri Slabyf0737572009-09-19 13:13:12 -07003032 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3033
3034 return cd;
3035}
3036
3037static void cyy_dtr_rts(struct tty_port *port, int raise)
3038{
3039 struct cyclades_port *info = container_of(port, struct cyclades_port,
3040 port);
3041 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0737572009-09-19 13:13:12 -07003042 unsigned long flags;
Jiri Slabyf0737572009-09-19 13:13:12 -07003043
3044 spin_lock_irqsave(&cinfo->card_lock, flags);
Jiri Slaby4d768202009-09-19 13:13:15 -07003045 cyy_change_rts_dtr(info, raise ? TIOCM_RTS | TIOCM_DTR : 0,
3046 raise ? 0 : TIOCM_RTS | TIOCM_DTR);
Jiri Slabyf0737572009-09-19 13:13:12 -07003047 spin_unlock_irqrestore(&cinfo->card_lock, flags);
3048}
3049
3050static int cyz_carrier_raised(struct tty_port *port)
3051{
3052 struct cyclades_port *info = container_of(port, struct cyclades_port,
3053 port);
Jiri Slabyf0737572009-09-19 13:13:12 -07003054
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003055 return readl(&info->u.cyz.ch_ctrl->rs_status) & C_RS_DCD;
Jiri Slabyf0737572009-09-19 13:13:12 -07003056}
3057
3058static void cyz_dtr_rts(struct tty_port *port, int raise)
3059{
3060 struct cyclades_port *info = container_of(port, struct cyclades_port,
3061 port);
3062 struct cyclades_card *cinfo = info->card;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003063 struct CH_CTRL __iomem *ch_ctrl = info->u.cyz.ch_ctrl;
Jiri Slabyf0737572009-09-19 13:13:12 -07003064 int ret, channel = info->line - cinfo->first_line;
3065 u32 rs;
3066
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003067 rs = readl(&ch_ctrl->rs_control);
Jiri Slabyf0737572009-09-19 13:13:12 -07003068 if (raise)
3069 rs |= C_RS_RTS | C_RS_DTR;
3070 else
3071 rs &= ~(C_RS_RTS | C_RS_DTR);
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003072 cy_writel(&ch_ctrl->rs_control, rs);
Jiri Slabyf0737572009-09-19 13:13:12 -07003073 ret = cyz_issue_cmd(cinfo, channel, C_CM_IOCTLM, 0L);
3074 if (ret != 0)
3075 printk(KERN_ERR "%s: retval on ttyC%d was %x\n",
3076 __func__, info->line, ret);
3077#ifdef CY_DEBUG_DTR
3078 printk(KERN_DEBUG "%s: raising Z DTR\n", __func__);
3079#endif
3080}
3081
3082static const struct tty_port_operations cyy_port_ops = {
3083 .carrier_raised = cyy_carrier_raised,
3084 .dtr_rts = cyy_dtr_rts,
Alan Coxe936ffd2009-09-19 13:13:22 -07003085 .shutdown = cy_do_close,
Jiri Slabyf0737572009-09-19 13:13:12 -07003086};
3087
3088static const struct tty_port_operations cyz_port_ops = {
3089 .carrier_raised = cyz_carrier_raised,
3090 .dtr_rts = cyz_dtr_rts,
Alan Coxe936ffd2009-09-19 13:13:22 -07003091 .shutdown = cy_do_close,
Jiri Slabyf0737572009-09-19 13:13:12 -07003092};
3093
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094/*
3095 * ---------------------------------------------------------------------
3096 * cy_init() and friends
3097 *
3098 * cy_init() is called at boot-time to initialize the serial driver.
3099 * ---------------------------------------------------------------------
3100 */
3101
Jiri Slabydd025c02007-05-08 00:37:02 -07003102static int __devinit cy_init_card(struct cyclades_card *cinfo)
Jiri Slaby0809e262007-05-08 00:36:14 -07003103{
3104 struct cyclades_port *info;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003105 unsigned int channel, port;
Jiri Slaby0809e262007-05-08 00:36:14 -07003106
Jiri Slaby3046d502007-05-08 00:36:46 -07003107 spin_lock_init(&cinfo->card_lock);
Jiri Slaby963118e2009-06-11 12:34:27 +01003108 cinfo->intr_enabled = 0;
Jiri Slaby3046d502007-05-08 00:36:46 -07003109
Jiri Slaby963118e2009-06-11 12:34:27 +01003110 cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
3111 GFP_KERNEL);
Jiri Slabydd025c02007-05-08 00:37:02 -07003112 if (cinfo->ports == NULL) {
3113 printk(KERN_ERR "Cyclades: cannot allocate ports\n");
3114 return -ENOMEM;
3115 }
3116
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003117 for (channel = 0, port = cinfo->first_line; channel < cinfo->nports;
3118 channel++, port++) {
3119 info = &cinfo->ports[channel];
Alan Cox44b7d1b2008-07-16 21:57:18 +01003120 tty_port_init(&info->port);
Jiri Slaby3046d502007-05-08 00:36:46 -07003121 info->magic = CYCLADES_MAGIC;
Jiri Slaby875b2062007-05-08 00:36:49 -07003122 info->card = cinfo;
Jiri Slaby3046d502007-05-08 00:36:46 -07003123 info->line = port;
Jiri Slaby3046d502007-05-08 00:36:46 -07003124
Alan Cox44b7d1b2008-07-16 21:57:18 +01003125 info->port.closing_wait = CLOSING_WAIT_DELAY;
3126 info->port.close_delay = 5 * HZ / 10;
Alan Cox77451e52008-07-16 21:57:02 +01003127 info->port.flags = STD_COM_FLAGS;
Jiri Slaby2c7fea92007-05-08 00:36:51 -07003128 init_completion(&info->shutdown_wait);
Jiri Slaby3046d502007-05-08 00:36:46 -07003129
Jiri Slaby2693f482009-06-11 12:31:06 +01003130 if (cy_is_Z(cinfo)) {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003131 struct FIRM_ID *firm_id = cinfo->base_addr + ID_ADDRESS;
3132 struct ZFW_CTRL *zfw_ctrl;
3133
Jiri Slabyf0737572009-09-19 13:13:12 -07003134 info->port.ops = &cyz_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003135 info->type = PORT_STARTECH;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003136
3137 zfw_ctrl = cinfo->base_addr +
3138 (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3139 info->u.cyz.ch_ctrl = &zfw_ctrl->ch_ctrl[channel];
3140 info->u.cyz.buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
3141
Jiri Slaby101b8152009-06-11 12:30:10 +01003142 if (cinfo->hw_ver == ZO_V1)
Jiri Slaby0809e262007-05-08 00:36:14 -07003143 info->xmit_fifo_size = CYZ_FIFO_SIZE;
3144 else
Jiri Slaby3046d502007-05-08 00:36:46 -07003145 info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
Jiri Slaby0809e262007-05-08 00:36:14 -07003146#ifdef CONFIG_CYZ_INTR
Jiri Slaby39914282007-05-08 00:36:54 -07003147 setup_timer(&cyz_rx_full_timer[port],
3148 cyz_rx_restart, (unsigned long)info);
Jiri Slaby0809e262007-05-08 00:36:14 -07003149#endif
Jiri Slaby3046d502007-05-08 00:36:46 -07003150 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003151 unsigned short chip_number;
Jiri Slaby963118e2009-06-11 12:34:27 +01003152 int index = cinfo->bus_index;
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003153
Jiri Slabyf0737572009-09-19 13:13:12 -07003154 info->port.ops = &cyy_port_ops;
Jiri Slaby0809e262007-05-08 00:36:14 -07003155 info->type = PORT_CIRRUS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003156 info->xmit_fifo_size = CyMAX_CHAR_FIFO;
Jiri Slaby3046d502007-05-08 00:36:46 -07003157 info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
Jiri Slaby0809e262007-05-08 00:36:14 -07003158 info->cor2 = CyETC;
3159 info->cor3 = 0x08; /* _very_ small rcv threshold */
Jiri Slaby3046d502007-05-08 00:36:46 -07003160
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003161 chip_number = channel / CyPORTS_PER_CHIP;
Jiri Slaby3aeea5b2009-09-19 13:13:16 -07003162 info->u.cyy.base_addr = cinfo->base_addr +
3163 (cy_chip_offset[chip_number] << index);
3164 info->chip_rev = cyy_readb(info, CyGFRCR);
Alan Cox15ed6cc2008-04-30 00:53:55 -07003165
3166 if (info->chip_rev >= CD1400_REV_J) {
Jiri Slaby0809e262007-05-08 00:36:14 -07003167 /* It is a CD1400 rev. J or later */
3168 info->tbpr = baud_bpr_60[13]; /* Tx BPR */
3169 info->tco = baud_co_60[13]; /* Tx CO */
3170 info->rbpr = baud_bpr_60[13]; /* Rx BPR */
3171 info->rco = baud_co_60[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003172 info->rtsdtr_inv = 1;
3173 } else {
3174 info->tbpr = baud_bpr_25[13]; /* Tx BPR */
3175 info->tco = baud_co_25[13]; /* Tx CO */
3176 info->rbpr = baud_bpr_25[13]; /* Rx BPR */
3177 info->rco = baud_co_25[13]; /* Rx CO */
Jiri Slaby0809e262007-05-08 00:36:14 -07003178 info->rtsdtr_inv = 0;
3179 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003180 info->read_status_mask = CyTIMEOUT | CySPECHAR |
3181 CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
Jiri Slaby0809e262007-05-08 00:36:14 -07003182 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003183
Jiri Slaby0809e262007-05-08 00:36:14 -07003184 }
Jiri Slaby3046d502007-05-08 00:36:46 -07003185
3186#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003187 if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
Jiri Slaby3046d502007-05-08 00:36:46 -07003188 mod_timer(&cyz_timerlist, jiffies + 1);
3189#ifdef CY_PCI_DEBUG
3190 printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
3191#endif
3192 }
3193#endif
Jiri Slabydd025c02007-05-08 00:37:02 -07003194 return 0;
Jiri Slaby0809e262007-05-08 00:36:14 -07003195}
3196
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197/* initialize chips on Cyclom-Y card -- return number of valid
3198 chips (which is number of ports/4) */
Jiri Slaby31b4f0a2007-05-08 00:36:44 -07003199static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
3200 int index)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201{
Jiri Slaby02f11752006-12-08 02:39:28 -08003202 unsigned int chip_number;
3203 void __iomem *base_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204
Jiri Slaby02f11752006-12-08 02:39:28 -08003205 cy_writeb(true_base_addr + (Cy_HwReset << index), 0);
3206 /* Cy_HwReset is 0x1400 */
3207 cy_writeb(true_base_addr + (Cy_ClrIntr << index), 0);
3208 /* Cy_ClrIntr is 0x1800 */
3209 udelay(500L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210
Alan Cox15ed6cc2008-04-30 00:53:55 -07003211 for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
3212 chip_number++) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003213 base_addr =
3214 true_base_addr + (cy_chip_offset[chip_number] << index);
3215 mdelay(1);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003216 if (readb(base_addr + (CyCCR << index)) != 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003217 /*************
3218 printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
3219 chip_number, (unsigned long)base_addr);
3220 *************/
3221 return chip_number;
3222 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223
Jiri Slaby02f11752006-12-08 02:39:28 -08003224 cy_writeb(base_addr + (CyGFRCR << index), 0);
3225 udelay(10L);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226
Jiri Slaby02f11752006-12-08 02:39:28 -08003227 /* The Cyclom-16Y does not decode address bit 9 and therefore
3228 cannot distinguish between references to chip 0 and a non-
3229 existent chip 4. If the preceding clearing of the supposed
3230 chip 4 GFRCR register appears at chip 0, there is no chip 4
3231 and this must be a Cyclom-16Y, not a Cyclom-32Ye.
3232 */
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003233 if (chip_number == 4 && readb(true_base_addr +
Jiri Slaby02f11752006-12-08 02:39:28 -08003234 (cy_chip_offset[0] << index) +
3235 (CyGFRCR << index)) == 0) {
3236 return chip_number;
3237 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238
Jiri Slaby02f11752006-12-08 02:39:28 -08003239 cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
3240 mdelay(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003242 if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003243 /*
3244 printk(" chip #%d at %#6lx is not responding ",
3245 chip_number, (unsigned long)base_addr);
3246 printk("(GFRCR stayed 0)\n",
3247 */
3248 return chip_number;
3249 }
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003250 if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
Jiri Slaby02f11752006-12-08 02:39:28 -08003251 0x40) {
3252 /*
3253 printk(" chip #%d at %#6lx is not valid (GFRCR == "
3254 "%#2x)\n",
3255 chip_number, (unsigned long)base_addr,
3256 base_addr[CyGFRCR<<index]);
3257 */
3258 return chip_number;
3259 }
3260 cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003261 if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
Jiri Slaby02f11752006-12-08 02:39:28 -08003262 /* It is a CD1400 rev. J or later */
3263 /* Impossible to reach 5ms with this chip.
3264 Changed to 2ms instead (f = 500 Hz). */
3265 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_60_2MS);
3266 } else {
3267 /* f = 200 Hz */
3268 cy_writeb(base_addr + (CyPPR << index), CyCLOCK_25_5MS);
3269 }
3270
3271 /*
3272 printk(" chip #%d at %#6lx is rev 0x%2x\n",
3273 chip_number, (unsigned long)base_addr,
Jiri Slabydb05c3b2007-05-08 00:35:46 -07003274 readb(base_addr+(CyGFRCR<<index)));
Jiri Slaby02f11752006-12-08 02:39:28 -08003275 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003277 return chip_number;
3278} /* cyy_init_card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279
3280/*
3281 * ---------------------------------------------------------------------
3282 * cy_detect_isa() - Probe for Cyclom-Y/ISA boards.
3283 * sets global variables and return the number of ISA boards found.
3284 * ---------------------------------------------------------------------
3285 */
Jiri Slaby02f11752006-12-08 02:39:28 -08003286static int __init cy_detect_isa(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287{
3288#ifdef CONFIG_ISA
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003289 struct cyclades_card *card;
Jiri Slaby02f11752006-12-08 02:39:28 -08003290 unsigned short cy_isa_irq, nboard;
3291 void __iomem *cy_isa_address;
3292 unsigned short i, j, cy_isa_nchan;
Jiri Slaby02f11752006-12-08 02:39:28 -08003293 int isparam = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294
Jiri Slaby02f11752006-12-08 02:39:28 -08003295 nboard = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 /* Check for module parameters */
Jiri Slaby02f11752006-12-08 02:39:28 -08003298 for (i = 0; i < NR_CARDS; i++) {
3299 if (maddr[i] || i) {
3300 isparam = 1;
3301 cy_isa_addresses[i] = maddr[i];
3302 }
3303 if (!maddr[i])
3304 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306
Jiri Slaby02f11752006-12-08 02:39:28 -08003307 /* scan the address table probing for Cyclom-Y/ISA boards */
3308 for (i = 0; i < NR_ISA_ADDRS; i++) {
3309 unsigned int isa_address = cy_isa_addresses[i];
Alan Cox15ed6cc2008-04-30 00:53:55 -07003310 if (isa_address == 0x0000)
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003311 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312
Jiri Slaby02f11752006-12-08 02:39:28 -08003313 /* probe for CD1400... */
Alan Coxcd989b32008-04-30 00:53:56 -07003314 cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003315 if (cy_isa_address == NULL) {
3316 printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
3317 "address\n");
3318 continue;
3319 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003320 cy_isa_nchan = CyPORTS_PER_CHIP *
3321 cyy_init_card(cy_isa_address, 0);
3322 if (cy_isa_nchan == 0) {
Jiri Slaby31375532007-05-08 00:37:04 -07003323 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003324 continue;
3325 }
Bartlomiej Zolnierkiewicz20904362009-12-09 12:34:14 -08003326
Roel Kluin196b3162009-10-01 15:44:24 -07003327 if (isparam && i < NR_CARDS && irq[i])
Jiri Slaby02f11752006-12-08 02:39:28 -08003328 cy_isa_irq = irq[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 else
Jiri Slaby02f11752006-12-08 02:39:28 -08003330 /* find out the board's irq by probing */
3331 cy_isa_irq = detect_isa_irq(cy_isa_address);
3332 if (cy_isa_irq == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003333 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
3334 "IRQ could not be detected.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003335 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003336 iounmap(cy_isa_address);
Jiri Slaby02f11752006-12-08 02:39:28 -08003337 continue;
3338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339
Jiri Slaby02f11752006-12-08 02:39:28 -08003340 if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
Jiri Slaby21719192007-05-08 00:36:42 -07003341 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3342 "more channels are available. Change NR_PORTS "
3343 "in cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003344 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003345 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003346 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003347 }
3348 /* fill the next cy_card structure available */
3349 for (j = 0; j < NR_CARDS; j++) {
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003350 card = &cy_card[j];
3351 if (card->base_addr == NULL)
Jiri Slaby02f11752006-12-08 02:39:28 -08003352 break;
3353 }
3354 if (j == NR_CARDS) { /* no more cy_cards available */
Jiri Slaby21719192007-05-08 00:36:42 -07003355 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
3356 "more cards can be used. Change NR_CARDS in "
3357 "cyclades.c and recompile kernel.\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003358 (unsigned long)cy_isa_address);
Jiri Slaby31375532007-05-08 00:37:04 -07003359 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003360 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003361 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362
Jiri Slaby02f11752006-12-08 02:39:28 -08003363 /* allocate IRQ */
3364 if (request_irq(cy_isa_irq, cyy_interrupt,
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003365 0, "Cyclom-Y", card)) {
Jiri Slaby21719192007-05-08 00:36:42 -07003366 printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
3367 "could not allocate IRQ#%d.\n",
3368 (unsigned long)cy_isa_address, cy_isa_irq);
Jiri Slaby31375532007-05-08 00:37:04 -07003369 iounmap(cy_isa_address);
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003370 return nboard;
Jiri Slaby02f11752006-12-08 02:39:28 -08003371 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372
Jiri Slaby02f11752006-12-08 02:39:28 -08003373 /* set cy_card */
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003374 card->base_addr = cy_isa_address;
3375 card->ctl_addr.p9050 = NULL;
3376 card->irq = (int)cy_isa_irq;
3377 card->bus_index = 0;
3378 card->first_line = cy_next_channel;
3379 card->num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
3380 card->nports = cy_isa_nchan;
3381 if (cy_init_card(card)) {
3382 card->base_addr = NULL;
3383 free_irq(cy_isa_irq, card);
Jiri Slaby31375532007-05-08 00:37:04 -07003384 iounmap(cy_isa_address);
3385 continue;
3386 }
Jiri Slaby02f11752006-12-08 02:39:28 -08003387 nboard++;
3388
Jiri Slaby21719192007-05-08 00:36:42 -07003389 printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
3390 "%d channels starting from port %d\n",
Jiri Slaby02f11752006-12-08 02:39:28 -08003391 j + 1, (unsigned long)cy_isa_address,
3392 (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
Jiri Slaby21719192007-05-08 00:36:42 -07003393 cy_isa_irq, cy_isa_nchan, cy_next_channel);
3394
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07003395 for (j = cy_next_channel;
3396 j < cy_next_channel + cy_isa_nchan; j++)
3397 tty_register_device(cy_serial_driver, j, NULL);
Jiri Slaby02f11752006-12-08 02:39:28 -08003398 cy_next_channel += cy_isa_nchan;
3399 }
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003400 return nboard;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401#else
Jiri Slaby096dcfc2006-12-08 02:39:30 -08003402 return 0;
Jiri Slaby02f11752006-12-08 02:39:28 -08003403#endif /* CONFIG_ISA */
3404} /* cy_detect_isa */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405
Jiri Slaby58936d82007-05-08 00:36:13 -07003406#ifdef CONFIG_PCI
Jiri Slaby054f5b02007-07-17 04:05:16 -07003407static inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
3408{
3409 unsigned int a;
3410
3411 for (a = 0; a < size && *str; a++, str++)
3412 if (*str & 0x80)
3413 return -EINVAL;
3414
3415 for (; a < size; a++, str++)
3416 if (*str)
3417 return -EINVAL;
3418
3419 return 0;
3420}
3421
David Woodhousef61e7612008-05-23 23:57:19 +01003422static inline void __devinit cyz_fpga_copy(void __iomem *fpga, const u8 *data,
Jiri Slaby054f5b02007-07-17 04:05:16 -07003423 unsigned int size)
3424{
3425 for (; size > 0; size--) {
3426 cy_writel(fpga, *data++);
3427 udelay(10);
3428 }
3429}
3430
3431static void __devinit plx_init(struct pci_dev *pdev, int irq,
3432 struct RUNTIME_9060 __iomem *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433{
Jiri Slaby02f11752006-12-08 02:39:28 -08003434 /* Reset PLX */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003435 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003436 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003437 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438
Jiri Slaby02f11752006-12-08 02:39:28 -08003439 /* Reload Config. Registers from EEPROM */
Jiri Slaby054f5b02007-07-17 04:05:16 -07003440 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
Jiri Slaby02f11752006-12-08 02:39:28 -08003441 udelay(100L);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003442 cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);
3443
3444 /* For some yet unknown reason, once the PLX9060 reloads the EEPROM,
3445 * the IRQ is lost and, thus, we have to re-write it to the PCI config.
3446 * registers. This will remain here until we find a permanent fix.
3447 */
3448 pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
3449}
3450
3451static int __devinit __cyz_load_fw(const struct firmware *fw,
3452 const char *name, const u32 mailbox, void __iomem *base,
3453 void __iomem *fpga)
3454{
David Woodhousef61e7612008-05-23 23:57:19 +01003455 const void *ptr = fw->data;
3456 const struct zfile_header *h = ptr;
3457 const struct zfile_config *c, *cs;
3458 const struct zfile_block *b, *bs;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003459 unsigned int a, tmp, len = fw->size;
3460#define BAD_FW KERN_ERR "Bad firmware: "
3461 if (len < sizeof(*h)) {
3462 printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h));
3463 return -EINVAL;
3464 }
3465
3466 cs = ptr + h->config_offset;
3467 bs = ptr + h->block_offset;
3468
3469 if ((void *)(cs + h->n_config) > ptr + len ||
3470 (void *)(bs + h->n_blocks) > ptr + len) {
3471 printk(BAD_FW "too short");
3472 return -EINVAL;
3473 }
3474
3475 if (cyc_isfwstr(h->name, sizeof(h->name)) ||
3476 cyc_isfwstr(h->date, sizeof(h->date))) {
3477 printk(BAD_FW "bad formatted header string\n");
3478 return -EINVAL;
3479 }
3480
3481 if (strncmp(name, h->name, sizeof(h->name))) {
3482 printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name);
3483 return -EINVAL;
3484 }
3485
3486 tmp = 0;
3487 for (c = cs; c < cs + h->n_config; c++) {
3488 for (a = 0; a < c->n_blocks; a++)
3489 if (c->block_list[a] > h->n_blocks) {
3490 printk(BAD_FW "bad block ref number in cfgs\n");
3491 return -EINVAL;
3492 }
3493 if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */
3494 tmp++;
3495 }
3496 if (!tmp) {
3497 printk(BAD_FW "nothing appropriate\n");
3498 return -EINVAL;
3499 }
3500
3501 for (b = bs; b < bs + h->n_blocks; b++)
3502 if (b->file_offset + b->size > len) {
3503 printk(BAD_FW "bad block data offset\n");
3504 return -EINVAL;
3505 }
3506
3507 /* everything is OK, let's seek'n'load it */
3508 for (c = cs; c < cs + h->n_config; c++)
3509 if (c->mailbox == mailbox && c->function == 0)
3510 break;
3511
3512 for (a = 0; a < c->n_blocks; a++) {
3513 b = &bs[c->block_list[a]];
3514 if (b->type == ZBLOCK_FPGA) {
3515 if (fpga != NULL)
3516 cyz_fpga_copy(fpga, ptr + b->file_offset,
3517 b->size);
3518 } else {
3519 if (base != NULL)
3520 memcpy_toio(base + b->ram_offset,
3521 ptr + b->file_offset, b->size);
3522 }
3523 }
3524#undef BAD_FW
3525 return 0;
3526}
3527
3528static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
3529 struct RUNTIME_9060 __iomem *ctl_addr, int irq)
3530{
3531 const struct firmware *fw;
3532 struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
3533 struct CUSTOM_REG __iomem *cust = base_addr;
3534 struct ZFW_CTRL __iomem *pt_zfwctrl;
Jiri Slabyc4923b42007-07-17 04:05:17 -07003535 void __iomem *tmp;
Jiri Slaby963118e2009-06-11 12:34:27 +01003536 u32 mailbox, status, nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003537 unsigned int i;
3538 int retval;
3539
3540 retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev);
3541 if (retval) {
3542 dev_err(&pdev->dev, "can't get firmware\n");
3543 goto err;
3544 }
3545
3546 /* Check whether the firmware is already loaded and running. If
3547 positive, skip this board */
Jiri Slaby2693f482009-06-11 12:31:06 +01003548 if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003549 u32 cntval = readl(base_addr + 0x190);
3550
3551 udelay(100);
3552 if (cntval != readl(base_addr + 0x190)) {
3553 /* FW counter is working, FW is running */
3554 dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. "
3555 "Skipping board.\n");
3556 retval = 0;
3557 goto err_rel;
3558 }
3559 }
3560
3561 /* start boot */
3562 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) &
3563 ~0x00030800UL);
3564
3565 mailbox = readl(&ctl_addr->mail_box_0);
3566
Jiri Slaby2693f482009-06-11 12:31:06 +01003567 if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003568 /* stops CPU and set window to beginning of RAM */
3569 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3570 cy_writel(&cust->cpu_stop, 0);
3571 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3572 udelay(100);
3573 }
3574
3575 plx_init(pdev, irq, ctl_addr);
3576
3577 if (mailbox != 0) {
3578 /* load FPGA */
3579 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL,
3580 base_addr);
3581 if (retval)
3582 goto err_rel;
Jiri Slaby2693f482009-06-11 12:31:06 +01003583 if (!__cyz_fpga_loaded(ctl_addr)) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003584 dev_err(&pdev->dev, "fw upload successful, but fw is "
3585 "not loaded\n");
3586 goto err_rel;
3587 }
3588 }
3589
3590 /* stops CPU and set window to beginning of RAM */
3591 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3592 cy_writel(&cust->cpu_stop, 0);
3593 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3594 udelay(100);
3595
3596 /* clear memory */
Jiri Slabyc4923b42007-07-17 04:05:17 -07003597 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003598 cy_writeb(tmp, 255);
3599 if (mailbox != 0) {
3600 /* set window to last 512K of RAM */
3601 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
Jiri Slabyc4923b42007-07-17 04:05:17 -07003602 for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
Jiri Slaby054f5b02007-07-17 04:05:16 -07003603 cy_writeb(tmp, 255);
3604 /* set window to beginning of RAM */
3605 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003606 }
3607
3608 retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
3609 release_firmware(fw);
3610 if (retval)
3611 goto err;
3612
3613 /* finish boot and start boards */
3614 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3615 cy_writel(&cust->cpu_start, 0);
3616 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3617 i = 0;
3618 while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40)
3619 msleep(100);
3620 if (status != ZFIRM_ID) {
3621 if (status == ZFIRM_HLT) {
3622 dev_err(&pdev->dev, "you need an external power supply "
3623 "for this number of ports. Firmware halted and "
3624 "board reset.\n");
3625 retval = -EIO;
3626 goto err;
3627 }
3628 dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting "
3629 "some more time\n", status);
3630 while ((status = readl(&fid->signature)) != ZFIRM_ID &&
3631 i++ < 200)
3632 msleep(100);
3633 if (status != ZFIRM_ID) {
3634 dev_err(&pdev->dev, "Board not started in 20 seconds! "
3635 "Giving up. (fid->signature = 0x%x)\n",
3636 status);
3637 dev_info(&pdev->dev, "*** Warning ***: if you are "
3638 "upgrading the FW, please power cycle the "
3639 "system before loading the new FW to the "
3640 "Cyclades-Z.\n");
3641
Jiri Slaby2693f482009-06-11 12:31:06 +01003642 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003643 plx_init(pdev, irq, ctl_addr);
3644
3645 retval = -EIO;
3646 goto err;
3647 }
3648 dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n",
3649 i / 10);
3650 }
3651 pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr);
3652
3653 dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n",
3654 base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
3655 base_addr + readl(&fid->zfwctrl_addr));
3656
Jiri Slaby963118e2009-06-11 12:34:27 +01003657 nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003658 dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
Jiri Slaby963118e2009-06-11 12:34:27 +01003659 readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
Jiri Slaby054f5b02007-07-17 04:05:16 -07003660
Jiri Slaby963118e2009-06-11 12:34:27 +01003661 if (nchan == 0) {
Jiri Slaby054f5b02007-07-17 04:05:16 -07003662 dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
3663 "check the connection between the Z host card and the "
3664 "serial expanders.\n");
3665
Jiri Slaby2693f482009-06-11 12:31:06 +01003666 if (__cyz_fpga_loaded(ctl_addr))
Jiri Slaby054f5b02007-07-17 04:05:16 -07003667 plx_init(pdev, irq, ctl_addr);
3668
3669 dev_info(&pdev->dev, "Null number of ports detected. Board "
3670 "reset.\n");
3671 retval = 0;
3672 goto err;
3673 }
3674
3675 cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX);
3676 cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION);
3677
3678 /*
3679 Early firmware failed to start looking for commands.
3680 This enables firmware interrupts for those commands.
3681 */
3682 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3683 (1 << 17));
3684 cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
3685 0x00030800UL);
3686
Jiri Slaby963118e2009-06-11 12:34:27 +01003687 return nchan;
Jiri Slaby054f5b02007-07-17 04:05:16 -07003688err_rel:
3689 release_firmware(fw);
3690err:
3691 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692}
3693
Jiri Slaby58936d82007-05-08 00:36:13 -07003694static int __devinit cy_pci_probe(struct pci_dev *pdev,
3695 const struct pci_device_id *ent)
3696{
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003697 struct cyclades_card *card;
Jiri Slaby31375532007-05-08 00:37:04 -07003698 void __iomem *addr0 = NULL, *addr2 = NULL;
3699 char *card_name = NULL;
Jiri Slaby101b8152009-06-11 12:30:10 +01003700 u32 uninitialized_var(mailbox);
Jiri Slaby31375532007-05-08 00:37:04 -07003701 unsigned int device_id, nchan = 0, card_no, i;
3702 unsigned char plx_ver;
3703 int retval, irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003704
3705 retval = pci_enable_device(pdev);
3706 if (retval) {
3707 dev_err(&pdev->dev, "cannot enable device\n");
Jiri Slaby31375532007-05-08 00:37:04 -07003708 goto err;
Jiri Slaby58936d82007-05-08 00:36:13 -07003709 }
3710
3711 /* read PCI configuration area */
Jiri Slaby31375532007-05-08 00:37:04 -07003712 irq = pdev->irq;
Jiri Slaby58936d82007-05-08 00:36:13 -07003713 device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
3714
Jiri Slaby31375532007-05-08 00:37:04 -07003715#if defined(__alpha__)
3716 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
3717 dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
3718 "addresses on Alpha systems.\n");
3719 retval = -EIO;
3720 goto err_dis;
3721 }
3722#endif
3723 if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
3724 dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
3725 "addresses\n");
3726 retval = -EIO;
3727 goto err_dis;
3728 }
3729
3730 if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
3731 dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
3732 "it...\n");
3733 pdev->resource[2].flags &= ~IORESOURCE_IO;
3734 }
3735
3736 retval = pci_request_regions(pdev, "cyclades");
3737 if (retval) {
3738 dev_err(&pdev->dev, "failed to reserve resources\n");
3739 goto err_dis;
3740 }
3741
3742 retval = -EIO;
Jiri Slaby58936d82007-05-08 00:36:13 -07003743 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3744 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby31375532007-05-08 00:37:04 -07003745 card_name = "Cyclom-Y";
Jiri Slaby58936d82007-05-08 00:36:13 -07003746
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003747 addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
3748 CyPCI_Yctl);
Jiri Slaby31375532007-05-08 00:37:04 -07003749 if (addr0 == NULL) {
3750 dev_err(&pdev->dev, "can't remap ctl region\n");
3751 goto err_reg;
3752 }
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003753 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
3754 CyPCI_Ywin);
Jiri Slaby31375532007-05-08 00:37:04 -07003755 if (addr2 == NULL) {
3756 dev_err(&pdev->dev, "can't remap base region\n");
3757 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003758 }
3759
Jiri Slaby31375532007-05-08 00:37:04 -07003760 nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
3761 if (nchan == 0) {
Jiri Slaby21719192007-05-08 00:36:42 -07003762 dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
3763 "Serial-Modules\n");
Andrew Mortonc847d472009-01-02 13:50:07 +00003764 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003765 }
Jiri Slaby31375532007-05-08 00:37:04 -07003766 } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
3767 struct RUNTIME_9060 __iomem *ctl_addr;
3768
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003769 ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0),
3770 CyPCI_Zctl);
Jiri Slaby31375532007-05-08 00:37:04 -07003771 if (addr0 == NULL) {
3772 dev_err(&pdev->dev, "can't remap ctl region\n");
3773 goto err_reg;
Jiri Slaby58936d82007-05-08 00:36:13 -07003774 }
3775
Jiri Slaby31375532007-05-08 00:37:04 -07003776 /* Disable interrupts on the PLX before resetting it */
Jiri Slaby97e87f82009-06-11 12:29:27 +01003777 cy_writew(&ctl_addr->intr_ctrl_stat,
3778 readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
Jiri Slaby31375532007-05-08 00:37:04 -07003779
Jiri Slaby054f5b02007-07-17 04:05:16 -07003780 plx_init(pdev, irq, addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07003781
Jiri Slaby101b8152009-06-11 12:30:10 +01003782 mailbox = readl(&ctl_addr->mail_box_0);
Jiri Slaby31375532007-05-08 00:37:04 -07003783
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003784 addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
3785 mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
Jiri Slaby31375532007-05-08 00:37:04 -07003786 if (addr2 == NULL) {
3787 dev_err(&pdev->dev, "can't remap base region\n");
3788 goto err_unmap;
3789 }
3790
3791 if (mailbox == ZE_V1) {
3792 card_name = "Cyclades-Ze";
Jiri Slaby31375532007-05-08 00:37:04 -07003793 } else {
3794 card_name = "Cyclades-8Zo";
Jiri Slaby31375532007-05-08 00:37:04 -07003795#ifdef CY_PCI_DEBUG
3796 if (mailbox == ZO_V1) {
3797 cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
3798 dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
3799 "id %lx, ver %lx\n", (ulong)(0xff &
3800 readl(&((struct CUSTOM_REG *)addr2)->
3801 fpga_id)), (ulong)(0xff &
3802 readl(&((struct CUSTOM_REG *)addr2)->
3803 fpga_version)));
3804 cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
3805 } else {
3806 dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
3807 "Cyclades-Z board. FPGA not loaded\n");
3808 }
3809#endif
3810 /* The following clears the firmware id word. This
3811 ensures that the driver will not attempt to talk to
3812 the board until it has been properly initialized.
3813 */
3814 if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
3815 cy_writel(addr2 + ID_ADDRESS, 0L);
Jiri Slaby31375532007-05-08 00:37:04 -07003816 }
Jiri Slabyace08c32009-06-11 12:20:38 +01003817
3818 retval = cyz_load_fw(pdev, addr2, addr0, irq);
Jiri Slaby963118e2009-06-11 12:34:27 +01003819 if (retval <= 0)
Jiri Slabyace08c32009-06-11 12:20:38 +01003820 goto err_unmap;
Jiri Slaby963118e2009-06-11 12:34:27 +01003821 nchan = retval;
Jiri Slaby31375532007-05-08 00:37:04 -07003822 }
3823
3824 if ((cy_next_channel + nchan) > NR_PORTS) {
3825 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
3826 "channels are available. Change NR_PORTS in "
3827 "cyclades.c and recompile kernel.\n");
3828 goto err_unmap;
3829 }
3830 /* fill the next cy_card structure available */
3831 for (card_no = 0; card_no < NR_CARDS; card_no++) {
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003832 card = &cy_card[card_no];
3833 if (card->base_addr == NULL)
Jiri Slaby31375532007-05-08 00:37:04 -07003834 break;
3835 }
3836 if (card_no == NR_CARDS) { /* no more cy_cards available */
3837 dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
3838 "more cards can be used. Change NR_CARDS in "
3839 "cyclades.c and recompile kernel.\n");
3840 goto err_unmap;
3841 }
3842
3843 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3844 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07003845 /* allocate IRQ */
Jiri Slaby31375532007-05-08 00:37:04 -07003846 retval = request_irq(irq, cyy_interrupt,
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003847 IRQF_SHARED, "Cyclom-Y", card);
Jiri Slaby58936d82007-05-08 00:36:13 -07003848 if (retval) {
Jiri Slaby21719192007-05-08 00:36:42 -07003849 dev_err(&pdev->dev, "could not allocate IRQ\n");
Jiri Slaby31375532007-05-08 00:37:04 -07003850 goto err_unmap;
Jiri Slaby58936d82007-05-08 00:36:13 -07003851 }
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003852 card->num_chips = nchan / CyPORTS_PER_CHIP;
Jiri Slaby31375532007-05-08 00:37:04 -07003853 } else {
Jiri Slabyf0eefdc2009-09-19 13:13:13 -07003854 struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
3855 struct ZFW_CTRL __iomem *zfw_ctrl;
3856
3857 zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
3858
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003859 card->hw_ver = mailbox;
3860 card->num_chips = (unsigned int)-1;
3861 card->board_ctrl = &zfw_ctrl->board_ctrl;
Jiri Slaby31375532007-05-08 00:37:04 -07003862#ifdef CONFIG_CYZ_INTR
3863 /* allocate IRQ only if board has an IRQ */
3864 if (irq != 0 && irq != 255) {
3865 retval = request_irq(irq, cyz_interrupt,
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003866 IRQF_SHARED, "Cyclades-Z", card);
Jiri Slaby31375532007-05-08 00:37:04 -07003867 if (retval) {
3868 dev_err(&pdev->dev, "could not allocate IRQ\n");
3869 goto err_unmap;
3870 }
3871 }
3872#endif /* CONFIG_CYZ_INTR */
Jiri Slaby31375532007-05-08 00:37:04 -07003873 }
Jiri Slaby58936d82007-05-08 00:36:13 -07003874
Jiri Slaby31375532007-05-08 00:37:04 -07003875 /* set cy_card */
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003876 card->base_addr = addr2;
3877 card->ctl_addr.p9050 = addr0;
3878 card->irq = irq;
3879 card->bus_index = 1;
3880 card->first_line = cy_next_channel;
3881 card->nports = nchan;
3882 retval = cy_init_card(card);
Jiri Slaby31375532007-05-08 00:37:04 -07003883 if (retval)
3884 goto err_null;
Jiri Slaby58936d82007-05-08 00:36:13 -07003885
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003886 pci_set_drvdata(pdev, card);
Jiri Slaby31375532007-05-08 00:37:04 -07003887
3888 if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
3889 device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
Jiri Slaby58936d82007-05-08 00:36:13 -07003890 /* enable interrupts in the PCI interface */
Jiri Slaby31375532007-05-08 00:37:04 -07003891 plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
Jiri Slaby58936d82007-05-08 00:36:13 -07003892 switch (plx_ver) {
3893 case PLX_9050:
Jiri Slaby31375532007-05-08 00:37:04 -07003894 cy_writeb(addr0 + 0x4c, 0x43);
Jiri Slaby58936d82007-05-08 00:36:13 -07003895 break;
3896
3897 case PLX_9060:
3898 case PLX_9080:
3899 default: /* Old boards, use PLX_9060 */
Jiri Slaby97e87f82009-06-11 12:29:27 +01003900 {
3901 struct RUNTIME_9060 __iomem *ctl_addr = addr0;
3902 plx_init(pdev, irq, ctl_addr);
3903 cy_writew(&ctl_addr->intr_ctrl_stat,
3904 readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
Jiri Slaby58936d82007-05-08 00:36:13 -07003905 break;
3906 }
Jiri Slaby97e87f82009-06-11 12:29:27 +01003907 }
Jiri Slaby58936d82007-05-08 00:36:13 -07003908 }
3909
Jiri Slaby31375532007-05-08 00:37:04 -07003910 dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
3911 "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
3912 for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
3913 tty_register_device(cy_serial_driver, i, &pdev->dev);
3914 cy_next_channel += nchan;
3915
Jiri Slaby58936d82007-05-08 00:36:13 -07003916 return 0;
Jiri Slaby31375532007-05-08 00:37:04 -07003917err_null:
Jiri Slaby718c4ca2012-06-04 13:35:15 +02003918 card->base_addr = NULL;
3919 free_irq(irq, card);
Jiri Slaby31375532007-05-08 00:37:04 -07003920err_unmap:
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003921 iounmap(addr0);
Jiri Slaby31375532007-05-08 00:37:04 -07003922 if (addr2)
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003923 iounmap(addr2);
Jiri Slaby31375532007-05-08 00:37:04 -07003924err_reg:
3925 pci_release_regions(pdev);
3926err_dis:
3927 pci_disable_device(pdev);
3928err:
3929 return retval;
Jiri Slaby58936d82007-05-08 00:36:13 -07003930}
Jiri Slaby58936d82007-05-08 00:36:13 -07003931
Jiri Slaby6747cd92007-05-08 00:36:34 -07003932static void __devexit cy_pci_remove(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933{
Jiri Slaby38d09092007-05-08 00:36:10 -07003934 struct cyclades_card *cinfo = pci_get_drvdata(pdev);
Jiri Slabyf3851e72007-05-08 00:36:16 -07003935 unsigned int i;
Jiri Slaby38d09092007-05-08 00:36:10 -07003936
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003937 /* non-Z with old PLX */
Jiri Slaby2693f482009-06-11 12:31:06 +01003938 if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
Jiri Slabyc2ad4c72007-05-08 00:36:32 -07003939 PLX_9050)
Jiri Slaby97e87f82009-06-11 12:29:27 +01003940 cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003941 else
3942#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003943 if (!cy_is_Z(cinfo))
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003944#endif
Jiri Slaby97e87f82009-06-11 12:29:27 +01003945 cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
3946 readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
3947 ~0x0900);
Jiri Slaby85c93fa2007-05-08 00:36:23 -07003948
Jiri Slaby24e6fd42008-10-13 10:34:09 +01003949 iounmap(cinfo->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01003950 if (cinfo->ctl_addr.p9050)
3951 iounmap(cinfo->ctl_addr.p9050);
Jiri Slaby38d09092007-05-08 00:36:10 -07003952 if (cinfo->irq
3953#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01003954 && !cy_is_Z(cinfo)
Jiri Slaby38d09092007-05-08 00:36:10 -07003955#endif /* CONFIG_CYZ_INTR */
3956 )
3957 free_irq(cinfo->irq, cinfo);
3958 pci_release_regions(pdev);
3959
3960 cinfo->base_addr = NULL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07003961 for (i = cinfo->first_line; i < cinfo->first_line +
3962 cinfo->nports; i++)
3963 tty_unregister_device(cy_serial_driver, i);
Jiri Slabydd025c02007-05-08 00:37:02 -07003964 cinfo->nports = 0;
3965 kfree(cinfo->ports);
Jiri Slaby38d09092007-05-08 00:36:10 -07003966}
3967
Jiri Slaby6747cd92007-05-08 00:36:34 -07003968static struct pci_driver cy_pci_driver = {
3969 .name = "cyclades",
3970 .id_table = cy_pci_dev_id,
3971 .probe = cy_pci_probe,
3972 .remove = __devexit_p(cy_pci_remove)
3973};
3974#endif
3975
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003976static int cyclades_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977{
Jiri Slaby02f11752006-12-08 02:39:28 -08003978 struct cyclades_port *info;
Jiri Slabydd025c02007-05-08 00:37:02 -07003979 unsigned int i, j;
Jiri Slaby02f11752006-12-08 02:39:28 -08003980 __u32 cur_jifs = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981
Alexey Dobriyan444697d2009-03-31 15:19:15 -07003982 seq_puts(m, "Dev TimeOpen BytesOut IdleOut BytesIn "
Jiri Slaby02f11752006-12-08 02:39:28 -08003983 "IdleIn Overruns Ldisc\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984
Jiri Slaby02f11752006-12-08 02:39:28 -08003985 /* Output one line for each known port */
Jiri Slabydd025c02007-05-08 00:37:02 -07003986 for (i = 0; i < NR_CARDS; i++)
3987 for (j = 0; j < cy_card[i].nports; j++) {
3988 info = &cy_card[i].ports[j];
Jiri Slaby02f11752006-12-08 02:39:28 -08003989
Jiri Slabyd13549f2009-09-19 13:13:12 -07003990 if (info->port.count) {
3991 /* XXX is the ldisc num worth this? */
3992 struct tty_struct *tty;
3993 struct tty_ldisc *ld;
3994 int num = 0;
3995 tty = tty_port_tty_get(&info->port);
3996 if (tty) {
3997 ld = tty_ldisc_ref(tty);
3998 if (ld) {
3999 num = ld->ops->num;
4000 tty_ldisc_deref(ld);
4001 }
4002 tty_kref_put(tty);
4003 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004004 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabyd13549f2009-09-19 13:13:12 -07004005 "%10lu %8lu %9lu %6d\n", info->line,
Jiri Slabydd025c02007-05-08 00:37:02 -07004006 (cur_jifs - info->idle_stats.in_use) /
4007 HZ, info->idle_stats.xmit_bytes,
4008 (cur_jifs - info->idle_stats.xmit_idle)/
4009 HZ, info->idle_stats.recv_bytes,
4010 (cur_jifs - info->idle_stats.recv_idle)/
4011 HZ, info->idle_stats.overruns,
Jiri Slabyd13549f2009-09-19 13:13:12 -07004012 num);
4013 } else
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004014 seq_printf(m, "%3d %8lu %10lu %8lu "
Jiri Slabydd025c02007-05-08 00:37:02 -07004015 "%10lu %8lu %9lu %6ld\n",
4016 info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
Jiri Slaby02f11752006-12-08 02:39:28 -08004017 }
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004018 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019}
4020
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004021static int cyclades_proc_open(struct inode *inode, struct file *file)
4022{
4023 return single_open(file, cyclades_proc_show, NULL);
4024}
4025
4026static const struct file_operations cyclades_proc_fops = {
4027 .owner = THIS_MODULE,
4028 .open = cyclades_proc_open,
4029 .read = seq_read,
4030 .llseek = seq_lseek,
4031 .release = single_release,
4032};
4033
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034/* The serial driver boot-time initialization code!
4035 Hardware I/O ports are mapped to character special devices on a
4036 first found, first allocated manner. That is, this code searches
4037 for Cyclom cards in the system. As each is found, it is probed
4038 to discover how many chips (and thus how many ports) are present.
4039 These ports are mapped to the tty ports 32 and upward in monotonic
4040 fashion. If an 8-port card is replaced with a 16-port card, the
4041 port mapping on a following card will shift.
4042
4043 This approach is different from what is used in the other serial
4044 device driver because the Cyclom is more properly a multiplexer,
4045 not just an aggregation of serial ports on one card.
4046
4047 If there are more cards with more ports than have been
4048 statically allocated above, a warning is printed and the
4049 extra ports are ignored.
4050 */
4051
Jeff Dikeb68e31d2006-10-02 02:17:18 -07004052static const struct tty_operations cy_ops = {
Jiri Slaby02f11752006-12-08 02:39:28 -08004053 .open = cy_open,
4054 .close = cy_close,
4055 .write = cy_write,
4056 .put_char = cy_put_char,
4057 .flush_chars = cy_flush_chars,
4058 .write_room = cy_write_room,
4059 .chars_in_buffer = cy_chars_in_buffer,
4060 .flush_buffer = cy_flush_buffer,
4061 .ioctl = cy_ioctl,
4062 .throttle = cy_throttle,
4063 .unthrottle = cy_unthrottle,
4064 .set_termios = cy_set_termios,
4065 .stop = cy_stop,
4066 .start = cy_start,
4067 .hangup = cy_hangup,
4068 .break_ctl = cy_break,
4069 .wait_until_sent = cy_wait_until_sent,
Jiri Slaby02f11752006-12-08 02:39:28 -08004070 .tiocmget = cy_tiocmget,
4071 .tiocmset = cy_tiocmset,
Alan Cox05871022010-09-16 18:21:52 +01004072 .get_icount = cy_get_icount,
Alexey Dobriyan444697d2009-03-31 15:19:15 -07004073 .proc_fops = &cyclades_proc_fops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074};
4075
Jiri Slaby02f11752006-12-08 02:39:28 -08004076static int __init cy_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077{
Jiri Slabydd025c02007-05-08 00:37:02 -07004078 unsigned int nboards;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004079 int retval = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080
Jiri Slaby02f11752006-12-08 02:39:28 -08004081 cy_serial_driver = alloc_tty_driver(NR_PORTS);
4082 if (!cy_serial_driver)
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004083 goto err;
Jiri Slaby21719192007-05-08 00:36:42 -07004084
Michal Marek64a14b52011-04-01 12:41:20 +02004085 printk(KERN_INFO "Cyclades driver " CY_VERSION "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086
Jiri Slaby02f11752006-12-08 02:39:28 -08004087 /* Initialize the tty_driver structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088
Jiri Slaby02f11752006-12-08 02:39:28 -08004089 cy_serial_driver->driver_name = "cyclades";
4090 cy_serial_driver->name = "ttyC";
4091 cy_serial_driver->major = CYCLADES_MAJOR;
4092 cy_serial_driver->minor_start = 0;
4093 cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
4094 cy_serial_driver->subtype = SERIAL_TYPE_NORMAL;
4095 cy_serial_driver->init_termios = tty_std_termios;
4096 cy_serial_driver->init_termios.c_cflag =
4097 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004098 cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
Jiri Slaby02f11752006-12-08 02:39:28 -08004099 tty_set_operations(cy_serial_driver, &cy_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004101 retval = tty_register_driver(cy_serial_driver);
4102 if (retval) {
4103 printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
4104 goto err_frtty;
4105 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106
Jiri Slaby02f11752006-12-08 02:39:28 -08004107 /* the code below is responsible to find the boards. Each different
4108 type of board has its own detection routine. If a board is found,
4109 the next cy_card structure available is set by the detection
4110 routine. These functions are responsible for checking the
4111 availability of cy_card and cy_port data structures and updating
4112 the cy_next_channel. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113
Jiri Slaby02f11752006-12-08 02:39:28 -08004114 /* look for isa boards */
Jiri Slaby14a55a62007-05-08 00:36:18 -07004115 nboards = cy_detect_isa();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116
Jiri Slaby6747cd92007-05-08 00:36:34 -07004117#ifdef CONFIG_PCI
Jiri Slaby02f11752006-12-08 02:39:28 -08004118 /* look for pci boards */
Jiri Slaby6747cd92007-05-08 00:36:34 -07004119 retval = pci_register_driver(&cy_pci_driver);
Jesper Juhld941ea72007-10-18 03:06:23 -07004120 if (retval && !nboards) {
4121 tty_unregister_driver(cy_serial_driver);
4122 goto err_frtty;
4123 }
Jiri Slaby6747cd92007-05-08 00:36:34 -07004124#endif
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004125
4126 return 0;
Jiri Slaby9dacf3b2007-05-08 00:36:20 -07004127err_frtty:
4128 put_tty_driver(cy_serial_driver);
4129err:
4130 return retval;
Jiri Slaby02f11752006-12-08 02:39:28 -08004131} /* cy_init */
4132
4133static void __exit cy_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134{
Jiri Slabydd025c02007-05-08 00:37:02 -07004135 struct cyclades_card *card;
Jiri Slaby65f76a82007-10-18 03:06:22 -07004136 unsigned int i, e1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137
4138#ifndef CONFIG_CYZ_INTR
Jiri Slabyb7050902007-05-08 00:35:48 -07004139 del_timer_sync(&cyz_timerlist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140#endif /* CONFIG_CYZ_INTR */
4141
Alan Cox15ed6cc2008-04-30 00:53:55 -07004142 e1 = tty_unregister_driver(cy_serial_driver);
4143 if (e1)
Jiri Slaby21719192007-05-08 00:36:42 -07004144 printk(KERN_ERR "failed to unregister Cyclades serial "
4145 "driver(%d)\n", e1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146
Jiri Slaby6747cd92007-05-08 00:36:34 -07004147#ifdef CONFIG_PCI
4148 pci_unregister_driver(&cy_pci_driver);
4149#endif
4150
Jiri Slaby02f11752006-12-08 02:39:28 -08004151 for (i = 0; i < NR_CARDS; i++) {
Jiri Slabydd025c02007-05-08 00:37:02 -07004152 card = &cy_card[i];
4153 if (card->base_addr) {
Jiri Slaby85c93fa2007-05-08 00:36:23 -07004154 /* clear interrupt */
Jiri Slabydd025c02007-05-08 00:37:02 -07004155 cy_writeb(card->base_addr + Cy_ClrIntr, 0);
4156 iounmap(card->base_addr);
Jiri Slaby97e87f82009-06-11 12:29:27 +01004157 if (card->ctl_addr.p9050)
4158 iounmap(card->ctl_addr.p9050);
Jiri Slabydd025c02007-05-08 00:37:02 -07004159 if (card->irq
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160#ifndef CONFIG_CYZ_INTR
Jiri Slaby2693f482009-06-11 12:31:06 +01004161 && !cy_is_Z(card)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162#endif /* CONFIG_CYZ_INTR */
Jiri Slaby02f11752006-12-08 02:39:28 -08004163 )
Jiri Slabydd025c02007-05-08 00:37:02 -07004164 free_irq(card->irq, card);
Jiri Slaby65f76a82007-10-18 03:06:22 -07004165 for (e1 = card->first_line; e1 < card->first_line +
Jiri Slabydd025c02007-05-08 00:37:02 -07004166 card->nports; e1++)
Jiri Slaby6ad1ccc2007-05-08 00:36:22 -07004167 tty_unregister_device(cy_serial_driver, e1);
Jiri Slabydd025c02007-05-08 00:37:02 -07004168 kfree(card->ports);
Jiri Slaby02f11752006-12-08 02:39:28 -08004169 }
4170 }
Jiri Slabyf2462bf2007-05-08 00:37:01 -07004171
4172 put_tty_driver(cy_serial_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173} /* cy_cleanup_module */
4174
4175module_init(cy_init);
4176module_exit(cy_cleanup_module);
4177
4178MODULE_LICENSE("GPL");
Jiri Slabyc8e16932007-05-08 00:37:05 -07004179MODULE_VERSION(CY_VERSION);
Scott James Remnant9f56fad72009-04-06 17:33:04 +01004180MODULE_ALIAS_CHARDEV_MAJOR(CYCLADES_MAJOR);
Ben Hutchingse6c4ef92010-01-13 23:34:18 +00004181MODULE_FIRMWARE("cyzfirm.bin");